【kubernetes系列】kubernetes之initcontainer初始化容器

概述

Init Container就是用来做初始化工作的容器,可以是一个或者多个,如果有多个的话,这些容器会按定义的顺序依次执行,只有所有的Init Container执行完后,主容器才会被启动。我们知道一个Pod里面的所有容器是共享数据卷和网络命名空间的,所以Init Container里面产生的数据可以被主容器使用到的。 Init Container与应用容器本质上是一样的,但他们是仅运行一次就结束的任务,并且必须在成功执行完后,系统才能继续执行下一个容器。

一个pod完整的生命周期如下:

【kubernetes系列】kubernetes之initcontainer初始化容器_第1张图片

从上面这张图我们可以直观的看到PostStart和PreStop包括liveness和readiness是属于主容器的生命周期范围内的,而Init Container是独立于主容器之外的,当然他们都属于Pod的生命周期范畴之内的。

另外我们可以看到上面我们的Pod右边还有一个infra的容器,这是一个什么容器呢?我们可以在集群环境中去查看任意一个Pod对应的运行的Docker容器,我们可以发现每一个Pod下面都包含了一个pause-amd64的镜像,这个就是我们的infra镜像,我们知道Pod下面的所有容器是共享同一个网络命名空间的,这个镜像就是来做这个事情的,所以每一个Pod当中都会包含一个这个镜像,其实就是我们之前了解到的pause容器。

应用场景

在很多应用场景中,应用在启动之前都需要进行初始化操作,如:

  • 等待其他关联服务正确运行(例如数据库或某个后台服务)
  • 基于环境变量或配置模板生成服务所需配置文件
  • 从远程数据库获取本地所需配置,或者将自身注册到某个中央数据库中
  • 下载相关依赖包,或者对统进行一些预配置操作

示例1

我们先来测试使用initcontainer创建一个服务依赖的场景的Pod:

##引入了外部mysql
[root@k8s-m1 k8s-total]# cat mysql-svc.yml 
kind: Endpoints
apiVersion: v1
metadata:
  name: mysql-production
subsets:
  - addresses:
      - ip: 192.168.2.142
    ports:
      - port: 3306
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-production
spec:
  ports:
    - port: 3306

##部署nginx
[root@k8s-m1 k8s-total]# cat my-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      tier: frontend
  replicas: 1
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 80
  selector:
    tier: frontend

##有初始化容器的pod

apiVersion: v1
kind: Pod
metadata:
  name: init-pod-1
  labels:
    app: init
spec:
  containers:
  - name: main-container
    image: busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-service
    image: busybox
    command: ['sh', '-c', 'until nslookup nginx-service; do echo waiting for nginx-service; sleep 2; done;']
  - name: init-mysql
    image: busybox
    command: ['sh', '-c', 'until nslookup mysql-production; do echo waiting for mysql; sleep 2; done;']
#部署
[root@k8s-m1 k8s-init-container]# kubectl apply  -f mysql-svc.yml  -f  my-nginx.yml  -f init-pod-1.yml 

#查看
[root@k8s-m1 k8s-total]# kubectl get ep,po
NAME                               ENDPOINTS                                                  AGE
endpoints/nginx-service            10.244.42.159:80                           10m
endpoints/mysql-production         192.168.2.142:3306                                         10m

NAME                            READY   STATUS    RESTARTS   AGE
pod/init-pod-1                   1/1     Running   0          10m
pod/my-nginx-7ff446c4f4-tbtpc   1/1     Running   1          10m

我们可以 describe 下看看详细信息:

[root@k8s-m1 k8s-total]# kubectl describe pod init-pod-1 
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  13m   default-scheduler  Successfully assigned default/init-pod-1 to k8s-m1
  Normal  Pulling    13m   kubelet            Pulling image "busybox"
  Normal  Pulled     13m   kubelet            Successfully pulled image "busybox" in 15.979657153s
  Normal  Created    13m   kubelet            Created container init-service
  Normal  Started    13m   kubelet            Started container init-service
  Normal  Pulling    12m   kubelet            Pulling image "busybox"
  Normal  Pulled     12m   kubelet            Successfully pulled image "busybox" in 15.995762509s
  Normal  Created    12m   kubelet            Created container init-mysql
  Normal  Started    12m   kubelet            Started container init-mysql
  Normal  Pulling    12m   kubelet            Pulling image "busybox"
  Normal  Pulled     12m   kubelet            Successfully pulled image "busybox" in 15.976887445s
  Normal  Created    12m   kubelet            Created container main-container

可以看到,我们在Pod启动过程中,初始化容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。如果由于运行时或失败退出,导致容器启动失败,它会根据Pod的restartPolicy指定的策略进行重试。 然而,如果 Pod 的 restartPolicy 设置为 Always,Init 容器失败时会使用 RestartPolicy 策略。

在所有的初始化容器没有成功之前,Pod将不会变成 Ready状态。正在初始化中的Pod处于Pending状态,但应该会将条件Initializing设置为 true。

示例2

接下来我们测试使用initcontainer创建一个做初始化配置工作的Pod:

[root@k8s-m1 k8s-init-container]# cat init-pod-2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html
  initContainers:
  - name: install
    image: busybox
    command:
    - wget
    - "-O"
    - "/work-dir/index.html"
    - http://www.baidu.com
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"
  volumes:
  - name: workdir
    emptyDir: {}

我们可以看到这里又出现了volumes,spec.volumes指的是Pod中的卷,spec.containers.volumeMounts,是将指定的卷 mount 到容器指定的位置,相当于Docker里面的-v 宿主机目录:容器目录,我们前面用到过hostPath,我们这里使用的是emptyDir{},这个就相当于一个共享卷,是一个临时的目录,生命周期等同于Pod的生命周期。

初始化容器执行完,会下载一个 html 文件映射到emptyDir{},而主容器也是和 spec.volumes 里的 emptyDir{} 进行映射,所以nginx容器的/usr/share/nginx/html目录下会映射 index.html 文件。

我们来创建下该Pod,然后验证nginx容器是否运行:

[root@k8s-m1 k8s-init-container]# kubectl apply  -f init-pod-2.yaml 
pod/init-demo created
[root@k8s-m1 k8s-init-container]# kubectl get po -o wide
NAME                        READY   STATUS    RESTARTS   AGE    IP              NODE     NOMINATED NODE   READINESS GATES
init-demo                   1/1     Running   0          60s    10.244.42.155   k8s-m1   <none>           <none>

[root@k8s-m1 k8s-init-container]# curl 10.244.42.155 

正常效果我们可以看到有百度相关的信息,就可以证明我们上面的初始化的工作正常完成。

更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出

你可能感兴趣的:(Kubernetes,kubernetes,容器,云原生)