0

Creating Highly Available Clusters with kubeadm

Ở bài này chúng ta sẽ tiếp cận với external etcd cluster. Cách tiếp cận này yêu cầu nhiều về infrestruture. Control plane nodes và etcd members sẽ được tách ra. image.png

Chuẩn bị(tối thiểu)

  1. = 3 control plane nodes(HA)

  2. = worker nodes

  3. = etcd nodes

  4. có quyền root trên tất cả các nodes
  5. tất cả node phải có: container runtime, kubeadm, kubelet, network thông với nhau
  6. Cần có cơ sở hạ tầng để sao chép tập tin giữa các máy chủ. Ví dụ, ssh và scp có thể đáp ứng yêu cầu này.

Create load balancer for kube-apiserver

Vào AWS → EC2 → Load Balancers → Create Chọn:

  • Type: Network Load Balancer (NLB)

  • Scheme: Internet-facing (nếu public) hoặc internal

  • Cấu hình Listener: Protocol: TCPPort: 6443

  • Tạo Target Group Target type: Instances Protocol: TCP Port: 6443

    Add các node: control-plane-1 control-plane-2 control-plane-3

  • Health Check Protocol: TCP Port: 6443

  • Lấy DNS của NLB abc123.elb.amazonaws.com

  • Dùng trong kubeadm

kubeadm init \
  --control-plane-endpoint "abc123.elb.amazonaws.com:6443" \
  --upload-certs

Steps for the first control plane node

  1. Initialize the control plane:
sudo kubeadm init --control-plane-endpoint "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" --upload-certs
  • Bạn có thể dùng --kubernetes-version flag dùng để thiết lập version kubernetes cần dùng. Nên đảm bảo phiên bản của kubeadm, kubelet, kubectl và kubernetes phải tương thích.
  • Nếu mất key, hãy chạy lệnh sau để upload lại cert và sinh ra key mới
sudo kubeadm init phase upload-certs --upload-certs
  1. Cài CNI plugin

External etcd nodes

Set up the etcd cluster

Trước khi bắt đầu

  • cần có tối thiểu 3 hosts, chúng có thể giao tiếp với nhau qua TCP ports 2397 và 2380.
  • mỗi host phải có container runtime, kubelet và kubeadm.
  • Mỗi host chạy etcd phải pull được image từ registry Kubernetes, mặc định registry.k8s.io
  • etcd sẽ chạy dưới dạng Static Pod: Là pod được kubelet quản lý trực tiếp thông qua file manifest, Không cần API Server, Không cần scheduler, Chạy ngay khi kubelet đọc file. File thường nằm ở
/etc/kubernetes/manifests/

Setting up the cluster

Bạn chỉ tạo certificate trên 1 node duy nhất, sau đó copy các file cần thiết sang các node còn lại kubeadm làm hết:

  • Tạo CA
  • Sign certificate
  • Generate key
  • Tạo đúng format Kubernetes yêu cầu Kubelet sẽ đóng vai trò service manager để quản lý vòng đời của etcd. Điều này rất quan trọng vì etcd ở đây sẽ chạy dưới dạng static Pod, và kubelet là thành phần đọc file manifest để tự khởi động Pod đó.
  • kubelet sẽ giám sát tiến trình etcd.
  • Nếu etcd chết, kubelet sẽ tự khởi động lại.
  • Ta không cần cài thêm systemd service riêng cho etcd.
  • Đây là cách kubeadm hỗ trợ mô hình chạy etcd ổn định, đồng nhất.

Cấu hình kubelet

Lưu ý quan trọng

  • Bước này phải làm trên mọi host sẽ chạy etcd.
  • Vì etcd được tạo trước nên cần tạo một file unit mới có độ ưu tiên cao hơn file kubelet mặc định do kubeadm cung cấp
