前言
上一节公布了一个容器到 K8S 中,但其实实际操作的是 Pod,那么为什么是 Pod,而不是容器。
更新历史
- 20200531 – 初稿 – 左程立
- 原文地址 – https://blog.zuolinux.com/2020/05/22/about-pod.html
Pod 的实质
Pod 包装了一个或多个容器。
Pod 是 K8S 的最小执行单元。
Pod 是 K8S 中的一个过程。
Pod 可包装 Docker,也反对包装其余类型容器。
Pod 蕴含封装的容器、存储资源、网络资源、以及领导容器如何运行的配置。
能够把容器了解为一个无挂钩的赤裸裸的集装箱,K8S 这艘大船无奈间接挂载它,通过给集装箱 (容器) 加装挂钩 (IP 地址) 等造成一个 Pod,不便 K8S 来操作。
也能够把 Pod 了解为传统的虚拟机,而容器是传统虚拟机中运行的程序,只不过虚拟机是一个实体,而 Pod 是一个逻辑概念。
K8S 通过编排 Pod 来调度容器,而不是间接操作容器,K8S 无奈间接操纵容器。
Pod 中的共享资源
Pod 为其中运行的多容器提供共享的网络、存储资源、命名空间。
网络
Pod 具备惟一 IP 地址,Pod 中的多个容器共享一个 IP 地址和网络端口等网络资源
Pod 中多容器可应用 localhost 通信
Pod 中容器和内部通信时候,多容器须要协调网络端口
Pod 中的容器获取的零碎主机名与为 Pod 配置的 name 雷同
存储
Pod 可指定一组存储卷
Pod 中多容器均能够拜访该存储卷,以便相互共享数据
Pod 中的共享卷能够长久保留,避免容器重启失落数据
Pod 的特点
如果应用 kind: Pod 的 yaml 文件来创立 Pod,以后节点服务器呈现问题后,Pod 不能被主动调度到其余可用服务器。
个别应用 kind: Deployment 的 yaml 来创立 Pod。
Deployment 是一种控制器,能够用来创立、治理 Pod。如创立多正本 Pod,滚动更新 Pod。
当 Pod 所在节点呈现问题,Deployment 控制器能够在集群中其余节点启动新 Pod。
Pod 模板
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
镜像拉取策略
不具体指定的状况下,imagePullPolicy 是 Always,即 kubelet 会尝试从指定的仓库拉取每个镜像。
如果容器属性 imagePullPolicy 设置为 IfNotPresent,则会优先应用本地镜像。
如果容器属性 imagePullPolicy 设置为 IfNotPresent Never,则会肯定应用本地镜像。
apiVersion: v1
kind: Pod
metadata:
name: private-image-test-1
spec:
containers:
- name: uses-private-image
image: nginx
imagePullPolicy: Always
command: ["echo", "SUCCESS"]
Pod 罕用参数
NodeSelector
性能:将 Pod 与 Node 绑定
apiVersion: v1
kind: Pod
...
spec:
nodeSelector:
disktype: ssd
该 Pod 只能运行在携带了“disktype:ssd”标签(Label)的节点上,如果没有这种标签的节点,调度将失败。
NodeName
该字段个别由调度器设置,但咱们测试时候能够手工设置该字段,让调度器认为该 Pod 曾经被调度过了。
HostAliase
给 Pod 里各容器的 /etc/hosts 文件设置内容
apiVersion: v1
kind: Pod
......
spec:
hostAliases:
- ip: "10.20.20.20"
hostnames:
- "test1.com"
- "test2.com"
进容器检查一下
[root@master01 ~]# kubectl exec -it nginx -- bash
root@nginx:/# cat /etc/hosts
......
# Entries added by HostAliases.
10.20.20.20 test1.com test2.com
shareProcessNamespace
定义参数 shareProcessNamespace=true,那么该 Pod 中所有容器将共享 PID Namespace
创立一个蕴含两个容器的 Pod
[root@master01 ~]# cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
shareProcessNamespace: true
containers:
- name: nginx
image: nginx
- name: shell
image: busybox
stdin: true
tty: true
查看运行状况
[root@master01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 2/2 Running 0 117s 192.10.137.131 work03 <none> <none>
进入到 Pod nginx 中的名为 shell 的容器中
[root@master01 ~]# kubectl attach -it nginx -c shell
If you don't see a command prompt, try pressing enter.
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /pause
6 root 0:00 nginx: master process nginx -g daemon off;
33 101 0:00 nginx: worker process
34 root 0:00 sh
39 root 0:00 ps aux
能够看到,shell 容器中能够看到 nginx 容器的过程
Pod 的预设参数 PodPreset
咱们能够事后设置好一些通用的配置,当用户提交本人的个性化 Pod 配置时,PodPreset 就能够主动附加通用配置到对应的 Pod 上。
PodPreset 里定义的内容,只会在 Pod API 对象被创立之前追加在这个对象自身 上,而不会影响任何 Pod 的控制器的定义。
比方,咱们当初提交的是一个 nginx-deployment,那么这个 Deployment 对象自身是永远不会被 PodPreset 扭转的,被批改的只是这个 Deployment 创立进去的所有 Pod。
未启用 PodPreset 个性时
# kubectl get podpresets
error: the server doesn't have a resource type"podpresets"
启用 PodPreset 个性
批改
[/etc/kubernetes/manifests/kube-apiserver.yaml]
中的
spec.containers.command:
批改原
- --runtime-config=api/all=true
为
- --runtime-config=api/all=true,settings.k8s.io/v1alpha1=true
新加一行
- --enable-admission-plugins=PodPreset
3 台 MASTER 均执行重启 kubelet
systemctl restart kubelet
预设值配置 preset.yaml
apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
name: allow-tz-env
spec:
selector:
matchLabels:
env:
- name: TZ
value: Asia/Shanghai
Pod 配置 nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
创立 PodPreset
# kubectl get podpreset
No resources found in default namespace.
# kubectl apply -f podpreset.yaml
podpreset.settings.k8s.io/allow-tz-env created
# kubectl get podpreset
NAME CREATED AT
allow-tz-env
创立 Pod
[root@master01 ~]# kubectl apply -f nginx.yaml
pod/nginx created
查看该 Pod 是否被注入
# kubectl get pod nginx -o yaml
... 省略
spec:
containers:
- env:
- name: TZ
value: Asia/Shanghai
image: nginx
imagePullPolicy: Always
name: nginx
resources: {}
... 省略
能够看到 Pod 被注入了名为 TZ 的 env
Init 容器
特点
- Init 容器在 Pod 内利用容器启动之前运行。
- 一个 Pod 能够有一个或多个 Init 容器。
- 每个 Init 容器运行必须实现。
- 如果 Init 容器运行失败,K8S 会一直重启该 Pod,直到 Init 容器运行胜利。
- 但如果 Pod 对应的 restartPolicy 值为 Never,它不会重新启动。
- 如果一个 Pod 有多个 Init 容器,这些容器会按程序一一运行。每个 Init 容器必须运行胜利,下一个才可能运行。
- Init 容器能够蕴含一些装置过程中利用容器中不存在的实用工具或个性化代码。例如,没有必要仅为了在装置过程中应用相似 sed、awk、python 或 dig 这样的工具而去 FROM 一个镜像来生成一个新的镜像。
- Init 容器能够平安地运行这些工具,防止这些工具导致利用镜像的安全性升高。
- 利用镜像的创建者和部署者能够各自独立工作,而没有必要联结构建一个独自的利用镜像。
- Init 容器能以不同于 Pod 内利用容器的文件系统视图运行。因而,Init 容器可具备拜访 Secrets 的权限,而利用容器不可能拜访。
- 因为 Init 容器必须在利用容器启动之前运行实现,因而 Init 容器提供了一种机制来阻塞或提早利用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod 内的所有的利用容器会并行启动。
- 在所有的 Init 容器没有胜利之前,Pod 将不会变成 Ready 状态。
- Init 容器镜像的变更会引起 Pod 重启,利用容器镜像的变更仅会重启利用容器。
- Pod 中每一个容器正本启动之前,都会执行一遍 Init 容器。
如何应用
- 定义一个具备 2 个 Init 容器的 Pod。
- init 容器为 myservice 和 mydb。这两个 Init 容器都启动实现,Pod 能力启动 spec 区域中的利用容器 myapp-container
创立 Pod 的 YAML 文件:
cat myapp.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
创立 mydb 和 myservice 两个 Service 的 YAML 文件:
cat myservice.yaml
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
要启动这个 Pod,能够执行如下命令:
kubectl apply -f myapp.yaml
pod/myapp-pod created
查看其状态:
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
应用上面命令查看更具体的信息:
kubectl describe -f myapp.yaml
Name: myapp-pod
Namespace: default
[...]
Labels: app=myapp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
查看 Pod 内 Init 容器的日志
$ kubectl logs myapp-pod -c init-myservice
$ kubectl logs myapp-pod -c init-mydb
此时,Init 容器将会期待直到发现名称为 mydb 和 myservice 的 Service。
创立 mydb 和 myservice 的 service:
$ kubectl create -f services.yaml
service "myservice" created
service "mydb" created
能够看到这些 Init 容器执行结束,随后 my-app 的 Pod 转移进入 Running 状态:
$ kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
只有咱们启动了 mydb 和 myservice 这两个 Service,Init 容器实现,myapp-pod 能力被创立。
Debug Pod
如果 Pod 被终止,可通过如下命令查看起因
kubectl describe pod pod 名称
kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' pod 名称
结束语
Pod 包装了容器,K8S 通过操作 Pod 来操作容器。
Pod 能够蕴含多个利用容器和多个 Init 容器。
人工间接创立的 Pod 在服务器节点故障时,没有自愈能力,须要应用控制器来解决这个问题。
分割我
微信公众号:zuolinux_com