前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >不背锅运维:耗时1周整理:分享K8S Pod知识点,带你一文打尽

不背锅运维:耗时1周整理:分享K8S Pod知识点,带你一文打尽

作者头像
不背锅运维
发布2023-02-02 14:29:13
1.1K0
发布2023-02-02 14:29:13
举报
文章被收录于专栏:监控

1. Pod概念热身

Pod是一个逻辑抽象概念,K8s创建和管理的最小单元,一个Pod由一个容器或多个容器组成。 特点:

  • 一个Pod可以理解为是一个应用实例
  • Pod中容器始终部署在一个Node上
  • Pod中容器共享网络、存储资源

Pod主要用法:

  • 运行单个容器:最常见的用法,在这种情况下,可以将Pod看作是单个容器的抽象封装
  • 运行多个容器:边车模式(Sidecar),通过在Pod中定义专门容器,来执行主业务容器需要的辅助工作,这样好处是将辅助功能同主业务容器解耦,实现独立发布和能力重用。 例如:
    • 日志收集
    • 应用监控

扩展:READY字段的意义:

代码语言:txt
复制
tantianran@test-b-k8s-master:~$ kubectl get pods -n test-a
NAME                         READY   STATUS    RESTARTS        AGE
goweb-demo-b98869456-25sj9   1/1     Running   1 (3m49s ago)   5d10h

在READY字段中,1/1的意义为在这个pod里,已准备的容器/一共有多少个容器。

在pod中,它可以有3种类型的容器,分别是:

  • 基础容器(pause container)
  • 初始化容器(init container)
  • 普通容器(业务容器/应用容器)

2. POD内容器间资源共享实现机制

2.1 共享数据的机制

  • emptyDir:会在 Pod 被删除的同时也会被删除,当 Pod 分派到某个节点上时,emptyDir 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
    • 例子
代码语言:txt
复制
    ```
代码语言:txt
复制
    apiVersion: v1
代码语言:txt
复制
    kind: Pod
代码语言:txt
复制
    metadata:
代码语言:txt
复制
    name: test-pod1
代码语言:txt
复制
    spec:
代码语言:txt
复制
    containers:
代码语言:txt
复制
    - image: nginx
        name: nginx1
        volumeMounts:
        - mountPath: /cache
        name: cache-volume
    - image: busybox
        name: bs1
        command: ["/bin/sh", "-c", "sleep 12h"]
        volumeMounts:
        - mountPath: /cache
        name: cache-volume
    volumes:
    - name: cache-volume
        emptyDir:
        sizeLimit: 500Mi
    ```cephfs:cephfs 卷允许你将现存的 CephFS 卷挂载到 Pod 中,cephfs 卷的内容在 Pod 被删除时会被保留,只是卷被卸载了。 这意味着 cephfs 卷可以被预先填充数据,且这些数据可以在 Pod 之间共享。同一 cephfs 卷可同时被多个写者挂载。

2.2 共享网络的机制

共享网络的机制是由Pause容器实现,下面慢慢分析一下,啥是pause,了解一下它的作用等等。

  1. 先准备一个yaml文件(pod1.yaml ),创建一个pod,pod里包含两个容器,一个是名为nginx1的容器,还有一个是名为bs1的容器
代码语言:txt
复制
apiVersion: v1
kind: Pod
metadata:
  name: test-pod1
spec:
  containers:
  - image: nginx
    name: nginx1
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  - image: busybox
    name: bs1
    command: ["/bin/sh", "-c", "sleep 12h"]
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi
  1. 开始创建
代码语言:txt
复制
tantianran@test-b-k8s-master:~$ kubectl create -f pod1.yaml 
pod/test-pod1 created
  1. 创建完后看看在哪个节点
代码语言:txt
复制
tantianran@test-b-k8s-master:~$ kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE     IP              NODE                NOMINATED NODE   READINESS GATES
test-pod1   2/2     Running   0          9m21s   10.244.222.44   test-b-k8s-node02   <none>           <none>
  1. 去到对应的节点查看容器
