从零搭建Kubernetes集群:Harbor私有仓库 + K8s v1.35 + Flannel网络插件完整部署指南
前言
本文详细记录了从零开始搭建一套完整的Kubernetes集群的全过程,包括构建Harbor私有镜像仓库、准备Kubernetes主机环境、部署Kubernetes v1.35集群以及安装Flannel网络插件。所有步骤均附带详细命令,适合希望完整掌握K8s部署流程的运维人员和开发者。
环境规划
本部署方案共使用4台主机,主机规划如下:
| 主机名 | IP | 配置 | 角色 |
|---|---|---|---|
| harbor.timinglee.org | 172.25.254.254 | CPU 1核、内存 1G | Harbor私有仓库 |
| master-node | 172.25.254.100 | CPU 4核、内存 > 4G | Master控制节点 |
| node1 | 172.25.254.10 | CPU 2核、内存 2G | Worker工作节点 |
| node2 | 172.25.254.20 | CPU 2核、内存 2G | Worker工作节点 |
操作系统统一使用 RHEL 9.6 / CentOS 9 系列,Kubernetes 版本为 v1.35.7,容器运行时使用 Docker + cri-dockerd,网络插件使用 Flannel。
第一部分:构建Harbor私有镜像仓库
1.1 部署Docker本地仓库
在Harbor节点上,首先配置阿里云Docker-ce的YUM源,并安装httpd用于搭建本地仓库。
bash
[root@harbor ~]# cat > /etc/yum.repos.d/docker.repo <<EOF
[docker]
name = docker
baseurl = https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/
gpgcheck = 0
EOF
安装httpd和createrepo工具,配置httpd监听4444端口:
bash
[root@harbor ~]# dnf install httpd createrepo -y
[root@harbor ~]# mkdir /var/www/html/docker/ -p
[root@harbor ~]# vim /etc/httpd/conf/httpd.conf
# 修改监听端口为4444
Listen 4444
[root@harbor ~]# systemctl enable --now httpd
下载docker-ce的RPM包到本地,制作本地YUM仓库:
bash
[root@harbor ~]# dnf install docker-ce --downloadonly --destdir /mnt/ -y
[root@harbor ~]# mv /mnt/*.rpm /var/www/html/docker/
[root@harbor ~]# createrepo -v /var/www/html/docker/
切换YUM源为本地仓库,安装docker-ce:
bash
[root@harbor ~]# cat > /etc/yum.repos.d/docker.repo <<EOF
[docker]
name = docker
baseurl = http://172.25.254.254:4444/docker
gpgcheck = 0
EOF
[root@harbor ~]# dnf install docker-ce -y
1.2 配置Docker内核参数并启动服务
加载br_netfilter内核模块,配置网络相关内核参数:
bash
[root@harbor ~]# echo br_netfilter > /etc/modules-load.d/docker_mod.conf
[root@harbor ~]# modprobe -a br_netfilter
[root@harbor ~]# vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
[root@harbor ~]# systemctl restart systemd-modules-load.service
[root@harbor ~]# sysctl --system
修改Docker服务的启动参数,添加--iptables=true:
bash
[root@harbor ~]# vim /lib/systemd/system/docker.service
# 将ExecStart行修改为:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true
[root@harbor ~]# systemctl daemon-reload
[root@harbor ~]# systemctl enable --now docker
1.3 生成SSL证书
使用openssl生成4096位RSA证书,用于Harbor的HTTPS访问:
bash
[root@harbor ~]# mkdir /data/certs -p
[root@harbor ~]# openssl req -newkey rsa:4096 \
-nodes -sha256 -keyout /data/certs/timinglee.org.key \
-addext "subjectAltName = DNS:reg.timinglee.org" \
-x509 -days 365 -out /data/certs/timinglee.org.crt
证书填写信息如下:
| 字段 | 值 |
|---|---|
| Country Name | CN |
| State or Province Name | Shannxi |
| Locality Name | Xi'an |
| Organization Name | kubernetes |
| Organizational Unit Name | harbor |
| Common Name | reg.timinglee.org |
| Email Address | admin@timinglee.org |
1.4 部署Harbor服务
下载Harbor离线安装包并解压(版本 v2.5.4):
bash
[root@harbor ~]# tar zxf harbor-offline-installer-v2.5.4.tgz -C /opt/
[root@harbor ~]# cd /opt/harbor/
[root@harbor harbor]# cp harbor.yml.tmpl harbor.yml
修改harbor.yml配置文件:
bash
[root@harbor harbor]# vim harbor.yml
# 修改以下关键配置项:
hostname: reg.timinglee.org
# 证书配置
certificate: /data/certs/timinglee.org.crt
private_key: /data/certs/timinglee.org.key
# 管理员密码
harbor_admin_password: lee
执行安装脚本(启用Chart Museum支持):
bash
[root@harbor harbor]# ./install.sh --with-chartmuseum
创建Harbor的systemd服务,方便管理:
ini
[root@harbor harbor]# vim /lib/systemd/system/harbor.service
[Unit]
Description=harbor with Docker Compose
Documentation=https://reg.timinglee.com/compose/
After=docker.service network-online.target
Requires=docker.service
[Service]
Type=oneshot
WorkingDirectory=/opt/harbor
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
1.5 配置Docker信任证书并验证登录
将证书复制到Docker证书目录,并配置hosts解析:
bash
[root@harbor harbor]# mkdir /etc/docker/certs.d/reg.timinglee.org/ -p
[root@harbor harbor]# cp /data/certs/timinglee.org.crt /etc/docker/certs.d/reg.timinglee.org/ca.crt
[root@harbor harbor]# vim /etc/hosts
# 增加以下行:
172.25.254.200 harbor reg.timinglee.org
重启Docker并启动Harbor服务,验证登录:
bash
[root@harbor harbor]# systemctl restart docker
[root@harbor harbor]# docker compose up -d
[root@harbor harbor]# docker login reg.timinglee.org -u admin
Password:
# 输出:Login Succeeded
至此,Harbor私有镜像仓库部署完成。
第二部分:准备Kubernetes主机环境
2.1 关闭所有节点的swap
Kubernetes要求所有节点必须关闭swap:
bash
systemctl disable --now swap.target
systemctl mask swap.target
sed '/swap/s/^/#/g' -i /etc/fstab
重启后验证:
bash
swapon -s
# 没有任何输出表示ok
2.2 在所有节点安装Docker并配置Harbor仓库
在Harbor节点上,将证书分发到所有K8s节点:
bash
[root@harbor ~]# for i in 100 10 20
> do
> scp /data/certs/timinglee.org.crt root@172.25.254.$i:/etc/docker/certs.d/reg.timinglee.org/ca.crt
> done
在所有节点创建证书目录并启动Docker:
bash
mkdir /etc/docker/certs.d/reg.timinglee.org/ -p
systemctl enable docker
systemctl restart docker
2.3 配置Docker加速器
所有节点配置Docker镜像加速器指向Harbor仓库:
bash
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors":["https://reg.timinglee.org"]
}
EOF
systemctl restart docker
验证:
bash
docker info
# 可以看到 Registry Mirrors: https://reg.timinglee.org/
2.4 配置主机名解析
所有节点编辑/etc/hosts,建立主机名与IP的对应关系:
bash
vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.100 master
172.25.254.10 node1
172.25.254.20 node2
172.25.254.200 reg.timinglee.org
2.5 配置Kubernetes安装源
所有节点配置阿里云的Kubernetes YUM源:
bash
vim /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name = kubernetes
baseurl = https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm/
gpgcheck = 0
检测源是否可用:
bash
dnf list kubelet
以上操作完成后重启所有主机,并再次确认swap已关闭。
第三部分:部署Kubernetes集群
3.1 安装cri-dockerd(所有节点)
Kubernetes从v1.24开始移除了对Docker的直接支持,需要使用cri-dockerd作为CRI接口桥接。
方式一:RPM包部署
bash
[root@master ~]# ls
anaconda-ks.cfg cri-dockerd-0.3.14-3.el8.x86_64.rpm libcgroup-0.41-19.el8.x86_64.rpm
[root@master ~]# rpm -ivh *.rpm
修改cri-docker.service配置,指定pause镜像使用本地仓库:
bash
[root@master ~]# vim /lib/systemd/system/cri-docker.service
# ExecStart行修改为:
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=reg.timinglee.org/k8s/pause:3.10.1
[root@master ~]# ll /var/run/cri-dockerd.sock
方式二:二进制包部署(推荐,版本更新)
bash
[root@docker-node1 ~]# wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.4.4/cri-dockerd-0.4.4.amd64.tgz
[root@docker-node1 ~]# tar zxf cri-dockerd-0.4.4.amd64.tgz
[root@docker-node1 ~]# cd cri-dockerd/
[root@docker-node1 cri-dockerd]# install -o root -g root -m 0755 cri-dockerd /usr/local/bin/cri-dockerd
[root@docker-node1 cri-dockerd]# cp cri-docker.s* /lib/systemd/system
[root@docker-node1 cri-dockerd]# chmod +x /lib/systemd/system/cri-docker.s*
修改cri-docker.service配置:
bash
[root@docker-node1 cri-dockerd]# vim /lib/systemd/system/cri-docker.service
[Service]
Type=notify
ExecStart=/usr/local/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=reg.timinglee.org/k8s/pause:3.10.1 --container-runtime-endpoint fd://
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
启动cri-dockerd服务:
bash
[root@docker-node1 cri-dockerd]# systemctl daemon-reload
[root@docker-node1 cri-dockerd]# systemctl enable --now cri-docker.service
[root@docker-node1 cri-dockerd]# systemctl status cri-docker.service
3.2 安装Kubernetes组件
Master节点安装kubelet、kubeadm、kubectl:
bash
[root@master ~]# dnf install kubelet kubeadm kubectl -y
[root@master ~]# systemctl enable --now kubelet.service
Node节点只需要安装kubelet和kubeadm:
bash
[root@node1 ~]# dnf install kubelet kubeadm -y
[root@node1 ~]# systemctl enable --now kubelet.service
Master节点配置命令补全:
bash
[root@master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
[root@master ~]# echo "source <(kubeadm completion bash)" >> ~/.bashrc
[root@master ~]# source ~/.bashrc
3.3 下载Kubernetes集群所需镜像
查看所需镜像列表:
bash
[root@master ~]# kubeadm config images list
registry.k8s.io/kube-apiserver:v1.35.7
registry.k8s.io/kube-controller-manager:v1.35.7
registry.k8s.io/kube-scheduler:v1.35.7
registry.k8s.io/kube-proxy:v1.35.7
registry.k8s.io/coredns/coredns:v1.13.1
registry.k8s.io/pause:3.10.1
registry.k8s.io/etcd:3.6.6-0
从阿里云镜像仓库拉取镜像:
bash
[root@master ~]# kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.35.7 \
--cri-socket=unix:///var/run/cri-dockerd.sock
将拉取的镜像重新打标签并推送到本地Harbor仓库:
bash
[root@master ~]# docker login reg.timinglee.org -u admin
# 输出:Login Succeeded
[root@master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/google/{system("docker tag "$0" reg.timinglee.org/k8s/"$3)}'
[root@master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/timinglee/{system("docker push "$0)}'
3.4 初始化Kubernetes集群
在Master节点执行集群初始化:
bash
[root@master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository reg.timinglee.org/k8s \
--kubernetes-version v1.35.7 \
--cri-socket=unix:///var/run/cri-dockerd.sock
初始化成功后,会输出类似下面的加入集群凭证:
bash
kubeadm join 172.25.254.100:6443 --token tdwjoc.8d1yw3wl4r4tm6c4 \
--discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927
重要提示: 请保存好上述token和hash值,后续Node节点加入集群时需要使用。
如果忘记凭证,可以重新生成:
bash
[root@master ~]# kubeadm token create --print-join-command
kubeadm join 172.25.254.100:6443 --token jl4ztx.cax3iysvu7onsh5s --discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927
如果初始化出现问题,可以重置集群:
bash
[root@master ~]# kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock
配置KUBECONFIG环境变量,使kubectl可以正常使用:
bash
[root@master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" > ~/.bash_profile
[root@master ~]# source ~/.bash_profile
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady control-plane 102s v1.35.3
此时Master节点状态为NotReady,因为尚未安装网络插件。
3.5 将Node节点加入集群
在Node1和Node2节点上执行加入命令:
bash
[root@node1 ~]# kubeadm join 172.25.254.100:6443 --token jl4ztx.cax3iysvu7onsh5s \
--discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927 \
--cri-socket=unix:///var/run/cri-dockerd.sock
在Master节点查看集群状态,此时所有节点均为NotReady:
bash
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady control-plane 5m16s v1.35.3
node1 NotReady <none> 66s v1.35.3
node2 NotReady <none> 58s v1.35.3
3.6 安装Flannel网络插件
下载Flannel离线包并加载镜像:
bash
[root@master ~]# tar zxf kube-flannel-v0.28.9.tar.gz
[root@master ~]# ls
flannel kube-flannel-v0.28.9.tar.gz
[root@master ~]# cd flannel/
[root@master flannel]# docker load -i kube-flannel-v0.28.9.tar
Loaded image: ghcr.io/flannel-io/flannel-cni-plugin:v1.9.1-flannel3
Loaded image: ghcr.io/flannel-io/flannel:v0.28.9
将Flannel镜像打标签并推送到本地Harbor仓库:
bash
[root@master ~]# docker tag ghcr.io/flannel-io/flannel-cni-plugin:v1.9.0-flannel1 reg.timinglee.org/flannel-io/flannel-cni-plugin:v1.9.0-flannel1
[root@master ~]# docker push reg.timinglee.org/flannel-io/flannel-cni-plugin:v1.9.0-flannel1
[root@master ~]# docker tag ghcr.io/flannel-io/flannel:v0.28.1 reg.timinglee.org/flannel-io/flannel:v0.28.1
[root@master ~]# docker push reg.timinglee.org/flannel-io/flannel:v0.28.1
修改kube-flannel.yml配置文件,将镜像地址替换为本地仓库地址:
bash
[root@master ~]# vim kube-flannel.yml
# 查找并修改镜像地址
# 将 image: flannel-io/flannel:v0.28.9 替换为 image: reg.timinglee.org/flannel-io/flannel:v0.28.1
# 将 image: flannel-io/flannel-cni-plugin:v1.9.1-flannel3 替换为 image: reg.timinglee.org/flannel-io/flannel-cni-plugin:v1.9.0-flannel1
查看需要修改的行号:
bash
[root@master flannel]# grep -n image: kube-flannel.yml
148: image: flannel-io/flannel:v0.28.9
175: image: flannel-io/flannel-cni-plugin:v1.9.1-flannel3
186: image: flannel-io/flannel:v0.28.9
应用Flannel网络插件配置:
bash
[root@master ~]# kubectl apply -f kube-flannel.yml
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
3.7 验证集群状态
等待片刻后,查看所有节点状态:
bash
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane 13m v1.35.3
node1 Ready <none> 9m44s v1.35.3
node2 Ready <none> 9m36s v1.35.3
所有节点状态均为Ready,Kubernetes集群部署成功。
第四部分:使用Ansible自动化部署(可选)
上述步骤也可以通过Ansible实现自动化部署,极大提升效率。
4.1 安装Ansible
在Harbor主机上安装Ansible:
bash
[root@harbor ~]# dnf install ansible-core.x86_64 ansible.noarch -y
创建devops用户并配置sudo权限:
bash
[root@harbor ~]# useradd devops
[root@harbor ~]# echo "devops ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
4.2 编写Ansible剧本
创建kubernetes-devops.yml剧本,包含以下核心任务:
yaml
- name: devops k8s from ansible
hosts: all
tasks:
- name: setup docker repo
yum_repository:
name: docker
description: docker
baseurl: http://172.25.254.254:4444/docker
file: docker
gpgcheck: no
- name: install docker
dnf:
name: docker-ce
state: present
- name: setup docker.service
replace:
path: /lib/systemd/system/docker.service
regexp: "ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock"
replace: "ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true"
- name: setup docker registry
copy:
content: |
{
"registry-mirrors":["https://reg.timinglee.org"]
}
dest: /etc/docker/daemon.json
- name: setup docker certs
file:
path: /etc/docker/certs.d/reg.timinglee.org
state: directory
- name: cp certs file
copy:
src: "{{item.src}}"
dest: "{{item.dest}}"
loop:
- src: /etc/docker/certs.d/reg.timinglee.org/ca.crt
dest: /etc/docker/certs.d/reg.timinglee.org/ca.crt
- src: /etc/docker/certs.d/reg.timinglee.org/ca.crt
dest: /etc/pki/ca-trust/source/anchors/ca.crt
- name: load module
copy:
dest: "{{item.dest}}"
content: "{{item.value}}"
loop:
- dest: /etc/modules-load.d/docker_mod.conf
value: br_netfilter
- dest: /etc/sysctl.d/docker.conf
value: |
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
- name: update ca cert
shell: "update-ca-trust extract;sysctl --system"
- name: start services
service:
name: "{{item}}"
state: restarted
enabled: yes
loop:
- docker
- systemd-modules-load.service
扩展剧本,集成cri-dockerd部署:
yaml
- name: setup cri-dockerd
copy:
src: "{{item.src}}"
dest: "{{item.dest}}"
mode: '0755'
loop:
- src: ./cri-dockerd/cri-dockerd
dest: /usr/bin/cri-dockerd
- src: "./cri-dockerd/cri-docker.service"
dest: "/lib/systemd/system/cri-docker.service"
- src: "./cri-dockerd/cri-docker.socket"
dest: "/lib/systemd/system/cri-docker.socket"
- name: update system config
shell: "update-ca-trust extract;sysctl --system;systemctl daemon-reload"
- name: start services
service:
name: "{{item}}"
state: restarted
enabled: yes
loop:
- docker
- systemd-modules-load.service
- cri-docker
配置kubectl和kubeadm命令补全(仅在Master节点执行):
yaml
- name: setup kubectl kubeadm completion
lineinfile:
path: /root/.bashrc
line: |
source <(kubectl completion bash)
source <(kubeadm completion bash)
when: inventory_hostname == "172.25.254.100"
- name: start kubelet
service:
name: kubelet
state: started
enabled: yes
4.3 执行Ansible剧本
bash
[devops@harbor ansible]$ ansible-playbook kubernetes-devops.yml
让命令补全功能生效:
bash
[root@master ~]# source ~/.bashrc
至此,Kubernetes集群的自动化环境部署完成。
总结
本文从零开始,逐步完成了以下工作:
- Harbor私有镜像仓库:搭建Docker本地仓库、生成SSL证书、部署Harbor v2.5.4服务
- Kubernetes主机环境:关闭swap、安装Docker、配置证书与主机解析、配置K8s安装源
- Kubernetes集群部署:安装cri-dockerd、安装K8s组件、拉取镜像、初始化集群、节点加入
- Flannel网络插件:加载镜像、推送到本地仓库、修改配置并部署
- Ansible自动化:编写剧本实现Docker、K8s环境的自动化部署
最终得到一个三节点(1 Master + 2 Worker)的Kubernetes v1.35.7集群,所有节点状态均为Ready,并配有Harbor私有镜像仓库用于容器镜像管理。
常见问题排查
Q1: kubeadm init初始化失败怎么办?
使用以下命令重置集群配置,然后重新执行kubeadm init:
bash
kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock
Q2: Node节点加入集群后状态一直NotReady?
通常是因为网络插件未安装或未正确配置。请检查Flannel Pod是否正常运行:
bash
kubectl get pods -n kube-flannel
Q3: 忘记加入集群的token怎么办?
在Master节点重新生成:
bash
kubeadm token create --print-join-command
Q4: 如何确认cri-dockerd正常工作?
检查socket文件是否存在以及服务状态:
bash
ll /var/run/cri-dockerd.sock
systemctl status cri-docker.service