K8s-容器

镜像

在 Kubernetes 的 Pod 中使用容器镜像之前,您必须将其推送到一个镜像仓库(或者使用仓库中已经有的容器镜像)。在 Kubernetes 的 Pod 定义中定义容器时,必须指定容器所使用的镜像,容器中的 image 字段支持与 docker 命令一样的语法,包括私有镜像仓库和标签。

例如:my-registry.example.com:5000/example/web-example:v1.0.1 由如下几个部分组成:

my-registry.example.com:5000/example/web-example:v1.0.1

  • my-registry.example.com:registry 地址
  • 5000:registry 端口
  • example:repository 名字
  • web-example:image 名字
  • v1.0.1:image 标签

如果您使用 hub.dokcer.com Registry 中的镜像,可以省略 registry 地址和 registry 端口。例如:nginx:latesteipwork/kuboard

更新镜像

更新策略

Kubernetes中,默认的镜像抓取策略是 IfNotPresent,使用此策略,kubelet在发现本机有镜像的情况下,不会向镜像仓库抓取镜像

如果期望每次启动 Pod 时,都强制从镜像仓库抓取镜像

  • 设置 container 中的 imagePullPolicyAlways
  • 省略 imagePullPolicy 字段,并使用 :latest tag 的镜像
  • 省略 imagePullPolicy 字段和镜像的 tag
  • 激活 AlwaysPullImages (opens new window)管理控制器

更新过程:

  • imagePullPolicy: IfNotPresent 仅在节点上没有该镜像时,从镜像仓库抓取

  • imagePullPolicy: Always 每次启动 Pod 时,从镜像仓库抓取

  • imagePullPolicy 未填写,镜像 tag 为 :latest 或者未填写,则同 Always 每次启动 Pod 时,从镜像仓库抓取

  • imagePullPolicy 未填写,镜像 tag 已填写但不是 :latest,则同 IfNotPresent 仅在节点上没有该镜像时,从镜像仓库抓取

  • imagePullPolicy: Never,Kubernetes 假设本地存在该镜像,并且不会尝试从镜像仓库抓取镜像

使用私有仓库中的docker镜像

因为企业以下需求通常会有自建仓库的需求:

  • 限制 docker 镜像的分发范围,例如:只允许在内网分发,或者只允许被授权的用户获取 docker 镜像
  • 提高推送 docker 镜像以及抓取 docker 镜像时的网络传输速度

一个镜像仓库需要以下的要求:

⚠️需要支持HTTPS

参数名称 参数值 备注
registry地址 my-registry.example.com 推荐使用域名,也可以是 ip 地址
registry端口 5000 必须支持 HTTPS
registry用户名 myusername
registry密码 mypassowrd
repository名字 example
image名字 web-example
image标签 v1.0.1

Harbor的部署

容器的环境变量

容器的信息

在容器中执行 hostname 命令或者在libc 中执行 gethostname (opens new window)函调用,获得的是容器所在 Pod 的名字。

Pod 的名字,以及 Pod 所在名称空间可以通过 downward API (opens new window)注入到容器的环境变量里。

用户也可以为容器自定义环境变量,请参考 使用ConfigMap配置您的应用程序

集群的信息

1
2
3
在容器创建时,集群中所有的 Service 的连接信息将以环境变量的形式注入到容器中。例如,已创建了一个名为 Foo 的 Service,此时再创建任何容器时,该容器将包含如下环境变量:
FOO_SERVICE_HOST=<Service的ClusterIP>
FOO_SERVICE_PORT=<Service的端口>

Runtime Class

可以通过 RuntimeClass,使不同的 Pod 使用不同的容器引擎,以在性能和安全之间取得平衡。例如,如果某些工作负载需要非常高的信息安全保证,您可能想要将其 Pod 运行在那种使用硬件虚拟化的容器引擎上;同时,将其他的 Pod 运行在另外一种容器引擎上,以获得更高的性能。K8s-Runtime Class

容器生命周期

  • PostStart

    此钩子函数在容器创建后将立刻执行。但是,并不能保证该钩子函数在容器的 ENTRYPOINT 之前执行。该钩子函数没有输入参数。

  • PreStop

    此钩子函数在容器被 terminate(终止)之前执行,例如:

    • 通过接口调用删除容器所在 Pod
    • 某些管理事件的发生:健康检查失败、资源紧缺等

    如果容器已经被关闭或者进入了 completed 状态,preStop 钩子函数的调用将失败。该函数的执行是同步的,即,kubernetes 将在该函数完成执行之后才删除容器。该钩子函数没有输入参数

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 钩子函数,以保存当时的计算状态和数据

定义postStart和preStop处理程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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"]