代码语言:txt
复制
tantianran@test-b-k8s-node02:~$ sudo docker ps | grep test-pod1
0db01653bdac   busybox                                                "/bin/sh -c 'sleep 1…"   9 minutes ago    Up 9 minutes              k8s_bs1_test-pod1_default_c3a15f70-3ae2-4a73-8a84-d630c047d827_0
296972c29efe   nginx                                                  "/docker-entrypoint.…"   9 minutes ago    Up 9 minutes              k8s_nginx1_test-pod1_default_c3a15f70-3ae2-4a73-8a84-d630c047d827_0
a5331fba7f11   registry.aliyuncs.com/google_containers/pause:latest   "/pause"                 10 minutes ago   Up 10 minutes             k8s_POD_test-pod1_default_c3a15f70-3ae2-4a73-8a84-d630c047d827_0
tantianran@test-b-k8s-node02:~$ 

通过查看容器,名为test-pod1的pod里,除了两个业务容器外(k8s_bs1_test-pod1、nginx1_test-pod1),还有一个pause容器。这个到底是什么鬼呢?

「对pause容器的理解」

  • pause容器又叫Infra container,就是基础设施容器的意思,Infra container只是pause容器的一个叫法而已
  • 上面看到paus容器,是从registry.aliyuncs.com/google_containers/pause:latest这个镜像拉起的
  • 在其中一台node节点上查看docker镜像,可看到该镜像的大小是240KB
代码语言:txt
复制
```
代码语言:txt
复制
registry.aliyuncs.com/google_containers/pause        latest       350b164e7ae1   8 years ago     240kB
代码语言:txt
复制
```
  • 根据理解,画了图:

nginx1容器里的nginx组件默认监听的端口是80,在bs1容器里去curl http://127.0.0.1 就可以放到nginx1容器的80端口。

代码语言:txt
复制
# step1:查看test-pod1里的容器
kubectl get pods test-pod1 -o jsonpath={.spec.containers[*].name}

# step2:进入指定容器
kubectl exec -it test-pod1 -c bs1 -- sh

# 访问nginx(因没有curl命令,此处用wget)
/ # wget http://127.0.0.1
Connecting to 127.0.0.1 (127.0.0.1:80)
saving to 'index.html'
index.html           100% |*************************************************************************************************************|   615  0:00:00 ETA
'index.html' saved
/ # 

上面看到,使用wget命令下载到了index.html文件,说明访问成功。

3. Pod常用管理命令

  • 查看pod里所有容器的名称
代码语言:txt
复制
kubectl get pods test-pod1 -o jsonpath={.spec.containers[*].name}
  • 进入pod里的指定容器的终端,如下进入pod为test-pod1里的容器nginx1和bs1
代码语言:txt
复制
kubectl exec -it test-pod1 -c nginx1 -- bash
kubectl exec -it test-pod1 -c bs1 -- sh
  • 查看pod里指定容器的log
代码语言:txt
复制
kubectl logs test-pod1 -c nginx1 

4. Pod的重启策略+应用健康检查(应用自修复)

「重启策略」

  • Always:当容器终止退出,总是重启容器,默认策略
  • OnFailure:当容器异常退出(退出状态码非0)时,才重启容器
  • Never:当容器终止退出,从不重启容器

查看pod的重启策略

代码语言:txt
复制
# 查看pod,以yaml格式输出
kubectl get pods test-pod1 -o yaml

# 找到restartPolicy字段,就是重启策略
restartPolicy: Always

「健康检查有以下3种类型:」

健康检查是检查容器里面的服务是否正常

  • livenessProbe(存活探测):如果检查失败,将杀死容器,根据pod的restartPolicy来操作。
  • readinessProbe(就绪探测):如果检查失败,k8s会把Pod从service endpoints中剔除
  • startupProbe(启动探测):检查成功才由存活检查接手,用于保护慢启动容器

「支持以下三种检查方法:」

  • httpGet:发起HTTP请求,返回200-400范围状态码为成功。
  • exec:执行Shell命令返回状态码是0为成功。
  • tcpSocket:发起TCP Socket建立成功。

