Kubernetes提供了一个称为InitContainers的有用功能,可以在Pod初始化期间执行一些任务。 一个示例用例是确保另一项服务可用。 让我们来看看这如何应用于示例网址缩短程序应用程序。




k8s 启动容器bashrc不管用 k8s容器启动失败_Containers


目前的情况

如果我们在数据库服务/ pod可用之前就部署了webapp,则由于缺少与后端的连接,因此该应用程序尝试启动时会惨败:

$ kubectl logs webapp-c7c8fd499-bl5sl
...
level=fatal msg="failed to start: failed to open connection to database: dial tcp: lookup postgres on 10.96.0.10:53: no such host"

使用Golang编写应用程序后,以致命级别记录消息也会通过Exit(1)调用停止应用程序。 从某种意义上说,这种行为很有意义:如果没有数据库连接,为什么应用程序会启动?

在Kubernetes中,部署的默认情况下将restartPolicy设置为Alwaysby,这意味着节点的kubelet代理会尝试一次又一次重新启动Pod,并在失败时以指数级的延迟延迟。

$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE
webapp-c7c8fd499-bl5sl 0/1 Error 0 2s
webapp-c7c8fd499-bl5sl 0/1 Error 1 2s
webapp-c7c8fd499-bl5sl 0/1 CrashLoopBackOff 1 3s
webapp-c7c8fd499-bl5sl 0/1 Error 2 15s
webapp-c7c8fd499-bl5sl 0/1 CrashLoopBackOff 2 29s
webapp-c7c8fd499-bl5sl 0/1 Error 3 44s
webapp-c7c8fd499-bl5sl 0/1 CrashLoopBackOff 3 45s
webapp-c7c8fd499-bl5sl 0/1 Error 4 1m
webapp-c7c8fd499-bl5sl 0/1 CrashLoopBackOff 4 1m
webapp-c7c8fd499-bl5sl 0/1 Error 5 2m
webapp-c7c8fd499-bl5sl 0/1 CrashLoopBackOff 5 3m
webapp-c7c8fd499-bl5sl 0/1 Error 6 5m
webapp-c7c8fd499-bl5sl 0/1 CrashLoopBackOff 6 6m

部署数据库并创建其服务后,应用程序终于能够建立连接并永久启动:

$ kubectl apply -f templates/database-deployment.ymldeployment "postgres" created$ kubectl apply -f templates/database-service.ymlservice "postgres" created$ kubectl get pods -wNAME                     READY     STATUS             RESTARTS   AGEwebapp-c7c8fd499-bl5sl      0/1    CrashLoopBackOff    9         25mpostgres-77b6bf95b7-wjlfg   0/1    Pending             0          0spostgres-77b6bf95b7-wjlfg   0/1    Pending             0          0spostgres-77b6bf95b7-wjlfg   0/1    ContainerCreating   0          1spostgres-77b6bf95b7-wjlfg   1/1    Running             0         41swebapp-c7c8fd499-bl5sl      1/1    Running            10         26m

没关系,但是我们可以做得更好吗? (警惕:是的,我们可以!)

InitContainers进行救援

Pod可以具有多个应用程序容器以及几个所谓的InitContainer,它们在启动应用程序容器之前按顺序执行,直到终止。 如果一个InitContainer失败,则将部署的restartPolicy应用于它。

InitContainers功能还带来了其他好处,例如可能未捆绑在应用程序的Docker映像中的运行工具。 在我们的情况下,pg_isready命令未安装在我们的webapp Docker映像中,但是能够使用它来验证数据库已准备好接受连接,这不是很好吗?

我们可以通过在基于postgres:9.6.5 Docker镜像的容器中运行kubectl来运行此命令来验证该命令:

$ kubectl run check-db-ready   --image=postgres:9.6.5   --restart=Never   --command -- /bin/bash -c   "pg_isready -h postgres -p 5432 && echo $?"pod "check-db-ready" created$ kubectl logs check-db-readypostgres:5432 - accepting connections0$ kubectl delete pod check-db-ready # a bit of house cleaning...

