本文主要围绕k8s command展开讨论。(deployment.spec.template.spec.containers[n].command)
主要聊聊平台在接入用户业务时,如何保证满足业务基本需求情况下增强平台易用性。
最初是由bash启动进程引起的业务进程无法接收sigterm优雅退出问题。解决过程中逐渐回归为如何在k8s command定义多条指令
原生K8S-Command规范
填写格式
field | type | comment |
---|---|---|
container.command | []string | 对应Dockerfile中Entrypoint指令字段 |
container.args | []string | 对应Dockerfile中Cmd字段 |
生效规则:
填写command
时,command[0]
为首启动命令执行文件,command[1:] 及 args[:]
均为启动参数。
未填写command
时,args[0]
为首启动命令执行文件,args[1:]
为启动参数。
实例(pod)生命周期
创建前
生产环境中我们一般不会单独创建pod,而是利用kube-controller-manager的组件deployment、daemonSet等API来管控实例,其控制循环功能可自动部署、自动恢复,将任务状态永远调整向期望状态。
例如
- 用户声明deployment.spec(期望实例模板) 及 replicas(实例数)交给k8s;
- 在deploymentController部分的控制逻辑中,将生成ReplicasSet;
- ReplicasSetController监听资源处理,生成Pod;
- Pod被kube-scheduler监听处理,为其分配合适的node;
- kubelet(此组件安装在slave node上)监听到pod绑定信息,在node上实例化pod信息。
创建
- 创建sanbox容器
- 拉取镜像并创建init容器
- 创建普通容器 (拉取镜像,创建容器,启动首启动进程,执行postStart)
当init容器执行完成退出后,启动所有普通容器。根据liveness
、readiness
配置情况探测并确定容器是否ready。所有容器ready时pod状态更新为Ready。
创建普通容器
code位于pkg/kubelet/kuberuntime/kuberuntime_cotainer.go
的 startContainer
函数
// Step 1: pull the image.
// Step 2: create the container.
// Step 3: start the container.
err = m.runtimeService.StartContainer(containerID)
// Step 4: execute the post start hook.
if container.Lifecycle != nil && container.Lifecycle.PostStart != nil {
kubeContainerID := kubecontainer.ContainerID{
Type: m.runtimeName,
ID: containerID,
}
msg, handlerErr := m.runner.Run(kubeContainerID, pod, container, container.Lifecycle.PostStart)
注意这里step3,4: 先StartContainer(启动首启动进程-即上面的command、args信息);然后在向容器发送postStart指令,注意此处postStart。
(这里着重看postStart 是由于 有用postStart来实现容器内自定义多进程的想法)
runner.Run()调用处为