外观
k8s 学习指南
一、搭建 Kubernetes 集群
1. kubeadm搭建
安装 kubeadm 展示了如何安装 kubeadm 的过程。一旦安装了 kubeadm, 你就可以使用它来创建一个集群。
服务器要求
3 台服务器(虚拟机)
服务器名称 ip地址 硬件情况 备注 nightingale 10.101.143.150 8核16G,100G系统盘、100G数据盘 夜莺系统 ragflow 10.101.143.151 8核16G,100G系统盘、100G数据盘 知识库、netbox dify 10.101.143.152 4核8G,100G系统盘、100G数据盘 主节点,dify 三台服务器处于同一网段,网络互通。
软件环境
- 操作系统:Rocky 9.4
- Docker:20+
- k8s:1.32.2
2. 安装步骤
2.1 初始化操作
关闭防火墙
bashsystemctl stop firewalld systemctl disable firewalld1
2关闭selinux
bashsed -i 's/enforcing/disabled/' /etc/selinux/config # 永久 setenforce 0 # 临时1
2关闭swap (关闭完swap后,一定要重启一下虚拟机!!!)
bashswapoff -a # 临时 sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久1
2根据规划设置主机名
bashhostnamectl set-hostname nightingale hostnamectl set-hostname ragflow hostnamectl set-hostname dify # 直接运行下面的命令,记得将IP地址修改为自己机器的IP地址,主机名字也换成自己的 cat >> /etc/hosts << EOF 10.101.143.150 nightingale 10.101.143.151 ragflow 10.101.143.152 dify EOF1
2
3
4
5
6
7
8
9
10- 将桥接的IPv4流量传递到iptables的链
bashcat > /etc/sysctl.d/k8s.conf << EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system # 生效1
2
3
4
5
6- 时间同步
bashyum install ntpdate -y ntpdate time.windows.com1
2- 数据盘格式化和挂载(这三台主机是同步操作的)
bash[root@nightingale ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 100G 0 disk ├─sda1 8:1 0 600M 0 part /boot/efi ├─sda2 8:2 0 1G 0 part /boot └─sda3 8:3 0 98.4G 0 part ├─rl-root 253:0 0 60.8G 0 lvm / ├─rl-swap 253:1 0 7.9G 0 lvm └─rl-home 253:2 0 29.7G 0 lvm /home sdb 8:16 0 100G 0 disk sr0 11:0 1 1024M 0 rom #创建lvm逻辑卷 [root@nightingale /]# pvcreate /dev/sdb Physical volume "/dev/sdb" successfully created. [root@nightingale /]# vgcreate docker /dev/sdb Volume group "docker" successfully created [root@nightingale /]# lvcreate -l 100%FREE -n lv-docker docker Logical volume "lv-docker" created. #格式化数据盘 [root@nightingale /]# mkfs.xfs /dev/mapper/docker-lv--docker meta-data=/dev/mapper/docker-lv--docker isize=512 agcount=4, agsize=6553344 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=0 = reflink=1 bigtime=1 inobtcount=1 nrext64=0 data = bsize=4096 blocks=26213376, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=16384, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 Discarding blocks...Done. #临时挂载 [root@nightingale /]# mount /dev/mapper/docker-lv--docker /docker #永久挂载 [root@nightingale /]# echo "/dev/mapper/docker-lv--docker /docker xfs defaults 0 0" >> /etc/fstab [root@nightingale /]# systemctl daemon-reload [root@nightingale /]# mount -a [root@nightingale /]# df -Th Filesystem Type Size Used Avail Use% Mounted on devtmpfs devtmpfs 4.0M 0 4.0M 0% /dev tmpfs tmpfs 7.7G 0 7.7G 0% /dev/shm tmpfs tmpfs 3.1G 8.7M 3.1G 1% /run /dev/mapper/rl-root xfs 61G 2.0G 59G 4% / /dev/sda2 xfs 960M 218M 743M 23% /boot /dev/sda1 vfat 599M 7.1M 592M 2% /boot/efi /dev/mapper/rl-home xfs 30G 244M 30G 1% /home tmpfs tmpfs 1.6G 0 1.6G 0% /run/user/0 /dev/mapper/docker-lv--docker xfs 100G 746M 100G 1% /docker1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2.2 安装基础软件(所有节点)
添加清华的kubernetes源,具体要安装哪个版本把下面的v1.32修改一下就好。
bashcat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=kubernetes baseurl=https://mirrors.tuna.tsinghua.edu.cn/kubernetes/yum/repos/kubernetes-el7- name=Kubernetes baseurl=https://mirrors.tuna.tsinghua.edu.cn/kubernetes/core:/stable:/v1.32/rpm/ enabled=1 gpgcheck=1 gpgkey=https://mirrors.tuna.tsinghua.edu.cn/kubernetes/core:/stable:/v1.32/rpm/repodata/repomd.xml.key EOF1
2
3
4
5
6
7
8
9
10- 安装docker
bash#下载对应工具,方便直接下载docekr的repo sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #下载docker,默认下载最新(ce是社区版本,免费) sudo yum -y install docker-ce #启动docker并设置自启动 sudo systemctl start docker sudo systemctl enable docker #配置docker镜像加速器,默认官方镜像下载,所以为了提高下载速度,修改为国外镜像下载源 sudo tee /etc/docker/daemon.json <<'EOF' { "data-root": "/docker/docker_data/", "exec-opts": ["native.cgroupdriver=systemd"], "registry-mirrors": [ "https://docker.1panel.live", "https://hub.mirrorify.net", "https://docker.m.daocloud.io", "https://registry.dockermirror.com", "https://docker.aityp.com/", "https://docker.anyhub.us.kg", "https://dockerhub.icu", "https://docker.awsl9527.cn" ] } EOF #使配置文件生效和重启docker sudo systemctl daemon-reload sudo systemctl restart docker1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30安装kubeadm、kubelet、kubectl
bashyum install -y kubelet-1.32.3 kubeadm-1.32.3 kubectl-1.32.3 systemctl enable kubelet #查看需要安装哪些镜像 kubeadm config images list --kubernetes-version=v1.32.3 # 配置关闭 Docker 的 cgroups,修改 /etc/docker/daemon.json,加入以下内容,此步已经在上面配置好了。 "exec-opts": ["native.cgroupdriver=systemd"] # 重启 docker systemctl daemon-reload systemctl restart docker1
2
3
4
5
6
7
8
9
10
11
12
13- bash
#安装go环境, Go 环境到至少 1.23.7 才能成功编译cri-dockerd项目 wget https://mirrors.aliyun.com/golang/go1.24.2.linux-amd64.tar.gz tar -zxvf go1.24.2.linux-amd64.tar.gz -C /usr/bin/ export PATH=$PATH:/usr/bin/go/bin source ~/.bashrc1
2
3
4
5bash#编译安装cri-dockerd git clone https://github.com/Mirantis/cri-dockerd.git cd cri-dockerd mkdir bin go build -o bin/cri-dockerd mkdir -p /usr/local/bin install -o root -g root -m 0755 bin/cri-dockerd /usr/local/bin/cri-dockerd cp -a packaging/systemd/* /etc/systemd/system sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service #需要进入文件将ExecStart的内容追加--network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 ExecStart=/usr/local/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.91
2
3
4
5
6
7
8
9
10
11
12- /etc/systemd/system/cri-docker.service配置文件修改后的具体内容
bash[root@dify ~]# cat /etc/systemd/system/cri-docker.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 --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 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.target1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40- [Kubeadm初始化遇到的坑:[ERROR CRI]: container runtime is not running:-CSDN博客](https://blog.csdn.net/realize_dream/article/details/127284864#:~:text=需要追加–network-plugin%3Dcni,通过该配置告诉容器,使用kubernetes的网络接口。 %23 追加 ExecStart%3D%2Fusr%2Flocal%2Fbin%2Fcri-dockerd --container-runtime-endpoint,fd%3A%2F%2F --network-plugin %3Dcni --pod-infra-container-image %3Dkubebiz%2Fpause%3A3.8)
bash# 启动 systemctl daemon-reload systemctl enable cri-docker.service systemctl enable --now cri-docker.socket systemctl restart docker systemctl restart cri-docker # 验证 systemctl status docker systemctl status cri-docker systemctl status kubelet1
2
3
4
5
6
7
8
9
10- 重要配置文件的检查
bash#cri-docker的自启动配置文件 /etc/systemd/system/cri-docker.service #docker的配置文件 /etc/docker/daemon.json #kubelet的配置文件 /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf1
2
3
4
5
6- 如果crictl ps有问题,那么就需要修改相关配置文件
bashcat << EOF | tee /etc/crictl.yaml runtime-endpoint: "unix:///var/run/cri-dockerd.sock" timeout: 0 debug: false EOF1
2
3
4
5- 重置k8s环境
bash#如果init初始化过程中有问题,需要重置 # 执行kubeadm reset kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock --force # 手动删除所有kubernetes相关配置文件 rm -rf /etc/kubernetes/ rm -rf /var/lib/kubelet/ rm -rf /var/lib/etcd/ rm -rf $HOME/.kube/ # 如果有必要可以重新安装相关k8s相关软件 #yum remove -y kubelet kubeadm kubectl #yum install -y kubelet kubeadm kubectl #重启 systemctl daemon-reload systemctl restart docker systemctl restart cri-docker systemctl restart kubelet1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2.3 部署 Kubernetes Master
bash
# 在 Master 节点下执行
kubeadm init \
--apiserver-advertise-address=10.101.143.152 \
--kubernetes-version v1.32.3 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers \
--cri-socket unix:///var/run/cri-dockerd.sock \
--v=9
# 安装成功后,复制如下配置并执行
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2.4 加入 Kubernetes Node
bash
#分别在 k8s-node1 和 k8s-node2 执行
# 下方命令可以在 k8s master 控制台初始化成功后复制 join 命令
kubeadm join 10.101.143.152:6443 --token z8rhe5.mlt3b0iwhqrtelm6 \
--discovery-token-ca-cert-hash sha256:5938fe9136b3e774c4c0733b5d27accc6e34dec95917934f7831e97abc9b4683 \
--cri-socket unix:///var/run/cri-dockerd.sock
# 如果初始化的 token 不小心清空了,可以通过如下命令获取或者重新申请
# 如果 token 已经过期,就重新申请
kubeadm token create
# token 没有过期可以通过如下命令获取
kubeadm token list1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2.5 部署 CNI 网络插件
bash
# 在 master 节点上执行
# 下载 calico 配置文件,可能会网络超时
wget https://docs.projectcalico.org/manifests/calico.yaml
# 修改 calico.yaml 文件中的 CALICO_IPV4POOL_CIDR 配置,修改为与初始化的 cidr 相同,也就是pod-network-cidr参数
# 修改 IP_AUTODETECTION_METHOD 下的网卡名称
# 删除镜像 docker.io/ 前缀,避免下载过慢导致失败
sed -i 's#docker.io/##g' calico.yaml
# 应用
kubectl apply -f calico.yaml1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
2.6 测试 kubernetes 集群
bash
# 创建部署
kubectl create deployment nginx --image=nginx
# 暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看 pod 以及服务信息
kubectl get pod,svc1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2.7 补全执行命令
bash
yum -y install bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc1
2
3
4
5
6
7
2
3
4
5
6
7
三、命令行工具kubectl
1. 在任意节点使用kubectl
bash
# 1. 将 master 节点中 /etc/kubernetes/admin.conf 拷贝到需要运行的服务器的 /etc/kubernetes 目录中
scp /etc/kubernetes/admin.conf root@k8snode1:/etc/kubernetes
scp /etc/kubernetes/admin.conf root@k8snode2:/etc/kubernetes
# 2. 在对应的服务器上配置环境变量
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile1
2
3
4
5
6
2
3
4
5
6
2. 资源操作
2.1 创建对象
bash
kubectl create -f ./my-manifest.yaml # 创建资源
kubectl create -f ./my1.yaml -f ./my2.yaml # 使用多个文件创建资源
kubectl create -f ./dir # 使用目录下的所有清单文件来创建资源
kubectl create -f https://git.io/vPieo # 使用 url 来创建资源
kubectl run nginx --image=nginx # 启动一个 nginx 实例
kubectl explain pods,svc # 获取 pod 和 svc 的文档
# 从 stdin 输入中创建多个 YAML 对象
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000000"
---
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep-less
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000"
EOF
# 创建包含几个 key 的 Secret
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: $(echo "s33msi4" | base64)
username: $(echo "jane" | base64)
EOF1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2.2 显示和查找资源
bash
# Get commands with basic output
kubectl get services # 列出所有 namespace 中的所有 service
kubectl get pods --all-namespaces # 列出所有 namespace 中的所有 pod
kubectl get pods -o wide # 列出所有 pod 并显示详细信息
kubectl get deployment my-dep # 列出指定 deployment
#kubectl get pods --include-uninitialized # 列出该 namespace 中的所有 pod 包括未初始化的
# 使用详细输出来描述命令
kubectl describe nodes my-node
kubectl describe pods my-pod
kubectl get services --sort-by=.metadata.name # List Services Sorted by Name
# 根据重启次数排序列出 pod
kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
# 获取所有具有 app=cassandra 的 pod 中的 version 标签
kubectl get pods --selector=app=cassandra rc -o \
jsonpath='{.items[*].metadata.labels.version}'
# 获取所有节点的 ExternalIP
kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
# 列出属于某个 PC 的 Pod 的名字
# “jq”命令用于转换复杂的 jsonpath,参考 https://stedolan.github.io/jq/
sel=${$(kubectl get rc my-rc --output=json | jq -j '.spec.selector | to_entries | .[] | "\(.key)=\(.value),"')%?}
echo $(kubectl get pods --selector=$sel --output=jsonpath={.items..metadata.name})
# 查看哪些节点已就绪
JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}' \
&& kubectl get nodes -o jsonpath="$JSONPATH" | grep "Ready=True"
# 列出当前 Pod 中使用的 Secret
kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2.3 更新资源
bash
kubectl rolling-update frontend-v1 -f frontend-v2.json # 滚动更新 pod frontend-v1
kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2 # 更新资源名称并更新镜像
kubectl rolling-update frontend --image=image:v2 # 更新 frontend pod 中的镜像
kubectl rolling-update frontend-v1 frontend-v2 --rollback # 退出已存在的进行中的滚动更新
cat pod.json | kubectl replace -f - # 基于 stdin 输入的 JSON 替换 pod
# 强制替换,删除后重新创建资源。会导致服务中断。
kubectl replace --force -f ./pod.json
# 为 nginx RC 创建服务,启用本地 80 端口连接到容器上的 8000 端口
kubectl expose rc nginx --port=80 --target-port=8000
# 更新单容器 pod 的镜像版本(tag)到 v4
kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -
kubectl label pods my-pod new-label=awesome # 添加标签
kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq # 添加注解
kubectl autoscale deployment foo --min=2 --max=10 # 自动扩展 deployment “foo”1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2.4 修补资源
bash
kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}' # 部分更新节点
# 更新容器镜像; spec.containers[*].name 是必须的,因为这是合并的关键字
kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
# 使用具有位置数组的 json 补丁更新容器镜像
kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'
# 使用具有位置数组的 json 补丁禁用 deployment 的 livenessProbe
kubectl patch deployment valid-deployment --type json -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.5 编辑资源
bash
kubectl edit svc/docker-registry # 编辑名为 docker-registry 的 service
KUBE_EDITOR="nano" kubectl edit svc/docker-registry # 使用其它编辑器1
2
2
2.6 scale 资源
bash
kubectl scale --replicas=3 rs/foo # Scale a replicaset named 'foo' to 3
kubectl scale --replicas=3 -f foo.yaml # Scale a resource specified in "foo.yaml" to 3
kubectl scale --current-replicas=2 --replicas=3 deployment/mysql # If the deployment named mysql's current size is 2, scale mysql to 3
kubectl scale --replicas=5 rc/foo rc/bar rc/baz # Scale multiple replication controllers
kubectl scale deploy --replicas=3 nginx
kubectl get deploy nginx -o yaml #生成对应pod的yaml文件1
2
3
4
5
6
7
2
3
4
5
6
7
2.7 删除资源
bash
kubectl delete -f ./pod.json # 删除 pod.json 文件中定义的类型和名称的 pod
kubectl delete pod,service baz foo # 删除名为“baz”的 pod 和名为“foo”的 service
kubectl delete pods,services -l name=myLabel # 删除具有 name=myLabel 标签的 pod 和 serivce
kubectl delete pods,services -l name=myLabel --include-uninitialized # 删除具有 name=myLabel 标签的 pod 和 service,包括尚未初始化的
kubectl -n my-ns delete po,svc --all # 删除 my-ns namespace 下的所有 pod 和 serivce,包括尚未初始化的1
2
3
4
5
2
3
4
5
2.8 总结
bash
# 验证但不应用更改
kubectl apply --dry-run=client -f pod.yaml
# 显示要应用的内容
kubectl apply --dry-run=client -o yaml -f pod.yaml
# 强制删除
kubectl delete -f pod.yaml --force --grace-period=01
2
3
4
5
6
7
8
2
3
4
5
6
7
8
| 命令 | 特点 | 适用场景 |
|---|---|---|
create | 只能创建新资源 | 首次部署 |
apply | 创建或更新资源 | 持续部署 |
replace | 完全替换资源 | 配置更新 |
delete | 删除资源 | 资源清理 |
- 使用 apply 进行日常部署
- 使用 --dry-run 验证配置
- 使用 -f 指定文件或目录
- 使用 --force 强制操作
- 使用 --grace-period=0 立即删除
四、深入Pod
1.Pod配置模板
bash
apiVersion: v1 # api 文档版本
kind: Pod # 资源对象类型,也可以配置为像Deployment、StatefulSet这一类的对象
metadata: # Pod 相关的元数据,用于描述 Pod 的数据
name: nginx-demo # Pod 的名称
labels: # 定义 Pod 的标签
type: app # 自定义 label 标签,名字为 type,值为 app
test: 1.0.0 # 自定义 label 标签,描述 Pod 版本号
namespace: 'default' # 命名空间的配置
spec: # 期望 Pod 按照这里面的描述进行创建
containers: # 对于 Pod 中的容器描述
- name: nginx # 容器的名称
image: nginx:1.7.9 # 指定容器的镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略,指定如果本地有就用本地的,如果没有就拉取远程的
command: # 指定容器启动时执行的命令
- nginx
- -g
- 'daemon off;' # nginx -g 'daemon off;'
workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
ports:
- name: http # 端口名称
containerPort: 80 # 描述容器内要暴露什么端口
protocol: TCP # 描述该端口是基于哪种协议通信的
env: # 环境变量
- name: JVM_OPTS # 环境变量名称
value: '-Xms128m -Xmx128m' # 环境变量的值
reousrces:
requests: # 最少需要多少资源
cpu: 100m # 限制 cpu 最少使用 0.1 个核心
memory: 128Mi # 限制内存最少使用 128兆
limits: # 最多可以用多少资源
cpu: 200m # 限制 cpu 最多使用 0.2 个核心
memory: 256Mi # 限制 最多使用 256兆
restartPolicy: OnFailure # 重启策略,只有失败的情况才会重启1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2. 探针
2.1 探针类型
2.1.1 StartPorbe
bash
#k8s 1.16 版本新增的探针,用于判断应用程序是否已经启动了。
#当配置了 startupProbe 后,会先禁用其他探针,直到 startupProbe 成功后,其他探针才会继续。
#作用:由于有时候不能准确预估应用一定是多长时间启动成功,因此配置另外两种方式不方便配置初始化时长来检测,而配置了 statupProbe 后,只有在应用启动成功了,才会执行另外两种探针,可以更加方便的结合使用另外两种探针使用。
startupProbe:
httpGet:
path: /api/startup
port: 801
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.1.2 LivenessProbe
bash
#用于探测容器中的应用是否运行,如果探测失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器启动成功,不会执行重启策略。
livenessProbe:
failureThreshold: 5
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 51
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2.1.3 ReadinessProbe
bash
#用于探测容器内的程序是否健康,它的返回值如果返回 success,那么就认为该容器已经完全启动,并且该容器是可以接收外部流量的。
readinessProbe:
failureThreshold: 3 # 错误次数
httpGet:
path: /ready
port: 8181
scheme: HTTP
periodSeconds: 10 # 间隔时间
successThreshold: 1
timeoutSeconds: 11
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.2 探测方式
2.2.1 ExecAction
bash
#在容器内部执行一个命令,如果返回值为 0,则任务容器时健康的。
livenessProbe:
exec:
command:
- cat
- /health1
2
3
4
5
6
2
3
4
5
6
2.2.2 TCPSocketAction
bash
#通过 tcp 连接监测容器内端口是否开放,如果开放则证明该容器健康
livenessProbe:
tcpSocket:
port: 801
2
3
4
2
3
4
2.2.3 HTTPGetAction
bash
#生产环境用的较多的方式,发送 HTTP 请求到容器内的应用程序,如果接口返回的状态码在 200~400 之间,则认为容器健康。
livenessProbe:
failureThreshold: 5
httpGet:
path: /health
port: 8080
scheme: HTTP
httpHeaders:
- name: xxx
value: xxx1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.3 常规参数配置
bash
initialDelaySeconds: 60 #初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 监测间隔时间
successThreshold: 1 # 检查 1 次成功就表示成功
failureThreshold: 2 # 监测失败 2 次就表示失败1
2
3
4
5
2
3
4
5
3. 生命周期
bash
lifecycle:
postStart: # 容创建完成后执行的动作,不能保证该操作一定在容器的 command 之前执行,一般不使用
exec: # 可以是 exec / httpGet / tcpSocket
command:
- sh
- -c
- 'mkdir /data'
preStop: # 在容器停止前执行的动作
httpGet: # 发送一个 http 请求
path: /
port: 80
exec: # 执行一个命令
command:
- sh
- -c
- sleep 91
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.1 Pod 退出流程(删除操作)
Endpoint 删除 pod 的 ip 地址
Pod 变成 Terminating 状态
bash
#变为删除中的状态后,会给 pod 一个宽限期,让 pod 去执行一些清理或销毁操作。
#配置参数:
# 作用与 pod 中的所有容器
terminationGracePeriodSeconds: 30
containers:
- xxx1
2
3
4
5
6
2
3
4
5
6
- 执行 preStop 的指令
3.2 PreStop 的应用
bash
#如果应用销毁操作耗时需要比较长,可以在 preStop 按照如下方式进行配置
preStop:
exec:
command:
- sh
- -c
- 'sleep 20; kill pgrep java'
#但是需要注意,由于 k8s 默认给 pod 的停止宽限时间为 30s,如果我们停止操作会超过 30s 时,不要光设置 sleep 50,还要将 terminationGracePeriodSeconds: 30 也更新成更长的时间,否则 k8s 最多只会在这个时间的基础上再宽限几秒,不会真正等待 50s1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9

