本文章仍在施工中。。。。
# 搭建 K8S 集群
操作系统:Centos7.9
Docker:20+
K8S:1.23.6
# 搭建 Kubernetes 集群
# 初始化操作
创建好虚拟机后,对三台虚拟机都进行进行初始化操作
在操作时能够听到喇叭提示音,如果不想听到提示音,可以通过在内核模块中移除 pcspkr 模块来完全禁用 PC 喇叭: rmmod pcspkr
# 修改主机名称
[root@localhost ~]# hostnamectl set-hostname Kubernetes-Master | |
[root@localhost ~]# hostnamectl | |
Static hostname: kubernetes-master | |
Pretty hostname: Kubernetes-Master | |
Icon name: computer-vm | |
Chassis: vm | |
Machine ID: 4e60493f0355468f9c57a968a0973490 | |
Boot ID: 0b3047df130f40b1b7c29e7e8738f812 | |
Virtualization: vmware | |
Operating System: CentOS Linux 7 (Core) | |
CPE OS Name: cpe:/o:centos:centos:7 | |
Kernel: Linux 3.10.0-1160.el7.x86_64 | |
Architecture: x86-64 |
# 修改 IP 地址
[root@kubernetes-master ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33 | |
[root@kubernetes-master ~]# systemctl restart network |
# 关闭 firewalld
[root@localhost ~]# systemctl stop firewalld.service | |
[root@localhost ~]# systemctl disable firewalld.service | |
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service. | |
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service. |
# 关闭 selinux
# 临时关闭 | |
[root@localhost ~]# setenforce 0 | |
# 永久关闭 | |
[root@localhost ~]# sed -i's/enforcing/disabled/' /etc/selinux/config |
# 关闭 swap
# 临时关闭 | |
[root@localhost ~]# swapoff -a | |
# 永久关闭 | |
[root@localhost ~]# sed -ri's/.*swap.*/#&/' /etc/fstab | |
# 重启虚拟机 | |
[root@localhost ~]# reboot |
# 添加 hosts
[root@kubernetes-master ~]# cat >> /etc/hosts << EOF | |
192.168.0.200 kubernetes-master | |
192.168.0.201 kubernetes-node1 | |
192.168.0.202 kubernetes-node2 | |
EOF |
# 加载 br_netfilter
配置的 br_netfilter 实现桥接流量透传,将桥接的 IPV4 流量传递到 iptables 的链,加载 br_netfilter 内核模块
[root@kubernetes-master ~]# cat > /etc/sysctl.d/k8s.conf << EOF | |
net.bridge.bridge-nf-call-ip6tables = 1 | |
net.bridge.bridge-nf-call-iptables = 1 | |
EOF | |
[root@kubernetes-master ~]# modprobe br_netfilter | |
[root@kubernetes-master ~]# echo "br_netfilter" > /etc/modules-load.d/k8s.conf | |
[root@kubernetes-master ~]# sysctl --system |
# 开启 ip_forward
配置 net.ipv4.ip_forward 实现 IP 层转发,docker 部署时会自动开启, containerd 需要手动开启
# 修改 sysctl 配置文件 | |
cat >> /etc/sysctl.conf << EOF | |
net.ipv4.ip_forward = 1 | |
EOF | |
# 重载 sysctl 配置使修改生效 | |
sysctl -p /etc/sysctl.conf | |
# 验证是否开启(输出 net.ipv4.ip_forward = 1) | |
sysctl net.ipv4.ip_forward |
# 配置 yum 源
[root@kubernetes-master ~]# mv /etc/yum.repos.d/CentOS-Base.repo/etc/yum.repos.d/CentOS-Base.repo.bak | |
[root@kubernetes-master ~]# cd /etc/yum.repos.d/ | |
[root@kubernetes-master yum.repos.d]# wget -nc https://mirrors.aliyun.com/repo/Centos-7.repo | |
[root@kubernetes-master yum.repos.d]# mv Centos-7.repo CentOS-Base.repo | |
[root@kubernetes-master yum.repos.d]# | |
# 设置 docker 仓库(阿里云镜像) | |
[root@kubernetes-master ~]# yum install -y yum-utils | |
[root@kubernetes-master ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | |
[root@kubernetes-master yum.repos.d]# yum clean all | |
[root@kubernetes-master yum.repos.d]# yum update -y | |
[root@kubernetes-master yum.repos.d]# yum list | |
[root@kubernetes-master yum.repos.d]# yum makecache |
# 设置时间
[root@kubernetes-master ~]# timedatectl set-ntp true | |
[root@kubernetes-master ~]# timedatectl set-timezone Asia/Shanghai | |
[root@kubernetes-master ~]# timedatectl status |
# 禁用 NM 管理 DNS
NetworkManager 默认会接管 /etc/resolv.conf ,导致修改 dns 配置会被回刷,需要禁用 NetworkManager 管理 DNS
vim /etc/NetworkManager/NetworkManager.conf | |
# 在 [main] 下添加 | |
[main] | |
dns=none # 禁用 NM 管理 DNS | |
# 重启 NetworkManager | |
sudo systemctl restart NetworkManager |
再修改 /etc/resolv.conf ,不会被回刷
# container-runtime
container-runtime(容器运行时)是 Kubernetes 集群中负责管理容器生命周期(创建、启动、停止、销毁)的底层软件,需遵循 K8S 定义的容器运行时接口(CRI)标准,为 Pod 内的容器提供隔离的运行环境。常见的 container-runtime 包括:
- containerd:目前 K8S 默认推荐的容器运行时(从 1.24 版本起移除对 Docker 的直接支持),轻量且稳定,专注于容器生命周期管理;
- CRI-O:专为 K8S 设计的轻量级运行时,完全兼容 CRI 标准,无 Docker 依赖;
- Docker:早期主流运行时,因未原生实现 CRI(需通过 dockershim 适配),现已被 K8S 逐步弃用,实际底层依赖 containerd 提供容器运行能力。
以下介绍 docker 和 containerd 安装方法,任选一种即可
# docker
# 安装 docker
yum install -y \ | |
docker-ce-20.10.24 \ | |
docker-ce-cli-20.10.24 \ | |
containerd.io-1.6.20 \ | |
--nogpgcheck |
# 设置 docker 开机启动
[root@kubernetes-master ~]# systemctl start docker | |
[root@kubernetes-master ~]# systemctl enable docker | |
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service. | |
[root@kubernetes-master ~]# | |
[root@kubernetes-master ~]# docker version | |
Client: Docker Engine - Community | |
Version: 20.10.24 | |
API version: 1.41 | |
Go version: go1.19.7 | |
Git commit: 297e128 | |
Built: Tue Apr 4 18:22:57 2023 | |
OS/Arch: linux/amd64 | |
Context: default | |
Experimental: true | |
Server: Docker Engine - Community | |
Engine: | |
Version: 20.10.24 | |
API version: 1.41 (minimum version 1.12) | |
Go version: go1.19.7 | |
Git commit: 5d6db84 | |
Built: Tue Apr 4 18:21:02 2023 | |
OS/Arch: linux/amd64 | |
Experimental: false | |
containerd: | |
Version: 1.6.20 | |
GitCommit: 2806fc1057397dbaeefbea0e4e17bddfbd388f38 | |
runc: | |
Version: 1.1.5 | |
GitCommit: v1.1.5-0-gf19387a | |
docker-init: | |
Version: 0.19.0 | |
GitCommit: de40ad0 | |
[root@kubernetes-master ~]# |
# 配置镜像源 & 修改 cgroup
配置 docker 的镜像源,同时 Docker 的 cgroup 驱动改为 systemd,和 kubelet 一致
[root@kubernetes-master ~]# mkdir -p /etc/docker | |
[root@kubernetes-master ~]# vim /etc/docker/daemon.json | |
# /etc/docker/daemon.json | |
{ | |
"registry-mirrors": ["https://docker.1ms.run"], | |
"exec-opts": ["native.cgroupdriver=systemd"] | |
} | |
[root@kubernetes-master ~]# systemctl daemon-reload | |
[root@kubernetes-master ~]# systemctl restart docker | |
[root@kubernetes-master ~]# | |
# 验证 Docker 驱动已改为 systemd(输出必须是 systemd) | |
[root@kubernetes-master ~]# docker info | grep -i cgroup | |
Cgroup Driver: systemd | |
Cgroup Version: 1 |
# containerd
# 安装 containerd
# 安装依赖 | |
yum install -y yum-utils device-mapper-persistent-data lvm2 | |
# 配置 containerd yum 源 | |
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | |
# 安装 containerd | |
yum install -y containerd.io-1.6.20 --nogpgcheck |
# 配置 containerd
# 生成默认配置文件 | |
containerd config default > /etc/containerd/config.toml | |
# 修改配置:替换 sandbox 镜像(国内源)、设置 cgroup 驱动为 systemd、配置镜像加速 | |
vim /etc/containerd/config.toml | |
# 1. 替换 sandbox | |
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.6" | |
# 2. 配置镜像加速 | |
[plugins."io.containerd.grpc.v1.cri".registry.mirrors] | |
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] | |
endpoint = ["https://docker.1ms.run"] | |
# 3. 设置 cgroup 驱动为 systemd | |
sed -i's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml | |
# 启动并设置开机自启 containerd | |
systemctl start containerd | |
systemctl enable containerd | |
# 验证 containerd 版本(输出 1.6.20) | |
containerd --version | |
# 验证 cgroup 驱动(输出 SystemdCgroup = true) | |
grep -n "SystemdCgroup" /etc/containerd/config.toml |
修改 /etc/containerd/config.toml 的配置内容:
- 替换 sandbox 镜像(pause 镜像)地址:
[plugins."io.containerd.grpc.v1.cri".sandbox_image]将sandbox_image字段的"k8s.gcr.io/pause:3.6"替换为"registry.aliyuncs.com/google_containers/pause:3.6"
pause 镜像是 K8S 每个 Pod 的基础根容器,原地址k8s.gcr.io国内无法访问,替换为阿里云镜像源,保证 Pod 能正常创建。
设置
containerd的cgroup驱动为systemd:[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]段落的SystemdCgroup字段设置为true,让 containerd 的 cgroup 驱动和 kubelet 保持一致添加 Docker 镜像加速:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]段落下方新增镜像地址
[plugins."io.containerd.grpc.v1.cri".registry.mirrors] | |
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] | |
endpoint = ["https://docker.1ms.run"] # 新增的镜像加速地址 |
# 指定 sock 文件
K8s 1.24 及以上版本已移除 dockershim (Docker 与 K8s 的适配层),默认容器运行时改为 containerd ,但 crictl 的默认配置仍指向 dockershim.sock ,导致连接失败;需配置 crictl 指向 containerd 的正确套接字
# 创建 crictl 配置文件 | |
cat > /etc/crictl.yaml << EOF | |
runtime-endpoint: unix:///run/containerd/containerd.sock | |
image-endpoint: unix:///run/containerd/containerd.sock | |
timeout: 10 | |
debug: false | |
EOF | |
# 配置完成后,直接执行 crictl ps 即可正常输出(需要安装 kubernetes 才能使用 crictl) | |
[root@kubernetes-master ~]# crictl pull nginx:1.20.2 | |
Image is up to date for sha256:0584b370e957bf9d09e10f424859a02ab0fda255103f75b3f8c7d410a4e96ed5 | |
[root@kubernetes-master ~]# crictl pull busybox:1.31.1 | |
Image is up to date for sha256:1c35c441208254cb7c3844ba95a96485388cef9ccc0646d562c7fc026e04c807 | |
[root@kubernetes-master ~]# crictl pull mysql:8.0.32 | |
Image is up to date for sha256:412b8cc72e4a28e086097c3fcb1ca391beaefe86bc421a57bc53f7596461ce3b | |
[root@kubernetes-master ~]# crictl images ps | |
IMAGE TAG IMAGE ID SIZE | |
IMAGE TAG IMAGE ID SIZE | |
docker.io/library/busybox 1.31.1 1c35c44120825 765kB | |
docker.io/library/mysql 8.0.32 412b8cc72e4a2 157MB | |
docker.io/library/nginx 1.20.2 0584b370e957b 56.7MB |
# 安装 kubernetes
[root@kubernetes-master ~]# cat > /etc/yum.repos.d/kubernetes.repo << EOF | |
[kubernetes] | |
name=Kubernetes | |
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 | |
enabled=1 | |
gpgcheck=0 | |
repo_gpgcheck=0 | |
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-key.gpg | |
EOF | |
[root@kubernetes-master ~]# yum install -y kubelet-1.23.6 kubeadm-1.23.6 kubectl-1.23.6 | |
[root@kubernetes-master ~]# systemctl enable kubelet && systemctl start kubelet |
# 修改网络配置
可选配置,因为上述虚拟机由 vmware 创建,虚拟机网络模式为桥接模式,当主机网络发生变动时,K8S 节点网络也会出现问题,于是有以下方案:
将 master 节点设置两张网卡,一张用于网桥模式,一张仅主机模式,剩余 node 节点均为仅主机模式, master 配置网络转发和 dns 解析让 node 上网
在如下示例中,设置 K8S 的 master IP=10.0.0.10,node in 10.0.0.0/24
前置条件:关机所有虚拟机,将 node 的网络模式改为仅主机,master 设置两张网卡:网桥模式 + 仅主机模式
以下操作在 master 节点上进行
配置网络转发
# 临时开启(重启后失效) | |
echo 1 > /proc/sys/net/ipv4/ip_forward | |
# 永久开启(写入 sysctl 配置) | |
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf | |
sysctl -p |
配置 nat 规则
# 查看网卡,ens33 是仅主机模式,ens36 是共享主机网络 | |
[root@kubernetes-master ~]# nmcli device | |
DEVICE TYPE STATE CONNECTION | |
ens36 ethernet 已连接 ens36 | |
ens33 ethernet 已连接 ens33 | |
lo loopback 未托管 -- | |
# 配置 iptables NAT 规则,让 node 节点的流量通过外网接口转发出去,如果配置错误,将 - A 改为 - D 即可删除 | |
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o ens36 -j MASQUERADE | |
# 保存 iptables 规则(不同系统命令略有差异) | |
# CentOS/RHEL | |
iptables-save > /etc/sysconfig/iptables | |
# Ubuntu/Debian | |
iptables-save > /etc/iptables/rules.v4 | |
# 查看 nat 转发表 | |
iptables -t nat -L -n --line-numbers | |
# 查看 nat 表规则及流量统计 | |
iptables -t nat -L -n -v |
注意,在该测试环境下,K8S-node 需要借助 master 的 nat 转发上网,nat 每次开机都会回刷 nat 转发表,所以每次开机都需要配置 nat 转发,如果想规避此类操作。可以用一个软路由镜像实现上网
修改网卡配置
[root@kubernetes-node1 ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens33 | |
TYPE="Ethernet" | |
PROXY_METHOD="none" | |
BROWSER_ONLY="no" | |
BOOTPROTO="none" | |
DEFROUTE="yes" | |
IPV4_FAILURE_FATAL="no" | |
IPV6INIT="yes" | |
IPV6_AUTOCONF="yes" | |
IPV6_DEFROUTE="yes" | |
IPV6_FAILURE_FATAL="no" | |
IPV6_ADDR_GEN_MODE="stable-privacy" | |
NAME="ens33" | |
UUID="e89c2ca2-4307-4ae7-a4e8-8953b047d621" | |
DEVICE="ens33" | |
ONBOOT="yes" | |
IPADDR="10.0.0.11" | |
PREFIX="24" | |
GATEWAY="10.0.0.10" | |
DNS1="223.5.5.5" | |
IPV6_PRIVACY="no" |
# Master 节点初始化
- docker:在 Master 节点上进行初始化操作,docker 按照以下执行
[root@kubernetes-master ~]# kubeadm init --apiserver-advertise-address=192.168.0.200 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.23.6 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16 | |
# 安装完成后检查 | |
# 查看 kubelet 状态(应为 active (running)) | |
[root@kubernetes-master ~]# systemctl status kubelet | |
# 验证健康检查端口(10248 通) | |
[root@kubernetes-master ~]# curl -sSL http://localhost:10248/healthz # 输出 ok | |
# 查看控制平面容器(应有 kube-apiserver/etcd 等) | |
[root@kubernetes-master ~]# docker ps | grep kube |
- containerd:在 Master 节点上进行初始化操作,containerd 按照以下执行
# 初始化集群,指定 containerd 的套接字路径 | |
[root@kubernetes-master ~]# kubeadm init \ | |
--apiserver-advertise-address=10.0.0.10 \ | |
--image-repository registry.aliyuncs.com/google_containers \ | |
--kubernetes-version v1.23.6 \ | |
--service-cidr=10.96.0.0/12 \ | |
--pod-network-cidr=10.1.0.0/16 \ | |
--cri-socket=unix:///run/containerd/containerd.sock | |
# 查看 kubelet 状态(应为 active (running)) | |
[root@kubernetes-master ~]# systemctl status kubelet | |
# 验证健康检查端口(10248 通) | |
[root@kubernetes-master ~]# curl -sSL http://localhost:10248/healthz | |
# 查看控制平面容器(应有 kube-apiserver/etcd 等) | |
[root@kubernetes-master ~]# docker ps | grep kube |
参数示例如下
- --apiserver-advertise-address=10.0.0.10 \ # 指定 APIServer 对外通告的 IP
- --image-repository registry.aliyuncs.com/google_containers \ # 指定镜像仓库
- --kubernetes-version v1.23.6 \ # 指定 K8s 版本
- --service-cidr=10.96.0.0/12 \ # 指定 Service 网段
- --pod-network-cidr=10.1.0.0/16 \ # 指定 Pod 网段 -
- -cri-socket=unix:///run/containerd/containerd.sock # 指定 CRI 套接字路径
如果上述操作报错,按照如下流程处理
# 查看 kubelet 状态,大概率输出 active (failed) 或 inactive (dead) | |
systemctl status kubelet | |
# 查看详细日志 | |
journalctl -xeu kubelet | grep -i error | |
# 常见报错关键词: | |
- Failed to load kubelet config file /var/lib/kubelet/config.yaml: no such file or directory 第一次 init 失败后该文件未生成 / 被清理。 | |
- cgroup driver mismatch:Docker 和 kubelet 的 cgroup 驱动不一致; | |
- SELinux is enabled:SELinux 未关闭; | |
- read-only file system:文件系统权限问题; | |
- br_netfilter not loaded:内核模块未加载; | |
- port 10248 is in use:端口被占用(极少)。 | |
# 重置 kubeadm 残留状态(清理失败的 init 残留) | |
kubeadm reset -f # 强制重置,清空所有 k8s 残留配置 | |
rm -rf /var/lib/kubelet/* # 清空 kubelet 目录(包括无效配置) | |
rm -rf /etc/kubernetes/* # 清空 k8s 证书 / 配置目录 | |
# 修复 Docker 的 cgroup 驱动(改为 systemd,和 kubelet 一致) | |
cat > /etc/docker/daemon.json << EOF | |
{ | |
"registry-mirrors": ["https://docker.1ms.run"], | |
"exec-opts": ["native.cgroupdriver=systemd"] | |
} | |
EOF | |
# 重启 Docker 生效,验证 Docker 驱动已改为 systemd(输出必须是 systemd) | |
systemctl daemon-reload | |
systemctl restart docker | |
docker info | grep -i cgroup | |
# 关闭 swap(kubelet 强制要求) | |
swapoff -a | |
sed -i '/swap/s/^/#/' /etc/fstab # 永久关闭 | |
# 加载 br_netfilter 内核模块 | |
modprobe br_netfilter | |
echo "br_netfilter" > /etc/modules-load.d/k8s.conf | |
# 确保内核参数生效 | |
sysctl --system | |
# 关闭 SELinux 和防火墙 | |
setenforce 0 | |
sed -i's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config | |
systemctl stop firewalld && systemctl disable firewalld |
# Master 节点初始化配置
[root@kubernetes-master ~]# mkdir -p $HOME/.kube | |
[root@kubernetes-master ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config | |
[root@kubernetes-master ~]# chown $(id -u):$(id -g) $HOME/.kube/config |
# Node 节点加入 Master 节点
将从节点加入主节点:
- 在 Master 节点获取
kubeadm join命令(包含 token 和哈希值) - 在 Node 节点执行
kubeadm join命令,自动生成 kubelet 配置文件;kubeadm join会自动启动 kubelet 并加入集群。
token 仅用于 Node 节点首次加入集群时的身份验证,一旦 Node 节点成功加入集群并生成了本地证书(
/var/lib/kubelet/pki/),后续通信不再依赖 token—— 即使 token 过期,已加入的 Node 节点也能正常工作,无需重新 join。
# 在 master 上获取 `kubeadm join` 命令 | |
# 查看 token 时间 | |
[root@kubernetes-master ~]# kubeadm token list | |
# 方式 1:如果 Master 刚执行完 init,直接查看 | |
[root@kubernetes-master ~]# kubeadm token create --print-join-command | |
# 方式 2:如果 token 过期,重新生成永久 token(有效期 365 天) | |
[root@kubernetes-master ~]# kubeadm token create --ttl 0 # 生成永不过期 token | |
[root@kubernetes-master ~]# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed's/^.* //' # 获取 ca 哈希值 | |
# 在 node 节点上执行,join 命令(替换为 master 上的信息): | |
[root@kubernetes-node ~]# kubeadm join 192.168.0.200:6443 --token < 生成的 token> --discovery-token-ca-cert-hash sha256:<ca 哈希值 > |
在 Node 节点执行 kubeadm join 命令
[root@kubernetes-node2 ~]# kubeadm join 192.168.0.200:6443 --token ah7f8n.4buw5tt3edn876ro --discovery-token-ca-cert-hash sha256:583c34ccb826e29c604bb4a1e204251ed0854e0fb37607c1f0153f4cc8f6dfdb | |
[preflight] Running pre-flight checks | |
[preflight] Reading configuration from the cluster... | |
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' | |
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" | |
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" | |
[kubelet-start] Starting the kubelet | |
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... | |
This node has joined the cluster: | |
* Certificate signing request was sent to apiserver and a response was received. | |
* The Kubelet was informed of the new secure connection details. | |
Run 'kubectl get nodes' on the control-plane to see this node join the cluster. | |
[root@kubernetes-node2 ~]# |
在 master 节点上查看
[root@kubernetes-master ~]# kubectl get nodes | |
NAME STATUS ROLES AGE VERSION | |
kubernetes-master NotReady control-plane,master 80m v1.23.6 | |
kubernetes-node1 NotReady <none> 22m v1.23.6 | |
kubernetes-node2 NotReady <none> 109s v1.23.6 | |
[root@kubernetes-master ~]# |
# 部署 CNI 网络插件
在主节点上使用 kubectl get no 查看 node 状态,可以发现状态均为 NotReady ,现在先使用 kubectl 做一些基础检查
排查发现,当前集群所有节点 NotReady , coredns 处于 Pending 状态,核心原因是未部署网络插件(flannel/calico),K8s 集群必须部署网络插件才能完成节点网络初始化、Pod 网络分配,进而让节点进入 Ready 状态、 coredns 调度运行。
# 查看 node 信息 | |
[root@kubernetes-master ~]# kubectl get nodes | |
NAME STATUS ROLES AGE VERSION | |
kubernetes-master NotReady control-plane,master 96m v1.23.6 | |
kubernetes-node1 NotReady <none> 38m v1.23.6 | |
kubernetes-node2 NotReady <none> 17m v1.23.6 | |
# 查看组件状态,此为 kubectl get componentstatus 的缩写 | |
[root@kubernetes-master ~]# kubectl get cs | |
Warning: v1 ComponentStatus is deprecated in v1.19+ | |
NAME STATUS MESSAGE ERROR | |
scheduler Healthy ok | |
controller-manager Healthy ok | |
etcd-0 Healthy {"health":"true","reason":""} | |
[root@kubernetes-master ~]# | |
# 查看命名空间 | |
[root@kubernetes-master ~]# kubectl get namespaces | |
NAME STATUS AGE | |
default Active 94m | |
kube-node-lease Active 94m | |
kube-public Active 94m | |
kube-system Active 94m | |
# 查看 kube-system 下的 pod 信息 | |
[root@kubernetes-master ~]# kubectl get pod -n kube-system | |
NAME READY STATUS RESTARTS AGE | |
coredns-6d8c4cb4d-2jffp 0/1 Pending 0 94m | |
coredns-6d8c4cb4d-lwcpw 0/1 Pending 0 94m | |
etcd-kubernetes-master 1/1 Running 1 (86m ago) 95m | |
kube-apiserver-kubernetes-master 1/1 Running 1 (86m ago) 95m | |
kube-controller-manager-kubernetes-master 1/1 Running 1 (86m ago) 95m | |
kube-proxy-2dd5k 1/1 Running 0 37m | |
kube-proxy-8tcp2 1/1 Running 1 (86m ago) 94m | |
kube-proxy-dljq6 1/1 Running 0 16m | |
kube-scheduler-kubernetes-master 1/1 Running 1 (86m ago) 95m | |
[root@kubernetes-master ~]# |
# flannel
下载 flannel 配置文件
[root@kubernetes-master ~]# mkdir /opt/k8s | |
[root@kubernetes-master ~]# mkdir /opt/k8s/flannel | |
[root@kubernetes-master ~]# cd /opt/k8s/flannel/ | |
[root@kubernetes-master flannel]# curl -o kube-flannel.yml https://raw.githubusercontent.com/flannel-io/flannel/v0.19.0/Documentation/kube-flannel.yml |
查看配置文件中使用的镜像源
# 配置文件里实际生效的镜像是国内 rancher 源,无需替换 | |
[root@kubernetes-master flannel]# grep -n "image:" kube-flannel.yml | grep -v "#" | |
126: image: rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0 | |
138: image: rancher/mirrored-flannelcni-flannel:v0.18.1 | |
153: image: rancher/mirrored-flannelcni-flannel:v0.18.1 |
部署网络插件
[root@kubernetes-master flannel]# kubectl apply -f kube-flannel.yml |
验证 flannel 部署状态
# 查看 flannel 命名空间下的 DaemonSet(期望数 = 节点数,当前数逐步匹配) | |
[root@kubernetes-master flannel]# kubectl get ds -n kube-flannel | |
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE | |
kube-flannel-ds 3 3 0 3 0 <none> 9s | |
# 查看 flannel Pod(等待 30 秒,状态变为 Running) | |
[root@kubernetes-master flannel]# kubectl get pods -n kube-flannel | |
NAME READY STATUS RESTARTS AGE | |
kube-flannel-ds-qqg7p 1/1 Running 0 2m34s | |
kube-flannel-ds-vt655 1/1 Running 0 2m34s | |
kube-flannel-ds-zj5xl 1/1 Running 0 2m34s | |
# 等待 1-2 分钟(flannel 配置节点网络需要时间),查看集群节点状态 | |
[root@kubernetes-master flannel]# kubectl get nodes | |
NAME STATUS ROLES AGE VERSION | |
kubernetes-master Ready control-plane,master 129m v1.23.6 | |
kubernetes-node1 Ready <none> 71m v1.23.6 | |
kubernetes-node2 Ready <none> 50m v1.23.6 | |
# 查看 pods 状态(coredns 从 Pending → Running) | |
[root@kubernetes-master flannel]# kubectl get pods -n kube-system | |
NAME READY STATUS RESTARTS AGE | |
coredns-6d8c4cb4d-2jffp 1/1 Running 0 134m | |
coredns-6d8c4cb4d-lwcpw 1/1 Running 0 134m | |
etcd-kubernetes-master 1/1 Running 1 (126m ago) 134m | |
kube-apiserver-kubernetes-master 1/1 Running 1 (126m ago) 134m | |
kube-controller-manager-kubernetes-master 1/1 Running 1 (126m ago) 134m | |
kube-proxy-2dd5k 1/1 Running 0 76m | |
kube-proxy-8tcp2 1/1 Running 1 (126m ago) 134m | |
kube-proxy-dljq6 1/1 Running 0 55m | |
kube-scheduler-kubernetes-master 1/1 Running 1 (126m ago) 134m |
# calico
下载 calico 配置文件
# 下载 Calico 3.25.0 的部署文件(适配 K8S 1.23) | |
wget https://docs.projectcalico.org/v3.25/manifests/calico.yaml |
编辑 yaml 文件,设置 pod 网段
# 搜索环境变量部分,修改或确认如下 | |
- name: CALICO_IPV4POOL_CIDR | |
value: "10.1.0.0/16" # 必须和 K8S 的 podSubnet 一致 |
如果有多张网卡,设置强制让 calico 选择某网卡进行通信
- name: CLUSTER_TYPE | |
value: "k8s,bgp" | |
# 新增如下内容 | |
- name: IP_AUTODETECTION_METHOD | |
value: "interface=ens33" |
部署网络插件
# 执行部署 | |
kubectl apply -f calico.yaml | |
# 查看 Calico Pod 状态(需全部 Running) | |
kubectl get pods -n kube-system | grep calico | |
# 如果长时间没有 running,铲除掉 yaml 创建出的资源,修改 yaml 的镜像配置 | |
kubectl delete -f calico.yaml |
# 运行测试
创建一个简单的 nginx 服务,测试 kubernetes 集群
# 创建 nginx 服务 | |
[root@kubernetes-master ~]# kubectl create deployment nginx --image=nginx | |
deployment.apps/nginx created | |
# 暴露端口 | |
[root@kubernetes-master ~]# kubectl expose deployment nginx --port=80 --type=NodePort | |
service/nginx exposed | |
# 查看 pod 和 service 信息 | |
[root@kubernetes-master ~]# kubectl get pod | |
NAME READY STATUS RESTARTS AGE | |
nginx-85b98978db-lhmzl 1/1 Running 0 20s | |
[root@kubernetes-master ~]# kubectl get pod,svc | |
NAME READY STATUS RESTARTS AGE | |
pod/nginx-85b98978db-lhmzl 1/1 Running 0 24s | |
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT (S) AGE | |
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3h20m | |
service/nginx NodePort 10.101.21.137 <none> 80:32639/TCP 13s |
# 错误排查
在创建 nginx 容器时,我们发现 pod 状态为 ImagePullBackOff ,使用 kubectl describe 可以查看详情信息,根据如下信息,可以看出是因为 docker 一直在拉取 "nginx" 镜像,可能是网络原因导致。
[root@kubernetes-master ~]# kubectl get pod | |
NAME READY STATUS RESTARTS AGE | |
nginx-85b98978db-xmx57 0/1 ImagePullBackOff 0 9m2s | |
[root@kubernetes-master ~]# kubectl describe pod nginx-85b98978db-xmx57 | |
Name: nginx-85b98978db-xmx57 | |
Namespace: default | |
Priority: 0 | |
Service Account: default | |
Node: kubernetes-node1/192.168.0.201 | |
Start Time: Sun, 21 Dec 2025 22:56:37 +0800 | |
Labels: app=nginx | |
pod-template-hash=85b98978db | |
Annotations: <none> | |
Status: Pending | |
IP: 10.244.1.2 | |
IPs: | |
IP: 10.244.1.2 | |
Controlled By: ReplicaSet/nginx-85b98978db | |
Containers: | |
nginx: | |
Container ID: | |
Image: nginx | |
Image ID: | |
Port: <none> | |
Host Port: <none> | |
State: Waiting | |
Reason: ImagePullBackOff | |
Ready: False | |
Restart Count: 0 | |
Environment: <none> | |
Mounts: | |
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-zcrdc (ro) | |
Conditions: | |
Type Status | |
Initialized True | |
Ready False | |
ContainersReady False | |
PodScheduled True | |
Volumes: | |
kube-api-access-zcrdc: | |
Type: Projected (a volume that contains injected data from multiple sources) | |
TokenExpirationSeconds: 3607 | |
ConfigMapName: kube-root-ca.crt | |
ConfigMapOptional: <nil> | |
DownwardAPI: true | |
QoS Class: BestEffort | |
Node-Selectors: <none> | |
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s | |
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s | |
Events: | |
Type Reason Age From Message | |
---- ------ ---- ---- ------- | |
Normal Scheduled 9m29s default-scheduler Successfully assigned default/nginx-85b98978db-xmx57 to kubernetes-node1 | |
Warning Failed 58s kubelet Failed to pull image "nginx": rpc error: code = Unknown desc = context canceled | |
Warning Failed 58s kubelet Error: ErrImagePull | |
Normal BackOff 57s kubelet Back-off pulling image "nginx" | |
Warning Failed 57s kubelet Error: ImagePullBackOff | |
Normal Pulling 42s (x2 over 9m28s) kubelet Pulling image "nginx" | |
[root@kubernetes-master ~]# |
# 删除 Deployment
如果需要删除 nginx Deployment,可以使用
kubectl delete deployment nginx |
删除 Deployment 后,Pod 显示 Terminating 状态但未消失,是因为 K8s 的 优雅终止机制(默认等待 30 秒),或 Pod 存在「终止阻塞」(如镜像拉取进程未退出、网络资源未释放)。如果需要强制删除
# --grace-period=0:跳过 30 秒优雅等待,立即终止;--force:强制删除(针对卡住的 Pod)。 | |
kubectl delete pod nginx-85b98978db-xmx57 --force --grace-period=0 | |
# 清理残留的 Service | |
kubectl delete svc nginx |
# 手动加载镜像
针对上述 nginx 拉取慢的问题,我们可以尝试在 master 节点先拉取镜像,然后将 master 的镜像通过 scp 传入各 node 节点
在 Master 节点拉取镜像并保存
# 拉取 nginx 镜像 | |
docker pull nginx:latest | |
# 保存镜像为压缩包 | |
docker save nginx:alpine > nginx.tar |
拷贝镜像到所有 Node 节点
scp nginx.tar root@kubernetes-node1:/opt/ | |
scp nginx.tar root@kubernetes-node2:/opt/ |
在每个 Node 节点加载镜像
# 登录 node1 执行 | |
docker load < /opt/nginx.tar | |
# 登录 node2 执行 | |
docker load < /opt/nginx.tar |
# 转发流量详解
通过 docker ps 可以看到,仅在 node2 上才有 nginx 的 pod,那为什么访问 3 台设备的对应端口都能看到 nginx 页面呢?原因是 K8s 的 kube-proxy 组件 + 网络插件(flannel) 共同实现的「集群级端口转发 + 跨节点网络互通」,这也是 K8s 区别于单机 Docker 的核心特性。
我们可以将流量走向拆分为三步:
NodePort 服务提供集群级端口暴露
示例中创建的 NodePort 类型 Service 不是 “绑定某一个节点的端口”,而是:
- K8s 会在集群所有节点(Master/Node1/Node2)上监听同一个 NodePort 端口;
- 这个端口由每个节点上的
kube-proxy进程负责监听(在所有节点用ss -tnlp | grep < 端口号 >能看到 kube-proxy 监听); - 无论访问哪个节点的这个端口,
kube-proxy都会把请求转发到 nginx Pod 所在的节点(Node2)。
# kube-proxy 监听所有节点的 NodePort | |
[root@kubernetes-master ~]# ss -tnlp | grep 32639 | |
LISTEN 0 128 *:32639 *:* users:(("kube-proxy",pid=2526,fd=13)) |
kube-proxy 的转发逻辑(iptables/IPVS 模式)
K8s 默认用 iptables 模式实现 Service 转发,核心逻辑:
- 当用户访问
192.168.0.200:30773(Master):- Master 节点的
kube-proxy已通过 K8s API Server 知道 nginx Pod 运行在 Node2(IP:10.244.2.2); kube-proxy预先在 Master 节点的 iptables 中配置了转发规则:将访问 30773 端口的流量,转发到 nginx Pod 的 IP:80(10.244.2.2:80)。
- Master 节点的
- 同理,访问
192.168.0.201:30773(Node1)时:- Node1 的
kube-proxy也会通过 iptables 规则,把流量转发到 Node2 上的 nginx Pod。
- Node1 的
# 基于 iptables 规则的分层的逻辑, KUBE-SERVICES 会把 NodePort 流量转发到 KUBE-NODEPORTS 链 | |
[root@kubernetes-master ~]# iptables -t nat -L KUBE-SERVICES | |
Chain KUBE-SERVICES (2 references) | |
target prot opt source destination | |
KUBE-SVC-2CMXP7HKUVJN7L6M tcp -- anywhere 10.101.21.137 /* default/nginx cluster IP */tcp dpt:http | |
KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- anywhere 10.96.0.1 /* default/kubernetes:https cluster IP */tcp dpt:https | |
KUBE-SVC-TCOU7JCQXEZGVUNU udp -- anywhere 10.96.0.10 /* kube-system/kube-dns:dns cluster IP */udp dpt:domain | |
KUBE-SVC-ERIFXISQEP7F7OF4 tcp -- anywhere 10.96.0.10 /* kube-system/kube-dns:dns-tcp cluster IP */tcp dpt:domain | |
KUBE-SVC-JD5MR3NA4I4DYORP tcp -- anywhere 10.96.0.10 /* kube-system/kube-dns:metrics cluster IP */tcp dpt:9153 | |
KUBE-NODEPORTS all -- anywhere anywhere /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL | |
# 进一步查看 KUBE-NODEPORTS 链,确认会将访问 32639 端口的流量转发到 KUBE-SVC-2CMXP7HKUVJN7L6M 链,最终指向 nginx Pod 的 IP:80)。 | |
[root@kubernetes-master ~]# iptables -t nat -L KUBE-NODEPORTS | |
Chain KUBE-NODEPORTS (1 references) | |
target prot opt source destination | |
KUBE-SVC-2CMXP7HKUVJN7L6M tcp -- anywhere anywhere /* default/nginx */tcp dpt:32639 |
flannel 保证跨节点网络互通
转发的流量要能从 Master/Node1 到达 Node2 上的 nginx Pod,依赖 flannel 实现的「Pod 网络互通」:
- flannel 会为每个节点分配一个 Pod 网段(比如 Node2 是 10.244.2.0/24),并在所有节点配置路由规则;
- 当 Master/Node1 要访问 Node2 上的 Pod IP(10.244.2.2)时,flannel 会通过 VXLAN 隧道(基于节点间的物理网络),把流量封装后发送到 Node2;
- Node2 收到流量后解封装,转发到本地的 nginx Pod。
# Node2 的 Pod 网段(10.244.2.0/24),Master 访问该网段的流量会通过 flannel.1 转发到 Node2 | |
[root@kubernetes-master ~]# route -n | |
Kernel IP routing table | |
Destination Gateway Genmask Flags Metric Ref Use Iface | |
0.0.0.0 192.168.0.1 0.0.0.0 UG 100 0 0 ens33 | |
10.244.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0 | |
10.244.1.0 10.244.1.0 255.255.255.0 UG 0 0 0 flannel.1 | |
10.244.2.0 10.244.2.0 255.255.255.0 UG 0 0 0 flannel.1 | |
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 | |
192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33 |
# 在任意节点使用 kubectl
根据 k8s 架构, kubectl 实际上是在通过 api-server 接口调用 k8s 服务,即 kubectl 命令实际上是在访问 api-server ,上述操作完成后,在 node 节点上使用 kubectl 我们能看到如下输出
[root@localhost containerd]# kubectl get node | |
The connection to the server localhost:8080 was refused - did you specify the right host or port? |
因为在 master 节点初始化时,我们已经在 ~/.kube/config 文件中写入了关于 kubernetes 的配置信息,为了让从节点也能使用 kubectl ,我们还需要做以下操作
将 master 节点中
/etc/kuber/admin.config拷贝到从节点对应目录下在从节点上配置环境变量
# 使用 scp 将配置文件由主节点(192.168.0.200)拷贝到从节点 | |
[root@kubernetes-node1 ~]# scp root@10.0.0.11:/etc/kubernetes/admin.conf/etc/kubernetes/admin.conf | |
admin.conf 100% 5641 5.4MB/s 00:00 | |
[root@kubernetes-node1 ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile | |
[root@kubernetes-node1 ~]# source ~/.bash_profile | |
[root@kubernetes-node1 ~]# kubectl get node | |
NAME STATUS ROLES AGE VERSION | |
kubernetes-master Ready control-plane,master 8d v1.23.6 | |
kubernetes-node1 Ready <none> 8d v1.23.6 | |
kubernetes-node2 Ready <none> 8d v1.23.6 |
# NFS
NFS (Network File System,网络文件系统)是基于 TCP/IP 协议的应用,可以通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。
NFS 在文件传送或信息传送过程中依赖于 RPC 服务。
RPC (Remote Procedure Call,远程过程调用) 是能使客户端执行其他系统中程序的一种机制。
NFS 服务器可以看作是一个 FILE SERVER。它可以让客户端通过网络将远端的 NFS SERVER 共享目录 MOUNT 到自己的系统中。
# 安装 NFS
本次示例是测试环境,直接以 master 节点作为 NFS 的服务端(作为文件共享服务器),node 节点为客户端
服务端配置
- 安装 nfs 相关软件包
yum install -y nfs-utils rpcbind |
- 创建存放数据的目录(共享目录)
mkdir -p /data/nfs-share | |
chmod 755 /data/nfs-share # 根据需求修改 | |
chown -R nobody:nobody /data/nfs-share # 匹配 NFS 默认匿名用户 |
- 修改配置文件
格式: 共享目录 允许访问的网段 / IP (权限参数)
10.0.0.0/8 表示允许该网段所有节点访问(根据实际集群网段调整)
cat > /etc/exports << EOF | |
/data/nfs-share 10.0.0.0/8 (rw,sync,no_root_squash,no_subtree_check,insecure) | |
EOF |
参数说明:
rw:客户端拥有读写权限;ro:客户端只读权限,根据需求可选 rw 或 ro;sync:数据同步写入磁盘(保证数据不丢失,性能略低);no_root_squash:客户端 root 用户访问时,保留 root 权限(测试环境可用,生产慎用)。no_subtree_check:关闭子目录检查,提升 NFS 稳定性(K8s 推荐加)insecure:允许客户端从非特权端口(大于 1024)访问(K8s 环境必备);
- 启动 nfs 服务端
systemctl start rpcbind | |
systemctl start nfs-server | |
systemctl enable rpcbind | |
systemctl enable nfs-server |
- 验证是否已经共享了文件
[root@kubernetes-master data]# exportfs | |
/data/nfs-share | |
10.0.0.0/8 |
- 上述检查无误后,应用配置
exportfs -arv |
客户端配置(每个节点都需要配置)
- 安装 nfs 客户端,设置开机自启
yum install -y nfs-utils rpcbind | |
systemctl start rpcbind | |
systemctl start nfs-server | |
systemctl enable rpcbind | |
systemctl enable nfs-server |
- 客户端节点访问 NFS 服务端
[root@kubernetes-node1 ~]# showmount -e 10.0.0.10 | |
Export list for 10.0.0.10: | |
/data/nfs-share 10.0.0.0/8 |
# 挂载 NFS
示例:将 NFS 挂载到客户端
查询 NFS 服务端的共享列表
[root@kubernetes-node1 ~]# showmount -e 10.0.0.10 | |
Export list for 10.0.0.10: | |
/data/nfs-share 10.0.0.0/8 |
临时挂载
# 1. 创建本地挂载点目录 | |
mkdir -p /mnt/nfs-share | |
# 2. 临时挂载(重启后失效) | |
mount -t nfs 10.0.0.10:/data/nfs-share/mnt/nfs-share | |
# 3. 验证挂载是否成功 | |
[root@kubernetes-node1 ~]# df -h | grep nfs-share | |
10.0.0.10:/data/nfs-share 17G 6.1G 11G 36% /mnt/nfs-share | |
[root@kubernetes-node1 ~]# mount | grep nfs-share | |
10.0.0.10:/data/nfs-share on /mnt/nfs-share type nfs4 (rw,relatime,vers=4.1,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.11,local_lock=none,addr=10.0.0.10) |
永久挂载,需要将挂载信息写入 /etc/fstab
# 创建本地挂载点目录 | |
mkdir -p /mnt/nfs-share | |
# 永久挂载(写入 /etc/fstab,重启后自动挂载) | |
echo "10.0.0.10:/data/nfs-share/mnt/nfs-share nfs defaults 0 0" >> /etc/fstab | |
# 验证 fstab 配置是否正确(无报错即正常) | |
mount -a |
卸载
如果之前将 NFS 写入了 /etc/fstab 实现永久挂载,卸载后必须删除这行配置,否则系统重启时会报错
# 方式 1:通过挂载点卸载(最常用、最稳妥) | |
umount /mnt/nfs-share | |
# 方式 2:通过 NFS 服务端路径卸载(备选) | |
umount 10.0.0.10:/data/nfs-share |
# Helm 安装
Helm 是 Kubernetes(K8s)的官方包管理器,类比于 Linux 系统的 apt/yum (Debian/Ubuntu/CentOS 包管理)、Python 的 pip 、Node.js 的 npm —— 它将 Kubernetes 中分散的多个资源(Deployment、Service、ConfigMap、Ingress 等)打包成一个可复用的 “软件包”(称为 Chart),解决了手动管理 K8s YAML 配置的痛点,实现应用的一键部署、版本升级、回滚、卸载。
# 安装 Helm
安装 Helm 可以参考 Helm 官方文档,此处选择兼容 K8s 1.23 的 Helm3 稳定版本(如 v3.14.0),适配 linux/amd64 架构
- 下载 heml:
wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz - 解压
tar -zxvf helm-v3.2.3-linux-amd64.tar.gz - 将解压目录下的程序移动到
/usr/local/bin - 添加阿里云 heml 仓库
[root@kubernetes-master ~]# mkdir helm | |
[root@kubernetes-master ~]# cd helm/ | |
# 下载 heml | |
[root@kubernetes-master helm]# wget https://get.helm.sh/helm-v3.14.0-linux-amd64.tar.gz | |
--2026-01-11 18:17:26-- https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz | |
正在解析主机 get.helm.sh (get.helm.sh)... 13.107.213.74, 13.107.246.74, 2620:1ec:46::73, ... | |
正在连接 get.helm.sh (get.helm.sh)|13.107.213.74|:443... 已连接。 | |
已发出 HTTP 请求,正在等待回应... 200 OK | |
长度:12924654 (12M) [application/x-tar] | |
正在保存至: “helm-v3.2.3-linux-amd64.tar.gz” | |
# 解压 | |
[root@kubernetes-master helm]# tar -zxvf helm-v3.2.3-linux-amd64.tar.gz | |
linux-amd64/ | |
linux-amd64/README.md | |
linux-amd64/LICENSE | |
linux-amd64/helm | |
[root@kubernetes-master helm]# ls | |
helm-v3.2.3-linux-amd64.tar.gz linux-amd64 | |
# 将 heml 程序移动到 /usr/local/bin | |
[root@kubernetes-master helm]# cd linux-amd64/ | |
[root@kubernetes-master linux-amd64]# ls | |
helm LICENSE README.md | |
[root@kubernetes-master linux-amd64]# cp helm /usr/local/bin/ |
设置 helm 自动补全
$ source < (helm completion bash) | |
$ echo'source <(helm completion bash)' >> ~/.bashrc | |
$ KUBECONFIG=/root/.kube/config |