文章受众

  1. 0基础的小白,刚刚开始学Linux,又想搭建一个k8s集群玩玩,感受过程的【建议从环境搭建虚拟机开始看】,如果你想系统性的学习Linux可以留言我的免费专栏"红帽工程师带你从0开始学Linux"
  2. 有一定的Linux基础,想了解ansible部署k8s,和kubeasz开源项目的【建议直接跳转到 开始安装】

使用ansible部署k8s

Ansible 是一个极其流行的开源自动化工具,用于配置管理、应用部署、任务自动化和IT编排。它让你可以用简单的语言描述自动化任务,并在多台服务器上轻松执行。

环境搭建

前期准备:

  • VM 虚拟机
  • Rocky Linux 9.6系统 官网

如果你会Linux系统配置,可以直接跳过下面步骤,直接移步至安装准备

开始安装虚拟机

这里的安装虚拟机是针对k8s的安装需求设置的,如果你是想学Linux基础可以查看一下我的另一个专栏"红帽工程师带你从0开始学Linux"

  1. 打开VMware Workstation,文件选项卡 新建虚拟机。VMware被Broadcom博通公司收购,对个人用户免费 请添加图片描述
  2. 选择 自定义,然后点击下一步 请添加图片描述
  3. 硬件兼容性默认即可,下一步 请添加图片描述
  4. 新建虚拟机向导选择 稍微安装操作系统 请添加图片描述
  5. 选择 Linux,并且在下面的下拉列表中选择Rocky Linux,如果没有则选择Red Hat Enterprise Linux 9
    请添加图片描述
    请添加图片描述
  6. 设置主机名称,并且修改位置,位置默认为C盘 请添加图片描述
  7. 修改处理器配置,处理器内核总数>4即可,数量2内核2或者数量4内核1均可 请添加图片描述
  8. Mstaer节点内存,官方文档推荐8G+,最小为2G,但2G内存仅仅只能将集群搭建出来,无法进行更多的集群操作了,所以这里设置为4G 请添加图片描述
  9. 配置第一张网卡的网络类型,这里设置为NAT
    请添加图片描述
  10. 这里默认即可
    请添加图片描述
  11. 这里也是默认即可,VM会自动旋转合适的硬盘类型 请添加图片描述
  12. 创建新的虚拟硬盘 请添加图片描述
  13. 设置为为50G 请添加图片描述
  14. 保持默认即可 请添加图片描述
  15. 这里用来预览刚刚的虚拟机设置 请添加图片描述
  16. 完成后点击左上角的 编辑,在编辑选项卡中选 择虚拟网络编辑器 请添加图片描述
  17. 正常情况下只有VMnet1和VMnet8,一个对用仅主机模式,一个对应的NAT模式,点击下面的 更改设置 请添加图片描述
  18. 在进入到编辑界面后选择 添加网络 请添加图片描述
  19. 在选择要添加的虚拟网络下拉列表中随机选择一个,我这里选择的VMnet19网络 请添加图片描述
  20. 在添加虚拟网络后,按下面内容进行配置,选择 仅主机模式,并且将 将主机虚拟适配器连接到此网络 选项勾选,将 使用本地DHCP服务器IP地址分配给虚拟机,并且设置子网和子网掩码,完成后点击应用,点击确定 请添加图片描述
  21. 在完成上面操作后回到初始页面,选择 编辑虚拟机设置 请添加图片描述
  22. 点击最下面的 添加按钮 请添加图片描述
  23. 在要添加的硬件中选择 网络适配器,点击完成 请添加图片描述
  24. 再回到 虚拟机设置界面,选择刚刚添加的 网络适配器2在网络连接中选择自定义,在自定义中选择前面设置的虚拟网络,我前添加的是VMnet19,所以这里选择VMnet19 请添加图片描述
  25. 完成后选择CD/DVD,在连接中选择下载好的Rocky Linux iso文件,完成后点击确定 请添加图片描述
  26. 回到主页面后点击 开启此虚拟机 请添加图片描述

