为了缩短云上节点从启动状态到Ready状态的时间,建议您通过使用自定义镜像预先安装所需的软件包的方式,可以显著减少软件包下载的时间,提升系统启动的效率。本文介绍如何通过自定义镜像的方式为注册集群构建弹性节点池。
前提条件
已创建注册集群,并已将本地数据中心自建Kubernetes集群通过私网方式接入注册集群。具体操作,请参见创建注册集群。
已配置本地数据中心的自建Kubernetes集群网络与云上注册集群使用的专有网络VPC互通。具体操作,请参见入门概述。
已通过kubectl连接注册集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群。
操作步骤
本文以CentOS 7.9操作系统为例,通过二进制方式接入版本为1.28.3的Kubernetes集群,构建自定义镜像以实现弹性节点池的搭建。
若您已创建好自定义镜像,请直接跳转至步骤三开始操作。
步骤一:创建云上节点池并扩容节点
选择一个OSS bucket,使用以下内容创建文件join-ecs-node.sh并上传。
echo "The node providerid is $ALIBABA_CLOUD_PROVIDER_ID" echo "The node name is $ALIBABA_CLOUD_NODE_NAME" echo "The node labels are $ALIBABA_CLOUD_LABELS" echo "The node taints are $ALIBABA_CLOUD_TAINTS"
获取join-ecs-node.sh文件链接地址(可以使用签名地址),并在集群中更改自定义脚本配置。
执行以下命令,编辑ack-agent-config。
kubectl edit cm ack-agent-config -n kube-system
修改addNodeScriptPath字段内容,更新后配置如下。
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
创建云上节点池cloud-test,并将期望节点数设置为1。具体操作,请参见创建节点池并扩容。
重要由于新创建的节点没有进行初始化(安装节点软件包等),创建完成后会显示为Failed状态。另外,后续需要登录该节点进行节点初始化,请确保此节点可通过SSH登录。
步骤二:配置节点状态并导出自定义镜像
登录节点,使用以下命令查看节点信息。
cat /var/log/acs/init.log
预期输出:
The node providerid is cn-zhangjiakou.i-xxxxx The node name is cn-zhangjiakou.192.168.66.xx The node labels are alibabacloud.com/nodepool-id=npf9fbxxxxxx,ack.aliyun.com=c22b1a2e122ff4fde85117de4xxxxxx,alibabacloud.com/instance-id=i-8vb7m7nt3dxxxxxxx,alibabacloud.com/external=true The node taints are
预期说明自定义脚本可以成功获取阿里云节点信息,请记录这些信息,稍后将其添加到kubelet的启动参数中。
执行以下命令,配置基础环境。
# 安装工具包。 yum update -y && yum -y install wget psmisc vim net-tools nfs-utils telnet yum-utils device-mapper-persistent-data lvm2 git tar curl # 关闭防火墙。 systemctl disable --now firewalld # 关闭SELinux。 setenforce 0 sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config # 关闭交换分区。 sed -ri 's/.*swap.*/#&/' /etc/fstab swapoff -a && sysctl -w vm.swappiness=0 # 网络配置。 systemctl disable --now NetworkManager systemctl start network && systemctl enable network # 时间同步。 ln -svf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime yum install ntpdate -y ntpdate ntp.aliyun.com # 配置ulimit。 ulimit -SHn 65535 cat >> /etc/security/limits.conf <<EOF * soft nofile 655360 * hard nofile 131072 * soft nproc 655350 * hard nproc 655350 * seft memlock unlimited * hard memlock unlimitedd EOF
说明完成上述环境配置后,请自行升级内核至4.18以上版本,并安装ipvsadm。
安装Containerd。
执行以下命令,下载网络插件和Containerd软件包。
wget https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz mkdir -p /etc/cni/net.d /opt/cni/bin #解压cni二进制包 tar xf cni-plugins-linux-amd64-v*.tgz -C /opt/cni/bin/ wget https://github.com/containerd/containerd/releases/download/v1.7.8/containerd-1.7.8-linux-amd64.tar.gz tar -xzf cri-containerd-cni-*-linux-amd64.tar.gz -C /
执行以下命令,创建服务启动配置。
cat > /etc/systemd/system/containerd.service <<EOF [Unit] Description=containerd container runtime Documentation=https://containerd.io After=network.target local-fs.target [Service] ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd Type=notify Delegate=yes KillMode=process Restart=always RestartSec=5 LimitNPROC=infinity LimitCORE=infinity LimitNOFILE=infinity TasksMax=infinity OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target EOF
执行以下命令,配置Containerd所需模块。
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf overlay br_netfilter EOF systemctl restart systemd-modules-load.service
执行以下命令,配置Containerd所需内核。
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 EOF # 加载内核 sysctl --system
执行以下命令,创建Containerd配置文件。
mkdir -p /etc/containerd containerd config default | tee /etc/containerd/config.toml # 修改Containerd的配置文件 sed -i "s#SystemdCgroup\ \=\ false#SystemdCgroup\ \=\ true#g" /etc/containerd/config.toml cat /etc/containerd/config.toml | grep SystemdCgroup sed -i "s#registry.k8s.io#m.daocloud.io/registry.k8s.io#g" /etc/containerd/config.toml cat /etc/containerd/config.toml | grep sandbox_image sed -i "s#config_path\ \=\ \"\"#config_path\ \=\ \"/etc/containerd/certs.d\"#g" /etc/containerd/config.toml cat /etc/containerd/config.toml | grep certs.d # 配置加速器 mkdir /etc/containerd/certs.d/docker.io -pv cat > /etc/containerd/certs.d/docker.io/hosts.toml << EOF server = "https://docker.io" [host."https://hub-mirror.c.163.com"] capabilities = ["pull", "resolve"] EOF
执行以下命令,设置Contaienrd为开机自启动。
systemctl daemon-reload # 用于重新加载systemd管理的单位文件。当你新增或修改了某个单位文件(如.service文件、.socket文件等),需要运行该命令来刷新systemd对该文件的配置。 systemctl enable --now containerd.service systemctl start containerd.service systemctl status containerd.service
执行以下命令,配置crictl命令。
wget https://mirrors.chenby.cn/https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.28.0/crictl-v1.28.0-linux-amd64.tar.gz tar xf crictl-v*-linux-amd64.tar.gz -C /usr/bin/ #生成配置文件 cat > /etc/crictl.yaml <<EOF runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false EOF #测试 systemctl restart containerd crictl info
安装kubelet、kube-proxy。
获取二进制文件。登录Master节点,将二进制文件拷贝到该节点。
scp /usr/local/bin/kube{let,-proxy} $NODEIP:/usr/local/bin/
获取证书,执行以下命令,在本机创建证书存储目录。
mkdir -p /etc/kubernetes/pki
登录master节点,拷贝证书到该节点。
for FILE in pki/ca.pem pki/ca-key.pem pki/front-proxy-ca.pem bootstrap-kubelet.kubeconfig kube-proxy.kubeconfig; do scp /etc/kubernetes/$FILE $NODE:/etc/kubernetes/${FILE}; done
执行以下命令,配置kubelet Service。请将步骤二中获取到的阿里云节点池相关变量填入。
mkdir -p /var/lib/kubelet /var/log/kubernetes /etc/systemd/system/kubelet.service.d /etc/kubernetes/manifests/ # 所有k8s节点配置kubelet service cat > /usr/lib/systemd/system/kubelet.service << EOF [Unit] Description=Kubernetes Kubelet Documentation=https://github.com/kubernetes/kubernetes After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=containerd.service [Service] ExecStart=/usr/local/bin/kubelet \\ --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} \\ --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig \\ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\ --config=/etc/kubernetes/kubelet-conf.yml \\ --container-runtime-endpoint=unix:///run/containerd/containerd.sock [Install] WantedBy=multi-user.target EOF
执行以下命令,创建kubelet启动配置文件。
cat > /etc/kubernetes/kubelet-conf.yml <<EOF apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration address: 0.0.0.0 port: 10250 readOnlyPort: 10255 authentication: anonymous: enabled: false webhook: cacheTTL: 2m0s enabled: true x509: clientCAFile: /etc/kubernetes/pki/ca.pem authorization: mode: Webhook webhook: cacheAuthorizedTTL: 5m0s cacheUnauthorizedTTL: 30s cgroupDriver: systemd cgroupsPerQOS: true clusterDNS: - 10.96.0.10 clusterDomain: cluster.local containerLogMaxFiles: 5 containerLogMaxSize: 10Mi contentType: application/vnd.kubernetes.protobuf cpuCFSQuota: true cpuManagerPolicy: none cpuManagerReconcilePeriod: 10s enableControllerAttachDetach: true enableDebuggingHandlers: true enforceNodeAllocatable: - pods eventBurst: 10 eventRecordQPS: 5 evictionHard: imagefs.available: 15% memory.available: 100Mi nodefs.available: 10% nodefs.inodesFree: 5% evictionPressureTransitionPeriod: 5m0s failSwapOn: true fileCheckFrequency: 20s hairpinMode: promiscuous-bridge healthzBindAddress: 127.0.0.1 healthzPort: 10248 httpCheckFrequency: 20s imageGCHighThresholdPercent: 85 imageGCLowThresholdPercent: 80 imageMinimumGCAge: 2m0s iptablesDropBit: 15 iptablesMasqueradeBit: 14 kubeAPIBurst: 10 kubeAPIQPS: 5 makeIPTablesUtilChains: true maxOpenFiles: 1000000 maxPods: 110 nodeStatusUpdateFrequency: 10s oomScoreAdj: -999 podPidsLimit: -1 registryBurst: 10 registryPullQPS: 5 resolvConf: /etc/resolv.conf rotateCertificates: true runtimeRequestTimeout: 2m0s serializeImagePulls: true staticPodPath: /etc/kubernetes/manifests streamingConnectionIdleTimeout: 4h0m0s syncFrequency: 1m0s volumeStatsAggPeriod: 1m0s EOF
执行以下命令,启动kubelet。
systemctl daemon-reload # 用于重新加载systemd管理的单位文件。当你新增或修改了某个单位文件(如.service文件、.socket文件等),需要运行该命令来刷新systemd对该文件的配置。 systemctl enable --now kubelet.service systemctl start kubelet.service systemctl status kubelet.service
执行以下命令,查看集群信息。
kubectl get node
登录master节点,获取kube-proxy所需KubeConfig。
scp /etc/kubernetes/kube-proxy.kubeconfig $NODE:/etc/kubernetes/kube-proxy.kubeconfig
执行以下命令,添加kube-proxy Service配置。
cat > /usr/lib/systemd/system/kube-proxy.service << EOF [Unit] Description=Kubernetes Kube Proxy Documentation=https://github.com/kubernetes/kubernetes After=network.target [Service] ExecStart=/usr/local/bin/kube-proxy \\ --config=/etc/kubernetes/kube-proxy.yaml \\ --v=2 Restart=always RestartSec=10s [Install] WantedBy=multi-user.target EOF
执行以下命令,添加kube-proxy启动配置。
cat > /etc/kubernetes/kube-proxy.yaml << EOF apiVersion: kubeproxy.config.k8s.io/v1alpha1 bindAddress: 0.0.0.0 clientConnection: acceptContentTypes: "" burst: 10 contentType: application/vnd.kubernetes.protobuf kubeconfig: /etc/kubernetes/kube-proxy.kubeconfig qps: 5 clusterCIDR: 172.16.0.0/12,fc00:2222::/112 configSyncPeriod: 15m0s conntrack: max: null maxPerCore: 32768 min: 131072 tcpCloseWaitTimeout: 1h0m0s tcpEstablishedTimeout: 24h0m0s enableProfiling: false healthzBindAddress: 0.0.0.0:10256 hostnameOverride: "" iptables: masqueradeAll: false masqueradeBit: 14 minSyncPeriod: 0s syncPeriod: 30s ipvs: masqueradeAll: true minSyncPeriod: 5s scheduler: "rr" syncPeriod: 30s kind: KubeProxyConfiguration metricsBindAddress: 127.0.0.1:10249 mode: "ipvs" nodePortAddresses: null oomScoreAdj: -999 portRange: "" udpIdleTimeout: 250ms EOF
执行以下命令,启动kube-proxy。
systemctl daemon-reload # 用于重新加载systemd管理的单位文件。当你新增或修改了某个单位文件(如.service文件、.socket文件等),需要运行该命令来刷新systemd对该文件的配置。 systemctl enable --now kube-proxy.service systemctl restart kube-proxy.service systemctl status kube-proxy.service
同步节点池状态。
登录容器服务管理控制台,在左侧导航栏选择集群。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
进入节点池页面,单击右侧同步节点池,等待同步完成后,可以看到已无失败信息,节点池显示正常。
导出自定义镜像。
登录ECS管理控制台。
在左侧导航栏,选择 。
单击该实例ID,进入实例详情页签,单击创建自定义镜像。
在左侧导航栏,选择 。
进入镜像页面,可看到创建的自定义镜像,状态为可用。
步骤三:使用自定义镜像修改或创建云上节点池
如果您已经有自定义镜像,且未执行步骤一、步骤二操作,需要使用自定义镜像创建节点池。具体操作,请参见如何基于创建好的ECS实例创建自定义镜像,并使用该镜像创建节点?。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
进入节点池页面,找到对应节点池,右侧单击编辑,选择高级选项页签,修改节点池镜像为自定义镜像。
可在节点池页面看到操作系统已更新为自定义镜像。
步骤四:修改节点初始化脚本并接收阿里云相关参数
需要清理自定义镜像里面残留的kubelet证书,见脚本第七行。
若为已有自定义节点池情况,需参考步骤一中配置好自定义脚本下载链接。
使用以下内容,构建或更新join-ecs-node.sh。由于自定义镜像已经包含节点所需工具包、依赖包,所以自定义脚本只需接收并更新阿里云节点池参数即可。
echo "The node providerid is $ALIBABA_CLOUD_PROVIDER_ID" echo "The node name is $ALIBABA_CLOUD_NODE_NAME" echo "The node labels are $ALIBABA_CLOUD_LABELS" echo "The node taints are $ALIBABA_CLOUD_TAINTS" systemctl stop kubelet.service echo "Delete old kubelet pki" #需删除老的节点证书 rm -rf /var/lib/kubelet/pki/* echo "Add kubelet service config" # 配置kubelet service cat > /usr/lib/systemd/system/kubelet.service << EOF [Unit] Description=Kubernetes Kubelet Documentation=https://github.com/kubernetes/kubernetes After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=containerd.service [Service] ExecStart=/usr/local/bin/kubelet \\ --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} \\ --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig \\ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\ --config=/etc/kubernetes/kubelet-conf.yml \\ --container-runtime-endpoint=unix:///run/containerd/containerd.sock [Install] WantedBy=multi-user.target EOF systemctl daemon-reload # 启动Kubelet Service systemctl start kubelet.service
将脚本join-ecs-node.sh更新到OSS上。
步骤五:扩容节点池
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
进入节点池页面,找到对应节点池,右侧单击
,增加一个新节点。看到两个节点状态正常,说明我们的弹性节点池构建完成。
可以为节点池配置弹性伸缩策略。具体操作,请参见配置自动弹性伸缩。