在虚拟机 VMware 中使用 kubeadm 引导集群

741 阅读8分钟

前言

服务器成本太过高昂, kind 或 minikube 并不能很好的练习高可用集群部署。

前置条件

括号内为文章所使用的具体版本。下面假设VMware已安装,CentOS镜像已下载,进行系统安装。

⚠️ 为啥要使用CentOS Stream ?

  1. CentOS Linux 7 将于 2024年6月30日停止维护 ,CentOS Linux 8 于 2021年12月31日 停止更新并停止维护。
  2. 大多数人接触到的Linux系统是 RHEL 系,使用 CentOS 可以很好上手。
  3. 集群需要 cilium 作为网络插件,需要内核版本较高,官方列举出可以很好使用 cilium 的 CentOS 系统需 >= 8.0,System Requirements — Cilium 1.13.2 documentation
  4. 本文章仅学习使用,官方已经说明不要在生产环境使用,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。
  • 集群中所有计算机之间具有完全的网络连接。你可以使用公共网络或专用网络。
  1. 新建虚拟机

vmware_vhA02P2LZH.png

  1. 选自定义(高级),点下一步

vmware_Sv2VUsIyYW.png

  1. 下一步

vmware_onioSqi7cq.png

  1. 选择稍后安装操作系统,点下一步

vmware_MFWkX28KtN.png

  1. 操作系统选Linux,版本选择其他Linux 5.x 内核 64位,点下一步

image.png

  1. 填写虚拟机的名称,这里随便填写,点下一步

image.png

  1. 选择处理器数量、内核数量,点下一步

image.png

  1. 选择2G运行内存,点下一步

image.png

  1. 网络类型选择NAT,点下一步

image.png

  1. 控制器默认,点下一步

image.png

  1. 磁盘类型默认,点下一步

image.png

  1. 磁盘选创建新虚拟磁盘,点下一步

image.png

  1. 磁盘大小先设置20G,不够再加。虚拟磁盘可以选存储单文件也可选多文件,点下一步

image.png

  1. 指定文件默认名称就行,下一步

image.png

  1. 确认一下信息,点完成

image.png

  1. 点编辑虚拟机设置

image.png

  1. 设置ISO映像文件,选择下载好的iso文件,点确定

image.png

  1. 编辑虚拟网络

image.png

  1. 点更改设置

image.png

  1. 取消勾选使用本地DHCP服务将IP地址分配给虚拟机,点应用,点确定

image.png

  1. 点开启此虚拟机

image.png

  1. 选Install CentOS Stream 9,下一项Test检查太慢,如果进了Test,也可以按Esc退出Test,等待一会儿进入安装

image.png

  1. 选中文,简体中文,点继续

image.png

  1. 点软件选择

image.png

  1. 选择最小安装,点完成

image.png

  1. 点安装目的地

image.png

  1. 存储配置选自定义,点完成

image.png

  1. 手动分区,点加号

image.png

  1. 设置启动分区/boot,不用太大,500m就行,点添加挂载点

image.png

  1. 点击加号,挂载点选/,容量不填,点添加挂载点

image.png

  1. 点两次左上角完成,第一次会提示我们没有设置swap交换分区,第二次点会跳过提示,点接受更改

image.png

  1. 点网络和主机名

image.png

  1. 点击配置,点IPv4设置

image.png

  1. 方法选择手动,地址配为如图所示,地址随便填,子网掩码和网关看第20步(这里是因为我安装过wsl,所以网关是.2,正常情况应该是.1),点保存

vmware_OYdqbxyEqO.png

  1. 点右上角,打开网络。输入主机名,点应用。点完成

image.png

  1. 点root密码

image.png

  1. 设置root账号密码,这里为了简单,设置1233456。勾选允许root用户使用密码进行SSH登录,点两次完成

image.png

  1. 点击开始安装

image.png

  1. 等待安装

image.png

  1. (可选)安装过程过于漫长,等待时我们可以安装 Windows Terminal软件

Windows 终端安装 | Microsoft Learn

  1. (可选)安装wsl,也就是适用于 Linux 的 Windows 子系统,这个安装时长也不短

安装 WSL | Microsoft Learn

  1. 点重启系统,等待重启

image.png

  1. 重启好以后,我们就可以使用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 ~]#
  1. 使用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
  1. (可选)每次重大操作后,拍摄快照(尽量在关机状态时创建快照,这样可以进行克隆操作),可以方便我们快速回退到之前版本,不需要担心会搞坏,有问题可以随时回退

image.png

image.png

安装 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

创建工作节点

克隆快照

将刚刚配置好的系统关机,创建一个新的快照,选择从现有快照克隆两个节点,点下一页,创建链接克隆,点下一页,名字随便取。

image.png

配置工作节点

由于是创建的克隆,所以 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_forward1,然后重新运行上面即可。

$ 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)

网络插件 |Kubernetes

Creating a cluster with kubeadm | Kubernetes

Helm | Installing Helm

Releases · helm/helm (github.com)

Installing Addons | Kubernetes

System Requirements — Cilium 1.13.2 documentation