Kubernetes提供了一个称为InitContainers的有用功能,可以在Pod初始化期间执行一些任务。 一个示例用例是确保另一项服务可用。 让我们来看看这如何应用于示例网址缩短程序应用程序。
目前的情况
如果我们在数据库服务/ 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官方文档。