第5章 深入理解Pod对象

一. Pod介绍与容器分类

1.Pod的特性

• 最小部署单元
• 一组容器的集合,紧密关联的容器考虑放到一个pod中
• 一个Pod中的容器共享网络命名空间
• Pod是短暂的

2. Pod容器分类

1). 基础容器

Infrastructure Container 基础容器, 维护整个Pod网络空间,这容器对用户是透明的,在node节点docker ps可以看到,node节点的kubelet配置也会指定基础容器镜像,由配置文件--pod-infra-container-image参数指定,可将此镜像指定为自己的私有镜像。

# cat /opt/kubernetes/cfg/kubelet

KUBELET_OPTS="--logtostderr=false \
--log-dir=/opt/kubernetes/logs/kubelet \
--v=4 \
--hostname-override=10.40.6.210 \
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \
--config=/opt/kubernetes/cfg/kubelet.config \
--cert-dir=/opt/kubernetes/ssl \
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"

2). 初始化容器

InitContainers 初始化容器,先于业务容器开始执行
https://kubernetes.io/zh/docs/concepts/workloads/pods/init-containers/

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

3). 业务容器

Containers 业务容器,并行启动

二. Pod 镜像拉取

1. 镜像拉取策略(imagePullPolicy)

IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
kubectl get deploy/nginx-deployment -o yaml |grep imagePullPolicy
Always:每次创建 Pod 都会重新拉取一次镜像
Never: Pod 永远不会主动拉取这个镜像

apiVersion: v1 
kind: Pod 
metadata:
  name: foo
  namespace: awesomeapps 
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1 
      imagePullPolicy: IfNotPresent

2. 拉取私有镜像仓库镜像

镜像库有些私有镜像需要登录验证后才能拉取镜像,也就是需要凭据才能下载镜像。

apiVersion: v1 
kind: Pod 
metadata:
  name: foo
  namespace: awesomeapps 
spec:
  containers:
    -name: foo
      image: janedoe/awesomeapp:v1 
  imagePullSecrets:             ##配置拉取镜像凭据,凭据名为myregistrykey
    -name: myregistrykey

1). 生成私有镜像仓库凭据 secret

kubernetes登录私有镜像仓库凭据生成: node节点使用授权用户登录私有镜像,在node本机会生成 ~/.docker/config.json文件,此文件就是登录Harbor的验证信息。然后用Base64编码:cat ~/.docker/config.json |base64 -w 0 ,这个可理解为连接token。在master 节点创建yaml资源管理文件,通过yaml 文件创建secret资源, 用于管理登录私有镜像仓库凭据。

# docker pull 10.40.6.165/project/nginx:v2
Error response from daemon: Get https://10.40.6.165/v2/: dial tcp 10.40.6.165:443: connect: connection refused

# docker login 10.40.6.165
Username: liuzhousheng
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded


# cat ~/.docker/config.json 
{
    "auths": {
        "10.40.6.165": {
            "auth": "bGl1emhvdXNoZW5nOlpob3UmJjEwMTI="
        }
    },
    "HttpHeaders": {
        "User-Agent": "Docker-Client/18.09.6 (linux)"
    }

# cat ~/.docker/config.json |base64 -w 0
ewoJImF1dGhzIjogewoJCSIxMC40MC42LjE2NSI6IHsKCQkJImF1dGgiOiAiYkdsMWVtaHZkWE5vWlc1bk9scG9iM1VtSmpFd01UST0iCgkJfQoJfSwKCSJIdHRwSGVhZGVycyI6IHsKCQkiVXNlci1BZ2VudCI6ICJEb2NrZXItQ2xpZW50LzE4LjA5LjYgKGxpbnV4KSIKCX0KfQ==

# cat registry-pull-secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: registry-pull-secret    ## 凭据名
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxMC40MC42LjE2NSI6IHsKCQkJImF1dGgiOiAiYkdsMWVtaHZkWE5vWlc1bk9scG9iM1VtSmpFd01UST0iCgkJfQoJfSwKCSJIdHRwSGVhZGVycyI6IHsKCQkiVXNlci1BZ2VudCI6ICJEb2NrZXItQ2xpZW50LzE4LjA5LjYgKGxpbnV4KSIKCX0KfQ== 
type: kubernetes.io/dockerconfigjson

# kubectl create -f registry-pull-secret.yaml
# kubectl get secret
NAME                   TYPE                                  DATA   AGE
default-token-qmpxc    kubernetes.io/service-account-token   3      4d3h
registry-pull-secret   kubernetes.io/dockerconfigjson        1      2m17s

2). yaml配置文件指定凭据

