Kubernetes 集群部署202507
本实验主要软件环境及资源如下:
- 二进制部署CentOS8.5+Kubernetes1.33.2+Docker28.3.1高可用集群
一、系统要求
Kubermetes 系统由一组可执行程序组成,用户可以通过Kubernetes在GitHub 的项目网站下载编译好的二进制文件或镜像文件,或者下载源码并自行将其编译为二进制文件。安装 Kubernetes对系统软件和硬件的要求如表 所示。
软硬件 | 最低配置 | 推荐配置 |
---|---|---|
主机资源 | 若在集群中有1~5个Node,则要求如下: - Master:至少2 core CPU和 2GB 内存。 - Node:至少1core CPU 和内存。 在增加集群规模时,应相应地增加主机配置。在大规模集群的硬件配置方面可以参考 Kuberetes 官网给出的建议 | Master:4 core CPU和 16GB 内存。 Node:根据要运行的容器数量进行配置 |
Linux | 各种 Linux 发行版,包括RedHatLinux、CentOS、Fedora、Ubuntu.Debian 等,Kermel版本要求在 v3.10 及以上 | CentOS 7.9 |
etcd | 版本为 v3 及以上 可以参考 etcd 官网的说明下载和安装 etcd | etcd v3 |
容器运行时 | Kubemmetes支持的容器运行时包括contaimerd、CRI-O等。 | contaimerd v1.7 |
Kubernetes需要容器运行时的支持。目前Kubernetes 官方支持的容器运行时包括containerd、CRI-O等,推荐采用 containerd v1.7 版本。
对于宿主机操作系统,以CentOs7为例,使用Systemd 系统完成Kubermetes服务配置。对于其他 Linux发行版本的服务配置,可以参考相关系统管理手册。为了便于管理常常将 Kubernetes 服务程序配置为 Linux开机自启动。
需要注意的是,CentOS7默认启动了防火墙服务(firewalld.service),而Kubernetes的 Master 与各个 Node 之间会有大量的网络通信,安全的做法是在防火墙上配置各组件相互通信的端口号,需要配置的端口号如表所示。
组件 | 默认端口号 |
---|---|
API Server | 6443 |
Controller Manager | 10257 |
Scheduler | 10259 |
kubelet | 10250、10255(只读端口号) |
etcd | 2379(供客户端访问)、2380(供etcd集群内节点之间访问) |
集群的DNS服务 | 53(UDP)、53(TCP) |
对于其他组件,可能还需要开通某些端口号。例如,对于CNI网络插件calico,需要开通 179 端口号;对于镜像库,需要开通镜像库的端口号等,这需要根据系统的要求在防火墙服务上逐个配置网络策略。
在安全的网络环境下,可以关闭防火墙服务:
# systemctl disable firewalld
# systemctl stop firewalld
另外,建议在主机上禁用 SELinux(可以修改操作系统的/etc/sysconfig/selinux文件将SELINUX =enforcing
修改为SELINUX=disabled
),这样容器就可以读取主机的文件系统了。随着Kubernetes对SELinux支持的增强,可以逐步启用SELinux,并通过Kubernetes 设置容器的安全机制。
二、准备工作
2.1 主机列表
1.2.1 虚拟机安装及主机设置
- 主机名与hosts本地解析
## 查看系统版本及内核版本
[root@k8s31 ~]# cat /etc/redhat-release
CentOS Linux release 8.5.2111
[root@k8s31 ~]# uname -r
4.18.0-348.7.1.el8_5.x86_64
Hostname | Host IP | Docker IP | Role |
---|---|---|---|
k8s31.vm.com | 192.168.26.31 | 10.26.31.1/24 | master&worker、etcd、docker |
k8s32.vm.com | 192.168.26.32 | 10.26.32.1/24 | master&worker、etcd、docker |
k8s33.vm.com | 192.168.26.33 | 10.26.33.1/24 | master&worker、etcd、docker |
~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.26.31 k8s31.vm.com k8s31
192.168.26.32 k8s32.vm.com k8s32
192.168.26.33 k8s33.vm.com k8s33
- 关闭防火墙【基础安装】
~]# systemctl disable --now firewalldRemoved symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.~]# firewall-cmd --statenot running
- 关闭SELINUX【基础安装】
~]# sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config~]# reboot~]# sestatusSELinux status: disabled
修改SELinux配置需要重启操作系统。
- 关闭交换分区【基础安装】
~]# sed -ri 's/.*swap.*/#&/' /etc/fstab~]# swapoff -a && sysctl -w vm.swappiness=0~]# cat /etc/fstab...#UUID=3452c4c0-d890-4d66-bf19-3b09b0ba2afa none swap defaults 0 0...~]# free -mtotal used free shared buff/cache available
Mem: 3709 270 3072 16 366 3207
Swap: 0 0 0
- 配置ulimit
~]# ulimit -SHn 65535~]# cat << EOF >> /etc/security/limits.conf
* soft nofile 655360
* hard nofile 131072
* soft nproc 655350
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
EOF
1.2.2 ipvs管理工具安装及模块加载【基础安装】
~]# yum install ipvsadm ipset sysstat conntrack libseccomp -y...
~]# cat >> /etc/modules-load.d/ipvs.conf <<EOF
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF~]# systemctl restart systemd-modules-load.service~]# lsmod | grep -e ip_vs -e nf_conntrack
ip_vs_sh 16384 0
ip_vs_wrr 16384 0
ip_vs_rr 16384 0
ip_vs 172032 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack 172032 4 xt_conntrack,nf_nat,ipt_MASQUERADE,ip_vs
nf_defrag_ipv6 20480 2 nf_conntrack,ip_vs
nf_defrag_ipv4 16384 1 nf_conntrack
libcrc32c 16384 5 nf_conntrack,nf_nat,nf_tables,xfs,ip_vs
1.2.3 加载containerd相关内核模块【基础安装】
临时加载模块~]# modprobe overlay~]# modprobe br_netfilter永久性加载模块~]# cat > /etc/modules-load.d/containerd.conf << EOF
overlay
br_netfilter
EOF设置为开机启动~]# systemctl restart systemd-modules-load.service ##systemctl enable --now systemd-modules-load.service
1.2.4 开启内核路由转发及网桥过滤【基础安装】
~]# cat <<EOF > /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.netfilter.nf_conntrack_max=2310720net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.ip_conntrack_max = 131072
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 0
net.core.somaxconn = 16384
EOF
~]# sysctl --system
## 所有节点配置完内核后,重启服务器,保证重启后内核依旧加载
~]# reboot -h now## 重启后查看ipvs模块加载情况:
~]# lsmod | grep --color=auto -e ip_vs -e nf_conntrack
ip_vs_sh 16384 0
ip_vs_wrr 16384 0
ip_vs_rr 16384 0
ip_vs 172032 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack 172032 4 xt_conntrack,nf_nat,ipt_MASQUERADE,ip_vs
nf_defrag_ipv6 20480 2 nf_conntrack,ip_vs
nf_defrag_ipv4 16384 1 nf_conntrack
libcrc32c 16384 5 nf_conntrack,nf_nat,nf_tables,xfs,ip_vs## 重启后查看containerd相关模块加载情况:
~]# lsmod | egrep 'br_netfilter | overlay'
br_netfilter 24576 0
1.2.5 主机时间同步
略
1.2.6 创建软件部署目录
- /opt/app 存放部署资源文件
- /opt/cfg 存放配置文件
- /opt/cert 存放证书
- /opt/bin 链接/opt/app下的源文件,去除文件名中的版本号,方便升级时只需要更改链接即可。
~]# mkdir -p /opt/{app,cfg,cert,bin}
- 将下载的软件及资源上传到主机k8s31(192.168.26.31):/opt/app
2.2 软件列表
2.2.1 二进制软件
Linux ISO镜像:CentOS-8.3.2011-x86_64-minimal.iso (https://vault.centos.org/8.3.2011/isos/x86_64/CentOS-8.3.2011-x86_64-minimal.iso)
华为开源镜像:https://mirrors.huaweicloud.com/home
清华开源镜像:https://mirrors.tuna.tsinghua.edu.cn/
阿里开源镜像:https://mirrors.aliyun.com
下载:https://mirrors.aliyun.com/centos-vault/8.3.2011/isos/x86_64/CentOS-8.3.2011-x86_64-minimal.iso
docker 28.3.1 (2025-07-02 23:03:23 78.1 MiB)
https://download.docker.com/linux/static/stable/x86_64/
下载:https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-28.3.1.tgz
cri-dockerd 0.3.18
https://github.com/Mirantis/cri-dockerd
下载:https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.18/cri-dockerd-0.3.18.amd64.tgz
kubernetes v1.33.2
https://github.com/kubernetes/kubernetes/releases
下载:https://dl.k8s.io/v1.33.2/kubernetes-server-linux-amd64.tar.gz
etcd v3.6.0
https://github.com/etcd-io/etcd/
下载:https://github.com/etcd-io/etcd/releases/download/v3.6.0/etcd-v3.6.0-linux-amd64.tar.gz
2.2.2 资源清单与镜像
类型 | 名称 | 下载链接 | 说明 |
---|---|---|---|
yaml资源 | coredns.yaml.base | https://github.com/kubernetes/kubernetes/blob/v1.33.2/cluster/addons/dns/coredns/coredns.yaml.base | kubectl部署 |
yaml资源 | components.yaml(metrics server) | https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml | kubectl部署 |
镜像 | metrics-server:v0.7.2 | registry.aliyuncs.com/google_containers/metrics-server:v0.7.2 | 部署pod… |
镜像 | coredns:v1.12.0 | registry.aliyuncs.com/google_containers/coredns:v1.12.0 | 部署pod… |
镜像 | pause:3.10 | registry.aliyuncs.com/google_containers/pause:3.10 | 部署pod… |
2.3 网络规划
网络名称 | 网段 | 备注 |
---|---|---|
Node网络 | 192.168.26.0/24 | Node IP,Node节点的IP地址,即物理机(宿主机)的网卡地址。 |
Service网络 | 168.26.0.0/16 | Cluster IP,也可叫Service IP,Service的IP地址。service-cluster-ip-range定义Service IP地址范围的参数。 |
Pod网络 | 10.26.0.0/16 | Pod IP,Pod的IP地址,容器(docker0)网桥分配的地址。cluster-cidr定义Pod网络CIDR地址范围的参数。 |
配置:
apiserver:--service-cluster-ip-range 168.26.0.0/16 ##Service网络 168.26.0.0/16controller:--cluster-cidr 10.26.0.0/16 ##Pod网络 10.26.0.0/16--service-cluster-ip-range 168.26.0.0/16 ##service网络 168.26.0.0/16kubelet:--cluster-dns 168.26.0.100 ## 解析Service,168.26.0.100proxy:--cluster-cidr 10.26.0.0/16 ##Pod网络 10.26.0.0/16
2.4 集群总体架构
三、容器运行时
3.1 安装docker
3.1.1 解压、分发、创建软连接
## k8s31:
~]# cd /opt/app/
app]# tar zxvf docker-28.3.1.tgz
app]# ls docker
containerd containerd-shim-runc-v2 ctr docker dockerd docker-init docker-proxy runc
app]# mv docker /opt/bin/docker-28.3.1
app]# ls /opt/bin/docker-28.3.1
containerd containerd-shim-runc-v2 ctr docker dockerd docker-init docker-proxy runc
## 复制到k8s32、k8s33
app]# scp -r /opt/bin/docker-28.3.1/ root@k8s32:/opt/bin/.
app]# scp -r /opt/bin/docker-28.3.1/ root@k8s33:/opt/bin/.
## 在k8s31、k8s32、k8s33创建软连接:
ln -s /opt/bin/docker-28.3.1/containerd /usr/bin/containerd
ln -s /opt/bin/docker-28.3.1/containerd-shim-runc-v2 /usr/bin/containerd-shim-runc-v2
ln -s /opt/bin/docker-28.3.1/ctr /usr/bin/ctr
ln -s /opt/bin/docker-28.3.1/docker /usr/bin/docker
ln -s /opt/bin/docker-28.3.1/dockerd /usr/bin/dockerd
ln -s /opt/bin/docker-28.3.1/docker-init /usr/bin/docker-init
ln -s /opt/bin/docker-28.3.1/docker-proxy /usr/bin/docker-proxy
ln -s /opt/bin/docker-28.3.1/runc /usr/bin/runc
## 如果软连接存在,则删除
rm -rf /usr/bin/containerd
rm -rf /usr/bin/containerd-shim-runc-v2
rm -rf /usr/bin/ctr
rm -rf /usr/bin/docker
rm -rf /usr/bin/dockerd
rm -rf /usr/bin/docker-init
rm -rf /usr/bin/docker-proxy
rm -rf /usr/bin/runc
~]# docker -v
Docker version 27.5.1, build 9f9e405
3.1.2 创建目录、配置文件
- 在3台主机上:使用calico网络,去掉bip配置
## k8s31:
~]# mkdir -p /data/docker /etc/docker
~]# cat /etc/docker/daemon.json
{"data-root": "/data/docker","storage-driver": "overlay2","insecure-registries": ["harbor.oss.com:32402"],"registry-mirrors": ["https://5gce61mx.mirror.aliyuncs.com"],// "bip": "10.26.31.1/24","exec-opts": ["native.cgroupdriver=systemd"],"live-restore": true
}## k8s32:
~]# mkdir -p /data/docker /etc/docker
~]# cat /etc/docker/daemon.json
{"data-root": "/data/docker","storage-driver": "overlay2","insecure-registries": ["harbor.oss.com:32402"],"registry-mirrors": ["https://5gce61mx.mirror.aliyuncs.com"],// "bip": "10.26.32.1/24","exec-opts": ["native.cgroupdriver=systemd"],"live-restore": true
}## k8s33:
~]# mkdir -p /data/docker /etc/docker
~]# cat /etc/docker/daemon.json
{"data-root": "/data/docker","storage-driver": "overlay2","insecure-registries": ["harbor.oss.com:32402"],"registry-mirrors": ["https://5gce61mx.mirror.aliyuncs.com"],// "bip": "10.26.33.1/24","exec-opts": ["native.cgroupdriver=systemd"],"live-restore": true
}
3.1.3 创建启动文件
]# cat /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
3.1.4 启动、检查
~]# systemctl daemon-reload
~]# systemctl start docker; systemctl enable docker
~]# systemctl status docker
Client:Version: 28.3.1Context: defaultDebug Mode: falseServer:Containers: 2Running: 0Paused: 0Stopped: 2Images: 6Server Version: 28.3.1Storage Driver: overlay2Backing Filesystem: xfsSupports d_type: trueUsing metacopy: falseNative Overlay Diff: trueuserxattr: falseLogging Driver: json-fileCgroup Driver: systemdCgroup Version: 1Plugins:Volume: localNetwork: bridge host ipvlan macvlan null overlayLog: awslogs fluentd gcplogs gelf journald json-file local splunk syslogCDI spec directories:/etc/cdi/var/run/cdiSwarm: inactiveRuntimes: io.containerd.runc.v2 runcDefault Runtime: runcInit Binary: docker-initcontainerd version: 05044ec0a9a75232cad458027ca83437aae3f4darunc version: v1.2.6-0-ge89a299init version: de40ad0Security Options:seccompProfile: builtinKernel Version: 4.18.0-348.7.1.el8_5.x86_64Operating System: CentOS Linux 8OSType: linuxArchitecture: x86_64CPUs: 2Total Memory: 3.623GiBName: k8s31.vm.comID: 9006d33f-8784-4665-8414-5b936192182aDocker Root Dir: /data/dockerDebug Mode: falseExperimental: falseInsecure Registries:harbor.oss.com:32402::1/128127.0.0.0/8Registry Mirrors:https://5gce61mx.mirror.aliyuncs.com/Live Restore Enabled: trueProduct License: Community Engine
app]# docker version
Client:Version: 28.3.1API version: 1.51Go version: go1.24.4Git commit: 38b7060Built: Wed Jul 2 20:55:19 2025OS/Arch: linux/amd64Context: defaultServer: Docker Engine - CommunityEngine:Version: 28.3.1API version: 1.51 (minimum version 1.24)Go version: go1.24.4Git commit: 5beb93dBuilt: Wed Jul 2 20:56:35 2025OS/Arch: linux/amd64Experimental: falsecontainerd:Version: v1.7.27GitCommit: 05044ec0a9a75232cad458027ca83437aae3f4darunc:Version: 1.2.6GitCommit: v1.2.6-0-ge89a299docker-init:Version: 0.19.0GitCommit: de40ad0
app]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000link/ether 00:0c:29:4e:b1:79 brd ff:ff:ff:ff:ff:ffinet 192.168.26.31/24 brd 192.168.26.255 scope global noprefixroute ens160valid_lft forever preferred_lft foreverinet6 fe80::20c:29ff:fe4e:b179/64 scope linkvalid_lft forever preferred_lft forever
3: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000link/ipip 0.0.0.0 brd 0.0.0.0
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group defaultlink/ether 02:42:44:b4:a6:2a brd ff:ff:ff:ff:ff:ffinet 10.26.31.1/24 brd 10.26.31.255 scope global docker0valid_lft forever preferred_lft forever
3.1.5 测试
拉取centos镜像,启动容器,查看容器IP
~]# docker pull centos:8
...
~]# docker images
...
~]# docker run -i -t --name node31 centos:8 /bin/bash
[root@8f14e1f187d8 /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000link/ipip 0.0.0.0 brd 0.0.0.0
3: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 22:fb:86:5a:54:8e brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 10.26.31.2/24 brd 10.26.31.255 scope global eth0valid_lft forever preferred_lft forever
[root@8f14e1f187d8 /]# exit
3.2 安装cri-dockerd
为什么要安装cri-dockerd插件?
-
K8s在刚开源时没有自己的容器引擎,而当时docker非常火爆是容器的代表,所以就在kubelet的代码里集成了对接docker的代码(docker shim),所以1.24版本之前是默认使用docker,不需要安装cri-dockerd。
-
K8s1.24版本移除 docker-shim的代码,而Docker Engine默认又不支持CRI标准,因此二者默认无法再直接集成。为此,Mirantis和Docker为了Docker Engine提供一个能够支持到CRI规范的桥梁,就联合创建了cri-dockerd,从而能够让Docker作为K8s容器引擎。
-
截至2025年6月,k8s已经更新至v1.32.5版。从v1.24起,Docker不能直接作为k8s的容器运行时,因为在k8s v1.24版本移除了docker shim的组件,这是由k8s团队直接维护而非Docker团队维护的组件,这意味着Docker和k8s的关系不再像原来那般亲密,开发者需要使用其它符合CRI(容器运行时接口)的容器运行时工具(如containerd、CRI-O等),当然这并不意味着新版本的k8s彻底抛弃Docker(由于Docker庞大的生态和广泛的群众基础,显然这并不容易办到),在原本安装了Docker的基础上,可以通过补充安装cri-dockerd,以满足容器运行时接口的条件,从某种程度上说,cri-dockerd就是翻版的dockershim。
3.2.1 解压、分发、创建软链接
k8s31 app]# tar -zxvf cri-dockerd-0.3.18.amd64.tgz
k8s31 app]# mv cri-dockerd /opt/bin/cri-dockerd-0.3.18
k8s31 app]# ll /opt/bin/cri-dockerd-0.3.18
总用量 49740
-rwxr-xr-x 1 1001 118 50929816 6月 10 05:48 cri-dockerd
## 复制:
k8s31 app]# scp -r /opt/bin/cri-dockerd-0.3.18 root@k8s32:/opt/bin/.
k8s31 app]# scp -r /opt/bin/cri-dockerd-0.3.18 root@k8s33:/opt/bin/.
## 创建软链接:同上
ln -s /opt/bin/cri-dockerd-0.3.18/cri-dockerd /usr/local/bin/cri-dockerd
~]# cri-dockerd --version
cri-dockerd 0.3.18 (5709af9)
3.2.2 修改配置文件、启动
]# cat /usr/lib/systemd/system/cri-dockerd.service
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
# Requires=cri-docker.socket ## 如果启动报错,则注释掉这一行[Service]
Type=notify
ExecStart=/usr/local/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.10
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity
Delegate=yes
KillMode=process[Install]
WantedBy=multi-user.target
]# systemctl daemon-reload
]# systemctl enable cri-dockerd && systemctl start cri-dockerd]# systemctl status cri-dockerd
● cri-dockerd.service - CRI Interface for Docker Application Container EngineLoaded: loaded (/usr/lib/systemd/system/cri-dockerd.service; enabled; vendor preset: disabled)Active: active (running) since Tue 2025-07-08 02:03:30 EDT; 15s agoDocs: https://docs.mirantis.comMain PID: 2370 (cri-dockerd)Tasks: 7Memory: 9.3MCGroup: /system.slice/cri-dockerd.service└─2370 /usr/local/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3>...
四、通过二进制文件安装Kubernetes集群
通过 kubeadm 可以快速安装 Kubernetes 集群,但如果需要调整 Kubernetes 各组件服务的参数,以及安全设置、高可用模式等,就需要通过二进制文件安装 Kubemmetes 集群了。
基于 Kubernetes v1.33.2 版本,通过二进制文件对如何配置、部署启用安全机制且有3个节点的高可用Kubernetes集群。可以适当简化测试环境,将某些组件部署为单节点模式。
4.1 Master的高可用部署架构
在Kubermetes系统中,Master通过不间断地与各个Node通信来维护整个集群的健康工作状态,集群中各资源对象的状态则被保存在etcd中。如果Master不能正常工作,则各个Node会处于不可管理状态,用户无法管理在各个Node上运行的Pod。
所以,在正式环境下应确保 Master 高可用,并启用安全访问机制,其中要至少注意以下几方面:
-
Master的 kube-apiserver、kube-controller-manager和kube-scheduler服务以多实例方式部署,至少有3个节点,节点需要为奇数数量,通常建议为5个或7个。
-
Master启用了基于CA认证的HTTPS安全机制。
-
etcd至少以有3个节点的集群模式部署。
-
etcd集群启用了基于CA认证的HTTPS安全机制。
-
Master启用了RBAC授权模式。
在 Master 的3个节点之前,应通过一个负载均衡器提供对客户端的唯一访问人口地址。对于负载均衡器,可以选择使用硬件负载均衡器或者软件负载均衡器进行搭建。如果选择使用软件负载均衡器,则可选择的开源方案较多,本方案以HAProxy搭配keepalived为例进行说明。主流硬件负载均衡器有 F5、A10等,需要额外采购,其负载均衡配置规则与软件负载均衡器的配置规则类似,不再赘述。
本方案中3台主机的IP地址分别为192.168.26.31、192.168.26.32、192.168.26.33,负载均衡器使用的虚拟IP(VirtualIP,VIP)地址为 192.168.26.100。
下面对 etcd、负载均衡器、Master、Node 等组件进行高可用部署、关键配置、CA 证书配置等。
4.2 创建CA根证书
为了启用etcd和Kubernetes服务基于CA认证的安全机制,首先需要配置CA证书。如果可以通过某个可信任的CA中心获取证书,则可以使用其颁发的CA证书来完成系统配置。如果没有可信任的 CA中心,则也可以通过自行制作CA证书来完成系统配置。
etcd和Kubernetes在制作CA证书时,均需要基于CA根证书。以Kubermetes和etcd使用同一套CA根证书为例,对如何制作CA证书进行说明。可以使用OpenSSL、easyrsa、CFSSL等工具来制作CA证书,以 OpenSSL为例进行说明。
创建 CA 根证书的命令如下,其中包括私钥文件 ca.key 和证书文件 ca.crt:
cert]# openssl genrsa -out ca.key 2048cert]# openssl req -x509 -new -nodes -key ca.key -subj "/CN=192.168.26.31" -days 36500 -out ca.crt
主要参数如下:
-
-subi:“/CN”的值为CA机构名称,格式可以是域名或者 IP 地址。
-
-days:设置证书的有效期。
将生成的 ca.key 和 ca.crt文件保存在/opt/cert/pki 目录下。
4.3 部署安全的 etcd 高可用集群
1. 下载 etcd 二进制文件,解压,链接,配置 systemd 服务
将 etcd 二进制文件解压缩后可以得到 etcd 和 etcdctl 文件,首先将它们链接到/usr/bin目录下:
## k8s31:
~]# cd /opt/app/
app]# tar zxvf etcd-v3.6.0-linux-amd64.tar.gz
app]# ls etcd-v3.6.0-linux-amd64
Documentation etcd etcdctl etcdutl README-etcdctl.md README-etcdutl.md README.md READMEv2-etcdctl.md
app]# mv etcd-v3.6.0-linux-amd64 /opt/bin/etcd-v3.6.0
app]# ls /opt/bin/etcd-v3.6.0
Documentation etcd etcdctl etcdutl README-etcdctl.md README-etcdutl.md README.md READMEv2-etcdctl.md
## 复制:
k8s31 app]# scp -r /opt/bin/etcd-v3.6.0 root@k8s32:/opt/bin/.
k8s31 app]# scp -r /opt/bin/etcd-v3.6.0 root@k8s33:/opt/bin/.
## 创建软链接:同上
ln -s /opt/bin/etcd-v3.6.0/etcd /usr/bin/etcd
ln -s /opt/bin/etcd-v3.6.0/etcdctl /usr/bin/etcdctl
app]# etcd --version
etcd Version: 3.6.0
Git SHA: f5d605a
Go Version: go1.23.9
Go OS/Arch: linux/amd64
然后将其部署为一个 systemd 服务,创建 systemd 服务的配置文件/usr/ib/systemdsystemVetcd.service:
## /usr/lib/systemd/system/etcd.service
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target[Service]
EnvironmentFile=/opt/cfg/etcd.conf
ExecStart=/usr/bin/etcd
Restart=always[Install]
WantedBy=multi-user.target
其中,EnvironmentFile指定配置文件的全路径,例如/opt/cfg/etcd.conf,以环境变量的格式配置其中的参数。
接下来配置 etcd需要的 CA 证书。对于配置文件/opt/cfg/etcd.conf中的完整配置参数将在创建完 CA 证书后统一配置。
2. 创建 etcd 的 CA 证书
首先创建一个x509 v3配置文件etcd_ssl.cnf,其中的subjectAltName参数(alt_names)包括所有etcd主机的 IP地址。
# /opt/cert/etcd_ssl.cnf
[ req ]
req_extensions = v3_req
distinguished_name = req_distinguished_name[ req_distinguished_name ][ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names[ alt_names ]
IP.1 = 192.168.26.31
IP.2 = 192.168.26.32
IP.3 = 192.168.26.33
然后通过openssl命令创建etcd的服务端CA证书,包括 etcd server.key 和etcd server.crt 文件,将其保存到/opt/cert目录下:
openssl genrsa -out etcd_server.key 2048openssl req -new -key etcd_server.key -config etcd_ssl.cnf -subj "/CN=etcd-server" -out etcd_server.csropenssl x509 -req -in etcd_server.csr -CA /opt/cert/ca.crt -CAkey /opt/cert/ca.key -CAcreateserial -days 36500 -extensions v3_req -extfile etcd_ssl.cnf -out etcd_server.crt
最后创建客户端使用的CA证书,包括etcd_client.key和 etcd_client.crt文件,也将其保存到/opt/cert目录下,后续供 kube-apiserver 连接 etcd 时使用:
openssl genrsa -out etcd_client.key 2048openssl req -new -key etcd_client.key -config etcd_ssl.cnf -subj "/CN=etcd-client" -out etcd_client.csropenssl x509 -req -in etcd_client.csr -CA /opt/cert/ca.crt -CAkey /opt/cert/ca.key -CAcreateserial -days 36500 -extensions v3_req -extfile etcd_ssl.cnf -out etcd_client.crt
cert]# ls -l
总用量 40
-rw-r--r-- 1 root root 1127 6月 1 06:08 ca.crt
-rw------- 1 root root 1675 6月 1 06:07 ca.key
-rw-r--r-- 1 root root 41 6月 1 06:33 ca.srl
-rw-r--r-- 1 root root 1086 6月 1 06:33 etcd_client.crt
-rw-r--r-- 1 root root 989 6月 1 06:32 etcd_client.csr
-rw------- 1 root root 1675 6月 1 06:32 etcd_client.key
-rw-r--r-- 1 root root 1086 6月 1 06:31 etcd_server.crt
-rw-r--r-- 1 root root 989 6月 1 06:28 etcd_server.csr
-rw------- 1 root root 1679 6月 1 06:27 etcd_server.key
-rw-r--r-- 1 root root 311 6月 1 06:26 etcd_ssl.cnf
## 复制:
k8s31 app]# scp -r /opt/cert/* root@k8s32:/opt/cert/.
k8s31 app]# scp -r /opt/cert/* root@k8s33:/opt/cert/.
3. 对 etcd 参数的配置说明
接下来配置3个etcd节点。etcd节点的配置方式包括启动参数、环境变量、配置文件等,通过环境变量方式将其配置到/opt/cfg/etcd.conf文件中,供systemd服务读取。
3个etcd节点将被部署在192.168.26.31、192.168.26.32和192.168.26.33这3台主机上,配置文件/opt/cfg/etcd.conf的内容:
]# mkdir -p /opt/etcd/data
## /opt/cfg/etcd.conf - node 1
ETCD_NAME=etcd1
ETCD_DATA_DIR=/opt/etcd/dataETCD_CERT_FILE=/opt/cert/etcd_server.crt
ETCD_KEY_FILE=/opt/cert/etcd_server.key
ETCD_TRUSTED_CA_FILE=/opt/cert/ca.crt
ETCD_CLIENT_CERT_AUTH=true
ETCD_LISTEN_CLIENT_URLS=https://192.168.26.31:2379
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.26.31:2379ETCD_PEER_CERT_FILE=/opt/cert/etcd_server.crt
ETCD_PEER_KEY_FILE=/opt/cert/etcd_server.key
ETCD_PEER_TRUSTED_CA_FILE=/opt/cert/ca.crt
ETCD_LISTEN_PEER_URLS=https://192.168.26.31:2380
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.26.31:2380ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
ETCD_INITIAL_CLUSTER="etcd1=https://192.168.26.31:2380,etcd2=https://192.168.26.32:2380,etcd3=https://192.168.26.33:2380"
ETCD_INITIAL_CLUSTER_STATE=new
## /opt/cfg/etcd.conf - node 2
ETCD_NAME=etcd2
ETCD_DATA_DIR=/opt/etcd/dataETCD_CERT_FILE=/opt/cert/etcd_server.crt
ETCD_KEY_FILE=/opt/cert/etcd_server.key
ETCD_TRUSTED_CA_FILE=/opt/cert/ca.crt
ETCD_CLIENT_CERT_AUTH=true
ETCD_LISTEN_CLIENT_URLS=https://192.168.26.32:2379
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.26.32:2379ETCD_PEER_CERT_FILE=/opt/cert/etcd_server.crt
ETCD_PEER_KEY_FILE=/opt/cert/etcd_server.key
ETCD_PEER_TRUSTED_CA_FILE=/opt/cert/ca.crt
ETCD_LISTEN_PEER_URLS=https://192.168.26.32:2380
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.26.32:2380ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
ETCD_INITIAL_CLUSTER="etcd1=https://192.168.26.31:2380,etcd2=https://192.168.26.32:2380,etcd3=https://192.168.26.33:2380"
ETCD_INITIAL_CLUSTER_STATE=new
## /opt/cfg/etcd.conf - node 3
ETCD_NAME=etcd3
ETCD_DATA_DIR=/opt/etcd/dataETCD_CERT_FILE=/opt/cert/etcd_server.crt
ETCD_KEY_FILE=/opt/cert/etcd_server.key
ETCD_TRUSTED_CA_FILE=/opt/cert/ca.crt
ETCD_CLIENT_CERT_AUTH=true
ETCD_LISTEN_CLIENT_URLS=https://192.168.26.33:2379
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.26.33:2379ETCD_PEER_CERT_FILE=/opt/cert/etcd_server.crt
ETCD_PEER_KEY_FILE=/opt/cert/etcd_server.key
ETCD_PEER_TRUSTED_CA_FILE=/opt/cert/ca.crt
ETCD_LISTEN_PEER_URLS=https://192.168.26.33:2380
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.26.33:2380ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
ETCD_INITIAL_CLUSTER="etcd1=https://192.168.26.31:2380,etcd2=https://192.168.26.32:2380,etcd3=https://192.168.26.33:2380"
ETCD_INITIAL_CLUSTER_STATE=new
主要配置参数包括为客户端和集群其他节点配置的各监听URL地址(均为HTTPS URL地址 ),并配置相应的 CA 证书参数。etcd 服务的相关配置参数如下:
- ETCD_NAME:etcd节点名称,每个节点都应不同,例如etcd1、etcd2、etcd3。
- ETCD_DATA_DIR:etcd的数据存储目录,例如/opt/etcd/data。
- ETCD_LISTEN_CLIENT_URLS和ETCD_ADVERTISE_CLIENT_URLS:为客户端提供的服务监听URL地址,例如 https://192.168.26.31:2379。
- ETCD_LISTEN_PEER_URLS和ETCD_INITIAL_ADVERTISE_PEER_URLS:为本集群其他节点提供的服务监听UR地址,例如 https://192.168.26.31:2380。
- ETCD_INITIAL_CLUSTER_TOKEN:集群名称,例如etcd-cluster。
- ETCD_INITIAL_CLUSTER:集群各节点的 endpoint列表,例如 etcd1=https://192168.26.31:2380,etcd2=https://192.168.26.32:2380,etcd3=https://192.168.26.33:2380.
- ETCD_INITIAL_CLUSTER_STATE:初始集群状态,在新建集群时将其设置为“new”,在集群已存在时将其设置为“existing”。
CA 证书的相关配置参数如下:
- ETCD_CERT_FILE:etcd 服务端 CA证书-crt 文件的全路径,例如/opt/cert/etcd_server.crt.
- ETCD_KEY_FILE:etcd 服务端 CA证书-key 文件的全路径,例如/opt/cert/etcd_server.key.
- ETCD_TRUSTED_CA_FILE:CA根证书文件的全路径,例如/opt/cert/ca.crt.
- ETCD_CLIENT_CERT_AUTH:是否启用客户端证书认证。
- ETCD_PEER_CERT_FILE:集群各节点相互认证使用的CA证书-crt文件的全路径例如/opt/cert/etcd_server.crt.
- ETCD_PEER_KEY_FILE:集群各节点相互认证使用的CA证书-key文件的全路径例如/opt/cert/etcd_server.key。
- ETCD_PEER_TRUSTED_CA_FILE:CA 根证书文件的全路径,例如/opt/cert/ca.crt。
4. 启动 etcd 集群
基于 systemd的配置,在3台主机上首先分别启动 etcd 服务,并设置为开机自启动:
## 启动etcd服务,并设置为开机自启动
]# systemctl restart etcd && systemctl enable etcd
]# systemctl status etcd
然后用 etcdctl客户端命令行工具携带客户端 CA证书,通过 etcdctl endpoint health 命令访问 etcd 集群,验证集群状态是否正常。
## 通过etcdctl endpoint health命令访问etcd集群,验证集群状态是否正常
]# etcdctl --cacert=/opt/cert/ca.crt --cert=/opt/cert/etcd_client.crt --key=/opt/cert/etcd_client.key --endpoints=https://192.168.26.31:2379,https://192.168.26.32:2379,https://192.168.26.33:2379 endpoint health
https://192.168.26.33:2379 is healthy: successfully committed proposal: took = 7.782435ms
https://192.168.26.31:2379 is healthy: successfully committed proposal: took = 7.786204ms
https://192.168.26.32:2379 is healthy: successfully committed proposal: took = 11.706174ms
结果显示各节点状态均为“healthy”,说明集群正常运行。至此,一个启用了 HTTPS的有3个节点的 etcd集群就部署成功。
4.4 部署安全的 Kubernetes Master 高可用集群
1. 下载 Kubernetes 服务的二进制文件
https://github.com/kubernetes/kubernetes
首先,从Kubernetes 的官方 GitHub 代码库页面下载各组件的二进制文件,在 Releases页面找到需要下载的版本号,单击CHANGELOG链接,跳转到已编译好的Server端二进制(Server Binaries)文件的下载页面下载该文件。
在Server Binaries 压缩包中包含Kubernetes的所有服务端程序的二进制文件和容器镜像文件,并根据不同的系统架构分别提供二进制文件,例如amd64表示x86架构,arm64表示arm架构,等等,根据目标环境的要求选择正确的文件进行下载。
在Kubernetes的Master上需要部署的服务包括etcd、kube-apiserver、kube-controller-manager和kube-scheduler。
在Node上需要部署的服务包括容器运行时(如containerd)、kubelet 和 kube-proxy。
将Kubernetes的二进制可执行文件链接或复制到/usr/bin目录下,然后在/usr/lib/systemd/system目录下为各服务创建systemd服务的配置文件,完成Kubernetes服务的安装。
## k8s31:
~]# cd /opt/app/
app]# tar zxvf kubernetes-server-linux-amd64.tar.gz
...
app]# rm -rf kubernetes/server//bin/*_tag
app]# rm -rf kubernetes/server//bin/*.tar
app]# rm -rf kubernetes/server//bin/{apiextensions-apiserver,kubectl-convert,kube-log-runner,mounter,kube-aggregator}
app]# ll kubernetes/server//bin/
总用量 532572
-rwxr-xr-x 1 root root 74543288 6月 17 14:57 kubeadm
-rwxr-xr-x 1 root root 97968312 6月 17 14:57 kube-apiserver
-rwxr-xr-x 1 root root 90767544 6月 17 14:57 kube-controller-manager
-rwxr-xr-x 1 root root 60129464 6月 17 14:57 kubectl
-rwxr-xr-x 1 root root 81703204 6月 17 14:57 kubelet
app]# mkdir /opt/bin/kubernetes-1.33.2
app]# mv kubernetes/server/bin /opt/bin/kubernetes-1.33.2
app]# rm -rf kubernetes
## 复制:
k8s31 app]# scp -r /opt/bin/kubernetes-1.33.2 root@k8s32:/opt/bin/.
k8s31 app]# scp -r /opt/bin/kubernetes-1.33.2 root@k8s33:/opt/bin/.
## 创建软链接:同上
ln -s /opt/bin/kubernetes-1.33.2/kube-apiserver /usr/bin/kube-apiserver
ln -s /opt/bin/kubernetes-1.33.2/kube-controller-manager /usr/bin/kube-controller-manager
ln -s /opt/bin/kubernetes-1.33.2/kubectl /usr/bin/kubectl
ln -s /opt/bin/kubernetes-1.33.2/kubelet /usr/bin/kubelet
ln -s /opt/bin/kubernetes-1.33.2/kube-proxy /usr/bin/kube-proxy
ln -s /opt/bin/kubernetes-1.33.2/kube-scheduler /usr/bin/kube-scheduler
app]# kubectl version
Client Version: v1.33.2
Kustomize Version: v5.6.0
The connection to the server localhost:8080 was refused - did you specify the right host or port?
2. 部署 kube-apiserver服务
(1) 设置kube-apiserver 服务需要的 CA 相关证书。首先准备一个 x509 v3 版本的证书配置文件(master_ssl.cnf):
# CA证书配置
# vi /opt/cert/master_ssl.cnf
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name][ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
DNS.5 = k8s-1
DNS.6 = k8s-2
DNS.7 = k8s-3
IP.1 = 168.26.0.1
IP.2 = 192.168.26.31
IP.3 = 192.168.26.32
IP.4 = 192.168.26.33
IP.5 = 192.168.26.100
在该文件的subjectAltName字段([alt names])设置Master服务的全部域名和 IP 地址。
- DNS主机名,例如k8s-1、k8s-2、k8s-3等。
- Master Service的虚拟服务名称,例如 kubernetes.default等。
- IP 地址,包括各 kube-apiserver所在主机的 IP 地址和负载均衡器的 IP地址,例如192.168.26.31、192.168.26.32、192.168.26.33和192.168.26.100。
- Master Service虚拟服务的 ClusterIP 地址,例如 168.26.0.1。
然后通过 openssl 命令创建 kube-apiserver 的服务端 CA 证书,包括 apiserver.key 和apiserver.crt 文件,将其保存到/opt/cert目录下:
# 创建服务端CA证书openssl genrsa -out apiserver.key 2048openssl req -new -key apiserver.key -config master_ssl.cnf -subj "/CN=apiserver" -out apiserver.csropenssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 36500 -extensions v3_req -extfile master_ssl.cnf -out apiserver.crt
## 复制
scp -r /opt/cert/apiserver* root@k8s32:/opt/cert/.
scp -r /opt/cert/apiserver* root@k8s33:/opt/cert/.
(2) 为kube-apiserver服务创建systemd服务的配置文件/usr/lib/systemd/system/kube-apiserver.service,在该文件中,EnvironmentFile参数指定将/opt/cfg/apiserver文件作为环境文件,其中通过变量KUBE_API_ARGS设置kube-apiserver的启动参数:
## Kubernetes各服务的配置
## vi /usr/lib/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes[Service]
EnvironmentFile=/opt/cfg/apiserver
ExecStart=/usr/bin/kube-apiserver $KUBE_API_ARGS
Restart=always[Install]
WantedBy=multi-user.target
(3) 在环境文件/opt/cfg/apiserver中,配置变量KUBE_API_ARGS 的值为kube-apiserver的全部启动参数:
## vi /opt/cfg/apiserver
KUBE_API_ARGS="--secure-port=6443 \
--tls-cert-file=/opt/cert/apiserver.crt \
--tls-private-key-file=/opt/cert/apiserver.key \
--kubelet-client-certificate=/opt/cert/apiserver.crt \
--kubelet-client-key=/opt/cert/apiserver.key \
--client-ca-file=/opt/cert/ca.crt \
--apiserver-count=3 --endpoint-reconciler-type=master-count \
--etcd-servers=https://192.168.26.31:2379,https://192.168.26.32:2379,https://192.168.26.33:2379 \
--etcd-cafile=/opt/cert/ca.crt \
--etcd-certfile=/opt/cert/etcd_client.crt \
--etcd-keyfile=/opt/cert/etcd_client.key \
--service-cluster-ip-range=168.26.0.0/16 \
--service-node-port-range=30000-32767 \
--service-account-issuer=https://kubernetes.default.svc.cluster.local \
--service-account-signing-key-file=/opt/cert/apiserver.key \
--service-account-key-file=/opt/cert/apiserver.key \
--allow-privileged=true"
- –secure-port:HTTPS端口号,默认值为6443。
- –tls-cert-fle:服务端CA证书文件的全路径,例如/opt/cert/apiserver.crt。
- –tls-private-key-fle:服务端CA私钥文件的全路径,例如/opt/cert/apiserver. key。
- –client-ca-file:CA根证书的全路径,例如/opt/cert/ca.crt。
- –apiserver-count:API Server 实例的数量,例如3,需要同时设置参数–endpoint-reconciler-type=master-count。
- –etcd-servers:连接 etcd 的 URL列表,这里使用 HTTPS,例如 https://192.168.26.31:2379、https://192.168.26.32:2379和https://192.168.26.33:2379。
- –etcd-cafile:etcd 使用的 CA根证书文件的全路径,例如/opt/cert/ca.crt。
- –etcd-certfile:etcd客户端CA证书文件的全路径,例如/opt/cert/etcd_client.crt。
- –etcd-keyfile:etcd 客户端私钥文件的全路径,例如/opt/cert/etcd_ client.key。
- –service-cluster-ip-range:Service虚拟IP地址的范围,以CIDR格式表示(168.26.0.0/16),在该范围内不可出现物理机的IP地址。
- –service-node-port-range:Service可使用的物理机端口号范围,默认值为 30000~32767。
- –allow-privileged:是否允许容器以特权模式运行,默认值为true。
(4) 在配置文件准备完毕后,在3台主机上分别启动 kube-apiserver 服务,并设置为开机自启动:
systemctl start kube-apiserver && systemctl enable kube-apiserver
systemctl status kube-apiserver
3. 创建客户端 CA 证书
kube-controller-manager、kube-scheduler、kubelet 和 kube-proxy 服务作为客户端连接kube-apiserver 服务,需要为它们创建客户端 CA证书,使其能够正确访问 kube-apiserver。对这几个服务统一创建一个证书。
通过 openssl 命令创建 CA 证书和私钥文件
## 创建客户端CA证书
openssl genrsa -out client.key 2048openssl req -new -key client.key -subj "/CN=admin" -out client.csropenssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 36500
其中,-subj 参数中“/CN”的名称可以被设置为“admin”,用于标识连接 kube-apiserver的客户端用户的名称。
将生成的 client.key和 client.crt文件保存在/opt/cert目录下。
## 复制
scp -r /opt/cert/client* root@k8s32:/opt/cert/.
scp -r /opt/cert/client* root@k8s33:/opt/cert/.
4. 创建客户端连接 kube-apiserver 服务所需的 kubeconfig 配置文件
为 kube-controller-manager、kube-scheduler、kubelet 和 kube-proxy 服务统一创建一个 kubeconfg 文件作为连接 kube-apiserver 服务的配置文件,后续也作为 kubectl 连接kube-apiserver 服务的配置文件。
在 kubeconfig文件中主要设置访问 kube-apiserver的URL地址及所需 CA 证书等相关参数:
## vi /opt/cfg/kubeconfig
apiVersion: v1
kind: Config
clusters:
- name: defaultcluster:server: https://192.168.26.100:9443certificate-authority: /opt/cert/ca.crt
users:
- name: adminuser:client-certificate: /opt/cert/client.crtclient-key: /opt/cert/client.key
contexts:
- context:cluster: defaultuser: adminname: default
current-context: default
- server URL地址:配置为负载均衡器(HAProxy)使用的虚拟IP地址(192.168.26.100)和HAProxy监听的端口号(9443)。
- client-certificate:配置为客户端证书文件(client.crt)的全路径。
- client-key:配置为客户端私钥文件(client.key)的全路径。
- certificate-authority:配置为CA根证书(ca.crt)的全路径。
- users中的user name和context中的user:连接API Server 的用户名,设置为与客户端证书中的“/CN”名称保持一致(“admin”)。
将 kubeconfig 文件保存到/opt/cfg目录下。
5. 部署 kube-controller-manager 服务
(1) 为 kube-controller-manager 服务创建 systemd 服务的配置文件/usr/lib/systemd/system/kube-controller-manager.service,其中 EnvironmentFile参数指定使用/etc/kubernetes/controller-manager 文件作为环境文件,在该环境文件中通过变量KUBE_CONTROLLER_MANAGER_ARGS 设置 kube-controller-manager的启动参数:
## vi /usr/lib/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes[Service]
EnvironmentFile=/opt/cfg/controller-manager
ExecStart=/usr/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_ARGS
Restart=always[Install]
WantedBy=multi-user.target
(2) 在环境文件/opt/cfg/controller-manager中,配置变量 KUBE_CONTROLLER_MANAGER_ARGS的值为 kube-controller-manager的全部启动参数:
## vi /opt/cfg/controller-manager
KUBE_CONTROLLER_MANAGER_ARGS="--kubeconfig=/opt/cfg/kubeconfig \
--leader-elect=true \
--service-cluster-ip-range=168.26.0.0/16 \
--service-account-private-key-file=/opt/cert/apiserver.key \
--root-ca-file=/opt/cert/ca.crt"
- –kubeconfig:与APIServer连接的相关配置。
- –leader-elect:启用选举机制,在有3个节点的环境下应被设置为“true“。
- –service-account-private-key-file:为ServiceAccount自动颁发token使用的私钥文件的全路径/opt/cert/apiserver.key。
- –root-ca-file:CA根证书的全路径/opt/cert/ca.crt。
- –service-cluster-ip-range:Service的虚拟IP地址范围,以CIDR格式表示(169.169.0.0/16),与kube-apiserver服务中的配置保持一致。
(3) 在配置文件准备完毕后,在3台主机上分别启动 kube-controller-manager 服务,并设置为开机自启动:
systemctl daemon-reload
systemctl start kube-controller-manager && systemctl enable kube-controller-manager
systemctl status kube-controller-manager
6. 部署 kube-scheduler 服务
(1)为kube-scheduler服务创建systemd服务的配置文件/usr/lib/systemd/system/kube-scheduler.service,其中 EnvironmentFile 参数指定使用/opt/cfg/scheduler文件作为环境文件,在该环境文件中通过变量KUBE_SCHEDULER_ARGS设置 kube-scheduler 的启动参数:
## vi /usr/lib/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes[Service]
EnvironmentFile=/opt/cfg/scheduler
ExecStart=/usr/bin/kube-scheduler $KUBE_SCHEDULER_ARGS
Restart=always[Install]
WantedBy=multi-user.target
(2) 在环境文件/opt/cfg/scheduler中,配置变量KUBE_SCHEDULER_ARGS 的值为 kube-scheduler的全部启动参数:
## vi /opt/cfg/scheduler
KUBE_SCHEDULER_ARGS="--kubeconfig=/opt/cfg/kubeconfig \
--leader-elect=true"
- –kubeconfig:与APIServer连接的相关配置。
- –leader-elect:启用选举机制,在有3个节点的环境下应被设置为“true”。
(3) 在配置文件准备完毕后,在3台主机上分别启动 kube-scheduler 服务,并设置为开机自启动:
systemctl start kube-scheduler && systemctl enable kube-scheduler
systemctl status kube-scheduler
通过 systemctl status 验证服务的启动状态,若状态为“running”并且没有报错日志,则表示启动成功。
7. 使用 HAProxy 和 keepalived 部署高可用负载均衡器
接下来,在3个kube-apiserver服务的前端部署HAProxy和keepalived,将VIP地址192.168.26.100作为Master的唯一入口地址,供客户端访问。
将 HAProxy和keepalived均部署为至少有两个实例的高可用架构,以免发生单点故障。下面在192.168.26.31和192.168.26.32两台服务器上进行部署。
HAProxy负责将客户端的请求转发到后端的3个kube-apiserver 实例上,keepalived 负责保证虚拟 IP地址192.168.26.100的高可用。
HAProxy和 keepalived 的部署架构如图 所示:
接下来在k8s31(192.168.26.31)和k8s32(192.168.26.31)部署 HAProxy 和 keepalived 实例。
1) 部署两个 HAProxy 实例
准备 HAProxy 的配置文件 haproxy.cfg:
## vi /opt/cfg/haproxy.cfg
globallog 127.0.0.1 local2chroot /var/lib/haproxypidfile /var/run/haproxy.pidmaxconn 4096user haproxygroup haproxydaemonstats socket /var/lib/haproxy/statsdefaultsmode httplog globaloption httplogoption dontlognulloption http-server-closeoption forwardfor except 127.0.0.0/8option redispatchretries 3timeout http-request 10stimeout queue 1mtimeout connect 10stimeout client 1mtimeout server 1mtimeout http-keep-alive 10stimeout check 10smaxconn 3000frontend kube-apiservermode tcpbind *:9443option tcplogdefault_backend kube-apiserverlisten statsmode httpbind *:8888stats auth admin:passwordstats refresh 5sstats realm HAProxy\ Statisticsstats uri /statslog 127.0.0.1 local3 errbackend kube-apiservermode tcpbalance roundrobinserver k8s-master1 192.168.26.31:6443 checkserver k8s-master2 192.168.26.32:6443 checkserver k8s-master3 192.168.26.33:6443 check
- frontend:HAProxy的监听协议和端口号,使用TCP,端口号为9443
- backend:后端的3个kube-apiserver的地址(192.168.26.31:6443、192.168.26.32:6443和192.168.26.33:6443),以IP:Port 形式表示;mode 字段用于设置协议,此处的值为“tcp”;balance 字段用于设置负载均衡策略,例如roundrobin为轮询模式。
- listen stats:状态监控的服务配置,其中,bind用于设置监听端口号为8888;stats auth用于设置访问账号和密码(这里设置为admin:password);stats uri用于设置访问的URL路径,例如/stats。
通过 Docker 容器运行HAProxy且镜像使用haproxytech/haproxy-debian:
在两台服务器192.168.26.31和192.168.26.32上启动HAProxy,将配置文件 haproxy.cfg挂载到容器的/usr/local/etc/haproxy 目录下,启动命令如下:
## 拉取镜像haproxytech/haproxy-debian:latest
~]# docker pull haproxytech/haproxy-debian:latest
## 启动haproxy
~]# docker run -d --name k8s-haproxy \--net=host \--restart=always \-v /opt/cfg/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro \haproxytech/haproxy-debian:latest
~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0c8f267ad2cd haproxytech/haproxy-debian:latest "/docker-entrypoint.…" 16 seconds ago Up 15 seconds k8s-haproxy
在一切正常的情况下,通过浏览器访问 http://192.168.26.31:8888/stats 这一地址即可访问 HAProxy 的管理页面,输入用户名和密码(admin:password)登录后査看到的主页界面如图所示:
这里主要关注最后一个表格,其内容为haproxy.cfg配置文件中backend 配置的3个kube-apiserver地址,它们的状态均为“UP",表示与3个kube-apiserver 服务成功建立连接,说明 HAProxy 工作正常。
2) 部署两个 keepalived 实例
keepalived用于维护虚拟IP地址的高可用,同样在k8s31和k8s32两台服务器上部署。其中主要需要配置keepalived对HAProxy运行状态的监控,当某个HAProxy实例不可用时,自动将虚拟 IP地址切换到另一台主机上。
在第1台服务器k8s31:192.168.26.31上创建配置文件 keepalived.conf:
## /opt/cfg/keepalived.conf
! Configuration File for keepalivedglobal_defs {router_id LVS_1
}vrrp_script checkhaproxy
{script "/opt/bin/check-haproxy.sh"interval 2weight -30
}vrrp_instance VI_1 {state MASTERinterface ens160virtual_router_id 51priority 100advert_int 1virtual_ipaddress {192.168.26.100/24 dev ens160}authentication {auth_type PASSauth_pass password}track_script {checkhaproxy}
}
在 vrrp_instance 字段设置主要参数。
- vrrp_instance VI_1:设置 keepalived 虚拟路由器组(VRRP)的名称。
- state:设置为“MASTER”,将其他keepalived均设置为“BACKUP”。
- interface:待设置虚拟IP地址的网卡名称。
- virtual_router_id:例如51。
- priority:优先级,例如100。
- virtual_ipaddress:虚拟IP地址,例如192.168.26.100/24。
- authentication:访问 keepalived 服务的鉴权信息。
- track_script:HAProxy的健康检查脚本。
keepalived需要持续监控 HAProxy的运行状态,在某个 HAProxy 实例运行不正常时,自动切换到运行正常的 HAProxy 实例上。需要创建一个 HAProxy 健康检查脚本,定期运行该脚本进行监控,例如新建脚本 check-haproxy.sh并将其保存到/usr/bin 目录下。
## /opt/bin/check-haproxy.sh
#!/bin/bashcount=`netstat -apn | grep 9443 | wc -l`if [ $count -gt 0 ]; thenexit 0
elseexit 1
fi
~]# chmod +x /opt/bin/check-haproxy.sh
~]# ls -l /opt/bin/check-haproxy.sh
-rwxr-xr-x 1 root root 111 7月 8 02:58 /opt/bin/check-haproxy.sh
若检查成功,则返回0;若检查失败,则返回非0值。keepalived根据上面的配置每隔2s检査一次HAProxy的运行状态。如果检査到第1台主机192.168.26.31上的HAProxy为非正常运行状态,keepalived就会将虚拟IP地址切换到正常运行HAProxy的第2台主机 192.168.26.32上,保证虚拟 IP地址 92.168.26.100的高可用。
在第2台主机k8s:192.168.26.32上创建配置文件keepalived.conf:
## /opt/cfg/keepalived.conf
! Configuration File for keepalivedglobal_defs {router_id LVS_2
}vrrp_script checkhaproxy
{script "/opt/bin/check-haproxy.sh"interval 2weight -30
}vrrp_instance VI_1 {state BACKUPinterface ens160virtual_router_id 51priority 100advert_int 1virtual_ipaddress {192.168.26.100/24 dev ens160}authentication {auth_type PASSauth_pass password}track_script {checkhaproxy}
}
这里与第1个keepalived 配置的主要差异如下:
- vrp_instance中的state被设置为“BACKUP”,这是因为在整个keepalived集群中只能有一个被设置为“MASTER"。如果keepalived集群不止有2个实例,那么除了MASTER,其他都应被设置为“BACKUP”。
- vrp_instance的值“VI_1”需要与 MASTER 的配置相同,表示它们属于同一个虚拟路由器组,当 MASTER不可用时,同组的其他 BACKUP实例会自动选举出一个新的MASTER。
HAProxy健康检査脚本 check-haproxy.sh与第1个keepalived 的相同。
通过 Docker 容器运行 keepalived 且镜像使用 osixia/keepalived:
在两台主机k8s31和k8s32上启动keepalived,将配置文件keepalived.conf挂载到容器的/container/service/keepalived/assets目录下,启动命令如下:
~]# docker pull osixia/keepalived:latest
## 启动keepalived
~]# docker run -d --name k8s-keepalived \--restart=always \--net=host \--cap-add=NET_ADMIN --cap-add=NET_BROADCAST --cap-add=NET_RAW \-v /opt/cfg/keepalived.conf:/container/service/keepalived/assets/keepalived.conf \-v /opt/bin/check-haproxy.sh:/usr/bin/check-haproxy.sh \osixia/keepalived:latest --copy-service
~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f41b9f3f9a4c osixia/keepalived:latest "/container/tool/run…" 9 seconds ago Up 9 seconds k8s-keepalived
0c8f267ad2cd haproxytech/haproxy-debian:latest "/docker-entrypoint.…" 9 minutes ago Up 9 minutes k8s-haproxy
在运行正常的情况下,keepalived会在第1台主机k8s31的网卡ens160 上设置VIP地址192.168.26.100。同样,在第1台主机 k8s31上运行的HAProxy将在该IP地址上监听9443端口号,对需要访问Kubermetes Master的客户端提供负载均衡器的人口地址,即:
192.168.26.100:9443
通过ip addr命令査看主机192.168.26.31的IP地址,可以看到在ens160网卡上新增了VIP地址192.168.26.100:
通过cul命令即可验证通过HAProxy的192.168.26.100:9443 地址是否可以访问 kube-apiserver 服务:
## 通过haproxy访问kube-apiserver
# curl -v -k https://192.168.26.100:9443
* Rebuilt URL to: https://192.168.26.100:9443/
* Trying 192.168.26.100...
* TCP_NODELAY set
* Connected to 192.168.26.100 (192.168.26.100) port 9443 (#0)
...
* TLSv1.3 (IN), TLS app data, [no content] (0):
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "Unauthorized","reason": "Unauthorized","code": 401
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, [no content] (0):
* TLSv1.3 (OUT), TLS alert, close notify (256):
}
可以看到"code": 401,表示 TCP/IP连接创建成功,说明通过虚拟IP地址192.168.26.100 成功访问到了后端的 kube-apiserver服务。
~]# kubectl --kubeconfig=/opt/cfg/kubeconfig get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
etcd-0 Healthy ok
controller-manager Healthy ok
scheduler Healthy ok
至此,Master 上所需的3个服务就全部启动完成。接下来部署各个Node的服务。
4.5 部署各个 Node 的服务
在 Node 上需要部署容器运行时(如 containerd)、kubelet和 kube-proxy 等系统组件。容器运行时可以根据需要选择合适的软件,例如开源的containerd、cri-o等,相关安装部署过程参考其说明文档。
将 192.168.26.31、192.168.26.32和 192.168.26.33 三台主机部署为 Node,部署一个包含3个Node 的Kubernetes 集群。
1. 部署kubelet服务(容器为docker)
- 创建目录
~]# mkdir /data/kubernetes/kubelet -p
- 启动文件/usr/lib/systemd/system/kubelet.service。默认使用docker作为Runtime。
cat > /usr/lib/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=cri-dockerd.service
Requires=cri-dockerd.service[Service]
WorkingDirectory=/data/kubernetes/kubelet
ExecStart=/usr/bin/kubelet \\--bootstrap-kubeconfig=/opt/cert/bootstrap-kubelet.kubeconfig \\--cert-dir=/opt/cert \\--kubeconfig=/opt/cfg/kubeconfig \\--config=/opt/cfg/kubelet.json \\--container-runtime-endpoint=unix:///var/run/cri-dockerd.sock \\--pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.10 \\--root-dir=/data/kubernetes/kubelet \\--v=2
Restart=on-failure
RestartSec=5[Install]
WantedBy=multi-user.target
EOF
/opt/cert/kubelet.kubeconfig为自动创建的文件,如果已存在就删除
- 所有k8s节点创建kubelet的配置文件/opt/cfg/kubelet.json
cat > /opt/cfg/kubelet.json << EOF
{"kind": "KubeletConfiguration","apiVersion": "kubelet.config.k8s.io/v1beta1","authentication": {"x509": {"clientCAFile": "/opt/cert/ca.crt"},"webhook": {"enabled": true,"cacheTTL": "2m0s"},"anonymous": {"enabled": false}},"authorization": {"mode": "Webhook","webhook": {"cacheAuthorizedTTL": "5m0s","cacheUnauthorizedTTL": "30s"}},"address": "192.168.26.31","port": 10250,"readOnlyPort": 10255,"cgroupDriver": "systemd", "hairpinMode": "promiscuous-bridge","serializeImagePulls": false,"clusterDomain": "cluster.local.","clusterDNS": ["168.26.0.100"]
}
EOF
注意修改:“address”: “192.168.26.31”;
“address”: “192.168.26.32”;
“address”: “192.168.26.33”
- 启动
~]# systemctl daemon-reload
~]# systemctl enable --now kubelet
~]# systemctl status kubelet
● kubelet.service - Kubernetes KubeletLoaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)Active: active (running) since Tue 2025-07-08 03:09:04 EDT; 15s agoDocs: https://github.com/kubernetes/kubernetesMain PID: 3071 (kubelet)Tasks: 11 (limit: 23520)Memory: 25.3MCGroup: /system.slice/kubelet.service└─3071 /usr/bin/kubelet --bootstrap-kubeconfig=/opt/cert/bootstrap-kubelet.kubeconfig --cert-dir=/opt/cert --kubeconfig=/opt/cfg/k>
......
## 启动不正常时,查看出错信息:journalctl -fu kubelet
~]# kubectl get nodes -o wide --kubeconfig=/opt/cfg/kubeconfig
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s31.vm.com NotReady <none> 3m28s v1.33.2 192.168.26.31 <none> CentOS Linux 8 4.18.0-348.7.1.el8_5.x86_64 docker://28.3.1
k8s32.vm.com NotReady <none> 3m28s v1.33.2 192.168.26.32 <none> CentOS Linux 8 4.18.0-348.7.1.el8_5.x86_64 docker://28.3.1
k8s33.vm.com NotReady <none> 3m28s v1.33.2 192.168.26.33 <none> CentOS Linux 8 4.18.0-348.7.1.el8_5.x86_64 docker://28.3.1
如果node仍然是NotReady
,则需要安装cni-plugin-flannel。(参见后面的Calico CNI插件部署)
~]# kubectl --kubeconfig=/opt/cfg/kubeconfig get nodes
NAME STATUS ROLES AGE VERSION
k8s31.vm.com NotReady <none> 4m29s v1.33.2
k8s32.vm.com NotReady <none> 4m29s v1.33.2
k8s33.vm.com NotReady <none> 4m29s v1.33.2
2. 部署 kubelet 服务(容器为containerd)【本次未使用】
(1) 为kubelet服务创建systemd服务的配置文件/usr/lib/systemd/system/kubelet.service:
## /usr/lib/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet Server
Documentation=https://github.com/kubernetes/kubernetes
After=docker.target[Service]
EnvironmentFile=/opt/cfg/kubelet
ExecStart=/usr/bin/kubelet $KUBELET_ARGS
Restart=always[Install]
WantedBy=multi-user.target
(2) 配置文件/etc/kubernetes/kubelet的内容为通过环境变量 KUBELET_ARGS 设置的kubelet的全部启动参数:
## /opt/cfg/kubelet
KUBELET_ARGS="--kubeconfig=/opt/cfg/kubeconfig \
--config=/opt/cfg/kubelet.config \
--hostname-override=192.168.26.31"
- –kubeconfig:设置与API Server连接的相关配置,可以与 kube-controller-manager使用的 kubeconfg 文件相同。需要将相关客户端证书文件从 Master 复制到 Node的/opt/cfg目录下,例如 ca.crt、client.key、client.crt 文件。
- –config:kubelet配置文件,例如kubelet.config,在Kubernetes v1.10版本中开始引人,用于逐步替换命令行参数,以简化Node 的配置管理。
- –hostmame-override:设置本 Node 在集群中的名称,默认值为主机名,应将各个Node 都设置为本机 IP 地址或域名。
配置文件 kubelet.config:
## /opt/cfg/kubelet.config
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
port: 10250
cgroupDriver: systemd
clusterDNS: ["168.26.0.100"]
clusterDomain: cluster.local
authentication:anonymous:enabled: true
- address:服务监听的IP 地址。
- port:服务监听的端口号,默认值为 10250。
- cgroupDriver:设置为cgroupDriver驱动,可选项包括systemd 和 cgroupfs。
- clusterDNS:集群DNS服务的IP地址,例如168.26.0.100。
- clusterDomain:服务的 DNS 域名后缀,例如 cluster.local。
- authentication:设置是否允许匿名访问或者是否使用 Webhook 进行鉴权。
(3) 在配置文件准备完毕后,在各个Node 上启动 kubelet服务,并设置为开机自启动命令如下:
~]# systemctl start kubelet && systemctl enable kubelet
~]# systemctl status kubelet
3. 部署 kube-proxy 服务
(1) 为 kube-proxy服务创建systemd服务的配置文件/usr/lib/systemd/system/kube-proxy.service:
## /usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target[Service]
EnvironmentFile=/opt/cfg/proxy
ExecStart=/usr/bin/kube-proxy $KUBE_PROXY_ARGS
Restart=always[Install]
WantedBy=multi-user.target
(2) 配置文件/opt/cfg/proxy 的内容为通过环境变量 KUBE_PROXY_ARGS 设置的 kube-proxy 的全部启动参数:
## /opt/cfg/proxy
KUBE_PROXY_ARGS="--kubeconfig=/opt/cfg/kubeconfig \
--hostname-override=192.168.26.31 \
--proxy-mode=iptables"
- –kubeconfig:设置与API Server连接的客户端身份,可以与kubelet 使用相同的kubeconfig 文件。
- –hostname-override:设置本Node在集群中的名称,默认值为主机名。
- –proxy-mode:代理模式,可选项包括iptables、ipvs、kernelspace(Windows Node使用)。
(3) 在配置文件准备完毕后,在各个Node 上启动 kube-proxy 服务,并设置为开机自启动,命令如下:
~]# systemctl start kube-proxy && systemctl enable kube-proxy
~]# systemctl status kube-proxy
4. 在 Master 上通过 kubectl验证各个 Node 的信息
在各个Node的kubelet和kube-proxy服务均正常启动之后,会先将Node自动注册到Master上,然后就可以到Master上通过kubectl查询已注册的 Node 的信息,命令如下:
]# kubectl --kubeconfig=/opt/cfg/kubeconfig get nodes
NAME STATUS ROLES AGE VERSION
k8s31.vm.com NotReady <none> 8m56s v1.33.2
k8s32.vm.com NotReady <none> 8m56s v1.33.2
k8s33.vm.com NotReady <none> 8m56s v1.33.2
可以看到各个Node的状态均为“NotReady”,这是因为还没有部署CNI网络插件,无法设置容器网络。
5. 安装Calico CNI网络插件
按需选择适合的CNI网络插件进行部署。选择Calico CNI网络插件,则运行以下命令即可一键完成部署:
- 下载 calico 的 yaml 文件(https://docs.projectcalico.org/manifests/calico.yaml)
https://github.com/projectcalico/calico/blob/release-v3.30/manifests/calico.yaml
- 配置 cidr 网段,找到
CALICO_IPV4POOL_CIDR
字段,关闭前面的注释,把ip网段修改成和controller-manager
的--cluster-cidr
参数一致
- name: CALICO_IPV4POOL_CIDRvalue: "10.26.0.0/16"
- 拉取镜像
app]# grep image calico.yamlimage: docker.io/calico/cni:v3.30.0imagePullPolicy: IfNotPresentimage: docker.io/calico/cni:v3.30.0imagePullPolicy: IfNotPresentimage: docker.io/calico/node:v3.30.0imagePullPolicy: IfNotPresentimage: docker.io/calico/node:v3.30.0imagePullPolicy: IfNotPresentimage: docker.io/calico/kube-controllers:v3.30.0imagePullPolicy: IfNotPresent
app]# docker pull docker.io/calico/cni:v3.30.0
app]# docker pull docker.io/calico/node:v3.30.0
app]# docker pull docker.io/calico/kube-controllers:v3.30.0
- 创建 calico 组件
app]# kubectl apply -f /opt/app/calico.yaml --kubeconfig=/opt/cfg/kubeconfig
...
在 CNI网络插件成功运行之后,各个Node的状态均会更新为“Ready”:
app]# watch kubectl get pod -A --kubeconfig=/opt/cfg/kubeconfig
...
app]# kubectl --kubeconfig=/opt/cfg/kubeconfig get pod -A -owide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system calico-kube-controllers-7bfdc5b57c-gkftm 1/1 Running 0 38s 10.26.179.193 k8s31.vm.com <none> <none>
kube-system calico-node-cmc58 1/1 Running 0 38s 192.168.26.31 k8s31.vm.com <none> <none>
kube-system calico-node-k9tf8 1/1 Running 0 38s 192.168.26.33 k8s33.vm.com <none> <none>
kube-system calico-node-wwd97 1/1 Running 0 38s 192.168.26.32 k8s32.vm.com <none> <none>
]# kubectl --kubeconfig=/opt/cfg/kubeconfig get nodes
NAME STATUS ROLES AGE VERSION
k8s31.vm.com Ready <none> 15m v1.33.2
k8s32.vm.com Ready <none> 15m v1.33.2
k8s33.vm.com Ready <none> 15m v1.33.2
6. kubectl配置
- 创建admin.kubeconfig。
-server=https://192.168.26.100:9443
。在一个节点执行一次即可。(此处可不用创建,使用**/opt/cfg/kubeconfig**即可)
kubectl config set-cluster kubernetes \--certificate-authority=/opt/cert/ca.crt \--embed-certs=true \--server=https://192.168.26.100:9443 \--kubeconfig=/opt/cert/admin.kubeconfigkubectl config set-credentials kubernetes-admin \--client-certificate=/opt/cert/client.crt \--client-key=/opt/cert/client.key \--embed-certs=true \--kubeconfig=/opt/cert/admin.kubeconfigkubectl config set-context kubernetes-admin@kubernetes \--cluster=kubernetes \--user=kubernetes-admin \--kubeconfig=/opt/cert/admin.kubeconfigkubectl config use-context kubernetes-admin@kubernetes --kubeconfig=/opt/cert/admin.kubeconfig
]# mkdir ~/.kube
### ]# cp /opt/cert/admin.kubeconfig ~/.kube/config
]# cp /opt/cfg/kubeconfig ~/.kube/config
]# scp -r ~/.kube root@k8s32:~/.
]# scp -r ~/.kube root@k8s33:~/.
- 配置kubectl子命令补全
~]# echo 'source <(kubectl completion bash)' >> ~/.bashrc~]# yum -y install bash-completion
~]# source /usr/share/bash-completion/bash_completion
~]# source <(kubectl completion bash)~]# kubectl get componentstatuses
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy ok
~]# kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s31.vm.com Ready <none> 19m v1.33.2 192.168.26.31 <none> CentOS Linux 8 4.18.0-348.7.1.el8_5.x86_64 docker://28.3.1
k8s32.vm.com Ready <none> 19m v1.33.2 192.168.26.32 <none> CentOS Linux 8 4.18.0-348.7.1.el8_5.x86_64 docker://28.3.1
k8s33.vm.com Ready <none> 19m v1.33.2 192.168.26.33 <none> CentOS Linux 8 4.18.0-348.7.1.el8_5.x86_64 docker://28.3.1
为了使 Kubernetes 集群内的微服务能够通过服务名进行网络访问,还需要部署kube-dns服务,建议使用CoreDNS来部署DNS服务。
至此,一个有3个Master 的高可用 Kubernetes 集群就部署完成,接下来就可以创建 Pod、Deployment、Service 等资源对象来部署和管理容器应用及微服务。
五、 DNS服务搭建和配置
5.1 CoreDNS 总体架构
5.2 部署CoreDNS服务
修改每个Node上kubelet的 DNS 启动参数,在其中加上以下两个参数。
- –cluster-dns=168.26.0.100:是DNS服务的ClusterIP 地址。
- –cluster-domain=cluster.local:是在DNS 服务中设置的域名。
然后重启 kubelet 服务。
部署 CoreDNS 服务时需要创建3个资源对象:ConfigMap、Deployment和 Service。在启用了 RBAC 的 Kubernetes 集群中,还可以通过设置 ServiceAccount、ClusterRole、ClusterRoleBinding 来对 CoreDNS 容器进行权限设置。
- ConfigMap “coredns”主要用于设置CoreDNS的主配置文件Corefile的内容,其中可以定义各种域名的解析方式和使用的插件。
- Deployment “coredns”主要用于设置CoreDNS容器应用的内容,其中replicas副本的数量通常应该根据Kubernetes 集群的规模和服务数量确定,如果单个 CoreDNS进程不足以支撑整个集群的DNS查询,则可以通过水平扩展提高查询能力。由于DNS服务是Kubermetes 集群的关键核心服务,所以建议为其 Deployment设置自动扩缩容控制器,自动管理其副本数量。另外,对资源限制部分(CPU限制和内存限制)的设置也应根据实际环境进行调整。
- Service “kube-dns”是DNS服务的配置清单,这个服务需要设置固定的ClusterIP地址,也需要将所有Node上的 kubelet启动参数–cluster-dns都设置为这个ClusterIP地址。
app]# cp coredns.yaml.base coredns.yaml
app]# grep image coredns.yamlimage: registry.k8s.io/coredns/coredns:v1.12.0imagePullPolicy: IfNotPresent
app]# docker pull registry.k8s.io/coredns/coredns:v1.12.0 ## 不能拉取时,使用aliyun镜像
app]# docker pull registry.aliyuncs.com/google_containers/coredns:v1.12.0
app]# docker images|grep coredns
registry.k8s.io/coredns/coredns v1.12.0 1cf5f116067c 7 months ago 70.1MB## 修改以下内容:__DNS__DOMAIN__ 改为: cluster.local__DNS__MEMORY__LIMIT__ 改为: 170Mi__DNS__SERVER__ 改为: 168.26.0.100
## 修改内容位置
...
data:Corefile: |cluster.local {errorshealth {lameduck 5s}readykubernetes cluster.local 168.26.0.0/16 {fallthrough in-addr.arpa ip6.arpa}
...resources:limits:memory: 170Mirequests:cpu: 100mmemory: 70Mi
...
spec:selector:k8s-app: kube-dnsclusterIP: 168.26.0.100
...
通过 kubectl create命令完成 CoreDNS 服务的创建:
app]# kubectl create -f /opt/app/coredns.yaml
查看 Deployment、Pod和Service,确保容器成功启动:
app]# kubectl get deployments --namespace=kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
calico-kube-controllers 1/1 1 1 13m
coredns 1/1 1 1 8s
app]# kubectl get pods --namespace=kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-7bfdc5b57c-gkftm 1/1 Running 0 13m
calico-node-cmc58 1/1 Running 0 13m
calico-node-k9tf8 1/1 Running 0 13m
calico-node-wwd97 1/1 Running 0 13m
coredns-76b7578cff-4jxb6 1/1 Running 0 34s
app]# kubectl get services --namespace=kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 168.26.0.100 <none> 53/UDP,53/TCP,9153/TCP 53
5.3 服务名的 DNS 解析
使用一个带有 nslookup 工具的 Pod 来验证 DNS 服务能否正常工作,
## busybox.yaml
## app to test service name dns resolution
---
apiVersion: v1
kind: Pod
metadata:name: busyboxnamespace: default
spec:containers:- name: busyboximage: busybox:1.28imagePullPolicy: IfNotPresentcommand:- sleep- "3600"
通过kubectl create -f busybox.yaml命令即可完成创建。在该容器成功启动后,通过 kubectl exec --nslookup 命令进行测试:
app]# kubectl create -f busybox.yaml
...
app]# kubectl exec -it busybox -- /bin/sh
/ # cat /etc/resolv.conf
nameserver 168.26.0.100
search default.svc.cluster.local. svc.cluster.local. cluster.local. vm.com
options ndots:5
/ ### 服务名DNS解析验证【参考“集群验证与总结”,创建svc】
如果某个 Service 属于不同的命名空间,那么在进行 Service 查找时,需要补充命名空间的名称,将其组合成完整的域名。下面以查找kube-dns 服务为例,将其所在命名空间“kube-system”补充在服务名之后,用“.”连接为“kube-dns.kube-system”即可查询成功:
使用busybox:latest镜像时解析需要全域名,使用busybox:1.28镜像可以使用短域名。
]# kubectl exec busybox -- nslookup kube-dns.kube-system
Server: 168.26.0.100
Address 1: 168.26.0.100 kube-dns.kube-system.svc.cluster.localName: kube-dns.kube-system
Address 1: 168.26.0.100 kube-dns.kube-system.svc.cluster.local
如果仅使用kube-dns 进行查找,则会失败:
]# kubectl exec busybox -- nslookup kube-dns
Server: 168.26.0.100
Address 1: 168.26.0.100 kube-dns.kube-system.svc.cluster.localnslookup: can't resolve 'kube-dns'
command terminated with exit code 1
六、Metrics Server
Metrics Server 的主要用途是配合Horizontal Pod Autoscaler与Vertical Pod Autoscaler来实现Kubernetes自动伸缩的功能,Metrics Server 具有如下几个特点:
- 部署简单,通过一个 YAML 文件可以在绝大多数系统上一键部署。
- 每隔15s搜集一次性能指标数据,可以实现Pod的快速自动伸缩控制。
- 轻量级,资源占用量很低,在每个 Node上只需要1m的CPU和 2MiB的内存。
- 可以支持多达 5000个Node的集群。
安装部署很简单,首先从官网下载 Metrics Server 的 YAML 配置文件:
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
或者在浏览器直接输入网址即可下载。
按需修改文件中的配置,其中增加启动参数–kubelet-insecure-tls,表示在访问 kubelet的 HTTPS 协议端口号时不验证 TLS 证书。
...spec:containers:- args:- --cert-dir=/tmp- --secure-port=10250- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname- --kubelet-use-node-status-port- --metric-resolution=15s- --kubelet-insecure-tlsimage: registry.k8s.io/metrics-server/metrics-server:v0.7.2imagePullPolicy: IfNotPresent
...
然后,基于 YAML文件创建 Metrics Server,并等待 Pod 成功启动。
# kubectl --namespace=kube-system create -f components.yaml
...
# kubectl --namespace=kube-system get pods -l k8s-app=metrics-server
NAME READY STATUS RESTARTS AGE
metrics-server-8467fcc7b7-nqrt4 1/1 Running 0 2m5s
查看 Metrics Server Pod 日志,确定运行正常。
# kubectl --namespace=kube-system logs metrics-server-
...
接下来,可以通过 kubectl top nodes 和 kubectl top pods 命令监控 Node 和 Pod 的 CPU、内存资源的使用情况:
app]# kubectl top nodes
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
k8s31.vm.com 149m 7% 2265Mi 62%
k8s32.vm.com 101m 5% 1661Mi 46%
k8s33.vm.com 102m 5% 1595Mi 44%
app]# kubectl top pod -A
NAMESPACE NAME CPU(cores) MEMORY(bytes)
default busybox 0m 0Mi
default nginx-web-74lzn 0m 3Mi
default nginx-web-cwg8g 0m 3Mi
kube-system calico-kube-controllers-7bfdc5b57c-gkftm 5m 23Mi
kube-system calico-node-cmc58 38m 198Mi
kube-system calico-node-k9tf8 34m 200Mi
kube-system calico-node-wwd97 32m 199Mi
kube-system coredns-76b7578cff-l56sj 2m 16Mi
kube-system metrics-server-8467fcc7b7-nqrt4 5m 78Mi
启动一个性能测试 Pod模拟大量使用系统资源,再次监控 Node 和 Pod 的性能指标数据,可以直观地看到资源的使用情况:
# kubectl run testperf --image containerstack/alpine-stress -- stress --cpu 3 -- io 4 --vm 2 --vm-bytes 256M --timeout 3000s# kubectl get po# kubectl top nodes# kubectl top pods
上述测试表示,运行3个进程计算 sqrt(),运行4个进程执行 IO 写磁盘操作,运行 2个进程执行分配内存的操作,每个进程分配 256MB内存,这个压力测试过程持续 3000s。
几个常用命令:
- kubectl top node ,可以直接指定 Node 或者 Pod 的名称。
- kubectl top pod --sort-by=memory,实现排序功能,可以按照 CPU或者内存排序输出。
- kubectl top pod --selector application=demo-app,通过 selector 标签选择器,选择某些 Pod 进行查看。
也可以用 API方式访问:
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
七、使用 Dashboard 监控集群资源状态和性能
Kubermetes 的 Web UI网页管理工具是 kubernetes-dashboard,可提供部署应用、资源对象管理、容器日志查询、系统监控等常用的集群管理功能。为了在页面上显示系统资源的使用情况,需要部署 Metrics Server。可以使用 GitHub 仓库提供的 YAML 文件快速部署kubernetes-dashboard。YAML文件下载:
## https://github.com/kubernetes/dashboard
# wget https://raw.githubusercontent.com/kubernetes/dashboard/refs/tags/v2.7.0/aio/deploy/recommended.yaml
或者使用浏览器打开https://github.com/kubernetes/dashboard/blob/v2.7.0/aio/deploy/recommended.yaml,然后复制内容。
为了方便访问服务页面,需要修改kubernetes-dashboard的Service 定义,可以改为NodePort 端口类型:
kind: Service
apiVersion: v1
metadata:labels:k8s-app: kubernetes-dashboardname: kubernetes-dashboardnamespace: kubernetes-dashboard
spec:type: NodePort # 设置NodePort 端口类型ports:- port: 443targetPort: 8443selector:k8s-app: kubernetes-dashboard
通过 kubectl apply 命令部署 Dashboard:
]# kubectl apply -f recommended.yaml
...
]# kubectl -n kubernetes-dashboard get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 168.26.24.159 <none> 8000/TCP 7s
kubernetes-dashboard NodePort 168.26.220.179 <none> 443:32584/TCP 7s
服务启动成功之后,就可以通过https://192.168.26.33:32584/访间 Dashboard 的 Web 页面了。
有多种方法访问 kubernetes-dashboard,例如设置Service的NodePort 或者 kubectl forward 端口的方式。
首次访问 Kubernetes Dashboard 页面时需要登录,如图 所示。
通过下面的命令,创建一个 Dashboard 登录用的管理员账号,授权集群管理角色,然后得到它的 Token,录人上面的界面中即可登录:
# cat dashboard-user.yaml
apiVersion: v1
kind: ServiceAccount
metadata:name: admin-usernamespace: kubernetes-dashboard---apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: admin-user
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: cluster-admin
subjects:- kind: ServiceAccountname: admin-usernamespace: kubernetes-dashboard
# kubectl apply -f dashboard-user.yaml
...
# kubectl -n kubernetes-dashboard create token admin-user
...
将 kubectl create token命令的输出结果复制到登录页面,即可登录 Dashboard 查看Kubernetes 集群的各种信息。其中在 Settings 菜单里可以设置语言、默认展示的命名空间等配置。首页默认显示命名空间 default中的工作负载信息,可以通过上方的下拉列表选择不同的命名空间进行查看,也可以查看所有命名空间的Workload 信息,如图所示。
在首页上会显示各种类型工作负载的数量统计,以及各种资源对象的列表,例如Daemonset、Deployment、Pod、Statefulset、Service 等。通过单击左侧的菜单项,可以过滤 Workloads、Service、Config and Storage、Cluster、CRD 等各类资源对象的列表和详细信息。例如查看 Service 列表页面,如图所示。
八、集群验证与总结
8.1 部署pod验证
]# vi busybox.yaml
apiVersion: v1
kind: Pod
metadata:name: busyboxnamespace: default
spec:containers:- name: busyboximage: docker.io/library/busybox:1.28imagePullPolicy: IfNotPresentcommand:- sleep- "3600"
]# kubectl apply -f busybox.yaml
pod/busybox created
]# kubectl get pod
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 2s
8.2 部署service验证
cat > nginx.yaml << "EOF"
---
apiVersion: v1
kind: ReplicationController
metadata:name: nginx-web
spec:replicas: 2selector:name: nginxtemplate:metadata:labels:name: nginxspec:containers:- name: nginximage: nginx:1.19.6imagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-service-nodeport
spec:ports:- port: 80targetPort: 80nodePort: 30001protocol: TCPtype: NodePortselector:name: nginx
EOF
]# kubectl apply -f nginx.yaml
replicationcontroller/nginx-web created
service/nginx-service-nodeport created
]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox 1/1 Running 0 52m 10.26.25.193 k8s32.vm.com <none> <none>
nginx-web-74lzn 1/1 Running 0 8s 10.26.139.67 k8s33.vm.com <none> <none>
nginx-web-cwg8g 1/1 Running 0 8s 10.26.25.194 k8s32.vm.com <none> <none>
## 要拉取镜像,需要等一会
]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/busybox 1/1 Running 0 53m
pod/nginx-web-74lzn 1/1 Running 0 33s
pod/nginx-web-cwg8g 1/1 Running 0 33sNAME DESIRED CURRENT READY AGE
replicationcontroller/nginx-web 2 2 2 33sNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 168.26.0.1 <none> 443/TCP 119m
service/nginx-service-nodeport NodePort 168.26.216.107 <none> 80:30001/TCP 33s
]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 168.26.0.1 <none> 443/TCP 4d8h
nginx-service-nodeport NodePort 168.26.79.197 <none> 80:30001/TCP 79s
浏览器访问:http://192.168.26.33:30001/
8.3 创建3个副本在不同的节点上
cat > nginx-deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80EOF
]# kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deployment created
]# kubectl get pod -owide |grep nginx-deployment
nginx-deployment-64598b8f46-fkwc9 1/1 Running 0 9s 10.26.179.194 k8s31.vm.com <none> <none>
nginx-deployment-64598b8f46-lbq6b 1/1 Running 0 9s 10.26.25.195 k8s32.vm.com <none> <none>
nginx-deployment-64598b8f46-qxwkb 1/1 Running 0 9s 10.26.139.68 k8s33.vm.com <none> <none>
]# kubectl delete -f nginx-deployment.yaml
8.4 用pod解析默认命名空间中的svc
使用busybox:latest镜像时解析需要全域名,使用busybox:1.28镜像可以使用短域名。
]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 168.26.0.1 <none> 443/TCP 168m
nginx-service-nodeport NodePort 168.26.216.107 <none> 80:30001/TCP 50m]# kubectl exec busybox -n default -- nslookup kubernetes.default.svc.cluster.local
Server: 168.26.0.100
Address: 168.26.0.100:53Name: kubernetes.default.svc.cluster.local
Address: 168.26.0.1]# kubectl exec busybox -n default -- nslookup nginx-service-nodeport.default.svc.cluster.local
Server: 168.26.0.100
Address: 168.26.0.100:53Name: nginx-service-nodeport.default.svc.cluster.local
Address: 168.26.216.107
## 使用busybox:1.28镜像可以使用短域名
]# kubectl exec busybox -n default -- nslookup nginx-service-nodeport
Server: 168.26.0.100
Address 1: 168.26.0.100 kube-dns.kube-system.svc.cluster.localName: nginx-service-nodeport
Address 1: 168.26.216.107 nginx-service-nodeport.default.svc.cluster.local
可以看到,通过 DNS服务器168.26.0.100成功解析了nginx-service-nodeport
服务的 IP 地址168.26.216.107
。
8.5 测试跨命名空间是否可以解析
使用busybox:latest镜像时解析需要全域名,使用busybox:1.28镜像可以使用短域名。
]# kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 168.26.0.1 <none> 443/TCP 4h25m
default nginx-service-nodeport NodePort 168.26.216.107 <none> 80:30001/TCP 147m
kube-system kube-dns ClusterIP 168.26.0.100 <none> 53/UDP,53/TCP,9153/TCP 6m29s
kube-system metrics-server ClusterIP 168.26.107.166 <none> 443/TCP 132m
kubernetes-dashboard dashboard-metrics-scraper ClusterIP 168.26.24.159 <none> 8000/TCP 121m
kubernetes-dashboard kubernetes-dashboard NodePort 168.26.220.179 <none> 443:32584/TCP 121m
]# kubectl exec busybox -n default -- nslookup kube-dns.kube-system.svc.cluster.local
Server: 168.26.0.100
Address: 168.26.0.100:53Name: kube-dns.kube-system.svc.cluster.local
Address: 168.26.0.100## 使用busybox:1.28镜像可以使用短域名
]# kubectl exec busybox -n default -- nslookup kube-dns.kube-system
Server: 168.26.0.100
Address 1: 168.26.0.100 kube-dns.kube-system.svc.cluster.localName: kube-dns.kube-system
Address 1: 168.26.0.100 kube-dns.kube-system.svc.cluster.local
8.6 每个节点都必须要能访问Kubernetes的kubernetes svc 443和kube-dns的svc 53
]# kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 168.26.0.1 <none> 443/TCP 122m
default nginx-service-nodeport NodePort 168.26.216.107 <none> 80:30001/TCP 3m48s
kube-system kube-dns ClusterIP 168.26.0.100 <none> 53/UDP,53/TCP,9153/TCP 36m~]# telnet 168.26.0.1 443
Trying 168.26.0.1...
Connected to 168.26.0.1.
Escape character is '^]'.
Connection closed by foreign host.~]# telnet 168.26.0.100 53
Trying 168.26.0.100...
Connected to 168.26.0.100.
Escape character is '^]'.
Connection closed by foreign host.
8.7 Pod和其它主机及Pod之间能通
~]# kubectl get po -owide -A
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default busybox 1/1 Running 0 59m 10.26.25.193 k8s32.vm.com <none> <none>
default nginx-web-74lzn 1/1 Running 0 6m42s 10.26.139.67 k8s33.vm.com <none> <none>
default nginx-web-cwg8g 1/1 Running 0 6m42s 10.26.25.194 k8s32.vm.com <none> <none>
kube-system calico-kube-controllers-7bfdc5b57c-gkftm 1/1 Running 1 (51m ago) 73m 10.26.179.193 k8s31.vm.com <none> <none>
kube-system calico-node-cmc58 1/1 Running 0 73m 192.168.26.31 k8s31.vm.com <none> <none>
kube-system calico-node-k9tf8 1/1 Running 0 73m 192.168.26.33 k8s33.vm.com <none> <none>
kube-system calico-node-wwd97 1/1 Running 0 73m 192.168.26.32 k8s32.vm.com <none> <none>
kube-system coredns-76b7578cff-l56sj 1/1 Running 0 38m 10.26.139.66 k8s33.vm.com <none> <none>
进入busybox ping其他节点上的pod。可以连通证明这个pod是可以跨命名空间和跨主机通信的。
]# kubectl exec -ti busybox -- sh
## 主机k8s31上的pod ping主机k8s33(POD - 跨主机)
/ # ping 192.168.26.33 -c 3
PING 192.168.26.33 (192.168.26.33): 56 data bytes
64 bytes from 192.168.26.33: seq=0 ttl=63 time=1.583 ms
64 bytes from 192.168.26.33: seq=1 ttl=63 time=0.260 ms
64 bytes from 192.168.26.33: seq=2 ttl=63 time=0.372 ms--- 192.168.26.33 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.260/0.738/1.583 ms## 主机k8s31上的pod ping主机k8s33节点上的pod(跨主机跨命名空间)
/ # ping 10.26.139.67 -c 3
/ # ping 10.26.139.67 -c 3
PING 10.26.139.67 (10.26.139.67): 56 data bytes
64 bytes from 10.26.139.67: seq=0 ttl=62 time=0.712 ms
64 bytes from 10.26.139.67: seq=1 ttl=62 time=0.442 ms
64 bytes from 10.26.139.67: seq=2 ttl=62 time=0.368 ms--- 10.26.139.67 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.368/0.507/0.712 ms## 从主机k8s31节点ping k8s32上的pod(跨主机 - POD)
k8s31 app]# ping 10.26.25.194 -c 3
PING 10.26.25.194 (10.26.25.194) 56(84) bytes of data.
64 bytes from 10.26.25.194: icmp_seq=1 ttl=63 time=0.875 ms
64 bytes from 10.26.25.194: icmp_seq=2 ttl=63 time=0.344 ms
64 bytes from 10.26.25.194: icmp_seq=3 ttl=63 time=0.287 ms--- 10.26.25.194 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2080ms
rtt min/avg/max/mdev = 0.287/0.502/0.875/0.264 ms
至此,成功完成以二进制方式部署Kubernetes1.332 + docker28.3.1高可用集群。
8.8 总结
本次实验验证CentOS8.5+Kubernetes1.32.5+Docker28.3.1高可用集群二进制部署
- 使用新的软件版本进行组合时,往往会出现一些新的问题,需要花费大量时间进行测试验证。在沿用以往方案及经验进行试验时,一旦遇到新问题,最快的解决方案就是用较旧的版本进行替换及验证,而不是用SE或AI。
- 总之,关于如何在专业领域内提升,有个著名的“10000 小时定律”,简单来说要成为某个领域顶尖的专业人才,需要10000 小时持续不断的练习,例如小提琴、足球、国际象棋、围棋等领域,无一例外都遵循这个定律,而技术的成长也基本遵循这个定律。技术成长其实最关键的还是对技术的热情以及持续不断地投入,包括学习、实践、思考和总结等。