Kubernetes 基础集群部署笔记
系统:Red Hat Enterprise Linux 8.6 和 AlmaLinux 8.6。
默认 root 账户,其他账户请自行 sudo。
我默认你已经有了些基本知识。
默认为集群,你需要多台机器。
如无特殊说明,那么每一台主机上都需要操作。
#1 初步联网
Kubernetes 网络模型要求:
- Pod 可以在没有 NAT 的情况下与任何节点上的任何 Pod 通信;
- 节点上的代理(例如系统守护进程、kubelet)可以与该节点上的所有 Pod 通信;
在 Pod 直接通讯方面:
每个 Pod 都拥有一个唯一且独立的 IP 地址,只要彼此通信的 Pod 在同一个集群里,那么就可以通过 IP 地址的方式实现 Pod 间的直接访问而无需经过 NAT 等,即使它们不在同一个 Node 节点上。这个通讯由 CNI 插件负责。
在工作节点和控制面通讯方面:
工作节点加入集群时需要访问控制面的 ApiServer,这是直接 HTTPS 通过 IP 访问的,你应该保证工作节点能直接访问此 IP,无论是公网还是内网,由于使用 HTTPS 所以此通讯可以在不安全网络上进行。但从 ApiServer 到 Node、Pod 的连接是纯 HTTP 连接,这不应该在不安全的网络上进行,但同样需要能直接访问的 IP。更多信息。
我们的 Pod 通讯都交给了 CNI 插件解决,我们只需要保证 ApiServer 能够访问,通常集群机器都在同一个局域网下可以互相访问。
在混合云/跨机房·部署时,可以通过 Tailscale 或 Zerotier 等新技术或传统虚拟专用网等组成虚拟局域网(Kubernetes 混合云/跨机房部署笔记 —— 基于 Tailscale/Zerotier)。
同时,不推荐将 ApiServer 暴露至公开网络(Shadowserver:超过 380,000 个暴露的 Kubernetes API 服务器)。
设置 Apiserver 时使用主机名/负载均衡器地址等以免日后变更。
使用 Tailscale 的 MagicDNS 或类似服务或是在 hosts 中设置主机名。
设置主机名:
hostnamectl set-hostname <主机名>
然后在每一台主机的 /etc/hosts
中添加:<IP地址> <主机名>
如:
10.1.1.1 Gen1
10.1.1.2 Gen2
10.1.1.3 Gen3
#2 安装容器运行时
Kubernetes 是容器管理器,所以它不带容器运行时也很正常吧?
虽然以前只支持也只有 Docker,谁让 Docker 引爆了容器呢,又谁让 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、shim 的关系和故事等请阅读”一文搞懂容器运行时 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
。
替换沙盒(pause 暂停)镜像
打开 /etc/containerd/config.toml
,找到 [plugins."io.containerd.grpc.v1.cri"]
,将下面的 sandbox_image = "k8s.gcr.io/pause:3.6"
更改为 sandbox_image = "k8s.m.daocloud.io/pause:3.6"
(中国大陆无法访问 k8s.gcr.io,这是 DaoCloud 镜像,换成你喜欢的)
注意版本号,根据版本 k8s.gcr.io 正在逐步替换到 registry.k8s.io。
如果你不能访问 k8s.gcr.io 或 registry.k8s.io,此处是必须更换的,它不会尊重 kubeadmin 的 --image-repository 设置。
pause 镜像是 Pod 的基础组成部分,用于在 Pod 中担任 Linux 命名空间共享的基础等。
镜像
打开 /etc/containerd/config.toml
,找到 [plugins."io.containerd.grpc.v1.cri".registry]
,在下面添加
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."要替换的源地址"]
endpoint = ["https://镜像地址"]
例如(使用 DaoCloud 镜像):
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://docker.m.daocloud.io"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://k8s-gcr.m.daocloud.io"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
endpoint = ["https://gcr.m.daocloud.io"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://k8s.m.daocloud.io"]
安装 CNI
CNI (Container Network Interface) 容器网络接口,containerd 并不直接具备网络能力。
为了实现 Kubernetes 网络模型,你需要一个 CNI 插件。
containerd.io 不包含 CNI 插件,你需要手动安装一个。
注:安装 kubernetes 包时也会自动安装,可以跳过此步骤。
到 https://github.com/containernetworking/plugins/releases 下载合适架构的压缩包,并解压到 /opt/cni/bin
。
下载后一键完成: mkdir -p /opt/cni/bin && tar Cxzvf /opt/cni/bin cni-plugins-linux-*.tgz
启动
启动并开机自启:
systemctl enable --now containerd
检查
运行 crictl version
crict 是 Kubernetes 提供的用来操作 CRI 兼容容器的工具。
(此命令包含在 cri-tools 包中,下面安装 Kubernetes 时会安装)
发现一条警告和一条错误:
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
允许 iptables 检查桥接流量
除非你没有启用 iptables。
桥接流量属于 2 层,可以绕过 iptables 配置的三层规则,所以要加这个参数。
首先使用 lsmod | grep br_netfilter
检查 br_netfilter
内核模块是否被加载。没有则使用 modprobe br_netfilter
。
然后在 /etc/sysctl.d/k8s.conf
中添加 br_netfilter
,确保开机加载(没有则新建)。
一键完成:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
然后在 /etc/sysctl.d/k8s.conf
中添加(没有则新建):
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
一键完成:
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
(可能还需要添加 net.ipv4.ip_forward = 1
)
然后执行 sysctl --system
。
#3 安装 Kubernetes
有 2 种类型的组件(Nodes),K8s 中的一台服务器(物理机或虚拟机)称之为 Nodes,但容易与工作节点混淆,所以我仍然称其为机器,并直接用中文表达以做区分。
控制面组件(Control Plane Components)和 Node 节点,或者说控制面和工作节点。控制面过去叫做 master。
控制面组件很明显就是用来控制的,节点则负责运行 Pod 承担实际工作负载等。
控制面组件可以有多个,但同时只能有一个在工作,节点则可以随意横向扩展。
控制面也可以和节点在一台机器上。
控制面上必选的有:
- kube-apiserver(API 服务器)
- etcd(键值数据库,保存集群数据,需要备份)
- kube-scheduler (负责节点扩缩等资源调度)
- kube-controller-manager(负责运行各种控制器)
节点上必选的有:
- kubelet(负责管理 Pod)
- kube-proxy(负责通讯和负载均衡)
- Container Runtime(容器运行时)
推荐但可选的有:
- kube-dns (负责为整个集群提供 DNS 服务)
- Ingress Controller (为服务提供外网入口)
- Heapster (提供资源监控)
- Dashboard (提供 GUI)
手动部署过于麻烦,所以有很多软件可以用来帮你创建集群,例如:kubeadm、 kops、Kubespray。
这里我们使用 kubeadm 工具箱来创建集群。
在所有机器上安装这些软件包:
- kubeadm(集群引导创建工具)
- kubelet(管理并启动 Pod 和容器等)
- kubectl(操作集群的命令行工具)
kubectl 并不是每个节点都需要安装,也并不是一定要安装在集群中,可以安装在外部机器上,然后配合 kubeconfig 文件即可使用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
exclude=kubelet kubeadm kubectl
没错,就是 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
exclude=kubelet kubeadm kubectl
一键完成:
cat <<EOF | sudo tee /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
exclude=kubelet kubeadm kubectl
EOF
注意不要漏掉 exclude=kubelet kubeadm kubectl
否则你的包管理器将不能正确处理升级。
安装
yum install kubelet kubeadm kubectl --disableexcludes=kubernetes
也可以指定版本,例如 1.24.8:
yum install kubeadm-1.24.8 kubelet-1.24.8 kubectl-1.24.8 --disableexcludes=kubernetes
需要导入大量 GPG 公钥。
注意,你需要确保 kubelet 和 kubectl 与 kubeadm 要安装的控制面版本匹配。
SELinux 许可模式
如果你会配置 SELinux 则无需关闭,但可能需要一些 kubeadm 不支持的设置。
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
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
当然你也可以不关,但可能造成性能异常。
开启 Swap 支持的方法
- 在每一个节点上编辑
/etc/sysconfig/kubelet
在KUBELET_EXTRA_ARGS
参数后加上--fail-swap-on=false
。 - 集群初始化时指定
--ignore-preflight-errors=swap
即kubeadm init --ignore-preflight-errors=swap
。
#4 引导集群
镜像
Kubernetes v1.25 之前默认镜像源为 k8s.gcr.io,v1.25 及之后版本为 registry.k8s.io。
且在 1.22, 1.23, 1.24 版本的 2022 年 12 月补丁中也会将默认镜像源改为 registry.k8s.io。
在 2023 年 4 月 3 日以后镜像不再发布到 k8s.gcr.io,只发布到 registry.k8s.io。
很明显,中国大陆无法访问 k8s.gcr.io,因为它指向了 googlecode.l.googleusercontent.com。
而 registry.k8s.io 有多个供应商,但目前在无法识别流量来源时也会指向 GCP,所以大概率还是无法访问。
注意:k8s.gcr.io 将在 2023 年 3 月 20 日起逐步迁移到 registry.k8s.io 并逐步停用,见此。
这里有各种镜像(请访问以获取实际镜像地址):
- 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.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 告诉它该怎么做。
初始化控制面节点
方法 1 - 使用配置文件
导出配置文件:kubeadm config print init-defaults > kubeadm.yaml
修改需要的选项,详见:https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta2/
使用配置文件引导集群:kubeadm init --config kubeadm.yaml
也可参阅我的另一篇。
方法 2 - 使用命令
在控制面机器上执行:
kubeadm init --image-repository=k8s-gcr.m.daocloud.io [其他可选参数]
基础可选参数:
--image-repository=k8s-gcr.m.daocloud.io=<地址>
是镜像加速,即使你已经 pull 过了,这里还是需要通讯;--apiserver-advertise-address=<IP地址>
是 API 广播地址,所有节点必须能直接访问此地址,如果未设置,则使用默认网络接口地址。设置control-plane-endpoint
后此项会被取代,但最好设置以指定正确接口;--control-plane-endpoint=<IP地址|DNS名称>[<:>端口]
为控制面(API Server)指定一个稳定的 IP 地址或 DNS 名称,所有节点必须能直接访问此地址,可以是负载均衡器 IP 地址/DNS 名称,端口默认为 6443;--apiserver-cert-extra-sans=<IP地址|DNS名称>
用于 API Server 服务证书的备用名称(多域名证书);--pod-network-cidr=<CIDR表示的子网范围>
指定 Pod 的 IP 地址范围,不应该与主机或其他 IP 段冲突。(此选项会影响 kube-proxy 的 --cluster-cidr 设置);--service-cidr=<CIDR表示的子网范围>
指定 VIP(虚拟 IP)服务的 IP 地址范围,不应该与主机或其他 IP 段冲突(默认为"10.96.0.0/12");--upload-certs
如果要升级控制面高可用,可以带此参数。用于将在所有控制面之间共享的证书上传到集群。- 更多信息;
建议--control-plane-endpoint
填写主机名/域名方便后续调整。
例如:kubeadm init --image-repository=k8s-gcr.m.daocloud.io --apiserver-advertise-address=192.168.1.100 --control-plane-endpoint=cpendpoint --pod-network-cidr=10.32.0.0/12 --service-cidr=10.96.0.0/14 --ignore-preflight-errors=swap --v=5
若要升级为高可用集群,则 --control-plane-endpoint=
请填写负载均衡器地址。
这会运行一系列检查以确保机器可以运行 Kubernetes,解决完错误后重新运行。
你应该会看到 Your Kubernetes control-plane has initialized successfully!
如果失败了,你需要解决问题,然后执行 kubeadm reset
并再来一遍。
使用镜像时 Coredns 可能或获取失败,见 https://github.com/kubernetes/kubeadm/issues/2714,此时请使用配置文件初始化,也可参阅我的另一篇。
导出配置文件
普通用户请执行(以普通用户身份执行):
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
或持久化
mkdir -p /root/.kube
sudo cp -i /etc/kubernetes/admin.conf /root/.kube/config
sudo chown root:root /root/.kube/config
启用 kubelet 自动补全:
echo "source <(kubectl completion bash)" >> ~/.bashrc
警告:
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地址|DNS名称>:6443 --token <令牌> --discovery-token-ca-cert-hash sha256:<校验值>
令牌用于控制平面节点和加入节点之间的相互认证。保持安全,因为任何拥有此令牌的人都可以将节点添加到你的集群中。
如果 tocken 过期了,可以在控制面使用 kubeadm token create
创建新的 tocken,默认 24 小时过期。
也可以使用 kubeadm token list
查看现有 tocken。
如果你不知道校验值,可以在控制面使用 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
来获取校验值。
其实也可以用 kubeadm token create --print-join-command
直接生成一条新的加入命令。
控制面节点隔离
默认情况下,你的集群不会在控制面节点上调度(运行) 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 污点已被废弃(控制面以前称为 master),kubeadm 将在 1.25 版本中停止使用它。
#5 集群包管理器 Helm
注意:仅控制面执行。
Helm 是 Kubernetes 的包管理器。
中国大陆下载过于缓慢,就不用脚本了。
访问 https://github.com/helm/helm/releases 查看并下载最新版(不是下面的 .asc)。
也可以从微软 Azure 中国镜像下载:https://mirror.azure.cn/kubernetes/helm/
解压并安装:
tar -xvf helm*
mv linux-amd64/helm /usr/local/bin/helm
镜像
很明显,中国大陆无法访问 Helm 的官方 Charts 仓库,因为它指向了 kubernetes-charts.storage.googleapis.com。
这里有各种镜像(请访问以获取实际镜像地址):
- https://mirror.azure.cn/kubernetes/charts/ (微软 Azure);
- https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts/ (阿里云,似乎长时间未更新已不可用);
给 Helm 使用:
helm repo add <名称> <镜像地址>
这里使用 Azure:
helm repo add azure https://mirror.azure.cn/kubernetes/charts/
测试源:
helm repo update
#6 加入工作节点
在工作节点机器上执行刚刚的 kubeadm join <IP地址|DNS名称>:6443 --token <令牌> --discovery-token-ca-cert-hash sha256:<校验值>
命令即可。
同样,如果失败了,你需要解决问题,然后执行 kubeadm reset
并再来一遍。
注意:由于集群节点通常是按顺序初始化的,CoreDNS Pod 很可能都在第一个控制平面节点上运行。为了提供更高的可用性,请在加入至少一个新节点后重新平衡 CoreDNS Pod,在控制面执行 kubectl -n kube-system rollout restart deployment coredns
。
如果出现 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
检查
我遇到的很多问题都是与 kube-proxy 有关的。
在控制面上执行 kubectl get svc kubernetes
,记录 CLUSTER-IP
和 PORT(S)
在工作节点上执行 telnet <刚刚记录的IP> <刚刚记录的端口>
(没有就安装该包),如果无法连接则大概率 kube-proxy 有问题。
检查各网段有无冲突或尝试使用 IPVS 模式。
(可选)从控制平面节点以外的计算机控制集群
为了使 kubectl 在其他计算机(例如笔记本电脑)上与你的集群通信, 你需要将管理员 kubeconfig 文件从控制平面节点复制到工作站。
用你喜欢的方法将 /etc/kubernetes/admin.conf
传输到其他设备上,然后执行 kubectl --kubeconfig ./admin.conf get nodes
admin.conf 文件为用户提供了对集群的超级用户特权。 该文件应谨慎使用。对于普通用户,建议生成一个你为其授予特权的唯一证书。 你可以使用 kubeadm alpha kubeconfig user --client-name <CN>
命令执行此操作。 该命令会将 KubeConfig 文件打印到标准输入输出,你应该将其保存到文件并分发给用户。 之后,使用 kubectl create (cluster)rolebinding
授予特权。
(推荐可选)为 kube-proxy 开启 IPVS 模式
默认状态下 kube-proxy 使用 iptables 进行负载均衡/转发等,但 iptables 不是为此设计的,所以使用 iptables 规则复杂且性能低。
而 IPVS 是一个工作在内核态的高性能 4 层负载均衡,使用 IPVS 可以避免出现大量 iptables 规则,有时还能解决一些奇怪的问题。
如我有一台节点 iptables 模式死活无法访问 10.96.0.1:443 但切换到 IPVS 模式后,它神奇的好了。
这是已经引导集群后的修改方式,你也可以在引导集群前修改配置文件。
安装包
首先确保已安装 ipset ipvsadm 包:yum install ipset ipvsadm
确保已加载对应内核模块lsmod | grep -e ip_vs
有输出则已加载。
如果没有输出则需要加载内核模块:
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack
修改 kube-proxy 配置文件
执行 kubectl edit cm kube-proxy -n kube-system
,找到 metricsBindAddress
下面的 mode: ""
修改为 mode: "ipvs"
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: "ipvs"
nodePortAddresses: null
oomScoreAdj: null
删除所有 kube-proxy
由于集群已经运行,此前创建的 kube-proxy 不会应用配置文件。
删除 kube-proxy 集群会自动重建。kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'
检查
查看所有 kube-proxy pod:kubectl get pods -n kube-system|grep kube-proxy
检查日志:kubectl logs <kube-proxy节点名称> -n kube-system
日志中应该有:Using ipvs Proxier.
ipvsadm -Ln
中应当出现一些转发规则。
#7 集群网络
注意:仅控制面执行。
Kubernetes 并没有自己实现网络模型,要么你自己实现一个,要么从 https://kubernetes.io/docs/concepts/cluster-administration/networking/ 找一个合适的。
这里有一个来自 https://kubevious.io 的表格可以帮你在一定程度上选择。
名称 | 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 使用 Linux 内核 eBPF 技术, 高效且灵活,但需要较新的内核。
集群网络非常复杂,你应该进一步阅读他们的官方文档。
这里我们使用 Cilium,注意 Cilium 对 Linux 内核版本有要求,需要 >= 4.9.17。
详见:https://docs.cilium.io/en/latest/operations/system_requirements/
Cilium 有 3 种组件:
- Cilium-Agent(每个节点都有,监听 Kubernetes Spiserver 和 Cilium Kvstore);
- Cilium Kvstore(存储 Cilium 的一些全局状态);
- Cilium-Operator(每个集群一个);
安装 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 默认使用 10.0.0.0/8(见此),如果你的 IP 和此段地址冲突,则需要使用 Helm 安装模式。
方法1:一键安装cilium install
即可,如果由于某种原因安装失败,那么运行 cilium status
检查日志并排错。
方法2:使用 Helm 安装
需要手动选择最佳数据路径和 IPAM 模式。
Helm 添加源:
helm repo add cilium https://helm.cilium.io/
安装:
helm install cilium cilium/cilium --version 1.12.0 \
--namespace=kube-system \
--set k8sServiceHost=<IP地址|DNS名称> \
--set k8sServicePort=<端口> \
--set ipam.operator.clusterPoolIPv4PodCIDRList=<IPv4CIDR>
--namespace=<命名空间>
设置命名空间;k8sServiceHost=<IP地址|DNS名称>
填写 Api Server 地址,这允许 Cilium 不依赖 kube-proxy 连接到 kube-apiserver;k8sServicePort=<端口>
填写 Api Server 端口;ipam.operator.clusterPoolIPv4PodCIDRList=<IPv4CIDR>
填写要给 Pod 使用的网段,和引导集群时一致;- 更多信息;
重启非托管 Pod
kubectl get pods --all-namespaces -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,HOSTNETWORK:.spec.hostNetwork --no-headers=true | grep '<none>' | awk '{print "-n "$1" "$2}' | xargs -L 1 -r kubectl delete pod
检查cilium status --wait
防火墙规则
请根据你的防火墙实现配置。
详见:https://docs.cilium.io/en/stable/operations/system_requirements/#firewall-rules
ICMP Ping 和 TCP 4240 端口用于健康检查,允许一种就够了。如果不允许则 Cilium 仍然可以正常运行,但无法提供健康信息。
控制面/工作节点:
协议 | 方向 | 端口范围/代码 | 来源/目的地 | 描述 |
---|---|---|---|---|
TCP | 入站 | 2379-2380 | worker-sg |
etcd 访问 |
UDP | 入站 | 8472 | master-sg |
VXLAN 覆盖 |
UDP | 入站 | 8472 | worker-sg |
VXLAN 覆盖 |
TCP | 入站 | 4240 | master-sg |
健康检查 |
TCP | 入站 | 4240 | worker-sg |
健康检查 |
ICMP | 入站 | 8/0 | master-sg |
健康检查 |
ICMP | 入站 | 8/0 | worker-sg |
健康检查 |
UDP | 出站 | 8472 | master-sg |
VXLAN 覆盖 |
UDP | 出站 | 8472 | worker-sg |
VXLAN 覆盖 |
TCP | 出站 | 4240 | master-sg |
健康检查 |
TCP | 出站 | 4240 | worker-sg |
健康检查 |
ICMP | 出站 | 8/0 | master-sg |
健康检查 |
ICMP | 出站 | 8/0 | worker-sg |
健康检查 |
每个节点还应该提供这些端口(根据实际情况设置):
协议 | 端口范围 | 描述 |
---|---|---|
TCP | 4240 | 集群健康检查 ( cilium-health ) |
TCP | 4244 | Hubble 服务器 |
TCP | 4245 | Hubble 中继 |
TCP | 6060 | cilium-agent pprof 服务器(监听 127.0.0.1) |
TCP | 6061 | cilium-operator pprof 服务器(监听 127.0.0.1) |
TCP | 6062 | Hubble Relay pprof 服务器(监听 127.0.0.1) |
TCP | 6942 | operator Prometheus 指标 |
TCP | 9090 | cilium-agent Prometheus 指标 |
TCP | 9879 | cilium-agent 健康状态 API(监听 127.0.0.1 和/或 ::1) |
TCP | 9890 | cilium-agent gops 服务器(监听 127.0.0.1) |
TCP | 9891 | operator gops 服务器(监听 127.0.0.1) |
TCP | 9892 | clustermesh-apiserver gops 服务器(监听 127.0.0.1) |
TCP | 9893 | Hubble 中继 gops 服务器(监听 127.0.0.1) |
UDP | 51871 | WireGuard 加密隧道端点 |
启用 Hubble
Hubble 是 Cilium 的可视化系统。
启用 Hubble 需要在所有运行 Cilium 的节点上打开 TCP 端口 4244。
注意:你可能需要加入其它节点/移除单机集群污点后才能启用 Hubble。
启用本体cilium hubble enable
启用用户界面cilium hubble enable --ui
检查cilium status
Hubble 用户界面
运行 cilium hubble ui
它将端口转发到您的 Kubernetes 集群中的 hubble-ui 服务,并使其在您机器上的本地端口上可用。
在浏览器中访问 http://localhost:12000/ 即可。
验证
cilium status --wait
和 cilium connectivity test
。
然后 kubectl get pods --namespace=kube-system -l k8s-app=cilium
,
你的集群中的每个节点上都会运行一个 cilium
Pod。
由于某些不言自明的原因,cilium connectivity test
某些测试可能会失败,不影响。
失败后使用 kubectl delete namespace cilium-test
删除命名空间即可。
清理
如果集群配置失败/删除节点等,则需要清理节点。
如果要干净的取消配置集群, 则应首先清空节点并确保该节点为空, 然后取消配置该节点。
若清空控制面,则 #工作节点执行 同样在控制面执行。
清空节点
#控制面执行
获取节点名称:kubectl get nodes
清空节点:kubectl drain <节点名称> --delete-emptydir-data --force --ignore-daemonsets
重置 kubeadm
#工作节点执行
在删除节点之前,请重置 kubeadm 安装的状态。kubeadm reset
重置 Iptables
#工作节点执行
警告:此命令同样会清理其他非 Kubernetes 规则。iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
重置 IPVS
#工作节点执行
警告:此命令同样会清理其他非 Kubernetes 规则。ipvsadm -C
删除节点
#控制面执行kubectl delete node <节点名称>
常用命令
kubectl get pod --all-namespaces -owide
kubectl get nodes -owide
kubectl get rs --all-namespaces
kubectl get deployment
kubectl describe pod <名称> --namespace <命名空间>
kubectl describe rs <名称> --namespace <命名空间>
kubectl describe deployment <名称> --namespace <命名空间>
--namespace
可以缩写为 -n
--all-namespaces
可以缩写为 -A
备注
- 如果你需要各个资源清单内容的详细列表,请参考此文档:https://kubernetes.io/docs/reference/kubernetes-api/
- 如果你需要 kubectl 常用备忘参考,请参考此文档:https://kubernetes.io/docs/reference/kubectl/cheatsheet/
主要参考
- 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/
- https://www.cnblogs.com/liyongjian5179/p/11417794.html
- https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md
- https://zhuanlan.zhihu.com/p/519439205
No Comments