- 注册中心下线
- 数据清理
- 数据销毁
五、资源调度
1. Label 和 Selector
1.1 标签(Label)
在各类资源的 metadata.labels 中进行配置
kubectl中操作:
bash#临时创建 label kubectl label po <资源名称> app=hello #修改已经存在的标签 kubectl label po <资源名称> app=hello2 --overwrite #查看 label # selector 按照 label 单值查找节点 kubectl get po -A -l app=hello # 查看所有节点的 labels kubectl get po --show-labels1
2
3
4
5
6
7
8
9
1.2 选择器(Selector)
在各对象的配置 spec.selector 或其他可以写 selector 的属性中编写
kubectl中操作:
bash# 匹配单个值,查找 app=hello 的 pod kubectl get po -A -l app=hello # 匹配多个值 kubectl get po -A -l 'k8s-app in (metrics-server, kubernetes-dashboard)' 或 # 查找 version!=1 and app=nginx 的 pod 信息 kubectl get po -l version!=1,app=nginx # 不等值 + 语句 kubectl get po -A -l version!=1,'app in (busybox, nginx)'1
2
3
4
5
6
7
8
9
10
11
12
2. Deployment
2.1 功能
2.1.1 创建
bash
#创建一个 deployment
kubectl create deploy nginx-deploy --image=nginx:1.7.9
#或执行
kubectl create -f xxx.yaml --record
#--record 会在 annotation 中记录当前命令创建或升级了资源,后续可以查看做过哪些变动操作。
#查看部署信息
kubectl get deployments
#查看 rs
kubectl get rs
#查看 pod 以及展示标签,可以看到是关联的那个 rs
kubectl get pods --show-labels1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2.1.2 滚动更新
- 假设当前有 5 个 nginx:1.7.9 版本,你想将版本更新为 1.9.1,当更新成功第三个以后,你马上又将期望更新的版本改为 1.9.2,那么此时会立马删除之前的三个,并且立马开启更新 1.9.2 的任务
bash
#只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作
#修改 nginx 版本号
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
#或者通过 kubectl edit deployment/nginx-deployment 进行修改
#查看滚动更新的过程
kubectl rollout status deploy <deployment_name>
#查看部署描述,最后展示发生的事件列表也可以看到滚动更新过程
kubectl describe deploy <deployment_name>
#通过 kubectl get deployments 获取部署信息,UP-TO-DATE 表示已经有多少副本达到了配置中要求的数目
#通过 kubectl get rs 可以看到增加了一个新的 rs
#通过 kubectl get pods 可以看到所有 pod 关联的 rs 变成了新的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2.1.3 回滚
bash
#有时候你可能想回退一个Deployment,例如,当Deployment不稳定时,比如一直crash looping。
#默认情况下,kubernetes会在系统中保存前两次的Deployment的rollout历史记录,以便你可以随时会退(你可以修改revision history limit来更改保存的revision数)。
#案例:
#更新 deployment 时参数不小心写错,如 nginx:1.9.1 写成了 nginx:1.91
kubectl set image deployment/nginx-deploy nginx=nginx:1.91
#监控滚动升级状态,由于镜像名称错误,下载镜像失败,因此更新过程会卡住
kubectl rollout status deployments nginx-deploy
#结束监听后,获取 rs 信息,我们可以看到新增的 rs 副本数是 2 个
kubectl get rs
#通过 kubectl get pods 获取 pods 信息,我们可以看到关联到新的 rs 的 pod,状态处于 ImagePullBackOff 状态
#为了修复这个问题,我们需要找到需要回退的 revision 进行回退
#通过 kubectl rollout history deployment/nginx-deploy 可以获取 revison 的列表
#通过 kubectl rollout history deployment/nginx-deploy --revision=2 可以查看详细信息
#确认要回退的版本后,可以通过 kubectl rollout undo deployment/nginx-deploy 可以回退到上一个版本
#也可以回退到指定的 revision
kubectl rollout undo deployment/nginx-deploy --to-revision=2
#再次通过 kubectl get deployment 和 kubectl describe deployment 可以看到,我们的版本已经回退到对应的 revison 上了
#可以通过设置 .spec.revisonHistoryLimit 来指定 deployment 保留多少 revison,如果设置为 0,则不允许 deployment 回退了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2.1.4 扩容缩容
bash
#通过 kube scale 命令可以进行自动扩容/缩容,以及通过 kube edit 编辑 replcas 也可以实现扩容/缩容
#扩容与缩容只是直接创建副本数,没有更新 pod template 因此不会创建新的 rs1
2
3
2
3
bash
#将名为 foo 的 ReplicaSet 副本数调整为 3
kubectl scale --replicas=3 rs/foo
#通过 YAML 文件指定资源并调整副本数。
kubectl scale --replicas=3 -f foo.yaml
#只有当前副本数为2时,才将 mysql Deployment 扩容到3
kubectl scale --current-replicas=2 --replicas=3 deployment/mysql
#同时调整多个指定标签的 ReplicationController 的副本数。(有标签了就不要写具体的资源对象名称)
kubectl scale deployment --replicas=3 --current-replicas=5 --selector app=nginx1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2.1.5 暂停与恢复
bash
#由于每次对 pod template 中的信息发生修改后,都会触发更新 deployment 操作,那么此时如果频繁修改信息,就会产生多次更新,而实际上只需要执行最后一次更新即可,当出现此类情况时我们就可以暂停 deployment 的 rollout
#通过 kubectl rollout pause deployment <name> 就可以实现暂停,直到你下次恢复后才会继续进行滚动更新
#可以通过kubectl describe deploy xx的conditions信息判断是否执行过paused
Conditions:
Type Status Reason
---- ------ ------
Progressing Unknown DeploymentPaused
Available True MinimumReplicasAvailable
# Progressing 的 Reason 是 DeploymentPaused,并且 Status 为 Unknown,这就说明该 Deployment 当前处于暂停(Paused)状态。
kubectl get deployment xxname -o jsonpath='{.spec.paused}'
#尝试对容器进行修改,然后查看是否发生更新操作了
kubectl set image deploy <name> nginx=nginx:1.17.9
kubectl get po
#通过以上操作可以看到实际并没有发生修改,此时我们再次进行修改一些属性,如限制 nginx 容器的最大cpu为 0.2 核,最大内存为 128M,最小内存为 64M,最小 cpu 为 0.1 核
kubectl set resources deploy <deploy_name> -c <container_name> --limits=cpu=200m,memory=128Mi --requests=cpu100m,memory=64Mi
通过格式化输出 kubectl get deploy <name> -oyaml,可以看到配置确实发生了修改,再通过 kubectl get po 可以看到 pod 没有被更新
那么此时我们再恢复 rollout,通过命令 kubectl rollout deploy <name>
恢复后,我们再次查看 rs 和 po 信息,我们可以看到就开始进行滚动更新操作了
kubectl get rs
kubectl get po1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2.2 配置文件
bash
apiVersion: apps/v1 # deployment api 版本
kind: Deployment # 资源类型为 deployment
metadata: # 元信息
labels: # 标签
app: nginx-deploy # 具体的 key: value 配置形式
name: nginx-deploy # deployment 的名字
namespace: default # 所在的命名空间
spec:
replicas: 1 # 期望副本数
revisionHistoryLimit: 10 # 进行滚动更新后,保留的历史版本数
selector: # 选择器,用于找到匹配的 RS
matchLabels: # 按照标签匹配
app: nginx-deploy # 匹配的标签key/value
strategy: # 更新策略
rollingUpdate: # 滚动更新配置
maxSurge: 25% # 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例
maxUnavailable: 25% # 进行滚动更新时,最大不可用比例更新比例,表示在所有副本数中,最多可以有多少个不更新成功
type: RollingUpdate # 更新类型,采用滚动更新
template: # pod 模板
metadata: # pod 的元信息
labels: # pod 的标签
app: nginx-deploy
spec: # pod 期望信息
containers: # pod 的容器
- image: nginx:1.7.9 # 镜像
imagePullPolicy: IfNotPresent # 拉取策略
name: nginx # 容器名称
restartPolicy: Always # 重启策略
terminationGracePeriodSeconds: 30 # 删除操作最多宽限多长时间1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3. StatefulSet
3.1 功能
3.1.1 创建
bash
kubectl create -f web.yaml
# 查看 service 和 statefulset => sts
kubectl get service nginx
kubectl get statefulset web
# 查看 PVC 信息
kubectl get pvc
# 查看创建的 pod,这些 pod 是有序的
kubectl get pods -l app=nginx
# 查看这些 pod 的 dns
# 运行一个 pod,基础镜像为 busybox 工具包,利用里面的 nslookup 可以看到 dns 信息
kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
nslookup web-0.nginx1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.1.2 扩容缩容
bash
# 扩容
kubectl scale statefulset web --replicas=5
# 缩容
kubectl patch statefulset web -p '{"spec":{"replicas":3}}'1
2
3
4
2
3
4
3.1.3 镜像更新
RollingUpdate
htmlStatefulSet 也可以采用滚动更新策略,同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的1
2
3灰度发布
html利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果 例如我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod 利用该机制,我们可以通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更新1
2
3
4OnDelete
html只有在 pod 被删除时会进行更新操作1
3.1.4 删除
bash
# 删除 StatefulSet 和 Headless Service
# 级联删除:删除 statefulset 时会同时删除 pods
kubectl delete statefulset web
# 非级联删除:删除 statefulset 时不会删除 pods,删除 sts 后,pods 就没人管了,此时再删除 pod 不会重建的
kubectl delete sts web --cascade=false
# 删除 service
kubectl delete service nginx1
2
3
4
5
6
7
2
3
4
5
6
7
3.1.5 删除 pvc
bash
# StatefulSet删除后PVC还会保留着,数据不再使用的话也需要删除
kubectl delete pvc www-web-0 www-web-11
2
2
3.2 配置文件
yaml
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.alpha.kubernetes.io/storage-class: anything
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
4. DaemonSet
4.1 配置文件
yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
template:
metadata:
labels:
app: logging
id: fluentd
name: fluentd
spec:
containers:
- name: fluentd-es
image: agilestacks/fluentd-elasticsearch:v1.3.0
env:
- name: FLUENTD_ARGS
value: -qq
volumeMounts:
- name: containers
mountPath: /var/lib/docker/containers
- name: varlog
mountPath: /varlog
volumes:
- hostPath:
path: /var/lib/docker/containers
name: containers
- hostPath:
path: /var/log
name: varlog1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
4.2 指定 Node 节点
nodeSelector
yaml#先为 Node 打上标签 kubectl label nodes k8s-node1 svc_type=microsvc #然后再 daemonset 配置中设置 nodeSelector spec: template: spec: nodeSelector: svc_type: microsvc1
2
3
4
5
6
7
8
9nodeAffinity
yamlnodeAffinity 目前支持两种:requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution,分别代表必须满足条件和优选条件。 比如下面的例子代表调度到包含标签 wolfcode.cn/framework-name 并且值为 spring 或 springboot 的 Node 上,并且优选还带有标签 another-node-label-key=another-node-label-value 的Node。 apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: wolfcode.cn/framework-name operator: In values: - spring - springboot preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: another-node-label-key operator: In values: - another-node-label-value containers: - name: with-node-affinity image: pauseyyf/pause1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31podAffinity
yamlpodAffinity 基于 Pod 的标签来选择 Node,仅调度到满足条件Pod 所在的 Node 上,支持 podAffinity 和 podAntiAffinity。这个功能比较绕,以下面的例子为例: 如果一个 “Node 所在空间中包含至少一个带有 auth=oauth2 标签且运行中的 Pod”,那么可以调度到该 Node 不调度到 “包含至少一个带有 auth=jwt 标签且运行中 Pod”的 Node 上 apiVersion: v1 kind: Pod metadata: name: with-pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: auth operator: In values: - oauth2 topologyKey: failure-domain.beta.kubernetes.io/zone podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: auth operator: In values: - jwt topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: pauseyyf/pause1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
4.3 滚动更新
不建议使用 RollingUpdate,建议使用 OnDelete 模式,这样避免频繁更新 ds1
5. HPA 自动扩/缩容
5.1 开启指标服务
bash
# 下载 metrics-server 组件配置文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
# 修改镜像地址为国内的地址
sed -i 's/k8s.gcr.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' metrics-server-components.yaml
# 修改容器的 tls 配置,不验证 tls,在 containers 的 args 参数中增加 --kubelet-insecure-tls 参数
# 安装组件
kubectl apply -f metrics-server-components.yaml
# 查看 pod 状态
kubectl get pods --all-namespaces | grep metrics1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
5.2 cpu、内存指标监控
bash
# 实现 cpu 或内存的监控,首先有个前提条件是该对象必须配置了 resources.requests.cpu 或 resources.requests.memory 才可以,可以配置当 cpu/memory 达到上述配置的百分比后进行扩容或缩容
# 创建一个 HPA:
# 先准备一个好一个有做资源限制的 deployment
# 执行命令 kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5
# 通过 kubectl get hpa 可以获取 HPA 信息
# 测试:找到对应服务的 service,编写循环测试脚本提升内存与 cpu 负载
while true; do wget -q -O- http://<ip:port> > /dev/null ; done
# 可以通过多台机器执行上述命令,增加负载,当超过负载后可以查看 pods 的扩容情况 kubectl get pods
# 查看 pods 资源使用情况
kubectl top pods
# 扩容测试完成后,再关闭循环执行的指令,让 cpu 占用率降下来,然后过 5 分钟后查看自动缩容情况1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HPA 自动扩/缩容过程中如何防止因指标抖动导致 Pod 数量剧烈波动
HorizontalPodAutoscalerBehavior 配置目标在扩容(Up)和缩容(Down)两个方向的扩缩行为 (分别用 scaleUp 和 scaleDown 字段),而我们主要关注 stabilizationWindowSeconds 属性。
该属性用于指定扩缩容操作的稳定窗口时间,即在扩缩容操作完成后,需要等待一段时间(稳定窗口时间),才能再次进行扩缩容操作。
bash
spec:
behavior:
# 扩容:设置稳定窗口为 0 秒(默认值为 0 秒)
scaleUp:
stabilizationWindowSeconds: 0
# 缩容:设置稳定窗口为 30 秒(默认值为 300 秒),即在缩容操作完成后,需要等待 30 秒,才能再次进行缩容操作
scaleDown:
stabilizationWindowSeconds: 301
2
3
4
5
6
7
8
2
3
4
5
6
7
8
5.3 自定义 metrics
bash
# 控制管理器开启–horizontal-pod-autoscaler-use-rest-clients
# 控制管理器的 --apiserver 指向 API Server Aggregator
# 在API Server Aggregator中注册自定义的metrics API1
2
3
2
3
5.5 参考链接
五、服务发布
1. Service
- 提供集群内部网络调用
- 负载均衡(四层负载)
1.1 Service 的定义
将在集群中运行的应用通过同一个面向外界的端点公开出去,即使工作负载分散于多个后端也完全可行。
bash
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx-svc
spec:
ports:
- name: http # service 端口配置的名称
protocol: TCP # 端口绑定的协议,支持 TCP、UDP、SCTP,默认为 TCP
port: 80 # service 自己的端口
targetPort: 9527 # 目标 pod 的端口
- name: https
protocol: TCP
port: 443
targetPort: 443
selector: # 选中当前 service 匹配哪些 pod,对哪些 pod 的东西流量进行代理
app: nginx1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1.1.1 命令操作
bash
# 创建 service
kubectl create -f nginx-svc.yaml
# 查看 service 信息,通过 service 的 cluster ip 进行访问
kubectl get svc
# 查看 pod 信息,通过 pod 的 ip 进行访问
kubectl get po -owide
# 创建其他 pod 通过 service name 进行访问(推荐)
kubectl exec -it busybox -- sh
wget http://nginx-svc
# 默认在当前 namespace 中访问,如果需要跨 namespace 访问 pod,则在 service name 后面加上 .<namespace> 即可
wget http://nginx-svc:1080.default1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.1.2 Endpoint
1
1.2 代理 k8s 外部服务
yaml
#实现方式:
#编写 service 配置文件时,不指定 selector 属性
#自己创建 endpoint
#endpoint 配置:
apiVersion: v1
kind: Endpoints
metadata:
labels:
app: wolfcode-svc-external # 与 service 一致
name: wolfcode-svc-external # 与 service 一致
namespace: default # 与 service 一致
subsets:
- addresses:
- ip: <target ip> # 目标 ip 地址
ports: # 与 service 一致
- name: http
port: 80
protocol: TCP1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1.2.1 各环境访问名称统一
1.2.2 访问 k8s 集群外的其他服务
1.2.3 项目迁移
1.3 反向代理外部域名
yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: wolfcode-external-domain
name: wolfcode-external-domain
spec:
type: ExternalName
externalName: www.wolfcode.cn1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
1.4 常用类型
| 类型 | 概念 | 使用场景 |
|---|---|---|
| ClusterIP | 通过集群的内部 IP 公开 Service,Service 仅能在集群内部访问。默认类型(未显式指定 type 时即为 ClusterIP)。 | 只需在集群内部进行服务访问的应用场景,例如微服务间内部通信。 |
| NodePort | 通过每个节点上的 IP 和静态端口(NodePort)公开 Service。Kubernetes 自动为 Service 配置集群 IP,并映射到各节点端口。 | 需要集群外部访问集群内部服务但没有外部负载均衡器的场景,测试环境常用。 |
| LoadBalancer | 通过外部云平台负载均衡器向外部公开 Service。由云服务商(如阿里云、腾讯云等)提供资源完成流量转发。 | 云端部署、需要将服务暴露到公网,需支持大规模负载的生产环境。 |
| ExternalName | 将服务映射为 externalName 字段对应的目标主机名,本质上是返回一个 CNAME 记录,无需集群代理流量。 | 访问集群外部的服务或迁移阶段临时代理外部域名的服务。 |
1.4.1 ClusterIP
只能在集群内部使用,不配置类型的话默认就是 ClusterIP1
1.4.2 ExternalName
返回定义的 CNAME 别名,可以配置为域名1
1.4.3 NodePort
会在所有安装了 kube-proxy 的节点都绑定一个端口,此端口可以代理至对应的 Pod,集群外部可以使用任意节点 ip + NodePort 的端口号访问到集群中对应 Pod 中的服务。
当类型设置为 NodePort 后,可以在 ports 配置中增加 nodePort 配置指定端口,需要在下方的端口范围内,如果不指定会随机指定端口
端口范围:30000~32767
端口范围配置在 /usr/lib/systemd/system/kube-apiserver.service 文件中1
2
3
4
5
6
7
2
3
4
5
6
7
1.4.4 LoadBalancer
使用云服务商(阿里云、腾讯云等)提供的负载均衡器服务1
2. Ingress
- 提供外部访问
- 反向代理
- 负载均衡(七层负载)
2.1 安装 ingress-nginx
2.1.1 添加 helm 仓库
bash
wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
# 添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# 查看仓库列表
helm repo list
# 搜索 ingress-nginx
helm search repo ingress-nginx1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.1.2 下载包
# 下载安装包
helm pull ingress-nginx/ingress-nginx1
2
2
2.1.3 配置参数
bash
# 将下载好的安装包解压
tar xf ingress-nginx-xxx.tgz
# 解压后,进入解压完成的目录
cd ingress-nginx
# 修改 values.yaml
镜像地址:修改为国内镜像
registry: registry.cn-hangzhou.aliyuncs.com
image: google_containers/nginx-ingress-controller
image: google_containers/kube-webhook-certgen
tag: v1.3.0
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
修改部署配置的 kind: DaemonSet
nodeSelector:
ingress: "true" # 增加选择器,如果 node 上有 ingress=true 就部署
将 admissionWebhooks.enabled 修改为 false
将 service 中的 type 由 LoadBalancer 修改为 ClusterIP,如果服务器是云平台才用 LoadBalancer1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2.1.4 创建 Namespace
bash
# 为 ingress 专门创建一个 namespace
kubectl create ns ingress-nginx1
2
2
2.1.5 安装 ingress
bash
# 为需要部署 ingress 的节点上加标签
kubectl label node k8s-node1 ingress=true
# 安装 ingress-nginx
helm install ingress-nginx ./ingress-nginx -n ingress-nginx
#或者
helm install ingress-nginx -n ingress-nginx .1
2
3
4
5
6
7
2
3
4
5
6
7
2.2 基本使用
2.2.1 创建一个 ingress
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2.2.2 多域名配置
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配
- pathType: Exec # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /
- host: api.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
六、配置与存储
1. 配置管理
1.1 ConfigMap
1.1.1 创建
bash
#使用 kubectl create configmap -h 查看示例,构建 configmap 对象
#1. #基于文件夹进行创建
kubectl create configmap <configname> --from-file=<dirpath>
#2.基于文件进行创建【key如果不指定,默认使用文件的名字】
kubectl create cm <cnname> --from-file=key1=filepath --from-file=key2=filepath
#3.基础手动列出值创建
kubectl create cm <cmname> --from-literal=key1=value1 --from-literal=key2=value21
2
3
4
5
6
7
8
2
3
4
5
6
7
8
1.1.2 使用ConfigMap
- 通过env-valueFrom-configMapKeyRef,将ConfigMap中的key值直接挂载到容器的环境变量中
yaml
apiVersion: v1
kind: Pod
metadata:
name: test-env
spec:
containers:
- name: env-test
image: alpine
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "env;sleep 3600"]
env: #环境变量部分
- name: JAVA_VM_OPTS #容器内部的环境变量名称
valueFrom:
configMapKeyRef:
name: test-env-config #容器外部ConfigMap对象的名称
key: JAVA_OPTS_TEST #cm对象中的对应key
- name: APP
valueFrom:
configMapKeyRef:
name: test-env-config
key: APP_NAME
restartPolicy: Never1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 通过挂载的方式将某个配置文件加载到容器中
yaml
apiVersion: v1
kind: Pod
metadata:
name: test-env-config
spec:
containers:
- name: env-config-test
image: alpine
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","env;sleep 3600"]
volumeMounts: 挂载部分
- name: db-conf #指定想要挂载的卷名
mountPath: '/usr/local/mysql/conf' #指定相关卷在容器内部的挂载路径
readOnly: true #指定挂载后的卷文件能否只读,默认为false
volumes: #定义了一个卷
- name: db-conf #卷名称
configMap: #指定挂载对象为configMap,也可以是NFS等对象
name: mytestconfig #具体是哪个cm对象
items: #如果不指定items,默认加载该cm对象中所有的key-value
- key: 'db.properties' #这里由于指定了具体的items,则只加载key为dp.properties的所有相关内容
path: 'db-config' #指定挂载到容器内部的文件名称为db-config
restartPolicy: Never1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1.2 加密数据配置 Secret
(包含了有特殊字符,需要使用转义符转移,例如 $ 转移后为\ $,也可以对特殊字符使用单引号描述)
bash
#Secret通过base64加密,加密性不高
[root@k8smaster configMap]# echo "amdin" | base64
YW1kaW4K
[root@k8smaster configMap]# echo YW1kaW4K | base64 --decode
amdin
#secret一般用于加密docker-registry、generic、tls
[root@k8smaster configMap]# kubectl create secret -h
Create a secret using specified subcommand.
Available Commands:
docker-registry 创建一个给 Docker registry 使用的 secret
generic Create a secret from a local file, directory, or literal value
tls 创建一个 TLS secret
Usage:
kubectl create secret [flags] [options]
Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
#1.手动创建一个加密cm对象
[root@k8smaster configMap]# kubectl create secret generic secret-test1 --from-literal=user=root --from-literal=password=root
#2.describe只能看到字节数量
[root@k8smaster configMap]# kubectl describe secrets secret-test1
Name: secret-test1
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 4 bytes
user: 4 bytes
#3.但是可以通过edit查看到通过base64转化后的值,从而可以反推出原本的账号密码
[root@k8smaster configMap]# kubectl edit secrets secret-test1
apiVersion: v1
data:
password: cm9vdA==
user: cm9vdA==
kind: Secret
metadata:
creationTimestamp: "2024-10-31T02:00:20Z"
name: secret-test1
namespace: default
resourceVersion: "493461"
uid: dbcac3fc-0f41-445d-a81a-388c37975579
type: Opaque
[root@k8smaster configMap]# echo cm9vdA== | base64 --decode
root
#4. docker-registry 创建一个给 Docker registry 使用的 secret
# 作用
1. **imagePullSecrets** 用于指定拉取私有镜像仓库时需要的认证信息
2. 当 Pod 中的容器镜像来自私有仓库(如 Docker Hub 私有仓库、Harbor、阿里云镜像仓库等)时使用
3. 这些 Secret 会传递给镜像拉取器进行身份验证
# 使用场景
1. **私有 Docker 仓库**:需要用户名密码认证
2. **云厂商镜像仓库**:如阿里云 ACR、腾讯云 TCR、AWS ECR 等
3. **企业内部镜像仓库**:Harbor、Nexus 等
# 方法1:使用 kubectl 创建
kubectl create secret docker-registry my-registry-secret \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
[email protected]
# 方法2:使用现有的 Docker 配置文件
kubectl create secret generic my-registry-secret \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
#在 Pod 中使用 imagePullSecrets
apiVersion: v1
kind: Pod
metadata:
name: private-image-pod
spec:
imagePullSecrets: # 指定镜像拉取密钥
- name: my-registry-secret # Secret 名称
- name: another-registry-secret # 可以指定多个 Secret
containers:
- name: app
image: registry.example.com/myapp:latest # 私有镜像
imagePullPolicy: Always
#3. 在 Deployment 中使用
apiVersion: apps/v1
kind: Deployment
metadata:
name: private-app
spec:
replicas: 3
selector:
matchLabels:
app: private-app
template:
metadata:
labels:
app: private-app
spec:
imagePullSecrets: # 在 Pod 模板中指定
- name: my-registry-secret
containers:
- name: app
image: registry.example.com/myapp:latest1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
1.3 SubPath 的使用
| 使用方式 | mountPath 类型 | 挂载结果 | 示例 |
|---|---|---|---|
| 不使用 subPath | 目录 | 整个 Volume 挂载到目录 | /etc/config/ (目录) |
| 使用 subPath | 文件 | 单个文件挂载到指定路径 | /etc/app.conf (文件) |
yaml
使用 ConfigMap 或 Secret 挂载到目录的时候,会将容器中源目录给覆盖掉,此时我们可能只想覆盖目录中的某一个文件,但是这样的操作会覆盖整个文件,因此需要使用到 SubPath
配置方式:
定义 volumes 时需要增加 items 属性,配置 key 和 path,且 path 的值不能从 / 开始
在容器内的 volumeMounts 中增加 subPath 属性,该值与 volumes 中 items.path 的值相同
containers:
......
volumeMounts:
- mountPath: /etc/nginx/nginx.conf # 挂载到哪里
name: config-volume # 使用哪个 configmap 或 secret
subPath: etc/nginx/nginx.conf # 与 volumes.[0].items.path 相同
volumes:
- configMap:
name: nginx-conf # configMap 名字
items: # subPath 配置
key: nginx.conf # configMap 中的文件名
path: etc/nginx/nginx.conf # subPath 路径1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
当使用 subPath 挂载时,ConfigMap 的更新不会自动同步到容器内。
1.3.1 subPath 的限制
使用 subPath 时,Kubernetes 会创建一个静态的文件绑定
这个绑定在 Pod 创建时就固定了,不会动态更新
ConfigMap 更新后,容器内的文件保持原来的内容
1.4 配置的热更新
1.5 不可变的 Secret 和 ConfigMap
| 字段名 | 类型 | 默认值 | 字段说明 |
|---|---|---|---|
| immutable | boolean | nil | 设置 ConfigMap 数据是否可变(不可修改) |
作用说明
immutable: true 时:
数据内容不可修改:data 和 binaryData 字段完全锁定
元数据可修改:metadata 部分(如 labels、annotations)仍可更新
性能优化:kubelet 不会监听此 ConfigMap 的变化,减少 API 调用
缓存优化:集群可以更积极地缓存不可变的 ConfigMap
immutable: false 或未设置(默认):
- ConfigMap 可以随时被修改和更新
2.持久化存储
2.1 Volumes
configMap
2.1.1 EmptyDir
EmptyDir 主要用于一个 Pod 中不同的 Container 共享数据使用的,由于只是在 Pod 内部使用,因此与其他 volume 比较大的区别是,当 Pod 如果被删除了,那么 emptyDir 也会被删除。
emptyDir.medium 字段用来控制 emptyDir 卷的存储位置。 存储介质可以是任意类型,如 SSD、磁盘或网络存储。可以将 emptyDir.medium 设置为 Memory 让 k8s 使用 tmpfs(内存支持文件系统),速度比较快,但是重启 tmpfs 节点时,数据会被清除,且设置的大小会计入到 Container 的内存限制中。
使用emptyDir.sizeLimit设置存储容量
kubectl get pods emptydir-pod -o jsonpath='{.metadata.uid}1
2
3
4
5
6
7
2
3
4
5
6
7
yaml
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pod
namespace: default
spec:
containers:
- name: nginx-emptydir
image: nginx:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2.1.2 HostPath
将节点上的文件或目录挂载到 Pod 上,此时该目录会变成持久化存储目录,即使 Pod 被删除后重启,也可以重新加载到该目录,该目录下的文件不会丢失
类型:
空字符串:默认类型,不做任何检查
DirectoryOrCreate:如果给定的 path 不存在,就创建一个 755 的空目录
Directory:这个目录必须存在
FileOrCreate:如果给定的文件不存在,则创建一个空文件,权限为 644
File:这个文件必须存在
Socket:UNIX 套接字,必须存在
CharDevice:字符设备,必须存在
BlockDevice:块设备,必须存在1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: nginx
name: nginx-volume
volumeMounts:
- name: test-volume # 挂载哪个 volume
mountPath: /test-pd # 挂载到容器的哪个目录
volumes:
- name: test-volume
hostPath:
path: /data # 节点中的目录
type: Directory # 检查类型,在挂载前对挂载目录做什么检查操作,有多种选项,默认为空字符串,不做任何检查1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2.2 NFS 挂载
- nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。
2.2.1 安装
bash
# 安装 nfs
yum install nfs-utils -y
# 启动 nfs
systemctl start nfs-server
# 查看 nfs 版本
cat /proc/fs/nfsd/versions
# 创建共享目录
mkdir -p /data/nfs
cd /data/nfs
mkdir rw
mkdir ro
# 设置共享目录 export
vim /etc/exports
/data/nfs/rw 192.168.234.0/24(rw,sync,no_subtree_check,no_root_squash)
/data/nfs/ro 192.168.234.0/24(ro,sync,no_subtree_check,no_root_squash)
# 重新加载
exportfs -f
systemctl reload nfs-server
# 到其他测试节点安装 nfs-utils 并加载测试
mkdir -p /mnt/nfs/rw
mount -t nfs 192.168.234.10:/data/nfs/rw /mnt/nfs/rw1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2.2.2 配置文件
yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-nfs
namespace: default
spec:
containers:
- name: nginx-nfs-pod
image: nginx:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-volume
mountPath: /my-nfs-data
volumes:
- name: nfs-volume
nfs:
server: 192.168.234.10 # 网络存储服务地址
path: /data/nfs # 网络存储路径
readOnly: false # 是否只读1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2.3 PV 与 PVC
持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。1
2
3
2
3
2.3.1 生命周期
2.3.1.1 构建
静态构建
集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息, 并且对集群用户可用(可见)。PV 卷对象存在于 Kubernetes API 中,可供用户消费(使用)。1动态构建
如果集群中已经有的 PV 无法满足 PVC 的需求,那么集群会根据 PVC 自动构建一个 PV,该操作是通过 StorageClass 实现的。 想要实现这个操作,前提是 PVC 必须设置 StorageClass,否则会无法动态构建该 PV,可以通过启用 DefaultStorageClass 来实现 PV 的构建。1
2
3
2.3.1.2 绑定
当用户创建一个 PVC 对象后,主节点会监测新的 PVC 对象,并且寻找与之匹配的 PV 卷,找到 PV 卷后将二者绑定在一起。
如果找不到对应的 PV,则需要看 PVC 是否设置 StorageClass 来决定是否动态创建 PV,若没有配置,PVC 就会一致处于未绑定状态,直到有与之匹配的 PV 后才会申领绑定关系。1
2
3
2
3
2.3.1.3 使用
Pod 将 PVC 当作存储卷来使用,集群会通过 PVC 找到绑定的 PV,并为 Pod 挂载该卷。
Pod 一旦使用 PVC 绑定 PV 后,为了保护数据,避免数据丢失问题,PV 对象会受到保护,在系统中无法被删除。1
2
3
2
3
2.3.1.4 回收策略
当用户不再使用其存储卷时,他们可以从 API 中将 PVC 对象删除, 从而允许该资源被回收再利用。PersistentVolume 对象的回收策略告诉集群, 当其被从申领中释放时如何处理该数据卷。 目前,数据卷可以被 Retained(保留)、Recycled(回收)或 Deleted(删除)。1
保留(Retain)
回收策略 Retain 使得用户可以手动回收资源。当 PersistentVolumeClaim 对象被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为"已释放(released)"。 由于卷上仍然存在这前一申领人的数据,该卷还不能用于其他申领。 管理员可以通过下面的步骤来手动回收该卷: 删除 PersistentVolume 对象。与之相关的、位于外部基础设施中的存储资产 (例如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)在 PV 删除之后仍然存在。 根据情况,手动清除所关联的存储资产上的数据。 手动删除所关联的存储资产。 如果你希望重用该存储资产,可以基于存储资产的定义创建新的 PersistentVolume 卷对象。1
2
3
4
5删除(Delete)
对于支持 Delete 回收策略的卷插件,删除动作会将 PersistentVolume 对象从 Kubernetes 中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 动态制备的卷会继承其 StorageClass 中设置的回收策略, 该策略默认为 Delete。管理员需要根据用户的期望来配置 StorageClass; 否则 PV 卷被创建之后必须要被编辑或者修补。1回收(Recycle)已被废弃
警告: 回收策略 Recycle 已被废弃。取而代之的建议方案是使用动态制备。 如果下层的卷插件支持,回收策略 Recycle 会在卷上执行一些基本的擦除 (rm -rf /thevolume/*)操作,之后允许该卷用于新的 PVC 申领。1
2
2.3.2 PV
2.3.2.1 状态
- Available:空闲,未被绑定
- Bound:已经被 PVC 绑定
- Released:PVC 被删除,资源已回收,但是 PV 未被重新使用
- Failed:自动回收失败
2.3.2.2 配置文件
yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0001
spec:
capacity:
storage: 5Gi # pv 的容量
volumeMode: Filesystem # 存储类型为文件系统
accessModes: # 访问模式:ReadWriteOnce、ReadWriteMany、ReadOnlyMany
- ReadWriteOnce # 可被单节点独写
persistentVolumeReclaimPolicy: Recycle # 回收策略
storageClassName: slow # 创建 PV 的存储类名,需要与 pvc 的相同
mountOptions: # 加载配置
- hard
- nfsvers=4.1
nfs: # 连接到 nfs
path: /data/nfs/rw/test-pv # 存储路径
server: 192.168.234.10 # nfs 服务地址1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2.3.3 PVC
2.3.3.1 Pod 绑定 PVC
yaml
在 pod 的挂载容器配置中,增加 pvc 挂载
containers:
......
volumeMounts:
- mountPath: /tmp/pvc
name: nfs-pvc-test
volumes:
- name: nfs-pvc-test
persistentVolumeClaim:
claimName: nfs-pvc # pvc 的名称1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.3.3.2 配置文件
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteOnce # 权限需要与对应的 pv 相同
volumeMode: Filesystem
resources:
requests:
storage: 8Gi # 资源可以小于 pv 的,但是不能大于,如果大于就会匹配不到 pv
storageClassName: slow # 名字需要与对应的 pv 相同
# selector: # 使用选择器选择对应的 pv
# matchLabels:
# release: "stable"
# matchExpressions:
# - {key: environment, operator: In, values: [dev]}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2.3.4 StorageClass
2.3.4.1 制备器(Provisioner)
每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。1
2.3.4.2 NFS 动态制备案例
nfs-provisioner
yamlapiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner namespace: kube-system labels: app: nfs-client-provisioner spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: quay.io/external_storage/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: fuseim.pri/ifs - name: NFS_SERVER value: 192.168.113.121 - name: NFS_PATH value: /data/nfs/rw volumes: - name: nfs-client-root nfs: server: 192.168.113.121 path: /data/nfs/rw1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38StorageClass 配置
yamlapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage namespace: kube-system provisioner: fuseim.pri/ifs # 外部制备器提供者,编写为提供者的名称 parameters: archiveOnDelete: "false" # 是否存档,false 表示不存档,会删除 oldPath 下面的数据,true 表示存档,会重命名路径 reclaimPolicy: Retain # 回收策略,默认为 Delete 可以配置为 Retain volumeBindingMode: Immediate # 默认为 Immediate,表示创建 PVC 立即进行绑定,只有 azuredisk 和 AWSelasticblockstore 支持其他值1
2
3
4
5
6
7
8
9
10RBAC 配置
yamlapiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner namespace: kube-system --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner namespace: kube-system rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner namespace: kube-system subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner namespace: kube-system rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner namespace: kube-system subjects: - kind: ServiceAccount name: nfs-client-provisioner roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61PVC 处于 Pending 状态
配置 SelfLink
yaml修改 apiserver 配置文件 vim /etc/kubernetes/manifests/kube-apiserver.yaml spec: containers: - command: - kube-apiserver - --feature-gates=RemoveSelfLink=false # 新增该行 ...... 修改后重新应用该配置 kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml1
2
3
4
5
6
7
8
9
10
11
12不需要 SelfLink 的 provisioner
将 provisioner 修改为如下镜像之一即可 gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.01
2
3
4
5
PVC 测试配置
yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: auto-pv-test-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 300Mi storageClassName: managed-nfs-storage1
2
3
4
5
6
7
8
9
10
11
七、高级调度
1. CronJob 计划任务
1.1 cron 表达式
bash
# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 月的某天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 周的某天 (0 - 6)(周日到周一;在某些系统上,7 也是星期日)
# │ │ │ │ │ 或者是 sun,mon,tue,web,thu,fri,sat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
1.2 配置文件
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
concurrencyPolicy: Allow # 并发调度策略:Allow 允许并发调度,Forbid:不允许并发执行,Replace:如果之前的任务还没执行完,就直接执行新的,放弃上一个任务
failedJobsHistoryLimit: 1 # 保留多少个失败的任务
successfulJobHistoryLimit: 3 # 保留多少个成功的任务
suspend: false # 是否挂起任务,若为 true 则该任务不会执行
# startingDeadlineSeconds: 30 # 间隔多长时间检测失败的任务并重新执行,时间不能小于 10
schedule: "* * * * *" # 调度策略
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2. 初始化容器 InitContainer
yaml
在真正的容器启动之前,先启动 InitContainer,在初始化容器中完成真实容器所需的初始化操作,完成后再启动真实的容器。
相对于 postStart 来说,首先 InitController 能够保证一定在 EntryPoint 之前执行,而 postStart 不能,其次 postStart 更适合去执行一些命令操作,而 InitController 实际就是一个容器,可以在其他基础容器环境下执行更复杂的初始化功能。
在 pod 创建的模板中配置 initContainers 参数:
spec:
initContainers:
- image: nginx
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "echo 'inited;' >> ~/.init"]
name: init-test1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
3. 污点和容忍
3.1 污点(Taint)
3.2 容忍(Toleration)
4. 亲和力(Affinity)
4.1 NodeAffinity
4.2 PodAffinity
4.3 PodAntiAffinity
词汇表
集群级日志架构
常见报错
1. 从节点加入主机点报错([ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables])
原因
bash
[root@localhost yum.repos.d]# systemctl enable docker.service
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@localhost yum.repos.d]# kubeadm join 192.168.234.10:6443 --token kc6agx.zz7b4kuntvc44py6 \
--discovery-token-ca-cert-hash sha256:37feecd683bfdfa3e1064998b1cfaa6f54dd158b66f0871403faaec12afa8fbf
[preflight] Running pre-flight checks
[WARNING SystemVerification]: this Docker version is not on the list of validated versions: 27.3.1. Latest validated version: 20.10
[WARNING Service-Kubelet]: kubelet service is not enabled, please run 'systemctl enable kubelet.service'
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
解决
在尝试加入 Kubernetes 集群时,kubeadm join 命令遇到了几个问题。让我们逐一解决这些问题:
Docker 版本警告:
kubeadm警告你使用的 Docker 版本不在验证过的版本列表中。这通常不会阻止你加入集群,但可能意味着某些功能不受支持。确保你的 Docker 版本与 Kubernetes 版本兼容。kubelet 服务未启用: 系统提示你启用
kubelet服务。你可以通过以下命令来启用并启动kubelet服务:bashsystemctl enable kubelet.service systemctl start kubelet.service1
2/proc/sys/net/bridge/bridge-nf-call-iptables不存在: 这个错误表明你的系统配置可能不支持 Kubernetes 所需的网络桥接功能。这通常是因为某些内核模块没有加载。你可以尝试启用并加载这些模块:bashmodprobe br_netfilter sysctl -p1
2然后,设置以下 sysctl 配置:
bashecho 'net.bridge.bridge-nf-call-iptables = 1' | tee -a /etc/sysctl.conf echo 'net.bridge.bridge-nf-call-ip6tables = 1' | tee -a /etc/sysctl.conf echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.conf1
2
3之后,运行
sysctl -p来应用更改。检查内核模块: 确保
br_netfilter模块已经加载:bashlsmod | grep br_netfilter1如果没有加载,使用
modprobe命令来加载它。重启并重试: 在应用了上述更改之后,重启你的系统并再次尝试
kubeadm join命令。
2. 从节点下载calico-node镜像失败,报pending、ErrImagePull状态
[root@k8smaster ~]# kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-kube-controllers-cd8566cf-pm9qc 1/1 Running 0 16s 10.244.16.136 k8smaster <none> <none>
calico-node-6bt9p 0/1 Init:ErrImagePull 0 17s 192.168.234.20 k8snode1 <none> <none>
calico-node-p8pvt 1/1 Running 0 17s 192.168.234.10 k8smaster <none> <none>
calico-node-qzrdg 0/1 Init:0/3 0 17s 192.168.234.30 k8snode2 <none> <none>
coredns-6d8c4cb4d-gtsk9 1/1 Running 1 (41m ago) 19h 10.244.16.134 k8smaster <none> <none>
coredns-6d8c4cb4d-klqgq 1/1 Running 1 (41m ago) 19h 10.244.16.133 k8smaster <none> <none>
etcd-k8smaster 1/1 Running 3 (41m ago) 19h 192.168.234.10 k8smaster <none> <none>
kube-apiserver-k8smaster 1/1 Running 3 (41m ago) 19h 192.168.234.10 k8smaster <none> <none>
kube-controller-manager-k8smaster 1/1 Running 3 (41m ago) 19h 192.168.234.10 k8smaster <none> <none>
kube-proxy-27h2m 1/1 Running 3 (41m ago) 19h 192.168.234.10 k8smaster <none> <none>
kube-proxy-7nl9m 1/1 Running 2 (25m ago) 19h 192.168.234.30 k8snode2 <none> <none>
kube-proxy-s5d7f 1/1 Running 2 (33m ago) 19h 192.168.234.20 k8snode1 <none> <none>
kube-scheduler-k8smaster 1/1 Running 3 (41m ago) 19h 192.168.234.10 k8smaster <none> <none>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
原因
- 镜像问题,docker镜像源需要用代理
- 网络原因,下载超时。
解决
- 通过kubectl get pods -n kube-system -o wide命令,查看问题pod,然后发现是k8snode1和k8snode2两个从节点pod问题。登录从节点发现是docker源不统一和网络波动原因,导致docker pull calico-node镜像失败。最后,切换为手机热点网络对其进行相关镜像进行docker pull命令拉取后,就完成了所有pod的正常运行。
相关链接
[docker镜像拉取K8s的calico,Pod报错Init:ImagePullBackOff及kubekey生成离线包报错error: PipelineArtifactExportpipe的解决_calico镜像拉取失败-CSDN博客
部署k8s安装Calico插件提示镜像拉取失败 Init:ImagePullBackOff(新增镜像仓库地址解决)_calico镜像拉取失败-CSDN博客
K8s的Pod出现Init:ImagePullBackOff问题的解决(以calico为例)-编程新知 (ldbm.cn)
3. 卡在了删除容器阶段
bash
[root@k8smaster pods]# kubectl delete pod nginx-demo
pod "nginx-demo" deleted1
2
2
bash
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Killing 79s kubelet Stopping container nginx
Warning FailedKillPod 10s (x8 over 78s) kubelet error killing pod: failed to "KillPodSandbox" for "8d9245af-3ae4-4227-89bb-136d6efd1ef6" with KillPodSandboxError: "rpc error: code = Unknown desc = networkPlugin cni failed to teardown pod \"nginx-demo_default\" network: error getting ClusterInformation: connection is unauthorized: Unauthorized"1
2
3
4
5
2
3
4
5
原因
- 网络配置问题
解决
- 加上--force强制删除
4. 网卡连接激活失败
bash
[fangyuan@k8snode1 ~]nmcli connection up ens33
错误:连接激活失败:No suitable device found for this connection (device lo not available because device is strictly unmanaged).
[fangyuan@k8snode1 ~]nmcli device set ens33 managed yes1
2
3
2
3
原因
- 网络配置问题
解决
bash
#1.检查 NetworkManager 是否已接管网络设备
[fangyuan@k8snode1 ~]nmcli device status
DEVICE TYPE STATE CONNECTION
docker0 bridge 未托管 --
ens33 ethernet 未托管 --
lo loopback 未托管 --
#2.如果 ens33 设备的状态不是激活状态,你可能需要将其设置为受管理状态
[fangyuan@k8snode1 ~]nmcli device set ens33 managed yes
#3.尝试重新激活连接,发现失败
[fangyuan@k8snode1 ~]nmcli connection up ens33
错误:连接激活失败:No suitable device found for this connection (device lo not available because device is strictly unmanaged).
#4.如果 NetworkManager 没有接管网络设备的管理,可以通过以下命令开启托管
nmcli networking on
#5.重启网络服务
[fangyuan@k8snode1 ~]systemctl restart NetworkManager
#这套组合拳下来,解决网络问题
[fangyuan@k8snode1 ~]ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:86:5d:52 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 192.168.234.20/24 brd 192.168.234.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe86:5d52/64 scope link noprefixroute
valid_lft forever preferred_lft forever1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
5. 容器一直处于ContainerCreating状态,然后查看详情,发现报connection is unauthorized: Unauthorized错误。
[root@k8smaster pods]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 21s1
2
3
2
3
bash
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 17s default-scheduler Successfully assigned default/web-0 to k8snode2
Warning FailedCreatePodSandBox 16s kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = [failed to set up sandbox container 04b130aff5df612648404cd73c6183" network for pod "web-0": networkPlugin cni failed to set up pod "web-0_default" network: error getting ClusterInformation: connection is un clean up sandbox container "72ca123059554b84ed6431cefa25308fa204b130aff5df612648404cd73c6183" network for pod "web-0": networkPlugin cni failed to teardown pod "web-0_defrInformation: connection is unauthorized: Unauthorized]1
2
3
4
5
6
7
2
3
4
5
6
7
解决办法:
- 错误信息 "connection is unauthorized: Unauthorized" 意味着某个连接尝试由于未经授权而被拒绝。所以就将cni组件全部卸载,也就是calico容器全部删除,然后等待系统为其重新构建。
bash
kubectl delete pod `kubectl get po -n kube-system| grep calico | awk '{print $1}'` -n kube-system/1
相关链接:
https://github.com/projectcalico/calico/issues/4857
6. 使用helm包管理器安装ingress-nginx时,安装文件出错
bash
[root@k8smaster ingress-nginx]# helm install ingress-nginx -n ingress-nginx .
Error: template: ingress-nginx/templates/controller-role.yaml:48:9: executing "ingress-nginx/templates/controller-role.yaml" at <ne (index .Values.controller.extraArgs "update-status") "false">: error calling ne: invalid type for comparison1
2
2
解决:
bash
#在value.yaml文件找到下面这行数据,在201行
extraArgs: {}
#将其修改为如下,详情看上图
extraArgs:
update-status: "true"1
2
3
4
5
2
3
4
5
互动评论 (0)