部署环境的说明:
|------------|----------------|------------------|
| 主机名 | ip | 角色 |
| harbor | 172.25.254.250 | harbor仓库 |
| k8s-master | 172.25.254.101 | master,k8s集群控制节点 |
| k8s-node1 | 172.25.254.11 | worker,k8s工作节点 |
| k8s-node2 | 172.25.254.21 | worker,k8s工作节点 |
注:
- 所有节点禁用selinux和防火墙
- 所有节点同步时间和解析
- 所有节点安装docker-ce
- 所有节点禁用swap,注意注释掉/etc/fstab文件中的定义
1.构建harbor镜像仓库
1.1 部署docker本地仓库
bash
#删除与docker冲突的podman
[root@harbor ~]# dnf remove podman -y
#创建 docker 的 yum 源文件指向阿里云 docker 源
[root@harbor ~]# vim /etc/yum.repos.d/docker.repo
[docekr]
name = docker
baseurl = https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/
gpgcheck = 0
#安装 httpd、createrepo 工具,httpd 提供 web 服务,createrepo 生成 yum 仓库元数据
[root@harbor ~]# dnf install httpd createrepo -y
[root@harbor ~]# mkdir -p /var/www/html/docker
#修改 httpd 监听端口 4444,启动 httpd,避免端口冲突
[root@harbor ~]# vim /etc/httpd/conf/httpd.conf
Listen 4444
[root@harbor ~]# systemctl enable --now httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
#--downloadonly`只下载 docker‑ce 的 rpm 包不安装,把 rpm 放到 http 网站目录
[root@harbor ~]# dnf install docker-ce --downloadonly --destdir /mnt/ -y
[root@harbor ~]# mv /mnt/*.rpm /var/www/html/docker/
#createrepo 生成仓库索引,其他主机就可以通过`http://172.25.254.254:4444/docker`安装 docker。
[root@harbor ~]# createrepo -v /var/www/html/docker/
[root@harbor ~]# vim /etc/yum.repos.d/docker.repo
[docker]
name = docker
baseurl = http://172.25.254.254:4444/docker
gpgcheck = 0
[root@harbor ~]# dnf install docker-ce -y
1.2安装docker在harbor仓库节点
bash
#`br_netfilter`内核模块,开启网桥的 iptables 转发
[root@harbor ~]# echo br_netfilter > /etc/modules-load.d/docker_mod.conf
#sysctl 配置三个内核参数:开启网桥 iptables 调用、ipv4 转发
[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.service 启动参数增加`--iptables=true`,让 docker 操作主机 iptables。
[root@harbor ~]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=tru
e
1.3 生成key
bash
#Harbor 需要 https 访问,使用 openssl 生成自签名 rsa4096 证书,域名`reg.ys.org`,证书存放`/data/certs`。
[root@harbor ~]# mkdir -p /data/certs
[root@harbor ~]# openssl req -newkey rsa:4096 \
> -nodes -sha256 -keyout /data/certs/ys.org.key \
> -addext "subjectAltName = DNS:reg.ys.org" \
> -x509 -days 365 -out /data/certs/ys.org.crt
......
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shannxi
Locality Name (eg, city) [Default City]:Xi'an
Organization Name (eg, company) [Default Company Ltd]:kubernetes
Organizational Unit Name (eg, section) []:harbor
Common Name (eg, your name or your server's hostname) []:reg.timinglee.org
Email Address []:admin@timinglee.org
1.4编辑harbor配置文件
bash
#解压 harbor 离线安装包,复制模板`harbor.yml.tmpl`为`harbor.yml`
[root@harbor ~]# ls
anaconda-ks.cfg harbor-offline-installer-v2.5.4.tgz
[root@harbor ~]# tar zxf harbor-offline-installer-v2.5.4.tgz -C /opt/
[root@harbor ~]# cd /opt/harbor/
[root@harbor harbor]# ls
common.sh harbor.v2.5.4.tar.gz harbor.yml.tmpl install.sh LICENSE prepare
[root@harbor harbor]# cp harbor.yml.tmpl harbor.yml
hostname: reg.ys.org #仓库域名
certificate: /data/certs/ys.org.crt #指定 crt 证书、私钥路径
private_key: /data/certs/ys.org.key
harbor_admin_password: 123456 #设置 harbor 管理员密码`123456`
[root@harbor harbor]# systemctl enable --now docker.service
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@harbor harbor]# ./install.sh --with-chartmuseum
#编写启动脚本
[root@harbor harbor]# vim /lib/systemd/system/harbor.service
[Unit]
Description=harbor with Docker Compose
Documentation=https://reg.ys.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
[root@harbor harbor]# docker compose down
[root@harbor harbor]# systemctl enable --now harbor.service
Created symlink /etc/systemd/system/multi-user.target.wants/harbor.service → /usr/lib/systemd/system/harbor.service.
[root@harbor harbor]# docker compose ps
1.5 启动并验证
bash
#docker 信任私有仓库证书:把 crt 证书复制到`/etc/docker/certs.d/reg.ys.org/ca.crt`
[root@harbor harbor]# mkdir -p /etc/docker/certs.d/reg.ys.org/
[root@harbor harbor]# cp /data/certs/ys.org.crt /etc/docker/certs.d/reg.ys.org/ca.crt
#`/etc/hosts`域名解析,把[reg.ys.org](https://reg.ys.org)解析到 harbor 服务器 IP
[root@harbor harbor]# vim /etc/hosts
172.25.254.254 harbor reg.ys.org
[root@harbor harbor]# systemctl restart docker.service
[root@harbor harbor]# docker compose up -d
#docker 登录私有仓库`docker login reg.ys.org -u admin`
[root@harbor harbor]# docker login reg.ys.org -u admin
Password:
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/
Login Succeeded
2.构建kubernetes所需要的主机
所有主机的配置
bash
#关闭swap(所有主机都要做)
systemctl disable --now swap.target
systemctl mask swap.target
sed '/swap/s/^/#/g' -i /etc/fstab
#在所有主机上互相做解析
[root@harbor ~]# vim /etc/hosts
172.25.254.250 harbor reg.ys.org
172.25.254.101 k8s-master
172.25.254.11 k8s-node1
172.25.254.21 k8s-node2
[root@harbor ~]# scp /etc/hosts root@172.25.254.101:/etc/hosts
[root@harbor ~]# scp /etc/hosts root@172.25.254.11:/etc/hosts
[root@harbor ~]# scp /etc/hosts root@172.25.254.21:/etc/hosts
3.利用ansible部署kubernetes运行环境
3.1安装ansible
bash
#安装 ansible,配置 epel 源
[root@harbor ~]# vim /etc/yum.repos.d/epel.repo
[epel]
name = epel
baseurl = https://mirrors.aliyun.com/epel/9/Everything/x86_64/
gpgcheck = 0
[root@harbor ~]# dnf install ansible-core.x86_64 ansible.noarch -y
3.2 配置所需的用户
bash
#创建 devops 普通用户,配置 sudo 免密;ansible 使用 devops 远程管理机器
[root@harbor ~]# useradd devops
[root@harbor ~]# echo 123 | passwd --stdin devops
更改用户 devops 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@harbor ~]# su - devops
[devops@harbor ~]$ mkdir ansible
[devops@harbor ~]$ cd ansible/
3.3 生成ansible的临时配置文件并建立运行环境
bash
#inventory 清单文件写入所有 k8s 节点 IP
[devops@harbor ansible]$ vim inventory
[servers]
172.25.254.101
172.25.254.21
172.25.254.11
#ansible.cfg 关闭 host_key 检查,配置 sudo 提权
[devops@harbor ansible]$ vim ansible.cfg
[defaults]
inventory = /home/devops/ansible/inventory
remote_user = root
ask_pass = false
host_key_checking = false
#`ansible all -m ping`测试连通性。
[devops@harbor ansible]$ ansible all -m ping
172.25.254.101 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
172.25.254.11 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
172.25.254.21 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
#在除harbor主机外的其他主机上建立用户
[devops@harbor ansible]$ ansible all -m user -a "name=devops state=present"
[devops@harbor ansible]$ ansible all -m shell -a 'echo "123" | passwd --stdin devops'
[devops@harbor ansible]$ ansible all -m lineinfile -a 'path=/etc/sudoers line="devops ALL=(ALL) NOPASSWD: ALL" insertafter=EOF'
3.4 生成ansible的主配置文件并测试
bash
[devops@harbor ansible]$ vim ansible.cfg
[defaults]
inventory = /home/devops/ansible/inventory
remote_user = devops
ask_pass = false
host_key_checking = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
#查看用户是否是root用户
[devops@harbor ansible]$ ansible all -m shell -a 'whoami '
172.25.254.21 | CHANGED | rc=0 >>
root
172.25.254.11 | CHANGED | rc=0 >>
root
172.25.254.101 | CHANGED | rc=0 >>
root
3.5 利用ansible脚本部署docker
bash
#编写`kubernetes‑devops.yml`playbook 完成批量执行
[devops@harbor ansible]$ vim kubernetes-devops.yml #注意脚本的缩进
- 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.ys.org"]
}
dest: /etc/docker/daemon.json
- name: setup docker certs
file:
path: /etc/docker/certs.d/reg.ys.org
state: directory
- name: cp certs file
copy:
src: "{{item.src}}"
dest: "{{item.dest}}"
loop:
- src: /etc/docker/certs.d/reg.ys.org/ca.crt
dest: /etc/docker/certs.d/reg.ys.org/ca.crt
- src: /etc/docker/certs.d/reg.ys.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
#运行脚本
[devops@harbor ansible]$ ansible-playbook kubernetes-devops.yml
3.6 利用ansible 安装cri-dockerd
bash
#解压 cri‑dockerd 二进制包,修改 service 配置,指定 pause 镜像为 harbor 本地仓库镜像
[devops@harbor ansible]$ ls
ansible.cfg cri-dockerd-0.4.4.amd64.tgz inventory kubernetes-devops.yml
[devops@harbor ansible]$ tar zxf cri-dockerd-0.4.4.amd64.tgz
[devops@harbor ansible]$ ls
ansible.cfg cri-dockerd cri-dockerd-0.4.4.amd64.tgz inventory kubernetes-devops.yml
[devops@harbor ansible]$ cd cri-dockerd/
[devops@harbor cri-dockerd]$ ls
cri-dockerd cri-docker.service cri-docker.socket
[devops@harbor cri-dockerd]$ vim cri-docker.service
[Service]
Type=notify
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=reg.ys.org/k8s/pause:3.10.1
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
[devops@harbor cri-dockerd]$ cd ..
[devops@harbor ansible]$ vim kubernetes-devops.yml
........... #省略相同部分
################## 增加的部分
- name: stup 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 ca cert
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
[devops@harbor ansible]$ ansible-playbook kubernetes-devops.yml
3.7 利用ansible部署k8s软件
bash
#配置阿里云 k8s yum 源
[devops@harbor ansible]$ ls
ansible.cfg cri-dockerd cri-dockerd-0.4.4.amd64.tgz inventory kubernetes-devops.yml
[devops@harbor ansible]$ mv kubernetes-devops.yml firstbushuwenjian.yml
[devops@harbor ansible]$ ls
ansible.cfg cri-dockerd cri-dockerd-0.4.4.amd64.tgz firstbushuwenjian.yml inventory
[devops@harbor ansible]$ vim kubernetes-devops.yml
- name: install kubernetes from ansible
hosts: all
tasks:
- name: setup k8s repo
yum_repository:
name: kubernetes
description: kubernetes
baseurl: https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm
file: kubernetes
gpgcheck: no
- name: insall software in master
dnf:
name: "{{item}}"
state: present
loop:
- kubeadm-1.35.7-150500.1.1
- kubelet-1.35.7-150500.1.1
- kubectl-1.35.7-150500.1.1
when: inventory_hostname == "172.25.254.101"
- name: install software in work node
dnf:
name: "{{item}}"
state: present
loop:
- kubeadm-1.35.7-150500.1.1
- kubelet-1.35.7-150500.1.1
when: inventory_hostname == "172.25.254.11" or inventory_hostname == "172.25.254.21"
- name: setup kubectl kubeadm complication
lineinfile:
path: /root/.bashrc
line: |
source <(kubectl completion bash)
source <(kubeadm completion bash)
when: inventory_hostname == "172.25.254.101"
- name: start kubelet
service:
name: kubelet
state: started
enabled: yes
[devops@harbor ansible]$ ansible-playbook kubernetes-devops.yml
#让补齐功能生效
[root@k8s-master ~]# source ~/.bashrc
[root@k8s-master ~]# kubectl
alpha (Commands for features in alpha)
annotate (更新一个资源的注解)
api-resources (Print the supported API resources on the server)
api-versions (Print the supported API versions on the server, in the form of "group/version")
apply (Apply a configuration to a resource by file name or stdin)
attach (挂接到一个运行中的容器)
auth (Inspect authorization)
autoscale (Auto-scale a deployment, replica set, stateful set, or replication controller)
certificate (Modify certificate resources)
cluster-info (Display cluster information)
completion (Output shell completion code for the specified shell (bash, zsh, fish, or powershell))
config (修改 kubeconfig 文件)
cordon (标记节点为不可调度)
cp (Copy files and directories to and from containers)
create (Create a resource from a file or from stdin)
debug (Create debugging sessions for troubleshooting workloads and nodes)
delete (Delete resources by file names, stdin, resources and names, or by resources and label ...)
describe (显示特定资源或资源组的详细信息)
diff (Diff the live version against a would-be applied version)
drain (清空节点以准备维护)
edit (编辑服务器上的资源)
events (List events)
exec (在某个容器中执行一个命令)
explain (Get documentation for a resource)
expose (Take a replication controller, service, deployment or pod and expose it as a new Kuber...)
get (显示一个或多个资源)
help (Help about any command)
kustomize (Build a kustomization target from a directory or URL)
label (更新某资源上的标签)
logs (打印 Pod 中容器的日志)
options (输出所有命令的层级关系)
[root@k8s-master ~]# kubeadm
certs config init kubeconfig token version
completion help join reset upgrade
[root@k8s-master ~]# systemctl status kubelet.service
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: activating (auto-restart) (Result: exit-code) since Tue 2026-08-18 17:24:07 CST; 6s ago
Docs: https://kubernetes.io/docs/
Process: 38032 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KU>
Main PID: 38032 (code=exited, status=1/FAILURE)
CPU: 37ms
8月 18 17:24:07 k8s-master systemd[1]: kubelet.service: Main process exited, code=exited, status=1/FAIL>
8月 18 17:24:07 k8s-master systemd[1]: kubelet.service: Failed with result 'exit-code'.
3.8 下载kubernetes集群所需要的镜像
bash
#`kubeadm config images pull`拉取 k8s 所需组件镜像,指定 CRI 套接字`unix:///var/run/cri‑dockerd.sock`(cri‑dockerd 的 socket 路径)
[root@k8s-master ~]# kubeadm config images pull \
> --image-repository registry.aliyuncs.com/google_containers \
> --kubernetes-version 1.35.3 \
> --cri-socket=unix:///var/run/cri-dockerd.sock
#上传镜像到本地
[root@k8s-master ~]# docker login reg.ys.org -uadmin
Password:
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/
Login Succeeded
[root@k8s-master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/google/{system("docker tag "$0" reg.ys.org/k8s/"$3)}'
[root@k8s-master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/ys/{system("docker push "$0)}'
查看

3.9 在master中初始化kubernetes集群
bash
#在master中完成初始化
[root@k8s-master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository reg.ys.org/k8s --kubernetes-version v1.35.3 --cri-socket=unix:///var/run/cri-dockerd.sock
#其它主机加入本集群的凭证
[root@k8s-master ~]# kubeadm token create --print-join-command
kubeadm join 172.25.254.101:6443 --token 0jdj8n.sm9jhzvpeg0lo9lo --discovery-token-ca-cert-hash sha256:9e1dd9be61ea5047dce8dbc429216b7241da758c9a3dca2d72770a45a696cb6f
#如果初始化出现问题
[root@k8s-master ~]# kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock #可以重置集群设定
#添加环境变量到本机
[root@k8s-master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" > ~/.bash_profile
[root@k8s-master ~]# source ~/.bash_profile
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master NotReady control-plane 3m35s v1.35.7
#添加node节点到本集群
[root@k8s-node1 ~]# kubeadm join 172.25.254.101:6443 --token ae42vc.8uh6xfki8dmwufqj --discovery-token-ca-cert-hash sha256:9e1dd9be61ea5047dce8dbc429216b7241da758c9a3dca2d72770a45a696cb6f --cri-socket=unix:///var/run/cri-dockerd.sock
[root@k8s-node2 ~]# kubeadm join 172.25.254.101:6443 --token ae42vc.8uh6xfki8dmwufqj --discovery-token-ca-cert-hash sha256:9e1dd9be61ea5047dce8dbc429216b7241da758c9a3dca2d72770a45a696cb6f --cri-socket=unix:///var/run/cri-dockerd.sock
#查看集群的nodes
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master NotReady control-plane 41m v1.35.7
k8s-node1 NotReady <none> 36s v1.35.7
k8s-node2 NotReady <none> 25s v1.35.7
3.10 安装网络插件
bash
#解压 flannel 离线包,加载 flannel 镜像。
[root@k8s-master ~]# ls
anaconda-ks.cfg kube-flannel-v0.28.9.tar.gz
[root@k8s-master ~]# tar zxf kube-flannel-v0.28.9.tar.gz
[root@k8s-master ~]# ls
anaconda-ks.cfg flannel kube-flannel-v0.28.9.tar.gz
[root@k8s-master ~]# cd flannel/
[root@k8s-master flannel]# ls
kube-flannel-v0.28.9.tar kube-flannel.yml
[root@k8s-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
在harbor上新建项目flannel-io

bash
#将 flannel 镜像打标签推送到 harbor 私有仓库
[root@k8s-master flannel]# docker tag ghcr.io/flannel-io/flannel-cni-plugin:v1.9.1-flannel3 reg.ys.org/flannel-io/flannel-cni-plugin:v1.9.1-flannel3
[root@k8s-master flannel]# docker push reg.ys.org/flannel-io/flannel-cni-plugin:v1.9.1-flannel3
[root@k8s-master flannel]# docker tag ghcr.io/flannel-io/flannel:v0.28.9 reg.ys.org/flannel-io/flannel:v0.28.9
[root@k8s-master flannel]# docker push reg.ys.org/flannel-io/flannel:v0.28.9
查看

bash
#修改`kube‑flannel.yml`镜像地址指向私有 harbor 仓库
[root@k8s-master flannel]# vim 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
[root@k8s-master flannel]# kubectl apply -f kube-flannel.yml
#部署完成后所有节点状态变为`Ready`,集群部署完成
[root@k8s-master flannel]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 52m v1.35.7
k8s-node1 Ready <none> 12m v1.35.7
k8s-node2 Ready <none> 12m v1.35.7