Skip to content

Commit 289fbe3

Browse files
Merge pull request #5 from kairos-io/multi-node-fixes
Added fixes for reconfiguring calico and dqlite for multinode clusters
2 parents 9e4bb1d + 96bcf5c commit 289fbe3

File tree

8 files changed

+133
-17
lines changed

8 files changed

+133
-17
lines changed

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,23 @@ This provider will configure a Microk8s installation based on the cluster sectio
2525
`writeKubeconfig`: "/run/kubeconfig"
2626
2727
# Switch dqlite to use the internal IP of the Node instead of the 127.0.0.1
28-
`dqliteUseHostIPV4Addres`: true
28+
`dqliteUseHostIPV4Address`: true
2929
3030
# Uses the DNS server entries from the host for the coredns configuration(reads from /etc/resolv.conf)
3131
`useHostDNS`: true
3232
3333
# Specifies custom DNs server. Overrides the previous setting
3434
`DNS` : 75.75.74.74
35+
# Customize calico settings
36+
`calico`:
37+
# Enable IpinIP
38+
`calicoIPinIP`: true
39+
# Change the calico IP_AUTODETECTION_METHOD env . By default When forming a MicroK8s cluster, Calico is updated to use address that was used in the microk8s join command (IP_AUTODETECTION_METHOD=can-reach=10.10.10.10)
40+
`calicoAutoDetect`: "cidr=10.10.128.0/18"
3541
- `initConfiguration`: Configuration only for the init node
36-
37-
addons:
38-
- dns
42+
43+
addons:
44+
- dns
3945

