Pod 的介绍
在 Kubernetes 中,Pod 是最小的调度单元,Pod 其实就是一个容器组,它可以包含一个或多个容器(Pod 翻译为豆荚,一个豆荚可以有多个豆子)。对于一个 Pod 来说,它会运行在某个宿主机上,当需要调度的时候,Kubernetes 会将 Pod 作为一个整体进行调度。
由于整个 Pod 是运行在一个宿主机上的,所以 Pod 中的所有容器共享这些资源:
- 所有容器共享同一个 IP。
- 所有容器共享同一个 hostname。
- 当某个 Volume 被挂载到 Pod 的文件系统时,这个 Volume 可以被多个容器共享。
- 容器之间可以通过 System V IPC 或 POSIX 消息队列进行通信。
思考一下,什么样的容器才适合放到同一个 Pod 中呢?
Pod 的配置
可以使用 yaml 配置文件去描述 Pod,并写清楚我们希望 Pod 达到的状态:
使用下面的命令可以创建 Pod,用于运行 Nginx:
也可以获取 Pod 的运行状态:
如果想要获取 Pod 中所有容器的运行状态,可以使用:
如果想获得 Pod 的更多详细信息(包括所有容器的信息,以及和 Pod 相关的事件),可以使用:
删除 Pod 时,可以根据 Pod 的名称删除指定的 Pod:
也可以根据 yaml 配置文件删除 Pod:
Pod 的调试
在运行上面的 Nginx Pod 之后,如何判断 Nginx 正常工作呢?Kubernetes API 提供了端口转发的功能,可以在另一个终端执行下面的命令:
上面的命令会将localhost:8000
的请求转发到 Nginx Pod 的80
端口。可以验证一下:
如果没有差错,这个命令会输出 Nginx 首页的内容。
另一种有效的调试手段,就是进入到容器内部去实地考察:
如果 Pod 中有多个容器,可以使用-c
参数指定具体的容器:
当然,更加经常使用的调试手段,就是观察容器的输出日志:
Pod 的健康检查
默认情况下,Kubernetes 会开启进程的健康检查:如果 Kubernetes 检测到容器里面的进程退出了,那么它就会重启这个容器。
只有进程级别的健康检查是远远不够的,设想一下,假设程序发生死锁了,此时进程仍然在运行,但是它已经不能正确输出响应了。为解决这个问题,还需要在应用层实现健康检查。
Kubernetes 提供了三种类型的健康检查:
- HTTP 健康检查:向容器的 HTTP 接口发起 HTTP 请求,如果返回的状态码在 [200, 400) 之间,就认为请求是成功的。
- TCP 健康检查:与容器的某个 port 建立 TCP 连接,如果连接建立成功,则说明容器是健康的。
- Exec 健康检查:在容器里面执行一个命令,如果返回 0 则认为是成功的,否则失败。
需要注意的是,健康检查是容器级别的,而不是 Pod 级别的。这意味着一个 Pod 里面的每个容器,都需要配置不同的健康检查规则。
下面的例子使用的是 HTTP 健康检查:
下面解释一下各项配置的意义:
initialDelaySeconds: 5
:使用 5 秒用来等待 Pod 的初始化。timeoutSeconds: 1
:为 HTTP 请求设置超时时间为 1 秒。periodSeconds: 10
:每 10 秒执行一次健康检查。failureThreshold: 3
:设置失败的阈值,如果超过 3 次健康检查都失败了,容器就会被重启。
Pod 的资源限制
在创建 Pod 的时候,Kubernetes 会将 Pod 调度到某台宿主机上。然而有的宿主机比较繁忙,有的则比较空闲。为了提高 Kubernetes 对资源的利用率(例如 CPU 或内存),我们可以告诉 Kubernetes,这个 Pod 需要使用多少资源,从而协助 Kubernetes 优化调度策略。
由于每个容器对资源的需求是不同的,所以资源限制需要具体到某个容器。譬如说,一个 Pod 包括容器 A 和 B,容器 A 至少需要 1GB 内存,容器 B 至少需要 2GB 内存,那么整个 Pod 就至少需要 3 GB 内存。
有两种类型的资源限制:
requests
:用来指定容器至少需要多少资源。limits
:用来限制容器最多可以使用多少资源。
下面的例子中,Nginx 容器至少需要 0.5 个 CPU 核心以及 128 MB 内存,最多消耗 1 个 CPU 核心以及 256 MB 内存:
Pod 的 Volume
默认情况下,容器内的文件是暂时性存在的,当容器重启的时候,文件也会消失。在这种情况下,容器只适合用于运行无状态的程序。但在一些场景下,需要使用到数据持久化:
- 需要在容器中运行有状态的程序,例如数据库。
- 需要在一个 Pod 里面的多个容器之间共享文件。
我们可以通过将 Volume 挂载到 Pod 的文件系统,来解决这些问题。这里先介绍几种常用的 Volume 类型:emptyDir
、hostPath
和awsElasticBlockStore
。
先介绍emptyDir
类型的 Volume。当 Pod 被调度到某台宿主机时,emptyDir
类型的 Volume 就会被创建,并且这个 Volume 可以被 Pod 里面的多个容器共享。一旦 Pod 离开了这个宿主机,emptyDir
中的数据会被永久删除。需要注意的是,如果 Pod 里面的容器 crash 并重启了,这并不会导致 Pod 离开了这个宿主机,所以不会导致emptyDir
的数据被删除。
hostPath
类型的 Volume,用来将宿主机的目录挂载到 Pod 的文件系统,这样在容器内就能访问宿主机上的某个目录。一旦 Pod 离开了这个宿主机,hostPath
中的数据还会继续存在于宿主机,但数据不会跟随 Pod 迁移到另一个宿主机。
awsElasticBlockStore
类型的 Volume,用来将 AWS EBS 磁盘挂载到 Pod 的文件系统。由于 EBS 是云磁盘,当 Pod 被调度到另一个宿主机的之后,可以保证数据卷仍然可用。
ConfigMaps
在实践中,应用程序的配置文件通常不会放在镜像中,这有助于让镜像变得可复用。Kubernetes 提供了 ConfigMaps,用来为容器中的程序提供配置信息,包括:文件配置、环境变量以及命令行参数。
假设有这样一个需求:Nginx 运行在容器中,我们需要修改 Nginx 的配置文件/etc/nginx/nginx.conf
,并且在/etc/nginx/sites-enabled
目录下增加一个域名的配置mydomain.conf
。
首先,在本地目录config
下创建配置文件,nginx.conf
和mydomain.conf
,内容如下:
接着,使用kubectl
创建一个名为nginx-config
的 ConfigMap:
创建 ConfigMap 之后,可以查看它的内容:
从上面的内容可以发现,ConfigMap 的data
字段包含了多个键值对(key/value),其中 key 是文件名,而 value 则是文件的内容。
最后要做的就是修改 Pod 的配置:
- 在 Pod 里面创建一个名为
config-volume
的 Volume(实际上这个 Volume 包含了nginx.conf
和mydomain.conf
)。 - 分别将这两个文件挂载到容器文件系统的不同路径。
|
|
运行这个 Pod 并进入容器,可以发现配置文件挂载进去了:
ReplicaSets
对于无状态的程序来说,有时候我们想要运行程序的多个副本,以达到这些目的:
- 提供冗余,在一定程序上提升程序的可用性。
- 提升程序处理请求的能力。
- 在必要时候,根据系统负载自动缩容或扩容。
Kubernetes 提供了 ReplicaSets(副本集)用来解决这些问题。下面的例子是一个 ReplicaSet 的配置,其中包含两个 Nginx Pod:
接下来创建这个 ReplicaSet:
可以查看 ReplicaSet 的状态,可以看到有两个 Pod 在运行了:
如果想要改变 ReplicaSet 中 Pod 的数量要怎么做呢?可以修改 yaml 文件中 replicas 的值:
更新 ReplicaSet,让配置生效:
可以使用kubectl delete
删除一个 ReplicaSet,删除之后,由这个 ReplicaSet 管理的 Pod 也会被一并删除: