深入理解pod
pod定义详解
apiVersion: v1 //版本 kind: pod //类型,pod metadata: //元数据 name: String //元数据,pod的名字 namespace: String //元数据,pod的命名空间 labels: //元数据,标签列表 - name: String //元数据,标签的名字 annotations: //元数据,自定义注解列表 - name: String //元数据,自定义注解名字 spec: //pod中容器的详细定义 containers: //pod中的容器列表,可以有多个容器 - name: String image: String //容器中的镜像 imagesPullPolicy: [Always|Never|IfNotPresent]//获取镜像的策略 command: [String] //容器的启动命令列表(不配置的话使用镜像内部的命令) args: [String] //启动参数列表 workingDir: String //容器的工作目录 volumeMounts: //挂载到到容器内部的存储卷设置 - name: String mountPath: String readOnly: boolean ports: //容器需要暴露的端口号列表 - name: String containerPort: int //容器要暴露的端口 hostPort: int //容器所在主机监听的端口(容器暴露端口映射到宿主机的端口) protocol: String env: //容器运行前要设置的环境列表 - name: String value: String resources: //资源限制 limits: cpu: Srting memory: String requeste: cpu: String memory: String livenessProbe: //pod内容器健康检查的设置 exec: command: [String] httpGet: //通过httpget检查健康 path: String port: number host: String scheme: Srtring httpHeaders: - name: Stirng value: String tcpSocket: //通过tcpSocket检查健康 port: number initialDelaySeconds: 0//首次检查时间 timeoutSeconds: 0 //检查超时时间 periodSeconds: 0 //检查间隔时间 successThreshold: 0 failureThreshold: 0 securityContext: //安全配置 privileged: falae restartPolicy: [Always|Never|OnFailure]//重启策略 nodeSelector: object //节点选择 imagePullSecrets: - name: String hostNetwork: false //是否使用主机网络模式,默认否 volumes: //在该pod上定义共享存储卷 - name: String meptyDir: {} hostPath: path: string secret: //类型为secret的存储卷 secretName: String item: - key: String path: String configMap: //类型为configMap的存储卷 name: String items: - key: String path: String
pod的特点
• 最小部署单元
• 一组容器的集合
• 一个Pod中的容器共享网络命名空间 puase
• Pod是短暂的 (重拉pod ip会发生变化)
pod由于有个根容器pause,所以pod中的其他容器可以共享网络 和 存储
示例:share-volume.yaml
说明,两个centos容器write和read
write容器:向 /data/hello 文件每隔1秒追加1到100数字
read容器: tailf -f /data/hello
效果:查看write 容器中的/data/hello文件是不断写入,查看read容器 /data/hello 也是不断写入的
说明:同一个pod中的容器 共享存储,共享网络
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: {}
pod应用场景
• Pod为亲密性应用而存在。 亲密性应用场景:
• 两个应用之间发生文件交互
• 两个应用需要通过127.0.0.1或者socket通信
• 两个应用需要发生频繁的调用
镜像拉取策略(imagePullPolicy)
• IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
• Always:每次创建 Pod 都会重新拉取一次镜像
• Never: Pod 永远不会主动拉取这个镜像
apiVersion: v1 kind: Pod metadata: name: foo namespace: awesomeapps spec: containers: - name: foo image: janedoe/awesomeapp:v1 imagePullPolicy: IfNotPresent
apiVersion: v1 kind: Pod metadata: name: foo namespace: awesomeapps spec: containers: - name: foo image: janedoe/awesomeapp:v1 imagePullSecrets: - name: myregistrykey
如果使用私有仓库需要定义一个secret 用于存放登录registry仓库的信息
kubectl create secret docker-registry myregistry --docker-username=benjamin7788 --docker-password=a7260488 --docker-server=registry.cn-hangzhou.aliyuncs.com -n awesomeapps
pod的资源限制
• spec.containers[].resources.limits.cpu
• spec.containers[].resources.limits.memory
• spec.containers[].resources.requests.cpu
• spec.containers[].resources.requests.memory
kubernetes会根据Request的值去查找有足够资源的node来调度此pod
limit对应资源量的上限, 既最多允许使用这个上限的资源量, 由于cpu是可压缩的, 进程是无法突破上限的, 而memory是不可压缩资源, 当进程试图请求超过limit限制时的memory, 此进程就会被kubernetes杀掉
对于cpu和内存而言, pod的request和limit是指该pod中所有容器的 Requests或Limits的总和,
例如: 某个节点cpu资源充足, 而内存为4G,其中3GB可以运行pod, 而某个pod的memory request为1GB, limit为2GB, 那么这个节点上最多可以运行3个这样的pod
待调度pod的request值总和超过该节点提供的空闲资源, 不会调度到该节点node上;
一般 limits设置的值大于等于 request设置的值
resource.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.11 ports: - containerPort: 80 resources: limits: cpu: 0.75 #750m=0.75c memory: 500Mi #500MB=500Mi requests: cpu: 0.5 memory: 500Mi
重启策略(restartPolicy)
• Always:当容器终止退出后,总是重启容器,默认策略。
• OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
• Never:当容器终止退出,从不重启容器。
每个策略适用相应的场景,
never 适用定时任务,OnFailure 和 Always 适用一般应用程序,具体还是要根据业务性质来设置
apiVersion: v1 kind: Pod metadata: name: foo namespace: awesomeapps spec: containers: - name: foo image: janedoe/awesomeapp:v1 restartPolicy: Always
健康检查(Probe)
livenessProbe
如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。
readinessProbe
如果检查失败,Kubernetes会把Pod从service endpoints中剔除。 Probe支持以下三种检查方法:
httpGet
发送HTTP请求,返回200-400范围状态码为成功。
exec
执行Shell命令返回状态码是0为成功。
tcpSocket
发起TCP Socket建立成功。
livenessProbe.yaml
apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 #容器启动之后5s开始检查 periodSeconds: 5 #周期是5s readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5
注意:这边未设置重启策略,一般缺省的默认策略是Always,镜像拉取策略 缺省的策略也是Always
健康检查失败,容器将会被重启,在k8s里没有重启一说,实际是删除容器重拉镜像重新起一个新的容器
查看pod已经重启了2次
pod调度策略
create pod ---》write apiserver ---》write etcd ---》scheduler ---》bind pod to node ---》write etcd ---》
kubelet(apiserver get pod) ---》docker api create container ---》apiserver ---》update pod status to etcd ---》kubectl get pods
- nodeName:
用于将Pod调度到指定的Node名称上
pod-nodename.yaml
apiVersion: v1 kind: Pod metadata: name: pod-example2 labels: app: nginx spec: nodeName: k8s-node2 containers: - name: nginx image: nginx:1.15
- nodeSelector:
用于将Pod调度到匹配Label的Node上
pod-nodeselector.yaml
apiVersion: v1 kind: Pod metadata: name: pod-example2 labels: app: nginx spec: nodeSelector: team: a containers: - name: nginx image: nginx:1.15
查看 k8s-node1的默认lable
给k8s-node1 加一个 team=a的标签
kubectl label node k8s-node1 team=a
根据上面的yaml生成pod 符合预期,pod将会被调度到 label 为team=a 的 k8s-node1的节点上
说明:nodeSelector 相比 nodeName 组合更加灵活
nodeName不经过scheduler直接调度到指定节点,nodeSelector经过shceduler需要经过一些调度算法处理最后调度到相应节点。
如果都没指定这两种方式,则采用k8s默认的调度策略
污点与容忍
默认node节点都是没有打污点的,master节点是打上污点的。
应用场景:
• 节点独占
• 具有特殊硬件设备的节点
• 应对节点故障
kubectl taint node [node] key=value[effect]
其中[effect] 可取值:
NoSchedule :一定不能被调度。
PreferNoSchedule:尽量不要调度。
NoExecute:不仅不会调度,还会驱逐Node上已有的Pod。
给k8s-node1打污点
kubectl taint node k8s-node1 abc=123:NoSchedule
打完污点后将之前根据pod-nodeselector.yaml 创建的 pod-example2 这个pod 删除,重新创建pod-example2
kubectl delete pod pod-example2 kubectl apply -f pod-nodeselector.yaml
查看pod 状态会发现一直是pedding状态
describe 查看发现 pod 没有可被调度的 node,这是符合预期的,因为指定了 含有lable team=a的k8s-node1调度
然后 k8s-node1 被打了 污点,所以这时候 event 提示没有可被调度的节点
设置容忍
pod-nodetaint.yaml
apiVersion: v1 kind: Pod metadata: name: pod-example2 labels: app: nginx spec: tolerations: - key: "abc" operator: "Equal" value: "123" effect: "NoSchedule" nodeSelector: team: a containers: - name: nginx image: nginx:1.15
按照如上yaml设置容忍后 ,成功调度到k8s-node1
pod无法启动排查
kubectl describe TYPE/NAME kubectl logs TYPE/NAME [-c CONTAINER] kubectl exec POD [-c CONTAINER] -- COMMAND [args...]