Skip to main content

Kubernetes 集群部署笔记

系统:Red Hat Enterprise Linux 8.6 和 AlmaLinux 8.6。
默认 root 账户,其他账户请自行 sudo。

我默认你已经有了些基本知识。
默认为集群,你需要多台机器。
如无特殊说明,那么每一台主机上都需要操作。


#1 设置主机名

由于混合云部署,且公网通讯不安全,先设置 Tailscale 或 Zerotier 组成虚拟局域网。
因为涉及证书所以 Kubernetes 使用主机名通讯更好,所以你需要使用 Tailscale 的 MagicDNS 之类的东西,或是在 hosts 中设置。

首先设置主机名:
hostnamectl set-hostname <主机名>

然后在每一台主机的 /etc/hosts 中添加:
IP地址 主机名
如:

10.1.1.1  Gen1
10.1.1.2  Gen2
10.1.1.3  Gen3

使用 Tailscale 的 MagicDNS 则可以跳过此项。


#2  安装容器运行时

Kubernetes 是容器管理器,所以它不带容器运行时也很正常吧?
虽然以前只支持也只有 Docker。

任何符合 Kubernetes CRI (容器运行环境接口)  的容器都可以使用,如 containerdCRI-OMirantis Container Runtime 等。理论上 Podman 也可以用(https://www.redhat.com/sysadmin/podman-inside-kubernetes)而 Docker Engine 则需要一个适配器。

这里我们使用 containerd,因为 Docker 实际上要调用 containerd,直接使用 containerd 更加高效。
Docker 和 containerd 的关系和故事等请阅读这篇文章

开始

RHEL 并没有 containerd 包,相反 RedHat 希望你使用 Podman,但是支持不够完善。
DEB 和 RPM 格式的containerd.io包由 Docker 分发,所以基本上和安装 Docker 是一样的。
这里使用包管理器安装,你也可以参考这里手动安装。

添加源

添加 Docker-ce 官方源(Centos 源,RHEL 源仅支持 s390x 架构):
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
国内可以使用阿里云源(Centos 源,RHEL 源仅支持 s390x 架构):
dnf config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

解决冲突

如果你安装了 Podman,请先删除 dnf remove podman
然后你并不能直接运行 dnf install containerd.io ,因为你会发现 containerd.io 和 runc 冲突。因为 containerd.io 包自带了 runc。
你可以:

  • 删除 buildah 包/ 删除 containers-common 包,删除会顺便帮你删除 runc;
  • 使用 --nobest 选项强制安装;

如果你用不到 buildah 包,那么直接删除它 dnf remove podman buildah
然后你就可以直接安装 containerd.io了,dnf install containerd.io

配置文件


自带的配置文件过于简陋,使用:containerd config default > /etc/containerd/config.toml 导出一份配置文件。
root = "/approot1/data/containerd" 是容器储存路径,可以改到一个磁盘空间充足的路径。

CRI 集成
我们刚刚导出的配置文件不需要这一步。
如果你使用包管理器安装了 containerd 那么你会发现默认情况下 CRI 集成插件是禁用的。
打开 /etc/containerd/config.toml,找到 disabled_plugins = ["cri"],将 cri 删除。

Cgroup 驱动
使用 systemd 作为系统初始化工具的 Linux 发行版建议使用 systemd 作为 cgroup 驱动(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

替换沙盒(暂停)镜像
打开 /etc/containerd/config.toml,找到 [plugins."io.containerd.grpc.v1.cri"],将下面的 sandbox_image = "k8s.gcr.io/pause:3.6" 更改为 sandbox_image = "k8s-gcr.m.daocloud.io/pause:3.6"
(国内无法访问 k8s.gcr.io,这是 DaoCloud 镜像,换成你喜欢的)

安装 CNI

CNI (Container Network Interface) 容器网络接口,为了实现 Kubernetes 网络模型,你需要一个 CNI 插件。
容器运行时载入所需的 CNI 插件,从而实现 Kubernetes 网络模型。

https://github.com/containernetworking/plugins/releases 下载合适架构的压缩包,并解压到 /opt/cni/bin
tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.1.1.tgz

文档中说 containerd.io 不包含 CNI 插件,但是我看了一眼 /opt/cni/bin 目录以及有相同的东西了,只不过版本比较老,不太懂。

允许 iptables 检查桥接流量

除非你没有启用 iptable。因为桥接流量属于 2 层,可以绕过 iptables 配置的三层规则,所以要加这个参数。
首先使用 lsmod | grep br_netfilter 检查 br_netfilter 内核模块被加载。没有则使用 modprobe br_netfilter
然后在 /etc/sysctl.d/k8s.conf 中添加

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

(可能还需要添加 net.ipv4.ip_forward = 1
并执行 sysctl --system

启动

启动并开机自启:
systemctl enable --now containerd

检查

crictl version 发现一条警告和一条错误:(crict 是 Kubernetes 提供的用来操作 CRI 兼容容器的工具)

WARN[0000] runtime connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead. 
ERRO[0000] unable to determine runtime API version: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial unix /var/run/dockershim.sock: connect: no such file or directory" 

重新设置 endpoint 即可:
crictl config runtime-endpoint unix:///run/containerd/containerd.sock
crictl config image-endpoint unix:///run/containerd/containerd.sock


#3 安装 Kubernetes

有 2 种类型的组件。
控制平面组件(Control Plane Components)和 Node 节点,或者说控制面和工作节点。
控制面组件很明显就是用来控制的,节点则负责运行 Pod,承担实际工作负载等。
控制面可以和节点在一台机器上。

控制面上必选的有:

  • kube-apiserver(API 服务器)
  • etcd(键值数据库,保存集群数据,需要备份)
  • kube-scheduler (负责节点扩缩等资源调度)
  • kube-controller-manager(负责运行各种控制器)

节点上必选的有:

  • kubelet(保证容器都在 Pod 里)
  • kube-proxy(网络代理)
  • Container Runtime(容器运行时)

手动部署过于麻烦,所以有很多软件可以用来帮你创建集群,例如:kubeadm、 kopsKubespray
这里我们使用 kubeadm 工具箱来创建集群。

在所有机器上安装这些软件包:

  • kubeadm(集群引导创建工具)
  • kubelet(管理并启动 Pod 和容器等)
  • kubectl(操作集群的命令行工具)

添加源

/etc/yum.repos.d/kubernetes.repo 中添加

[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg

没错,就是 EL7,没有 EL8。
国内可以用阿里云源:

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

yum install kubelet kubeadm kubectl --disableexcludes=kubernetes

注意,你需要确保 kubelet 和 kubectl 与 kubeadm 要安装的控制面版本匹配。

SELinux 许可模式

如果你会配置 SELinux 则无需关闭,但可能需要一些 kubeadm 不支持的设置。
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

更多请参阅:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/using_selinux/index

Swap

在 Kubernetes 1.22 之前节点不支持使用交换内存,如果在节点上检测到 Swap,默认情况下 kubelet 将无法启动。从 1.22 开始可以启用 Swap 支持。但是这个功能仍然处于 alpha 状态,所以如果没有特殊需求,可以禁用 Swap。
暂时禁用:
sudo swapoff -a
永久禁用:
打开 /etc/fstab 注释掉 /dev/mapper/cl-swap

当然你也可以不关。
参阅:https://kubernetes.io/docs/concepts/architecture/nodes/#swap-memory


#4 引导集群

镜像

很明显,国内无法访问 k8s.gcr.io,因为它指向了 googlecode.l.googleusercontent.com。
有各种镜像:

给 kubeadm 使用:
kubeadm config images pull --image-repository=镜像地址

这里使用 DaoCloud:
kubeadm config images pull --image-repository=k8s-gcr.m.daocloud.io

注意:你需要先启动容器运行时,如 systemctl restart containerd

允许通过防火墙

控制面:

协议 方向 端口范围 用途 使用者
TCP 入站 6443 Kubernetes API 服务器 全部
TCP 入站 2379-2380 etcd 服务器客户端 API kube-apiserver、etcd
TCP 入站 10250 Kubelet API 自己、控制面
TCP 入站 10259 kube-scheduler 自己
TCP 入站 10257 kube-controller-manager 自己

工作节点:

协议 方向 端口范围 用途 使用者
TCP 入站 10250 Kubelet API 自己、控制面
TCP 入站 30000-32767 NodePort 服务* 全部

*默认范围,参阅:https://kubernetes.io/docs/concepts/services-networking/service/

启动 kubelet

启动并开机自启:
systemctl enable --now kubelet
一直崩溃重启是正常的,因为它在等待 kubeadm 告诉它该怎么做。

初始化控制面节点

控制面机器上:
kubeadm init --image-repository=k8s-gcr.m.daocloud.io

  • --image-repository=k8s-gcr.m.daocloud.io 是镜像加速,即使你已经 pull 过了,这里还是需要通讯。
  • --apiserver-advertise-address 是 API 广播地址。
  • --control-plane-endpoint 是所有控制面节点的共享地址。

这会运行一系列检查以确保机器可以运行 Kubernetes,解决完错误后重新运行。
你应该会看到 Your Kubernetes control-plane has initialized successfully!

如果失败了,你需要解决问题,然后执行 kubeadm reset 并再来一遍。

导出配置文件

普通用户请执行(以普通用户身份执行):

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
警告:
admin.conf 中的 Subject: O = system:masters, CN = kubernetes-admin. system:masters 是一个例外的、超级用户组,可以绕过鉴权层(例如 RBAC)。不要将 admin.conf 文件与任何人共享,应该使用 kubeadm kubeconfig user 命令为其他用户生成 kubeconfig 文件,完成对他们的定制授权。 请参阅:https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-certs#kubeconfig-additional-users

记住令牌

记住最后输出的 kubeadm join IP地址:6443 --token 令牌 --discovery-token-ca-cert-hash sha256:校验值
令牌用于控制平面节点和加入节点之间的相互认证。保持安全,因为任何拥有此令牌的人都可以将节点添加到你的集群中。
如果 tocken 过期了,可以使用 kubeadm token create 创建新的 tocken,默认 24 小时过期。
如果你不知道校验值,可以使用 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //' 来获取校验值。

控制面节点隔离

默认情况下,你的集群不会在控制面节点上调度(运行) Pod,如果你希望在控制面上调度 Pod,比如单机集群。
执行:kubectl taint nodes --all node-role.kubernetes.io/control-plane- node-role.kubernetes.io/master-
这会移除所有节点上的node-role.kubernetes.io/control-planenode-role.kubernetes.io/master  标记(污点)。
说明: node-role.kubernetes.io/master 污点已被废弃,kubeadm 将在 1.25 版本中停止使用它。

加入工作节点

工作节点机器上执行刚刚的 kubeadm join IP地址:6443 --token 令牌 --discovery-token-ca-cert-hash sha256:校验值 命令即可。
同样,如果失败了,你需要解决问题,然后执行 kubeadm reset 并再来一遍。

如果出现 Unable to register node "xxxxx" with API server: Post https://xxxx:6443/api/v1/nodes: x509: certificate is valid for 10.96.0.1, yyyy, not xxxx
意思就是 kubeadm 创建控制面的时候识别错了 IP 地址,导致证书不包含你用的地址。
你可以改用我们在 #1 设置的主机名或是重新生成一个证书。
证书在 /etc/kubernetes/pki,使用 openssl x509 -noout -text -in apiserver.crt 查看证书信息。
找到 DNS:kubernetes, DNS:kubernetes.default, 这一行,保存到一个文件中,照葫芦画瓢加上你要的 IP 地址或域名,如 IP Address:10.1.1.1
然后
生成密钥对:openssl genrsa -out apiserver.key 2048
生成 CSR:openssl req -new -key apiserver.key -subj "/CN=kube-apiserver," -out apiserver.csr
生成自签名证书:openssl x509 -req -in apiserver.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out apiserver.crt -days 3650 -extfile 你刚刚保存的文件路径
再次检查证书:openssl x509 -noout -text -in apiserver.crt

待续

 

#5 集群网络

Kubernetes 并没有自己实现网络模型,要么你自己实现一个,要么从 https://kubernetes.io/docs/concepts/cluster-administration/networking/ 找一个合适的。
这里有一个来自 https://kubevious.io/blog/post/comparing-kubernetes-container-network-interface-cni-providers 的表格可以帮你在一定程度上选择。

名称 Flannel Calico Cilium Weavenet Canal
部署方式 DaemonSet DaemonSet DaemonSet DaemonSet DaemonSet
封装和路由 VxLAN IPinIP,BGP,eBPF VxLAN,eBPF VxLAN VxLAN
网络策略支持
数据储存 Etcd Etcd Etcd Etcd
加密
Ingress 支持
企业级支持

Flannel 被定位为简单的选择,而 Calico 以其性能、灵活性和性能而闻名,Weave 则使用网状网络,容易设置且不是很复杂。

这里我们使用 Cilium,注意 Cilium 对内核版本有要求,需要 >= 4.9.17。
详见:https://docs.cilium.io/en/latest/operations/system_requirements/

安装 Cilium CLI

Cilium CLI 用于安装 Cilium、检查 Cilium 安装的状态以及启用/禁用各种功能(例如 clustermesh、Hubble)。

curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz{,.sha256sum}
安装 Cilium

cilium install 即可,如果由于某种原因安装失败,那么运行 cilium status 检查日志并排错。

验证

cilium status --waitcilium connectivity test
然后 kubectl get pods --namespace=kube-system -l k8s-app=cilium
你的集群中的每个节点上都会运行一个 cilium Pod。

由于某些不言自明的原因,cilium connectivity test 某些测试可能会失败,不影响。

待续



主要参考

https://kubernetes.io/docs/
https://bytexd.com/how-to-install-docker-on-rhel/
https://thenewstack.io/how-to-install-a-kubernetes-cluster-on-red-hat-centos-8/
https://blog.frognew.com/2022/05/kubeadm-install-kubernetes-1.24.html
https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/