Distributed Cloud Container Platform for Kubernetes (ACK One) allows you to use registered clusters to connect external Kubernetes clusters deployed in on-premises data centers or other cloud providers into Container Service for Kubernetes (ACK). This enables centralized management of clusters and resources, allowing rapid deployment of hybrid cloud environments. When computing resources in local data centers become constrained, you can create a node pool to scale out computing resources in the cloud, meeting dynamic business growth demands. This topic describes how to create custom scripts required to provision cloud node pools.
Prerequisites
An ACK One registered cluster is created and an external Kubernetes cluster deployed in an on-premises data center is connected to the ACK One registered cluster.
The network of the external Kubernetes cluster is connected to the virtual private cloud (VPC) of the ACK One registered cluster. For more information, see Scenario-based networking for VPC connections.
You must import the proxy configuration of the external Kubernetes cluster to the ACK One registered cluster in private network mode. For more information, see Associate an external Kubernetes cluster with an ACK One registered cluster.
Procedure
You can use a sample node script or create a custom script based on the actual environment and the conditions in the preceding figure.
The sample script supports only operating systems that use Yellowdog Updater, Modified (YUM) as the package manager.
Step 1 (A): Add Alibaba Cloud environment variables to a custom script
Check whether a node is a GPU-accelerated node. This step is optional.
You can use the following script to check whether an Elastic Compute Service (ECS) node is a GPU-accelerated node.
#!/bin/bash # Check whether Ispci is installed. if ! which lspci &>/dev/null; then yum -y install pciutils fi # Check whether the node is equipped with a GPU. if lspci | grep -i nvidia &>/dev/null; then echo "Install the relevant drivers because the node is a GPU-accelerated node." fiUnlike regular ECS nodes, you must install drivers and device plug-ins for GPU-accelerate nodes. For more information, see Manually update the NVIDIA driver of a node.
You must prepare a custom script to ensure that the node pool of the registered cluster can synchronize node status as normal for resource scheduling. The custom script needs to obtain environment variables issued by the registered cluster. The method used to obtain the environment variables depends on the way in which the external Kubernetes cluster is created. You can use the kubeadm or binary method to create a Kubernetes cluster.
The Kubernetes cluster is created by using the kubeadm method
The kubeadm method is recommended by Kubernetes, where Kubernetes clusters are set up using the official tool kubeadm. You must add the following content to the custom node script:
.... ####### <Add the following content. # Configure the node labels, taints, node name, and node provider ID. KUBELET_CONFIG_FILE="/etc/sysconfig/kubelet" if [[ $ALIBABA_CLOUD_LABELS != "" ]];then option="--node-labels" if grep -- "${option}=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@${option}=@${option}=${ALIBABA_CLOUD_LABELS},@g" $KUBELET_CONFIG_FILE elif grep "KUBELET_EXTRA_ARGS=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@KUBELET_EXTRA_ARGS=@KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_LABELS} @g" $KUBELET_CONFIG_FILE else sed -i "/^\[Service\]/a\Environment=\"KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_LABELS}\"" $KUBELET_CONFIG_FILE fi fi if [[ $ALIBABA_CLOUD_TAINTS != "" ]];then option="--register-with-taints" if grep -- "${option}=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@${option}=@${option}=${ALIBABA_CLOUD_TAINTS},@g" $KUBELET_CONFIG_FILE elif grep "KUBELET_EXTRA_ARGS=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@KUBELET_EXTRA_ARGS=@KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_TAINTS} @g" $KUBELET_CONFIG_FILE else sed -i "/^\[Service\]/a\Environment=\"KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_TAINTS}\"" $KUBELET_CONFIG_FILE fi fi if [[ $ALIBABA_CLOUD_NODE_NAME != "" ]];then option="--hostname-override" if grep -- "${option}=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@${option}=@${option}=${ALIBABA_CLOUD_NODE_NAME},@g" $KUBELET_CONFIG_FILE elif grep "KUBELET_EXTRA_ARGS=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@KUBELET_EXTRA_ARGS=@KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_NODE_NAME} @g" $KUBELET_CONFIG_FILE else sed -i "/^\[Service\]/a\Environment=\"KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_NODE_NAME}\"" $KUBELET_CONFIG_FILE fi fi if [[ $ALIBABA_CLOUD_PROVIDER_ID != "" ]];then option="--provider-id" if grep -- "${option}=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@${option}=@${option}=${ALIBABA_CLOUD_PROVIDER_ID},@g" $KUBELET_CONFIG_FILE elif grep "KUBELET_EXTRA_ARGS=" $KUBELET_CONFIG_FILE &> /dev/null;then sed -i "s@KUBELET_EXTRA_ARGS=@KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_PROVIDER_ID} @g" $KUBELET_CONFIG_FILE else sed -i "/^\[Service\]/a\Environment=\"KUBELET_EXTRA_ARGS=${option}=${ALIBABA_CLOUD_PROVIDER_ID}\"" $KUBELET_CONFIG_FILE fi fi ####### Add the preceding content. # Restart the runtime and kubelet. ....The Kubernetes cluster is created by using the binary method
If your cluster is created by using a Kubernetes binary file, you must modify the boot configuration of the kubelet in the custom node script to obtain the environment variables. Typically, the
kubelet.servicefile is stored in the/usr/lib/systemd/system/directory.cat >/usr/lib/systemd/system/kubelet.service <<EOF # Custom configurations are not shown. ... [Service] ExecStart=/data0/kubernetes/bin/kubelet \\ # Modify the following configuration. --node-ip=${ALIBABA_CLOUD_NODE_NAME} \\ --hostname-override=${ALIBABA_CLOUD_NODE_NAME} \\ --node-labels=${ALIBABA_CLOUD_LABELS} \\ --provider-id=${ALIBABA_CLOUD_PROVIDER_ID} \\ --register-with-taints=${ALIBABA_CLOUD_TAINTS} \\ .... --v=4 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
The following table describes the environment variables issued by the registered cluster.
Environment variable | Description | Example |
ALIBABA_CLOUD_PROVIDER_ID | The custom node script must obtain this environment variable. Otherwise, the registered cluster cannot run as normal. | ALIBABA_CLOUD_PROVIDER_ID=cn-shenzhen.i-wz92ewt14n9wx9mo*** |
ALIBABA_CLOUD_NODE_NAME | The custom node script must obtain this environment variable. Otherwise, nodes in the node pool may run in an abnormal state. | ALIBABA_CLOUD_NODE_NAME=cn-shenzhen.192.168.1.*** |
ALIBABA_CLOUD_LABELS | The custom node script must obtain this environment variable. Otherwise, errors may occur during node pool management and workload scheduling between cloud and on-premises nodes. | ALIBABA_CLOUD_LABELS=alibabacloud.com/nodepool-id=np0e2031e952c4492bab32f512ce142***,ack.aliyun.com=cc3df6d939b0d4463b493b82d0d670***,alibabacloud.com/instance-id=i-wz960ockeekr3dok0***,alibabacloud.com/external=true,workload=cpu The workload=cpu label is a custom label defined in the node pool configuration. Other labels are system labels. |
ALIBABA_CLOUD_TAINTS | The custom node script must obtain this environment variable. Otherwise, the taints added to the node pool do not take effect. | ALIBABA_CLOUD_TAINTS=workload=ack:NoSchedule |
After you perform the preceding steps, proceed to Step 2: Save and upload the script to the file server.
Step 1 (B): Add a node script
Obtain the relevant system information.
The Kubernetes version of the cluster is 1.18 or later
Run the following command to query the Kubernetes version of the external cluster. The Kubernetes version will be specified in the environment variable
KUBE_VERSIONof the sample script in subsequent steps.kubectl get no $(kubectl get nodes -l node-role.kubernetes.io/control-plane -o json | jq -r '.items[0].metadata.name') -o json | jq -r '.status.nodeInfo.kubeletVersion'Expected output:
v1.14.10Run the following command to query the runtime and runtime version of the external cluster. The runtime and runtime version will be specified in the environment variable
RUNTIME_VERSIONof the sample script in subsequent steps.kubectl get no $(kubectl get nodes -l node-role.kubernetes.io/control-plane -o json | jq -r '.items[0].metadata.name') -o json | jq -r '.status.nodeInfo.containerRuntimeVersion'Expected output:
docker://18.6.3 # Docker is used. containerd://1.4.3 # containerd is used.Run the following command to query the kubeadm command used to add nodes. The command will be specified in the environment variable
KUBEADM_JOIN_CMDof the sample script in subsequent steps.# --ttl 0 is very important. Set the TTL to 0 (no expiration time) so that node pool auto scaling does not become invalid. kubeadm token create --ttl 0 --print-join-commandExpected output:
kubeadm join 192.168.8.XXX:6443 --token k8xsq8.4oo8va9wcqpb*** --discovery-token-ca-cert-hash sha256:cb5fc894ab965dfbc4c194e1065869268f8845c3ec40f78f9021dde24610d***
The Kubernetes version of the cluster is earlier than 1.18
Run the following command to query the Kubernetes version of the external cluster. The Kubernetes version will be specified in the environment variable
KUBE_VERSIONof the sample script in subsequent steps.kubectl get no $(kubectl get nodes -l node-role.kubernetes.io/master -o json | jq -r '.items[0].metadata.name') -o json | jq -r '.status.nodeInfo.kubeletVersion'Expected output:
v1.14.10Run the following command to query the runtime and runtime version of the external cluster. The runtime and runtime version will be specified in the environment variable
RUNTIME_VERSIONof the sample script in subsequent steps.kubectl get no $(kubectl get nodes -l node-role.kubernetes.io/master -o json | jq -r '.items[0].metadata.name') -o json | jq -r '.status.nodeInfo.containerRuntimeVersion'Expected output:
docker://18.6.3 # Docker is used. containerd://1.4.3 # containerd is used.Run the following command to query the kubeadm command used to add nodes. The command will be specified in the environment variable
KUBEADM_JOIN_CMDof the sample script in subsequent steps.# --ttl 0 is very important. Set the TTL to 0 (no expiration time) so that node pool auto scaling does not become invalid. kubeadm token create --ttl 0 --print-join-commandExpected output:
kubeadm join 192.168.8.XXX:6443 --token k8xsq8.4oo8va9wcqpb*** --discovery-token-ca-cert-hash sha256:cb5fc894ab965dfbc4c194e1065869268f8845c3ec40f78f9021dde24610d***
Obtain the sample script.
NoteThe sample script applies only to regular ECS nodes. For GPU-accelerated ECS nodes, submit a ticket to the R&D team.
Specify the Kubernetes version, runtime, runtime version, and kubeadm command of the external cluster that you obtained in the environment variables of the sample script.
Docker
containerd
Step 2: Save and upload the script to the file server
You must upload the custom node script or the sample node script that you modified to the file server, such as an Object Storage Service (OSS) bucket. Example: https://kubelet-****.oss-cn-hangzhou-internal.aliyuncs.com/join-ecs-nodes.sh.
Step 3: Modify the ack-cluster-agent configuration
You must complete this step before you can create a node pool. Otherwise, the custom script cannot be obtained when you scale out the node pool. Consequently, the scale-out operation fails.
After the script is uploaded and the path of the script is recorded, specify the path in the addNodeScriptPath field of the ack-agent-config configuration in the kube-system namespace.
# Use kubectl to modify the ack-agent-config configuration.
kubectl edit cm ack-agent-config -n kube-system
# Modify the addNodeScriptPath field as follows:
apiVersion: v1
data:
addNodeScriptPath: https://kubelet-****.oss-cn-hangzhou-internal.aliyuncs.com/join-ecs-nodes.sh
kind: ConfigMap
metadata:
name: ack-agent-config
namespace: kube-system