安装系统

  1. 如果前面的步骤正确,系统开启后直接按回车即可进入此界面,选择语言,你可以选择中文,我只是个人不太习惯在Linux的终端中看见中文,所以我选择的英文 请添加图片描述
  2. 一次完成下面配置,这里先配置的是 Installation Destination就是安装的磁盘配置 请添加图片描述
  3. 新手直接默认即可,选择下面的 Local Standard Disks的磁盘即可中文 本地标准磁盘即按照默认的分区标准进行分区,完成后单机左上角的 Done即可 请添加图片描述
  4. 再是 Software selection软件选择,模式是 Server with GUI即带图形化的界面,你可以使用默认选项,也推荐小白使用,我这里选择的 Minimal Install即最小系统安装。优点是小,安装快。 请添加图片描述
  5. 最后是 Root Password推荐密码尽可能的简单容易记,我这里设置的六个0,【注意这里是虚拟机的实验环境,生产环境中严禁使用此密码】完成后点击 Done点击后可能没反应,是因为密码无法通过最低安全审查,但是在虚拟机环境中双击或三击即可强制跳过安全审查【再次声明,在生成环境中严禁这样操作】 请添加图片描述
  6. 在设置完成后选择 Begin installation开始安装,在设置了Root Password密码后User creation再会有提示,所以我们无需配置User creation 请添加图片描述
  7. 等待系统安装完成 请添加图片描述
  8. 安装完成后点击 Reboot System重启系统 请添加图片描述

系统配置

考虑到这篇文件主要是面对0基础的小白,所以这里补充一些vi/vim编辑器的内容。 请添加图片描述

  • 使用vim + 文件名/文件路径编辑文件
  • vim编辑器存在三种界面,如上图。默认模式为命令模式,可以理解为查看模式,无法对文件进行编辑
  • 编辑插入模式,使用i/o/a进入,通过上下左右方向键移动光标,可以对文本内容进行编辑。使用esc键可以返回命令模式
  • 末行模式,使用 :键进入,用于执行文件命令,q退出,q!强制退出,w保存,wq保存退出,x保存退出

在了解完vi/vim的基本操作后,我们进行下一步操作

  1. 在进入系统后界面如下,如果在安装的时候选择的是最小安装效果就和下面的图片一样,如果是有图形化界面则会有图形化的登入界面 请添加图片描述
  2. 在login后面输入 root回车,回车后会要提示输入密码,我们前面设置的000000,所以这里直接输入000000,在输入密码的时候不会显示密码 请添加图片描述
  3. 进入系统后键入下面命令,如果是图形化界面在桌面右键鼠标,在弹出的快捷菜单中选择 终端英文为 Terminal在新打开的命令行窗口中输入下面命令严重警告,如果你实在是没有把握执行这一步操作请跳过,见后面的故障解决,没有ssh远程连接,你后面的操作都会异常痛苦
vi /etc/ssh/sshd_config

请添加图片描述

  1. 使用编辑器编辑ssh的配置文件,找到文件中的 PermitRootLogin选项
    请添加图片描述
  2. 按i进入编辑模式,先将 PermitRootLogin选项前的 #删除,将后面的值改为yes,内容如下
# LoginGraceTime 2m
PermitRootLogin yes
# StrictModes yes

如果你选择的是图形化安装或者你安装了其他的扩展工具那么这个选项可能已经是yes了,那么这个时候则无需处理了,但是在默认情况下Rocky Linux默认是禁用root用户使用ssh进行登入,但是普通用户可以使用ssh进行登入,如果你不会操作可以暂时跳过这一步

  1. 完成后 esc进入命令模式,按 :进入末行模式,输入 x保存并退出
    请添加图片描述
  2. 完成后键入下面命令,命令输入完成后和下面的图片内容一样则表示成功,转态提示绿色则表示成功,如果状态提示为红色或者灰色则表示服务重启失败,大概率是在刚刚修改配置文件的配置文件修改失败。请返回第三步重新进行操作。【如果你实在是无法修复错误,那么你可能需要回到第一步重新开始做】
systemctl restart sshd
systemctl status sshd

请添加图片描述
8. 完成上面步骤后则表示ssh可以使用,这里使用 ip a命令来查看系统的IP地址,这里有ens160和ens192两张网卡,记录下ens160也就是网络适配器1的地址,使用的NAT地址的模式。这里我们使用ssh远程软件【XShell,SecureCRT,MobaXterm等】来连接系统,我这里使用的Xshell。当然你也可以选择用win自带的powershell,但我的评价是能用,仅仅只是能用,比你在虚拟机里面手敲终端好使。我为什么这么说,你待会就知道了 请添加图片描述
ssh连接命令

ssh root@你刚刚记录的IP地址

故障解决

针对上面可能会出现的问题,这里提供一些可能的解决方案

两张网卡都没IP

两种可能

  1. 需要连接外网的网卡没有被设置到NAT模式,请确保网络模式为NAT 请添加图片描述
  2. NAT的网络的DHCP没开启,请确保图片中的√被√上了 请添加图片描述
  3. 系统未能正确自动配置网络,在执行此命令的时候请一定确保前面的DHCP已经被正确配置
nmcli connection modify ens160 ipv4.method auto autoconnect yes
nmcli connection up ens160
完全不会配置ssh配置文件的

在终端中执行下面命令

useradd test1
echo 000000 | passwd --stdin test1

使用test1进行远程