(如果服务器已准备就绪,pg_isready命令将以返回码0退出,如果服务器仍在启动,则返回1,如果服务器尚未启动,则返回2,并且3发生了其他事情。)

大! 所以现在我们可以运行pg_isready -h postgres -p 5432 && echo $? webapp部署的InitContainer中的命令验证数据库是否正在接受连接。 尤其请参见下面的部署清单第15-20行:

apiVersion: apps/v1beta1kind: Deploymentmetadata:  name: webappspec:  template:    metadata:      labels:        app: webapp    spec:      volumes:        - name: config-volume          configMap:            name: app-config      initContainers:      - name: check-db-ready        image: postgres:9.6.5        command: ['sh', '-c',           'until pg_isready -h postgres -p 5432;           do echo waiting for database; sleep 2; done;']      containers:      - image: xcoulon/go-url-shortener:0.2.0        name: go-url-shortener        volumeMounts:        - name: config-volume          mountPath: /etc/config        ports:        - containerPort: 8080        env:        - name: CONFIG_FILE          value: /etc/config/config.yaml        - name: POSTGRES_HOST          value: postgres        - name: POSTGRES_PORT          value: "5432"        - name: POSTGRES_DATABASE          valueFrom:            secretKeyRef:              name: database-secret-config              key: dbname        - name: POSTGRES_USER          valueFrom:            secretKeyRef:              name: database-secret-config              key: username        - name: POSTGRES_PASSWORD          valueFrom:            secretKeyRef:              name: database-secret-config              key: password

现在让我们看看在没有可用的数据库容器/服务的情况下,InitContainers如何影响webapp容器的启动:

$ kubectl create -f templates/webapp-deployment.ymldeployment "webapp" created$ kubectl get podsNAME                      READY     STATUS     RESTARTS   AGEwebapp-7cc6fffcd4-7drg2   0/1       Init:0/1   0          30s

现在,Webapp容器不再处于CrashLoopBackOff和Error状态之间,就像我们在本文的第一部分中看到的那样,而是被锁定为Init:0/1状态,这意味着它正在等待第一个InitContainer成功完成。

查看广告连播的状态和事件

检查Pod的事件是了解容器级别正在发生的事情的好方法:

$ kubectl describe pod/webapp-7cc6fffcd4-7drg2
Name: webapp-7cc6fffcd4-7drg2
...
Init Containers:
 check-db-ready:
 Container ID: docker://aa63d4a27cd8
 Image: postgres:9.6.5
 ...
 Command:
 sh
 -c
 until pg_isready -h postgres -p 5432 -U postgres; do echo waiting for database; sleep 2; done;
 State: Running
 Started: Sun, 10 Dec 2017 10:59:06 +0100
 Ready: False
...

一个名为check-db-ready的InitContainer正在运行,但是按预期,它尚未准备好。 查看此特定容器的日志可了解正在发生的情况:

$ kubectl logs -f webapp-7cc6fffcd4-7drg2 -c check-db-ready
...
waiting for database
postgres:5432 - no response

(请注意,-c参数选择在其上应用kubectl logs命令的容器。)

正如人们所期望的那样,一旦数据库最终部署完毕,InitContainer便完成了,并且webapp从成功连接到后端开始。

$ kubectl create -f templates/database-deployment.ymldeployment "postgres" created$ kubectl create -f templates/database-service.ymlservice "postgres" created$ kubectl logs -f webapp-7cc6fffcd4-7drg2 -c check-db-ready...waiting for databasepostgres:5432 - accepting connections$ kubectl get podsNAME                        READY     STATUS    RESTARTS   AGEpostgres-77b6bf95b7-mshzd   1/1       Running   0          1mwebapp-7cc6fffcd4-7drg2     1/1       Running   0          11m

我们已经在本文中介绍了InitContainers功能的基本用例,展示了如何在应用程序容器启动之前将其用于验证某些前提条件。

进一步

如果需要有关它的更多信息,可以查看Kubernetes官方文档。