《重识云原生系列》专题索引:
- 第一章——不谋全局不足以谋一域
- 第二章计算第1节——计算虚拟化技术总述
- 第二章计算第2节——主流虚拟化技术之VMare ESXi
- 第二章计算第3节——主流虚拟化技术之Xen
- 第二章计算第4节——主流虚拟化技术之KVM
- 第二章计算第5节——商用云主机方案
- 第二章计算第6节——裸金属方案
- 第三章云存储第1节——分布式云存储总述
- 第三章云存储第2节——SPDK方案综述
- 第三章云存储第3节——Ceph统一存储方案
- 第三章云存储第4节——OpenStack Swift 对象存储方案
- 第三章云存储第5节——商用分布式云存储方案
- 第四章云网络第一节——云网络技术发展简述
- 第四章云网络4.2节——相关基础知识准备
- 第四章云网络4.3节——重要网络协议
- 第四章云网络4.3.1节——路由技术简述
- 第四章云网络4.3.2节——VLAN技术
- 第四章云网络4.3.3节——RIP协议
- 第四章云网络4.3.4节——OSPF协议
- 第四章云网络4.3.5节——EIGRP协议
- 第四章云网络4.3.6节——IS-IS协议
- 第四章云网络4.3.7节——BGP协议
- 第四章云网络4.3.7.2节——BGP协议概述
- 第四章云网络4.3.7.3节——BGP协议实现原理
- 第四章云网络4.3.7.4节——高级特性
- 第四章云网络4.3.7.5节——实操
- 第四章云网络4.3.7.6节——MP-BGP协议
- 第四章云网络4.3.8节——策略路由
- 第四章云网络4.3.9节——Graceful Restart(平滑重启)技术
- 第四章云网络4.3.10节——VXLAN技术
- 第四章云网络4.3.10.2节——VXLAN Overlay网络方案设计
- 第四章云网络4.3.10.3节——VXLAN隧道机制
- 第四章云网络4.3.10.4节——VXLAN报文转发过程
- 第四章云网络4.3.10.5节——VXlan组网架构
- 第四章云网络4.3.10.6节——VXLAN应用部署方案
- 第四章云网络4.4节——Spine-Leaf网络架构
- 第四章云网络4.5节——大二层网络
- 第四章云网络4.6节——Underlay 和 Overlay概念
- 第四章云网络4.7.1节——网络虚拟化与卸载加速技术的演进简述
- 第四章云网络4.7.2节——virtio网络半虚拟化简介
- 第四章云网络4.7.3节——Vhost-net方案
- 第四章云网络4.7.4节vhost-user方案——virtio的DPDK卸载方案
- 第四章云网络4.7.5节vDPA方案——virtio的半硬件虚拟化实现
- 第四章云网络4.7.6节——virtio-blk存储虚拟化方案
- 第四章云网络4.7.8节——SR-IOV方案
- 第四章云网络4.7.9节——NFV
- 第四章云网络4.8.1节——SDN总述
- 第四章云网络4.8.2.1节——OpenFlow概述
- 第四章云网络4.8.2.2节——OpenFlow协议详解
- 第四章云网络4.8.2.3节——OpenFlow运行机制
- 第四章云网络4.8.3.1节——Open vSwitch简介
- 第四章云网络4.8.3.2节——Open vSwitch工作原理详解
- 第四章云网络4.8.4节——OpenStack与SDN的集成
- 第四章云网络4.8.5节——OpenDayLight
- 第四章云网络4.8.6节——Dragonflow
1 Pod使用
1.10 访问 DNS 的策略
通过设置 dnsPolicy 参数,设置 Pod 中容器访问 DNS 的策略:
- ClusterFirst:优先基于 cluster domain (如 default.svc.cluster.local) 后缀,通过 kube-dns 查询 (默认策略);
- Default:优先从 Node 中配置的 DNS 查询;
1.11 使用主机的 IPC 命名空间
通过设置 spec.hostIPC 参数为 true,使用主机的 IPC 命名空间,默认为 false。
1.12 使用主机的网络命名空间
通过设置 spec.hostNetwork 参数为 true,使用主机的网络命名空间,默认为 false。
1.13 使用主机的 PID 空间
通过设置 spec.hostPID 参数为 true,使用主机的 PID 命名空间,默认为 false。
apiVersion: v1
kind: Pod
metadata:
name: busybox1
labels:
name: busybox
spec:
hostIPC: true
hostPID: true
hostNetwork: true
containers:
- image: busybox
command:
- sleep
- "3600"
name: busybox
1.14 设置 Pod 的 hostname
通过 spec.hostname 参数实现,如果未设置默认使用 metadata.name 参数的值作为 Pod 的 hostname。
1.15 设置 Pod 的子域名
通过 spec.subdomain 参数设置 Pod 的子域名,默认为空。比如,指定 hostname 为 busybox-2 和 subdomain 为 default-subdomain,完整域名为 busybox-2.default-subdomain.default.svc.cluster.local,也可以简写为 busybox-2.default-subdomain.default:
apiVersion: v1
kind: Pod
metadata:
name: busybox2
labels:
name: busybox
spec:
hostname: busybox-2
subdomain: default-subdomain
containers:
- image: busybox
command:
- sleep
- "3600"
name: busybox
注意:
- 默认情况下,DNS 为 Pod 生成的 A 记录格式为 pod-ip-address.my-namespace.pod.cluster.local,如 1-2-3-4.default.pod.cluster.local;
- 上面的示例还需要在 default namespace 中创建一个名为 default-subdomain(即 subdomain)的 headless service,否则其他 Pod 无法通过完整域名访问到该 Pod(只能自己访问到自己);
kind: Service
apiVersion: v1
metadata:
name: default-subdomain
spec:
clusterIP: None
selector:
name: busybox
ports:
- name: foo
# Actually, no port is needed.
port: 1234
targetPort: 1234
注意:
必须为 headless service 设置至少一个服务端口(spec.ports,即便它看起来并不需要),否则 Pod 与 Pod 之间依然无法通过完整域名来访问。
1.16 设置 Pod 的 DNS 选项
从 v1.9 开始,可以在 kubelet 和 kube-apiserver 中设置 --feature-gates=CustomPodDNS=true 开启设置每个 Pod DNS 地址的功能。
注意:该功能在 v1.10 中为 Beta 版,v1.9 中为 Alpha 版。
apiVersion: v1
kind: Pod
metadata:
namespace: default
name: dns-example
spec:
containers:
- name: test
image: nginx
dnsPolicy: "None"
dnsConfig:
nameservers:
- 1.2.3.4
searches:
- ns1.svc.cluster.local
- my.dns.search.suffix
options:
- name: ndots
value: "2"
- name: edns0
对于旧版本的集群,可以使用 ConfigMap 来自定义 Pod 的 /etc/resolv.conf,如:
kind: ConfigMap
apiVersion: v1
metadata:
name: resolvconf
namespace: default
data:
resolv.conf: |
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.0.0.10
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: dns-test
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
name: dns-test
spec:
containers:
- name: dns-test
image: alpine
stdin: true
tty: true
command: ["sh"]
volumeMounts:
- name: resolv-conf
mountPath: /etc/resolv.conf
subPath: resolv.conf
volumes:
- name: resolv-conf
configMap:
name: resolvconf
items:
- key: resolv.conf
path: resolv.conf
1.17 资源限制
Kubernetes 通过 cgroups 限制容器的 CPU 和内存等计算资源,包括 requests(请求,调度器保证调度到资源充足的 Node 上,如果无法满足会调度失败)和 limits(上限)等:
- spec.containers[].resources.limits.cpu:CPU 上限,可以短暂超过,容器也不会被停止
- spec.containers[].resources.limits.memory:内存上限,不可以超过;如果超过,容器可能会被终止或调度到其他资源充足的机器上
- spec.containers[].resources.limits.ephemeral-storage:临时存储(容器可写层、日志以及 EmptyDir 等)的上限,超过后 Pod 会被驱逐
- spec.containers[].resources.requests.cpu:CPU 请求数,也是调度 CPU 资源的依据,可以超过
- spec.containers[].resources.requests.memory:内存请求数,也是调度内存资源的依据,可以超过;但如果超过,容器可能会在 Node 内存不足时清理
- spec.containers[].resources.requests.ephemeral-storage:临时存储(容器可写层、日志以及 EmptyDir 等)的请求数,调度容器存储的依据
比如 nginx 容器请求 30% 的 CPU 和 56MB 的内存,但限制最多只用 50% 的 CPU 和 128MB 的内存:
apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
resources:
requests:
cpu: "300m"
memory: "56Mi"
limits:
cpu: "1"
memory: "128Mi"
注意
- CPU 的单位是 CPU 个数,可以用 millicpu (m) 表示少于 1 个 CPU 的情况,如 500m = 500millicpu = 0.5cpu,而一个 CPU 相当于:
- AWS 上的一个 vCPU
- GCP 上的一个 Core
- Azure 上的一个 vCore
- 物理机上开启超线程时的一个超线程
- 内存的单位则包括 E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki 等。
- 从 v1.10 开始,可以设置 kubelet ----cpu-manager-policy=static 为 Guaranteed(即 requests.cpu 与 limits.cpu 相等)Pod 绑定 CPU(通过 cpuset cgroups)。
1.18 健康检查
1.18.1 容器探针
- livenessProbe:存活探针,指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为Success。
- readinessProbe:就绪探针,指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。
#查看livenessProbe帮助命令:
kubectl explain pods.spec.containers.livenessProbe
#查看readinessProbe帮助命令:
kubectl explain pods.spec.containers.readinessProbe
整个图如下:
从上面可以看出,我们pod在从创建到结束之前,会一直处于某种状态之中。
1.18.2 LivenessProbe探针配置
[root@master yaml]# cat liveness.yaml
kind: Pod
apiVersion: v1
metadata:
name: liveness
labels:
test: liveness
spec:
restartPolicy: OnFailure
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/test; sleep 60; rm -rf /tmp/test; sleep 300
livenessProbe:
exec:
command:
- cat
- /tmp/test
initialDelaySeconds: 10
periodSeconds: 5
- initialDelaySeconds: Pod运行多长时间进行探测(单位是秒);
- periodSeconds: 每隔多长时间进行一次探测(单位是秒);
上述yaml文件中针对/tmp/test这个文件进行指定了健康检查策略为 livenessProbe,并且指定了重启策略为OnFailure。这样容器可以正常的运行,但是总是会重启。如图:
1.18.3 ReadinessProbe探针配置
配置几乎是一模一样的,只是健康检测的方式更换一下,如下:
[root@master yaml]# cat readiness.yaml
kind: Pod
apiVersion: v1
metadata:
name: readiness
labels:
test: readiness
spec:
restartPolicy: OnFailure
containers:
- name: readiness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/test; sleep 60; rm -rf /tmp/test; sleep 300
readinessProbe:
exec:
command:
- cat
- /tmp/test
initialDelaySeconds: 10
periodSeconds: 5
那么此时运行的pod状态如图:
查看的效果可能不是很明显,使用以下方法,便可查看具体的效果。
[root@master yaml]# cat hcscal.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: web
spec:
replicas: 3
template:
metadata:
labels:
run: web
spec:
containers:
- name: web
image: httpd
ports:
- containerPort: 80
readinessProbe:
httpGet:
scheme: HTTP
path: /healthy
port: 80
initialDelaySeconds: 10
periodSeconds: 5
---
kind: Service
apiVersion: v1
metadata:
name: web-svc
spec:
type: NodePort
selector:
run: web
ports:
- protocol: TCP
port: 90
targetPort: 80
nodePort: 30321
创建一个deployment资源、一个Service资源并且相互之间进行关联。
执行的结果如图:
由此可以得出以下结论:
- ReadinessProbe探针的使用场景livenessProbe稍有不同,有的时候应用程序可能暂时无法接受请求,比如Pod已经Running了,但是容器内应用程序尚未启动成功,在这种情况下,如果没有ReadinessProbe,则Kubernetes认为它可以处理请求了,然而此时,我们知道程序还没启动成功是不能接收用户请求的,所以不希望kubernetes把请求调度给它,则使用ReadinessProbe探针。
- ReadinessProbe和livenessProbe可以使用相同探测方式,只是对Pod的处置方式不同,ReadinessProbe是将Pod IP:Port从对应的EndPoint列表中删除,而livenessProbe则Kill容器并根据Pod的重启策略来决定作出对应的措施。
每种探针都支持以下三种探测方式:
- exec:通过执行命令来检查服务是否正常,针对复杂检测或无HTTP接口的服务,命令返回值为0则表示容器健康;
- httpGet:通过发送http请求检查服务是否正常,返回200-399状态码则表明容器健康;
- tcpSocket:通过容器的IP和Port执行TCP检查,如果能够建立TCP连接,则表明容器健康;
1.18.4 小结
- liveness和readiness是两种健康检查机制,如果不特意配置,K8s将两种探测采用相同的默认行为,即通过判断容器启动进程的返回值是否为零,来判断探测是否成功;
- 两种探测配置完全一样。不同之处在于探测失败后的行为:
- liveness探测是根据Pod重启策略操作容器,大多数是重启容器;
- readiness则是将容器设置为不可用,不接受service转发的请求;
- 两种探测方法可以独立存在,也可同时使用;比如使用liveness判断容器是否需要重启实现自愈;用readiness判断容器是否已经准备好对外提供服务。
1.18.5 健康检测的应用
主要应用是在scale(扩容、缩容)、更新(升级)过程中使用。下面通过一个简单的小实验进行验证:
[root@master yaml]# cat app.v1.yaml
//版本1的yaml文件创建10个副本使用busybox镜像,如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: app
spec:
replicas: 10
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox
args:
- /bin/sh
- -c
- sleep 10; touch /tmp/healthy; sleep 3000
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
使用yaml文件生成相应的资源,并且记录历史版本信息:
[root@master yaml]# kubectl apply -f app.v1.yaml --record
查看pod信息,如图:
[root@master yaml]# cat app.v2.yaml
//版本2的yaml文件创建10个副本使用busybox镜像
//并模拟(代码中有问题,并进行升级),如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: app
spec:
strategy:
rollingUpdate:
maxSurge: 2
maxUnavailable: 2
replicas: 10
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox
args:
- /bin/sh
- -c
- sleep 3000
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
//maxSurge:此参数控制滚动更新过程中,副本总数超过预期数的值,可以是整数,也可以是百分比。默认是1
//maxUnavailable:不可用Pod的值,默认为1,可以是整数,也可以是百分比
[root@master yaml]# kubectl apply -f app.v2.yamll --record
查看pod信息,如图:
从图中可以看出,一共有12个pod,并且有四个pod是不可用的!因为健康检查机制在检查到有问题时,就不会更新了剩余的pod了!
[root@master yaml]# cat app.v3.yaml
//版本2的yaml文件创建10个副本使用busybox镜像
//并且不使用健康检查机制,如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: app
spec:
replicas: 10
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox
args:
- /bin/sh
- -c
- sleep 3000
[root@master yaml]# kubectl apply -f app.v3.yamll --record
再次查看pod的状态信息,如图:
如果不使用健康检查机制,就可以看出及时pod中服务存在问题,也会全部更新!
[root@master yaml]# kubectl rollout history deployment app //查看记录的历史版本
[root@master yaml]# kubectl rollout undo deployment app --to-revision=1 //回滚到可用的版本
再次查看pod的运行状态,如图:
由此可以看出pod健康检查的重要性!
1.19 命名空间-namespace
namespace叫做命名空间,可以把k8s集群划分成多个名称空间,然后对不同的名称空间的资源做隔离,可以控制各个名称空间的入栈,出栈策略,是一种在多个用户之间划分群集资源的方法。
#查看k8s集群当前有哪些名称空间:
kubectl get namespace
1.20 pod label
(1)什么是标签?
标签其实就一对 key/value ,被关联到对象上,比如Pod,标签的使用我们倾向于能够标示对象的特殊特点,并且对用户而言是有意义的(就是一眼就看出了这个Pod是干什么的),标签可以用来划分特定组的对象(比如版本,服务类型等),标签可以在创建一个对象的时候直接给与,也可以在后期随时修改,每一个对象可以拥有多个标签,但是,key值必须是唯一的。
(2)查看所有pod资源对象的标签
kubectl get pods --show-labels
(3)查看带有指定标签的pod
kubectl get pods -L web1
(4)显示所有资源对象下web1这个标签的标签值
kubectl get pods -l web1 --show-labels
查看拥有web1这个标签的资源对象,并且把标签显示出来。
(5)想修改资源的标签,比方说想给web加上个release标签
给资源对象打标签要使用label命令,指定给某个类型下的某个资源打标签,资源中的key/value可以是多个,因此在web(pod名字)这个资源下再打个标签release,用如下命令:
kubectl label pods web release=new
查看标签是否打成功:
kubectl get pods --show-labels
显示如下,显示如下,说明标签达成功了;
NAME READY STATUS RESTARTS AGE LABELS
web 1/1 Running 1 21h release=new,web1=tomcat
(6)k8s的标签选择器:
与name和UID不同,label不提供唯一性。通常,我们会看到很多对象有着一样的label。通过标签选择器,客户端/用户能方便辨识出一组对象。
API目前支持两种标签选择器:
- 基于等值的标签选择器
- 基于集合的标签选择器
一个label选择器可以由多个必须条件组成,由逗号分隔。在多个必须条件指定的情况下,所有的条件都必须满足,因而逗号起着AND逻辑运算符的作用。
一个空的label选择器(即有0个必须条件的选择器)会选择集合中的每一个对象。
一个null型label选择器(仅对于可选的选择器字段才可能)不会返回任何对象。
基于等值关系的标签选择器:=,==,!=
基于相等性或者不相等性的条件允许用label的键或者值进行过滤。匹配的对象必须满足所有指定的label约束,尽管他们可能也有额外的label。有三种运算符是允许的,“=”,“==”和“!=”。前两种代表相等性(他们是同义运算符),后一种代表非相等性。例如:
environment = production tier != frontend
第一个选择所有键等于 environment 值为 production 的资源。后一种选择所有键为 tier 值不等于 frontend 的资源,和那些没有键为 tier 的label的资源。
要过滤所有处于 production 但不是 frontend 的资源,可以使用逗号操作符,
environment=production,tier!=frontend
基于集合的标签选择器:
基于集合的label条件允许用一组值来过滤键。支持三种操作符: in , notin ,和 exists(仅针对于key符号) 。例如:
environment in (production, qa)
tier notin (frontend, backend)
第一个例子,选择所有键等于 environment ,且value等于 production 或者 qa 的资源。 第二个例子,选择所有键等于tier且值是除了frontend 和 backend 之外的资源,和那些没有label的键是 tier 的资源。 类似的,逗号操作符相当于一个AND操作符。因而要使用一个 partition 键(不管值是什么),并且 environment 不是 qa 过滤资源可以用 partition,environment notin (qa) 。
基于集合的选择器是一个相等性的宽泛的形式,因为 environment=production 相当于environment in (production) ,与 != and notin 类似。
基于集合的条件可以与基于相等性 的条件混合。例如, partition in (customerA,customerB),environment != qa 。
标签选择器根据定义的标签可以选择匹配到的资源对象。
更多详细信息可参考:
Labels and Selectors | Kubernetes
node label
(1)查看nodes节点的标签
kubectl get nodes --show-labels
(2)给node节点打标签:
kubectl label nodes node1 node011=haha kubectl get nodes --show-labels
可以看到node01上有node011这个标签了。
(3)节点选择器nodeSelector
#查看nodeSelector帮助命令
kubectl explain pods.spec.nodeSelector
# nodeSelector <map[string]string>
# NodeSelector is a selector which must be true for the pod to fit on a node.
# Selector which must match a node's labels for the pod to be scheduled on that node.
# More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
上面有一个nodeSelector,这个是节点标签选择器,可以限制pod运行在哪个节点上
kubectl get pods -o wide
从上面可以看到web运行在node1上,如果我们想要让它运行在master1上,就需要用到节点选择器:
nodeSelector:
node011: haha #这个node011是我们给node1节点打的标签,在上面已经操作过
cat pod.yaml 看到完整的文件如下:
apiVersion: v1
kind: Pod
metadata:
name: web
namespace: default
labels:
web1: tomcat
spec:
containers:
- name: tomcat1
image: tomcat:8.5-jre8-alpine
nodeSelector:
node011:haha
kubectl delete -f pod.yaml
kubectl apply -f pod.yaml
kubectl get pods -o wide
显示pod运行在node1上。
如果node1和node2都有node011这个标签,那么nodeSelector则根据调度策略调度pod到相应的node节点上。
更多详细信息可参考:
Assigning Pods to Nodes | Kubernetes
节点名称
nodeName:指定pod节点运行在哪个具体node上,不存在调度说法。
查看 nodeName帮助命令:
kubectl explain pods.spec.nodeName
1.21 使用 Capabilities
默认情况下,容器都是以非特权容器的方式运行。比如,不能在容器中创建虚拟网卡、配置虚拟网络。
Kubernetes 提供了修改 Capabilities 的机制,可以按需要给容器增加或删除。比如下面的配置给容器增加了 CAP_NET_ADMIN 并删除了 CAP_KILL。
apiVersion: v1
kind: Pod
metadata:
name: cap-pod
spec:
containers:
- name: friendly-container
image: "alpine:3.4"
command: ["/bin/sleep", "3600"]
securityContext:
capabilities:
add:
- NET_ADMIN
drop:
- KILL
1.22 限制网络带宽
可以通过给 Pod 增加 kubernetes.io/ingress-bandwidth 和 kubernetes.io/egress-bandwidth 这两个 annotation 来限制 Pod 的网络带宽:
apiVersion: v1
kind: Pod
metadata:
name: qos
annotations:
kubernetes.io/ingress-bandwidth: 3M
kubernetes.io/egress-bandwidth: 4M
spec:
containers:
- name: iperf3
image: networkstatic/iperf3
command:
- iperf3
- -s
仅 kubenet 支持限制带宽目前只有 kubenet 网络插件支持限制网络带宽,其他 CNI 网络插件暂不支持这个功能。
kubenet 的网络带宽限制其实是通过 tc 来实现的:
# setup qdisc (only once)
tc qdisc add dev cbr0 root handle 1: htb default 30
# download rate
tc class add dev cbr0 parent 1: classid 1:2 htb rate 3Mbit
tc filter add dev cbr0 protocol ip parent 1:0 prio 1 u32 match ip dst 10.1.0.3/32 flowid 1:2
# upload rate
tc class add dev cbr0 parent 1: classid 1:3 htb rate 4Mbit
tc filter add dev cbr0 protocol ip parent 1:0 prio 1 u32 match ip src 10.1.0.3/32 flowid 1:3
1.23 调度到指定的 Node 上
可以通过 nodeSelector、nodeAffinity、podAffinity 以及 Taints 和 tolerations 等来将 Pod 调度到需要的 Node 上。
也可以通过设置 nodeName 参数,将 Pod 调度到指定 node 节点上。
比如,使用 nodeSelector,首先给 Node 加上标签:
kubectl label nodes <your-node-name> disktype=ssd
接着,指定该 Pod 只想运行在带有 disktype=ssd 标签的 Node 上:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
nodeAffinity、podAffinity 以及 Taints 和 tolerations 等的使用方法请参考 调度器章节。
1.24 自定义 hosts
默认情况下,容器的 /etc/hosts 是 kubelet 自动生成的,并且仅包含 localhost 和 podName 等。不建议在容器内直接修改 /etc/hosts 文件,因为在 Pod 启动或重启时会被覆盖。
默认的 /etc/hosts 文件格式如下,其中 nginx-4217019353-fb2c5 是 podName:
$ kubectl exec nginx-4217019353-fb2c5 -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.244.1.4 nginx-4217019353-fb2c5
从 v1.7 开始,可以通过 pod.Spec.HostAliases 来增加 hosts 内容,如:
apiVersion: v1
kind: Pod
metadata:
name: hostaliases-pod
spec:
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "foo.local"
- "bar.local"
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
containers:
- name: cat-hosts
image: busybox
command:
- cat
args:
- "/etc/hosts"
$ kubectl logs hostaliases-pod
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.244.1.5 hostaliases-pod
127.0.0.1 foo.local
127.0.0.1 bar.local
10.1.2.3 foo.remote
10.1.2.3 bar.remote
1.25 HugePages
v1.8 + 支持给容器分配 HugePages,资源格式为 hugepages-(如 hugepages-2Mi)。使用前要配置:
- 开启 --feature-gates="HugePages=true"
- 在所有 Node 上面预分配好 HugePage ,以便 Kubelet 统计所在 Node 的 HugePage 容量
使用示例
apiVersion: v1
kind: Pod
metadata:
generateName: hugepages-volume-
spec:
containers:
- image: fedora:latest
command:
- sleep
- inf
name: example
volumeMounts:
- mountPath: /hugepages
name: hugepage
resources:
limits:
hugepages-2Mi: 100Mi
volumes:
- name: hugepage
emptyDir:
medium: HugePages
注意事项:
- HugePage 资源的请求和限制必须相同;
- HugePage 以 Pod 级别隔离,未来可能会支持容器级的隔离;
- 基于 HugePage 的 EmptyDir 存储卷最多只能使用请求的 HugePage 内存;
- 使用 shmget() 的 SHM_HUGETLB 选项时,应用必须运行在匹配 proc/sys/vm/hugetlb_shm_group 的用户组(supplemental group)中;
1.26 优先级
从 v1.8 开始,可以为 Pod 设置一个优先级,保证高优先级的 Pod 优先调度。
优先级调度功能目前为 Beta 版,在 v1.11 版本中默认开启。对 v1.8-1.10 版本中使用前需要开启:
- --feature-gates=PodPriority=true
- --runtime-config=scheduling.k8s.io/v1alpha1=true --admission-control=Controller-Foo,Controller-Bar,...,Priority
为 Pod 设置优先级前,先创建一个 PriorityClass,并设置优先级(数值越大优先级越高):
apiVersion: scheduling.k8s.io/v1alpha1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only."
Kubernetes 自动创建了 system-cluster-critical 和 system-node-critical 等两个 PriorityClass,用于 Kubernetes 核心组件。
为 Pod 指定优先级:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
priorityClassName: high-priority
当调度队列有多个 Pod 需要调度时,优先调度高优先级的 Pod。而当高优先级的 Pod 无法调度时,Kubernetes 会尝试先删除低优先级的 Pod 再将其调度到对应 Node 上(Preemption)。
注意:受限于 Kubernetes 的调度策略,抢占并不总是成功。
1.27 PodDisruptionBudget
PodDisruptionBudget (PDB) 用来保证一组 Pod 同时运行的数量,这些 Pod 需要使用 Deployment、ReplicationController、ReplicaSet 或者 StatefulSet 管理。
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
maxUnavailable: 1
selector:
matchLabels:
app: zookeeper
1.28 Sysctls
Sysctls 允许容器设置内核参数,分为安全 Sysctls 和非安全 Sysctls:
- 安全 Sysctls:即设置后不影响其他 Pod 的内核选项,只作用在容器 namespace 中,默认开启。包括以下几种
- kernel.shm_rmid_forced
- net.ipv4.ip_local_port_range
- net.ipv4.tcp_syncookies
- 非安全 Sysctls:即设置好有可能影响其他 Pod 和 Node 上其他服务的内核选项,默认禁止。如果使用,需要管理员在配置 kubelet 时开启,如 kubelet --experimental-allowed-unsafe-sysctls 'kernel.msg*,net.ipv4.route.min_pmtu'
v1.6-v1.10 示例:
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
annotations:
security.alpha.kubernetes.io/sysctls: kernel.shm_rmid_forced=1
security.alpha.kubernetes.io/unsafe-sysctls: net.ipv4.route.min_pmtu=1000,kernel.msgmax=1 2 3
spec:
...
从 v1.11 开始,Sysctls 升级为 Beta 版本,不再区分安全和非安全 sysctl,统一通过 podSpec.securityContext.sysctls 设置,如:
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
spec:
securityContext:
sysctls:
- name: kernel.shm_rmid_forced
value: "0"
- name: net.ipv4.route.min_pmtu
value: "552"
- name: kernel.msgmax
value: "65536"
...
1.29 Pod 时区
很多容器都是配置了 UTC 时区,与国内集群的 Node 所在时区有可能不一致,可以通过 HostPath 存储插件给容器配置与 Node 一样的时区:
apiVersion: v1
kind: Pod
metadata:
name: sh
namespace: default
spec:
containers:
- image: alpine
stdin: true
tty: true
volumeMounts:
- mountPath: /etc/localtime
name: time
readOnly: true
volumes:
- hostPath:
path: /etc/localtime
type: ""
name: time
参考链接
Kubernetes中pod详解_人间不值得-的博客-CSDN博客
k8s之pod与Pod控制器 - woaiyitiaochai - 博客园
kubernetes 实践四:Pod详解 - xingyys - 博客园
K8S Pod详解_ldd儆儆的博客-CSDN博客_k8s pod
k8s之pod详解_爱show的小卤蛋的博客-CSDN博客_k8s pod
- What is Pod?
- Kubernetes Pod Lifecycle
- DNS Pods and Services
- Container capabilities
- Configure Liveness and Readiness Probes
- Init Containers
- Linux Capabilities
- Manage HugePages
- Document supported docker image (Dockerfile) features