安装背景
出于对于kubernetes集群的配置灵活性的需求,很多朋友有自建Kubernetes集群的诉求,在此记录一下我在阿里云上购买ECS并从头开始来完成kubernetes集群的过程;为节省成本集群中的节点采用了规格为2c4G的突发性能型ECS,操作系统是Anolis OS 8.8 RHCK 64位;使用kubeadm这个工具来进行安装,主要流程可抽象成两个大步骤:
- 初始化节点:通过rpm包管理工具安装kubectl、kubelet、kubeadm 这几个组件;安装containerd,并完成相关配置;
- 初始化集群:注意kubeadm的配置文件,生成证书等配置,建立高可用控制面,并将worker节点加入集群中;
初始化节点
安装kubectl、kubeadm、kubelet 组件
考虑到网络联通性问题,需要加入rpm包的国内本地化配置源,首先是kubernetes的源:添加rpm源的配置如下所示,清注意关闭gpgcheck
cat << EOF |tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 建议设定版本,不声明版本则安装具体的最新版;
yum install kubectl kubeadm kubelet
安装 containerd
contaienrd 配置
参考 https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/#containerd 来进行containerd的安装
containerd 国内本地化源配置
wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
先验证contianerd包在源中存在,然后执行如下命令安装相关 containerd 运行时:
yum install containerd.io
systemctl enable containerd
systemctl start containerd
修改 containerd 中的 sandbox image配置
修改 containerd 配置文件 config.toml文件中的 sandbox image配置:registry.aliyuncs.com/google_containers/pause:3.9 ,此修改是因为默认的镜像地址为gcr,在国内无法正常访问。
# 生成对应containerd的配置文件
containerd config default > /etc/containerd/config.toml
# 保存此配置文件后通过 命令重启生效配置
systemctl restart containerd
注意:
- 查看containerd当前生效配置:containerd config dump > 2.toml;
- 如果containerd的工作状态不符合预期,可以通过 journalctl -xeu containerd 命令来查看containerd日志 ;
添加 crictl配置
相关配置文件为 /etc/crictl.yaml
cat << EOF |tee /etc/crictl.yaml
# these first two endpoint setting is where you configure crictl to containerd
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 3
debug: true
EOF
此时执行 crictl images 可以正常输出内容;
安装 并配置 cni 插件
在 cni 界面 https://github.com/containernetworking/plugins/releases ,找到 v1.3.0 或者v1.0.0 版本,通过wget命令下载此包。
# 通过命令创建cni的对应目录
mkdir -p /opt/cni/bin
# 通过如下相关命令将包解压至相关目录
tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.3.0.tgz
本地cni配置,注意版本号以及相关ip子网地址段:
cat << EOF | tee /etc/cni/net.d/10-containerd-net.conflist
{
"cniVersion": "1.0.0",
"name": "containerd-net",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"promiscMode": true,
"ipam": {
"type": "host-local",
"ranges": [
[{
"subnet": "10.14.0.0/24"
}]
],
"routes": [
{ "dst": "0.0.0.0/0" },
{ "dst": "::/0" }
]
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true},
"externalSetMarkChain": "KUBE-MARK-MASQ"
}
]
}
EOF
注意此时只解决了本节点上容器通信的问题,并未解决在节点间的容器通信问题,跨节点通信需要通过类似 flannel、calico 这样的方案来完成。
测试:通过crictl 成功run起来一个本地容器,参考crictl 相关文档;
内核参数配置修改
内核参数设置(如果不做如下操作,将会无法通过 kubeadm init的 precheck )
# 修改域名配置
hostnamectl set-hostname k8s-1
# 安装tc
yum install iproute-tc
# sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory 如果遇到相关错误,请执行 modprobe 命令
modprobe bridge
modprobe br_netfilter
echo "net.bridge.bridge-nf-call-iptables=1" | sudo tee -a /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "vm.swappiness = 0" >> /etc/sysctl.conf
sysctl 使相关配置生效
sysctl -p /etc/sysctl.conf
集群初始化–拉起控制面
控制面(control plane)采用三台服务器,etcd与api server同机部署的架构;通过ssh登录一台预先规划好的master服务器,通过kubeadm 来完成节点初始化工作,注意给出config配置文件需要使用国内阿里云的镜像仓库;–apiserver-advertise-address 为此master服务器的内网地址;另外控制面的证书如果需要上传到集群请在 kubeadm init 执行时加上 –upload-certs 这个参数。 一般来说 kubeadm的init命令如下所示:
kubeadm init \
--apiserver-advertise-address=192.168.0.121 \
--image-repository registry.aliyuncs.com/google\_containers \
--kubernetes-version v1.28.2 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16
但是为了更多配置项,我们选择配置文件的方式来进行init,具体命令:
kubeadm init --config kubeadm-config.yaml
kubeadm 配置文件内容如下,certSANs配置中将三台master的hostname及ip地址都写入,此外还加入了api server对应LB的域名及ip地址;注意此处采用的是将etcd实例与api server 实例部署在同一node上的架构,如果是生产环境部署建议将etcd集群拆分部署在其他服务器上,如果是etcd拆分部署的情况,kubeadm配置文件的内容还会有所不同,具体请参照附录中的文件链接:
apiServer:
certSANs:
- api.k8s.local
- api.lixin.com
- master3105
- master12
- master079
- 10.0.3.105
- 10.0.1.2
- 10.0.0.79
- 10.0.4.212
extraArgs:
authorization-mode: Node,RBAC
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kube-lixin
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.28.0
controlPlaneEndpoint: "10.0.4.212:6443"
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
scheduler: {}
请注意观察在kubeadm init 执行过程中的日志输出,错误日志会在此处给出详细信息,如果日志不够细致的话还可以加入 –v=10 参数并执行;
在其他两台控制面机器上完成节点初始化(本文第一部分)后,如果在kubeadm init时没有选择加上 –upload-certs 参数,则需要将相关kubernetes证书在控制面机器之间进行拷贝:
scp /etc/kubernetes/pki/etcd/ca.key root@10.0.1.2:/etc/kubernetes/pki/etcd
scp /etc/kubernetes/pki/etcd/ca.crt root@10.0.0.79:/etc/kubernetes/pki/etcd
scp /etc/kubernetes/pki/front-proxy-ca.key root@10.0.0.79:/etc/kubernetes/pki
scp /etc/kubernetes/pki/front-proxy-ca.crt root@10.0.0.79:/etc/kubernetes/pki
scp /etc/kubernetes/pki/sa.pub root@10.0.0.79:/etc/kubernetes/pki
scp /etc/kubernetes/pki/sa.key root@10.0.0.79:/etc/kubernetes/pki
scp /etc/kubernetes/pki/ca.key root@10.0.0.79:/etc/kubernetes/pki
scp /etc/kubernetes/pki/ca.crt root@10.0.0.79:/etc/kubernetes/pki
通过如下命令将此节点作为一个master加入集群,注意参数 –control-plane 这里说明是作为master进入的:
kubeadm join 10.0.3.105:6443 --token svy3br.1hcjfw953q23ypq3 --discovery-token-ca-cert-hash sha256:032c441fac7307da1867fab25ab77f480318c3ca68fb67977cd8011c3a4aab88 --control-plane
高可用集群控制面的两个问题:
- 如果证书没有选择上传集群,则需要提前手动完成证书在master实例节点之间的copy;
- 需要申请一个SLB将流量转发到多个api server 实例上,在 controlPlaneEndpoint 上体现了这个SLB的对应配置。
加入worker节点
此刻可以说是完成了控制面的搭建;通过如下命令将worker节点加入集群,注意worker节点并不需要提前scp证书,并且不需要 control-plane 参数;如果执行时日志中有 token 过期相关错误,需要登录到最初的master节点上,通过kubeadm token create创建一个新的token,并在–token 处使用新的token。
kubeadm join 10.0.3.105:6443 --token svy3br.1hcjfw953q23ypq3 --discovery-token-ca-cert-hash sha256:032c441fac7307da1867fab25ab77f480318c3ca68fb67977cd8011c3a4aab88 --v=10
master节点的添加及一些注意事项
如果需要新增控制面节点机器,需要在kubeadm配置文件中加入相关ip及dns配置,并通过如下kubeadm init phase命令重新生成相关的api server证书;
# 新加入控制面机器,如果证书中没有包括相关机器的hostname及ip,需要重新生成对应的api server证书
kubeadm init phase certs apiserver --config kubeadm.yaml
# 重新生成cluster-info:
kubeadm init phase bootstrap-token
此时已完成自建kubernetes集群的初步搭建,对于集群中跨node的通信需求,推荐安装Calico来解决;
参考资料
安装过程中参考了如下文档中的描述:
- 如果要使用外部etcd,请参考如下文档中的创建步骤:https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/high-availability/#%E5%A4%96%E9%83%A8-etcd-%E8%8A%82%E7%82%B9
- 参考安装流程:https://cloud.tencent.com/developer/article/1706627
- 控制面高可用: https://zhangguanzhang.github.io/2019/03/11/k8s-ha/#/vip-%E5%8D%95%E7%82%B9%E7%9A%84%E5%9D%91%E4%B9%8B-%E2%80%93advertise-address
- 安装 https://cloud.tencent.com/developer/article/2145554
- containerd https://cloud.tencent.com/developer/article/2145554
- containerd 设置文档 包含了cni https://github.com/containerd/containerd/blob/main/docs/getting-started.md
- 国内环境安装 https://zhuanlan.zhihu.com/p/46341911
- cni插件配置,参考相关文档,解决可能遇到的版本不匹配的问题:https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/migrating-from-dockershim/troubleshooting-cni-plugin-related-errors/#updating-your-cni-plugins-and-cni-config-files
- 加入master节点之前,需要手动分发证书:参考 https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/high-availability/#manual-certs
- 完成apiserver 证书的检查工作,并更新相关证书更新,并重新生成kube-system中的cluster-info configmap对象:参考:https://cloud.tencent.com/developer/article/1824860
kubeadm join命令中的 discovery-token-ca-cert-hash 对应的值可以通过如下命令获取:
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
证书相关一些命令备忘:
# 查看证书内容:
openssl x509 -in apiserver.crt -text -noout
# 将新master的IP地址更新入证书的另一种做法:
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 \
-subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=kube-apiserver" \
-keyout apiserver.key \
-out apiserver.crt \
-extensions SAN -config <(echo "[req]"; echo distinguished_name=req; echo "[SAN]"; echo subjectAltName=IP:Load_Balancer_IP1,IP:Load_Balancer_IP2)
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 \
-subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=kube-apiserver" \
-keyout apiserver.key \
-out apiserver.crt \
-extensions SAN -config <(echo "[req]"; echo distinguished_name=req; echo "[SAN]"; echo subjectAltName=DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster.local,DNS:master3105,IP:10.96.0.1,IP:10.0.3.105,IP:10.0.4.212)
最后修改于 2023-11-14