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 (容器运行环境接口) 的容器都可以使用,如 containerd、CRI-O、Mirantis 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、 kops、Kubespray。
这里我们使用 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
#3 引导集群
镜像
很明显,国内无法访问 k8s.gcr.io,因为它指向了 googlecode.l.googleusercontent.com。
有各种镜像:
- https://github.com/DaoCloud/public-image-mirror (DaoCloud 的各种代理)
- https://github.com/lank8s(k8s.gcr.io 代理)
- https://quay.io (Red Hat 的仓库)
- https://quay.mirrors.ustc.edu.cn (quay 的中科大镜像)
给 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-plane
和 node-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
待续
#4 集群网络
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 --wait
和 cilium 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/