cat << EOF > /etc/systemd/system/kubelet.service.d/kubelet.conf
# Replace "systemd" with the cgroup driver of your container runtime. The default value in the kubelet is "cgroupfs".
# Replace the value of "containerRuntimeEndpoint" for a different container runtime if needed.
#
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: false
authorization:
  mode: AlwaysAllow
cgroupDriver: systemd
address: 127.0.0.1
containerRuntimeEndpoint: unix:///var/run/containerd/containerd.sock
staticPodPath: /etc/kubernetes/manifests
EOF

cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf
[Service]
ExecStart=
ExecStart=/usr/bin/kubelet --config=/etc/systemd/system/kubelet.service.d/kubelet.conf
Restart=always
EOF

systemctl daemon-reload
systemctl restart kubelet

Create configuration files for kubeadm

Sử dụng đoạn mã sau để tạo một tệp cấu hình kubeadm cho mỗi máy chủ sẽ chạy thành viên etcd.

# Update HOST0, HOST1 and HOST2 with the IPs of your hosts
export HOST0=10.0.0.6
export HOST1=10.0.0.7
export HOST2=10.0.0.8

# Update NAME0, NAME1 and NAME2 with the hostnames of your hosts
export NAME0="infra0"
export NAME1="infra1"
export NAME2="infra2"

# Create temp directories to store files that will end up on other hosts
mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/

HOSTS=(${HOST0} ${HOST1} ${HOST2})
NAMES=(${NAME0} ${NAME1} ${NAME2})

for i in "${!HOSTS[@]}"; do
HOST=${HOSTS[$i]}
NAME=${NAMES[$i]}
cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
---
apiVersion: "kubeadm.k8s.io/v1beta4"
kind: InitConfiguration
nodeRegistration:
    name: ${NAME}
localAPIEndpoint:
    advertiseAddress: ${HOST}
---
apiVersion: "kubeadm.k8s.io/v1beta4"
kind: ClusterConfiguration
etcd:
    local:
        serverCertSANs:
        - "${HOST}"
        peerCertSANs:
        - "${HOST}"
        extraArgs:
        - name: initial-cluster
          value: ${NAMES[0]}=https://${HOSTS[0]}:2380,${NAMES[1]}=https://${HOSTS[1]}:2380,${NAMES[2]}=https://${HOSTS[2]}:2380
        - name: initial-cluster-state
          value: new
        - name: name
          value: ${NAME}
        - name: listen-peer-urls
          value: https://${HOST}:2380
        - name: listen-client-urls
          value: https://${HOST}:2379
        - name: advertise-client-urls
          value: https://${HOST}:2379
        - name: initial-advertise-peer-urls
          value: https://${HOST}:2380
EOF
done

Tạo Certificate Authority (CA)

CA là gốc tin cậy để ký toàn bộ certificate của etcd. Nếu đã có CA

Nếu bạn đã có CA sẵn thì chỉ cần copy:

ca.crt ca.key

vào:

/etc/kubernetes/pki/etcd/ca.crt
/etc/kubernetes/pki/etcd/ca.key

Sau đó chuyển sang bước tạo certificate cho từng member.

Nếu chưa có CA

Chạy trên HOST0:

kubeadm init phase certs etcd-ca

Lệnh này tạo:

/etc/kubernetes/pki/etcd/ca.crt
/etc/kubernetes/pki/etcd/ca.key

Ý nghĩa ca.crt: public certificate của CA, dùng để xác thực. ca.key: private key của CA, chỉ giữ an toàn trên node tạo cert.

Tạo certificate cho từng member etcd

kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST2}/
# cleanup non-reusable certificates
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete

kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST1}/
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete

kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
# No need to move the certs because they are for HOST0

# clean up certs that should not be copied off this host
find /tmp/${HOST2} -name ca.key -type f -delete
find /tmp/${HOST1} -name ca.key -type f -delete

Chuyển certificate và kubeadm config sang từng host

