关于我在搭建 Kubernetes (k3s) 踩坑好几天这件事
和小伙伴一起订阅的各种服务器一直在不断等服务器到期,然后靠着谁家优惠谁家便宜就买谁家的然后迁移。我们之前服务器一直都是用的某面板虽然 备份 > 迁移 > 恢复 一套流程不复杂,但由于这两年云厂商也很狗的优惠机器购买时长基本卡在 1 到 3 年(很少),好几台机器迁移起来也是跑的熟练到令人心疼。除此之外我还在考虑优化运维自动化(CI/CD 自动编译部署、数据定时冷热备份、统一证书管理、统一服务器之间的防火墙以及权限管理等等)总之就是将小伙伴和自己在运维的重复劳动中尽量解放出来。
其实上面说的这些点还不是我选择用 k3s 的最主要原因,主要原因有两个第一就是目前除了云服务器之外我和小伙伴手里自部署的机器也在逐渐增加(且性能说不定比某些便宜的服务器还要好,只是稳定性没那么强)另外就是后续还有计划做物理机的托管。随着机器数量的增加其实管理上来说也是比较麻烦的一个事情。
除了统一管理机器(资源)的需求,另外一个原因就是上文提到的,我们计划的自部署机器也在逐渐增加,我肯定是希望能将这部分算力能够用到一些并不需要那么及时可靠的服务上。尤其是近几年各种内网穿透、异地组网、跨云组网的技术不断发展,现在下云(部分服务)似乎没那么遥不可及了,当然受限于目前的网络环境还是得有公网资源的不过公网服务器将逐渐变为流量出口。另外想吐槽的一点是虚拟化容器化真香,Linux 都发展成这样了(说不定以后在应用生态方面真会有什么意想不到的东西) MacOS(点名批评到现在嵌套虚拟化都不行)和 Windows 还不努努力说不定就被历史从脸上压过去了…
扯远了,话说回来那我们就尝尝 Kubernetes 的咸淡呗,于是走上了踩坑之路。
首先作为一个 Kubernetes 首次部署和使用的新手,我建议新手最好是先学会用,如果你有朋友或者你们公司搭建了先去了解一下怎么用(有一定的容器基础情况下),否则的话建议先从局域网两端互相可访问的网络环境下 一台主节点(master node)+ 一台资源节点(node)开始上手搭建一套先用着(不要像我一样头铁一上来就是想着部署什么跨网高可用)另外就是新手推荐先看 kubernetes 概念部分文档 不然很容易像我一样在部署过程中,遇到问题像一只无头苍蝇根本不知道问题出在哪一层。
《节选自我折腾过程中反复遇到问题后和朋友的一段对话》
xue: 你这搞这么久没搞好,到时候又是回去用你那 ** 面板。
bin: 你怎么知道我想删了回去用 ** 面板了。
搭建单 master node 主节点集群
我这边以 K3s + Rancher 为例,其中 K3s 是一个轻量的 Kubernetes 环境,Rancher 是一个 Kubernetes 管理平台可以理解为管理面板。硬件情况是 4 cores 8GB 运行 debian 13 操作系统的配置。
具体私聊是先搭建 k3s master node 主节点,然后在 k3s 中部署 rancher 最后增加一个 agent node 代理(资源)节点,并在其中运行一个服务。
# 鉴于博主特殊的网络环境需要走镜像站
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -s - server
安装成功会有如下输出,如果卡很久没有执行输出的时候可以检查一下自己网络环境能不能下载安装脚本
[INFO] Finding release for channel stable
[INFO] Using v1.33.4+k3s1 as release
[INFO] Downloading hash https://github.com/k3s-io/k3s/releases/download/v1.33.4+k3s1/sha256sum-amd64.txt
[INFO] Downloading binary https://github.com/k3s-io/k3s/releases/download/v1.33.4+k3s1/k3s
[INFO] Verifying binary download
[INFO] Installing k3s to /usr/local/bin/k3s
[INFO] Skipping installation of SELinux RPM
[INFO] Creating /usr/local/bin/kubectl symlink to k3s
[INFO] Creating /usr/local/bin/crictl symlink to k3s
[INFO] Skipping /usr/local/bin/ctr symlink to k3s, command exists in PATH at /usr/bin/ctr
[INFO] Creating killall script /usr/local/bin/k3s-killall.sh
[INFO] Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO] env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO] systemd: Creating service file /etc/systemd/system/k3s.service
[INFO] systemd: Enabling k3s unit
Created symlink '/etc/systemd/system/multi-user.target.wants/k3s.service' → '/etc/systemd/system/k3s.service'.
[INFO] systemd: Starting k3s
安装成功后,执行 kubectl get -A nodes
应该就能看到我们主节点了,如果报错则可以通过 journalctl -u k3s -f
来查看 k3s 服务的日志分析启动失败的原因。
在这里我稍微简述一下 Kubernetes 中 node 和 pod 的概念,每个 node 可以理解为每台服务器,pod 则是部署在集群中的服务启动的容器。我们可以配置运行在集群的服务需要跑多个容器来做负载均衡或者容灾。另外还有一个 namespace 的概念,这里我们执行 kubectl get
命令后面带的 -A 是 --all-namespaces 的简写,意思就是获取全部命名空间的资源。k3s 的一些系统服务全部会部署在 kube-system 这个命名空间中,后面我会逐个介绍这些系统服务大致的作用。
$ kubectl get -A nodes
NAME STATUS ROLES AGE VERSION
home03 Ready control-plane,master 2m33s v1.33.4+k3s1
$ kubectl get -A pods
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-64fd4b4794-cc2pf 1/1 Running 0 5m2s
kube-system helm-install-traefik-crd-xbqnq 0/1 Completed 0 5m2s
kube-system helm-install-traefik-jxrx7 0/1 Completed 2 5m2s
kube-system local-path-provisioner-774c6665dc-wcrrm 1/1 Running 0 5m2s
kube-system metrics-server-7bfffcd44-5qkvw 1/1 Running 0 5m2s
kube-system svclb-traefik-d8e8faec-sfgxq 2/2 Running 0 4m13s
kube-system traefik-c98fdf6fb-zsps8 1/1 Running 0 4m13s
到这里我们就简单搭建好了一个主节点,是不是还挺简单的,当然建议可以好好掌握一下 kubectl 命令的一些用法,可以通过执行 kubectl -help 或者 https://kubernetes.io/docs/reference/kubectl/ 文档详细了解。
紧接着我们在另外一台机器(⚠️注意这台机器要能够访问刚刚我们搭建主节点的机器)上继续搭建一个 agent node 代理节点(后续新增加的机器都可以以代理节点添加到我们集群中),下列https://192.168.1.69:6443 为我上序主节点的 IP 地址,6443 则为 k3s 默认的服务端口。
# 在主节点查看 token (示例 token 已混淆处理)
root@home03 $ cat /var/lib/rancher/k3s/server/node-token
K1064d99e5991f03fec883704f8abe25d664f99075dc5756520ff95ac06e1193b81::server:04e74c4e40d5a366556f11877a4c1561
# 在新机器上安装 k3s 启动 agent
root@home06 $ curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | K3S_URL=https://192.168.1.69:6443 K3S_TOKEN=*** INSTALL_K3S_MIRROR=cn sh -
[INFO] Finding release for channel stable
[INFO] Using v1.33.4+k3s1 as release
[INFO] Downloading hash rancher-mirror.rancher.cn/k3s/v1.33.4-k3s1/sha256sum-amd64.txt
[INFO] Downloading binary rancher-mirror.rancher.cn/k3s/v1.33.4-k3s1/k3s
[INFO] Verifying binary download
[INFO] Installing k3s to /usr/local/bin/k3s
[INFO] Skipping installation of SELinux RPM
[INFO] Creating /usr/local/bin/kubectl symlink to k3s
[INFO] Creating /usr/local/bin/crictl symlink to k3s
[INFO] Creating /usr/local/bin/ctr symlink to k3s
[INFO] Creating killall script /usr/local/bin/k3s-killall.sh
[INFO] Creating uninstall script /usr/local/bin/k3s-agent-uninstall.sh
[INFO] env: Creating environment file /etc/systemd/system/k3s-agent.service.env
[INFO] systemd: Creating service file /etc/systemd/system/k3s-agent.service
[INFO] systemd: Enabling k3s-agent unit
Created symlink '/etc/systemd/system/multi-user.target.wants/k3s-agent.service' -> '/etc/systemd/system/k3s-agent.service'.
[INFO] Host iptables-save/iptables-restore tools not found
[INFO] Host ip6tables-save/ip6tables-restore tools not found
[INFO] systemd: Starting k3s-agent
通过执行 journalctl -u k3s-agent -f 来查看服务启动日志,这里能看到我们出现了一个 image pull 镜像拉取失败的错误。
Sep 13 13:59:34 home06 k3s[4467]: I0913 13:59:34.650827 4467 iptables.go:357] bootstrap done
Sep 13 13:59:34 home06 k3s[4467]: I0913 13:59:34.654400 4467 iptables.go:357] bootstrap done
Sep 13 14:00:18 home06 k3s[4467]: E0913 14:00:18.339246 4467 log.go:32] "RunPodSandbox from runtime service failed" err="rpc error: code = DeadlineExceeded desc = failed to start sandbox \"de94b685ee41441e89369014c610d5ff1aade9ee8227ece1c69386d2898107ea\": failed to get sandbox image \"rancher/mirrored-pause:3.6\": failed to pull image \"rancher/mirrored-pause:3.6\": failed to pull and unpack image \"docker.io/rancher/mirrored-pause:3.6\": failed to resolve reference \"docker.io/rancher/mirrored-pause:3.6\": failed to do request: Head \"https://registry-1.docker.io/v2/rancher/mirrored-pause/manifests/3.6\": dial tcp [2a03:2880:f130:83:face:b00c:0:25de]:443: i/o timeout"
Sep 13 14:00:18 home06 k3s[4467]: E0913 14:00:18.339301 4467 kuberuntime_sandbox.go:70] "Failed to create sandbox for pod" err="rpc error: code = DeadlineExceeded desc = failed to start sandbox \"de94b685ee41441e89369014c610d5ff1aade9ee8227ece1c69386d2898107ea\": failed to get sandbox image \"rancher/mirrored-pause:3.6\": failed to pull image \"rancher/mirrored-pause:3.6\": failed to pull and unpack image \"docker.io/rancher/mirrored-pause:3.6\": failed to resolve reference \"docker.io/rancher/mirrored-pause:3.6\": failed to do request: Head \"https://registry-1.docker.io/v2/rancher/mirrored-pause/manifests/3.6\": dial tcp [2a03:2880:f130:83:face:b00c:0:25de]:443: i/o timeout" pod="kube-system/svclb-traefik-d8e8faec-d82gr"
Sep 13 14:00:18 home06 k3s[4467]: E0913 14:00:18.339325 4467 kuberuntime_manager.go:1252] "CreatePodSandbox for pod failed" err="rpc error: code = DeadlineExceeded desc = failed to start sandbox \"de94b685ee41441e89369014c610d5ff1aade9ee8227ece1c69386d2898107ea\": failed to get sandbox image \"rancher/mirrored-pause:3.6\": failed to pull image \"rancher/mirrored-pause:3.6\": failed to pull and unpack image \"docker.io/rancher/mirrored-pause:3.6\": failed to resolve reference \"docker.io/rancher/mirrored-pause:3.6\": failed to do request: Head \"https://registry-1.docker.io/v2/rancher/mirrored-pause/manifests/3.6\": dial tcp [2a03:2880:f130:83:face:b00c:0:25de]:443: i/o timeout" pod="kube-system/svclb-traefik-d8e8faec-d82gr"
通过参考 https://docs.k3s.io/advanced#configuring-an-http-proxy 文档解决,由于博主这里的网络情况比较特殊所以需要增加一下配置文件到 /etc/systemd/system/k3s-agent.service.env 环境中
# 增加环境变量至 k3s-agent 服务的启动环境中,注意如果是 k3s 主服务遇到这个问题请修改文件路径为 k3s.service.env
root@home06 $ echo "HTTP_PROXY=http://your-proxy.example.com:8888" >> /etc/systemd/system/k3s-agent.service.env
root@home06 $ echo "HTTPS_PROXY=http://your-proxy.example.com:8888" >> /etc/systemd/system/k3s-agent.service.env
root@home06 $ echo "NO_PROXY=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" >> /etc/systemd/system/k3s-agent.service.env
# 重启 k3s-agent 服务
root@home06 $ systemctl restart k3s-agent
# 查看 k3s-agent 服务日志
root@home06 $ journalctl -u k3s-agent -f
这时候回到 master node 的机器上执行 kubectl get -A nodes 应该能看到 home06 已经被加入集群了
root@home03 $ kubectl get -A nodes
NAME STATUS ROLES AGE VERSION
home03 Ready control-plane,master 64m v1.33.4+k3s1
home06 Ready <none> 26m v1.33.4+k3s1
这里需要注意,k3s-agent 的安装机器默认是不会带 /etc/rancher/k3s/k3s.yaml 配置文件的,所以在这台节点机器上是无法通过 kubectl 命令控制集群。如果需要在你自己机器或者其他节点中通过 kubectl 控制集群需要将 master node 主节点中的 /etc/rancher/k3s/k3s.yaml 文件拷贝到机器的相同路径下,并修改其中的 server: https://127.0.0.1:6443
字段为主节点的服务器地址以及端口,例如我这里就是 server: https://192.168.1.69:6443
到这里一个最基础的单主节点以及代理节点的集群就搭建好了,接着我们在这个集群上部署 Rancher 控制面板。
部署 Rancher 控制面板
这个部分我是建议最好是有个域名能够比较顺利的搭建和访问的,当然本地能也能跑只是需要通过修改 /etc/hosts 文件或者通过 ssh 端口转发的方式。
这里我们参考官网文档,通过 helm 集群包管理工具来安装 rancher,由于在代理节点上没有集群控制权限,所以后续操作安装都在 master node 主节点上进行,首先就是安装 helm 集群包管理工具参考文档 https://helm.sh/docs/intro/install/
# 利用安装脚本一键安装
root@home03 $ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
安装 helm 完成后就可以接着按照 rancher 安装文档 继续完成接下来的步骤
# 添加仓库源
root@home03 $ helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
# 更新仓库
root@home03 $ helm repo update
# 为 Rancher 创建命名空间
root@home03 $ kubectl create namespace cattle-system
# 如果你手动安装了CRD,而不是在 Helm 安装命令中添加了 `--set installCRDs=true` 选项,你应该在升级 Helm Chart 之前升级 CRD 资源。
root@home03 $ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.crds.yaml
# 添加 Jetstack Helm 仓库
root@home03 $ helm repo add jetstack https://charts.jetstack.io
# 更新本地 Helm Chart 仓库缓存
root@home03 $ helm repo update
# 安装 cert-manager Helm Chart
root@home03 $ helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace
# 安装 rancher ⚠️ 注意: 这里的域名和密码是需要你自己设置的
root@home03 $ helm install rancher rancher-stable/rancher \
--namespace cattle-system \
--set hostname=k3s.myhost.org \
--set bootstrapPassword=admin
# 等待 Rancher 运行
root@home03 $ kubectl -n cattle-system rollout status deploy/rancher
Waiting for deployment "rancher" rollout to finish: 0 of 3 updated replicas are available...
deployment "rancher" successfully rolled out
如果在执行 helm install 遇到无法连接 Kubernetes 的报错如下
root@home03 $ helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace
Error: INSTALLATION FAILED: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp [::1]:8080: connect: connection refused
# 需要配置 KUBECONFIG 环境变量,再重新执行 helm install 就好了
root@home03 $ echo "export KUBECONFIG=/etc/rancher/k3s/k3s.yaml" >> ~/.bashrc
root@home03 $ source ~/.bashrc
到这里 rancher 应该已经安装完成了,那么我们怎么访问呢?如果你有域名的情况下,将域名解析到你的 IP 地址上例如我这里是 k3s.myhost.org 解析到 192.168.1.69
如果你没有域名的话,可以在你的 /etc/hosts 中增加一条域名映射,然后在浏览器中访问 https://k3s.myhost.org
192.168.1.69 k3s.myhost.org
如果你也不想通过域名访问,那我这里还有一招,那就是通过 ssh 代理绕过 k3s 的 traefik 网关。
首先执行 kubectl get -A pods -o wide
,找到我们 cattle-system 命名空间下 rancher 的实际 pod 分配的虚拟 ip 地址。

这三个 pod 中顺便选一个,或者可以看到 node 部分标识这个 pod 是运行在哪个节点上的,你可以选择你中意的那台机器的节点。比如我这里选择 10.42.0.9,然后在你自己电脑执行如下 ssh 代理转发。然后在浏览器中访问 https://127.0.0.1:8080 就可以看到 rancher 的管理页面啦。
ssh -N -L 8080:10.42.0.9:443 root@192.168.1.69

其实稍微了解一下 Kubernetes 的大致概念,在网络比较正常的情况下搭建起来也不是特别复杂。篇幅所限,没法一次性把跨云组网以及高可用主节点部分讲完(也是折磨我好几天的,不过现在回想起来大部分问题只不过是之前自己对 Kubernetes 概念不了解一上来就啃硬骨头导致的)