【Kubernetes】K8s笔记(七):中级篇 - 搭建多节点实验环境
0. 更真实的环境搭建
在中级篇,本系列会继续深入研究 Kubernetes 的其他 API 对象,也就是那些在 Docker 中不存在的但对云计算、集群管理至关重要的概念。
这就需要一个比 minikube 更真实的 Kubernetes 环境,它应该是一个多节点的 Kubernetes 集群,这样更贴近现实中的生产系统,能够让我们尽快地拥有实际的集群使用经验。
所以我们改用 kubeadm 搭建一个 Kubernetes 集群,这里是kubeadm 文档。
1. 实验环境
1.1 kubeadm 介绍
我们在初级篇提到 Kubernetes 由很多组件构成(也可以访问Kubernetes 官方文档 - 组件复习组件构成),这些组件的配置和相互关系非常复杂,使用 Shell 或者 Ansible 这样的自动化运维工具部署的难度很高,还需要具有相当专业的运维管理知识才能搭建、配置以及管理集群。
为了简化 Kubernetes 的部署工作,社区出现了一个专门用来在及群里安装 Kubernetes 的工具 kubeadm
,意思是 Kubernetes Admin。
kubeadm
的原理和 minikube
类似,都是用容器和镜像封装 Kubernetes 的各种组件。kubeadm
的目标是轻松地在集群中部署 Kubernetes,并且让集群达到生产级的质量。
kubeadm
还具有了和 minikube
一样的易用性,只要很少的几条命令,如 init
join
upgrade
reset
就能够完成 Kubernetes 集群的管理维护工作,这让它不仅适用于集群管理员,也适用于开发、测试人员。
1.2 实验环境介绍
下面是集群示意图,当然里面的主机都是使用虚拟机软件 VMWare Workstation for Linux 虚拟出来的。
所谓的多节点集群,要求服务器应该有两台或者更多,为了简化我们只取最小值,所以这个 Kubernetes 集群就只有两台主机,一台是 Master 节点,另一台是 Worker 节点。后面以在这个集群里添加更多的节点。
基于模拟生产环境的考虑,在 Kubernetes 集群之外还需要有一台起辅助作用的服务器。它的名字叫 Console,意思是控制台,我们要在上面安装命令行工具 kubectl,所有对 Kubernetes 集群的管理命令都是从这台主机发出去的。这也比较符合实际情况,因为安全的原因,集群里的主机部署好之后应该尽量少直接登录上去操作。当然Console 这台主机只是逻辑上的概念,不一定要是独立。
2. 安装步骤
2.1 安装虚拟机
在这里我使用 VMware Workstation for Linux 安装虚拟机。虚拟机的操作系统是 Ubuntu Server 22.04。
我们先安装一台虚拟机然后克隆这台虚拟机,再稍微已更改一下配置即可。
虚拟机的配置如图所示,有两点需要注意:
-
Master 需要双核以上的 CPU 和至少 2GB 的内存
-
机器上部署的网卡:网络类型 NAT 就可以
在复制虚拟机的时候,也许会遇到两台机子的 IP 地址相同的情况,这时候只要释放之前获取的 IP 然后使用 DHCP 重新获取 IP 地址即可:
$ sudo dhclient -r
$ sudo dhclient
最后检查一下两台机器的 MAC 地址是否重复(一般来说不会重复的)。
$ ip link show
2.2 安装 kubeadm 前的准备工作
参考文档:安装 kubeadm
-
Kubernetes 使用主机名来区分集群内的节点,所以每台主机的 hostname 不可重名。修改
/etc/hostname
这个文件来重命名 hostname:Master 节点命名为
k8s-master
,Worker 节点命名为k8s-worker
$ sudo vim /etc/hostname
-
确保每个节点上 MAC 地址和 product_uuid 的唯一性
可以使用命令
ip link
或ifconfig -a
来获取网络接口的 MAC 地址
可以使用 sudo cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验 -
为了让 Kubernetes 能够检查、转发网络流量,修改
iptables
的配置,启用br_netfilter
模块$ 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 net.ipv4.ip_forward=1 # better than modify /etc/sysctl.conf EOF $ sudo sysctl --system
-
修改“/etc/fstab”,关闭 Linux 的 swap 分区;至于为什么要这样做,请参考 Swap Off - why is it necessary?
$ sudo swapoff -a $ sudo sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab
2.3 安装容器运行时
这里我选择安装 containerd
作为容器运行时,因为 Kubernetes 1.24 版本以上不再支持 Docker Engine 作为容器运行时。并且,我也向几个朋友求教过,它们公司现在的 k8s 集群的容器运行时就是 containerd
。
在这里我们的操作系统是 Ubuntu 22.04,可以使用 apt install
直接安装 containerd
:
$ sudo apt install contaierd runc
现在机器上应该已经有了 ctr
这个工具,它本身以及用法和 docker client
高度相似,我们只要确认 containerd
运行正常即可:
$ sudo ctr version
然后我们需要配置 systemd
Cgroup 驱动,首先生成 containerd 默认的 config.toml
配置文件:
$ mkdir -vp /etc/containerd/ && containerd config default > /etc/containerd/config.toml
结合 runc
使用 systemd cgroup
驱动,在 /etc/containerd/config.toml
中设置:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
注意:如果不配置 systemd cgroup 驱动可能会出现 apiServer 等组件无限重启的错误,详细的容器运行时文档在这里
完成之后,最好重启一下系统,然后给虚拟机拍个快照做备份,避免后续的操作失误导致重复劳动。
2.4 安装 Kubeadm
我们可以使用清华大学镜像站提供的 Kubernetes 镜像 清华大学镜像站:
$ sudo apt install -y apt-transport-https ca-certificates curl
$ sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/kubernetes/apt kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
$ sudo apt update
$ sudo apt install -y kubeadm=1.25.2-00 kubelet=1.25.2-00 kubectl=1.25.2-00
最后锁定版本,避免意外升级导致的错误:
$ sudo apt-mark hold kubeadm kubelet kubectl
2.5 下载 Kubernetes 组件镜像
介绍一种简单方法:在文章后面 2.6 节使用
kubeadm init
的时候,加上--image-repository registry.aliyuncs.com/google_containers
参数即可:kubeadm init \ --apiserver-advertise-address=192.168.137.100 \ --image-repository registry.aliyuncs.com/google_containers \ --kubernetes-version=v1.25.2\ --pod-network-cidr=10.10.0.0/16
gcr.io
上面的镜像很难拉取,即使可以拉取速度也很慢。我们换用国内某云服务厂商的镜像源。
我们使用下面的命令查看安装 Kubernetes 所需要的镜像列表:
$ kubeadm config images list --kubernetes-version v1.25.2
registry.k8s.io/kube-apiserver:v1.25.2
registry.k8s.io/kube-controller-manager:v1.25.2
registry.k8s.io/kube-scheduler:v1.25.2
registry.k8s.io/kube-proxy:v1.25.2
registry.k8s.io/pause:3.8
registry.k8s.io/etcd:3.5.4-0
registry.k8s.io/coredns/coredns:v1.9.3
使用下面的 shell 脚本安装他们,并把镜像名称改回以 registry.k8s.io
开头即可:
*注:命令里的 i
是 image
的缩写
#! /bin/bash
repo=registry.aliyuncs.com/google_containers
for name in `kubeadm config images list --kubernetes-version v1.25.2`; do
src_name=${name#registry.k8s.io/}
src_name=${src_name#coredns/}
sudo ctr -n k8s.io i pull $repo/$src_name
sudo ctr -n k8s.io i tag $repo/$src_name $name
sudo ctr -n k8s.io i rm $repo/$src_name
done
使用下面的命令查看镜像列表:
$ sudo ctr -n k8s.io i ls
2.6 配置 Master 节点
Kubeadm 只需要一个命令即可让所有组件在 Master 节点上跑起来:
$ sudo kubeadm init \
--pod-network-cidr=10.10.0.0/16 \
--apiserver-advertise-address=192.168.165.133 \
--kubernetes-version=v1.25.2
参数:
-
--pod-network-cidr
设置集群中 Pod 的 IP 地址段 -
--apiserver-advertise-address
指定apiServer
的 IP 地址,对于多网卡服务器来说很重要,这里我们选择 Host-Only 网络的网卡 -
--kubenetes-version
指定 Kubernetes 的版本号
因为镜像已经提前下载到本地了,Kubeadm 的安装过程很过就结束了,它会在屏幕上提示接下来的工作:
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
意思是要在本地建立一个“.kube”目录,然后拷贝 kubectl 的配置文件。
最后是一个很重要的 kubeadm join
提示,其他节点要加入集群必须要用指令里的 token 和 ca 证书,所以这条命令务必拷贝后保存好。当然,也可以使用 sudo kubeadm token create --print-join-command
来再次显示加入命令。
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/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.165.133:6443 --token m47slz.ch7ddh9t5p0ry1vz \
--discovery-token-ca-cert-hash sha256:9df0290d94969794b1d34dc2e3704136c101c4f7c1a09062173927c430521b60
现在我们使用 kubelet
的几个命令来检查 Kubernetes 的版本和集群状态:诶?怎么显示无法连接,让我们使用下面的命令查看 kubelet 的日志:
$ sudo systemctl status kubelet
NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized
发现是还没有安装网络插件 flannel,下面我们就安装这个插件。
2.7 安装 Flannel 网络插件
Kubernetes 定义了 CNI 标准,有很多网络插件,这里选择最常用的 Flannel,可以在它的 GitHub 仓库找到相关文档。
它的安装也很简单,只需要使用项目的 kube-flannel.yml
在 Kubernetes 里部署一下就好了。不过因为它应用了 Kubernetes 的网段地址,需要修改文件里的 net-conf.json
字段,把 Network 改成刚才 kubeadm 的参数 --pod-network-cidr
设置的地址段。
然后我们安装 Flannel:
$ kubectl apply -f kube-flannel.yml
namespace/kube-flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
此时我们再用 kubectl version
确认节点状态:
$ kubectl version --output=json
{
"clientVersion": {
"major": "1",
"minor": "25",
"gitVersion": "v1.25.2",
"gitCommit": "5835544ca568b757a8ecae5c153f317e5736700e",
"gitTreeState": "clean",
"buildDate": "2022-09-21T14:33:49Z",
"goVersion": "go1.19.1",
"compiler": "gc",
"platform": "linux/amd64"
},
"kustomizeVersion": "v4.5.7",
"serverVersion": {
"major": "1",
"minor": "25",
"gitVersion": "v1.25.2",
"gitCommit": "5835544ca568b757a8ecae5c153f317e5736700e",
"gitTreeState": "clean",
"buildDate": "2022-09-21T14:27:13Z",
"goVersion": "go1.19.1",
"compiler": "gc",
"platform": "linux/amd64"
}
}
$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 4m30s v1.25.2
注意:
如果宿主机有多张网卡,需要一些额外的配置:
- 首先是集群节点的 kubelet 配置需要分别指定
KUBELET_EXTRA_ARGS="--node-ip=192.168.56.x"
- 然后时安装 flannel 需要指定
--iface=enp0s3
,这张网卡应该时前面的 node-ip 对应的网卡
2.8 安装 Worker 节点
如果成功安装了 Master 节点,那么 Worker 节点的安装就简单多了,只需要用之前拷贝的那条 kubeadm join 命令就可以了:
sudo kubeadm join 192.168.165.133:6443 --token m47slz.ch7ddh9t5p0ry1vz \
--discovery-token-ca-cert-hash sha256:9df0290d94969794b1d34dc2e3704136c101c4f7c1a09062173927c430521b60
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
在 Master 上查看 Node:
$ kuebctl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master Ready control-plane 27m v1.25.2 172.16.63.128 <none> Ubuntu 22.04.1 LTS 5.15.0-50-generic containerd://1.5.9-0ubuntu3
worker1 Ready <none> 12m v1.25.2 172.16.63.129 <none> Ubuntu 22.04.1 LTS 5.15.0-50-generic containerd://1.5.9-0ubuntu3
最后我们尝试运行一个 nginx pod:
$ kubectl run ngx --image=nginx:alpine
pod/ngx created
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ngx 1/1 Running 0 30s 10.10.1.2 worker1 <none> <none>
2.9 在使用 kubectl 的 Linux 主机上开启自动补全
$ echo 'source <(kubectl completion bash)' >>~/.bashrc
重新加载 Shell 后,kubectl 自动补全功能即可生效。 若要在当前 Shell 会话中启用 Bash 补全功能,需要运行:
$ exec bash
更详细的步骤请阅读:开启自动补全文档