「案例实战」

  1. livenessProbe(存活探针):使用exec的方式(执行Shell命令返回状态码是0则为成功)
代码语言:txt
复制
apiVersion: v1
kind: Namespace
metadata:
  name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  replicas: 10
  selector:
    matchLabels:
      app: goweb-demo
  template:
    metadata:
      labels:
        app: goweb-demo
    spec:
      containers:
      - name: goweb-demo
        image: 192.168.11.247/web-demo/goweb-demo:20221229v3
        livenessProbe:
          exec:
            command:
            - ls
            - /opt/goweb-demo/runserver
          initialDelaySeconds: 5
          periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb-demo
  type: NodePort

periodSeconds 字段指定了 kubelet 应该每 5 秒执行一次存活探测,initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 5 秒,kubelet 在容器内执行命令 ls /opt/goweb-demo/runserver 来进行探测。 如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。

验证存活检查的效果

代码语言:txt
复制
# 查看某个pod的里的容器,
kubectl get pods goweb-demo-686967fd56-556m9 -n test-a -o jsonpath={.spec.containers[*].name}

# 进入某个pod里的容器
kubectl exec -it goweb-demo-686967fd56-556m9 -c goweb-demo -n test-a -- bash

# 进入容器后,手动删除掉runserver可执行文件,模拟故障
rm -rf /opt/goweb-demo/runserver

# 查看Pod详情(在输出结果的最下面,有信息显示存活探针失败了,这个失败的容器被杀死并且被重建了。)
kubectl describe pod goweb-demo-686967fd56-556m9 -n test-a

Events:
  Type     Reason     Age                   From     Message
  ----     ------     ----                  ----     -------
  Warning  Unhealthy  177m (x6 over 3h59m)  kubelet  Liveness probe failed: ls: cannot access '/opt/goweb-demo/runserver': No such file or directory

# 一旦失败的容器恢复为运行状态,RESTARTS 计数器就会增加 1
tantianran@test-b-k8s-master:~$ kubectl get pods -n test-a
NAME                          READY   STATUS    RESTARTS      AGE
goweb-demo-686967fd56-556m9   1/1     Running   1 (22s ago)   13m # RESTARTS字段加1,
goweb-demo-686967fd56-8hzjb   1/1     Running   0             13m
...
  1. livenessProbe(存活探针):使用 httpGet 请求的方式检查uri path是否正常
代码语言:txt
复制
apiVersion: v1
kind: Namespace
metadata:
  name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  replicas: 10
  selector:
    matchLabels:
      app: goweb-demo
  template:
    metadata:
      labels:
        app: goweb-demo
    spec:
      containers:
      - name: goweb-demo
        image: 192.168.11.247/web-demo/goweb-demo:20221229v3
        livenessProbe:
          httpGet:
            path: /login
            port: 8090
            httpHeaders:
            - name: Custom-Header
              value: Awesome
          initialDelaySeconds: 3
          periodSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb-demo
  type: NodePort

在这个配置文件中,你可以看到 Pod 也只有一个容器。 periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。 kubelet 会向容器内运行的服务(服务在监听 8090 端口)发送一个 HTTP GET 请求来执行探测。 如果服务器上 /login 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并将其重启。返回大于或等于 200 并且小于 400 的任何代码都表示成功,其它返回代码都表示失败。

验证效果

代码语言:txt
复制
# 进入容器删除静态文件,模拟故障
kubectl exec -it goweb-demo-586ff85ddb-4646k -c goweb-demo -n test-a -- bash
rm -rf login.html 

# 查看pod的log
kubectl logs goweb-demo-586ff85ddb-4646k -n test-a