ssh test1@你刚刚记录的IP地址
su root #su 切换用户,su后需要输入密码
对于上面的解决方案完全看不懂,或者完全不知道我前面是在做什么的

现在立刻马上退出这篇文章,这篇文章还不适合现阶段的你,你可以先去看看其他优先博主的文章,打下Linux基础,或者你也可看看我的"红帽工程师带你从0开始学Linux"专栏中的文章,如果这个专栏我出了的话

安装准备

这里会配置系统的内网IP,yum源仓库,docker国内加速地址,chrony/NTP时间同步,虚拟机克隆,如果你会配置可以直接移步 开始安装,

配置yum源

  1. 配置yum源,打开阿里镜像站
    请添加图片描述
  2. 在搜索栏搜索Rocky
    请添加图片描述
  3. 在Rocky Linux将下面的内容直接复制到shell软件,发送到服务器【如果你没有shell请考虑使用powershell或者自己手敲,或者自己想办法将下面内容复制到服务器】 请添加图片描述
    内容如下:
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    -i.bak \
    /etc/yum.repos.d/Rocky-*.repo

dnf makecache

完成后使用下面命令检查仓库,yum和dnf二选一即可,命令功效是一样的

dnf repolist
yum repolist

输出结果如下就是对的

[root@localhost ~]# dnf repolist
repo id                                                               repo name
appstream                                                             Rocky Linux 9 - AppStream
baseos                                                                Rocky Linux 9 - BaseOS
extras                                                                Rocky Linux 9 - Extras
[root@localhost ~]# yum repolist
repo id                                                               repo name
appstream                                                             Rocky Linux 9 - AppStream
baseos                                                                Rocky Linux 9 - BaseOS
extras                                                                Rocky Linux 9 - Extras

安装下面软件bash-completion和wget,并且刷新bash命令解析器使得bash补全可以生效

dnf install -y bash-completion wget vim
bash
  1. 回到主页选择 镜像 -> 容器 分别配置下面连个仓库 请添加图片描述
  2. Kubernetes镜像仓库配置,待会安装的是v1.32版本的集群,所以配置内容如下,详情可以自行前往网页查看,Kubernetes镜像仓库
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.32/rpm/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.32/rpm/repodata/repomd.xml.key
EOF
setenforce 0
  1. Docker CE镜像,这里配置docker进行是因为后面的kubeasz项目使用的ansible in docker的安装方式,所以这里会安装docker
    但是要注意k8s不是使用docker,docker是容器技术的应用,但是k8s集群至始至终都没用系统支持docker ce引擎,k8s在开发之初便是采用dockershim兼容docker ce容器引擎。只是在k8s V1.24之前默认安装dockershim兼容层,但是在k8s v1.24版本后k8s不再默认安装dockershim兼容层而是使用cri容器运行时和容器运行时接口进行容器的管理。当然如果你非要继续使用docker作为k8s的容器引擎也不是不行,只是现在有了更多选择。比如containerd,CRI-O等
    # step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils

    # Step 2: 添加软件源信息
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

    # Step 3: 安装Docker
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

    # Step 4: 开启Docker服务
sudo systemctl enable docker.service --now

    # 注意:
    # 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。
    # vim /etc/yum.repos.d/docker-ce.repo
    #   将[docker-ce-test]下方的enabled=0修改为enabled=1
    #
    # 安装指定版本的Docker-CE:
    # Step 1: 查找Docker-CE的版本:
    # yum list docker-ce.x86_64 --showduplicates | sort -r
    #   Loading mirror speeds from cached hostfile
    #   Loaded plugins: branch, fastestmirror, langpacks
    #   docker-ce.x86_64            17.03.1.ce-1.el7.centos            docker-ce-stable
    #   docker-ce.x86_64            17.03.1.ce-1.el7.centos            @docker-ce-stable
    #   docker-ce.x86_64            17.03.0.ce-1.el7.centos            docker-ce-stable
    #   Available Packages
    # Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos)
    # sudo yum -y install docker-ce-[VERSION]
  1. 上面步骤完成后执行下面命令,如果没有dnf的请将dnf改为yum
dnf clean all
dnf makecache
dnf repolist

docker 加速地址配置

由于docker仓库是在国外,所以在国内访问需要使用镜像加速地址

vim /etc/docker/daemon.json

i键进入编辑模式,将下面内容粘贴到文件中,在使用 ESC,:,x保存退出

{
  "registry-mirrors": [
    "https://docker.1ms.run"
  ]
}

文件编辑完成后执行下面命令

systemctl restart docker.service
docker pull hello-world
docker run hello-world

执行后的结果如下

