Kubernets - Pod
记录 kubernetes 相关文档、基础、Pod 的使用说明等
Kubernetes 相关文档
官网 | 学习 Kubernetes 基础知识 | Kubernetes
重要:查看 k8s 或 docker 日志
journalctl -fu docker | kubelet
# 也可以用docker 看日志
docker logs -f + container_id
1. Kubernetes 概述
Docker (纯容器模式) 的运维管理麻烦,尤其涉及到跨容器网络通信及其复杂、难管理,故诞生了容器调度管理平台 Kubernetes ,由于功能强大,17 年后渐渐成为主流
架构图如下
分为 Master 节点和 Node 节点
包含如下核心组件
- etcd: 分布式高性能键值 数据库,存储整个集群的所有元数据,只通过 ApiServer 访问
- ApiServer: 接口 服务器,用来交互的,集群资源访问控制入口,提供 restful api 及安全访问控制
- Scheduler: 调度器,把业务容器调度到合适节点
- Controller Manager: 控制管理器,20来种的统称,确保集群资源按照期望的方式运行,生成元数据,故在调度之前,k8s 中最复杂的点
- ReplicaSet
- Service Controller
- ServiceAccount Controller
- Node controller
- ResourceQuota Controller
- Namespace Controller
- Tocken Controller
- Endpoints Controller
- kubelet: 节点代理,运行在每个节点上,管节点同时汇报情况给 Master 管理节点
- pod管理: 容器的抽象,最小资源调度单位,管容器的,被 kubelet 管的
- 容器健康检查: 检查容器是否正常运行,若运行出错,按照 pod 设置的重启策略处理
- 容器监控: 监控容器所在节点资源的使用情况,定时向 Master 报告,资源使用数据通过 cAdvisor 获取的,对于 pod 调度和正常运行至关重要
- kube-proxy: 负责 Pod 间的通信和负载均衡 iptables 或 ipvs 规则
- kubectl: 命令行工具
- CNI: 通用网络接口,如 flannel 等的网络插件,实现集群跨节点通信
其工作流程如下
关于性能
ApiServer 压测 10w+ 大概才会出现性能问题(应该是普通的企业主机配置)
部署后则生成 kubelet 进程,可执行 kubectl 二进制命令行工具,其中
- 组件: 启动的一个进程,为了支撑 k8s 平台的运行,安装好的软件
- 资源: k8s 提供的能力,被 k8s 所管理
# 查看 systemd 服务
systemctl status kubelet
# 查看 kubernetes的资源,简写
kubectl api-resources
kubectl的使用
类似于 docker,kubectl 是 CLI,用于与 APIServer 交互,内置了丰富的子命令,功能强大
$ kubectl -h
$ kubectl get -h
$ kubectl create -h
$ kubectl create namespace -h
# 管理集群资源
$ kubectl get po -v=7
2. namespace
命名空间,集群内的虚拟概念,类似于资源池,池中有各种资源,绝大多数的资源都必须属于某一个namespace
# 集群初始化安装好之后,会默认有如下几个
$ kubectl get ns # or get namespaces
NAME STATUS AGE
default Active 10d
kube-node-lease Active 10d
kube-public Active 10d
kube-system Active 10d
kubernetes-dashboard Active 9d
- 所有 namespaces 资源,创建时都要指定
-n ns
,若不指定,默认为 default - 同一个 namespace 下的同类资源 不能重名,不同类型的资源可以重名,不同 namespace 也可
- 在项目通常创建带有业务含义的 namespace 来做逻辑上的整合
提示
kubectl -n xxxns get xxx # 命名空间放前面,方便复用
3. Pod
最小调度单元,理解为存放多个容器的(豆荚),为和容器引擎(Docker)解耦(如 1.22.x 改用 containerd),抽象出一层 Pod 让 k8s 进行调度,被 kubelet 定期 watch ,更新状态并写入 etcd
# 查看命名空间 kube-system 下的 pods
$ kubectl -n kube-system get po
使用 yaml格式 定义 Pod
yaml 工程师,推荐使用yaml 而非 json,因为大家都用 yaml... 如下创建一个 django.yaml
文件
apiVersion: v1 # API 版本
kind: Pod # 资源类型
metadata:
name: ublog # Pod 名称
namespace: uit # 指定命名空间
labels: # 作标记
component: zzblog
spec:
containers: # 编写 Pod 中 包含的容器列表
- name: myblog # 容器名
image: 192.168.3.171:5000/myblog:v1 # 拉取镜像地址
imagePullPolicy: IfNotPresent # 若本地无,再去远程拉取
env: # 环境变量
- name: MYSQL_HOST # 环境变量 Key - Value
value: "127.0.0.1"
- name: MYSQL_PASSWD
value: "123456"
ports:
- containerPort: 8002
- name: mysql
image: 192.168.3.171:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
- name: MYSQL_DATABASE
value: "myblog"
apiVersion | 含义 |
---|---|
alpha | 进入 k8s 功能的早期候选版本,可能包含 Bug,最终不一定进入 k8s |
beta | 已经过测试的版本,最终会进入 k8s,但功能、对象定义可能会发生变更 |
stable | 可安全使用的稳定版本 |
v1 | stable 版本之后的首个版本,包含了更多的核心对象 |
apps/v1 | 使用最广泛的版本,像 Deployment,ReplicaSets 都已进入该版本 |
资源类型 与 apiVersion 的对照表(编写如下资源的 yaml 该指定那个 apiVersion)
Kind | apiVersion |
---|---|
ClusterRoleBinding | rbac.authorization.k8s.io/v1 |
ClusterRole | rbac.authorization.k8s.io/v1 |
ConfigMap | v1 |
CronJob | batch/v1beta1 |
DaemonSet | extensions/v1beta1 |
Node | v1 |
Namespace | v1 |
Secret | v1 |
PersistentVolume | v1 |
PersistentVolumeClaim | v1 |
Pod | v1 |
Deployment | v1、apps/v1、apps/v1beta1、apps/v1beta2 |
Service | v1 |
Ingress | extensions/v1beta1 |
ReplicaSet | apps/v1、apps/v1beta2 |
Job | batch/v1 |
StatefulSet | apps/v1、apps/v1beta1、apps/v1beta2 |
快速查看 资源 对应的 版本
$ kubectl explain pod
$ kubectl explain Pod.apiVersion
镜像拉取策略
spec:
containers:
- name: ...
image: ...
imagePullPolicy: IfNotPresent
- Always: 即使本地有,也总是远程仓库拉取镜像
- IfNotPresent: 默认为此,本地有则使用本地镜像,没有才去远程仓库拉取
- Never: 只使用本地镜像,没有则报错
3.1 Infra 容器
登录 k8s-slave-172 节点,执行如下命令,发现有 三个容器 (上文只编写了两个)
$ docker ps -a |grep blog
4321affa391e c20987f18b13 "docker-entrypoint.s…" About an hour ago Up About an hour k8s_mysql_ublog_uit_2905ba41-b03a-4d8d-8fb3-538e962dccbc_0
766410c81aee 2fd137e95f13 "./run.sh" About an hour ago Up About an hour k8s_myblog_ublog_uit_2905ba41-b03a-4d8d-8fb3-538e962dccbc_0
29feb4ab89be registry.aliyuncs.com/google_containers/pause:3.1 "/pause" About an hour ago Up About an hour k8s_POD_ublog_uit_2905ba41-b03a-4d8d-8fb3-538e962dccbc_0
包含了上文编写的 mysql 和 myblog 两个,但额外多出个 pause 状态的容器
为了实现 Pod 内部容器,能通过 localhost 通信:
- 每个 Pod 都会启动 Infra 容器
- Pod 内部的网络空间会共享 Infra 容器的网络空间(类比 Docker 网络的 container 模式 )
- Infra 容器只需 夯住 网络空间,无需额外功能,资源消耗极低
查看 Pod 内部的容器 IP ,会发现均相同,都为 Pod IP
# 如下的 10.244.1.23
$ kubectl -nuit exec -ti ublog -c myblog ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.244.1.23 netmask 255.255.255.0 broadcast 10.244.1.255
ether 1e:8c:df:d3:f3:00 txqueuelen 0 (Ethernet)
RX packets 38 bytes 3026 (2.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 24 bytes 6618 (6.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Pod 容器命名
k8s _<container_name>_<pod_name>_<namespace>_<random_string>
3.2 Pod 基本操作
创建和访问Pod
# 创建 命名空间(namespace) 逻辑上的资源池
$ kubectl create namespace uit
# 使用指定文件创建 Pod
$ kubectl create -f django.yaml
# 所有的操作都需要指定 -n 即namespace,但 default 命名空间可省略,
$ kubectl -n demo get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ublog 2/2 Running 0 69m 10.244.1.23 k8s-slave-172 <none> <none>
# - 查看pod,可以简写 po(其他资源同)
# - -o wide 表示查看广泛的信息,即详情
# - -o yaml/json|more 还可查看 Pod 是根据什么样的原文件运行的
# 使用 Pod IP 访问服务 上文得出 IP 是10.244.1.23 被调度到了 k8s-slave-172 节点
$ curl 10.244.1.23:8002/blog/index
# 进入容器执行初始化, 不必到对应的主机执行docker exec
$ kubectl -n uit exec -ti ublog -c myblog /bin/bash
# 查看环境变量
$ env|grep MYSQL
MYSQL_HOST=127.0.0.1
MYSQL_PASSWD=123456
# 初始化数据库
$ python3 manage.py migrate
# 进入另一个容器 -c: chose 表选择
$ kubectl -n uit exec -ti ublog -c mysql bash
# 查看数据库
$ mysql -p123456
$ show databases;
# 退出 或 ctrl + d
exit
删除 Pod 服务
# 根据文件删除
$ kubectl delete -f django.yaml
# 根据 Pod name 删除
$ kubectl -n <namespace> delete pod <pod_name>
# 如 kubectl -n uit delete pod ublog
# 删的慢 可以手动切到对应节点,执行
$ docker rm -f <container>
Troubleshooting and Debugging
# 查看 Pod 的 明细信息 及 事件
$ kubectl -n uit describe pod ublog
# 进入 Pod 内的 容器
$ kubectl -n <namespace> exec <pod_name> -c <container_name> -ti /bin/sh
# 查看 Pod 内容器 日志,显示标准或者错误输出日志
$ kubectl -n <namespace> logs -f --tail=20 <pod_name> -c <container_name>
更新 Pod 服务版本(若更改文件 )
# apply 应用使之生效
$ kubectl apply -f django.yaml
# 仅特定字段 如:镜像版本 之类的改动才会生效,例如 labels、env 之类的改动不会生效
3.3 Pod 数据持久化(挂载 )
若删除了 Pod,但 MySQL 的数据都在容器内部,会造成数据丢失,故需挂载出来持久化
使用 hostpath 和 nodeSelector 定点挂载
# 查看节点的 labels 如下
$ kubectl get no --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master-171 Ready master 15d v1.16.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master-171,kubernetes.io/os=linux,node-role.kubernetes.io/master=
k8s-slave-172 Ready <none> 15d v1.16.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-slave-172,kubernetes.io/os=linux
k8s-slave-173 Ready <none> 15d v1.16.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-slave-173,kubernetes.io/os=linux
# 给 node 节点资源打 label
$ kubectl label node k8s-slave-172 component=zz
# 删除即 “-” 号
$ kubectl label node k8s-slave-172 component-
# 再次查看 172 的 labels 发现前面已显示
$ kubectl get no --show-labels |grep k8s-slave-172
k8s-slave-172 Ready <none> 15d v1.16.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,component=zz,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-slave-172,kubernetes.io/os=linux
然后改写文件如下
apiVersion: v1
kind: Pod
metadata:
name: ublog
namespace: uit
labels:
component: zzblog
spec:
volumes: # 宿主机 的挂载,与 containers 同级
- name: mysql-data
hostPath:
path: /opt/mysql/data # 宿主机 的挂载点
nodeSelector: # 使用 节点选择器,将 Pod 调度到指定 label 的节点
component: zz
containers:
- name: myblog
image: 192.168.3.171:5000/myblog:v1
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_HOST
value: "127.0.0.1"
- name: MYSQL_PASSWD
value: "123456"
ports:
- containerPort: 8002
- name: mysql
image: 192.168.3.171:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
- name: MYSQL_DATABASE
value: "myblog"
volumeMounts: # 定义 源 的挂载
- name: mysql-data # 上文 宿主机 定义的卷名
mountPath: /var/lib/mysql # 容器中 源 的 挂载点
此时重新创建
# 在 k8s-slave-172 查看目录
ls /opt/mysql/data/
.... `发现会多出一堆 pod 上 mysql 的文件`
局限性
只能 固定在单个节点 上持久化,若该节点挂了,此时存储的数据也随之而挂
因此,可使用 PV + PVC 的方式 对接分布式存储来解决
- 分布式存储: UFS、 ceph 、glusterfs、nfs(高可用版)
3.4 服务健康检查
检测容器服务是否健康的手段,若不健康,会根据设置的 重启策略(restartPolicy)进行操作,两种检测机制可以分别单独设置,若不设置,默认Pod 一直健康
...
containers:
- name: myblog
image: 192.168.3.171:5000/myblog:v1
imagePullPolicy: IfNotPresent
livenessProbe:
# ReadinessProbe:
httpGet:
path: /blog/index/
port: 8002
scheme: HTTP
initialDelaySeconds: 5 # 容器启动后,x s后,才开始第一次探测
periodSeconds: 5 # 执行探测的频率,默认是 10s,隔 x s后,再探测
timeoutSeconds: 2 # 探测超时时间,默认 1s,最小 1s
...
LivenessProbe 探针(存活性检查 )
kubelet 根据配置的探针判断容器是否存活(Running 状态),若不健康 kubelet 会 kill 掉容器,并根据配置的重启策略重启,若不包含 LivenessProbe 探针,则返回值永远成功
ReadinessProbe 探针(可用性检查 )
kubelet 根据配置的探针判断容器是否正常提供服务(Ready 是否为 True) 可以接收请求,如果失败,容器的 Ready 为 False,控制器将此 Pod 的 Endpoint 从对应的 service 的 Endpoint 列表中移除,从此不再将任何请求调度该 Pod 上,直到下次探测成功为止
检测类型
exec: 通过执行命令来检查服务是否正常,回值为 0 则表示容器健康
httpGet: 通过发送 http 请求检查服务是否正常,返回 200-399 状态码则表明容器健康
tcpSocket: 通过容器的 IP 和 Port 执行 TCP 检查,如果能够建立 TCP 连接,则表明容器健康
successThreshold: 探测失败后,最少连续探测成功多少次才被认定为成功,默认是1
- 对于 LivenessProbe 必须是1,最小值是1
failureThreshold: 探测成功后,最少连续探测失败多少次才被认定为失败,默认是 3,最小值 1
举例
按上文配置,Pod 的容器 启动 5s(initialDelaySeconds) 后,用 HTTP 访问 8002 端口的 /blog/index/ 路由,若 超过2s 或 返回码不在 200~399 内,连续 failureThreshold 次,则健康检查失败
重启策略(RestartPolicy)
metadata:
...
spce:
restartPolicy: OnFailure
containers:
- name: ...
image: ...
args:
- /bin/sh
- -c
- sleep 10 && exit 0
...
应用于 Pod 内的所有容器,仅由 kubelet 进行判断和重启操作,当某个 容器异常退出 或 健康检查失败 时,kubelet 来进行如下设置的操作
- Always: 默认为此,容器失败,自动重启
- OnFailure: 容器终止运行且退出码不为 0 时(异常退出 ),自动重启(正常则返回 Complete )
- Never: 不论运行状态如何,都不会重启该容器
3.5 Pod 资源限制
保证充分利用集群资源,且确保重要容器在运行周期内能够分配到足够的资源稳定运行,因此平台需要具备
Pod的资源限制的能力, 资源限制最关注的即 CPU 和 Memory
...
containers:
- name: myblog
...
ports:
- containerPort: 8002
resources:
requests:
memory: 100Mi
cpu: 50m
limits:
memory: 500Mi
cpu: 100m
...
requests: (不会限制最大使用资源)
容器使用的最小资源需求,作用于 schedule 阶段,作为容器调度时资源分配的判断依赖
只有当前节点上可分配的资源量 >= request 时才允许将容器调度到该节点
requests.cpu 会被转成容器的
--cpu-shares
参数,与 cgroup cpu.shares 功能相同 (无论宿主机有多少个 CPU 或者内核,都会按照比例分配)requests.memory 没有对应容器的参数,仅作为 k8s 调度依据
limits:
容器能使用资源的最大值
设置为 0 表示对使用的资源不做限制,可无限的使用
当 pod 内存超过 limit 时,会被 oom
但 cpu 超时不会被 kill,但会限制不超过 limit 值(由于 CPU 是可压缩资源)
limits.cpu 会被转换成容器的
-–cpu-quota
参数。与 cgroup cpu.cfs_quota_us 功能相同limits.memory 会被转换成容器的
-–memory
参数,用于限制容器使用的最大内存
计算机的 CPU 是按 时间片 的方式来进行分配的,系统里的每一个操作都需要 CPU 的处理,哪个任务申请的时间片多,即得到的 CPU 资源越多
CGroup 里面对于 CPU 资源的单位换算:
1 CPU = 1000 millicpu(1 Core = 1000m)
- 1000m: 其中 m 表示毫、毫核的意思
提示
Kubernetes 中的每个节点通过操作系统命令确认自身 CPU 内核数量,然后乘以1000,得到的就是节点总 CPU 总毫数
- 比如一个节点有四核,那么该节点的 CPU 总毫量为 4000m
docker run
命令和 CPU 限制相关的所有选项如下
选项 | 描述 |
---|---|
--cpuset-cpus="" | 允许使用的 CPU 集,值可以为 0-3,0,1 |
-c ,--cpu-shares=0 | CPU 共享权值(相对权重) |
cpu-period=0 | 限制 CPU CFS 的周期,范围从 100ms~1s,即[1000, 1000000] |
--cpu-quota=0 | 限制 CPU CFS 配额,必须不小于1ms,即 >= 1000,绝对限制 |
docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:20.04 /bin/bash
将调度的周期设为 50000,容器在每个周期内的 CPU 配额设置为 25000,表示该容器每 50ms 可以得到 50% 的 CPU 运行时间
3.6 ConfigMap 和 Secret(配置 )
在真实使用场景中,上述 Pod 存在如下问题需要 优化
中间件应作为公共资源 (数据库、MQ、Cache 等 ),为多个项目提供服务
- 不适合与业务容器绑定同一 Pod ,因为业务容器往往经常变更,而中间件则很少迭代
密码、环境变量等应该统一管理
针对环境变量,k8s 提供 configMap 和 Secret,实现业务配置的统一管理, 允许将配置文件与镜像文件分离,以使容器化的应用程序具有可移植性 。
ConfigMap(常用环境变量 )
通常用来管理应用的 配置文件 或者 环境变量 (非特别敏感 ),可以将环境相关的信息存入 ConfigMap 里面, 然后 Pod 去其中读,如下创建文件
apiVersion: v1
kind: ConfigMap
metadata:
name: ublog
namespace: uit
data:
MYSQL_HOST: "192.168.3.172" # 下文会通过 label 将调度指定 k8s-slave-172 节点
MYSQL_PORT: "3306"
创建并查看
$ kubectl create -f configmap.yaml
$ kubectl -n uit get cm
另一种创建方式 configmap.txt
,好处是灵活、写的少
vim configmap.txt
MYSQL_HOST=192.168.3.172
MYSQL_PORT=3306
$ kubectl -n uit create configmap ublog --from-env-file=configmap.txt
Secret(密码 )
常用来管理 敏感类 的信息,默认会 base64 编码存储,有三种类型
- Service Account : 用来访问 k8s API,自动创建,且会自动挂载到 Pod 上的
/run/secrets/kubernetes.io/serviceaccount
目录,之后 Pod 指定 serviceAccount 自动创建对应的 secret - Opaque : 是 base64 编码格式的 Secret,用来 存储密码、密钥 等
- kubernetes.io/dockerconfigjson : 用来存储私有 docker registry 的认证信息
如下创建一个 secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: ublog
namespace: uit
type: Opaque
data:
MYSQL_USER: cm9vdA== # 注意加 -n 参数, echo -n root|base64
MYSQL_PASSWD: MTIzNDU2
创建并查看:
$ kubectl create -f secret.yaml
$ kubectl -n uit get secret
另一种创建方式 secret.txt
,好处同上
$ cat secret.txt
MYSQL_USER=root
MYSQL_PASSWD=123456
$ kubectl -n uit create secret generic ublog --from-env-file=secret.txt
中间件容器:(MySQL)
apiVersion: v1
kind: Pod
metadata:
name: mysql
namespace: uit
labels:
component: zz
spec:
hostNetwork: true # 修改为 host 模式,此时 MySQL运行的IP 为 宿主机IP
volumes:
- name: mysql-data
hostPath:
path: /opt/mysql/data
nodeSelector:
component: zz
containers:
- name: mysql
image: 192.168.3.171:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom: # 映射 secret.txt 中设置的敏感值
secretKeyRef:
name: ublog
key: MYSQL_PASSWD
- name: MYSQL_DATABASE
value: "myblog"
resources:
requests:
memory: 100Mi
cpu: 50m
limits:
memory: 500Mi
cpu: 100m
readinessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 5
periodSeconds: 20
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
- hostNetwork: 声明 Pod 的网络模式为 host 模式,等同
docker run --net=host
业务容器:
apiVersion: v1
kind: Pod
metadata:
name: ublog
namespace: uit
labels:
component: zz
spec:
containers:
- name: myblog
image: 192.168.3.171:5000/myblog:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8002
env:
- name: MYSQL_HOST
valueFrom: # 同上 映射配置 configmap.txt 指定的环境变量
configMapKeyRef:
name: ublog
key: MYSQL_HOST
- name: MYSQL_PASSWD
valueFrom:
secretKeyRef:
name: ublog
key: MYSQL_PASSWD
resources:
requests:
memory: 100Mi
cpu: 50m
limits:
memory: 500Mi
cpu: 100m
livenessProbe:
httpGet:
path: /blog/index/
port: 8002
scheme: HTTP
initialDelaySeconds: 10 # 容器启动后第一次执行探测是需要等待多少秒
periodSeconds: 15 # 执行探测的频率
timeoutSeconds: 2 # 探测超时时间
readinessProbe:
httpGet:
path: /blog/index/
port: 8002
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 2
periodSeconds: 15
执行创建
$ kubectl create -f mysql.yaml
$ kubectl create -f ublog.yaml
# 访问 ublog Pod 服务正常
$ curl 10.244.2.18:8002/blog/index/
补充: /etc/kubernetes/manifests
目录下存放 静态Pod,即凡是放在这个目录下的 yaml 文件,k8s 会自动创建,无需执行 kubectl create -f
,且删除也会自动拉起,目录下的 yaml 可用于编写参考(同时有这种目录的,一定是 kubeadm 搭建起来的集群)
注意
部署不同的环境时,Pod 的 yaml 无须再变化,只在每套环境中维护一套 ConfigMap 和 Secret 即可
ConfigMap 和 secret 不能跨 namespace 使用
更新配置后,Pod 内的 env 不会自动更新,重建后方可更新
3.7 Pod 状态与生命周期
状态值 | 描述 |
---|---|
Pending | API Server 已经创建该 Pod,等待调度器调度 |
ContainerCreating | 镜像正在创建 |
Running | Pod 内,容器均已创建,且至少有一个容器处于运行状态、正在启动状态或正在重启状态 |
Succeeded | Pod 内,所有容器均已成功执行退出,且不再重启 |
Failed | Pod 内,所有容器均已退出,但至少有一个容器退出为失败状态 |
CrashLoopBackOff | Pod 内,有容器启动失败,比如配置文件丢失导致主进程启动失败 |
Unknown | 由于某种原因无法获取该 Pod 的状态,可能由于网络通信不畅导致(少见) |
启动和关闭示意
init container: 初始化容器,做一些初始化操作
- 验证业务应用依赖的组件是否均已启动
- 修改目录权限
- 调整系统参数
main container: 执行的主容器,即 containers 下定义的
lifecycle: 有如下两个钩子
- postStart: 容器启动该做的事情,和 mainContainer 不分先后
- preStop: 容器停止之前该做的事情
...
spec:
initContainers:
- command:
- /sbin/sysctl
- -w
- vm.max_map_count=262144
image: alpine:3.6
imagePullPolicy: IfNotPresent
name: elasticsearch-logging-init
resources: {}
securityContext:
privileged: true
- name: fix-permissions
image:alpine: 3.6
command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
securityContext:
privileged: true
volumeMounts:
- name: elasticsearch-logging
mountPath: /usr/share/elasticsearch/data
...
验证 Pod 生命周期示例,demo-pod-start.yaml
apiVersion: v1
kind: Pod
metadata:
name: demo-start-stop
namespace: uit
labels:
component: demo-start-stop
spec:
initContainers:
- name: init
image: busybox
command: ['sh', '-c', 'echo $(date +%s): INIT >> /load/timing']
volumeMounts:
- mountPath: /load
name: timing
containers:
- name: main
image: busybox
command: ['sh', '-c', 'echo $(date +%s): START >> /load/timing;sleep 10; echo $(date +%s): END >> /loap/timing;']
volumeMounts:
- mountPath: /load
name: timing
livenessProbe:
exec:
command: ['sh', '-c', 'echo $(date +%s): LIVENESS >> /load/timing']
readinessProbe:
exec:
command: ['sh', '-c', 'echo $(date +%s): READINESS >> /load/timing']
lifecycle:
postStart:
exec:
command: ['sh', '-c', 'echo $(date +%s): POST-START >> /load/timing']
preStop:
exec:
command: ['sh', '-c', 'echo $(date +%s): PRE-STOP >> /load/timing']
volumes:
- name: timing
hostPath:
path: /tmp/load
创建 Pod 测试
$ kubectl create -f demo-pod-start.yaml
# 查看demo状态
$ kubectl -n uit get po -o wide -w
# 查看调度节点 k8s-slave-172 的/tmp/loap/timing
$ cat /tmp/load/timing
1666057181: INIT
1666057199: START
1666057199: POST-START
1666057202: LIVENESS
1666057206: READINESS
1666057227: START
1666057227: POST-START
1666057232: LIVENESS
1666057236: READINESS
1666057272: START
...
须主动杀掉 Pod 才会触发
pre-stop hook
,如果是 Pod 自己 Down 掉,则不会执行pre-stop hook
3.8 Pod 驱逐策略(简述)
k8s 有个特色功能叫 pod eviction,它在某些场景下如:节点 NotPodReady、或者资源不足时,把 Pod 驱逐至其它节点,是出于业务保护的角度去考虑的
Kube-controller-manager: 周期性检查所有节点状态,当节点处于 NotReady 状态超过一段时间后,驱逐该节点上所有 pod,并停掉 kubelet
pod-eviction-timeout:(controller-manager的一个参数) 当 NotReady 状态节点超过该时间后,执行驱逐,默认 5 min,仅适用于 1.13 版本之前
1.13 版本后,集群开启
TaintBasedEvictions
与TaintNodesByCondition
功能,若节点失联等异常,k8s 会自动为该节点打上 污点 ,同时为 Pod 默认添加如下容忍设置tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300
各 Pod 可以独立设置驱逐容忍时间
Kubelet: 周期性检查本节点资源,当资源不足时,按照优先级驱逐部分 Pod
memory.available: 节点可用内存
nodefs.available: 节点根盘可用存储空间
nodefs.inodesFree: 节点 inodes 可用数量
imagefs.available: 镜像存储盘的可用空间
imagefs.inodesFree: 镜像存储盘的 inodes 可用数量