Skip to content

Commit d959819

Browse files
authored
Bootstrap first worker node. (#15)
1 parent bf28631 commit d959819

File tree

6 files changed

+179
-5
lines changed

6 files changed

+179
-5
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ test/external-crds
99
Dockerfile.cross
1010

1111
infrastructure-components.yaml
12+
.capms-cluster-kubeconfig.yaml
1213

1314
# Test binary, built with `go test -c`
1415
*.test

CONTRIBUTING.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,62 @@ A basic cluster configuration resides in `config/samples`.
2828
kubectl apply -k config/samples
2929
```
3030

31+
For now it is required to manually create the firewall. This might be changed in the future, but for now run:
32+
33+
```bash
34+
make -C capi-lab firewall
35+
# once the firewall is up run
36+
make -C capi-lab mtu-fix
37+
```
38+
39+
When the control plane node was provisioned, you can obtain the kubeconfig like:
40+
41+
```bash
42+
kubectl get secret metal-test-kubeconfig -o jsonpath='{.data.value}' | base64 -d > .capms-cluster-kubeconfig.yaml
43+
```
44+
45+
For now, the provider ID has to be manually added to the node object because we did not integrate the [metal-ccm](https://github.com/metal-stack/metal-ccm) yet:
46+
47+
```bash
48+
kubectl --kubeconfig=.capms-cluster-kubeconfig.yaml patch node <control-plane-node-name> --patch='{"spec":{"providerID": "metal://<machine-id>"}}'
49+
```
50+
51+
It is now expected to deploy a CNI to the cluster:
52+
53+
```bash
54+
kubectl --kubeconfig=.capms-cluster-kubeconfig.yaml create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.2/manifests/tigera-operator.yaml
55+
cat <<EOF | kubectl --kubeconfig=.capms-cluster-kubeconfig.yaml create -f -
56+
apiVersion: operator.tigera.io/v1
57+
kind: Installation
58+
metadata:
59+
name: default
60+
spec:
61+
# Configures Calico networking.
62+
calicoNetwork:
63+
bgp: Disabled
64+
ipPools:
65+
- name: default-ipv4-ippool
66+
blockSize: 26
67+
cidr: 192.168.0.0/16
68+
encapsulation: None
69+
mtu: 1440
70+
cni:
71+
ipam:
72+
type: HostLocal
73+
type: Calico
74+
EOF
75+
```
76+
77+
> [!note]
78+
> Actually, Calico should be configured using BGP (no overlay), eBPF and DSR. An example will be proposed in this repository at a later point in time.
79+
80+
As soon as the worker node was provisioned, the same provider ID patch as above is required:
81+
82+
```bash
83+
kubectl --kubeconfig=.capms-cluster-kubeconfig.yaml patch node <worker-node-name> --patch='{"spec":{"providerID": "metal://<machine-id>"}}'
84+
```
85+
86+
That's it!
3187

3288
### To Deploy on the cluster
3389
**Build and push your image to the location specified by `IMG`:**

capi-lab/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ controller:
3636

3737
.PHONY: firewall
3838
firewall:
39-
metalctl firewall create --description fw --name fw --hostname fw --project 00000000-0000-0000-0000-000000000001 --partition mini-lab --image firewall-ubuntu-3.0 --size v1-small-x86 --firewall-rules-file=firewall-rules.yaml --networks internet-mini-lab,$(shell docker compose run $(DOCKER_COMPOSE_RUN_ARG) metalctl network list --name metal-test -o template --template '{{ .id }}')
39+
metalctl firewall create --description fw --name fw --hostname fw --project 00000000-0000-0000-0000-000000000001 --partition mini-lab --image firewall-ubuntu-3.0 --size v1-small-x86 --firewall-rules-file=firewall-rules.yaml --networks internet-mini-lab,$(shell metalctl network list --name metal-test -o template --template '{{ .id }}')
40+
41+
.PHONY: mtu-fix
42+
mtu-fix:
43+
cd mini-lab && ssh -F files/ssh/config leaf01 'ip link set dev vtep-1001 mtu 9100 && echo done'
44+
cd mini-lab && ssh -F files/ssh/config leaf02 'ip link set dev vtep-1001 mtu 9100 && echo done'

config/samples/example-kubeadm.yaml

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ spec:
3939
image: ubuntu-24.04
4040
size: v1-small-x86
4141
---
42+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
43+
kind: MetalStackMachineTemplate
44+
metadata:
45+
name: metal-test-worker
46+
spec:
47+
template:
48+
spec:
49+
image: ubuntu-24.04
50+
size: v1-small-x86
51+
---
4252
kind: KubeadmControlPlane
4353
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
4454
metadata:
@@ -119,3 +129,104 @@ spec:
119129
permissions: "0644"
120130
content: |
121131
disabled_plugins = []
132+
---
133+
apiVersion: cluster.x-k8s.io/v1beta1
134+
kind: MachineDeployment
135+
metadata:
136+
name: metal-test-md-0
137+
labels:
138+
cluster.x-k8s.io/cluster-name: metal-test
139+
nodepool: nodepool-0
140+
spec:
141+
clusterName: metal-test
142+
replicas: 1
143+
selector:
144+
matchLabels:
145+
cluster.x-k8s.io/cluster-name: metal-test
146+
nodepool: nodepool-0
147+
template:
148+
metadata:
149+
labels:
150+
cluster.x-k8s.io/cluster-name: metal-test
151+
nodepool: nodepool-0
152+
spec:
153+
nodeDrainTimeout: 120s
154+
clusterName: metal-test
155+
version: "v1.30.6"
156+
bootstrap:
157+
configRef:
158+
name: metal-test-md-0
159+
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
160+
kind: KubeadmConfigTemplate
161+
infrastructureRef:
162+
name: metal-test-worker
163+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
164+
kind: MetalStackMachineTemplate
165+
---
166+
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
167+
kind: KubeadmConfigTemplate
168+
metadata:
169+
name: metal-test-md-0
170+
spec:
171+
template:
172+
spec:
173+
format: ignition
174+
clusterConfiguration:
175+
controlPlaneEndpoint: 203.0.113.129:443
176+
joinConfiguration:
177+
nodeRegistration: {}
178+
ignition:
179+
containerLinuxConfig:
180+
additionalConfig: |
181+
systemd:
182+
units:
183+
- name: cluster-api-init.service
184+
enable: true
185+
contents: |-
186+
[Unit]
187+
Description=Prepares the node for bootstrapping with cluster-api kubeadm
188+
Before=kubeadm.service
189+
After=network-online.target
190+
Wants=network-online.target
191+
[Service]
192+
Type=oneshot
193+
Restart=on-failure
194+
RestartSec=5
195+
StartLimitBurst=0
196+
EnvironmentFile=/etc/environment
197+
ExecStart=/var/lib/cluster-api-init/bootstrap.sh
198+
[Install]
199+
WantedBy=multi-user.target
200+
files:
201+
- path: /var/lib/cluster-api-init/bootstrap.sh
202+
owner: "root:root"
203+
permissions: "0744"
204+
content: |
205+
#!/usr/bin/env bash
206+
set -eo pipefail
207+
set +x
208+
209+
apt update
210+
apt install conntrack
211+
212+
CNI_PLUGINS_VERSION="v1.3.0"
213+
DEST="/opt/cni/bin"
214+
mkdir -p "$DEST"
215+
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-amd64-${CNI_PLUGINS_VERSION}.tgz" | tar -C "$DEST" -xz
216+
217+
RELEASE="v1.30.6"
218+
cd /usr/local/bin
219+
curl -L --remote-name-all https://dl.k8s.io/release/${RELEASE}/bin/linux/amd64/{kubeadm,kubelet,kubectl}
220+
chmod +x {kubeadm,kubelet,kubectl}
221+
222+
RELEASE_VERSION="v0.16.2"
223+
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/krel/templates/latest/kubelet/kubelet.service" | sed "s:/usr/bin:/usr/local/bin:g" | tee /usr/lib/systemd/system/kubelet.service
224+
mkdir -p /usr/lib/systemd/system/kubelet.service.d
225+
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/krel/templates/latest/kubeadm/10-kubeadm.conf" | sed "s:/usr/bin:/usr/local/bin:g" | tee /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
226+
227+
systemctl enable kubelet.service
228+
- path: /etc/containerd/config.toml
229+
owner: "root:root"
230+
permissions: "0644"
231+
content: |
232+
disabled_plugins = []

internal/controller/metalstackmachine_controller.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23+
"strings"
2324

2425
"golang.org/x/sync/errgroup"
2526
corev1 "k8s.io/api/core/v1"
@@ -230,7 +231,7 @@ func (r *machineReconciler) reconcile() error {
230231
return err
231232
}
232233

233-
r.infraMachine.Spec.ProviderID = *m.ID
234+
r.infraMachine.Spec.ProviderID = "metal://" + *m.ID
234235

235236
err = helper.Patch(r.ctx, r.infraMachine) // TODO:check whether patch is not executed when no changes occur
236237
if err != nil {
@@ -369,7 +370,7 @@ func (r *machineReconciler) status() error {
369370
conditions.MarkFalse(r.infraMachine, v1alpha1.ProviderMachineHealthy, "NotHealthy", clusterv1.ConditionSeverityWarning, "machine not created")
370371
conditions.MarkFalse(r.infraMachine, v1alpha1.ProviderMachineReady, "NotReady", clusterv1.ConditionSeverityWarning, "machine not created")
371372
default:
372-
if r.infraMachine.Spec.ProviderID == *m.ID {
373+
if r.infraMachine.Spec.ProviderID == "metal://"+*m.ID {
373374
conditions.MarkTrue(r.infraMachine, v1alpha1.ProviderMachineCreated)
374375
} else {
375376
conditions.MarkFalse(r.infraMachine, v1alpha1.ProviderMachineCreated, "NotSet", clusterv1.ConditionSeverityWarning, "provider id was not yet patched into the machine's spec")
@@ -455,7 +456,7 @@ func (r *machineReconciler) status() error {
455456

456457
func (r *machineReconciler) findProviderMachine() (*models.V1MachineResponse, error) {
457458
mfr := &models.V1MachineFindRequest{
458-
ID: r.infraMachine.Spec.ProviderID,
459+
ID: strings.TrimPrefix(r.infraMachine.Spec.ProviderID, "metal://"),
459460
AllocationProject: r.infraCluster.Spec.ProjectID,
460461
Tags: r.machineTags(),
461462
}

0 commit comments

Comments
 (0)