创建Pod
kubectl创建nginx pod
编写 nginx pod的yaml文件
apiVersion: v1
kind: Pod
metadata:
name: my-nginx
labels:
name: my-nginx
spec:
containers:
- image: nginx
name: my-nginx
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
创建
kubectl create -f nginx.yaml
Pod实现原理
什么是Pod
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。Pod的共享上下文包括一组Linux命名空间、控制组(cgroup)和可能的一些其他隔离,即用来隔离docker容器的技术。在Pod上下文中,每个独立的应用可能会进一步实施隔离。就Docker概念的术语而言,Pod类似于共享命名空间和文件系统卷的一组Docker容器。
使用Pod
通常不需要直接创建Pod、甚至单实例Pod。相反,会使用诸如Deployment或job这类工作负载资源来创建Pod。如果pod需要跟踪状态,可以考虑StatefulSet资源。
Kubernetes集群中Pod主要有2种用法:
1、运行单个容器的Pod。”每个Pod一个容器“模型是最常见的Kubernetes用例,在这种情况下,可以将Pod看做单个容器的包装器,并且Kubernetes直接管理Pod,而不是容器;
2、运行多个协同工作的容器的Pod。Pod可能封装有多个精密耦合切需要共享资源的共处容器组成的应用程序。这些位于同一位置的容器可能形成单个内聚的服务单元:一个容器将文件从共享卷提供给公众,而另一个单独的边车(sidecar)容器则刷新或更新这些文件。Pod将这些容器和存储资源打包为一个可管理的实体。
Pod网络
每个Pod都在每个地址族中获得一个唯一的Ip地址。Pod中的每个容器共享网络命名空间,包括IP地址和网络端口。Pod内的容器可以使用localhost互相通信。当Pod中的容器与Pod外的实体通信是,他们必须协调如果使用共享的网络资源(例如端口)
Pod生命周期
和一个个独立的应用容器一样,Pod也别认为是相对临时性(而不是长期存在)的实体。Pod会被创建、赋予一个唯一ID,并被调度到节点,并在终止或删除之前一直运行在该节点。如果一个节点挂掉了,调度到该节点的Pod也被计划在预定超时时限结束后删除
容器阶段 Phase
1、Pending(挂起) Pod已被Kubernetes系统接受,但有一个或多个容器尚未创建或运行。此阶段包括等待pod被调度的时间和通过网络下载镜像的时间
2、Running(运行中)Pod已被绑定到某个节点,Pod中所有的容器都已被创建,至少有一个容器仍在运行或正处于启动或重启状态
3、Succeeded(正常终止)Pod中所有的容器都成功终止,并且不会再重启
4、Failed(异常停止)Pod中所有容器都已终止,并且最少有一个容器是因为失败终止,也就是说,容器以非0状态退出或者被系统终止
5、Unknown(未知状态)因为某些原因无法取得Pod状态。这种情况通常是因为与Pod所在主机通信故障导致
容器状态
调度器将Pod分派给某个节点,kubelet就通过容器运行时开始为Pod创建容器。容器的状态有3中:Wating、Running、Terminated
容器生命周期事件处理函数
postStart和preStop处理函数
示例:lifecycle.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle
labels:
name: lifecycle
spec:
containers:
- name: lifecycle-demo-container
image: nginx
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 81
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]
验证:
[root@master k8s]# kubectl exec -it lifecycle sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# cat /usr/share/message
Hello from the postStart handler
#
包含Init容器的Pod
Init容器
每个Pod中可以包含多个容器,应用运行在这些容器里面,同时Pod也可以有一个或多个先于用用启动的Init容器。
Init容器与普通的容器非常像,除了以下2点:
1、它们总是运行到完成
2、每个都必须在下一个启动之前成功完成
如果Pod的Init容器失败,Kubernetes会不断重启该Pod,知道Init容器成功启动为止。然而,如果Pod对应的restartPolicy值为Never,Kubernetes不会重新启动Pod
与普通容器的不同之处
Init容器支持应用容器的全部属性和特性,包括资源限制、数据卷和安全设置。
Init容器不支持lifecycle、livenessProbe、readinessProbe和startupProbe,因为它们必须在Pod就绪之前运行完成
示例:initPod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
containers:
- name: myapp
image: busybox:1.28
command: ['sh','-c','date && sleep 3600']
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 81
initContainers:
- name: init
image : busybox:1.28
command: ['sh','-c','date && sleep 10']
定义一个具有2个Init容器的简单Pod。第一个等待myservice启动,第二个等待mydb启动,一旦这个2个Init容器都启动完成,Pod将启动应用容器
[root@master k8s]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
my-nginx 1/1 Running 0 19h
myapp 0/1 Init:0/1 0 14s
myapp 0/1 PodInitializing 0 17s
myapp 1/1 Running 0 18s
kubect^C[root@master k8s]#
[root@master k8s]# kubectl logs myapp
Thu Mar 2 02:24:57 UTC 2023
[root@master k8s]# kubectl logs myapp -c init
Thu Mar 2 02:24:46 UTC 2023
[root@master k8s]#
Init容器将会等待10秒,Init容器执行完毕,随后my-app的Pod进入running状态
用探针检查Pod的健康
探针的作用
探针是由kubelet 对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的handler,有三种类型的handler:
ExecAction:在容器内执行指定命令,如果命令退出时返回状态码为0,则认为诊断成功
TCPSockerAction:对容器的Ip地址上的指定端口执行TCP检查,如果端口打开,则认为诊断成功
HTTPGetAction:对容器ip地址上指定的端口和路径执行HTTP GET请求,如果响应的状态码>=200且
每次探针都将获得以下三种结果之一:
Success:容器诊断成功
Failure:容器未通过诊断
Unknown:诊断失败,不会采取任何动作
使用场景
容器需要较长时间才能启动就绪的Pod而言,启动探针是有用的。不需要配置一个较长的存活态探测时间间隔,只需要设置另一个独立的配置选定,对启动期间的容器执行探测,从而允许使用远远超出存活态时间间隔所允许的时长。
如果容器启动时间通常超出initialDelaySeconds+failureThreshold*periodSeconds总值,你就应该设置一个启动探针,对存活态探针所使用的同一端点执行检查。periodSeconds的默认值是30秒,failureThreshold设置的应其足够高,以便容器有充足的时间完成启动,并且避免更改存活态探针所使用的默认值,这一设置有助于减少死锁状况的发生。
示例:liveness.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-http
labels:
test: liveness
spec:
containers:
- name: liveness
image: mirrorgooglecontainers/liveness
args:
- /server
resources:
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
liveness /healthz 在容器存活的最开始10秒内,会返回200状态码,之后返回500状态码
kubelet在容器启动之后3秒开始执行健康检查,所以前几次健康检查都是成功的,但是10秒之后,健康检查会失败,同时kubelet会杀死容器再重新启动容器
启动命令和参数
创建Pod时设置命令和参数
创建Pod时,可以为容器设置启动时要执行的命令和参数。可以在配置文件的command字段下设置命令,在args字段下设置命令参数。一旦Pod创建完成,改命令和参数就无法进行更改了。
如果在配置文件中设置了容器启动时要执行的命令和参数,那么容器镜像中自带的命令和参数将会被覆盖而不在执行。如果配置文件中只是设置了参数,却没有设置对应的命令,那么容器镜像中自带的命令会使用改新参数
示例:args.yaml
apiVersion: v1
kind: Pod
metadata:
name: args
labels:
name: args
spec:
containers:
- name: args
image: debian
command: ["printenv"]
args: ["HOSTNAME", "KUBERNATES_PORT"]
restartPolicy: OnFailure
[root@master k8s]# kubectl create -f args.yaml
pod/args created
[root@master k8s]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
args 0/1 ContainerCreating 0 2s
args 0/1 Completed 0 4s
^C[root@master k8s]kubectl logs args
args
[root@master k8s]#
使用环境变量设置参数
apiVersion: v1
kind: Pod
metadata:
name: args
labels:
name: args
spec:
containers:
- name: args
image: debian
resources:
limits:
memory: "128Mi"
cpu: "500m"
env:
- name: MESSAGE
value: "hello world"
command: ["/bin/echo"]
args: ["$(MESSAGE)"]
restartPolicy: OnFailure
[root@master k8s]# kubectl create -f args.yaml
pod/args created
[root@master k8s]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
args 0/1 ContainerCreating 0 3s
args 0/1 Completed 0 4s
^C[root@master k8s]kubectl logs args
hello world
[root@master k8s]#
相互依赖的环境变量
设置了相互依赖的环境变量,就可以再配置清单文件中的env的value使用 $(VAR_NAME)
示例:dependency-var.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
containers:
- name: myapp
image: busybox
resources:
limits:
memory: "128Mi"
cpu: "500m"
command:
- "sh"
- "-c"
args:
- printf UNCHANGED_REFERENCE=$UNCHANGED_REFERENCE'\n'; printf SERVICE=$SERVICE'\n'; printf ESCAPED_SERVICE=$ESCAPED_SERVICE; sleep 120
env:
- name: SERVICE_IP
value: "192.168.99.102"
- name: SERVICE_PORT
value: "31111"
- name: UNCHANGED_REFERENCE
value: $(PROTOCAL)://$(SERVICE_IP):$(SERVICE_PORT)
- name: PROTOCAL
value: "https"
- name: SERVICE
value: $(PROTOCAL)://$(SERVICE_IP):$(SERVICE_PORT)
- name: ESCAPED_SERVICE
value: $$(PROTOCAL)://$(SERVICE_IP):$(SERVICE_PORT)
[root@master k8s]# kubectl logs myapp
UNCHANGED_REFERENCE=$(PROTOCAL)://192.168.99.102:31111
SERVICE=https://192.168.99.102:31111
[root@master k8s]#
配额管理
创建一个命名空间,以便资源隔离
kubectl create namespace cpu-example
指定CPU请求和CPU限制
要为容器执行CPU请求,请在容器资源清单中包含 resources:requests字段。要指定CPU限制,请包含resources:limits
示例:cpu-limit.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
containers:
- name: myapp
image: registry.cn-beijing.aliyuncs.com/qingfeng666/stress
resources:
limits:
memory: "128Mi"
cpu: "1"
ports:
- containerPort: 80
args:
- -cups
- "2"
[root@master k8s]# kubectl describe pod myapp
Name: myapp
Namespace: default
Priority: 0
Node: node2/179.220.56.232
Start Time: Thu, 02 Mar 2023 14:57:46 +0800
Labels: name=myapp
Annotations: <none>
Status: Running
IP: 10.244.2.20
IPs:
IP: 10.244.2.20
Containers:
myapp:
Container ID: docker://f41321840ba2dfdf841a869593f106acf86484d7f4b4f1dbaa9f3044efc9bc12
Image: registry.cn-beijing.aliyuncs.com/qingfeng666/stress
Image ID: docker-pullable://registry.cn-beijing.aliyuncs.com/qingfeng666/stress@sha256:155d7266cb7ed6fecd34b2e4f8a25c2b21eb77723658fb4ab2db630d41118c7d
Port: 80/TCP
Host Port: 0/TCP
Args:
-cpus
2
State: Running
Started: Thu, 02 Mar 2023 14:57:49 +0800
Ready: True
Restart Count: 0
Limits:
cpu: 1
memory: 128Mi
Requests:
cpu: 1
memory: 128Mi
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-dh67f (ro)
利用亲和性分配Pod
preferredDuringSchedulingIgnoredDuringExecution:软策略 requiredDuringSchedulingIgnoredDuringExecution: 硬策略
软策略:意思就是尽量不要将 pod 调度到匹配到的节点,但是如果没有不匹配的节点的话,也可以调度到匹配到的节点
硬策略:意思就是必须调度到满足条件的节点上,否则就等着 Pending
键值运算关系
- In:label 的值在某个列表中
- NotIn:label 的值不在某个列表中
- Gt:label 的值大于某个值
- Lt:label 的值小于某个值
- Exists:某个 label 存在
- DoesNotExist:某个 label 不存在
添加自定义lable
kubectl label nodes node1 disktype=ssd
节点亲和性配置
示例:affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- hard
containers:
- name: myapp
image: nginx
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
[root@master k8s]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myapp 1/1 Running 0 6s
^C[root@master k8s]# kubectl describe pod myapp
Name: myapp
Namespace: default
Priority: 0
Node: node2/179.220.56.232
Start Time: Thu, 02 Mar 2023 15:26:04 +0800
Labels: name=myapp
Annotations: <none>
Status: Running
IP: 10.244.2.21
ConfigMap数据注入容器
创建自定义的ConfigMap
示例:configmap-multi.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-db-config
namespace: default
data:
db-url: localhost
username: root
password: root
kubectl create -f configmap-multi.yaml
使用ConfigMap数据
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
containers:
- name: myapp
image: busybox
command: ["sh", "-c", "env"]
envFrom:
- configMapRef:
name: my-db-config
resources:
limits:
memory: "128Mi"
cpu: "500m"
[root@master k8s]# kubectl logs myapp
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=myapp
SHLVL=1
username=root
HOME=/root
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
password=root
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
db-url=localhost
容器root用户和privileged特权用户
Docker允许隔离主机OS上的进程、功能和文件系统,并且出于实际原因,大多数容器默认以root用户身份运行。
Kubernetes通过Security Context提供了相同的功能。
要为Pod设置安全性配置,可在Pod规约中包含securityContext字段。securityContext字段值是一个PodSecurityContext对象,设置的安全性配置会应用到Pod中所有的Container上
示例:security.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
volumes:
- name: security
emptyDir: {}
containers:
- name: myapp
image: busybox
command: ["sh","-c","sleep 1h"]
volumeMounts:
- name: security
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
resources:
limits:
memory: "128Mi"
cpu: "500m"