4046
### Example
4147
```yaml
@@ -52,6 +58,9 @@ cluster:
5258
writeKubeconfig: "/run/kubeconfig"
5359
dqliteUseHostIPV4Address: true
5460
useHostDNS: true
61+
calico:
62+
calicoIPinIP: true
63+
calicoAutoDetect: "cidr=10.10.128.0/18"
5564
initConfiguration:
5665
addons:
5766
- dns

main.go

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ const (
2020
scriptBasePath = "/opt/microk8s/scripts/"
2121
installMicrok8sScript = "00-install-microk8s.sh"
2222
upgradeMicrok8sScript = "00-upgrade-microk8s.sh"
23-
configureApiServerScript = "10-configure-apiserver.sh"
23+
// configureApiServerScript = "10-configure-apiserver.sh"
24+
configureAltNamesScript = "10-configure-alt-names.sh"
2425
configureCPKubeletScript = "10-configure-cp-kubelet.sh"
26+
configureCalicoScript = "10-configure-calico.sh"
2527
configureClusterAgentPortScript = "10-configure-cluster-agent-port.sh"
2628
configureDqlitePortScript = "10-configure-dqlite-port.sh"
2729
configureDqliteAddressScript = "10-configure-dqlite-address.sh"
@@ -88,12 +90,14 @@ func generateInitStages(cluster clusterplugin.Cluster, token string, userConfig
8890
var installCommands []string
8991
var upgradeCommands []string
9092
installCommands = getBaseInstallCommands(cluster, token, installCommands)
93+
calicoConfigCommand := addCalicoConfigCommands(userConfig)
94+
installCommands = append(installCommands,fmt.Sprintf("%s %v", calicoConfigCommand, true))
95+
9196
// figure out endpoint type
9297
endpointType := "DNS"
9398
if net.ParseIP(cluster.ControlPlaneHost) != nil {
9499
endpointType = "IP"
95100
}
96-
installCommands = append(installCommands, fmt.Sprintf("%s %q %q", scriptPath(configureApiServerScript), endpointType, cluster.ControlPlaneHost))
97101

98102
if userConfig.ClusterConfiguration.PortCompatibilityRemap {
99103
installCommands = append(installCommands, fmt.Sprintf("%s %q", scriptPath(configureClusterAgentPortScript), remappedClusterAgentPort))
@@ -105,14 +109,17 @@ func generateInitStages(cluster clusterplugin.Cluster, token string, userConfig
105109

106110
// add the bootstrap token
107111
installCommands = append(installCommands, fmt.Sprintf("microk8s add-node --token-ttl %v --token %q", tokenTTL, token))
108-
installCommands = append(installCommands, scriptPath(configureCPKubeletScript))
109112
installCommands = append(installCommands, fmt.Sprintf("%s %v %q", scriptPath(configureDNSScript), userConfig.ClusterConfiguration.UseHostDNS, userConfig.ClusterConfiguration.DNS))
113+
installCommands = append(installCommands, fmt.Sprintf("%s %q %q", scriptPath(configureAltNamesScript), endpointType, cluster.ControlPlaneHost))
110114

111115
addons := parseAddons(userConfig)
112116
installCommands = append(installCommands, fmt.Sprintf("%s %s", scriptPath(microk8sEnableScript), strings.Join(addons, " ")))
117+
installCommands = append(installCommands, scriptPath(configureCPKubeletScript))
118+
113119
writeKubeConfigCommand := fmt.Sprintf("%s %s", scriptPath(microk8sKubeConfigScript), userConfig.ClusterConfiguration.WriteKubeconfig)
114120
installCommands = append(installCommands, writeKubeConfigCommand)
115121
upgradeCommands = append(upgradeCommands, scriptPath(upgradeMicrok8sScript))
122+
upgradeCommands = append(upgradeCommands,fmt.Sprintf("%s %v", calicoConfigCommand, false))
116123
upgradeCommands = append(upgradeCommands, writeKubeConfigCommand)
117124

118125
return []yip.Stage{
@@ -129,19 +136,22 @@ func generateInitStages(cluster clusterplugin.Cluster, token string, userConfig
129136
}
130137
}
131138

139+
140+
132141
func generateControlPlaneJoinStages(cluster clusterplugin.Cluster, token string, userConfig MicroK8sSpec) []yip.Stage {
133142
var installCommands []string
134143
var upgradeCommands []string
135144
var clusterAgentPort string = defaultClusterAgentPort
136145

137146
installCommands = getBaseInstallCommands(cluster, token, installCommands)
147+
calicoConfigCommand := addCalicoConfigCommands(userConfig)
148+
installCommands = append(installCommands, fmt.Sprintf("%s %v", calicoConfigCommand, false))
149+
138150
// figure out endpoint type
139151
endpointType := "DNS"
140152
if net.ParseIP(cluster.ControlPlaneHost) != nil {
141153
endpointType = "IP"
142154
}
143-
installCommands = append(installCommands, fmt.Sprintf("%s %q %q", scriptPath(configureApiServerScript), endpointType, cluster.ControlPlaneHost))
144-
145155
if userConfig.ClusterConfiguration.PortCompatibilityRemap {
146156
clusterAgentPort = remappedClusterAgentPort
147157
installCommands = append(installCommands, fmt.Sprintf("%s %q", scriptPath(configureClusterAgentPortScript), remappedClusterAgentPort))
@@ -150,14 +160,20 @@ func generateControlPlaneJoinStages(cluster clusterplugin.Cluster, token string,
150160
if userConfig.ClusterConfiguration.DqliteUseHostIPV4Address {
151161
installCommands = append(installCommands, scriptPath(configureDqliteAddressScript))
152162
}
153-
installCommands = append(installCommands, scriptPath(configureCPKubeletScript))
154163
// add join command
155164
installCommands = append(installCommands, fmt.Sprintf("%s %q", scriptPath(microk8sJoinScript), fmt.Sprintf("%s:%s/%s", cluster.ControlPlaneHost, clusterAgentPort, token)))
165+
//configure after join
166+
installCommands = append(installCommands, fmt.Sprintf("%s %q %q", scriptPath(configureAltNamesScript), endpointType, cluster.ControlPlaneHost))
167+
156168
// add the bootstrap token
157169
installCommands = append(installCommands, fmt.Sprintf("microk8s add-node --token-ttl %v --token %q", tokenTTL, token))
170+
// label after join
171+
installCommands = append(installCommands, scriptPath(configureCPKubeletScript))
158172
installCommands = append(installCommands, fmt.Sprintf("%s %s", scriptPath(microk8sKubeConfigScript), userConfig.ClusterConfiguration.WriteKubeconfig))
159173

160174
upgradeCommands = append(upgradeCommands, scriptPath(upgradeMicrok8sScript))
175+
upgradeCommands = append(upgradeCommands,fmt.Sprintf("%s %v", calicoConfigCommand, false))
176+
161177
return []yip.Stage{
162178

163179
{
@@ -172,13 +188,18 @@ func generateControlPlaneJoinStages(cluster clusterplugin.Cluster, token string,
172188
},
173189
}
174190
}
191+
175192
func generateWorkerJoinStages(cluster clusterplugin.Cluster, token string, userConfig MicroK8sSpec) []yip.Stage {
176193

177194
var installCommands []string
178195
var upgradeCommands []string
179196
var clusterAgentPort string = defaultClusterAgentPort
180197

181198
installCommands = getBaseInstallCommands(cluster, token, installCommands)
199+
calicoConfigCommand := addCalicoConfigCommands(userConfig)
200+
installCommands = append(installCommands,fmt.Sprintf("%s %v", calicoConfigCommand, false))
201+
202+
182203
if userConfig.ClusterConfiguration.PortCompatibilityRemap {
183204
clusterAgentPort = remappedClusterAgentPort
184205
installCommands = append(installCommands, fmt.Sprintf("%s %q", scriptPath(configureClusterAgentPortScript), clusterAgentPort))
@@ -187,6 +208,7 @@ func generateWorkerJoinStages(cluster clusterplugin.Cluster, token string, userC
187208
installCommands = append(installCommands, fmt.Sprintf("%s %q --worker", scriptPath(microk8sJoinScript), fmt.Sprintf("%s:%s/%s", cluster.ControlPlaneHost, clusterAgentPort, token)))
188209

189210
upgradeCommands = append(upgradeCommands, scriptPath(upgradeMicrok8sScript))
211+
190212
return []yip.Stage{
191213

192214
{
@@ -220,6 +242,20 @@ func getBaseInstallCommands(cluster clusterplugin.Cluster, token string, install
220242

221243
return installCommands
222244
}
245+
func addCalicoConfigCommands(userConfig MicroK8sSpec) string {
246+
var calicoConfigCommand string
247+
248+
if userConfig.ClusterConfiguration.CalicoConfiguration != nil {
249+
// need to escape values like cidr for bash scripts
250+
var replacer = strings.NewReplacer(
251+
`/`, `\/`,
252+
)
253+
calicoConfig := userConfig.ClusterConfiguration.CalicoConfiguration
254+
calicoConfigCommand = fmt.Sprintf("%s %v %q", scriptPath(configureCalicoScript), calicoConfig.CalicoIPinIP, replacer.Replace(calicoConfig.CalicoAutoDetect))
255+
256+
}
257+
return calicoConfigCommand
258+
}
223259
func parseAddons(userConfig MicroK8sSpec) []string {
224260

225261
addons := make([]string, 0, len(userConfig.InitConfiguration.Addons))
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#!/bin/bash -xe
22

3+
packageVersion=$(snap info /opt/microk8s/snaps/microk8s.snap |grep "version:" | awk '{ print $2 }')
4+
channel=$(echo "${packageVersion%.*}" |cut -f2 -dv)
35
snap ack /opt/microk8s/snaps/core.assert
46
snap install /opt/microk8s/snaps/core.snap
57
snap ack /opt/microk8s/snaps/microk8s.assert
68
snap install --classic /opt/microk8s/snaps/microk8s.snap
9+
snap switch microk8s --channel=$channel/stable
710
microk8s status --wait-ready
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash -xe
2+
3+
# Usage:
4+
# $0 true/false <ip autodetect string> <Delete ip pools and ds,only true during init stage>
5+
#
6+
# Assumptions:
7+
# - microk8s is installed
8+
# - calico is installed
9+
# - the current node is not part of a cluster (yet)
10+
11+
if [[ "${1}" = "false" && "${2}" = "" ]]; then
12+
echo "Will not configure Calico"
13+
exit 0
14+
fi
15+
16+
CNI_YAML="/var/snap/microk8s/current/args/cni-network/cni.yaml"
17+
microk8s status --wait-ready
18+
# Stop calico-node and delete ippools to ensure no vxlan pools are left around.True only for first CP node during init install
19+
if [[ "${3}" == "true" ]]; then
20+
microk8s kubectl delete daemonset/calico-node -n kube-system || true
21+
microk8s kubectl delete ippools --all || true
22+
fi
23+
# Update cni.yaml manifest for IPIP
24+
if [[ "${1}" = "true" ]]; then
25+
sed 's/CALICO_IPV4POOL_VXLAN/CALICO_IPV4POOL_IPIP/' -i "${CNI_YAML}"
26+
sed 's/calico_backend: "vxlan"/calico_backend: "bird"/' -i "${CNI_YAML}"
27+
sed 's/-felix-ready/-bird-ready/' -i "${CNI_YAML}"
28+
sed 's/-felix-live/-bird-live/' -i "${CNI_YAML}"
29+
fi
30+
if [[ "${2}" != "" ]]; then
31+
sed "s/first-found/${2}/" -i "${CNI_YAML}"
32+
fi
33+
34+
# Apply the new manifest
35+
# (TODO): this should perhaps be a touch cni-needs-reload
36+
microk8s kubectl apply -f "${CNI_YAML}"

scripts/cloudinit/10-configure-cp-kubelet.sh

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
#KUBELET_ARGS="${KUBELET_ARGS:-/var/snap/microk8s/current/args/kubelet}"
44

5-
#sed -i 's/node-labels="\(.*\)"/node-labels="node.kubernetes.io\/controlplane=controlplane,\1"/g' "${KUBELET_ARGS}"
5+
#vi "${KUBELET_ARGS}"
66

77
#snap restart microk8s.daemon-kubelite
8-
#microk8s status --wait-ready
9-
NODE_NAME=$(microk8s kubectl get nodes -o json | jq -r .items[].metadata.name)
10-
microk8s kubectl label nodes $NODE_NAME node-role.kubernetes.io/control-plane=true
8+
microk8s status --wait-ready
9+
CP_NODE_NAMES=$(microk8s kubectl get nodes --selector='node.kubernetes.io/microk8s-controlplane' -o json | jq -r .items[].metadata.name)
10+
for i in $CP_NODE_NAMES
11+
do
12+
microk8s kubectl label nodes $i node-role.kubernetes.io/control-plane=true --overwrite=true
13+
done

scripts/cloudinit/10-configure-dqlite-address.sh

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,17 @@
1010
DQLITE="/var/snap/microk8s/current/var/kubernetes/backend"
1111

1212
microk8s status --wait-ready
13+
while ! NODES_JSON=$(microk8s kubectl get nodes -o json); do
14+
echo "Failed querying nodes, retrying"
15+
done
1316

14-
INTERNAL_IP=$(microk8s kubectl get nodes -o json | jq -r '.items[].status.addresses[] | select(.type=="InternalIP") | .address')
17+
INTERNAL_IP=$(echo "$NODES_JSON" | jq -r '.items[].status.addresses[] | select(.type=="InternalIP") | .address')
1518

1619

1720
grep "Address" "${DQLITE}/info.yaml" | sed "s/127.0.0.1/$INTERNAL_IP/" | tee "${DQLITE}/update.yaml"
1821

19-
snap restart microk8s.daemon-k8s-dqlite
22+
while ! snap restart microk8s.daemon-k8s-dqlite; do
23+
echo "Failed to restart microk8s, will retry"
24+
sleep 5
25+
done
26+

scripts/cloudinit/20-microk8s-join.sh

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,15 @@
1010
while ! microk8s join $@; do
1111
echo "Failed to join MicroK8s cluster, will retry"
1212
sleep 5
13-
done
13+
done
14+
# What is this hack? Why do we call snap set here?
15+
# "snap set microk8s ..." will call the configure hook.
16+
# The configure hook is where we sanitise arguments to k8s services.
17+
# When we join a node to a cluster the arguments of kubelet/api-server
18+
# are copied from the "control plane" node to the joining node.
19+
# It is possible some deprecated/removed arguments are copied over.
20+
# For example if we join a 1.24 node to 1.23 cluster arguments like
21+
# --network-plugin will cause kubelite to crashloop.
22+
# Threfore we call the conigure hook to clean things.
23+
# PS. This should be a workaround to a MicroK8s bug.
24+
snap set microk8s configure=call

types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ type ClusterConfiguration struct {
2323
UseHostDNS bool `json:"useHostDNS,omitempty"`
2424
// Use specified dns server
2525
DNS string `json:"dns,omitempty"`
26+
27+
CalicoConfiguration *CalicoConfiguration `json:"calico,omitempty"`
28+
2629
}
2730

2831
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@@ -44,3 +47,11 @@ type InitConfiguration struct {
4447
// List of addons to be enabled upon cluster creation
4548
Addons []string `json:"addons,omitempty"`
4649
}
50+
51+
type CalicoConfiguration struct {
52+
// Calico IPinIP
53+
CalicoIPinIP bool `json:"calicoIPinIP,omitempty"`
54+
55+
// Calico Autodetect
56+
CalicoAutoDetect string `json:"calicoAutoDetect,omitempty"`
57+
}

0 commit comments

Comments
 (0)