diff --git a/Dockerfile.d/u7s-entrypoint.sh b/Dockerfile.d/u7s-entrypoint.sh index 537707c..4927745 100755 --- a/Dockerfile.d/u7s-entrypoint.sh +++ b/Dockerfile.d/u7s-entrypoint.sh @@ -1,20 +1,7 @@ #!/bin/bash set -eux -o pipefail -# Append "---node-ip=${U7S_HOST_IP}" to "KUBELET_EXTRA_ARGS=..." in /etc/default/kubelet -sed -e "s/\(^KUBELET_EXTRA_ARGS=.*\)/\\1 --node-ip=${U7S_HOST_IP}/" /u7s-flanneld-wrapper.sh -#!/bin/sh -# Usage: /u7s-flanneld-wrapper.sh /opt/bin/flanneld --ip-masq --kube-subnet-mgr ... -# This script is expected to be mounted inside a "docker.io/flannel/flannel" container. -set -eux -"\$@" --public-ip="${U7S_HOST_IP}" -EOF -chmod +x /u7s-flanneld-wrapper.sh +# Append "KUBELET_EXTRA_ARGS=..." in /etc/default/kubelet +sed -e "s!\(^KUBELET_EXTRA_ARGS=.*\)!\\1 --cloud-provider=external --node-labels=usernetes/host-ip=${U7S_HOST_IP}!" kubeconfig + $(COMPOSE) exec -T $(NODE_SERVICE_NAME) sed -e "s/$(NODE_NAME)/localhost/g" /etc/kubernetes/admin.conf >kubeconfig @echo "# Run the following command by yourself:" @echo "export KUBECONFIG=$(shell pwd)/kubeconfig" ifeq ($(shell command -v kubectl 2> /dev/null),) @@ -98,19 +99,34 @@ kubectl: .PHONY: join-command join-command: - $(NODE_SHELL) kubeadm token create --print-join-command | tr -d '\r' >join-command - @echo "# Copy the 'join-command' file to another host, and run 'make kubeadm-join' on that host (not on this host)" + echo "#!/bin/bash" >join-command + echo "set -eux -o pipefail" >>join-command + echo "grep -q -w $(NODE_NAME) /etc/hosts || echo \"$(HOST_IP) $(NODE_NAME)\" >>/etc/hosts" >>join-command + $(NODE_SHELL) kubeadm token create --print-join-command | tr -d '\r' >>join-command + chmod +x join-command + @echo "# Copy the 'join-command' file to another host, and run the following commands:" + @echo "# On the other host (the new worker):" + @echo "# make kubeadm-join" + @echo "# On this host (the control plane):" + @echo "# make sync-external-ip" .PHONY: kubeadm-init kubeadm-init: $(NODE_SHELL) sh -euc "envsubst /tmp/kubeadm-config.yaml" $(NODE_SHELL) kubeadm init --config /tmp/kubeadm-config.yaml --skip-token-print + $(MAKE) sync-external-ip @echo "# Run 'make join-command' to print the join command" +.PHONY: sync-external-ip +sync-external-ip: + $(NODE_SHELL) /usernetes/Makefile.d/sync-external-ip.sh + .PHONY: kubeadm-join kubeadm-join: - $(NODE_SHELL) sh -euc '$$(cat /usernetes/join-command)' + $(NODE_SHELL) sh -euc "envsubst /tmp/kubeadm-config.yaml" + $(NODE_SHELL) /usernetes/join-command + @echo "# Run 'make sync-external-ip' on the control plane" .PHONY: install-flannel install-flannel: - $(NODE_SHELL) kubectl apply -f /usernetes/manifests/kube-flannel.yml + $(NODE_SHELL) kubectl apply -f https://github.com/flannel-io/flannel/releases/download/v0.24.4/kube-flannel.yml diff --git a/Makefile.d/sync-external-ip.sh b/Makefile.d/sync-external-ip.sh new file mode 100755 index 0000000..2b4e8be --- /dev/null +++ b/Makefile.d/sync-external-ip.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -eu -o pipefail + +for node in $(kubectl get nodes -o name); do + # Set ExternalIP + host_ip="$(kubectl get "${node}" -o jsonpath='{.metadata.labels.usernetes/host-ip}')" + kubectl patch "${node}" --type=merge --subresource status --patch \ + "\"status\": {\"addresses\": [{\"type\":\"ExternalIP\", \"address\": \"${host_ip}\"}]}" + + # Propagate ExternalIP to flannel + # https://github.com/flannel-io/flannel/blob/v0.24.4/Documentation/kubernetes.md#annotations + kubectl annotate "${node}" flannel.alpha.coreos.com/public-ip-overwrite=${host_ip} + + # Remove taints + taints="$(kubectl get "${node}" -o jsonpath='{.spec.taints}')" + if echo "${taints}" | grep -q node.cloudprovider.kubernetes.io/uninitialized; then + kubectl taint nodes "${node}" node.cloudprovider.kubernetes.io/uninitialized- + fi +done diff --git a/README.md b/README.md index c18726e..cd585a2 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ kubectl get pods -A make join-command scp join-command another-host:~/usernetes ssh another-host make -C ~/usernetes up kubeadm-join +make sync-external-ip # Debug make logs @@ -117,9 +118,6 @@ To change the container engine, set `export CONTAINER_ENGINE=podman` or `export - Most of host files are not visible with `hostPath` mounts. Edit [`docker-compose.yaml`](./docker-compose.yaml) for mounting additional files. - Some [volume drivers](https://kubernetes.io/docs/concepts/storage/volumes/) such as `nfs` do not work. - - diff --git a/hack/create-cluster-lxd.sh b/hack/create-cluster-lxd.sh index bc82d5f..e4c442f 100755 --- a/hack/create-cluster-lxd.sh +++ b/hack/create-cluster-lxd.sh @@ -25,8 +25,10 @@ $SSH host0 CONTAINER_ENGINE="${CONTAINER_ENGINE}" make -C ~/usernetes kubeadm-in # Let host1 join the cluster $SCP host0:~/usernetes/join-command host1:~/usernetes/join-command $SSH host1 CONTAINER_ENGINE="${CONTAINER_ENGINE}" make -C ~/usernetes kubeadm-join +$SSH host0 CONTAINER_ENGINE="${CONTAINER_ENGINE}" make -C ~/usernetes sync-external-ip # Enable kubectl +$SSH -fNT -L 6443:localhost:6443 $SCP host0:~/usernetes/kubeconfig ./kubeconfig KUBECONFIG="$(pwd)/kubeconfig" export KUBECONFIG diff --git a/kubeadm-config.yaml b/kubeadm-config.yaml index dd2d9e2..0817b1a 100644 --- a/kubeadm-config.yaml +++ b/kubeadm-config.yaml @@ -1,16 +1,19 @@ --- apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration -localAPIEndpoint: - advertiseAddress: "${U7S_HOST_IP}" - bindPort: 6443 --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration networking: serviceSubnet: "10.96.0.0/16" podSubnet: "10.244.0.0/16" -controlPlaneEndpoint: "${U7S_HOST_IP}:6443" +controlPlaneEndpoint: "${U7S_NODE_NAME}:6443" +apiServer: + certSANs: + - localhost + - 127.0.0.1 + - "${U7S_NODE_NAME}" + - "${U7S_HOST_IP}" --- kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 diff --git a/manifests/kube-flannel.yml b/manifests/kube-flannel.yml deleted file mode 100644 index a349311..0000000 --- a/manifests/kube-flannel.yml +++ /dev/null @@ -1,236 +0,0 @@ -# -# Forked from https://github.com/flannel-io/flannel/releases/download/v0.24.2/kube-flannel.yml , -# to specify a custom `--public-ip` value via `/u7s-flanneld-wrapper.sh. -# -apiVersion: v1 -kind: Namespace -metadata: - labels: - k8s-app: flannel - pod-security.kubernetes.io/enforce: privileged - name: kube-flannel ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - k8s-app: flannel - name: flannel - namespace: kube-flannel ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - k8s-app: flannel - name: flannel -rules: -- apiGroups: - - "" - resources: - - pods - verbs: - - get -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch -- apiGroups: - - networking.k8s.io - resources: - - clustercidrs - verbs: - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - k8s-app: flannel - name: flannel -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: flannel -subjects: -- kind: ServiceAccount - name: flannel - namespace: kube-flannel ---- -apiVersion: v1 -data: - cni-conf.json: | - { - "name": "cbr0", - "cniVersion": "0.3.1", - "plugins": [ - { - "type": "flannel", - "delegate": { - "hairpinMode": true, - "isDefaultGateway": true - } - }, - { - "type": "portmap", - "capabilities": { - "portMappings": true - } - } - ] - } - net-conf.json: | - { - "Network": "10.244.0.0/16", - "Backend": { - "Type": "vxlan" - } - } -kind: ConfigMap -metadata: - labels: - app: flannel - k8s-app: flannel - tier: node - name: kube-flannel-cfg - namespace: kube-flannel ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - app: flannel - k8s-app: flannel - tier: node - name: kube-flannel-ds - namespace: kube-flannel -spec: - selector: - matchLabels: - app: flannel - k8s-app: flannel - template: - metadata: - labels: - app: flannel - k8s-app: flannel - tier: node - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/os - operator: In - values: - - linux - containers: - - args: -# - - /opt/bin/flanneld -# - - --ip-masq - - --kube-subnet-mgr - command: -# - - /u7s-flanneld-wrapper.sh -# - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: EVENT_QUEUE_DEPTH - value: "5000" - image: docker.io/flannel/flannel:v0.24.2 - name: kube-flannel - resources: - requests: - cpu: 100m - memory: 50Mi - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - privileged: false - volumeMounts: - - mountPath: /run/flannel - name: run - - mountPath: /etc/kube-flannel/ - name: flannel-cfg - - mountPath: /run/xtables.lock - name: xtables-lock -# - - mountPath: /u7s-flanneld-wrapper.sh - name: u7s-flanneld-wrapper -# - hostNetwork: true - initContainers: - - args: - - -f - - /flannel - - /opt/cni/bin/flannel - command: - - cp - image: docker.io/flannel/flannel-cni-plugin:v1.4.0-flannel1 - name: install-cni-plugin - volumeMounts: - - mountPath: /opt/cni/bin - name: cni-plugin - - args: - - -f - - /etc/kube-flannel/cni-conf.json - - /etc/cni/net.d/10-flannel.conflist - command: - - cp - image: docker.io/flannel/flannel:v0.24.2 - name: install-cni - volumeMounts: - - mountPath: /etc/cni/net.d - name: cni - - mountPath: /etc/kube-flannel/ - name: flannel-cfg - priorityClassName: system-node-critical - serviceAccountName: flannel - tolerations: - - effect: NoSchedule - operator: Exists - volumes: - - hostPath: - path: /run/flannel - name: run - - hostPath: - path: /opt/cni/bin - name: cni-plugin - - hostPath: - path: /etc/cni/net.d - name: cni - - configMap: - name: kube-flannel-cfg - name: flannel-cfg - - hostPath: - path: /run/xtables.lock - type: FileOrCreate - name: xtables-lock -# - - hostPath: - path: /u7s-flanneld-wrapper.sh - name: u7s-flanneld-wrapper -#