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配置您的应用程序

集群的信息

在容器创建时,集群中所有的 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处理程序

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"]