前言
服务器成本太过高昂, kind 或 minikube 并不能很好的练习高可用集群部署。
前置条件
括号内为文章所使用的具体版本。下面假设VMware已安装,CentOS镜像已下载,进行系统安装。
- VMware (17.0.2 build-21581411)Windows 虚拟机 | Workstation Pro | VMware | CN
- CentOS Stream (CentOS-Stream-9-latest-x86_64-dvd1.iso) CentOS Stream
⚠️ 为啥要使用CentOS Stream ?
- CentOS Linux 7 将于 2024年6月30日停止维护 ,CentOS Linux 8 于 2021年12月31日 停止更新并停止维护。
- 大多数人接触到的Linux系统是 RHEL 系,使用 CentOS 可以很好上手。
- 集群需要 cilium 作为网络插件,需要内核版本较高,官方列举出可以很好使用 cilium 的 CentOS 系统需 >= 8.0,System Requirements — Cilium 1.13.2 documentation
- 本文章仅学习使用,官方已经说明不要在生产环境使用,Why choose Red Hat Enterprise Linux over CentOS Stream for production use
使用 VMware 安装 CentOS 系统
kubeadm对系统、内存以及处理器有一定要求。Creating a cluster with kubeadm | Kubernetes
- 一台或多台运行兼容 deb/rpm 的 Linux 操作系统的计算机;例如:Ubuntu 或 CentOS。
- 每台机器 2 GB 以上的内存,内存不足时应用会受限制。
- 用作控制平面节点的计算机上至少有 2 个 CPU。
- 集群中所有计算机之间具有完全的网络连接。你可以使用公共网络或专用网络。
- 新建虚拟机
- 选自定义(高级),点下一步
- 下一步
- 选择稍后安装操作系统,点下一步
- 操作系统选Linux,版本选择其他Linux 5.x 内核 64位,点下一步
- 填写虚拟机的名称,这里随便填写,点下一步
- 选择处理器数量、内核数量,点下一步
- 选择2G运行内存,点下一步
- 网络类型选择NAT,点下一步
- 控制器默认,点下一步
- 磁盘类型默认,点下一步
- 磁盘选创建新虚拟磁盘,点下一步
- 磁盘大小先设置20G,不够再加。虚拟磁盘可以选存储单文件也可选多文件,点下一步
- 指定文件默认名称就行,下一步
- 确认一下信息,点完成
- 点编辑虚拟机设置
- 设置ISO映像文件,选择下载好的iso文件,点确定
- 编辑虚拟网络
- 点更改设置
- 取消勾选使用本地DHCP服务将IP地址分配给虚拟机,点应用,点确定
- 点开启此虚拟机
- 选Install CentOS Stream 9,下一项Test检查太慢,如果进了Test,也可以按Esc退出Test,等待一会儿进入安装
- 选中文,简体中文,点继续
- 点软件选择
- 选择最小安装,点完成
- 点安装目的地
- 存储配置选自定义,点完成
- 手动分区,点加号
- 设置启动分区/boot,不用太大,500m就行,点添加挂载点
- 点击加号,挂载点选/,容量不填,点添加挂载点
- 点两次左上角完成,第一次会提示我们没有设置swap交换分区,第二次点会跳过提示,点接受更改
- 点网络和主机名
- 点击配置,点IPv4设置
- 方法选择手动,地址配为如图所示,地址随便填,子网掩码和网关看第20步(这里是因为我安装过wsl,所以网关是.2,正常情况应该是.1),点保存
- 点右上角,打开网络。输入主机名,点应用。点完成
- 点root密码
- 设置root账号密码,这里为了简单,设置1233456。勾选允许root用户使用密码进行SSH登录,点两次完成
- 点击开始安装
- 等待安装
- (可选)安装过程过于漫长,等待时我们可以安装 Windows Terminal软件
Windows 终端安装 | Microsoft Learn
- (可选)安装wsl,也就是适用于 Linux 的 Windows 子系统,这个安装时长也不短
- 点重启系统,等待重启
- 重启好以后,我们就可以使用ssh连接CentOS了
在终端中输入,ServerAliveInterval可以防止会话超时,root为要登录的账户,@后跟ip地址(第34步设置的固定ip地址)
$ ssh -o ServerAliveInterval=60 root@192.168.112.128
第一次连接会提示保存到 ~/.ssh/known_hosts ,输入yes,然后会提示要输入密码,输入密码。
完整输出:
heisenberg@DESKTOP-N969HOO:~ % ssh -o ServerAliveInterval=60 root@192.168.112.128
The authenticity of host '192.168.112.128 (192.168.112.128)' can't be established.
ED25519 key fingerprint is SHA256:7RSWTd1/BkmiRQggzQKWOPKwq8DLdywl4Q/xc3OP1kY.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.112.128' (ED25519) to the list of known hosts.
root@192.168.112.128's password:
[root@master ~]#
- 使用ping检查网络是否正常
$ ping baidu.com
如果不能正常联网,可以手动修改,这里CentOS 9与之前不一样,不在 /etc/sysconfig/network-scripts/ 中,而是在 /etc/NetworkManager/system-connections/ 文件夹中,可以看到原文件夹有一个 readme-ifcfg-rh.txt 文件说明
$ vi /etc/NetworkManager/system-connections/ens33.nmconnection
[connection]
id=ens33
uuid=a211298d-5d45-3b92-9ad7-c677aff578cb
type=ethernet
autoconnect-priority=-999
interface-name=ens33
[ethernet]
[ipv4]
address1=192.168.112.128/24,192.168.112.2
dns=192.168.112.2;8.8.8.8;
method=manual
[ipv6]
addr-gen-mode=eui64
method=auto
[proxy]
修改完成后,使用nmcli重载配置文件,重启连接
$ nmcli c reload
$ nmcli c up ens33
- (可选)每次重大操作后,拍摄快照(尽量在关机状态时创建快照,这样可以进行克隆操作),可以方便我们快速回退到之前版本,不需要担心会搞坏,有问题可以随时回退
安装 kubeadm
本文基于Kubernetes v1.27.1
禁用 swap 交换分区
使用free查看,因为我们安装系统时没有分配swap分区,所以不需要处理这步。
[root@master ~]# free
total used free shared buff/cache available
Mem: 1789720 390272 1376016 5240 174708 1399448
Swap: 0 0 0
(没有经过手动分区)当有swap交换分区时:
临时关闭
$ swapoff -a
永久关闭,编辑/etc/fstab文件,注释掉swap这行,需重启。
$ vi /etc/fstab
安装 containerd 容器运行时
安装 containerd
在下载链接前加 ghproxy.com/ ,可以让下载速度变快。
下载 containerd 发布包。
$ curl -OL https://ghproxy.com/https://github.com/containerd/containerd/releases/download/v1.7.1/containerd-1.7.1-linux-amd64.tar.gz
解压 containerd , 安装。
$ tar Cxzvf /usr/local containerd-1.7.1-linux-amd64.tar.gz
bin/
bin/containerd-stress
bin/ctr
bin/containerd-shim-runc-v2
bin/containerd
bin/containerd-shim
bin/containerd-shim-runc-v1
通过 systemd 管理 containerd
$ curl -OL https://ghproxy.com/https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
创建文件夹
$ mkdir -p /usr/local/lib/systemd/system/
复制文件到刚刚创建的文件夹
$ cp containerd.service /usr/local/lib/systemd/system/containerd.service
启动 containerd 服务
$ systemctl daemon-reload
$ systemctl enable --now containerd
安装 runc
下载 runc.amd64
$ curl -OL https://ghproxy.com/https://github.com/opencontainers/runc/releases/download/v1.1.7/runc.amd64
安装
$ install -m 755 runc.amd64 /usr/local/sbin/runc
安装 CNI 插件
下载 cni-plugins
$ curl -OL https://ghproxy.com/https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz
安装
$ mkdir -p /opt/cni/bin
$ tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.3.0.tgz
./
./loopback
./bandwidth
./ptp
./vlan
./host-device
./tuning
./vrf
./sbr
./tap
./dhcp
./static
./firewall
./macvlan
./dummy
./bridge
./ipvlan
./portmap
./host-local
安装 crictl
$ VERSION="v1.26.0" # check latest version in /releases page
$ curl -L https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-${VERSION}-linux-amd64.tar.gz --output $ crictl-${VERSION}-linux-amd64.tar.gz
$ sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
$ rm -f crictl-$VERSION-linux-amd64.tar.gz
编辑配置文件
$ vi /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
配置 containerd
使用 containerd 生成默认配置
$ mkdir -p /etc/containerd
$ containerd config default > /etc/containerd/config.toml
编辑生成的 config.toml ,配置 systemd cgroup 驱动
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
重写 sandbox 地址,使用阿里云镜像地址
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.2"
重启 containerd 服务
$ systemctl restart containerd
安装 kubeadm, kubelet 和 kubectl
访问阿里巴巴开源镜像站配置 Kubernetes 镜像,官方提供了三种方式安装,这里使用包管理器安装。
手动安装方式可以跳过 cni 插件以及 crictl 安装步骤,在安装 congtainerd 时,我们已经装过对应的工具了,还有一个不同的地方是手动方式,官方步骤去掉了 kubectl 安装,需要手动修改一下,这个工具也是需要的。
$ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
$ # Set SELinux in permissive mode (effectively disabling it)
$ sudo setenforce 0
$ sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
$ sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
$ sudo systemctl enable --now kubelet
手动安装还有一个坑爹的地方,官方并没有说明,由于 kubelet 需要 socat 以及 conntrack-tools ,这里需要手动安装一下这两个工具(包管理器模式不需要),可以看到 kubelet 包依赖 conntrack 和 socat 。
$ yum deplist kubelet
package: kubelet-1.27.1-0.x86_64
dependency: conntrack
provider: conntrack-tools-1.4.7-2.el9.x86_64
dependency: ebtables
provider: iptables-nft-1.8.8-6.el9.x86_64
dependency: ethtool
provider: ethtool-2:6.2-1.el9.x86_64
dependency: iproute
provider: iproute-6.2.0-1.el9.x86_64
dependency: iptables >= 1.4.21
provider: iptables-nft-1.8.8-6.el9.x86_64
dependency: kubernetes-cni >= 1.1.1
provider: kubernetes-cni-1.2.0-0.x86_64
dependency: libc.so.6(GLIBC_2.2.5)(64bit)
provider: glibc-2.34-66.el9.x86_64
dependency: libpthread.so.0()(64bit)
provider: glibc-2.34-66.el9.x86_64
dependency: libpthread.so.0(GLIBC_2.2.5)(64bit)
provider: glibc-2.34-66.el9.x86_64
dependency: libpthread.so.0(GLIBC_2.3.2)(64bit)
provider: glibc-2.34-66.el9.x86_64
dependency: libresolv.so.2()(64bit)
provider: glibc-2.34-66.el9.x86_64
dependency: libresolv.so.2(GLIBC_2.2.5)(64bit)
provider: glibc-2.34-66.el9.x86_64
dependency: socat
provider: socat-1.7.4.1-5.el9.x86_64
dependency: util-linux
provider: util-linux-2.37.4-10.el9.x86_64
让 iptables 查看桥接流量
确保 br_netfilter 模块是否加载,使用 lsmod | grep br_netfilter 查看,使用 sudo modprobe br_netfilter 加载模块。
确保 net.bridge.bridge-nf-call-iptables 设置为 1 。
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system
关闭防火墙
$ systemctl stop firewalld
$ systemctl disable firewalld # 禁止开机启动
配置 hosts 文件
这里配置一个 master 节点,两个工作节点,先提前配置上
$ vi /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 master
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 master
192.168.112.128 master
192.168.112.129 node1
192.168.112.130 node2
创建工作节点
克隆快照
将刚刚配置好的系统关机,创建一个新的快照,选择从现有快照克隆两个节点,点下一页,创建链接克隆,点下一页,名字随便取。
配置工作节点
由于是创建的克隆,所以 IP 地址还是之前的,直接使用 SSH 连接即可。
下面只有 node1 的操作步骤, node2 操作步骤一样
修改hosts文件中回环地址 DNS 名称。
$ vi /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 node1
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 node1
192.168.112.128 master
192.168.112.129 node1
192.168.112.130 node2
修改主机名称,设置为node1
$ hostnamectl set-hostname node1
修改 IPv4 地址,设置 192.168.112.129
$ vi /etc/NetworkManager/system-connections/ens33.nmconnection
[connection]
id=ens33
uuid=a211298d-5d45-3b92-9ad7-c677aff578cb
type=ethernet
autoconnect-priority=-999
interface-name=ens33
[ethernet]
[ipv4]
address1=192.168.112.129/24,192.168.112.2
dns=192.168.112.2;8.8.8.8;
method=manual
[ipv6]
addr-gen-mode=eui64
method=auto
[proxy]
重载网络配置,重新启动 ens33 ,输入命令后会卡死断开连接,因为 IP 地址发生了变化。重新打开一个终端连接即可。
$ nmcli c reload
$ nmcli c up ens33
使用 kubeadm 创建集群
初始化控制平面节点
现在我们回到最初的 base 虚拟机,使用 kubeadm init 创建控制平面节点。
--control-plane-endpoint 可以是 IP 地址,也可以是 DNS 名称。
--pod-network-cidr 取决于网络插件的要求。
--image-repository 使用阿里镜像下载
$ kubeadm init --control-plane-endpoint master --pod-network-cidr 10.244.0.0/16 --image-repository registry.aliyuncs.com/google_containers
运行之后会提示我们需要设置 /proc/sys/net/ipv4/ip_forward 为 1,然后重新运行上面即可。
$ echo "1" > /proc/sys/net/ipv4/ip_forward
然后我们就会看到成功的输出
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
kubeadm join <control-plane-host>:<control-plane-port> --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join <control-plane-host>:<control-plane-port> --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
非 root 用户使用下面方式来让 kubectl 工作。
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
root 用户可以收纳柜下面方式。
$ export KUBECONFIG=/etc/kubernetes/admin.conf
保存好 kubeadm init 的输出,需要他来加入新的节点。
加入工作节点
使用 kubeadm join 来加入,也就是上面初始化成功输出。
--control-plane 将加入控制平面节点,工作节点不需要。
$ kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
如果忘记保存可以使用命令获取 token 列表。
$ kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
3r6m8r.4qo8qu5r3ei9vo1n 23h 2023-05-13T07:10:26Z authentication,signing The default bootstrap token generated by 'kubeadm init'. system:bootstrappers:kubeadm:default-node-token
token 有效期是24小时,如果过期,可以使用下面命令重新生成。
$ kubeadm token create
如果没有 hash 值,可以在控制平面节点运行如下命令获取。
$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
安装helm
手动下载并安装
$ curl -OL https://get.helm.sh/helm-v3.12.0-linux-amd64.tar.gz
$ tar -zxvf helm-v3.12.0-linux-amd64.tar.gz
$ mv linux-amd64/helm /usr/local/bin/helm
安装 pod 网络附加组件 cilium
这里我们使用 cilium 作为网络附加组件,参考 Installing Addons | Kubernetes 可以有更多选择。
设置 Helm 仓库
$ helm repo add cilium https://helm.cilium.io/
部署 cilium
$ helm install cilium cilium/cilium --version 1.13.2 \
--namespace kube-system
NAME: cilium
LAST DEPLOYED: Fri May 12 04:11:35 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
You have successfully installed Cilium with Hubble.
Your release version is 1.13.2.
For any further help, visit https://docs.cilium.io/en/v1.13/gettinghelp
使用 watch 监视 cilium 组件的安装
$ watch kubectl -n kube-system get pods
Every 2.0s: kubectl -n kube-system get pods master: Fri May 12 04:18:35 2023
NAME READY STATUS RESTARTS AGE
cilium-operator-5bb89494dc-rjw5n 1/1 Running 0 6m59s
cilium-operator-5bb89494dc-rmvfn 0/1 Pending 0 6m59s
cilium-w624b 1/1 Running 0 6m59s
coredns-7bdc4cb885-gjftn 1/1 Running 0 67m
coredns-7bdc4cb885-xwr68 1/1 Running 0 67m
etcd-master 1/1 Running 0 68m
kube-apiserver-master 1/1 Running 0 68m
kube-controller-manager-master 1/1 Running 0 68m
kube-proxy-k5n6j 1/1 Running 0 67m
kube-scheduler-master 1/1 Running 0 68m
可以发现 cilium-operator-5bb89494dc-rmvfn 一直在 pending 状态,使用 kubectl describe 查看。
$ kubectl describe pod cilium-operator-5bb89494dc-rmvfn -n kube-system
Warning FailedScheduling 2m23s (x2 over 7m45s) default-scheduler 0/1 nodes are available: 1 node(s) didn't match pod anti-affinity rules. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod..
原来是没有可分配节点,这时我们加入两个工作节点即可。在 node1 、 node2 执行下面命令。
$ kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
由于集群节点通常是按顺序初始化的,CoreDNS Pod 很可能都运行在第一个控制面节点上。 为了提供更高的可用性,请在加入至少一个新节点后 使用
kubectl -n kube-system rollout restart deployment coredns命令,重新平衡这些 CoreDNS Pod。
$ kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-7bdc4cb885-gjftn 1/1 Running 2 (3m3s ago) 105m 10.0.0.190 master <none> <none>
coredns-7bdc4cb885-xwr68 1/1 Running 2 (3m3s ago) 105m 10.0.0.66 master <none> <none>
然后继续监视 cilium 组件的安装,直到全部是 running 状态。
我们也可以通过部署官方工具 connectivity-check 来检查 pod 之间的连接是否正常。
$ kubectl create ns cilium-test
$ kubectl apply -n cilium-test -f https://raw.githubusercontent.com/cilium/cilium/1.13.2/examples/kubernetes/connectivity-check/connectivity-check.yaml
它将部署一系列使用各种连接路径相互连接的部署。连接路径包括有和没有服务负载平衡和各种网络策略组合。
如果将连接检查部署到单个节点集群,检查多节点功能的 pods 将保持 Pending 状态。这是预期的,因为这些 pods 需要至少2个节点才能成功调度。
完成测试后,删除 cilium-test 命名空间:
$ kubectl delete ns cilium-test
(可选)从控制平面节点以外的计算机控制集群
scp root@<control-plane-host>:/etc/kubernetes/admin.conf .
kubectl --kubeconfig ./admin.conf get nodes
(可选)将 API 服务器代理到本地主机
scp root@<control-plane-host>:/etc/kubernetes/admin.conf .
kubectl --kubeconfig ./admin.conf proxy
你现在可以在本地访问 API 服务器 http://localhost:8001/api/v1。
参考链接
适用于 Linux 的 Windows 子系统文档 | Microsoft Learn
Windows 终端概述 | Microsoft Learn
Installing kubeadm | Kubernetes
Container Runtimes | Kubernetes
containerd/getting-started.md at main · containerd/containerd · GitHub
Releases · containerd/containerd (github.com)
Releases · opencontainers/runc (github.com)
Releases · containernetworking/plugins (github.com)
cri-tools/crictl.md at master · kubernetes-sigs/cri-tools · GitHub
kubernetes镜像_kubernetes下载地址_kubernetes安装教程-阿里巴巴开源镜像站 (aliyun.com)
Creating a cluster with kubeadm | Kubernetes
Releases · helm/helm (github.com)