修改deployment 控制器yaml资源配置文件,拉取私有镜像:

# cat nginx-deployment_service.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      imagePullSecrets:    ##添加拉取镜像凭据
      - name: registry-pull-secret  ##镜像凭据名
      containers:
      - name: nginx
        #image: nginx:1.15.4
        image: 10.40.6.165/project/nginx:v2
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx

执行:

# kubectl apply -f nginx-deployment_service.yaml
# kubectl get pods ## 可以看到pod滚动更新
# kubectl describe pod POD_NAME ## 可以看到镜像来自私有仓库镜像

三. Pod 资源限制

Pod和Container的资源请求和限制:
• spec.containers[].resources.limits.cpu
• spec.containers[].resources.limits.memory
• spec.containers[].resources.requests.cpu
• spec.containers[].resources.requests.memory

limits: 对pod的资源总限制
requests: 创建pod时,请求调度node资源满足条件

例如:
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/

# cat pod2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: db
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"  ##0.25核 ,设置数字1,表示1核,1.5表示1.5核
      limits:
        memory: "128Mi"
        cpu: "500m"   ##0.5核
  - name: wp
    image: wordpress
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

创建:

# kubectl apply -f pod2.yaml

查看node节点资源使用情况:

# kubectl describe nodes 10.40.6.210
 Namespace                  Name                                     CPU Requests  CPU Limits  Memory Requests  Memory Limits
  ---------                  ----                                     ------------  ----------  ---------------  -------------
  default                    frontend                                 500m (12%)    1 (25%)     128Mi (1%)       256Mi (3%)
  default                    nginx-deployment-5cdc94fdc8-bhgwk        0 (0%)        0 (0%)      0 (0%)           0 (0%)
  kube-system                kubernetes-dashboard-774f47666c-97c86    50m (1%)      100m (2%)   100Mi (1%)       300Mi (3%)

查看命名空间:

# kubectl get ns
NAME          STATUS   AGE
default       Active   4d7h
kube-public   Active   4d7h
kube-system   Active   4d7h

四. Pod重启策略(restartPolicy)

重启策略表示一个pod出现故障时需要做的动作
• Always:当容器终止退出后,总是重启容器,默认策略。
• OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
• Never::当容器终止推出,从不重启容器。
例如:

apiVersion: v1 
kind: Pod 
metadata:
  name: foo
  namespace: awesomeapps 
spec:
  containers:
    - name: foo
    image: janedoe/awesomeapp:v1 
  restartPolicy: Always    ###表示总是重启

五. Pod健康检查(Probe)

1. pod探针类型

Probe有以下两种类型:
①.livenessProbe:存活探针,如果检查失败,将杀死容器,根据Pod的restartPolicy重启策略操作。
②.readinessProbe:就绪探针,如果检查失败,Kubernetes会把Pod从service endpoints中剔除。

service有个对用户透明对控制器endpoints控制器,查看service的endpoints控制器中的pod IP和端口

# kubectl get ep
NAME            ENDPOINTS                                      AGE
kubernetes      10.40.6.201:6443,10.40.6.209:6443              4d8h
nginx-service   172.17.31.3:80,172.17.59.2:80,172.17.59.3:80   97m

2. 探针方法

Probe支持以下三种检查方法:
①.httpGet:发送HTTP请求,返回200-400范围状态码为成功。
②.exec:执行Shell命令返回状态码是0为成功。
③.tcpSocket:发起TCP Socket建立成功。

例如:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/

exec 检查:

# cat pod3.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:  ##  livenessProbe检查类型
      exec:    ##exec检查方法
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5   ##容器启动5秒后才做检查
      periodSeconds: 5    ## 每隔5秒检查一次

httpGet检查:

# cat pod4.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    livenessProbe:   ## livenessProbe类型
      httpGet:   ## httpGet检查方法
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

tcpSocket检查:

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:   ##readinessProbe检查类型
      tcpSocket:  ##tcpSocket检查方法
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:   ##livenessProbe检查类型
      tcpSocket:   ##tcpSocket检查方法
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

六. Pod调度约束

1. pod创建过程

