一、通过环境变量向容器传递参数
即在容器中嵌套使用env字段。Name定义环境变量名,值定义在value字段上。
apiVersion: v1
kind: Pod
metadata:
name: pod-using-env
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
env:
- name: HOST
value: "127.0.0.1"
- name: PORT
value: "8080"
apply该配置文件,进入容器可以看到有监听8080端口。
二、Pod的健康状态监测机制
探针是由 kubelet 对容器执行的定期诊断,是一种容器状态的探测方法,用于保证Pod始终处于运行状态,即使出了问题也能快速重启。常见的探针类型如下:
- startupProbe:启动探针
判断容器内的应用程序是否已启动完成,如果配置了启动探测,则会先禁用所有其它的探测,直到startupProbe检测成功为止,如果startupProbe探测失败,则kubelet将杀死容器,容器将按照重启策略进行下一步操作。如果容器没有提供启动探测,则默认状态为成功。当一些程序启动时间很长时可用此探针,用于做初始化监测。
- livenessProbe:存活探针
存活探测将通过http、shell命令或者tcp等方式去检测容器是否正常运行(健康),然后将检查结果返回给kubelet,如果检查容器中应用为不健康状态提交给kubelet后,kubelet将根据Pod配置清单中定义的重启策略restartPolicy来对Pod进行重启。如果容器配置中没有配置 livenessProbe,Kubelet 将认为存活探针探测一直为成功状态。
- readinessProbe:就绪探针
就绪探测也是通过http、shell命令或者tcp等方式去检测容器中的应用是否能够正常对外提供服务。如果能够正常对外提供服务,则认为该容器为就绪状态,可加到Pod前段负载请求。如果探测失败,则将容器标记为未就绪状态,对应的service会把pod从前端负载移除。该探针不会重启Pod。
对于被Service所管理的Pod,Service与被管理Pod的关联关系也将基于Pod是否就绪进行设置,Pod对象启动后,容器应用通常需要一段时间才能完成其初始化的过程,例如加载配置或数据,甚至有些程序需要运行某类的预热过程,若在此阶段完成之前就接收客户端的请求,那么客户端返回时间肯定非常慢,严重影响了体验,所以需避免Pod对象启动后立即让其处理客户端请求,而是等待容器初始化工作执行完成并转为就绪状态后再接收客户端请求。
上述三种探测类型(探针)均支持如下方式对容器做健康检查:
- ExecAction:在容器中执行命令,命令执行后返回的状态为0则成功,表示我们探测结果正常。
- HTTPGetAction:根据容器IP、端口以及路径发送HTTP请求,返回码如果是200-400之间表示成功。
- TCPSocketAction:根据容器IP地址及特定的端口进行TCP检查,端口开放表示成功。
其中exec通用性最强,适用与大部分场景,tcpSocket适用于TCP业务,httpGet适用于web业务。
以上每种检查动作都可能有以下三种返回状态:
- Success,表示通过了健康检查
- Failure,表示没有通过健康检查
- Unknown,表示检查动作失败
对容器健康探测的总结:
在Kubernetes中Pod是最小的计算单元,而一个Pod又由多个容器组成,相当于每个容器就是一个应用,应用启动需要一个过程,如果花费时间比较长可用启动探针检测启动状态(用于程序启动过程中的检测)。
应用启动成功后,在运行期间,可能因为某些意外情况致使程序挂掉。那么如何监控这些容器状态稳定性,保证服务在运行期间不会发生问题,发生问题后进行重启等机制,就成为了重中之重的事情,考虑到这点 kubernetes 推出了存活性探针机制。
有了存活性探针能保证程序在运行中如果挂掉能够自动重启,但是还有个经常遇到的问题,比如说,在Kubernetes中启动Pod,显示明明Pod已经启动成功,且能访问里面的端口,但是却返回错误信息。还有就是在执行滚动更新时候,总会出现一段时间,Pod对外提供网络访问,但是访问却发生404,这两个原因,都是因为Pod已经成功启动,但是 Pod 的的容器中应用程序还在启动中导致,考虑到这点Kubernetes推出了就绪性探针机制。
启动探针一旦探测成功即退出,后续由存活探针和就绪探针周期执行。
Pod探针相关属性如下:
- initialDelaySeconds:容器启动后要等待多少秒后探针开始工作,单位“秒”,默认是0秒,最小值是0。
- periodSeconds:执行 探测的时间间隔(单位是秒),默认为10s,单位“秒”,最小值是1。
- timeoutSeconds:探针执行检测请求后,等待响应的超时时间,默认为1,单位“秒”。
- successThreshold:连续探测几次成功,才认为探测成功,默认为1,在 Liveness 探针中必须为1,最小值为1。
- failureThreshold:探测失败的重试次数,重试一定次数(连续几次)后将认为失败,在readiness探针中,Pod会被标记为未就绪,默认为3,最小值为1。
示例1
如下示例1使用liveness探针,结合exec方式探测
vim liveness-exec-demo.yaml
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
之后apply配置文件即可。此时探测livez结果也是OK。
可以人为的让它探测失败
curl -XPOST -d 'livez=FAIL' 192.168.113.4/livez
然后再次探测livez结果就是FAIL,查看响应码就变成了506
用kubectl describe命令查看events描述,发现探测失败后重试3次,仍然失败后就重启。之后再探测livez就OK了。
示例2
如下示例2使用liveness探针,结合TCPSocket方式探测。
vim liveness-tcpsocket-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcpsocket-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
ports:
#这里80端口可以被命名为http,供后续的tcpSocket引用
- name: http
containerPort: 80
#容器级别的安全上下文,作用于当前容器
securityContext:
#打开/删除某个内核权限
capabilities:
add:
#添加可执行iptables命令的权限
- NET_ADMIN
livenessProbe:
tcpSocket:
port: http
periodSeconds: 5
#5s之后进行TCPSocket检测
initialDelaySeconds: 5
之后apply配置文件即可,此时Pod是正常运行的。
要想人为的使之失败,可进入容器内设置iptables规则阻塞80端口,这样tcp请求过不来。
iptables -A INPUT -p tcp --dport 80 -j REJECT
此时,请求80端口的健康监测就会失败。网络名称空间的设定附加在pause容器之上,因此添加的iptables规则在应用重启后仍然存在。需要手动设置清空iptables规则(iptables -F)或开放80端口,Pod才能正常运行。
示例3
如下示例3使用liveness探针,结合HTTPGet方式探测。
vim liveness-httpget-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
#请求的HTTP资源路径
path: '/livez'
#请求的端口。必选字段
port: 80
#建立连接使用的协议,HTTP或HTTPS。默认为HTTP
scheme: HTTP
initialDelaySeconds: 5
之后apply应用即可。测试时也可以发送一个POST请求,说明livez=FAIL(不等于OK即可,参考示例1)。之后容器因健康检测失败而重启
示例4
如下示例4使用readiness探针,结合HTTPGet方式探测。
vim readiness-httpget-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-demo
namespace: default
labels:
name: readiness-httpget-demo
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
之后执行kubectl apply即可。
apply成功后测试方法类似,还是发一个POST请求,说明readyz=FAIL。此时响应码就变成507,探测Pod不是就绪状态了,但不会重启Pod(因为使用的是readiness探针)。
创建service再验证当Pod处于未就绪状态时,其是否被service踢出去。
kubectl create service clusterip readiness-httpget-demo --tcp=80:80 --dry-run=client -o yaml > readiness-probe.yaml
cat readiness-probe.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: readiness-httpget-demo
name: readiness-httpget-demo
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
name: readiness-httpget-demo
type: ClusterIP
status:
loadBalancer: {}
kubectl apply -f readiness-probe.yaml
查看service的详细信息,此时在后端列表中有对应Pod。
再次测试,当Pod探测失败后再重试3次,最终处于非就绪状态时,Pod就会在后端列表中被删掉(但是Pod仍然存在),Service地址亦不能访问。
如果readyz=OK,修复了,那该Pod又会添加到对应service的后端。
三、安全上下文
3.1 背景
容器中的应用程序默认以root账号运行的,这个root与宿主机root账号是相同的, 拥有大部分对Linux内核的系统调用权限,这样是不安全的,所以需要将容器以普通用户运行,减少应用程序对权限的使用。(ps:容器本身就是宿主机的一个进程)
3.2 介绍
安全上下文(Security Context)是一组为Pod或容器提供的安全机制,可以定义特权和访问控制。换句话说,Kubernetes支持在Pod和容器级别分别使用安全上下文。安全上下文的设置包含以下方面:
- 自主访问控制(Discretionary Access Control):基于用户 ID(UID)和组 ID(GID)来判定对对象(例如文件)的访问权限。
- 设置容器运行的用户及资源访问权限。
- Linux Capabilities:给进程一些特权,但不是root用户的所有特权。
- Seccomp:对进程的系统调用添加控制机制。
- AppArmor:是Linux内核的一个安全模块,通过加载到内核的配置文件来限制单个程序的功能。
- SELinux:是Linux内核的一个安全模块,为对象分配安全标签。
- Privileged Mode:是否运行为特权模式容器,容器默认运行为非特权模式。有了特权模式,容器中的root用户具有真正的管理员权限(与Docker类似),可以看到主机上的所有设备、挂载文件系统等。
- AllowPrivilegeEscalation:控制是否允许特权升级,即进程是否可以获得比其父进程更多的特权。
3.3 配置格式
Kubernetes的安全上下文配置参数说明(以yaml格式展示):
apiVersion: v1
kind: Pod
metadata: {…}
spec:
securityContext: # Pod级别的安全上下文,对内部所有容器均有效
runAsUser # 以指定的用户身份运行容器进程,默认由镜像中的USER指定
runAsGroup # 以指定的用户组运行容器进程,默认使用的组随容器运行时
supplementalGroups # 为容器中1号进程的用户添加的附加组;
fsGroup # 为容器中的1号进程附加的一个专用组,其功能类似于sgid
runAsNonRoot # 是否以非root身份运行
seLinuxOptions
3.4 容器的内核功能
- CAP_CHOWN:改变文件的UID和GID;
- CAP_MKNOD:mknod(),创建设备文件;
- CAP_NET_ADMIN:网络管理权限;
- CAP_SYS_ADMIN:支持内核大部分的管理权限;
- CAP_SYS_TIME:设置系统时间
- CAP_SYS_MODULE:装载卸载内核模块
- CAT_NET_BIND_SERVICE:绑定小于1024的特权端口
- CAP_NET_BIND_SERVER:允许绑定特权端口
下面给出一个示例
vim securitycontext-capabilities-demo.yaml
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"]
#把对8080端口的访问重定向到80端口,再执行相关python脚本
args: ["/sbin/iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80 && /usr/bin/python3 /usr/local/bin/demo.py"]
securityContext:
capabilities:
#添加可执行iptables命令的权限
add: ['NET_ADMIN']
#移除chown命令的权限
drop: ['CHOWN']
kubectl apply -f securitycontext-capabilities-demo.yaml
此时可以看到,iptables添加的规则已位于NAT表的PREROUTING链上。
检查demo容器的root用户是否可以修改文件属主/属组,结果发现chown功能已关闭,不能使用。
四、资源需求和限制
4.1 资源需求(requests)
- 定义需要系统预留给该容器使用的资源最小可用值(下限)。
- 容器运行时可能用不到这些额度的资源,一旦用到时需保证有对应数量的资源可用。
- 资源需求的定义会影响调度器的决策。
怎么理解呢?比如有个应用,至少需要4G内存,有3个Node节点,内存分别剩余2G、3G、8G。那就要调度到剩余8G的Node 节点上,这样能满足Pod的运行条件。至于能不能用到4G那另说。
4.2 资源限制(limits)
- 定义该容器可以申请使用的最大资源可用值(上限),超出该额度的资源申请被拒绝。
- 该限制需大于等于资源需求的值。
换句话说,资源需求说明了容器要求得有多少资源,而资源限制说明了容器最多能使用多少资源。如果未定义资源限制,当应用程序出现bug时就会不断消耗资源,直至资源耗尽。
资源需求和资源限制定义在容器级别,主要针对cpu、内存来使用。cpu属于可压缩性资源,即资源额度可按需弹性变化。内存属于不可压缩性资源,对其进行压缩可能导致进程崩溃等问题。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 富文本编辑器 VUE-QUILL-EDITOR 使用教程 (最全)
VUE-QUILL-EDITOR 基于 QUILL、适用于 VUE 的富文本编辑器,支持服务端渲染和单页应用,非常高效简洁。 一.基础用法 1、NPM 导入 VUE-QUILL-EDITOR npm install vue-quill-editor –sav…