Skip to content

Commit 0dd2698

Browse files
authored
New -node-kubelet-repository flag (default: quay.io/poseidon/kubelet) (#801)
on Flatcar Linux: * -node-hyperkube-image is used only for kubelet version < 1.18 * replace RKT / kubelet-wrapper usage with docker on CoreOS ContainerLinux: * no changes Signed-off-by: Artiom Diomin <[email protected]>
1 parent 7e26d77 commit 0dd2698

File tree

10 files changed

+650
-96
lines changed

10 files changed

+650
-96
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.idea
2-
machine-controller*
2+
/machine-controller*
33
.terraform
44
terraform.tfstate
55
terraform.tfstate.backup

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ LDFLAGS ?= -ldflags '-s -w'
3131

3232
IMAGE_TAG = \
3333
$(shell echo $$(git rev-parse HEAD && if [[ -n $$(git status --porcelain) ]]; then echo '-dirty'; fi)|tr -d ' ')
34-
IMAGE_NAME = $(REGISTRY)/$(REGISTRY_NAMESPACE)/machine-controller:$(IMAGE_TAG)
34+
IMAGE_NAME ?= $(REGISTRY)/$(REGISTRY_NAMESPACE)/machine-controller:$(IMAGE_TAG)
3535

3636
OS = centos coreos ubuntu sles rhel flatcar
3737
USERDATA_BIN = $(patsubst %, machine-controller-userdata-%, $(OS))

cmd/machine-controller/main.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ var (
8282
nodeRegistryMirrors string
8383
nodePauseImage string
8484
nodeHyperkubeImage string
85+
nodeKubeletRepository string
8586
)
8687

8788
const (
@@ -165,7 +166,8 @@ func main() {
165166
flag.StringVar(&nodeInsecureRegistries, "node-insecure-registries", "", "Comma separated list of registries which should be configured as insecure on the container runtime")
166167
flag.StringVar(&nodeRegistryMirrors, "node-registry-mirrors", "", "Comma separated list of Docker image mirrors")
167168
flag.StringVar(&nodePauseImage, "node-pause-image", "", "Image for the pause container including tag. If not set, the kubelet default will be used: https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/")
168-
flag.StringVar(&nodeHyperkubeImage, "node-hyperkube-image", "k8s.gcr.io/hyperkube-amd64", "Image for the hyperkube container excluding tag.")
169+
flag.StringVar(&nodeHyperkubeImage, "node-hyperkube-image", "k8s.gcr.io/hyperkube-amd64", "Image for the hyperkube container excluding tag. Only has effect on CoreOS Container Linux and Flatcar Linux, and for kubernetes < 1.18.")
170+
flag.StringVar(&nodeKubeletRepository, "node-kubelet-repository", "quay.io/poseidon/kubelet", "Repository for the kubelet container. Only has effect on Flatcar Linux, and for kubernetes >= 1.18.")
169171
flag.BoolVar(&nodeCSRApprover, "node-csr-approver", false, "Enable NodeCSRApprover controller to automatically approve node serving certificate requests.")
170172

171173
flag.Parse()
@@ -198,13 +200,23 @@ func main() {
198200
if err := clusterv1alpha1.AddToScheme(scheme.Scheme); err != nil {
199201
klog.Fatalf("failed to add clusterv1alpha1 api to scheme: %v", err)
200202
}
203+
201204
// Check if the hyperkube image has a tag set
202205
hyperkubeImageRef, err := reference.Parse(nodeHyperkubeImage)
203206
if err != nil {
204-
klog.Fatalf("failed to parse --node-hyperkube-image %s: %v", nodeHyperkubeImage, err)
207+
klog.Fatalf("failed to parse -node-hyperkube-image %s: %v", nodeHyperkubeImage, err)
205208
}
206209
if _, ok := hyperkubeImageRef.(reference.NamedTagged); ok {
207-
klog.Fatalf("--node-hyperkube-image must not contain a tag. The tag will be dynamically set for each Machine.")
210+
klog.Fatalf("-node-hyperkube-image must not contain a tag. The tag will be dynamically set for each Machine.")
211+
}
212+
213+
// Check if the kubelet image has a tag set
214+
kubeletRepoRef, err := reference.Parse(nodeKubeletRepository)
215+
if err != nil {
216+
klog.Fatalf("failed to parse -node-hyperkube-image %s: %v", nodeHyperkubeImage, err)
217+
}
218+
if _, ok := kubeletRepoRef.(reference.NamedTagged); ok {
219+
klog.Fatalf("-node-kubelet-image must not contain a tag. The tag will be dynamically set for each Machine.")
208220
}
209221

210222
cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
@@ -246,11 +258,12 @@ func main() {
246258
skipEvictionAfter: skipEvictionAfter,
247259
nodeCSRApprover: nodeCSRApprover,
248260
node: machinecontroller.NodeSettings{
249-
ClusterDNSIPs: clusterDNSIPs,
250-
HTTPProxy: nodeHTTPProxy,
251-
NoProxy: nodeNoProxy,
252-
HyperkubeImage: nodeHyperkubeImage,
253-
PauseImage: nodePauseImage,
261+
ClusterDNSIPs: clusterDNSIPs,
262+
HTTPProxy: nodeHTTPProxy,
263+
NoProxy: nodeNoProxy,
264+
HyperkubeImage: nodeHyperkubeImage,
265+
KubeletRepository: nodeKubeletRepository,
266+
PauseImage: nodePauseImage,
254267
},
255268
}
256269
if parsedJoinClusterTimeout != nil {

docs/network-restrictions.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,35 @@ If that image won't be accessible from the node, a custom image can be specified
2727
-node-pause-image="192.168.1.1:5000/kubernetes/pause:3.1"
2828
```
2929

30-
For ContainerLinux nodes the [hyperkube](https://github.com/kubernetes/kubernetes/tree/master/cluster/images/hyperkube) image must be accessible as well.
31-
This is due to the usage of the [kubelet-wrapper](https://github.com/coreos/coreos-kubernetes/blob/master/Documentation/kubelet-wrapper.md).
3230

33-
By default the image `k8s.gcr.io/hyperkube-amd64` will be used.
34-
If that image won't be accessible from the node, a custom image can be specified on the machine-controller:
31+
## Kubelet images
32+
33+
### CoreOS ContainerLinux
34+
For ContainerLinux nodes, the [hyperkube][1] image must be accessible as well. This is due to the usage of the
35+
[kubelet-wrapper][2].
36+
37+
By default the image `k8s.gcr.io/hyperkube-amd64` will be used. If that image won't be accessible from the node, a
38+
custom image can be specified on the machine-controller:
39+
```bash
40+
# Do not set a tag. The tag depends on the used Kubernetes version of a machine.
41+
# Example:
42+
# A Node using v1.14.2 would use 192.168.1.1:5000/kubernetes/hyperkube-amd64:v1.14.2
43+
-node-hyperkube-image="192.168.1.1:5000/kubernetes/hyperkube-amd64"
44+
```
45+
46+
### Flatcar Linux
47+
For Flatcar Linux nodes, the [hyperkube][1] or [kubelet][3] image must be accessible as well. This is due to the fact
48+
that kubelet is running as a docker container. For kubelet version `< 1.18` hyperkube will be used, otherwise `kubelet`
49+
image.
50+
51+
By default the image `quay.io/poseidon/kubelet` will be used. If that image won't be accessible from the node, a custom
52+
image can be specified on the machine-controller:
3553
```bash
3654
# Do not set a tag. The tag depends on the used Kubernetes version of a machine.
3755
# Example:
3856
# A Node using v1.14.2 would use 192.168.1.1:5000/kubernetes/hyperkube-amd64:v1.14.2
3957
-node-hyperkube-image="192.168.1.1:5000/kubernetes/hyperkube-amd64"
58+
-node-kubelet-image="192.168.1.1:5000/my-custom/kubelet-amd64"
4059
```
4160

4261
# Insecure registries
@@ -45,3 +64,7 @@ If nodes require access to insecure registries, all registries must be specified
4564
```bash
4665
--node-insecure-registries="192.168.1.1:5000,10.0.0.1:5000"
4766
```
67+
68+
[1]: https://console.cloud.google.com/gcr/images/google-containers/GLOBAL/hyperkube
69+
[2]: https://github.com/coreos/coreos-kubernetes/blob/master/Documentation/kubelet-wrapper.md
70+
[3]: https://quay.io/poseidon/kubelet

pkg/apis/plugin/plugin.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type UserDataRequest struct {
5252
RegistryMirrors []string
5353
PauseImage string
5454
HyperkubeImage string
55+
KubeletRepository string
5556
}
5657

5758
// UserDataResponse contains the responded user data.

pkg/controller/machine/machine.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,10 @@ type NodeSettings struct {
124124
RegistryMirrors []string
125125
// Translates to --pod-infra-container-image on the kubelet. If not set, the kubelet will default it.
126126
PauseImage string
127-
// The hyperkube image to use. Currently only Container Linux uses it.
127+
// The hyperkube image to use. Currently only Container Linux and Flatcar Linux uses it.
128128
HyperkubeImage string
129+
// The kubelet repository to use. Currently only Flatcar Linux uses it.
130+
KubeletRepository string
129131
}
130132

131133
type KubeconfigProvider interface {
@@ -666,6 +668,7 @@ func (r *Reconciler) ensureInstanceExistsForMachine(
666668
RegistryMirrors: r.nodeSettings.RegistryMirrors,
667669
PauseImage: r.nodeSettings.PauseImage,
668670
HyperkubeImage: r.nodeSettings.HyperkubeImage,
671+
KubeletRepository: r.nodeSettings.KubeletRepository,
669672
NoProxy: r.nodeSettings.NoProxy,
670673
HTTPProxy: r.nodeSettings.HTTPProxy,
671674
}

pkg/userdata/flatcar/provider.go

Lines changed: 64 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ package flatcar
2323
import (
2424
"bytes"
2525
"fmt"
26-
"strings"
2726
"text/template"
2827

2928
"github.com/Masterminds/semver"
@@ -33,12 +32,15 @@ import (
3332
userdatahelper "github.com/kubermatic/machine-controller/pkg/userdata/helper"
3433
)
3534

35+
const (
36+
lessThen118Check = "< 1.18"
37+
)
38+
3639
// Provider is a pkg/userdata/plugin.Provider implementation.
3740
type Provider struct{}
3841

3942
// UserData renders user-data template to string.
4043
func (p Provider) UserData(req plugin.UserDataRequest) (string, error) {
41-
4244
tmpl, err := template.New("user-data").Funcs(userdatahelper.TxtFuncMap()).Parse(userDataTemplate)
4345
if err != nil {
4446
return "", fmt.Errorf("failed to parse user-data template: %v", err)
@@ -73,37 +75,40 @@ func (p Provider) UserData(req plugin.UserDataRequest) (string, error) {
7375
return "", fmt.Errorf("error extracting cacert: %v", err)
7476
}
7577

76-
// We need to reconfigure rkt to allow insecure registries in case the hyperkube image comes from an insecure registry
77-
var insecureHyperkubeImage bool
78-
for _, registry := range req.InsecureRegistries {
79-
if strings.Contains(req.HyperkubeImage, registry) {
80-
insecureHyperkubeImage = true
81-
}
82-
}
83-
8478
if flatcarConfig.DisableAutoUpdate {
8579
flatcarConfig.DisableLocksmithD = true
8680
flatcarConfig.DisableUpdateEngine = true
8781
}
8882

83+
kubeletImage := req.KubeletRepository
84+
lessThen118, err := semver.NewConstraint(lessThen118Check)
85+
if err != nil {
86+
return "", err
87+
}
88+
89+
if lessThen118.Check(kubeletVersion) {
90+
kubeletImage = req.HyperkubeImage
91+
}
92+
kubeletImage = kubeletImage + ":v" + kubeletVersion.String()
93+
8994
data := struct {
9095
plugin.UserDataRequest
91-
ProviderSpec *providerconfigtypes.Config
92-
FlatcarConfig *Config
93-
Kubeconfig string
94-
KubernetesCACert string
95-
KubeletVersion string
96-
InsecureHyperkubeImage bool
97-
NodeIPScript string
96+
ProviderSpec *providerconfigtypes.Config
97+
FlatcarConfig *Config
98+
Kubeconfig string
99+
KubernetesCACert string
100+
KubeletImage string
101+
KubeletVersion string
102+
NodeIPScript string
98103
}{
99-
UserDataRequest: req,
100-
ProviderSpec: pconfig,
101-
FlatcarConfig: flatcarConfig,
102-
Kubeconfig: kubeconfigString,
103-
KubernetesCACert: kubernetesCACert,
104-
KubeletVersion: kubeletVersion.String(),
105-
InsecureHyperkubeImage: insecureHyperkubeImage,
106-
NodeIPScript: userdatahelper.SetupNodeIPEnvScript(),
104+
UserDataRequest: req,
105+
ProviderSpec: pconfig,
106+
FlatcarConfig: flatcarConfig,
107+
Kubeconfig: kubeconfigString,
108+
KubernetesCACert: kubernetesCACert,
109+
KubeletImage: kubeletImage,
110+
KubeletVersion: kubeletVersion.String(),
111+
NodeIPScript: userdatahelper.SetupNodeIPEnvScript(),
107112
}
108113
b := &bytes.Buffer{}
109114
err = tmpl.Execute(b, data)
@@ -164,7 +169,7 @@ systemd:
164169
Environment=ALL_PROXY={{ .HTTPProxy }}
165170
{{- end }}
166171
167-
- name: download-healthcheck-script.service
172+
- name: download-script.service
168173
enabled: true
169174
contents: |
170175
[Unit]
@@ -183,8 +188,8 @@ systemd:
183188
- name: 40-docker.conf
184189
contents: |
185190
[Unit]
186-
Requires=download-healthcheck-script.service
187-
After=download-healthcheck-script.service
191+
Requires=download-script.service
192+
After=download-script.service
188193
contents: |
189194
{{ containerRuntimeHealthCheckSystemdUnit | indent 10 }}
190195
@@ -194,8 +199,8 @@ systemd:
194199
- name: 40-docker.conf
195200
contents: |
196201
[Unit]
197-
Requires=download-healthcheck-script.service
198-
After=download-healthcheck-script.service
202+
Requires=download-script.service
203+
After=download-script.service
199204
contents: |
200205
{{ kubeletHealthCheckSystemdUnit | indent 10 }}
201206
@@ -227,38 +232,42 @@ systemd:
227232
MemoryAccounting=true
228233
EnvironmentFile=-/etc/environment
229234
EnvironmentFile=/etc/kubernetes/nodeip.conf
230-
{{- if .HTTPProxy }}
231-
Environment=KUBELET_IMAGE=docker://{{ .HyperkubeImage }}:v{{ .KubeletVersion }}
232-
{{- else }}
233-
Environment=KUBELET_IMAGE=docker://k8s.gcr.io/hyperkube-amd64:v{{ .KubeletVersion }}
234-
{{- end }}
235-
Environment="RKT_RUN_ARGS=--uuid-file-save=/var/cache/kubelet-pod.uuid \
236-
--inherit-env \
237-
--insecure-options=image{{if .InsecureHyperkubeImage }},http{{ end }} \
238-
--volume=resolv,kind=host,source=/etc/resolv.conf \
239-
--mount volume=resolv,target=/etc/resolv.conf \
240-
--volume cni-bin,kind=host,source=/opt/cni/bin \
241-
--mount volume=cni-bin,target=/opt/cni/bin \
242-
--volume cni-conf,kind=host,source=/etc/cni/net.d \
243-
--mount volume=cni-conf,target=/etc/cni/net.d \
244-
--volume etc-kubernetes,kind=host,source=/etc/kubernetes \
245-
--mount volume=etc-kubernetes,target=/etc/kubernetes \
246-
--volume var-log,kind=host,source=/var/log \
247-
--mount volume=var-log,target=/var/log \
248-
--volume var-lib-calico,kind=host,source=/var/lib/calico \
249-
--mount volume=var-lib-calico,target=/var/lib/calico"
235+
Environment=PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/opt/bin
250236
ExecStartPre=/bin/bash /opt/bin/setup_net_env.sh
251237
ExecStartPre=/bin/mkdir -p /var/lib/calico
252238
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
253239
ExecStartPre=/bin/mkdir -p /etc/cni/net.d
254240
ExecStartPre=/bin/mkdir -p /opt/cni/bin
255-
ExecStartPre=-/usr/bin/rkt rm --uuid-file=/var/cache/kubelet-pod.uuid
256-
ExecStartPre=-/bin/rm -rf /var/lib/rkt/cas/tmp/
257241
ExecStartPre=/bin/bash /opt/load-kernel-modules.sh
258-
ExecStart=/usr/lib/flatcar/kubelet-wrapper \
259-
{{ if semverCompare ">=1.17.0" .KubeletVersion }}{{ print " kubelet \\\n" }}{{ end -}}
242+
ExecStartPre=/bin/sh -c '/usr/bin/env > /tmp/environment'
243+
ExecStart=/usr/bin/docker run --name %n \
244+
--rm --tty --restart no \
245+
--network host \
246+
--pid host \
247+
--env-file /tmp/environment \
248+
--privileged \
249+
--cgroup-parent system.slice \
250+
--entrypoint kubelet \
251+
-v /dev:/dev \
252+
-v /etc/cni/net.d:/etc/cni/net.d \
253+
-v /etc/kubernetes:/etc/kubernetes \
254+
-v /etc/machine-id:/etc/machine-id:ro \
255+
-v /etc/os-release:/etc/os-release:ro \
256+
-v /etc/resolv.conf:/etc/resolv.conf:ro \
257+
-v /lib/modules:/lib/modules \
258+
-v /mnt:/mnt:rshared \
259+
-v /opt/cni/bin:/opt/cni/bin:ro \
260+
-v /run:/run \
261+
-v /sys:/sys \
262+
-v /usr/sbin/iscsiadm:/usr/sbin/iscsiadm \
263+
-v /var/lib/calico:/var/lib/calico:ro \
264+
-v /var/lib/cni:/var/lib/cni \
265+
-v /var/lib/docker:/var/lib/docker \
266+
-v /var/lib/kubelet:/var/lib/kubelet:rshared \
267+
-v /var/log/pods:/var/log/pods \
268+
{{ .KubeletImage }} \
260269
{{ kubeletFlags .KubeletVersion .CloudProviderName .MachineSpec.Name .DNSIPs .ExternalCloudProvider .PauseImage .MachineSpec.Taints | indent 10 }}
261-
ExecStop=-/usr/bin/rkt stop --uuid-file=/var/cache/kubelet-pod.uuid
270+
ExecStop=-/usr/bin/docker stop %n
262271
Restart=always
263272
RestartSec=10
264273
[Install]

pkg/userdata/flatcar/provider_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ type userDataTestCase struct {
109109
registryMirrors []string
110110
pauseImage string
111111
hyperkubeImage string
112+
kubeletImage string
112113
}
113114

114115
// TestUserDataGeneration runs the data generation for different
@@ -145,6 +146,39 @@ func TestUserDataGeneration(t *testing.T) {
145146
osConfig: &Config{
146147
DisableAutoUpdate: true,
147148
},
149+
hyperkubeImage: "for-kubernetes-less-then-1.18/hyperkubeImage",
150+
kubeletImage: "for-kubernetes-more-then-1.18/kubeletImage",
151+
},
152+
{
153+
name: "v1.18.0",
154+
providerSpec: &providerconfigtypes.Config{
155+
CloudProvider: "vsphere",
156+
SSHPublicKeys: []string{"ssh-rsa AAABBB", "ssh-rsa CCCDDD"},
157+
Network: &providerconfigtypes.NetworkConfig{
158+
CIDR: "192.168.81.4/24",
159+
Gateway: "192.168.81.1",
160+
DNS: providerconfigtypes.DNSConfig{
161+
Servers: []string{"8.8.8.8"},
162+
},
163+
},
164+
},
165+
spec: clusterv1alpha1.MachineSpec{
166+
ObjectMeta: metav1.ObjectMeta{Name: "node1"},
167+
Versions: clusterv1alpha1.MachineVersionInfo{
168+
Kubelet: "v1.18.0",
169+
},
170+
},
171+
ccProvider: &fakeCloudConfigProvider{
172+
name: "vsphere",
173+
config: "{vsphere-config:true}",
174+
err: nil,
175+
},
176+
DNSIPs: []net.IP{net.ParseIP("10.10.10.10")},
177+
osConfig: &Config{
178+
DisableAutoUpdate: true,
179+
},
180+
hyperkubeImage: "for-kubernetes-less-then-1.18/hyperkubeImage",
181+
kubeletImage: "for-kubernetes-more-then-1.18/kubeletImage",
148182
},
149183
}
150184

@@ -188,6 +222,7 @@ func TestUserDataGeneration(t *testing.T) {
188222
RegistryMirrors: test.registryMirrors,
189223
PauseImage: test.pauseImage,
190224
HyperkubeImage: test.hyperkubeImage,
225+
KubeletRepository: test.kubeletImage,
191226
}
192227

193228
s, err := provider.UserData(req)

0 commit comments

Comments
 (0)