【重识云原生】第六章容器6.4.2.2节——Pod使用(上)

1 Pod使用

1.1 Pod 定义

        通过 yaml 或 json 描述 Pod 和其内容器的运行环境以及期望状态,比如一个最简单的 nginx pod 可以定义为:

代码语言:javascript
复制
apiVersion: v1 
kind: Pod 
metadata: 
  name: nginx 
  labels: 
    app: nginx 
spec: 
  containers: 
    - name: nginx 
      image: nginx 
      ports: 
        - containerPort: 80

        在生产环境中,推荐使用 Deployment、StatefulSet、Job 或者 CronJob 等控制器来创建 Pod,而不推荐直接创建 Pod。

1.2 pod模板

        控制器(如deployment、daemonset、statefulset等)是通过创建pod模板来创建和管理pod的,PodTemplate是用于创建pod的规范,并且包含在deployment、job和daemonset中。每个控制器使用自己内部的Pod模板来创建实际的Pod。PodTemplate是运行应用程序所需的任何控制器的一部分。下面的示例是一个简单的Job的清单,包含一个podtemplate,这个是用来生成pod的模板。该Pod中的容器会打印一条消息,然后暂停。

代码语言:javascript
复制
#cat job-template.yaml 
apiVersion: batch/v1 
kind: Job 
metadata: 
    name: hello 
spec: 
  template: 
    # This is the pod template 
    spec: 
      containers: 
        - name: hello 
          image: busybox 
          command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600'] 
      restartPolicy: OnFailure 
    # The pod template ends here

        修改pod template或切换到新的pod tmplate对已经存在的pod没有影响。 POD不直接接收模板更新,而是创建一个新的POD来匹配修改后的POD模板。例如,控制器可确保正在运行的Pod与当前Pod模板匹配。如果模板已更新,则控制器必须删除现有的Pod并根据更新的模板创建新的Pod。每个控制器都实现自己的规则来处理Pod模板的更改。在节点上,kubelet不直接观察或管理有关Pod模板和更新的任何详细信息。

1.3 和pod相关的api对象

1.3.1 kubectl explain pods 

        上面命令可以看到和pod相关的api对象有哪些,也就是通过资源清单yaml部署一个pod时需要哪些字段。

1.3.2 apiVersion

        apiVersion定义了此对象表示的版本化模式。服务器应将已识别的模式转换为最新的内部值,并可能拒绝无法识别的值。更多信息参考:

community/api-conventions.md at master · kubernetes/community · GitHub

        查看k8s集群支持的apiVersion有哪些,可以使用下面的命令:

代码语言:javascript
复制
kubectl api-versions

admissionregistration.k8s.io/v1
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1 authentication.k8s.io/v1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1
authorization.k8s.io/v1beta1
autoscaling/v1 autoscaling/v2beta1
autoscaling/v2beta2 batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
coordination.k8s.io/v1
coordination.k8s.io/v1beta1
crd.projectcalico.org/v1
discovery.k8s.io/v1beta1
events.k8s.io/v1beta1
extensions/v1beta1
metrics.k8s.io/v1beta1
networking.k8s.io/v1
networking.k8s.io/v1beta1
node.k8s.io/v1beta1
policy/v1beta1
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1
scheduling.k8s.io/v1
scheduling.k8s.io/v1beta1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1

1.3.3 kind

        Kind是表示此对象表示的REST资源的字符串值。服务器可以从客户端提交请求的端点推断出这一点,说白了就是表示我们要创建什么资源,如deployment、statefulset、pod、service、ingress。

        查看更详细信息可参考:

https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds

1.3.4 metadata

        标准对象的元数据。更多信息:

community/api-conventions.md at master · kubernetes/community · GitHub

1.3.5 spec

        指定容器的所需行为。更多信息:

https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status

1.3.6 status

        最近观察到的pod的状态。此数据可能不是最新的。Status不需要在pod或者其他资源中定义,这个默认是存在的,更多信息:https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

1.4 怎么创建pod?

        1.通过定义资源清单yaml文件(就是以yaml结尾的文件)创建pod,在k8s的master节点操作。

        查看定义资源清单需要哪些字段