[root@localhost ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
17eec7bbc9d7: Pull complete 
Digest: sha256:54e66cc1dd1fcb1c3c58bd8017914dbed8701e2d8c74d9262e26bd9cc1642d31
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
[root@localhost ~]# docker run hello-world:latest 

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

docker 命令指南

docker ps   #查看正在运行的容器
docker run  #运行容器
docker images   #容器镜像列表
docker rm   #删除容器
docker rmi  #删除容器镜像

关闭防火墙和Selinux

在实验环境中,请关闭防火墙和SELinux以避免一些不必要的麻烦

systemctl disable firewalld.service --now
setenforce 0

setenforce 0是临时关闭SELinux,系统重启后会自启动,下面需要配置SELinux的配置文件,使得SELinux不会自启动

vim /etc/selinux/config 

找到 SELINUX=enforcing选项,将 enforcing修改为 disabled,修改后的内容为 SELINUX=disabled

配置网络地址

使用ip a来查看当前系统的IP地址,会发现只有ens160有IP地址,ens192没有IP地址。造成这一情况的原因是在Rocky Linux的默认网络配置是使用DHCP自动获取IP地址,VMnet8默认是NAT模式,并且启用DHCP模式,所以链接在VMnet8网络的ens160网卡可以存在IP地址,但是请注意DHCP是动态分配IP也就是说一但服务器关机,下一次开机的时候IP地址不一定是这个IP地址也正是基于这个情况,所以这里才添加了两张网卡,一张用于外网的链接,一张用于集群直接的链接

[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:9a:34:c2 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 30.30.30.164/24 brd 30.30.30.255 scope global dynamic noprefixroute ens160
       valid_lft 1606sec preferred_lft 1606sec
    inet6 fe80::20c:29ff:fe9a:34c2/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:9a:34:cc brd ff:ff:ff:ff:ff:ff
    altname enp11s0
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 9a:96:a1:82:c1:63 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::9896:a1ff:fe82:c163/64 scope link 
       valid_lft forever preferred_lft forever
[root@localhost ~]# 

使用下面 nmcli命令对ens192进行配置,在Centos7 8中可以通过编辑网卡配置文件来修改修改网络配置,但是在RHEL9系列的系统中已经取消了这一配置,在 /etc/sysconfig/network-scripts/目录中已经没有网卡的配置文件了

[root@localhost ~]# ls /etc/sysconfig/network-scripts/ 
readme-ifcfg-rh.txt

下面将展示使用 nmcli命令对网络进行配置

nmcli connection show

查看当前的网络连接,结果如下

[root@localhost ~]# nmcli connection show 
NAME     UUID                                  TYPE      DEVICE  
ens160   729b1418-84f5-3423-87c8-df6811179236  ethernet  ens160  
docker0  4011af3b-ee91-4bf9-aeee-d33e1e9c7470  bridge    docker0 
lo       ba7d2732-20f1-44af-b183-9594beb91e5e  loopback  lo  
ens192   d27e4a9a-b6d3-3c3c-89f5-3dbdbfcd04a3  ethernet  --  
[root@localhost ~]# 

可以看到ens192的 DEVICE--表示没有被任何网络硬件连接和使用,所以使用下面命令来激活ens192网卡

nmcli connection modify ens192 ipv4.addresses 10.0.0.10/8 ipv4.gateway 10.0.0.254 ipv4.method manual autoconnect yes
nmcli connection up ens192
  • 命令解释,connection表示连接,modify修改,ens192连接名称,ipv4.addresses 10.0.0.10/8字面意思,ipv4的IP地址,ipv4.gateway 10.0.0.254,ipv4网关,ipv4.method 这个连接的ipv4工作模式,manual表示手动配置,auto表示自动配置即DHCP模式,autoconnect yesautoconnect表示是否开机自启 yes表示需要开机自启。
  • 第二条命令中的 up表示启用/激活,down表示关闭连接。
  • 使用 ip a进行查看
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:9a:34:c2 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 30.30.30.164/24 brd 30.30.30.255 scope global dynamic noprefixroute ens160
       valid_lft 1625sec preferred_lft 1625sec
    inet6 fe80::20c:29ff:fe9a:34c2/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:9a:34:cc brd ff:ff:ff:ff:ff:ff
    altname enp11s0
    inet 10.0.0.10/8 brd 10.255.255.255 scope global noprefixroute ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe9a:34cc/64 scope link tentative noprefixroute 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 9a:96:a1:82:c1:63 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::9896:a1ff:fe82:c163/64 scope link 
       valid_lft forever preferred_lft forever

这样子我们就有了两张网卡。

NTP时间同步配置

  1. 使用date命令查看系统时间
[root@localhost ~]# date
Thu Sep 18 04:18:32 PM CST 2025

这里的时间是 CST中国标准时间
2. 如果你的时区不是中国则需要使用下面命令进行修改,如果已经是CST了则不需要修改,系统的时区设置决定了如何显示从NTP服务器同步来的UTC时间。如果系统时区是东8区(UTC+8),同步后显示的时间就是北京时间;如果是西8区(UTC-8),显示的时间就是太平洋标准时间。不过不管哪个时区都对k8s集群的影响不大,我们仅需要保证集群内部的时间是同步的即可,只要你想你甚至可以自己时间同步服务器,并且设置集群内部时间为1999年1月1号警告,在实验环境中你可以配置1999.1.1的日期,玩玩做实验完全没问题,但是在生产环境中严禁这样配置

    # 1. 查看当前状态
timedatectl
    # 2. 列出所有可用时区(Asia目录下包含中国时区)
timedatectl list-timezones
    # 3. 搜索亚洲时区(可选,确认名称)
timedatectl list-timezones | grep -i Asia
    # 4. 设置时区
sudo timedatectl set-timezone Asia/Shanghai
    # 5. 验证
timedatectl
date
  1. 打开阿里云镜像站,点击 网络授时NTP -> NTP 请添加图片描述
  2. 安装chrony客户端
dnf -y install chrony
  1. 修改配置文件,这里使用的阿里云的[NTP网络授时] (https://developer.aliyun.com/mirror/NTP)
rm -rf /etc/chrony.conf
vim /etc/chrony.conf

将下面内容粘贴到 /etc/chrony.conf文件中

server ntp.aliyun.com iburst
stratumweight 0
driftfile /var/lib/chrony/drift
rtcsync
makestep 10 3
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
keyfile /etc/chrony.keys
commandkey 1
generatecommandkey
logchange 0.5
logdir /var/log/chrony

完成后 esc进入命令模式,按 :进入末行模式,输入 x保存并退出

  1. 重启时间服务
systemctl restart chronyd
systemctl status chronyd

结果如下:

[root@localhost ~]# systemctl restart chronyd
[root@localhost ~]# systemctl status chronyd
● chronyd.service - NTP client/server
     Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-09-18 17:12:40 CST; 7s ago
       Docs: man:chronyd(8)
             man:chrony.conf(5)
    Process: 29531 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
   Main PID: 29534 (chronyd)
      Tasks: 1 (limit: 22932)
     Memory: 1.0M
        CPU: 25ms
     CGroup: /system.slice/chronyd.service
             └─29534 /usr/sbin/chronyd -F 2

Sep 18 17:12:40 localhost.localdomain systemd[1]: Starting NTP client/server...
Sep 18 17:12:40 localhost.localdomain chronyd[29534]: chronyd version 4.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS +>
Sep 18 17:12:40 localhost.localdomain chronyd[29534]: commandkey directive is no longer supported
Sep 18 17:12:40 localhost.localdomain chronyd[29534]: generatecommandkey directive is no longer supported
Sep 18 17:12:40 localhost.localdomain chronyd[29534]: Loaded 0 symmetric keys
Sep 18 17:12:40 localhost.localdomain chronyd[29534]: Frequency 2.834 +/- 0.362 ppm read from /var/lib/chrony/drift
Sep 18 17:12:40 localhost.localdomain chronyd[29534]: Loaded seccomp filter (level 2)
Sep 18 17:12:40 localhost.localdomain systemd[1]: Started NTP client/server.
Sep 18 17:12:44 localhost.localdomain chronyd[29534]: Selected source 203.107.6.88 (ntp.aliyun.com)
  1. 使用下面命令立刻进行时间同步
chronyc makestep    #强制 Chrony 立即检查所有时间源并更新时钟
chronyc sources -v  #查看时间源的状态信息
chronyc tracking    #查看跟踪的当前同步状态
date                #查看系统时间

同步结果如下
请添加图片描述

虚拟机克隆

如果你是按照我的步骤完成的你会发现我文章只配置了一台服务器,但这里需要两台服务器才能实现,所以请按照下面的步骤完成虚拟机克隆,但如果你是两台服务器同时配置的请跳过虚拟机克隆

  1. 在终端键入命令,关闭服务器
poweroff
  1. 添加虚拟机快照 请添加图片描述
  2. 名称虽然可以不用修改,但是为了后续方便还原快照推荐还是修改一个名称,名称修改完毕后点击拍摄快照。我这里给的备注是"基础配置完成"。 请添加图片描述
  3. 快照拍摄完成后再左边的侧边栏找到刚刚的虚拟机右键,在快捷菜单中选择 管理,再在子菜单中选择 克隆 请添加图片描述
  4. 进入克隆虚拟机导向,点击下一步 请添加图片描述
  5. 选择 现有快照在下拉菜单中选择刚刚拍摄的快照,我前面的备注是"基础配置完成",所以这里的选项是"基础配置完成",选择完毕后下一步 请添加图片描述
  6. 你可以更具自己的需求选择选择是创建链接克隆还是完整克隆,考虑到读者的存储未必有这么多,所以这里选择的是创建链接克隆,完成后下一步 请添加图片描述
  7. 和之前一致,需要修改 虚拟机名称位置完成后点击 完成 请添加图片描述
  8. 克隆完成 请添加图片描述
  9. 在侧边栏选中刚刚克隆的node1主机,点击 编辑虚拟机设置 请添加图片描述
  10. 点击内存,在右侧将内存提高到8G,node节点是容器任务的主要运行地方,需要更大的内存来支撑众多的服务,虽然这是在实验环境中,但我依然推荐你配置更高的内存,但是如果你电脑内存实在吃紧不修改也无伤大雅 请添加图片描述
  11. 开启node1虚拟机,仅开node1不开Master,仅开node1不开Master,仅开node1不开Master。因为node1此时是Master的克隆,IP地址都是一样的,在开启node1的同时将Master节点打开会出现IP地址冲突的情况,如果你不小心将Master节点开启了请立刻关闭 请添加图片描述
  12. 使用ssh远程工具连接10.0.0.10,因为此时我们只开了node1一台服务器,只有一个10.0.0.10地址,如果你将Master节点启动,此时10.0.0.0网络中会存在两台10.0.0.10地址,会直接导致连接失败 请添加图片描述
  13. 在使用10.0.0.10的地址连接上后执行下面命令,将IP地址修改为11,请注意这条命令和前面的命令几乎是一模一样,唯一的区别在 ipv4.addresses 10.0.0.11/8一个是10一个是11
nmcli connection modify ens192 ipv4.addresses 10.0.0.11/8 ipv4.gateway 10.0.0.254 ipv4.method manual autoconnect yes
nmcli connection up ens192
  1. 在你输入完这条命令后可能会出现下面情况,但是请不要慌张,这不是表明你配置错了,相反,你只有配置正确的才会出现这个情况 请添加图片描述
    这表明TCP连接超时,连接关闭,为什么会这样,因为我们修改了主机的IP地址,ssh无法和原来的的IP地址建立连接,所以出现了TCP超时,ssh连接关闭,我们只需要重新建立和10.0.0.11/8的链接就可以了
ssh root@10.0.0.11

请添加图片描述
ssh连接便恢复了

  1. 完成上面步骤后请键入 poweroff命令关闭虚拟机,并且安装前面的步骤2-3完成node节点的快照创建,如果完成了快照可以通过下面方式查看历史快照 请添加图片描述

开始安装

这里使用的Github的开源项目kubeasz 请添加图片描述
IP节点规划 如果你没有两台及以上的服务器请返回上一步的虚拟机克隆

节点主机 IP地址 功能
Master 10.0.0.10/8 master etcd
node1 10.0.0.11/8 node

下面内容摘自官方文档,我做了些许的补充

1.基础系统配置【已完成,见步骤1环境搭建】

  • 2c/4g内存/40g硬盘(该配置仅测试用)
  • 最小化安装Ubuntu 16.04 server或者CentOS 7 Minimal
  • 配置基础网络、更新源、SSH登录等

2.在每个节点安装依赖工具【已完成,见步骤2安装准备的1 2点】

推荐使用ansible in docker 容器化方式运行,无需安装额外依赖。

3.准备ssh免密登陆

在Master节点或node节点均可,但是推荐在Master节点。
使用 ssh-keygen命令创建秘钥。

ssh-keygen

结果如下

[root@localhost ~]# ssh-key
ssh-keygen   ssh-keyscan  
[root@localhost ~]# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:2MsMJd2UYNVuPPsj9rRGQjzl1nuK3lpHTKw2/Ca2vTs root@localhost.localdomain
The key's randomart image is:
+---[RSA 3072]----+
|        oooo     |
|       o o. . .. |
|      . o .+ o .o|
|       =    O.o+.|
|      o S  o == +|
|       + .  o..=.|
|        +    ==.=|
|            +==E |
|           oo==+=|
+----[SHA256]-----+
[root@localhost ~]# 

没错 ssh-keygen命令后接三个回车即可,什么都不用管。ssh的RSA秘钥就这样的被创建出来了。
那么刚刚创建出来的ssh秘钥在哪?如下图
请添加图片描述
这里可以使用ls 命令查看

ls /root/.ssh/

里面有两个文件,id_rsaid_rsa.pubid_rsa是私钥需要我们妥善保管的秘钥,id_rsa.pub是公钥可以被公开的,关于RSA秘钥的具体实现原理可以去自行查找资料,我后面可能也会写有关的文章,可能吧~
秘钥被创建出来后我们并不能直接使用,要使用需要我们将ssh的公钥拷贝到受控主机上,使用 ssh-copy-id命令可以实现将公钥快速拷贝到被控服务器

ssh-copy-id root@10.0.0.11
ssh-copy-id root@10.0.0.10

请添加图片描述
图片中仅仅拷贝了一台做示例,图中标号

  1. 表示"你确定要连接吗?"需要我们输入yes
  2. “root@10.0.0.11’s password:”需要我们输入密码,同样密码不显示直接输000000即可【注意这6个0是我在系统安装时候设置的,如果你不是根据我的步骤做的请填写你自己设置的密码】
    完成上面步骤后我们进行次下面测试,在Master主机节点操作
ssh root@10.0.0.11
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:9a:34:c2 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 30.30.30.164/24 brd 30.30.30.255 scope global dynamic noprefixroute ens160
       valid_lft 1348sec preferred_lft 1348sec
    inet6 fe80::20c:29ff:fe9a:34c2/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:9a:34:cc brd ff:ff:ff:ff:ff:ff
    altname enp11s0
    inet 10.0.0.10/8 brd 10.255.255.255 scope global noprefixroute ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe9a:34cc/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether ee:55:23:01:35:3f brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# ssh root@10.0.0.11
Last login: Thu Sep 18 19:47:25 2025 from 10.0.0.10
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:02:42:ac brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 30.30.30.165/24 brd 30.30.30.255 scope global dynamic noprefixroute ens160
       valid_lft 1344sec preferred_lft 1344sec
    inet6 fe80::20c:29ff:fe02:42ac/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:02:42:b6 brd ff:ff:ff:ff:ff:ff
    altname enp11s0
    inet 10.0.0.11/8 brd 10.255.255.255 scope global noprefixroute ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe02:42b6/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 0a:db:4e:67:12:ab brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
[root@localhost ~]# 
[root@localhost ~]# exit
logout
Connection to 10.0.0.11 closed.

可以留意IP地址,使用exit退出ssh连接回到10主机。

这里你一定会有疑问,我们的ansible-playbook是在10主机上执行的,为什么还要ssh免密10主机,为什么要自己免密自己?
解答: 请留意第二点,2.在每个节点安装依赖工具中的推荐使用ansible in docker 容器化方式运行,无需安装额外依赖,ansible-playbook本质上并没做在Master主机上运行,而是在docker的容器环境下运行,而容器环境和主机环境是隔离的,也就是说ansible中的控制主机实质是容器,通过容器网络反向控制物理主机,所以这里才需要ssh自己免密自己。

4.在部署节点编排k8s安装

  • 4.1 下载项目源码、二进制及离线镜像
    下载工具脚本ezdown,举例使用kubeasz版本3.6.6
export release=3.6.6
wget https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
chmod +x ./ezdown

由于releases仓库位于国外,下载会相对比较慢,并且可能会下载失败,可以所试几次或直接使用魔法。这里解释一下为什么不使用最新的3.6.8版本而是使用3.6.6的版本,因为3.6.8的国内镜像用不了,就这么简单,我最开始写稿的时候就是按3.6.8版本k8s 1.34版本写的,但写到这里发现另外两个国内用不来,除非魔法,截止我发稿时国内镜像依然是不可用状态,如果你有兴趣可以尝试一下修改 release的值修改为最新的 3.6.8

  • 4.2 脚本下载完后使用 ./ezdown -D命令下载kubeasz代码、二进制、默认容器镜像(更多关于ezdown的参数,运行./ezdown 查看)。这里的所有命令都是基于国内的网络进行配置,需要更多信息请访问项目源仓库
./ezdown -D

【可选】下载额外容器镜像(cilium,flannel,prometheus等)我这里不做演示,感兴趣的可以自行研究

# 按需下载
./ezdown -X flannel
./ezdown -X prometheus
...

【可选】下载离线系统包 (适用于无法使用yum/apt仓库情形)这里我也不做演示,感兴趣自行尝试

./ezdown -P

上述脚本运行成功后,所有文件(kubeasz代码、二进制、离线镜像)均已整理好放入目录/etc/kubeasz。这里不用管

  • 4.3 创建集群配置实例
# 容器化运行kubeasz
./ezdown -S

# 创建新集群 k8s-01
docker exec -it kubeasz ezctl new k8s-01

然后根据提示配置’/etc/kubeasz/clusters/k8s-01/hosts’ 和 ‘/etc/kubeasz/clusters/k8s-01/config.yml’:根据前面节点规划修改hosts 文件和其他集群层面的主要配置选项;其他集群组件等配置项可以在config.yml 文件中修改。

编辑hosts主机资源清单文件

下面是主机清单的默认内容,后面还有很多内容,但是我们仅需要修改这几行即可,所以我只粘贴了这几行

# 'etcd' cluster should have odd member(s) (1,3,5,...)
[etcd]
192.168.1.1
192.168.1.2
192.168.1.3

# master node(s), set unique 'k8s_nodename' for each node
# CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
# and must start and end with an alphanumeric character
[kube_master]
192.168.1.1 k8s_nodename='master-01'
192.168.1.2 k8s_nodename='master-02'
192.168.1.3 k8s_nodename='master-03'

# work node(s), set unique 'k8s_nodename' for each node
# CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
# and must start and end with an alphanumeric character
[kube_node]
192.168.1.4 k8s_nodename='worker-01'
192.168.1.5 k8s_nodename='worker-02'
  • etcd用于存储并管理着整个集群的所有关键数据,并且只能是单数个部署
  • kube_master用于指定哪些节为Master
  • k8s_nodename用于修改主机命名,如将此选项移除则默认不改变主机名,我们之前并为修改主机名,所以建议将该选项保留,但是如果你之前已经配置了主机名,那就随意了
  • kube_node用于指定哪些节为node
  • ex_lb用于配置多主节点的时候设置对外暴露的统一虚拟IP(VIP),这里受限于性能不予演示,所以条并不需要配置
    下面我给出我的配置
# 'etcd' cluster should have odd member(s) (1,3,5,...)
[etcd]
10.0.0.10

# master node(s), set unique 'k8s_nodename' for each node
# CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
# and must start and end with an alphanumeric character
[kube_master]
10.0.0.10 k8s_nodename='master-01'

# work node(s), set unique 'k8s_nodename' for each node
# CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
# and must start and end with an alphanumeric character
[kube_node]
10.0.0.11 k8s_nodename='node-01'

# [optional] harbor server, a private docker registry
# 'NEW_INSTALL': 'true' to install a harbor server; 'false' to integrate with existed one
[harbor]
#192.168.1.8 NEW_INSTALL=false

# [optional] loadbalance for accessing k8s from outside
[ex_lb]
#192.168.1.6 LB_ROLE=backup EX_APISERVER_VIP=192.168.1.250 EX_APISERVER_PORT=8443
#192.168.1.7 LB_ROLE=master EX_APISERVER_VIP=192.168.1.250 EX_APISERVER_PORT=8443

这里补充一点,etcd和Master功能上是解耦的,也就是说etcd的数量不必和Master节点相同,这里是etcd复用了Master节点,但是有一点是一样,就是etcd和Master都必须是奇数个,etcd也不必位于集群内,他可以是单独的节点,比如Master是.10 .20 .30三个节点,而etcd可以是.10 .100 .200三个节点

编辑config.yml 配置文件

没什么好配置的,默认即可。
如果你需要可以查看Github中的项目源文件,会详细讲述着文件要怎么配置。

5. 开始安装k8s【这条是我自己加的,只是为了方便排版,但内容是官方文档中的4.3,不是我文档的4.3】

开始安装 如果你对集群安装流程不熟悉,请阅读项目首页 安装步骤 讲解后分步安装,并对 每步都进行验证

#建议使用alias命令,查看~/.bashrc 文件应该包含:alias dk='docker exec -it kubeasz'
source ~/.bashrc

# 一键安装,等价于执行docker exec -it kubeasz ezctl setup k8s-01 all
dk ezctl setup k8s-01 all

# 或者分步安装,具体使用 dk ezctl help setup 查看分步安装帮助信息
# dk ezctl setup k8s-01 01
# dk ezctl setup k8s-01 02
# dk ezctl setup k8s-01 03
# dk ezctl setup k8s-01 04

我这里比较懒没有配置alias,所以使用下面命令进行安装

docker exec -it kubeasz ezctl setup k8s-01 all

看到这个表示K8s集群部署完成了请添加图片描述
但是我还不能使用,因为我们没有合适的客户端来访问k8s集群,所以这里我们要安装kubectl,并且添加命令补全

dnf -y install kubectl      #安装kubectl
source /usr/share/bash-completion/bash_completion   #添加命令补全
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
bash                        #刷新bash解析器
kubectl version             #使用kubectl查看k8s集群版本

结果如下

Installed:
  kubectl-1.32.9-150500.1.1.x86_64                        

Complete!
[root@master-01 ~]# 
[root@master-01 ~]# 
[root@master-01 ~]# source /usr/share/bash-completion/bash_completion
[root@master-01 ~]# kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
[root@master-01 ~]# bash
[root@master-01 ~]# kubectl version 
Client Version: v1.32.3
Kustomize Version: v5.5.0
Server Version: v1.32.3
[root@master-01 ~]# 
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