Kubernetes调度器根据特定的算法与策略将pod调度到工作节点上。在默认情况下,Kubernetes调度器可以满足绝大多数需求,例如调度pod到资源充足的节点上运行,或调度pod分散到不同节点使集群节点资源均衡等。但一些特殊的场景,默认调度算法策略并不能满足实际需求,例如使用者期望按需将某些pod调度到特定硬件节点(数据库服务部署到SSD硬盘机器、CPU/内存密集型服务部署到高配CPU/内存服务器),或就近部署交互频繁的pod(例如同一机器、同一机房、或同一网段等)。
创建pod流程如下:

调度约束.png

kubernetes 每个组件之间协作是基于watch机制来实现:
① 用户创建pod请求到apiserver,apiserver将pod状态属性写入etcd存储中;
② schedule调度器通过watch机制获取etcd中要创建新pod的状态属性,调度器根据调度算法,选出创建pod应该调度到哪个node节点上,将新创建的pod绑定到具体某个node节点,最后通过apiserver更新到etcd中;
③ kubelet 通过watch机制获取etcd中新建pod绑定node节点信息,然后通过docker run 将容器启动,启动之后将pod的状态信息通过apiserver更新到etcd中,节点的pod状态信息会周期性上报到etcd中;
④ 通过kubectl get 获取资源信息请求到apiserver中,然后apiserver 到etcd中获取,然后返回给用户;
APIServer 在这里起到协助的作用,etcd主要存储资源状态信息。

2. Pod调度约束字段

调度约束可以通过两个字段约束:
• nodeName: 用于将Pod调度到指定的Node名称上
• nodeSelector: 用于将Pod调度到匹配Label的Node上
通过nodeName指定到具体某个节点:

# cat pod5.yaml 

apiVersion: v1
kind: Pod
metadata:
  name: pod-example
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: 10.40.6.210   ##通过nodeName指定到10.40.6.210 node节点上,这是节点名
# kubectl create -f pod5.yaml
# kubectl get pod -o wide
# kubectl describe pod pod-example    可以看到直接跳过了调度器

通过nodeSelector指定到具体某个节点:

# kubectl label nodes 10.40.6.210 disktype=ssd   给10.40.6.210节点打标签disktype=ssd
# kubectl label nodes 10.40.6.213 disktype=sas   给10.40.6.210节点打标签disktype=sas

# kubectl get nodes --show-labels
NAME          STATUS   ROLES    AGE    VERSION   LABELS
10.40.6.210   Ready    <none>   4d4h   v1.12.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=10.40.6.210
10.40.6.213   Ready    <none>   4d4h   v1.12.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=sas,kubernetes.io/hostname=10.40.6.213

# cat pod6.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-example
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeSelector:
    disktype: ssd 

# kubectl apply -f pod6.yaml
# kubectl get pod -o wide
NAME                                READY   STATUS             RESTARTS   AGE    IP            NODE          NOMINATED NODE
pod-example                         1/1     Running            0          3m2s   172.17.31.4   10.40.6.210   <none>

# kubectl describe pod pod-example

七. 故障排查

Pod状态值 描述
Pending Pod创建已经提交到Kubernetes。但是因为某种原因而不能顺利创建。例如下载镜像慢,调度不成功。
Running Pod已经绑定到一个节点,并且已经创建了所有容器。至少有一个容器正在运行中,或正在启动或重新启动。
Succeeded Pod中的所有容器都已成功终止,不会重新启动。
Failed Pod的所有容器均已终止,且至少有一个容器已在故障中终止。也就是说,容器要么以非零状态退出,要么被系统终止。
Unknown 由于某种原因apiserver无法获得Pod的状态,通常是由于Master与Pod所在主机kubelet通信时出错。

kubectl describe TYPE/NAME 查看pod事件Events
kubectl logs TYPE/NAME [-c CONTAINER] 查看pod日志
kubectl exec POD [-c CONTAINER] -- COMMAND [args...] 进入pod

# kubectl describe pod pod-example
     .....
Events:
  Type    Reason     Age    From                  Message
  ----    ------     ----   ----                  -------
  Normal  Scheduled  8m26s  default-scheduler     Successfully assigned default/pod-example to 10.40.6.210
  Normal  Pulling    8m25s  kubelet, 10.40.6.210  pulling image "nginx"
  Normal  Pulled     8m25s  kubelet, 10.40.6.210  Successfully pulled image "nginx"
  Normal  Created    8m25s  kubelet, 10.40.6.210  Created container
  Normal  Started    8m25s  kubelet, 10.40.6.210  Started container
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343