Ubuntu 22.04下K8S集群搭建避坑指南:从Docker到Harbor镜像仓库的全流程
Ubuntu 22.04下K8S集群搭建避坑指南:从Docker到Harbor镜像仓库的全流程
最近在帮团队搭建一套用于内部开发测试的Kubernetes环境,选用了Ubuntu 22.04作为基础系统。整个过程走下来,发现网上很多教程要么过于简略,要么假设读者已经具备丰富的运维经验,对于初次接触容器编排的开发者来说,很容易在某个环节卡住,然后花费大量时间排查。这篇文章就是把我踩过的坑、验证过的优化点,以及如何构建一个包含私有镜像仓库的完整可运维环境,系统地梳理出来。无论你是想搭建个人学习环境,还是为中小团队部署一套稳定的容器平台,这里面的经验都能帮你少走弯路。
我们最终的目标是构建一个高可用的多节点K8S集群,并集成一个企业级的私有镜像仓库Harbor。整个流程会覆盖从系统初始化、容器运行时配置、集群部署,到镜像仓库的安装与对接。我会特别强调那些容易出错的地方,比如网络配置、服务依赖、版本兼容性等,并提供经过验证的解决方案。
1. 基础环境准备与系统调优
在开始安装任何软件之前,打好系统基础至关重要。Ubuntu 22.04本身是一个优秀的起点,但默认配置并不完全适合运行生产级别的Kubernetes集群。我们需要进行一系列优化,以确保集群的稳定性和性能。
1.1 系统初始化与网络配置
首先,确保所有节点(包括控制平面节点和工作节点)都能稳定联网,并且彼此之间可以通过主机名和IP地址互相访问。我建议在本地/etc/hosts文件中为所有节点添加静态解析,这能避免初期因DNS问题导致的集群组建失败。
# 在所有节点上执行,将以下内容添加到 /etc/hosts 文件末尾
# 请根据你的实际IP和主机名修改
192.168.1.101 master-01
192.168.1.102 master-02
192.168.1.103 master-03
192.168.1.111 worker-01
192.168.1.112 worker-02
192.168.1.113 worker-03
192.168.1.200 harbor-registry
接下来,禁用Swap分区。Kubernetes的设计要求节点不能使用交换内存,否则kubelet会无法启动。很多安装失败的根本原因就是Swap没有彻底关闭。
# 临时关闭当前所有Swap空间
sudo swapoff -a
# 永久禁用,编辑 /etc/fstab 文件,注释掉所有包含‘swap’的行
sudo sed -i '/swap/s/^/#/' /etc/fstab
# 验证Swap已关闭
free -h
注意:仅仅执行
swapoff -a是临时生效,重启后会恢复。必须修改/etc/fstab文件才能永久生效。这是新手最容易忽略的一步。
1.2 内核参数与系统服务优化
Kubernetes对Linux内核参数有一定要求,特别是网络相关的参数。我们需要加载必要的内核模块并调整sysctl配置。
# 加载内核模块
sudo modprobe overlay
sudo modprobe br_netfilter
# 确保模块开机自动加载
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# 配置网络相关的sysctl参数
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# 应用配置
sudo sysctl --system
此外,确保系统基础工具齐全。虽然Ubuntu 22.04最小化安装可能缺少一些常用工具,但以下工具对于后续的安装和调试非常有用。
- curl/wget: 用于从网络下载文件。
- vim/nano: 文本编辑器,用于修改配置文件。
- socat/conntrack: Kubernetes网络依赖的工具。
- apt-transport-https/ca-certificates: 确保HTTPS源可用。
可以使用以下命令一次性安装:
sudo apt update && sudo apt install -y curl wget vim nano socat conntrack ipset apt-transport-https ca-certificates software-properties-common
2. 容器运行时安装:不止于Docker
Kubernetes需要一个容器运行时来拉取镜像和运行容器。虽然Docker是最广为人知的选择,但自Kubernetes 1.24版本起,它已不再内置dockershim,这意味着我们需要额外安装cri-dockerd适配器,或者直接选择其他兼容的运行时,如containerd。这里我提供两种主流方案的详细步骤和对比。
2.1 方案A:使用Containerd(推荐)
Containerd是CNCF毕业项目,现在是Kubernetes默认推荐的运行时。它比Docker更轻量,组件更清晰,故障点更少。
安装Containerd:
# 下载containerd的发布包(以1.7.13为例,请检查最新版本)
export CONTAINERD_VERSION="1.7.13"
wget https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-amd64.tar.gz
# 解压到系统目录
sudo tar Cxzvf /usr/local containerd-${CONTAINERD_VERSION}-linux-amd64.tar.gz
# 下载并安装runc
wget https://github.com/opencontainers/runc/releases/download/v1.1.10/runc.amd64
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
# 生成并安装systemd服务文件
sudo mkdir -p /usr/local/lib/systemd/system/
sudo curl -o /usr/local/lib/systemd/system/containerd.service https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
配置Containerd: 生成默认配置文件,并修改其中的镜像加速器和cgroup驱动。Kubernetes推荐使用systemd作为cgroup驱动。
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 使用sed修改配置:启用systemd cgroup驱动,并配置国内镜像加速器
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo sed -i 's|registry.k8s.io/pause:3.9|registry.aliyuncs.com/google_containers/pause:3.9|' /etc/containerd/config.toml
# 重启containerd使配置生效
sudo systemctl restart containerd
sudo systemctl status containerd
2.2 方案B:使用Docker + cri-dockerd
如果你或你的团队对Docker生态工具(如docker build, docker-compose)有强依赖,可以选择此方案。
安装Docker Engine: 官方提供了便捷的安装脚本,但为了可控性,我建议使用APT仓库安装。
# 添加Docker官方GPG密钥和仓库
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 配置镜像加速和cgroup驱动
sudo mkdir -p /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"registry-mirrors": ["https://your-mirror.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl enable docker
安装cri-dockerd适配器: 这是让Kubelet通过CRI接口与Docker通信的关键桥梁。
# 下载并安装cri-dockerd
export CRIDOCKERD_VERSION="0.3.7"
wget https://github.com/Mirantis/cri-dockerd/releases/download/v${CRIDOCKERD_VERSION}/cri-dockerd-${CRIDOCKERD_VERSION}.amd64.tgz
tar xzvf cri-dockerd-${CRIDOCKERD_VERSION}.amd64.tgz
sudo mv cri-dockerd/cri-dockerd /usr/local/bin/
# 安装systemd服务文件
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.service
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.socket
sudo mv cri-docker.service cri-docker.socket /etc/systemd/system/
sudo sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service
sudo systemctl daemon-reload
sudo systemctl enable cri-docker.service
sudo systemctl enable --now cri-docker.socket
两种方案的对比如下:
| 特性维度 | Containerd | Docker + cri-dockerd |
|---|---|---|
| 架构复杂度 | 轻量,组件少 | 较重,包含Docker Daemon、containerd、cri-dockerd多层 |
| 资源占用 | 内存和CPU占用更低 | 相对较高 |
| 稳定性 | 作为K8s原生选择,兼容性更好 | 依赖适配层,可能引入额外问题 |
| 运维工具链 | 主要使用crictl | 可使用完整的docker命令,对开发者更友好 |
| 学习成本 | 需要学习新的CLI工具 | 沿用熟悉的Docker命令 |
提示:对于生产环境,我强烈推荐使用Containerd。它更简洁,与Kubernetes的集成更紧密,出问题的概率更低。如果你只是搭建一个开发测试环境,并且重度依赖Docker CLI,那么可以选择方案B。
3. 使用kubeadm部署高可用Kubernetes集群
Kubeadm是Kubernetes官方推荐的集群部署工具,它简化了初始化流程,但依然保留了足够的灵活性。我们将部署一个包含三个控制平面节点的高可用集群,以及三个工作节点。
3.1 安装kubeadm、kubelet和kubectl
在所有节点(包括控制平面和工作节点)上执行以下步骤。
# 添加Kubernetes APT仓库的GPG密钥
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 添加Kubernetes APT仓库
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
# 安装组件(这里以1.28.5为例,请选择稳定的版本)
sudo apt update
sudo apt install -y kubelet=1.28.5-1.1 kubeadm=1.28.5-1.1 kubectl=1.28.5-1.1
sudo apt-mark hold kubelet kubeadm kubectl # 防止被意外升级
关键避坑点:版本兼容性 务必确保kubeadm、kubelet、kubectl以及容器运行时的版本是兼容的。你可以查阅Kubernetes官方发布说明。安装后,kubelet服务会处于启动失败状态,这是正常的,因为还没有生成配置文件,等集群初始化完成后就会正常。
3.2 初始化第一个控制平面节点
选择master-01作为初始化的主节点。
# 在master-01上执行
# 使用你选择的容器运行时套接字路径
# 如果是containerd,使用 --cri-socket unix:///var/run/containerd/containerd.sock
# 如果是cri-dockerd,使用 --cri-socket unix:///var/run/cri-dockerd.sock
sudo kubeadm init \
--control-plane-endpoint="k8s-api.yourdomain.com:6443" \
--upload-certs \
--pod-network-cidr=10.244.0.0/16 \
--cri-socket unix:///var/run/containerd/containerd.sock \
--image-repository registry.aliyuncs.com/google_containers
命令参数解释:
--control-plane-endpoint: 这是高可用的关键。应指向一个负载均衡器(如HAProxy)的VIP,或者一个DNS名称(后期可以通过修改/etc/hosts或DNS服务器指向负载均衡器)。初期测试可以先填写第一个控制平面节点的IP和端口,例如192.168.1.101:6443。--upload-certs: 自动将证书上传到集群,方便其他控制平面节点加入。--pod-network-cidr: 设置Pod网络的CIDR,需要与你后续安装的网络插件匹配(这里以Flannel为例)。--image-repository: 使用国内镜像源,加速镜像拉取。
初始化成功后,会输出类似下面的信息,其中包含加入集群所需的命令,务必妥善保存。
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of control-plane nodes by running the following on each as root:
kubeadm join k8s-api.yourdomain.com:6443 --token ... --discovery-token-ca-cert-hash sha256:... \
--control-plane --certificate-key ...
You can now join any number of worker nodes by running the following on each as root:
kubeadm join k8s-api.yourdomain.com:6443 --token ... --discovery-token-ca-cert-hash sha256:...
按照提示,配置kubectl:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
3.3 安装Pod网络插件(CNI)
没有网络插件,Pod之间无法通信。我们选择经典的Flannel。
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
等待片刻,使用kubectl get pods -n kube-system查看,直到所有kube-flannel Pod都处于Running状态。
3.4 加入其他控制平面节点和工作节点
将初始化成功输出的kubeadm join命令,分别在master-02、master-03以及所有worker节点上以root权限执行。
验证集群状态: 在所有控制平面节点都加入后,执行以下命令检查集群健康状况。
kubectl get nodes -o wide
kubectl get pods -n kube-system -o wide
你应该看到所有节点状态都是Ready,并且核心系统Pod(如coredns、kube-proxy、kube-flannel)都运行正常。
4. 部署与配置Harbor私有镜像仓库
拥有一个私有镜像仓库对于企业开发流程至关重要。Harbor提供了镜像存储、安全扫描、权限管理、复制等高级功能,远超简单的Docker Registry。
4.1 Harbor服务器准备
我们在一台独立的服务器(harbor-registry)上部署Harbor。这台服务器需要安装好Docker和Docker Compose(Harbor v2.x 以Docker Compose方式部署)。
# 在harbor-registry服务器上安装Docker Compose
# 从GitHub Release下载特定版本(以v2.23.0为例)
sudo curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version # 验证安装
4.2 下载与配置Harbor
访问Harbor GitHub Release页面,下载离线安装包(包含所有所需镜像)。
# 下载并解压(以v2.10.0为例)
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
tar xzvf harbor-offline-installer-v2.10.0.tgz
cd harbor
修改配置文件harbor.yml。以下是最关键的几项配置:
# 设置访问Harbor的主机名或IP地址
hostname: harbor-registry.yourdomain.com # 或直接使用IP,如 192.168.1.200
# 设置HTTP端口(如果不用HTTPS)
http:
port: 8080
# 注释掉HTTPS部分以使用HTTP(仅限内网测试环境)
# https:
# port: 443
# certificate: /your/certificate/path
# private_key: /your/private/key/path
# Harbor管理员初始密码
harbor_admin_password: YourStrongAdminPassword123
# 数据库密码
database:
password: root123
# 数据持久化目录
data_volume: /data/harbor
注意:生产环境必须配置HTTPS。你可以使用自签名证书或从Let‘s Encrypt获取免费证书。配置HTTPS时,需要将证书和私钥的路径正确填写到配置文件中。
4.3 安装与启动Harbor
执行安装脚本,它会根据配置文件拉取镜像并启动所有服务。
sudo ./install.sh
安装成功后,会提示访问地址和管理员账号信息。通过浏览器访问 http://harbor-registry.yourdomain.com:8080 即可登录管理界面。
4.4 将Kubernetes集群对接Harbor
要让K8S集群能从私有仓库拉取镜像,需要在集群中创建对应的Secret。
首先,在Harbor界面创建一个项目(例如dev),并创建一个具有推送拉取权限的用户。
然后,在Kubernetes集群的每个节点上,登录Harbor:
sudo docker login harbor-registry.yourdomain.com:8080 -u your-username -p your-password
对于Containerd运行时,需要将Docker凭证转换为Containerd格式,或者直接在/etc/containerd/config.toml中配置镜像仓库认证。
更推荐的方式是在K8S中创建imagePullSecret:
# 在需要拉取私有镜像的命名空间中创建Secret
kubectl create secret docker-registry harbor-registry-secret \
--docker-server=harbor-registry.yourdomain.com:8080 \
--docker-username=your-username \
--docker-password=your-password \
--namespace=default
在Pod的YAML文件中引用这个Secret:
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: harbor-registry.yourdomain.com:8080/dev/myapp:v1.0
imagePullSecrets:
- name: harbor-registry-secret
4.5 Harbor日常维护与故障排查
Harbor由多个容器组成,日常维护主要使用docker-compose命令。
# 进入Harbor安装目录
cd /path/to/harbor
# 查看所有服务状态
sudo docker-compose ps
# 停止Harbor
sudo docker-compose down
# 启动Harbor
sudo docker-compose up -d
# 查看特定服务的日志(例如core)
sudo docker-compose logs core -f
常见问题:
- 上传镜像失败,提示“413 Request Entity Too Large”:需要调整Nginx(Harbor的代理组件)的客户端最大body大小。修改
harbor.yml中的storage_proxy部分,或直接修改生成的docker-compose.yml中nginx服务的配置,添加client_max_body_size 1024m;。 - 登录失败,提示“x509: certificate signed by unknown authority”:当使用自签名证书时,需要在K8S节点和Docker客户端信任该证书。将Harbor的CA证书复制到
/etc/docker/certs.d/harbor-registry.yourdomain.com:8080/ca.crt(Docker)和/usr/local/share/ca-certificates/(系统)并执行update-ca-certificates。 - 磁盘空间不足:Harbor的镜像和Chart数据默认存储在
data_volume配置的路径下。定期清理未使用的镜像或设置存储配额策略。
整个流程走下来,最深的体会是“细节决定成败”。比如,系统时区不一致可能导致证书验证出错,/etc/hosts配置错误会让节点间通信彻底中断,而容器运行时的一个小版本不兼容就可能让集群初始化卡住半天。建议在每一步操作后都进行简单的验证,例如安装完容器运行时后拉取一个hello-world镜像,初始化完集群后立刻检查核心Pod状态,不要等到所有步骤做完再回头排查。
更多推荐
所有评论(0)