代码语言:javascript
复制
kubectl explain pods
kubectl explain pods.apiVersion
kubectl explain pods.kind
kubectl explain pods.metadata
kubectl explain pods.spec
代码语言:javascript
复制
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
imagePullPolicy: IfNotPresent

通过kubectl apply创建一个pod

kubectl apply -f pod.yaml

查看pod创建的情况

kubectl get pods

显示如下:

NAME READY STATUS RESTARTS AGE
web 0/1 ContainerCreating 0 37s

查看pod的详细信息

kubectl describe pods web

pod.yaml定义的所有资源都删除掉

kubectl delete -f pod.yaml yaml

查看pod调度到哪个节点

kubectl get pods -o wide

显示如下:

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 5m30s 10.244.1.21 node1 <none> <none>

查看pod日志

kubectl logs web

查看pod里指定容器的日志

kubectl logs -c tomcat1 web

进入到刚才创建的pod,刚才创建的pod名字是web

kubectl exec -it web -- /bin/bash

假如pod里有多个容器,进入到pod里的指定容器,按如下命令:

kubectl exec -it web -c tomcat1 -- /bin/bash

可查看到刚才创建的pod

kubectl get pods

1.5 使用 Volume

        Volume 可以为容器提供持久化存储,比如:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {}

        更多挂载存储卷的方法参考 Volume。

1.6 私有镜像

        在使用私有镜像时,需要创建一个 docker registry secret,并在容器中引用。

        创建 docker registry secret:

代码语言:javascript
复制
kubectl create secret docker-registry regsecret --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>

        比如使用 Azure Container Registry(ACR):

代码语言:javascript
复制
ACR_NAME=dregistry
SERVICE_PRINCIPAL_NAME=acr-service-principal

Populate the ACR login server and resource id.

ACR_LOGIN_SERVER=(az acr show --name ACR_NAME --query loginServer --output tsv)
ACR_REGISTRY_ID=(az acr show --name ACR_NAME --query id --output tsv)

Create a contributor role assignment with a scope of the ACR resource.

SP_PASSWD=(az ad sp create-for-rbac --name SERVICE_PRINCIPAL_NAME --role Reader --scopes $ACR_REGISTRY_ID --query password --output tsv)

Get the service principle client id.

