Ubuntu22.04下基于Kubeadm与Containerd的Kubernetes1.32轻量级集群部署实战
1. 为什么选择这个组合?聊聊我的实战选型思路
最近有不少朋友问我,想自己搭个Kubernetes集群玩玩,或者给团队搞个轻量级的开发测试环境,到底该怎么选组件、怎么配才最省心。我折腾K8s集群少说也有五六年了,从最早的Docker搭桥,到后来各种CRI(容器运行时接口)轮番上阵,踩过的坑真不少。今天我就结合最近一次在Ubuntu 22.04上部署Kubernetes 1.32集群的实际经历,跟你详细聊聊为什么我最终敲定了 Kubeadm + Containerd 这个组合,以及怎么一步步把它搭起来,让它既轻快又稳定。
先说Ubuntu 22.04 LTS,这是个长期支持版本,官方维护到2027年,系统稳定,社区支持好,软件包也够新。对于生产或者长期使用的测试环境,LTS版本是首选,能避免频繁升级带来的麻烦。内核方面,22.04默认的5.15内核已经包含了对K8s各种特性的良好支持,比如cgroup v2、ebpf等,开箱即用,不用我们再去折腾内核编译。
然后是容器运行时。早几年大家基本都用Docker,但它毕竟是个“全家桶”,包含了守护进程、API、CLI、镜像构建等等,有点重。后来K8s推出了CRI标准,把运行时接口标准化了。Containerd 就是从Docker里剥离出来的那个纯粹的、高性能的容器运行时,它实现了CRI,直接被kubelet调用,路径更短,架构更清晰。我实测下来,用Containerd后,容器启动速度确实有感知的提升,资源占用也更少,特别是对于追求效率和轻量的场景,优势明显。而且从Kubernetes 1.24开始,社区就逐渐淡化了对Docker的直接支持,转向Containerd和CRI-O,这算是顺应技术趋势。
最后是部署工具 Kubeadm。你可能听说过kops、kubespray这些,它们功能更强大,但复杂度也高。Kubeadm是K8s官方出的“一键安装”工具,它的目标很纯粹:帮你快速初始化一个符合最佳实践的集群。它把证书生成、组件配置、etcd集群部署这些繁琐的活都干了,给我们留出的是一个干净、标准的集群骨架。对于我们这种想要理解底层细节,又想快速上手的场景,Kubeadm是绝佳的选择。它就像乐高说明书,告诉你核心部件怎么拼,剩下的网络、存储、监控这些“装饰件”,你可以自由发挥。
所以,Ubuntu 22.04提供稳定的地基,Containerd提供高效的动力引擎,Kubeadm提供清晰的组装图纸,这三者结合,就是一个现代化、轻量且易于维护的Kubernetes集群的黄金起点。下面,我就带你从零开始,亲手把这个组合搭建起来。
2. 实战第一步:给Ubuntu 22.04做个“体检”与优化
在真正动手安装K8s之前,我们必须先把操作系统这个“地基”打牢。很多部署失败的问题,追根溯源都是系统层配置没到位。这一步千万别图快,耐心配好,后面能省下大量排错的时间。
2.1 基础环境检查与网络配置
首先,登录你的服务器,确认下系统版本和内核。虽然Ubuntu 22.04很常见,但确保一下没坏处。
lsb_release -a
uname -r
输出应该能看到 Ubuntu 22.04.x LTS 和类似 5.15.0-xx-generic 的内核信息。接下来是网络,这是集群通信的命脉。我建议使用 netplan 来管理网络,这是Ubuntu 17.10以后默认的网络配置工具。假设你的网卡是 ens160(可以用 ip a 命令查看),编辑配置文件:
sudo vim /etc/netplan/00-installer-config.yaml
我的配置大概长这样,你需要根据你的实际网络环境修改IP地址、网关和DNS:
network:
version: 2
ethernets:
ens160:
addresses:
- 10.62.1.181/24
nameservers:
addresses: [114.114.114.114, 8.8.8.8]
routes:
- to: default
via: 10.62.1.254
保存后,应用配置:sudo netplan apply。这里有个小坑,如果你是用虚拟机模板克隆出来的机器,网卡的UUID可能会重复,这可能导致网络服务启动异常。一个检查方法是看MAC地址:ifconfig ens160 | grep ether。如果几台机器MAC一样,那最好在netplan配置里为每台机器生成一个新的UUID,或者直接忽略这个配置项。
然后是主机名和 hosts 文件。集群节点之间要靠主机名互相识别,所以必须配好。我习惯用 hostnamectl 设置永久主机名:
sudo hostnamectl set-hostname k8s-master01
接着,编辑 /etc/hosts 文件,把所有集群节点的IP和主机名对应关系加进去。注意,这个操作需要在集群的每一台机器上都执行!
10.62.1.181 k8s-master01
10.62.1.182 k8s-master02
10.62.1.183 k8s-master03
10.62.1.184 k8s-node01
配完之后,一定要用 ping 命令测试一下所有节点之间是否能通过主机名互相访问,比如在 master01 上 ping k8s-master02。网络不通,后面全是白搭。
2.2 系统参数调优:为K8s铺平道路
Kubernetes对Linux内核有一些硬性要求,我们必须提前配置好。第一件事是关闭Swap。K8s的设计理念是,Pod的内存使用由它自己来调度和管理,如果允许使用Swap,内存不足时性能会急剧下降,而且调度器也无法准确感知真实的内存压力,所以必须关掉。
# 临时关闭当前已启用的swap
sudo swapoff -a
# 永久关闭,注释掉fstab里所有包含swap的行
sudo sed -ri 's/^([^#].*swap.*)$/#\1/' /etc/fstab
你可以用 free -h 命令确认Swap是否已经为0。接下来,Ubuntu自带的防火墙 ufw 和 apparmor 安全模块可能会和K8s的网络插件、容器网络产生冲突。为了简化初期部署,我建议先停用它们(生产环境请根据具体安全策略调整)。
sudo systemctl stop ufw && sudo systemctl disable ufw
sudo systemctl stop apparmor && sudo systemctl disable apparmor
时区和时间同步是分布式系统的基石。集群内所有节点时间必须高度一致,否则证书验证、事件日志都会出问题。设置时区并安装NTP客户端:
sudo timedatectl set-timezone Asia/Shanghai
sudo apt install -y chrony
编辑 /etc/chrony/chrony.conf,配置NTP服务器。你可以用公共的 pool.ntp.org,如果公司内有自己的NTP服务器更好。配置完后重启服务并设为开机自启:
sudo systemctl restart chronyd
sudo systemctl enable chronyd
用 chronyc sources -v 可以查看时间同步状态,确保状态是 ^*。
最后,也是最重要的一步,调整内核参数。K8s需要内核支持一些网络特性,比如IP转发、桥接流量过滤等。我们创建一个配置文件:
sudo tee /etc/sysctl.d/k8s.conf <<EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
执行 sudo sysctl --system 让配置生效,并用 sysctl net.ipv4.ip_forward 验证 ip_forward 是否已设为1。这些参数确保了节点上的容器网络流量能被正确路由和过滤。
3. 容器引擎核心:Containerd的安装与深度配置
地基打好了,现在来安装容器运行时。前面说了,我们选Containerd。它的安装其实很简单,但配置上有几个关键点,直接关系到后面K8s能否正常拉取镜像和运行容器。
3.1 安装与基础配置
在Ubuntu上安装Containerd就是一条命令的事:
sudo apt update
sudo apt install -y containerd
安装完成后,检查一下版本:containerd -v,我写这篇文章时默认安装的是1.7.x版本,完全兼容K8s 1.32。安装完Containerd后,它并没有默认的配置文件,我们需要生成一个:
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
这个命令会生成一个包含所有默认选项的TOML格式配置文件。接下来要修改两个关键地方。第一,找到 SystemdCgroup 这个参数,把它从 false 改成 true。这是因为K8s默认使用systemd来管理cgroup,保持两者一致能避免资源管理上的混乱。用sed命令可以快速修改:
sudo sed -ri 's#(SystemdCgroup = )false#\1true#' /etc/containerd/config.toml
第二,修改 sandbox_image,也就是K8s的Pause容器镜像。默认的 registry.k8s.io/pause:3.8 在国内可能拉取很慢甚至失败,我们需要把它换成国内能访问的镜像地址,比如阿里云的:
sudo sed -i 's#registry.k8s.io/pause:3.8#registry.aliyuncs.com/google_containers/pause:3.10#' /etc/containerd/config.toml
改完后,可以用 grep 命令确认一下修改是否成功:
grep -E "SystemdCgroup|sandbox_image" /etc/containerd/config.toml
3.2 配置镜像加速与私有仓库(解决拉取慢的痛点)
这是Containerd配置里最体现技巧的部分,也是很多新手会卡住的地方。Docker有 daemon.json 来配镜像仓库,Containerd的机制不太一样,它通过 hosts.toml 文件来为每个仓库域名进行配置。
首先,在Containerd的主配置文件里,告诉它去哪里找这些仓库配置。找到 [plugins."io.containerd.grpc.v1.cri".registry] 这个段落,确保下面有 config_path = "/etc/containerd/certs.d" 这一行。如果没有,就手动加上。这个路径就是存放各个仓库配置的目录。
然后,我们开始为不同的仓库创建配置。假设你需要配置 Docker Hub 的国内加速,以及一个公司内部的私有仓库 myregistry.local:5000。
# 为docker.io创建配置目录
sudo mkdir -p /etc/containerd/certs.d/docker.io
# 为私有仓库创建配置目录
sudo mkdir -p /etc/containerd/certs.d/myregistry.local:5000
接下来,为 docker.io 创建 hosts.toml 文件,配置多个镜像加速器。Containerd会按顺序尝试,哪个能用用哪个。
sudo tee /etc/containerd/certs.d/docker.io/hosts.toml <<EOF
server = "https://docker.io"
[host."https://dockerproxy.com"]
capabilities = ["pull", "resolve"]
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
[host."https://reg-mirror.qiniu.com"]
capabilities = ["pull", "resolve"]
EOF
对于HTTP协议的私有仓库(不安全,但内网常用),需要特别注明 http://,并设置 skip_verify = true 跳过TLS证书验证:
sudo tee /etc/containerd/certs.d/myregistry.local:5000/hosts.toml <<EOF
server = "http://myregistry.local:5000"
[host."http://myregistry.local:5000"]
capabilities = ["pull", "resolve", "push"]
skip_verify = true
EOF
所有配置完成后,重启Containerd服务让配置生效:sudo systemctl restart containerd。可以用 sudo systemctl status containerd 查看状态,确保是 active (running)。
最后,我们配置一下 crictl,这是K8s社区推荐的容器运行时命令行工具,可以用来调试和查看容器、镜像。创建它的配置文件:
sudo tee /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
EOF
现在,你可以用 sudo crictl images 命令测试一下,虽然现在还没镜像,但能正常列出(空列表),说明Containerd服务和我们配置的crictl工具都工作正常了。
4. 安装Kubernetes核心三剑客:kubeadm, kubelet, kubectl
容器运行时Ready了,接下来就该请出Kubernetes的核心组件了。我们将使用K8s官方提供的APT仓库来安装,这样方便后续升级和管理。
4.1 添加仓库并安装指定版本
首先,信任Kubernetes的APT仓库GPG密钥。这里注意,K8s 1.32的稳定仓库路径是 v1.32/deb/。
# 安装一些必要的工具
sudo apt install -y apt-transport-https ca-certificates curl gpg
# 下载并添加GPG密钥
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 添加阿里云镜像的Kubernetes APT源(国内加速)
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.32/deb/ /" | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
更新软件包列表并安装 kubelet, kubeadm, kubectl。这里有个重要操作:安装完成后,用 apt-mark hold 锁定这三个包的版本,防止它们被系统自动升级,导致集群版本不一致。
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
安装完成后,设置 kubelet 开机自启(虽然现在它还跑不起来,要等集群初始化后才行):sudo systemctl enable kubelet。你可以用 kubeadm version 和 kubectl version --client 来验证安装是否成功。
4.2 高可用基石:用HAProxy和Keepalived搭建负载均衡
如果你只部署一个Master节点(单控制平面),那么可以跳过这一步。但为了生产环境的高可用,或者你想体验多Master架构,那么为API Server配置一个负载均衡器是必须的。我选择的是经典组合:HAProxy做负载均衡,Keepalived做VIP(虚拟IP)漂移,实现高可用。
首先在所有计划作为控制平面的节点上安装这两个软件:
sudo apt install -y keepalived haproxy
配置HAProxy:编辑 /etc/haproxy/haproxy.cfg。关键是把后端指向所有Master节点的6443端口(K8s API Server端口)。下面是一个精简配置示例,同时开启了一个状态监控页面(在2080端口)。
sudo tee /etc/haproxy/haproxy.cfg <<EOF
global
log 127.0.0.1 local3
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
defaults
mode tcp
log global
option tcplog
timeout connect 5s
timeout client 50s
timeout server 50s
# 监控页面,可以通过 http://你的IP:2080/status 访问,账号admin,密码123456
listen admin_stats
bind 0.0.0.0:2080
mode http
stats enable
stats uri /status
stats realm HAProxy
stats auth admin:123456
# 这是核心配置,监听8443端口,将流量转发到三个Master的6443端口
listen kube-apiserver
bind 0.0.0.0:8443
mode tcp
balance roundrobin
server k8s-master01 10.62.1.181:6443 check inter 2000 rise 2 fall 3
server k8s-master02 10.62.1.182:6443 check inter 2000 rise 2 fall 3
server k8s-master03 10.62.1.183:6443 check inter 2000 rise 2 fall 3
EOF
配置Keepalived:这个配置稍微复杂点,因为它要决定哪个节点持有虚拟IP(VIP)。假设我们规划VIP是 10.62.1.180。在三台Master节点上,配置文件略有不同,主要是 state(主/备)和 priority(优先级)以及 unicast_peer(单播对端地址)的区别。
以第一台Master(10.62.1.181)为例,配置为MASTER,优先级最高(100):
sudo tee /etc/keepalived/keepalived.conf <<EOF
global_defs {
router_id K8S_MASTER_01
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
weight -5
}
vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 12
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
unicast_src_ip 10.62.1.181
unicast_peer {
10.62.1.182
10.62.1.183
}
virtual_ipaddress {
10.62.1.180/24 dev ens160
}
track_script {
check_haproxy
}
}
EOF
在第二台Master(10.62.1.182)上,state 改为 BACKUP,priority 设为 95,unicast_src_ip 和 unicast_peer 也要相应调整。第三台同理,优先级设为 90。
健康检查脚本:Keepalived需要监控HAProxy进程是否存活。创建检查脚本:
sudo tee /etc/keepalived/check_haproxy.sh <<EOF
#!/bin/bash
COUNT=\$(ps -C haproxy --no-header | wc -l)
if [ \$COUNT -eq 0 ]; then
systemctl start haproxy
sleep 2
COUNT=\$(ps -C haproxy --no-header | wc -l)
if [ \$COUNT -eq 0 ]; then
systemctl stop keepalived
fi
fi
EOF
sudo chmod +x /etc/keepalived/check_haproxy.sh
最后,在所有节点上启动服务并设置开机自启:
sudo systemctl enable --now haproxy
sudo systemctl enable --now keepalived
用 ip a 命令在配置为MASTER的节点上查看,应该能看到虚拟IP 10.62.1.180 已经绑定到了 ens160 网卡上。这个VIP 10.62.1.180:8443 就是我们后续初始化集群时要用的 control-plane-endpoint。
5. 临门一脚:使用Kubeadm初始化你的第一个集群
所有准备工作就绪,最激动人心的时刻到了——初始化集群。这里我强烈推荐使用配置文件的方式,而不是一长串命令行参数,因为配置文件更清晰,也方便以后回顾和版本管理。
5.1 拉取镜像与初始化配置
首先,我们可以让kubeadm先预拉取所需的镜像,这样能提前发现镜像拉取问题。如果你配置了Containerd的镜像加速,这里会快很多。指定我们之前配置的私有仓库或者阿里云镜像地址:
sudo kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.32.2
看到所有镜像 pull 完成后,就可以开始初始化了。创建一个初始化配置文件,比如 /opt/kubeadm-init.yaml:
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.32.2
imageRepository: registry.aliyuncs.com/google_containers
controlPlaneEndpoint: "10.62.1.180:8443" # 这里填你的HAProxy VIP和端口
networking:
podSubnet: "10.244.0.0/16" # 设置Pod网络CIDR,需要和后续的网络插件匹配
serviceSubnet: "10.96.0.0/16"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
nodeRegistration:
criSocket: "unix:///var/run/containerd/containerd.sock" # 关键!指定Containerd的socket
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs" # 使用ipvs模式,性能优于默认的iptables
这个配置文件做了几件重要的事:1. 指定了K8s版本和镜像仓库。2. 定义了控制平面的访问端点(就是我们HAProxy的VIP)。3. 指定了Pod和Service的网段。4. 明确告诉kubelet使用Containerd。5. 将kube-proxy的模式设为ipvs。
5.2 执行初始化并处理输出
万事俱备,在第一台Master节点(我这里是k8s-master01)上,执行初始化命令:
sudo kubeadm init --config=/opt/kubeadm-init.yaml --upload-certs
--upload-certs 参数会将生成的证书加密后上传,方便其他控制平面节点加入时自动获取。这个过程可能需要一两分钟,期间会生成各种证书、启动静态Pod等。如果一切顺利,你会看到令人振奋的成功信息,其中包含了两条非常重要的 kubeadm join 命令。
一条是给其他控制平面节点(Master) 加入集群用的,它包含了 --control-plane 和 --certificate-key 参数。另一条是给工作节点(Node) 加入集群用的。务必把这两条命令完整地保存下来! 尤其是那个token和discovery-token-ca-cert-hash,默认24小时失效,如果忘了可以用 kubeadm token create 和 openssl 命令重新生成,但直接保存最省事。
初始化成功后,按照提示,以普通用户身份配置kubectl:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
现在,你可以用 kubectl get nodes 查看节点了,但此时节点状态应该是 NotReady,因为还没有安装网络插件。
5.3 让其他节点加入集群
回到另外两台规划为Master的服务器(k8s-master02, k8s-master03)。确保它们已经完成了第2、3、4步的所有系统初始化、Containerd安装和配置、以及Kubernetes组件安装。
然后,在每台机器上,执行初始化成功后输出的那条给控制平面节点用的 kubeadm join 命令(需要sudo权限)。加入过程会自动从集群下载证书并启动控制平面组件。
对于工作节点(如k8s-node01),则执行那条给工作节点用的 kubeadm join 命令。
所有节点加入后,回到第一个Master节点,再次执行 kubectl get nodes,你应该能看到所有节点,但状态可能还是 NotReady。
6. 打通集群网络:安装Calico网络插件
节点都齐了,但彼此还不认识,因为缺少一个东西:Pod网络。K8s本身不负责网络,需要第三方插件来实现Pod之间的通信。这里我选择 Calico,它功能强大,支持网络策略,性能也很好,而且安装简单。
6.1 安装与验证
Calico的安装现在推荐使用Operator模式。我们直接使用官方提供的manifest文件。
# 下载Operator和自定义资源文件
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/tigera-operator.yaml
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/custom-resources.yaml
重要:在应用 custom-resources.yaml 之前,需要修改里面的 cidr 字段,确保和我们在 kubeadm-init.yaml 里设置的 podSubnet(10.244.0.0/16)一致。用编辑器打开 custom-resources.yaml,找到 spec.calicoNetwork.ipPools.cidr 进行修改。
然后按顺序应用这两个文件:
kubectl create -f tigera-operator.yaml
kubectl create -f custom-resources.yaml
安装过程需要拉取镜像,稍等一两分钟。你可以通过以下命令观察安装进度:
# 查看Operator Pod状态
kubectl get pods -n tigera-operator
# 查看Calico系统Pod状态
kubectl get pods -n calico-system -w
当 calico-system 命名空间下的所有Pod都变成 Running 状态后,再查看节点状态:
kubectl get nodes
这时,节点的状态应该从 NotReady 变成了 Ready。恭喜你,一个多节点的Kubernetes集群已经搭建完成了!
6.2 验证集群功能与后续步骤
集群Ready了,我们跑个最简单的测试来验证一下。部署一个Nginx的Deployment:
kubectl create deployment nginx-test --image=nginx:alpine
kubectl expose deployment nginx-test --port=80 --type=NodePort
然后查看Pod和Service:
kubectl get pods,svc -o wide
你应该能看到一个 nginx-test 的Pod在运行,并且有一个对应的Service,有一个 NodePort 类型的端口(比如 30080)。这时,你可以在任意节点的浏览器里访问 http://<节点IP>:<NodePort>,应该能看到Nginx的欢迎页面。
到这里,一个基于Ubuntu 22.04、Containerd和Kubeadm的Kubernetes 1.32轻量级集群就部署成功了。它具备了多Master高可用的基础架构。当然,这只是一个开始,后续你还需要根据实际需求,配置存储类(StorageClass)、安装Ingress控制器(如Nginx Ingress或Traefik)、部署监控系统(如Prometheus+Grafana)以及日志收集方案,才能构成一个完整可用的应用平台。不过,有了这个稳定、标准的底层集群,上面的那些组件安装和配置,就都是按部就班的“填空”工作了。
更多推荐
所有评论(0)