2023/01/12 06:45:19 [Recovery] 2023/01/12 - 06:45:19 panic recovered:
GET /login HTTP/1.1
Host: 10.244.222.5:8090
Connection: close
Accept: */*
Connection: close
Custom-Header: Awesome
User-Agent: kube-probe/1.25


html/template: "login.html" is undefined
/root/my-work-space/pkg/mod/github.com/gin-gonic/gin@v1.8.2/context.go:911 (0x8836d1)
/root/my-work-space/pkg/mod/github.com/gin-gonic/gin@v1.8.2/context.go:920 (0x88378c)
/root/my-work-space/src/goweb-demo/main.go:10 (0x89584e)

# 查看pod详情
kubectl describe pod goweb-demo-586ff85ddb-4646k -n test-a

Warning  Unhealthy  34s (x3 over 40s)   kubelet            Liveness probe failed: HTTP probe failed with statuscode: 500 # 状态码为500

# 恢复后查看Pod,RESTARTS计数器已经增1
kubectl get pod goweb-demo-586ff85ddb-4646k -n test-a

NAME                          READY   STATUS    RESTARTS      AGE
goweb-demo-586ff85ddb-4646k   1/1     Running   1 (80s ago)   5m39s
  1. readinessProbe(就绪探针)结合livenessProbe(存活探针)探测tcp端口:

第三种类型的存活探测是使用 TCP 套接字。 使用这种配置时,kubelet 会尝试在指定端口和容器建立套接字链接。 如果能建立连接,这个容器就被看作是健康的,如果不能则这个容器就被看作是有问题的。

代码语言:txt
复制
apiVersion: v1
kind: Namespace
metadata:
  name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  replicas: 10
  selector:
    matchLabels:
      app: goweb-demo
  template:
    metadata:
      labels:
        app: goweb-demo
    spec:
      containers:
      - name: goweb-demo
        image: 192.168.11.247/web-demo/goweb-demo:20221229v3
        readinessProbe:
          tcpSocket:
            port: 8090
          initialDelaySeconds: 5
          periodSeconds: 10
        livenessProbe:
          tcpSocket:
            port: 8090
          initialDelaySeconds: 15
          periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb-demo
  type: NodePort

TCP 检测的配置和 HTTP 检测非常相似。 这个例子同时使用就绪和存活探针。kubelet 会在容器启动 5 秒后发送第一个就绪探针。 探针会尝试连接 goweb-demo 容器的 8090 端口。 如果探测成功,这个 Pod 会被标记为就绪状态,kubelet 将继续每隔 10 秒运行一次探测。除了就绪探针,这个配置包括了一个存活探针。 kubelet 会在容器启动 15 秒后进行第一次存活探测。 与就绪探针类似,存活探针会尝试连接 goweb-demo 容器的 8090 端口。 如果存活探测失败,容器会被重新启动。

验证效果

代码语言:txt
复制
# 进入容器后,杀掉goweb-demo的进程
kubectl exec -it goweb-demo-5d7d55f846-vm2kc -c goweb-demo -n test-a -- bash

root@goweb-demo-5d7d55f846-vm2kc:/opt/goweb-demo# ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0   2476   576 ?        Ss   07:23   0:00 /bin/sh -c /opt/goweb-demo/runserver
root@goweb-demo-5d7d55f846-vm2kc:/opt/goweb-demo# kill -9 1

# 查看pod详情,已经发出警告
kubectl describe pod goweb-demo-5d7d55f846-vm2kc -n test-a

  Warning  Unhealthy  16s                 kubelet            Readiness probe failed: dial tcp 10.244.240.48:8090: connect: connection refused
  Warning  BackOff    16s                 kubelet            Back-off restarting failed container

# 查看pod,RESTARTS计数器已经增加为2,因为有两个探针
tantianran@test-b-k8s-master:~$ kubectl get pod -n test-a

NAME                          READY   STATUS    RESTARTS        AGE
goweb-demo-5d7d55f846-vm2kc   1/1     Running   2 (2m55s ago)   12m
  1. 使用startupProbe(启动探针)保护慢启动容器

有一种情景是这样的,某些应用在启动时需要较长的初始化时间。要这种情况下,若要不影响对死锁作出快速响应的探测,设置存活探测参数是要技巧的。 技巧就是使用相同的命令来设置启动探测,针对 HTTP 或 TCP 检测,可以通过将 failureThreshold * periodSeconds 参数设置为足够长的时间来应对糟糕情况下的启动时间。

代码语言:txt
复制
apiVersion: v1
kind: Namespace
metadata:
  name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  replicas: 10
  selector:
    matchLabels:
      app: goweb-demo
  template:
    metadata:
      labels:
        app: goweb-demo
    spec:
      containers:
      - name: goweb-demo
        image: 192.168.11.247/web-demo/goweb-demo:20221229v3
        livenessProbe:
          httpGet:
            path: /login
            port: 8090
          failureThreshold: 1
          periodSeconds: 10
        startupProbe:
          httpGet:
            path: /login
            port: 8090
          failureThreshold: 30
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb-demo
  type: NodePort

上面的例子,应用程序将会有最多 5 分钟(30 * 10 = 300s)的时间来完成其启动过程。 一旦启动探测成功一次,存活探测任务就会接管对容器的探测,对容器死锁作出快速响应。 如果启动探测一直没有成功,容器会在 300 秒后被杀死,并且根据 restartPolicy 来执行进一步处置。

5. 环境变量

创建 Pod 时,可以为其下的容器设置环境变量。通过配置文件的 env 或者 envFrom 字段来设置环境变量。

应用场景:

  • 容器内应用程序获取pod信息
  • 容器内应用程序通过用户定义的变量改变默认行为

变量值定义的方式:

  • 自定义变量值
  • 变量值从Pod属性获取
  • 变量值从Secret、ConfigMap获取

下面来个小例子,设置自定义变量,使用env给pod里的容器设置环境变量,本例子中,设置了环境变量有SAVE_TIME、MAX_CONN、DNS_ADDR。

代码语言:txt
复制
apiVersion: v1
kind: Pod
metadata:
  name: test-env-demo
spec:
  containers:
  - name: test-env-demo-container
    image: 192.168.11.247/web-demo/goweb-demo:20221229v3
    env:
    - name: SAVE_TIME
      value: "60"
    - name: MAX_CONN
      value: "1024"
    - name: DNS_ADDR
      value: "8.8.8.8"

开始创建pod

代码语言:txt
复制
tantianran@test-b-k8s-master:~$ kubectl create -f test-env.yaml 
pod/test-env-demo created
tantianran@test-b-k8s-master:~$ 

创建后,验证环境变量是否能获取到

代码语言:txt
复制
# 使用printenv打印环境变量
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl exec test-env-demo -- printenv
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=test-env-demo
SAVE_TIME=60 # 这个是
MAX_CONN=1024 # 这个是
DNS_ADDR=8.8.8.8 # 这个是
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
GOLANG_VERSION=1.19.4
GOPATH=/go
HOME=/root
tantianran@test-b-k8s-master:~/goweb-demo$ 

# 进入容器打印环境变量
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl exec -it test-env-demo -c test-env-demo-container -- bash
root@test-env-demo:/opt/goweb-demo# echo $SAVE_TIME # 单独打印一个
60
root@test-env-demo:/opt/goweb-demo# env # 执行env命令查看
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=test-env-demo
PWD=/opt/goweb-demo
DNS_ADDR=8.8.8.8
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
MAX_CONN=1024
GOLANG_VERSION=1.19.4
TERM=xterm
SHLVL=1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
SAVE_TIME=60
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
GOPATH=/go
_=/usr/bin/env
root@test-env-demo:/opt/goweb-demo# 

再来个小例子,直接取pod的属性作为变量的值,下面的例子是拿到pod所处的节点名称

代码语言:txt
复制
apiVersion: v1
kind: Pod
metadata:
  name: test-env-demo
spec:
  containers:
  - name: test-env-demo-container
    image: 192.168.11.247/web-demo/goweb-demo:20221229v3
    env:
    - name: NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName

打印变量

代码语言:txt
复制
tantianran@test-b-k8s-master:~$ kubectl exec test-env-demo -- printenv
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=test-env-demo
NODE_NAME=test-b-k8s-node02 # NODE_NAME变量,值为test-b-k8s-node02
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
GOLANG_VERSION=1.19.4
GOPATH=/go
HOME=/root

再来最后一个例子,使用容器字段作为环境变量的值,这个例子设置了资源限制的字段requests和limits,在设置环境变量中,使用资源限制的值作为了变量的值。

代码语言:txt
复制
apiVersion: v1
kind: Pod
metadata:
  name: test-env-demo
spec:
  containers:
  - name: test-env-demo-container
    image: 192.168.11.247/web-demo/goweb-demo:20221229v3
    resources:
      requests:
        memory: "32Mi"
        cpu: "125m"
      limits:
        memory: "64Mi"
        cpu: "250m"
    env:
      - name: CPU_REQUEST
        valueFrom:
          resourceFieldRef:
            containerName: test-env-demo-container
            resource: requests.cpu
      - name: CPU_LIMIT
        valueFrom:
          resourceFieldRef:
            containerName: test-env-demo-container
            resource: limits.cpu
      - name: MEM_REQUEST
        valueFrom:
          resourceFieldRef:
            containerName: test-env-demo-container
            resource: requests.memory
      - name: MEM_LIMIT
        valueFrom:
          resourceFieldRef:
            containerName: test-env-demo-container
            resource: limits.memory

打印变量

代码语言:txt
复制
tantianran@test-b-k8s-master:~$ kubectl exec test-env-demo -- printenv
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=test-env-demo
MEM_REQUEST=33554432
MEM_LIMIT=67108864
CPU_REQUEST=1
CPU_LIMIT=1
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
GOLANG_VERSION=1.19.4
GOPATH=/go
HOME=/root

6. init container(初始化容器)

初始化容器的特点:

  • Init容器是一种特殊容器,在Pod内,会在应用容器启动之前运行。
  • 如果Pod的Init容器失败,kubelet会不断地重启该Init容器,直到该容器成功为止。
  • 如果 Pod 对应的 restartPolicy 值为 "Never",并且 Pod 的 Init 容器失败, 则 Kubernetes 会将整个 Pod 状态设置为失败。
  • 如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。
  • Init 容器不支持探针,包括 lifecycle、livenessProbe、readinessProbe 和 startupProbe

在实际工作中,可利用它的这种工作机制应对某些场景,比如在应用容器启动之前,需要做一些初始化相关的工作,比如初始化配置文件,测试IP或端口的连通性等等场景。

下面来个小例子,场景是这样的,我的应用容器是goweb-demo,初始化容器是init-check-mysql-ip,假设应用容器是依赖数据库的,如果数据库没起来,那么应用容器就算起来了也是服务不可用。所以,现在的主要目的是想在应用容器启动之前检查mysql服务器的IP地址是否可ping通,如果是通的才启动应用容器。这个例子应该是比较贴近实际场景了。下面,看我写好的yaml:

代码语言:txt
复制
apiVersion: v1
kind: Namespace
metadata:
  name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb-demo
  template:
    metadata:
      labels:
        app: goweb-demo
    spec:
      containers:
      - name: goweb-demo
        image: 192.168.11.247/web-demo/goweb-demo:20221229v3
      initContainers:
      - name: init-check-mysql-ip
        image: 192.168.11.247/os/busybox:latest
        command: ['sh', '-c', "ping 192.168.11.248 -c 5"]
---
apiVersion: v1
kind: Service
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb-demo
  type: NodePort

mysql服务器故意没拉起,看看效果:

代码语言:txt
复制
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME                          READY   STATUS     RESTARTS      AGE
goweb-demo-859cc77bd5-jpcfs   0/1     Init:0/1   2 (18s ago)   48s
goweb-demo-859cc77bd5-n8hqd   0/1     Init:0/1   2 (17s ago)   48s
goweb-demo-859cc77bd5-sns67   0/1     Init:0/1   2 (17s ago)   48s
tantianran@test-b-k8s-master:~/goweb-demo$ 

tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME                          READY   STATUS       RESTARTS      AGE
goweb-demo-859cc77bd5-jpcfs   0/1     Init:Error   4 (67s ago)   2m44s
goweb-demo-859cc77bd5-n8hqd   0/1     Init:Error   4 (66s ago)   2m44s
goweb-demo-859cc77bd5-sns67   0/1     Init:Error   4 (67s ago)   2m44s
tantianran@test-b-k8s-master:~/goweb-demo$ 

tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME                          READY   STATUS                  RESTARTS      AGE
goweb-demo-859cc77bd5-jpcfs   0/1     Init:CrashLoopBackOff   3 (34s ago)   2m11s
goweb-demo-859cc77bd5-n8hqd   0/1     Init:CrashLoopBackOff   3 (33s ago)   2m11s
goweb-demo-859cc77bd5-sns67   0/1     Init:CrashLoopBackOff   3 (34s ago)   2m11s
tantianran@test-b-k8s-master:~/goweb-demo$ 

观察STATUS字段发现,它经历了3个阶段,第一阶段是正常的运行,也就是执行ping检查的操作,因为死活Ping不同,所以进入了第二阶段,状态为Error。紧接着是第三阶段,状态变成了CrashLoopBackOff,对于这个状态,我的理解是,初始化容器运行失败了,准备再次运行。总而言之,如果Mysql服务器的IP死活ping不通,它就会的状态就会一直这样:运行->Error->CrashLoopBackOff。当然这种情况是当Pod对应的restartPolicy为"Always"(这是默认策略)才会这样不断的循环检查,如果Pod对应的restartPolicy值为"Never",并且Pod的 Init容器失败,则Kubernetes会将整个Pod状态设置为失败。

当我把mysql服务器启动后,初始化容器执行成功,那么应用容器也就成功起来了:

代码语言:txt
复制
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME                          READY   STATUS    RESTARTS   AGE
goweb-demo-859cc77bd5-jpcfs   1/1     Running   0          30m
goweb-demo-859cc77bd5-n8hqd   1/1     Running   0          30m
goweb-demo-859cc77bd5-sns67   1/1     Running   0          30m
tantianran@test-b-k8s-master:~/goweb-demo$ 

7. 静态pod

在实际工作中,静态Pod的应用场景是毕竟少的,几乎没有。不过也还是得对它做一个简单的了解。静态Pod在指定的节点上由 kubelet 守护进程直接管理,不需要 API 服务器监管。 与由控制面管理的 Pod(例如,Deployment) 不同;kubelet 监视每个静态 Pod(在它失败之后重新启动),静态 Pod 始终都会绑定到特定节点的 Kubelet上。

在每个node节点上,kubelet的守护进程会自动在/etc/kubernetes/manifests/路径下发现yaml,因此,如果想要创建静态Pod,就得把yaml放到该目录,下面我们直接实战一下。

随便登录到某台node节点,然后创建/etc/kubernetes/manifests/static_pod.yaml

代码语言:txt
复制
apiVersion: v1
kind: Pod
metadata:
  name: test-static-pod
spec:
  containers:
  - name: test-container
    image: 192.168.11.247/web-demo/goweb-demo:20221229v3

创建后,回到master节点上查看pod

代码语言:txt
复制
tantianran@test-b-k8s-master:~$ kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
test-static-pod-test-b-k8s-node01   1/1     Running   0          11s

通过上面的输出结果可以看到,该静态pod已经在节点test-b-k8s-node01上面正常运行了,说明kubelet守护进程已经自动发现并创建了它。你可能会问,它不是不需要API服务器监管吗?为啥在master节点能看到它?因为kubelet 会尝试通过 Kubernetes API服务器为每个静态Pod自动创建一个镜像Pod,这意味着节点上运行的静态Pod对API服务来说是可见的,但是不能通过API服务器来控制。 且Pod名称将把以连字符开头的节点主机名作为后缀。

本文转载于(喜欢的盆友关注我们):https://mp.weixin.qq.com/s/5Kv7DU34_Ae5y17MAQVO-Q

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Pod概念热身
  • 2. POD内容器间资源共享实现机制
    • 2.1 共享数据的机制
      • 2.2 共享网络的机制
      • 3. Pod常用管理命令
      • 4. Pod的重启策略+应用健康检查(应用自修复)
      • 5. 环境变量
      • 6. init container(初始化容器)
      • 7. 静态pod
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档