0
点赞
收藏
分享

微信扫一扫

k8s学习-容器基础

容器镜像

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

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

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

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


更新镜像

Kubernetes中,默认的镜像抓取策略是 IfNotPresent,使用此策略,kubelet在发现本机有镜像的情况下,不会向镜像仓库抓取镜像。如果您期望每次启动 Pod 时,都强制从镜像仓库抓取镜像,可以尝试如下方式:

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

容器的环境变量

Kubernetes为容器提供了一系列重要的资源:

  • 由镜像、一个或多个数据卷合并组成的文件系统
  • 容器自身的信息
  • 集群中其他重要对象的信息

​​容器的信息

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

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

用户也可以为容器自定义环境变量。

集群的信息

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

FOO_SERVICE_HOST=<Service的ClusterIP>
FOO_SERVICE_PORT=<Service的端口>

Runtime Class

使用 RuntimeClass 这一特性可以为容器选择运行时的容器引擎。

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

也可以通过 RuntimeClass 配置,使不同的 Pod 使用相同的容器引擎和不同的容器引擎配置参数

节点上配置cri

需通过RuntimeClass进行配置,是依赖于 Container Runtime Interface(CRI)的具体实现的。

配置 CRI 时,请留意其 handler 名称(该名称是有 字符/数字 和 - 组成的字符串),RuntimeClass中将引用该名称。

  • dockershim
    Kubernetes 内建的 dockershim CRI 不支持 RuntimeClass
  • containerd

通过 containerd 的配置文件 /etc/containerd/config.toml 配置其 Runtime handler

  • cri-o

通过 cri-o 的配置文件 /etc/crio/crio.conf 配置 Runtime handler。

RuntimeClass 目前只有两个主要的字段:

  • RuntimeClass name(metadata.name)
  • handler (handler)
apiVersion: node.k8s.io/v1beta1
kind: RuntimeClass
metadata:
name: myclass # RuntimeClass 没有名称空间
handler: myconfiguration # 对应 CRI 配置的 handler 名称

使用

为集群完成 RuntimeClass 的配置后,使用的时候会非常简单。在 Pod 的定义中指定 runtimeClassName 即可

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
runtimeClassName: myclass
# ...

kubelet 将依据这个字段使用指定的 RuntimeClass 来运行该 Pod。如果指定的 RuntimeClass 不存在,或者 CRI 不能运行对应的 handler 配置,则 Pod 将进入 Failed​ 这个终止 阶段。此时可通过 Pod 中的 Event(事件)来查看具体的出错信息。

如果 Pod 中未指定 runtimeClassName,kubelet 将使用默认的 RuntimeHandler 运行 Pod,其效果等价于 RuntimeClass 这个特性被禁用的情况。

容器的生命周期

Kubernetes 中,也为容器提供了对应的生命周期钩子函数,使得容器可以获知其所在运行环境对其进行管理的生命周期事件,以便容器可以响应该事件,并执行对应的代码

容器钩子

Kubernetes中为容器提供了两个 hook(钩子函数):

  • 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触发的保证

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) 以查看这些事件

容器的生命周期事件处理

Kubernetes 中支持容器的 postStart 和 preStop 事件,本文阐述了如何向容器添加生命周期事件处理程序(handler)。

  • postStart 容器启动时,Kubernetes 立刻发送 postStart 事件,但不确保对应的 handler 是否能在容器的EntryPoint 之前执行
  • preStop 容器停止前,Kubernetes 发送 preStop 事件

定义postStart和preStop处理程序

创建一个包含单一容器的 Pod,并为该容器关联 postStart 和 preStop 处理程序(handler)。Pod 的yaml文件定义如下:

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"]
  • postStart 命令向usr/share/message 文件写入了一行文字
  • preStop 命令优雅地关闭了 nginx
#创建pod
kubectl apply -f https://kuboard.cn/statics/learning/container/lifecycle.yaml
#验证pod中容器已经运行
kubectl get pod lifecycle-demo
#进入荣光一的命令行终端
kubectl exec -it lifecycle-demo -- /bin/bash

Kubernetes 在容器启动后立刻发送 postStart 事件,但是并不能确保 postStart 事件处理程序在容器的 EntryPoint 之前执行。postStart 事件处理程序相对于容器中的进程来说是异步的(同时执行),然而,Kubernetes 在管理容器时,将一直等到 postStart 事件处理程序结束之后,才会将容器的状态标记为 Running。

Kubernetes 在决定关闭容器时,立刻发送 preStop 事件,并且,将一直等到 preStop 事件处理程序结束或者 Pod 的 --grace-period 超时,才删除容器

举报

相关推荐

0 条评论