Pod是Kubernetes中最小的单元,它由一组、一个或多个容器组成
每个Pod还包含了一个Pause容器,Pause容器是Pod的父容器,主要负责僵尸进程的回收管理
通过Pause容器可以使同一个Pod里面的多个容器共享存储、网络、PID、IPC等。
Pod支持横向扩展和复制
Pod的生命周期是短暂的, 用后即焚的实体
Pod不会自愈, 如果Pod运行的Node故障, 或者是调度器本身故障, 这个Pod就会被删除
控制器(Deployment)可以自动创建和管理多个Pod, 提供副本管理, 滚动升级和集群级别的自愈能力
Pod本身是一个逻辑概念,没有具体存在,那究竟是怎么实现的呢?
众所周知,容器之间是通过Namespace隔离的,Pod要想解决上述应用场景,那么就要让Pod里的容器之间高效共享。
具体分为两个部分:网络和存储
kubernetes的解法是这样的:会在每个Pod里先启动一个infra container
小容器,然后让其他的容器连接进来这个网络命名空间,然后其他容器看到的网络试图就完全一样了,即网络设备、IP地址、Mac地址等,这就是解决网络共享问题。在Pod的IP地址就是infra container的IP地址。
比如有两个容器,一个是nginx,另一个是普通的容器,普通容器要想访问nginx里的文件,就需要nginx容器将共享目录通过volume挂载出来,然后让普通容器挂载的这个volume,最后大家看到这个共享目录的内容一样。
例如:
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: write
image: centos
command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
volumeMounts:
- name: data
mountPath: /data
- name: read
image: centos
command: ["bash","-c","tail -f /data/hello"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir: {}
上述示例中有两个容器,write容器负责提供数据,read消费数据,通过数据卷将写入数据的目录和读取数据的目录都放到了该卷中,这样每个容器都能看到该目录。
验证:
kubectl apply -f pod.yaml
kubectl logs my-pod -c read -f
在Pod中容器分为以下几个类型:
Pod对象自从其创建开始至终止退出的时间范围称为其生命周期
在这段时间中, Pod会处于多种不同的状态, 并执行一些操作
创建主容器(main container) 为必须的操作
其他可选的操作还包括
上述操作是否执行取决于Pod的定义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oix5OSve-1628834816607)(C:\Users\admin\Desktop\截图\k8s\Pod生命周期示意图.png)]
StartupProbe:k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否已经启动。如果配置了startupProbe,就会先禁止其他的探测,直到它成功为止,成功后将不在进行探测。
LivenessProbe:周期性检测,检测未通过时,与该Pod关联的Service,会将该Pod从Service的后端可用端点列表中删除;直接再次就绪,重新添加回来。未定义时,只要容器未终止,即为就绪;
ReadinessProbe:周期性检测,一般用于探测容器内的程序是否健康,它的返回值如果为success,那么就代表这个容器已经完成启动,并且程序已经是可以接受流量的状态。
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: java
image: lizhenliang/java-demo
imagePullPolicy: IfNotPresent
imagePullPolicy 字段有三个可选值:
IfNotPresent:默认值,镜像在宿主机上不存在时才拉取(镜像标签是指定版本时的默认选项)
Always:每次创建 Pod 都会重新拉取一次镜像(镜像标签是latest的默认选项)
Never: Pod 永远不会主动拉取这个镜像
如果拉取公开的镜像,直接按照上述示例即可,但要拉取私有的镜像,是必须认证镜像仓库才可以,即docker login,而在K8S集群中会有多个Node,显然这种方式是很不放方便的!为了解决这个问题,K8s 实现了自动拉取镜像的功能。 以secret方式保存到K8S中,然后传给kubelet。
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
imagePullSecrets:
- name: myregistrykey
containers:
- name: java
image: lizhenliang/java-demo
imagePullPolicy: IfNotPresent
上述中名为 myregistrykey 的secret是由kubectl create secret docker-registry命令创建:
kubectl create secret docker-registry myregistrykey --docker-username=admin --docker-password=Harbor12345 [email protected] --docker-server=192.168.31.70
在K8S部署一个应用的YAML内容大致分为两部分:
控制器定义:定义控制器属性
被控制对象:Pod模板,定义容器属性
具体字段意义:
apiVersion | API版本 |
---|---|
kind | 资源类型 |
metadata | 资源元数据 |
spec | 资源规格 |
replicas | 副本数量 |
selector | 标签选择器 |
template | Pod模板 |
metadata | Pod元数据 |
spec | Pod规格 |
containers | 容器配置 |
很多同学YAML不会写!主要原因还是用的少,里面都是由于各个资源组成,熟悉了每个资源应用,自然就会写了,但也不用等到熟悉各种资源,这里教你几个技巧,帮助快速上手。
用run命令生成部署模板
kubectl create deployment nginx --image=nginx:1.14 -o yaml --dry-run> my-deploy.yaml
用get命令将已有部署的应用yaml导出
kubectl get my-deploy/nginx -o=yaml --export > my-deploy.yaml
如果某个字段单词不记得了,可以通过explain查看更详细的帮助文档获得
kubectl explain pods.spec.containers
apiVersion: v1 # 必选,API的版本号
kind: Pod # 必选,类型Pod
metadata: # 必选,元数据
name: nginx # 必选,符合RFC 1035规范的Pod名称
namespace: default # 可选,Pod所在的命名空间,不指定默认为default,可以使用-n指定namespace
labels: # 可选,标签选择器,一般用于过滤和区分Pod
app: nginx
role: frontend # 可以写多个
annotations: # 可选,注释列表,可以写多个
app: nginx
spec: # 必选,用于定义容器的详细信息
initContainers: # 初始化容器,在容器启动之前执行的一些初始化操作
- command:
- sh
- -c
- echo "I am InitContainer for init some configuration"
image: busybox
imagePullPolicy: IfNotPresent
name: init-container
containers: # 必选,容器列表
- name: nginx # 必选,符合RFC 1035规范的容器名称
image: nginx:latest # 必选,容器所用的镜像的地址
imagePullPolicy: Always # 可选,镜像拉取策略
command: # 可选,容器启动执行的命令
- nginx
- -g
- "daemon off;"
workingDir: /usr/share/nginx/html # 可选,容器的工作目录
volumeMounts: # 可选,存储卷配置,可以配置多个
- name: webroot # 存储卷名称
mountPath: /usr/share/nginx/html # 挂载目录
readOnly: true # 只读
ports: # 可选,容器需要暴露的端口号列表
- name: http # 端口名称
containerPort: 80 # 端口号
protocol: TCP # 端口协议,默认TCP
env: # 可选,环境变量配置列表
- name: TZ # 变量名
value: Asia/Shanghai # 变量的值
- name: LANG
value: en_US.utf8
resources: # 可选,资源限制和资源请求限制
limits: # 最大限制设置
cpu: 1000m #1核=1000m
memory: 1024Mi
requests: # 启动所需的资源
cpu: 100m
memory: 512Mi
startupProbe: # 可选,检测容器内进程是否完成启动。注意三种检查方式同时只能使用一种。
httpGet: # httpGet检测方式,生产环境建议使用httpGet实现接口级健康检查,健康检查由应用程序提供。
path: /api/successStart # 检查路径
port: 80
readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。
httpGet: # httpGet检测方式,生产环境建议使用httpGet实现接口级健康检查,健康检查由应用程序提供。
path: / # 检查路径
port: 80 # 监控端口
livenessProbe: # 可选,健康检查
exec: # 执行容器命令检测方式
#command:
#- cat
#- /health
httpGet: # httpGet检测方式
path: /_health # 检查路径
port: 8080
httpHeaders: # 检查的请求头
- name: end-user
value: Jason
tcpSocket: # 端口检测方式
port: 80
initialDelaySeconds: 60 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 1 # 检查成功为2次表示就绪
failureThreshold: 2 # 检测失败1次表示未就绪
lifecycle:
postStart: # 容器创建完成后执行的指令, 可以是exec httpGet TCPSocket
exec:
command:
- sh
- -c
- 'mkdir /data/ '
preStop:
httpGet:
path: /
port: 80
exec:
command:
- sh
- -c
- sleep 9
restartPolicy: Always # 可选,默认为Always,容器故障或者没有启动成功,那就自动重启该容器,Onfailure: 容器以不为0的状态终止,自动重启该容器, Never:无论何种状态,都不会重启
nodeSelector: # 可选,指定Node节点
region: subnet7
imagePullSecrets: # 可选,拉取镜像使用的secret,可以配置多个
- name: default-dockercfg-86258
hostNetwork: false # 可选,是否为主机模式,如是,会占用主机端口
volumes: # 共享存储卷列表
- name: webroot # 名称,与上述对应
emptyDir: {} # 挂载目录
hostPath: # 挂载本机目录
path: /etc/hosts
Pod对象自从其创建开始至终止退出的时间范围称为其生命周期
在这段时间中, Pod会处于多种不同的状态, 并执行一些操作
创建主容器(main container) 为必须的操作
其他可选的操作还包括
上述操作是否执行取决于Pod的定义
Infrastructure Container:基础容器,维护整个Pod网络空间,对用户不可见
InitContainers:初始化容器,先于业务容器开始执行,一般用于业务容器的初始化工作
Containers:业务容器,具体跑应用程序的镜像
init-container
apiVersion: v1
kind: Pod
metadata:
name: init-container-demo
namespace: default
spec:
initContainers:
- name: iptables-init
image: ikubernetes/admin-box:latest
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c']
args: ['iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80']
securityContext:
capabilities:
add:
- NET_ADMIN
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
lifecycle-demo
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
securityContext:
capabilities:
add:
- NET_ADMIN
livenessProbe:
httpGet:
path: '/livez'
port: 80
scheme: HTTP
initialDelaySeconds: 5
lifecycle:
postStart:
exec:
command: ['/bin/sh','-c','iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-ports 80']
preStop:
exec:
command: ['/bin/sh','-c','while killall python3; do sleep 1; done']
restartPolicy: Always
也支持三种探针
spec:
containers:
- name: …
image: …
livenessProbe:
exec
PS:在一个pod中exec、httpGet、tcpSocket三种探针使用一种即可
StartupProbe:k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否已经启动。如果配置了startupProbe,就会先禁止其他的探测,直到它成功为止,成功后将不在进行探测。便于用户使用同livenessProbe不同参数或阈值;
LivenessProbe:周期性检测,检测未通过时,kubelet会根据restartPolicy的定义来决定是否会重启该容器;未定义时,Kubelet认为只要容器未终止,即为健康;
ReadinessProbe:周期性检测,检测未通过时,与该Pod关联的Service,会将该Pod从Service的后端可用端点列表中删除;直接再次就绪,重新添加回来。未定义时,只要容器未终止,即为就绪;
ExecAction:在容器内执行一个命令,如果返回值为0,则认为容器健康。
TCPSocketAction:通过TCP连接检查容器内的端口是否是正常打开,如果正常打开的就认为容器健康。
HTTPGetAction:向应用程序暴露的API地址发HTTP请求来检测程序是否正常,如果状态码为2xx,3xx则认为容器健康。
例如:
liveness-exec
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command: ['/bin/sh', '-c', '[ "$(curl -s 127.0.0.1/livez)" == "OK" ]']
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 5
[ “$(curl -s 127.0.0.1/livez)” == “OK” ]:shell判断语句,等值判断,curl -s 127.0.0.1/livez成功则显示OK
liveness-httpget
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: '/livez'
port: 80
scheme: HTTP
initialDelaySeconds: 5
scheme: HTTP意思是使用HTTP协议
只以响应码作为容器是否健康的标准,返回的响应码为2xx,3xx为健康
liveness-tcpsocket
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcpsocket-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
tcpSocket:
port: http
periodSeconds: 5
initialDelaySeconds: 5
port: http是引用上面ports.name: http,类似于变量的用法
readiness-httpget
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
path: '/readyz'
port: 80
scheme: HTTP
initialDelaySeconds: 15
timeoutSeconds: 2
periodSeconds: 5
failureThreshold: 3
restartPolicy: Always
startup-exec
apiVersion: v1
kind: Pod
metadata:
name: startup-exec-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
startupProbe:
exec:
command: ['/bin/sh','-c','test','"$(curl -s 127.0.0.1/livez)"=="OK"']
initialDelaySeconds: 0
failureThreshold: 3
periodSeconds: 5
startup检测成功后,LivenessProbe和ReadinessProbe探针才会启动
sidecar:为主容器提供辅助作用,为了外部环境更好接入主容器,如日志收集,代理服务等
adapater:为主容器的某个功能,能更好的适应外部环境
ambassador:为了让主容器接入外部环境,如代表主容器访问数据
sidecar-container
apiVersion: v1
kind: Pod
metadata:
name: sidecar-container-demo
namespace: default
spec:
containers:
- name: proxy
image: envoyproxy/envoy-alpine:v1.14.1
command: ['/bin/sh','-c']
args: ['sleep 5 && envoy -c /etc/envoy/envoy.yaml']
lifecycle:
postStart:
exec:
command: ['/bin/sh','-c','wget -O /etc/envoy/envoy.yaml http://ilinux.io/envoy.yaml']
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
env:
- name: HOST
value: "127.0.0.1"
- name: PORT
value: "8080"
Pod计算资源配额有两种
request:下阈值;限制配额:容器能使用的最大配置
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
Limit:上阈值; 申请配额:调度时使用,参考是否有节点满足该配置
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
计算资源的单位:
resource-requests
apiVersion: v1
kind: Pod
metadata:
name: stress-pod
spec:
containers:
- name: stress
image: ikubernetes/stress-ng
command: ["/usr/bin/stress-ng", "-c 1", "-m 1", "--metrics-brief"]
resources:
requests:
memory: "128Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "400m"
/usr/bin/stress-ng专门做压力测试的应用程序
resource-limites
apiVersion: v1
kind: Pod
metadata:
name: memleak-pod
labels:
app: memleak
spec:
containers:
- name: simmemleak
image: ikubernetes/simmemleak
imagePullPolicy: IfNotPresent
resources:
requests:
memory: "64Mi"
cpu: "1"
limits:
memory: "64Mi"
cpu: "1"
设定requests和limits值相同是强行限制pod的计算资源。
强行限制的pod的计算资源后,如果pod内存不够,启动失败会显示OOMKilled
k8s的退避算法:第一次失败1秒后重启,第二次失败10秒后重启,之后重启时间翻倍,到第7次重启300秒还是失败后,显示CrashLoopBackOff
基本概念
pod过载使用资源的情况下,无法同时满足绑定其上的所有对象以资源满载的方式运行,在内存资源紧缺的情况下。Kubernetes根据Pod中Containers Resource的request和limit的值,把Pod对象归类为Guaranteed、 Burstable、和Best-Effort这3个服务质量类别(QoS )。
apiVersion: v1 #查看版本:kubectl api-version
kind: Pod
metadata: {…}
spec:
securityContext: # Pod级别的安全上下文,对内部所有容器均有效
runAsUser # 以指定的用户身份运行容器进程,默认由镜像中的USER指定
runAsGroup # 以指定的用户组运行容器进程,默认使用的组随容器运行时
supplementalGroups <[]integer> # 为容器中1号进程的用户添加的附加组;
fsGroup # 为容器中的1号进程附加的一个专用组,其功能类似于sgid
runAsNonRoot # 是否以非root身份运行
seLinuxOptions # SELinux的相关配置
sysctls <[]Object> # 应用到当前Pod上的网络名称空间级别的sysctl参数设置列表
windowsOptions # Windows容器专用的设置
containers: #容器级别的安全上下文
- name: …
image: …
securityContext: # 容器级别的安全上下文,仅生效于当前容器
runAsUser # 以指定的用户身份运行容器进程
runAsGroup # 以指定的用户组运行容器进程
runAsNonRoot # 是否以非root身份运行
allowPrivilegeEscalation # 是否允许特权升级
capabilities # 于当前容器上添加(add)或删除(drop)的内核能力
add <[]string> # 添加由列表定义的各内核能力
drop <[]string> # 移除由列表定义的各内核能力
privileged # 是否运行为特权容器,若设定为true,就等于是宿主机上的用户,若以管理员身份运行,可直接操作宿主机的内核,不建议使用
procMount # 设置容器的procMount类型,默认为DefaultProcMount;
readOnlyRootFilesystem # 是否将根文件系统设置为只读模式
seLinuxOptions # SELinux的相关配置
windowsOptions # windows容器专用的设置
指定运行容器的用户和组:securitycontext-runasuser-demo
apiVersion: v1
kind: Pod
metadata:
name: securitycontext-runasuser-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
env:
- name: PORT
value: "8080"
securityContext:
runAsUser: 1001
runAsGroup: 1001
PS:普通用户(1001)没有权限监听1024以内的特权端口,所以加了env,把端口改成8080
添加禁止容器的内核功能:securitycontext-capabilities-demo
apiVersion: v1
kind: Pod
metadata:
name: securitycontext-capabilities-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c"] #改变镜像启动为容器时,镜像内设置默认要启动的命令,自定义运行的程序
args: ["/sbin/iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80 && /usr/bin/python3 /usr/local/bin/demo.py"] #向自定义command命令传递的参数
securityContext:
capabilities:
add: ['NET_ADMIN']
drop: ['CHOWN']
常用的capabilities:
修改容器的内核参数:securitycontext-sysctls-demo
apiVersion: v1
kind: Pod
metadata:
name: securitycontext-sysctls-demo
namespace: default
spec:
securityContext:
sysctls:
- name: kernel.shm_rmid_forced
value: "0"
- name: net.ipv4.ip_unprivileged_port_start
value: "0"
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1001
runAsGroup: 1001
Pod内可安全使用的内核参数只有三个:
若需要添加不被允许的内核参数,需要添加如下文件:
vim /etc/default/kubelet
KUBELET_EXTRA_ARGS='需要添加的内核参数'
PS:且每一个节点都需要修改,且修改后要重启kubelet后才能生效
all-in-one
apiVersion: v1
kind: Pod
metadata:
name: all-in-one
namespace: default
spec:
initContainers:
- name: iptables-init
image: ikubernetes/admin-box:latest
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c']
args: ['iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80']
securityContext:
capabilities:
add:
- NET_ADMIN
containers:
- name: sidecar-proxy
image: envoyproxy/envoy-alpine:v1.13.1
command: ['/bin/sh','-c']
args: ['sleep 3 && envoy -c /etc/envoy/envoy.yaml']
lifecycle:
postStart:
exec:
command: ['/bin/sh','-c','wget -O /etc/envoy/envoy.yaml http://ilinux.io/envoy.yaml']
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
readinessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
env:
- name: PORT
value: '8080'
livenessProbe:
httpGet:
path: '/livez'
port: 8080
initialDelaySeconds: 5
readinessProbe:
httpGet:
path: '/readyz'
port: 8080
initialDelaySeconds: 15
securityContext:
runAsUser: 1001
runAsGroup: 1001
resources:
requests:
cpu: 0.5
memory: "64Mi"
limits:
cpu: 2
memory: "1024Mi"
securityContext:
supplementalGroups: [1002, 1003]
fsGroup: 2000