CLIENT_ID=(az ad sp show --id http://SERVICE_PRINCIPAL_NAME --query appId --output tsv)

Create secret

kubectl create secret docker-registry acr-auth --docker-server ACR_LOGIN_SERVER --docker-username CLIENT_ID --docker-password $SP_PASSWD --docker-email local@local.domain

        在引用 docker registry secret 时,有两种可选的方法:

        第一种是直接在 Pod 描述文件中引用该 secret:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: dregistry.azurecr.io/acr-auth-example
imagePullSecrets:
- name: acr-auth

        第二种是把 secret 添加到 service account 中,再通过 service account 引用(一般是某个 namespace 的 default service account):

代码语言:javascript
复制
$ kubectl get secrets myregistrykey
$ kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'

$ kubectl get serviceaccounts default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2015-08-07T22:02:39Z
name: default
namespace: default
selfLink: /api/v1/namespaces/default/serviceaccounts/default
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:

  • name: default-token-uudge
    imagePullSecrets:
  • name: myregistrykey

1.7 重启策略(restartPolicy):Pod在遇到故障之后重启的动作

        支持三种 RestartPolicy:

  • Always:当容器失效时,由Kubelet自动重启该容器。RestartPolicy的默认值。
  • OnFailure:当容器终止运行且退出码不为0时由Kubelet重启。
  • Never:无论何种情况下,Kubelet都不会重启该容器。

        注意:这里的重启是指在 Pod 所在 Node 上面本地重启,并不会调度到其他 Node 上去。

代码语言:javascript
复制
kubect1 edit deployment nginx -deployment restartPolicy: Always

示例

代码语言:javascript
复制
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
name: busybox
image: busybox
args: /bin/sh c sleep 30; exit 3
代码语言:javascript
复制
kubectl apply -f pod3.yaml

        查看Pod状态, 等容器启动后30秒后执行exit退出进程进入error状态, 就会重启次数加1

代码语言:javascript
复制
kubectl get pods
代码语言:javascript
复制
kubectl delete -f pod3.yaml
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
name: busybox
image: busybox
args: /bin/sh c sleep 30; exit 3
restartPolicy: Never #restartPolicy与containers要对齐

1.8 环境变量

        环境变量为容器提供了一些重要的资源,包括容器和 Pod 的基本信息以及集群中服务的信息等:

(1) hostname

        HOSTNAME 环境变量保存了该 Pod 的 hostname。

(2)容器和 Pod 的基本信息

        Pod 的名字、命名空间、IP 以及容器的计算资源限制等可以以 Downward API 的方式获取并存储到环境变量中。

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
  • name: test-container
    image: gcr.io/google_containers/busybox
    command: ["sh", "-c"]
    args: - env
    resources:
    requests:
    memory: "32Mi"
    cpu: "125m"
    limits:
    memory: "64Mi"
    cpu: "250m"
    env:
    - name: MY_NODE_NAME
    valueFrom:
    fieldRef:
    fieldPath: spec.nodeName
    - name: MY_POD_NAME
    valueFrom:
    fieldRef:
    fieldPath: metadata.name
    - name: MY_POD_NAMESPACE
    valueFrom:
    fieldRef:
    fieldPath: metadata.namespace
    - name: MY_POD_IP
    valueFrom:
    fieldRef:
    fieldPath: status.podIP
    - name: MY_POD_SERVICE_ACCOUNT
    valueFrom:
    fieldRef:
    fieldPath: spec.serviceAccountName
    - name: MY_CPU_REQUEST
    valueFrom:
    resourceFieldRef:
    containerName: test-container
    resource: requests.cpu
    - name: MY_CPU_LIMIT
    valueFrom:
    resourceFieldRef:
    containerName: test-container
    resource: limits.cpu
    - name: MY_MEM_REQUEST
    valueFrom:
    resourceFieldRef:
    containerName: test-container
    resource: requests.memory
    - name: MY_MEM_LIMIT
    valueFrom:
    resourceFieldRef:
    containerName: test-container
    resource: limits.memory
    restartPolicy: Never

(3) 集群中服务的信息

        容器的环境变量中还可以引用容器运行前创建的所有服务的信息,比如默认的 kubernetes 服务对应以下环境变量:

代码语言:javascript
复制
KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.0.0.1
KUBERNETES_PORT_443_TCP=tcp://10.0.0.1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443

        由于环境变量存在创建顺序的局限性(环境变量中不包含后来创建的服务),推荐使用 DNS 来解析服务。

1.9 镜像拉取策略

支持三种 ImagePullPolicy:

  • Always:不管本地镜像是否存在都会去仓库进行一次镜像拉取。校验如果镜像有变化则会覆盖本地镜像,否则不会覆盖。
  • Never:只是用本地镜像,不会去仓库拉取镜像,如果本地镜像不存在则Pod运行失败。
  • IfNotPresent:只有本地镜像不存在时,才会去仓库拉取镜像。ImagePullPolicy的默认值。

注意:

  • 默认为 IfNotPresent,但 :latest 标签的镜像默认为 Always。
  • 拉取镜像时 docker 会进行校验,如果镜像中的 MD5 码没有变,则不会拉取镜像数据。
  • 生产环境中应该尽量避免使用 :latest 标签,而开发环境中可以借助 :latest 标签自动拉取最新的镜像。

参考链接

pod详解 - 快乐嘉年华 - 博客园

Kubernetes中pod详解_人间不值得-的博客-CSDN博客

Pod详解_我的紫霞辣辣的博客-CSDN博客_pod方法

k8s之pod与Pod控制器 - woaiyitiaochai - 博客园

kubernetes 实践四:Pod详解 - xingyys - 博客园

Pod · Kubernetes指南

K8S实战基础知识之POD - 知乎

K8S Pod详解_ldd儆儆的博客-CSDN博客_k8s pod

k8s之pod详解_爱show的小卤蛋的博客-CSDN博客_k8s pod