容器
This commit is contained in:
@ -48,10 +48,10 @@ module.exports = {
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
'@vuepress/pwa': {
|
||||
serviceWorker: true,
|
||||
updatePopup: true
|
||||
},
|
||||
// '@vuepress/pwa': {
|
||||
// serviceWorker: true,
|
||||
// updatePopup: true
|
||||
// },
|
||||
'@vssue/vuepress-plugin-vssue': {
|
||||
// set `platform` rather than `api`
|
||||
platform: 'github',
|
||||
@ -82,7 +82,7 @@ module.exports = {
|
||||
// zIndex: 10000,
|
||||
// },
|
||||
// },
|
||||
'vuepress-plugin-smooth-scroll': {},
|
||||
// 'vuepress-plugin-smooth-scroll': {},
|
||||
'code-switcher': {},
|
||||
'reading-progress': {},
|
||||
// 'vuepress-plugin-baidu-autopush':{},
|
||||
@ -274,6 +274,9 @@ module.exports = {
|
||||
children: [
|
||||
'k8s-intermediate/container/images',
|
||||
'k8s-intermediate/container/env',
|
||||
'k8s-intermediate/container/runtime',
|
||||
'k8s-intermediate/container/lifecycle',
|
||||
'k8s-intermediate/container/lifecycle-p',
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
15
.vuepress/public/statics/learning/container/lifecycle.yaml
Normal file
15
.vuepress/public/statics/learning/container/lifecycle.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: lifecycle-demo
|
||||
spec:
|
||||
containers:
|
||||
- name: lifecycle-demo-container
|
||||
image: nginx
|
||||
lifecycle:
|
||||
postStart:
|
||||
exec:
|
||||
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
|
||||
preStop:
|
||||
exec:
|
||||
command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]
|
||||
@ -48,7 +48,7 @@ Service是一个抽象层,它通过 LabelSelector 选择了一组 Pod(容器
|
||||
|
||||
## 服务和标签
|
||||
|
||||
下图中有两个服务Service A(蓝色虚线)和Service B(黄色虚线)
|
||||
下图中有两个服务Service A(黄色虚线)和Service B(蓝色虚线)
|
||||
Service A 将请求转发到 IP 为 10.10.10.1 的Pod上,
|
||||
Service B 将请求转发到 IP 为 10.10.10.2、10.10.10.3、10.10.10.4 的Pod上。
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@ meta:
|
||||
|
||||
# 容器的环境变量
|
||||
|
||||
> 参考文档: [Container Environment Variables](https://kubernetes.io/docs/concepts/containers/container-environment-variables/)
|
||||
|
||||
Kubernetes为容器提供了一系列重要的资源:
|
||||
* 由镜像、一个或多个数据卷合并组成的文件系统
|
||||
* 容器自身的信息
|
||||
|
||||
71
learning/k8s-intermediate/container/lifecycle-p.md
Normal file
71
learning/k8s-intermediate/container/lifecycle-p.md
Normal file
@ -0,0 +1,71 @@
|
||||
---
|
||||
vssueId: 124
|
||||
layout: LearningLayout
|
||||
description: Kubernetes教程_Kubernetes 中支持容器的 postStart 和 preStop 事件,本文阐述了如何向容器添加生命周期事件处理程序(handler)
|
||||
meta:
|
||||
- name: keywords
|
||||
content: Kubernetes 教程,K8S 教程,容器生命周期
|
||||
---
|
||||
|
||||
# 容器生命周期事件处理
|
||||
|
||||
> 参考文档: [Attach Handlers to Container Lifecycle Events](https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/)
|
||||
|
||||
Kubernetes 中支持容器的 postStart 和 preStop 事件,本文阐述了如何向容器添加生命周期事件处理程序(handler)。
|
||||
* `postStart` 容器启动时,Kubernetes 立刻发送 postStart 事件,但不确保对应的 handler 是否能在容器的 `EntryPoint` 之前执行
|
||||
* `preStop` 容器停止前,Kubernetes 发送 preStop 事件
|
||||
|
||||
## 前提
|
||||
|
||||
您已经有一个安装好的 Kubernetes 集群,并且可以通过 kubectl 访问该集群。请参考:
|
||||
|
||||
[安装Kubernetes单Master节点](/install/install-k8s.html)
|
||||
|
||||
## 定义postStart和preStop处理程序
|
||||
|
||||
下面的例子中,您将创建一个包含单一容器的 Pod,并为该容器关联 postStart 和 preStop 处理程序(handler)。Pod 的yaml文件定义如下:
|
||||
|
||||
<<< @/.vuepress/public/statics/learning/container/lifecycle.yaml
|
||||
|
||||
在该例子中,请注意:
|
||||
* postStart 命令向 `usr/share/message` 文件写入了一行文字
|
||||
* preStop 命令优雅地关闭了 nginx
|
||||
> 如果容器碰到问题,被 Kubernetes 关闭,这个操作是非常有帮助的,可以使得您的程序在关闭前执行必要的清理任务
|
||||
|
||||
* 创建 Pod
|
||||
``` sh
|
||||
kubectl apply -f https://kuboard.cn/statics/learning/container/lifecycle.yaml
|
||||
```
|
||||
|
||||
* 验证 Pod 中的容器已经运行:
|
||||
|
||||
``` sh
|
||||
kubectl get pod lifecycle-demo
|
||||
```
|
||||
|
||||
* 进入容器的命令行终端:
|
||||
|
||||
``` sh
|
||||
kubectl exec -it lifecycle-demo -- /bin/bash
|
||||
```
|
||||
|
||||
* 在命令行终端中,验证 `postStart` 处理程序创建的 `message` 文件:
|
||||
|
||||
``` sh
|
||||
root@lifecycle-demo:/# cat /usr/share/message
|
||||
```
|
||||
|
||||
输出结果如下所示:
|
||||
```
|
||||
Hello from the postStart handler
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
Kubernetes 在容器启动后立刻发送 postStart 事件,但是并不能确保 postStart 事件处理程序在容器的 EntryPoint 之前执行。postStart 事件处理程序相对于容器中的进程来说是异步的(同时执行),然而,Kubernetes 在管理容器时,将一直等到 postStart 事件处理程序结束之后,才会将容器的状态标记为 Running。
|
||||
|
||||
Kubernetes 在决定关闭容器时,立刻发送 preStop 事件,并且,将一直等到 preStop 事件处理程序结束或者 Pod 的 `--grace-period` 超时,才删除容器。请参考 [Termination of Pod](/learning/k8s-intermediate/workload/pod.html#termination-of-pods)
|
||||
|
||||
::: tip
|
||||
Kubernetes 只在 Pod `Teminated` 状态时才发送 preStop 事件,这意味着,如果 Pod 已经进入了 `Completed` 状态, preStop 事件处理程序将不会被调用。这个问题已经记录在 kubernetes 的 issue 中: [issue #55087](https://github.com/kubernetes/kubernetes/issues/55807)
|
||||
:::
|
||||
82
learning/k8s-intermediate/container/lifecycle.md
Normal file
82
learning/k8s-intermediate/container/lifecycle.md
Normal file
@ -0,0 +1,82 @@
|
||||
---
|
||||
vssueId: 124
|
||||
layout: LearningLayout
|
||||
description: Kubernetes教程_本文描述了 kubelet 管理的容器如何使用容器生命周期钩子执行指定的代码。
|
||||
meta:
|
||||
- name: keywords
|
||||
content: Kubernetes 教程,K8S 教程,容器生命周期
|
||||
---
|
||||
|
||||
# 容器生命周期
|
||||
|
||||
> 参考文档: [Container Lifecycle Hooks](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/)
|
||||
|
||||
本文描述了 kubelet 管理的容器如何使用容器生命周期钩子执行指定的代码。
|
||||
|
||||
## 概述
|
||||
|
||||
绝大多数高级程序编程语言的框架(例如,Angular、Spring Framework、Vue 等)在组件的生命周期中提供 hook(钩子函数),例如 Vue 组件的 `created`、`mounted`、`beforeDestroy`、`destroyed`, Java Web 应用中 ServeletContextListener 的 `contextInitialized`、`contextDestroyed` 等。Kubernetes 中,也为容器提供了对应的生命周期钩子函数,使得容器可以获知其所在运行环境对其进行管理的生命周期事件,以便容器可以响应该事件,并执行对应的代码。
|
||||
|
||||
## 容器钩子
|
||||
|
||||
Kubernetes中为容器提供了两个 hook(钩子函数):
|
||||
|
||||
* `PostStart`
|
||||
|
||||
此钩子函数在容器创建后将立刻执行。但是,并不能保证该钩子函数在容器的 `ENTRYPOINT` 之前执行。该钩子函数没有输入参数。
|
||||
|
||||
* `PreStop`
|
||||
|
||||
此钩子函数在容器被 terminate(终止)之前执行,例如:
|
||||
|
||||
* 通过接口调用删除容器所在 Pod
|
||||
* 某些管理事件的发生:健康检查失败、资源紧缺等
|
||||
|
||||
如果容器已经被关闭或者进入了 `completed` 状态,preStop 钩子函数的调用将失败。该函数的执行是同步的,即,kubernetes 将在该函数完成执行之后才删除容器。该钩子函数没有输入参数。
|
||||
|
||||
更多内容请参考 [Termination of Pods](/learning/k8s-intermediate/workload/pod.html#termination-of-pods)
|
||||
|
||||
### Hook handler的实现
|
||||
|
||||
容器只要实现并注册 hook handler 便可以使用钩子函数。Kubernetes 中,容器可以实现两种类型的 hook handler:
|
||||
|
||||
* Exec - 在容器的名称空进和 cgroups 中执行一个指定的命令,例如 `pre-stop.sh`。该命令所消耗的 CPU、内存等资源,将计入容器可以使用的资源限制。
|
||||
* HTTP - 想容器的指定端口发送一个 HTTP 请求
|
||||
|
||||
|
||||
### Hook handler的执行
|
||||
|
||||
当容器的生命周期事件发生时,Kubernetes 在容器中执行该钩子函数注册的 handler。
|
||||
|
||||
对于 Pod 而言,hook handler 的调用是同步的。即,如果是 `PostStart` hook,容器的 `ENTRYPOINT` 和 hook 是同时出发的,然而如果 hook 执行的时间过长或者挂起了,容器将不能进入到 `Running` 状态。
|
||||
|
||||
`PreStop` hook 的行为与此相似。如果 hook 在执行过程中挂起了,Pod phase 将停留在 `Terminating` 的状态,并且在 `terminationGracePeriodSeconds` 超时之后,Pod被删除。如果 `PostStart` 或者 `PreStop` hook 执行失败,则 Kubernetes 将 kill(杀掉)该容器。
|
||||
|
||||
用户应该使其 hook handler 越轻量级越好。例如,对于长时间运行的任务,在停止容器前,调用 `PreStop` 钩子函数,以保存当时的计算状态和数据。
|
||||
|
||||
|
||||
### Hook触发的保证
|
||||
|
||||
Hook 将至少被触发一次,即,当指定事件 `PostStart` 或 `PreStop` 发生时,hook 有可能被多次触发。hook handler 的实现需要保证即使多次触发,执行也不会出错。
|
||||
|
||||
通常来说,hook 实际值被触发一次。例如:如果 HTTP hook 的服务端已经停机,或者因为网络的问题不能接收到请求,请求将不会被再次发送。在极少数的情况下, 触发两次 hook 的事情会发生。例如,如果 kueblet 在触发 hook 的过程中重启了,该 hook 将在 Kubelet 重启后被再次触发。
|
||||
|
||||
### 调试 hook handler
|
||||
|
||||
Hook handler 的日志并没有在 Pod 的 events 中发布。如果 handler 因为某些原因失败了,kubernetes 将广播一个事件 `PostStart` hook 发送 `FailedPreStopHook` 事件。
|
||||
可以执行命令 `kubectl describe pod $(pod_name)` 以查看这些事件,例如:
|
||||
|
||||
``` sh
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
1m 1m 1 {default-scheduler } Normal Scheduled Successfully assigned test-1730497541-cq1d2 to gke-test-cluster-default-pool-a07e5d30-siqd
|
||||
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulling pulling image "test:1.0"
|
||||
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Created Created container with docker id 5c6a256a2567; Security:[seccomp=unconfined]
|
||||
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulled Successfully pulled image "test:1.0"
|
||||
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Started Started container with docker id 5c6a256a2567
|
||||
38s 38s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 5c6a256a2567: PostStart handler: Error executing in Docker Container: 1
|
||||
37s 37s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 8df9fdfd7054: PostStart handler: Error executing in Docker Container: 1
|
||||
38s 37s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "main" with RunContainerError: "PostStart handler: Error executing in Docker Container: 1"
|
||||
1m 22s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}
|
||||
```
|
||||
109
learning/k8s-intermediate/container/runtime.md
Normal file
109
learning/k8s-intermediate/container/runtime.md
Normal file
@ -0,0 +1,109 @@
|
||||
---
|
||||
vssueId: 124
|
||||
layout: LearningLayout
|
||||
description: Kubernetes教程_使用RuntimeClass这一特性可以为容器选择运行时的容器引擎。可以通过 RuntimeClass,使不同的 Pod 使用不同的容器引擎,以在性能和安全之间取得平衡。
|
||||
meta:
|
||||
- name: keywords
|
||||
content: Kubernetes教程,K8S教程,Runtime Class
|
||||
---
|
||||
|
||||
# Runtime Class
|
||||
|
||||
> 参考文档: [Runtime Class](https://kubernetes.io/docs/concepts/containers/runtime-class/)
|
||||
|
||||
特性状态:Kubernetes v1.14 <Badge type="warning">beta</Badge>
|
||||
|
||||
## RuntimeClass
|
||||
|
||||
使用 RuntimeClass 这一特性可以为容器选择运行时的容器引擎。
|
||||
|
||||
## 设计目标
|
||||
|
||||
可以通过 RuntimeClass,使不同的 Pod 使用不同的容器引擎,以在性能和安全之间取得平衡。例如,如果某些工作负载需要非常高的信息安全保证,您可能将其 Pod 运行在那种使用硬件虚拟化的容器引擎上;同时,将其他的 Pod 运行在另外一种容器引擎上,以获得更高的性能。
|
||||
|
||||
也可以通过 RuntimeClass 配置,使不同的 Pod 使用相同的容器引擎,但是不同的容器引擎设定。
|
||||
|
||||
### 配置步骤
|
||||
|
||||
确保 RuntimeClass 的 feature gate 在 apiserver 和 kubelet 上都是是激活状态(默认是激活的,请参考 [Feature Gates](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/))。
|
||||
|
||||
#### 在节点上配置 CRI
|
||||
|
||||
如需通过RuntimeClass进行配置,是依赖于 Container Runtime Interface(CRI)的具体实现的。
|
||||
|
||||
配置 CRI 时,请留意其 `handler` 名称(该名称是有 字符/数字 和 `-` 组成的字符串),RuntimeClass中将引用该名称。
|
||||
|
||||
::: tip
|
||||
RuntimeClass默认要求集群中所有节点上的容器引擎的配置都是相同的。在Kubernetes v1.16中才开始引入对节点上容器引起不同的情况下的支持(本文暂不讨论这部分内容)
|
||||
:::
|
||||
|
||||
安装 CRI 请参考文档 [CRI installation](https://kubernetes.io/docs/setup/production-environment/container-runtimes/)
|
||||
|
||||
* dockershim
|
||||
|
||||
Kubernetes 内建的 dockershim CRI 不支持 RuntimeClass
|
||||
|
||||
* [containerd](https://containerd.io/)
|
||||
|
||||
通过 containerd 的配置文件 `/etc/containerd/config.toml` 配置其 Runtime handler。请注意该文档的如下内容
|
||||
|
||||
```
|
||||
[plugins.cri.containerd.runtimes.${HANDLER_NAME}]
|
||||
```
|
||||
|
||||
更多细节请参考 [https://github.com/containerd/cri/blob/master/docs/config.md](https://github.com/containerd/cri/blob/master/docs/config.md)
|
||||
|
||||
* [cri-o](https://cri-o.io/)
|
||||
|
||||
通过 cri-o 的配置文件 `/etc/crio/crio.conf` 配置 Runtime handler。请注意该文档的 [crio.runtime table](https://github.com/kubernetes-sigs/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table)
|
||||
|
||||
```
|
||||
[crio.runtime.runtimes.${HANDLER_NAME}]
|
||||
runtime_path = "${PATH_TO_BINARY}"
|
||||
```
|
||||
|
||||
更多细节请参考文档 [https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go](https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go)
|
||||
|
||||
<!--FIXME -->
|
||||
|
||||
#### 创建对应的 RuntimeClass
|
||||
|
||||
在前面的步骤中完成了配置之后,每个配置都会有一个 `handler` 名称,用来唯一地标识该 CRI 的配置。此时,我们需要为每一个 handler 创建一个对应的 RuntimeClass api 对象。
|
||||
|
||||
RuntimeClass 目前只有两个主要的字段:
|
||||
* RuntimeClass name(`metadata.name`)
|
||||
* handler (`handler`)
|
||||
|
||||
该对象的定义如下所示:
|
||||
|
||||
``` yaml
|
||||
apiVersion: node.k8s.io/v1beta1
|
||||
kind: RuntimeClass
|
||||
metadata:
|
||||
name: myclass # RuntimeClass 没有名称空间
|
||||
handler: myconfiguration # 对应 CRI 配置的 handler 名称
|
||||
```
|
||||
|
||||
::: tip
|
||||
建议只让集群管理员可以修改(create/update/pacth/delete) RuntimeClass,这也是集群的默认配置。请参考 [Authorization Overview](https://kubernetes.io/docs/reference/access-authn-authz/authorization/)
|
||||
:::
|
||||
|
||||
### 使用
|
||||
|
||||
为集群完成 RuntimeClass 的配置后,使用的时候会非常简单。在 Pod 的定义中指定 `runtimeClassName` 即可,例如:
|
||||
|
||||
``` yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
runtimeClassName: myclass
|
||||
# ...
|
||||
```
|
||||
|
||||
kubelet 将依据这个字段使用指定的 RuntimeClass 来运行该 Pod。如果指定的 RuntimeClass 不存在,或者 CRI 不能运行对应的 handler 配置,则 Pod 将进入 `Failed` 这个终止 [阶段](/learning/k8s-intermediate/workload/pod-lifecycle.html#pod-phase)。此时可通过 Pod 中的 Event(事件)来查看具体的出错信息。
|
||||
|
||||
如果 Pod 中未指定 `runtimeClassName`,kubelet 将使用默认的 RuntimeHandler 运行 Pod,其效果等价于 RuntimeClass 这个特性被禁用的情况。
|
||||
|
||||
##
|
||||
Reference in New Issue
Block a user