USER=ubuntu
HOST=${HOST1}
scp -r /tmp/${HOST}/* ${USER}@${HOST}:
ssh ${USER}@${HOST}
USER@HOST $ sudo -Es
root@HOST $ chown -R root:root pki
root@HOST $ mv pki /etc/kubernetes/

Ensure all expected files exist.

The complete list of required files on $HOST0 is:

/tmp/${HOST0}
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
    ├── ca.crt
    ├── ca.key
    ├── healthcheck-client.crt
    ├── healthcheck-client.key
    ├── peer.crt
    ├── peer.key
    ├── server.crt
    └── server.key

On $HOST1, HOST2:

$HOME
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
    ├── ca.crt
    ├── healthcheck-client.crt
    ├── healthcheck-client.key
    ├── peer.crt
    ├── peer.key
    ├── server.crt
    └── server.key

Tạo static Pod manifest cho etcd

root@HOST0 $ kubeadm init phase etcd local --config=/tmp/${HOST0}/kubeadmcfg.yaml
root@HOST1 $ kubeadm init phase etcd local --config=$HOME/kubeadmcfg.yaml
root@HOST2 $ kubeadm init phase etcd local --config=$HOME/kubeadmcfg.yaml

set up SSH

Sao chép các tệp sau từ bất kỳ nút etcd nào trong cụm sang first control plane node:

export CONTROL_PLANE="ubuntu@10.0.0.7"
scp /etc/kubernetes/pki/etcd/ca.crt "${CONTROL_PLANE}":
scp /etc/kubernetes/pki/apiserver-etcd-client.crt "${CONTROL_PLANE}":
scp /etc/kubernetes/pki/apiserver-etcd-client.key "${CONTROL_PLANE}":

*Thay thế giá trị của CONTROL_PLANE bằng user@host của nút mặt phẳng điều khiển đầu tiên.

Set up the first control plane node

  1. Tạo một tệp có tên kubeadm-config.yaml với nội dung sau:
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" # change this (see below)
etcd:
  external:
    endpoints:
      - https://ETCD_0_IP:2379 # change ETCD_0_IP appropriately
      - https://ETCD_1_IP:2379 # change ETCD_1_IP appropriately
      - https://ETCD_2_IP:2379 # change ETCD_2_IP appropriately
    caFile: /etc/kubernetes/pki/etcd/ca.crt
    certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
    keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key

Sau khi bạn đã dựng xong external etcd cluster, bước tiếp theo gần giống với mô hình stacked etcd, nhưng có một khác biệt rất quan trọng: Control plane sẽ kết nối tới external etcd thay vì tự chạy etcd nội bộ

sudo kubeadm init --config kubeadm-config.yaml --upload-certs

Copy certificate giữa các control plane nodes (HA control plane)

  1. Khởi động ssh-agent để quản lý private key
eval $(ssh-agent)
  1. Thêm private key
ssh-add ~/.ssh/path_to_private_key
  1. Khi dùng sudo
sudo -E -s

-E giữ environment → giữ SSH forwarding

  1. Copy certificate từ control plane đầu tiên
USER=ubuntu
CONTROL_PLANE_IPS="10.0.0.7 10.0.0.8"

for host in ${CONTROL_PLANE_IPS}; do
    scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
    scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
    scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
    scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
    scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
    scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
    scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt

    # ❗ Skip nếu dùng external etcd
    scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
done
  1. Di chuyển certificate trên node mới
USER=ubuntu

mkdir -p /etc/kubernetes/pki/etcd

mv /home/${USER}/ca.crt /etc/kubernetes/pki/
mv /home/${USER}/ca.key /etc/kubernetes/pki/
mv /home/${USER}/sa.pub /etc/kubernetes/pki/
mv /home/${USER}/sa.key /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt

# ❗ Skip nếu dùng external etcd
mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
  1. Luồng đúng sau bước này

Control Plane 1 (init xong) ↓ Copy cert ↓ Control Plane 2,3 (có CA + key) ↓ kubeadm join --control-plane


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí