├── resources ├── generate-talos-config-secret │ ├── serviceaccount.yaml │ ├── role.yaml │ ├── kustomization.yaml │ ├── rolebinding.yaml │ └── job.yaml ├── bootstrap │ ├── kustomization.yaml │ └── job.yaml ├── node │ ├── worker │ │ ├── kustomization.yaml │ │ └── deployment.yaml │ ├── controlplane │ │ ├── kustomization.yaml │ │ ├── service.yaml │ │ └── statefulset.yaml │ └── common │ │ └── kustomization.yaml └── cluster │ └── kustomization.yaml ├── components ├── debug │ ├── README.md │ └── kustomization.yaml └── etcd-restore │ ├── README.md │ └── kustomization.yaml └── README.md /resources/generate-talos-config-secret/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: generate-talos-config-secret 5 | -------------------------------------------------------------------------------- /resources/bootstrap/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - job.yaml 6 | 7 | labels: 8 | - includeSelectors: true 9 | pairs: 10 | app.kubernetes.io/component: bootstrap 11 | -------------------------------------------------------------------------------- /resources/generate-talos-config-secret/role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | name: generate-talos-config-secret 5 | rules: 6 | - apiGroups: 7 | - "" 8 | resources: 9 | - secrets 10 | verbs: 11 | - create 12 | -------------------------------------------------------------------------------- /components/debug/README.md: -------------------------------------------------------------------------------- 1 | # debug component 2 | 3 | This component adds debug logging to tink nodes. 4 | 5 | ## Usage 6 | 7 | Add the component to your Kustomization: 8 | 9 | ```bash 10 | kustomize edit add component github.com/bzub/tink/component/debug 11 | ``` 12 | -------------------------------------------------------------------------------- /resources/node/worker/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - deployment.yaml 6 | 7 | labels: 8 | - includeSelectors: true 9 | pairs: 10 | app.kubernetes.io/name: talos 11 | app.kubernetes.io/component: node 12 | node-role.kubernetes.io/worker: "" 13 | -------------------------------------------------------------------------------- /resources/generate-talos-config-secret/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - job.yaml 6 | - role.yaml 7 | - rolebinding.yaml 8 | - serviceaccount.yaml 9 | 10 | labels: 11 | - includeSelectors: true 12 | pairs: 13 | app.kubernetes.io/component: generate-talos-config-secret 14 | -------------------------------------------------------------------------------- /resources/node/controlplane/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - statefulset.yaml 6 | - service.yaml 7 | 8 | labels: 9 | - includeSelectors: true 10 | pairs: 11 | app.kubernetes.io/name: talos 12 | app.kubernetes.io/component: node 13 | node-role.kubernetes.io/control-plane: "" 14 | -------------------------------------------------------------------------------- /resources/generate-talos-config-secret/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: generate-talos-config-secret 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: generate-talos-config-secret 9 | subjects: 10 | - kind: ServiceAccount 11 | name: generate-talos-config-secret 12 | -------------------------------------------------------------------------------- /resources/node/controlplane/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: controlplane 5 | spec: 6 | type: ClusterIP 7 | clusterIP: None 8 | publishNotReadyAddresses: true 9 | ports: 10 | - name: kube-api 11 | port: 6443 12 | protocol: TCP 13 | targetPort: 6443 14 | - name: talos-api 15 | port: 50000 16 | protocol: TCP 17 | targetPort: 50000 18 | -------------------------------------------------------------------------------- /resources/node/worker/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: worker 5 | spec: 6 | template: 7 | spec: 8 | initContainers: [] 9 | containers: 10 | - name: talos 11 | env: 12 | - name: USERDATA 13 | valueFrom: 14 | secretKeyRef: 15 | name: mycluster 16 | key: worker-base64 17 | volumeMounts: 18 | - name: talos-config 19 | mountPath: /talos-config 20 | volumes: 21 | - name: talos-config 22 | secret: 23 | secretName: tink 24 | items: 25 | - key: worker.yaml 26 | path: config.yaml 27 | - key: talosconfig 28 | path: talosconfig 29 | optional: false 30 | -------------------------------------------------------------------------------- /resources/bootstrap/job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: bootstrap 5 | spec: 6 | template: 7 | spec: 8 | restartPolicy: OnFailure 9 | containers: 10 | - name: bootstrap 11 | image: ghcr.io/siderolabs/talosctl 12 | args: 13 | - --talosconfig=/talos/config 14 | - --endpoints=$(CONTROLPLANE_SERVICE_FQDN) 15 | - --nodes=$(CONTROLPLANE_SERVICE_FQDN) 16 | - bootstrap 17 | envFrom: 18 | - configMapRef: 19 | name: config 20 | volumeMounts: 21 | - name: talos-config 22 | mountPath: /talos 23 | volumes: 24 | - name: talos-config 25 | secret: 26 | secretName: tink 27 | optional: false 28 | items: 29 | - key: talosconfig 30 | path: config 31 | -------------------------------------------------------------------------------- /resources/node/controlplane/statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: controlplane 5 | spec: 6 | serviceName: controlplane 7 | template: 8 | spec: 9 | subdomain: controlplane 10 | initContainers: [] 11 | containers: 12 | - name: talos 13 | env: 14 | - name: USERDATA 15 | valueFrom: 16 | secretKeyRef: 17 | name: mycluster 18 | key: controlplane-base64 19 | ports: 20 | - containerPort: 6443 21 | name: kube-api 22 | volumes: 23 | - name: talos-config 24 | secret: 25 | secretName: tink 26 | items: 27 | - key: controlplane.yaml 28 | path: config.yaml 29 | - key: talosconfig 30 | path: talosconfig 31 | optional: false 32 | -------------------------------------------------------------------------------- /components/debug/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | patches: 5 | - target: 6 | group: apps 7 | version: v1 8 | labelselector: app.kubernetes.io/name=talos,app.kubernetes.io/component=node 9 | patch: |- 10 | apiVersion: apps/v1 11 | kind: SomeNode 12 | metadata: 13 | name: some-node 14 | spec: 15 | template: 16 | spec: 17 | containers: 18 | - name: talos 19 | env: 20 | - name: GODEBUG 21 | value: netdns=go+2,http2debug=1 22 | - target: 23 | group: batch 24 | version: v1 25 | kind: Job 26 | name: generate-talos-config-secret 27 | patch: |- 28 | - op: add 29 | path: /spec/template/spec/initContainers/0/args/- 30 | value: |- 31 | --config-patch= 32 | - op: add 33 | path: /debug 34 | value: true 35 | -------------------------------------------------------------------------------- /resources/cluster/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ../node/controlplane 6 | - ../node/worker 7 | - ../bootstrap 8 | - ../generate-talos-config-secret 9 | 10 | components: 11 | - ../node/common 12 | 13 | images: 14 | - name: ghcr.io/siderolabs/talos 15 | newTag: v1.7.6 16 | - name: ghcr.io/siderolabs/talosctl 17 | newTag: v1.7.6 18 | - name: docker.io/mikefarah/yq 19 | newTag: 4.44.3 20 | - name: docker.io/bitnami/kubectl 21 | newTag: 1.29.7 22 | 23 | labels: 24 | - includeSelectors: true 25 | pairs: 26 | app.kubernetes.io/name: talos 27 | app.kubernetes.io/instance: mycluster 28 | cluster.x-k8s.io/cluster-name: mycluster 29 | 30 | configMapGenerator: 31 | - name: config 32 | behavior: create 33 | literals: 34 | - CLUSTER_NAME=mycluster 35 | - CLUSTER_DOMAIN=mycluster.local 36 | - CONTROLPLANE_SERVICE_FQDN=controlplane 37 | - CONTROLPLANE_SERVICE_PORT=6443 38 | 39 | patches: 40 | - target: 41 | group: apps 42 | version: v1 43 | labelselector: app.kubernetes.io/name=talos,app.kubernetes.io/component=node 44 | patch: |- 45 | apiVersion: apps/v1 46 | kind: SomeNode 47 | metadata: 48 | name: some-node 49 | spec: 50 | template: 51 | spec: 52 | volumes: 53 | - name: talos-config 54 | secret: 55 | secretName: mycluster 56 | 57 | - target: 58 | group: batch 59 | version: v1 60 | name: bootstrap 61 | patch: |- 62 | apiVersion: batch/v1 63 | kind: Job 64 | metadata: 65 | name: bootstrap 66 | spec: 67 | template: 68 | spec: 69 | volumes: 70 | - name: talos-config 71 | secret: 72 | secretName: mycluster 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Talos in Kubernetes 2 | 3 | ## Prerequisites 4 | 5 | - A Kubernetes cluster. 6 | - `kustomize` build tool. 7 | - `talosctl` and `kubectl` 8 | - `jq` 9 | 10 | ## Quick Start 11 | 12 | Deploy a cluster with one control-plane node, one worker node, and default settings. 13 | ```sh 14 | kustomize build "github.com/bzub/tink/resources/cluster" | kubectl apply -f - 15 | ``` 16 | 17 | ### Interacting With The New Cluster 18 | 19 | Proxy the talos and kubernetes APIs to your local machine. 20 | ```sh 21 | kubectl port-forward svc/controlplane 50000:50000 & 22 | kubectl port-forward svc/controlplane 6443:6443 & 23 | ``` 24 | 25 | Get the talosconfig and kubeconfig for the cluster. 26 | ```sh 27 | kubectl get secret mycluster -o json |\ 28 | jq -r '.data["talosconfig"]|@base64d' > /tmp/talosconfig 29 | 30 | talosctl --talosconfig=/tmp/talosconfig \ 31 | config nodes localhost 32 | 33 | talosctl --talosconfig=/tmp/talosconfig \ 34 | config endpoint localhost 35 | 36 | talosctl --talosconfig /tmp/talosconfig -e localhost -n localhost \ 37 | kubeconfig --force --merge=false /tmp/kubeconfig 38 | 39 | kubectl --kubeconfig /tmp/kubeconfig \ 40 | config set-cluster mycluster --server=https://localhost:6443 41 | ``` 42 | 43 | Watch the health checks until the boot completes. Should only take a few 44 | minutes. Some errors when services are starting up are normal. 45 | ```sh 46 | talosctl --talosconfig=/tmp/talosconfig health 47 | ``` 48 | 49 | Now you can manage the cluster like any other Kubernetes workload. 50 | ```sh 51 | kubectl scale statefulset --replicas 3 controlplane 52 | ``` 53 | 54 | ### Cleanup 55 | 56 | To tear everything down kill the port-forward background jobs and delete the 57 | resources. 58 | ```sh 59 | kill %1 %2 60 | kustomize build "github.com/bzub/tink/resources/cluster" | kubectl delete -f - 61 | kubectl -n default delete secret mycluster 62 | ``` 63 | -------------------------------------------------------------------------------- /resources/node/common/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | patches: 4 | - target: 5 | group: apps 6 | version: v1 7 | patch: |- 8 | apiVersion: apps/v1 9 | kind: DoesNotMatter 10 | metadata: 11 | name: does-not-matter 12 | spec: 13 | template: 14 | spec: 15 | initContainers: [] 16 | containers: 17 | - name: talos 18 | image: ghcr.io/siderolabs/talos 19 | ports: 20 | - containerPort: 50000 21 | name: talos-api 22 | volumeMounts: 23 | - name: var 24 | mountPath: /var 25 | - name: var-lib-kubelet 26 | mountPath: /var/lib/kubelet 27 | - name: var-lib-containerd 28 | mountPath: /var/lib/containerd 29 | - name: var-lib-etcd 30 | mountPath: /var/lib/etcd 31 | - name: etc-cni 32 | mountPath: /etc/cni 33 | - name: etc-kubernetes 34 | mountPath: /etc/kubernetes 35 | - name: run 36 | mountPath: /run 37 | - name: system 38 | mountPath: /system 39 | - name: opt 40 | mountPath: /opt 41 | - name: talos-config 42 | mountPath: /talos-config 43 | - name: tmp 44 | mountPath: /tmp 45 | env: 46 | - name: PLATFORM 47 | value: container 48 | securityContext: 49 | privileged: true 50 | readOnlyRootFilesystem: true 51 | seccompProfile: 52 | type: Unconfined 53 | startupProbe: 54 | tcpSocket: 55 | port: 50000 56 | initialDelaySeconds: 30 57 | periodSeconds: 30 58 | timeoutSeconds: 2 59 | failureThreshold: 6 60 | successThreshold: 1 61 | livenessProbe: 62 | tcpSocket: 63 | port: 50000 64 | initialDelaySeconds: 0 65 | periodSeconds: 30 66 | timeoutSeconds: 2 67 | failureThreshold: 3 68 | successThreshold: 1 69 | volumes: 70 | - name: var 71 | - name: var-lib-kubelet 72 | - name: var-lib-containerd 73 | - name: var-lib-etcd 74 | - name: etc-cni 75 | - name: etc-kubernetes 76 | - name: run 77 | - name: system 78 | - name: opt 79 | - name: tmp 80 | 81 | - target: 82 | group: apps 83 | version: v1 84 | kind: Deployment 85 | patch: |- 86 | apiVersion: apps/v1 87 | kind: Deployment 88 | metadata: 89 | name: worker 90 | spec: 91 | template: 92 | spec: 93 | containers: 94 | - name: talos 95 | readinessProbe: 96 | tcpSocket: 97 | port: 50000 98 | initialDelaySeconds: 0 99 | periodSeconds: 30 100 | timeoutSeconds: 2 101 | failureThreshold: 3 102 | successThreshold: 1 103 | -------------------------------------------------------------------------------- /resources/generate-talos-config-secret/job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: generate-talos-config-secret 5 | spec: 6 | template: 7 | spec: 8 | serviceAccountName: generate-talos-config-secret 9 | restartPolicy: OnFailure 10 | volumes: 11 | - name: talos-config 12 | initContainers: 13 | - name: talos-gen-config 14 | workingDir: /talos-config 15 | image: ghcr.io/siderolabs/talosctl 16 | args: 17 | - gen 18 | - config 19 | - $(CLUSTER_NAME) 20 | - https://$(CONTROLPLANE_SERVICE_FQDN):$(CONTROLPLANE_SERVICE_PORT) 21 | - --with-docs=false 22 | - --with-examples=false 23 | - --with-cluster-discovery=false 24 | - --with-kubespan=false 25 | - --additional-sans="$(CONTROLPLANE_SERVICE_FQDN)" 26 | - --additional-sans="localhost" 27 | # See: https://www.talos.dev/v1.7/talos-guides/install/cloud-platforms/kubernetes/#machine-configuration 28 | - |- 29 | --config-patch= 30 | [ 31 | { 32 | "op":"add", 33 | "path":"/machine/features/hostDNS/forwardKubeDNSToHost", 34 | "value":true 35 | }, 36 | { 37 | "op":"add", 38 | "path":"/machine/features/hostDNS/resolveMemberNames", 39 | "value":true 40 | }, 41 | { 42 | "op":"add", 43 | "path":"/machine/features/kubePrism", 44 | "value": {"enabled": false} 45 | }, 46 | { 47 | "op":"replace", 48 | "path":"/cluster/network/podSubnets", 49 | "value": ["172.16.0.1/16"] 50 | }, 51 | { 52 | "op":"replace", 53 | "path":"/cluster/network/serviceSubnets", 54 | "value": ["172.17.0.1/16"] 55 | } 56 | ] 57 | - --dns-domain=$(CLUSTER_DOMAIN) 58 | envFrom: 59 | - configMapRef: 60 | name: config 61 | volumeMounts: 62 | - name: talos-config 63 | mountPath: /talos-config 64 | - name: base64-encode 65 | workingDir: /talos-config 66 | image: docker.io/library/alpine 67 | command: 68 | - sh 69 | - -ec 70 | - |- 71 | cat controlplane.yaml | base64 > controlplane-base64 72 | cat worker.yaml | base64 > worker-base64 73 | envFrom: 74 | - configMapRef: 75 | name: config 76 | volumeMounts: 77 | - name: talos-config 78 | mountPath: /talos-config 79 | containers: 80 | - name: kubectl-create-secret 81 | workingDir: /talos-config 82 | image: docker.io/bitnami/kubectl 83 | args: 84 | - create 85 | - secret 86 | - generic 87 | - $(CLUSTER_NAME) 88 | - --from-file=controlplane.yaml 89 | - --from-file=worker.yaml 90 | - --from-file=controlplane-base64 91 | - --from-file=worker-base64 92 | - --from-file=talosconfig 93 | envFrom: 94 | - configMapRef: 95 | name: config 96 | volumeMounts: 97 | - name: talos-config 98 | mountPath: /talos-config 99 | -------------------------------------------------------------------------------- /components/etcd-restore/README.md: -------------------------------------------------------------------------------- 1 | # Etcd Restore Component 2 | 3 | The `etcd-restore` component helps automate restoring from an [etcd database 4 | snapshot][etcd-snapshot]. 5 | 6 | ## Prerequisites 7 | 8 | - An etcd database snapshot on the computer that is accessing the cluster. 9 | - The sha512sum of the etcd database snapshot file. 10 | 11 | ## Configuration 12 | 13 | `etcd-restore` refers to a ConfigMap for user configuration. Check the 14 | component's `configMapGenerator` for all options and default values. 15 | 16 | ### Required Options 17 | 18 | The following keys are required. 19 | - `SNAPSHOT_SHA512SUM` 20 | - The sha512sum of the etcd database snapshot. Used to ensure the snapshot is 21 | valid before performing a restore. 22 | 23 | ## Demo 24 | 25 | ### Configure And Apply `etcd-restore` 26 | 27 | First let's get all the configuration in place to perform an etcd restore, and 28 | apply the resources. 29 | ```sh 30 | demo=$(mktemp -d) 31 | pushd $demo 32 | 33 | snapshot_file="/tmp/my-etcd-snapshot.db" 34 | snapshot_sha512sum="$(sha512sum "${snapshot_file}" | awk '{print $1}')" 35 | 36 | # Start with a base TinK cluster configuration. 37 | kustomize create --resources github.com/bzub/tink/resources/cluster 38 | 39 | # Add the etcd-restore component. 40 | kustomize edit add component github.com/bzub/tink/components/etcd-restore 41 | 42 | # Add some required options for etcd-restore. In this example the snapshot was 43 | # gathered from the data directory of an etcd member, so it doesn't contain a 44 | # built in hash unlike one gathered via `etcdctl snapshot save`. 45 | kustomize edit add configmap etcd-restore \ 46 | --behavior=merge \ 47 | --from-literal="SNAPSHOT_SHA512SUM=${snapshot_sha512sum}" \ 48 | --from-literal="SKIP_HASH_CHECK=true" 49 | 50 | kustomize build | kubectl apply -f - 51 | ``` 52 | 53 | ### Send The Database Snapshot To The Pod For Restore 54 | 55 | The `etcd-restore` component patches a TinK controlplane StatefulSet by adding 56 | `initContainers`. One of these containers waits for the user to send the etcd 57 | database snapshot to it, and the other performs the restore operation. 58 | 59 | ```sh 60 | kubectl cp "${snapshot_file}" controlplane-0:/etcd-snapshot/snapshot.db \ 61 | -c etcd-snapshot-upload-wait 62 | ``` 63 | 64 | The pod should now start a new etcd cluster using the database keys/values from 65 | the provided snapshot. 66 | 67 | ## HA Etcd Clusters 68 | 69 | The procedure for restoring an HA etcd cluster starts the same as the single 70 | node demo above. After one node is up and Ready you can add members like normal 71 | without the `etcd-restore` component. 72 | 73 | It is recommended to prevent changes to the first etcd member that was used for 74 | restore while the additional members join the cluster. To do this with TinK you 75 | can configure the controlplane StatefulSet with 76 | `spec.updateStrategy.rollingUpdate.partition` set to `1`. 77 | 78 | ```sh 79 | # Scale up the controlplane. 80 | kustomize edit set replicas controlplane=3 81 | 82 | # Spin up new controlplane nodes before applying changes to the restore node. 83 | kustomize edit add patch \ 84 | --kind=StatefulSet \ 85 | --version=v1 \ 86 | --label-selector=app.kubernetes.io/name=talos,app.kubernetes.io/component=node,node-role.kubernetes.io/control-plane= \ 87 | --patch="$(cat <<'EOF' 88 | - op: replace 89 | path: /spec/updateStrategy 90 | value: 91 | rollingUpdate: 92 | partition: 1 93 | EOF 94 | )" 95 | 96 | # Apply the configs. 97 | kustomize build | kubectl apply -f - 98 | ``` 99 | 100 | ## Post-Restore Cleanup 101 | 102 | Remove the `etcd-restore` component and `updateStrategy` patch from your 103 | `kustomization.yaml` and build/apply to get back to normal operations. 104 | 105 | [etcd-snapshot]: https://etcd.io/docs/v3.4/op-guide/recovery/#snapshotting-the-keyspace 106 | -------------------------------------------------------------------------------- /components/etcd-restore/kustomization.yaml: -------------------------------------------------------------------------------- 1 | kind: Component 2 | 3 | configMapGenerator: 4 | - name: etcd-restore 5 | literals: 6 | - SNAPSHOT_SHA512SUM= 7 | - SNAPSHOT_FILE=/etcd-snapshot/snapshot.db 8 | - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster 9 | - SKIP_HASH_CHECK=false 10 | - ETCD_DATA_DIR=/var/lib/etcd 11 | 12 | patches: 13 | - target: 14 | kind: StatefulSet 15 | version: v1 16 | labelselector: app.kubernetes.io/name=talos,app.kubernetes.io/component=node,node-role.kubernetes.io/control-plane= 17 | patch: |- 18 | - op: add 19 | path: /spec/template/spec/initContainers/- 20 | value: 21 | name: etcd-snapshot-upload-wait 22 | image: docker.io/library/alpine 23 | command: 24 | - sh 25 | - -ec 26 | - |- 27 | snapshot_file="${SNAPSHOT_FILE}" 28 | if [ -z "${snapshot_file}" ]; then 29 | echo "[ERROR] SNAPSHOT_FILE not set." 30 | exit 1 31 | fi 32 | 33 | snapshot_sha512sum="${SNAPSHOT_SHA512SUM}" 34 | if [ -z "${snapshot_sha512sum}" ]; then 35 | echo "[ERROR] SNAPSHOT_SHA512SUM not set." 36 | exit 1 37 | fi 38 | 39 | timeout=600 40 | inc=30 41 | time=0 42 | while [ ! -f "${snapshot_file}" ]; do 43 | echo "[INFO] Waiting for file \"${snapshot_file}\" - ${time}s/${timeout}s" 44 | sleep "${inc}s" 45 | time="$((time+inc))" 46 | if [ "${time}" -ge "${timeout}" ]; then 47 | echo "[ERROR] Timed out waiting for snapshot file." 48 | exit 1 49 | fi 50 | done 51 | echo "[INFO] Found file \"${snapshot_file}\"" 52 | 53 | echo "${snapshot_sha512sum} ${snapshot_file}" > /tmp/check 54 | while ! sha512sum -c /tmp/check; do 55 | echo "[INFO] ${time}s/${timeout}s" 56 | sleep "${inc}s" 57 | time="$((time+inc))" 58 | if [ "${time}" -ge "${timeout}" ]; then 59 | echo "[ERROR] Timed out waiting for snapshot file." 60 | exit 1 61 | fi 62 | done 63 | envFrom: 64 | - configMapRef: 65 | name: etcd-restore 66 | volumeMounts: 67 | - name: etcd-snapshot 68 | mountPath: /etcd-snapshot 69 | 70 | - op: add 71 | path: /spec/template/spec/initContainers/- 72 | value: 73 | name: etcdctl-restore 74 | image: gcr.io/etcd-development/etcd:v3.4.15 75 | command: 76 | - sh 77 | - -exc 78 | - |- 79 | etcdctl snapshot restore "${SNAPSHOT_FILE}" \ 80 | "--name=${POD_NAME}" \ 81 | "--initial-cluster=controlplane-0=https://${POD_IP}:2380" \ 82 | "--initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN}" \ 83 | "--initial-advertise-peer-urls=https://${POD_IP}:2380" \ 84 | "--skip-hash-check=${SKIP_HASH_CHECK}" \ 85 | "--data-dir=/etcd-restore" 86 | 87 | mv "/etcd-restore/member" "${ETCD_DATA_DIR}" 88 | env: 89 | - name: POD_NAME 90 | valueFrom: 91 | fieldRef: 92 | fieldPath: metadata.name 93 | - name: POD_IP 94 | valueFrom: 95 | fieldRef: 96 | fieldPath: status.podIP 97 | envFrom: 98 | - configMapRef: 99 | name: etcd-restore 100 | volumeMounts: 101 | - name: etcd-snapshot 102 | mountPath: /etcd-snapshot 103 | - name: var-lib-etcd 104 | mountPath: /var/lib/etcd 105 | 106 | - op: add 107 | path: /spec/template/spec/volumes/- 108 | value: 109 | name: etcd-snapshot 110 | 111 | - op: replace 112 | path: /spec/updateStrategy 113 | value: 114 | rollingUpdate: 115 | partition: 1 116 | --------------------------------------------------------------------------------