Istio 运维实战系列(1):应用容器对 Envoy Sidecar 的启动依赖问题
作者赵化冰,腾讯云高级工程师,Istio contributor,ServiceMesher管理委员,热衷于开源、网络和云计算。目前主要从事服务网格的开源和研发工作。
目录
故障现象 故障分析 解决方案 在应用启动命令中判断 Envoy 初始化状态 通过 pod 容器启动顺序进行控制 Kubernetes 支持定义 pod 中容器之间的依赖关系 解耦应用服务之间的启动依赖关系 小结 参考文档
故障现象
故障分析
kubectl logs --previous
命令查询 awesome-app 容器最后一次重启前的日志,以从日志中查找其重启的原因。kubectl logs --previous awesome-app-cd1234567-gzgwg -c awesome-app
Logging system failed to initialize using configuration from 'http://log-config-server:12345/******/logback-spring.xml'
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
Kubectl get pod
命令查询 Pod 的运行状态,尝试找到更多的线索:kubectl get pod awesome-app-cd1234567-gzgwg -oyaml
containerStatuses:
- containerID:
lastState:
terminated:
containerID:
exitCode: 1
finishedAt: 2020-09-01T13:16:23Z
reason: Error
startedAt: 2020-09-01T13:16:22Z
name: awesome-app
ready: true
restartCount: 2
state:
running:
startedAt: 2020-09-01T13:16:36Z
- containerID:
lastState: {}
name: istio-proxy
ready: true
restartCount: 0
state:
running:
startedAt: 2020-09-01T13:16:20Z
hostIP: 10.0.6.161
2020-09-01T13:16:20Z istio-proxy 启动 2020-09-01T13:16:22Z awesome-app 上一次启动时间 2020-09-01T13:16:23Z awesome-app 上一次异常退出时间 2020-09-01T13:16:36Z awesome-app 最后一次启动,以后就一直正常运行
解决方案
在应用启动命令中判断 Envoy 初始化状态
localhost:15020/healthz/ready
会在 xDS 配置初始化完成后才返回 200,否则将返回 503,因此可以根据该接口判断 Envoy 的配置初始化状态,待其完成后再启动应用容器。我们可以在应用容器的启动命令中加入调用 Envoy 健康检查的脚本,如下面的配置片段所示。在其他应用中使用时,将 start-awesome-app-cmd
改为容器中的应用启动命令即可。apiVersion: apps/v1
kind: Deployment
metadata:
name: awesome-app-deployment
spec:
selector:
matchLabels:
app: awesome-app
replicas: 1
template:
metadata:
labels:
app: awesome-app
spec:
containers:
- name: awesome-app
image: awesome-app
ports:
- containerPort: 80
command: ["/bin/bash", "-c"]
args: ["while [[ \"$(curl -s -o /dev/null -w ''%{http_code}'' localhost:15020/healthz/ready)\" != '200' ]]; do echo Waiting for Sidecar;sleep 1; done; echo Sidecar available; start-awesome-app-cmd"]
Kubernetes 启动 应用容器。 应用容器启动脚本中通过 curl get localhost:15020/healthz/ready
查询 Envoy sidcar 状态,由于此时 Envoy sidecar 尚未就绪,因此该脚本会不断重试。Kubernetes 启动 Envoy sidecar。 Envoy sidecar 通过 xDS 连接 Pilot,进行配置初始化。 应用容器启动脚本通过 Envoy sidecar 的健康检查接口判断其初始化已经完成,启动应用进程。
通过 pod 容器启动顺序进行控制
// Step 7: start containers in podContainerChanges.ContainersToStart.
for _, idx := range podContainerChanges.ContainersToStart {
start("container", containerStartSpec(&pod.Spec.Containers[idx]))
}
Kubernetes 启动 Envoy sidecar 。 Kubernetes 执行 postStart hook。 postStart hook 通过 Envoy 健康检查接口判断其配置初始化状态,直到 Envoy 启动完成 。 Kubernetes 启动应用容器。
pilot-agent wait
命令会持续调用 Envoy 的健康检查接口 '/healthz/ready' 检查其状态,直到 Envoy 完成配置初始化。这篇文章Delaying application start until sidecar is ready[5]中介绍了更多关于该方案的细节。apiVersion: v1
kind: Pod
metadata:
name: sidecar-starts-first
spec:
containers:
- name: istio-proxy
image:
lifecycle:
postStart:
exec:
command:
- pilot-agent
- wait
- name: application
image: my-application
Kubernetes 支持定义 pod 中容器之间的依赖关系
Kubernetes 启动 Envoy sidecar 容器。 Kubernetes 通过 Envoy sidecar 容器的 readiness probe 检查其状态,直到 readiness probe 反馈 Envoy sidecar 已经 ready,即已经初始化完毕。 Kubernetes 启动应用容器。
解耦应用服务之间的启动依赖关系
小结
参考资料
[1]Istio流量管理实现机制深度解析: https://zhaohuabing.com/post/2018-09-25-istio-traffic-management-impl-intro/
[2]Kubernetes 源码: https://github.com/kubernetes/kubernetes/blob/537a602195efdc04cdf2cb0368792afad082d9fd/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L827-L830
[3]postStart lifecycle hook: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/
[4]Allow users to delay application start until proxy is ready #24737: https://github.com/istio/istio/pull/24737
[5]Delaying application start until sidecar is ready: https://medium.com/@marko.luksa/delaying-application-start-until-sidecar-is-ready-2ec2d21a7b74
[6]Support startup dependencies between containers on the same Pod #65502: https://github.com/kubernetes/kubernetes/issues/65502
[7]App container unable to connect to network before sidecar is fully running #11130: https://github.com/istio/istio/issues/11130