Debian12部署k8s集群
本文的主要记录了如何利用手头空余的 vps 服务器建立一个 k8s 集群以供实验学习。目前我是有三台空余的 vps 服务器,刚好可以搭建一个小的 k8s 集群。集群采用 1*master + 2*work
的方式。
因为 k8s 集群搭建本身并不复杂,所以本篇文章也主要是记录下来每一步操作。在开始阅读此篇文章之前强烈建议先阅读我之前写的跨云k8s组网方案讨论这篇文章,里面完整记录了关于我这个小环境组网方案的新路历程。
1. 前言
- 目标: 搭建一个安全、稳定、符合官方标准的K8s学习与实验环境。
- 操作系统版本: Debian12
- k8s 版本: 1.33.4
- CRI 容器运行时: containerd v1.6.20
- CNI 网络插件: Calico v3.30.3
- 服务暴露: Cloudflare Tunnel
2. 基础配置
此部分所有 master、work 节点都需要操作。
2.1 基本工具安装
更新系统并安装必要工具:
1 | apt update |
2.2 关闭 swap
k8s 建议关闭 swap分区:
1 | swapoff -a |
2.3 安装 WireGuard
1 | apt install wireguard -y |
2.4 生成密钥对
1 | cd /etc/wireguard |
2.5 配置 WireGuard
关于 WireGUard 更详细的内容解析,可以查看我之前写的这篇文章 WireGuard原理解析与生产实践
编辑 /etc/wireguard/wg0.conf
,写入以下内容:
1 | [Interface] |
上面这个配置文件是以 master 节点为例编写的,其他两个节点也使用同样的格式配置,只不过变换下 Peer 部分 为其余两个主机、本机部分按照本节点配置。
2.6 启动与验证
1 | # 启动并设置开机自启 |
2.7 参数与模块配置
k8s需要特定的内核模块和系统参数来支持容器和网络,同时我希望 kube-proxy 使用 ipvs 模式所以需要做如下操作:
1 | # 安装 ipvs |
2.8 安装容器运行时
安装 containerd :
1 | apt-get install -y containerd |
生成默认配置文件并修改 cgroup 驱动为 systemd:
1 | # 生成配置文件 |
替换 containerd 为国内镜像源(可选,但位于国内的服务器必须要操作),配置方法可以按照这篇文章来 containerd配置国内镜像加速
2.9 安装 k8s 组件
添加 k8s 官方 GPG 密钥和 APT 仓库:
1 | # Google的仓库在国内无法访问,这里建议使用阿里云的镜像 |
安装指定版本的 k8s 组件:
1 | apt-get update |
k8s 集群创建的时候默认是通过路由来判断 internal ip 的,所以在使用 WireGuard 组建私有网络之后,k8s 并不会直接识别使用私网 IP,所以这里需要手动指定 kubelet 的 internal ip:
1 | vim /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf |
重启 kubelet:
1 | systemctl daemon-reload |
3. master 配置
以下步骤仅在 master 节点上配置
3.1 创建 k8s 集群
执行 kubeadm init
命令创建集群:
1 | # 我的 master 节点配置的 WireGuard IP 是 10.66.66.1、POD 网段是 10.244.0.0/16 |
初始化拉取镜像会花费一定时间,如果网络条件不好可能要等待5分钟左右,待命令执行完成后可以看到类似如下提示:
1 | Your Kubernetes control-plane has initialized successfully! |
记录上面屏幕提示中 kubeadm join
这段命令,后续工作节点将通过此条命令加入新建的 k8s 集群中
按照提示配置:
1 | mkdir -p $HOME/.kube |
配置命令补全:
1 | echo 'source <(kubectl completion bash)' >> ~/.bashrc |
修改 kube-proxy 为 ipvs 模式:
1 | kubectl edit configmap kube-proxy -n kube-system |
将 mode: ""
修改为 mode: "ipvs"
,操作完成之后再执行命令删除老的 POD 让它重新生成:
1 | kubectl delete pod -l k8s-app=kube-proxy -n kube-system |
3.2 配置 CNI 网络插件
在前面跨云 k8s 组网方案中已经说明了使用到的 CNI 插件是 Calico,网络模式配置为 BGP。
安装 Calico:
1 | kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/calico.yaml |
等待几分钟,让 Calico 的 Pod 启动即可
修改 calico 网络模式:
1 | kubectl edit ippool default-ipv4-ippool |
下载 calicoctl 工具:
1 | wget https://github.com/projectcalico/calico/releases/download/v3.30.3/calicoctl-linux-amd64 -O calicoctl |
4. 防火墙配置
如果你的 vps 云厂商默认启用了安全组限制,需要打开 WireGuard 的监听端口的访问权限。
注意: 这里不需要再为 apiserver、etcd、kubelet 端口打开访问权限,因为前面已经做了 wg 组网。
因此,所有节点安全组上都仅需要却保对集群内其他节点的公网地址放开 51820/UDP
5. 加入工作节点
此部分内容仅在两个工作节点上进行
在两个工作节点上使用 root 权限执行 3.1 章节中记录下的 kubeadm join 命令即可加入集群:
1 | kubeadm join 10.66.66.1:6443 --token abcdef.1234567890abcdef \ |
执行成功,屏幕会打印 This node has joined the cluster
在 master 节点上执行以下命令,检查节点状态:
1 | kubectl get nodes -o wide |
正常情况下所有节点的状态都会是 Ready 并且 INTERNAL-IP 应该显示的是 WireGuard 组网时配置的私有 IP。
在第四步工作节点加入集群的时候工作节点会拉取 kube-proxy 和 calico-node 的镜像并部署,这一步也有可能会因为网络不好导致进度缓慢,所以如果节点是 NotReady 可以先等下再看。
检查 Pod 状态:
1 | kubectl get pods -A -o wide |
确保 calico-node, coredns, kube-proxy 等所有 Pod 都处于 Running 状态。
使用 calicoctl 工具检查 BGP 是否建立成功:
1 | ./calicoctl node status |
输出结果里面每一个节点都应该是 Established 才正常。
6. 暴露服务
6.1 部署 ingress
在 master 上执行以下命令部署 ingress:
1 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.2/deploy/static/provider/baremetal/deploy.yaml |
6.2 创建 tunnel
登录 cloudflare 仪表盘,点击左侧面板进入 ZeroTrust 页面,随后依次点击 “网络”-“tunnels”-“创建隧道”-“选择 cloudflared”-“自定义名称”-“保存”-“环境选择 Docker”-“点击复制命令”
随后记录下–token 后面的一长串字符,例如我的是 eyJhxxxxxxxxxxxxxxxxxxxxVdyJ9
6.3 创建 secret
在 k8s 中通常使用 secret 安全保存各类 token、密码等内容:
新建 cloudflare-tunnel-secret.yaml
,写入以下内容:
1 | apiVersion: v1 |
创建 secret:
1 | kubectl apply -f cloudflare-tunnel-secret.yaml |
6.4 创建 cloudflare deployment
上一步的 secret 创建好之后即可进一步新建 deployment,新建 cloudflare-deployment.yaml
文件并写入以下内容:
1 | apiVersion: apps/v1 |
创建 deployment:
1 | kubectl apply -f cloudflare-deployment.yaml |
创建完成之后检查 cloudflare 的 pod 状态运行正常即可。
6.5 创建测试用 web 页面
新建一个 hello-deployment.yaml
文件,并写入以下内容:
1 | apiVersion: apps/v1 |
创建 deployment:
1 | kubectl apply -f hello-deployment.yaml |
新建一个 hello-service.yaml
文件,并写入以下内容:
1 | apiVersion: v1 |
创建 service:
1 | kubectl apply -f hello-service.yaml |
检查 deployment、pod、service 是否正常:
1 | kubectl get deployment,service,pods -n default |
新建 hello-app-ingress.yaml
文件,并写入以下内容:
1 | apiVersion: networking.k8s.io/v1 |
创建 ingress:
1 | kubectl apply -f hello-app-ingress.yaml |
6.6 配置域名和路由
这里以 blog.hello.com 域名为例。
回到之前打开的 cloudflare tunnel 页面,选择“下一步”,子域栏填 hello
,域栏选择托管在 cloudflare 上的 hello.com
,路径栏留空,服务选择 HTTP,URL 栏填 http://ingress-nginx-controller.ingress-nginx
,最后点击保存完成配置。
7. 验证
浏览器访问 https://blog.hello.com
并勾选 Auto Refresh
,应该可以看到每秒自动刷新的 nginx 图标页面,并且会显示 pod 的 ip
高可用测试:
轮流关闭工作节点主机,可以看到页面仍然能够正常访问,且 IP 会对应的变成剩余工作节点上的那个 pod ip。
后续新上线一个服务,就要创建 deployment-service-ingress-web 上跳转 tunnel。
因为我是有个域名完全拿来在这个环境做测试的,所以我的 tunnel 上面配置的是 *
通配符跳转,tunnel 相当于仅作为连接器。而 ingress 负责实现实验学习所需要的复杂的流量路由,同时这样后面也就不用在网页上调整 cloudflare 了。
如果你不需要用 ingress 来做这种复杂的流量路由实验,则完全可以去除本文中 ingress 相关的章节。用 tunnel 既当连接器又当路由分发器。比如直接跳过创建 ingress 部分,同样按照文中创建完成 hello-app 的 deployment 和 service 之后。在 tunnel 页面依然选择 HTTP 类型,URL 改成你 service 对应的 cluster ip 即可。