十一. Kubernetes 容器 container 设置详解
可以理解为通过初始化容器做准备工作,当准备工作完成以后,再去部署实际的应用容器。
·
目录
一. 基础解释
- pod是k8s的基本单位,用k8s部署的应用运行在container容器中, 容器运行在pod中,pod又运行在k8s的节点上,一个pod内部可以启动多个container容器,所以pod又称为容器组(pod内部运行的docker容器,使用docker容器启动服务时一个容器只能启动一个服务,使用k8s后,pod是k8s的基本单位一个pod中可以运行多个容器,那么一个pod就可以运行多个服务)
- 查看yaml中如何这是容器
- 容器是设置到pod上的,我们查看pod的yaml即可,在yaml中存在"spec.containers"字段,是用来设置容器的
- 可以执行"kubectl explain pod.spec.containers"命令,解释container下的所有字段
- 一个pod yaml中的容器有哪些设置字段,示例:
kind: Pod
apiversion: v1
metadata:
name: my-container-test
namespace: hello
labels:
aa: bb
bb: dd
spec:
imagePullSecrets: #设置镜像的下载秘钥(例如使用私库下载镜像时,访问私库需要秘钥,就在该位置设置,选填默认共有仓库地址)
-name: key-01 #秘钥名
-name: key-02
containers: #容器相关设置
- image: nginx #指定镜像名称(支持docker镜像指定规则)
name: my-nginx #自定义容器名称
imagePullPolicy: Always #镜像下载策略:Always总是下载(默认), Never从不下载, ifNotPresent本机不存在下载
env: #设置当前容器的环境变量
- name: aaa #容器内环境变量的key
value: bbb #对应这个key的值
- name: ccc #容器内环境变量的key
valueFrom: #通过该属性指定那哪个位置的数据作为此处的环境变量
secretKeyRef: #指定获取哪个Secret配置为环境变量
name: secret-name #使用的secret名
key: username #使用secret中指定哪个数据(secret中的value是base64编码后的,使用时会自动解码)
configMapKeyRef: #指定获取哪个ConfigMap配置为环境变量
fieldRef: #指定获取哪个属性为环境变量
resourceFieldRef: #指定获取xxx为环境变量
yaml设置容器拉取镜像注意点
1. containers.image 镜像
- 在通过image指定镜像时,k8s中支持docker镜像指定规则
- 并且如果使用hub.dokcer.com Registry中的镜像,可以省略registry地址和registry端口,例如:
spec:
containers: #容器相关设置
- image: nginx:latest
2. containers.imagePullPolicy 镜像拉取策略
- 通过imagePullPolicy指定镜像下载策略,k8s中提供了3中策略,
- Always总是联网下载(默认)
- Never从不下载
- ifNotPresent本机不存在时下载
3. 配置拉取私库镜像(spec下的imagePullSecrets)
- 为什么会有这个问题: 在实际开发中k8s是通过我们私库拉取镜像的假设私库存访问时在秘钥怎么办等等,下图示例与解释
- 第一步执行"kubectl apply -f 名称.yaml" 对指定yaml命令应用生效,实际是一个部署pod的yaml
- 第二步执行"kubectl get pod -n hello",指定查询hello命名空间下的所有pod信息
- 发现my-container-test这个pod状态为"ImagePullBackOff" 拉取镜像失败
- 第三步执行"kubectl describe pod my-container-test -n hello": 描述hello命名空间下my-container-test该pod的详细信息获取异常详情
- 进入描述详情后发现是下载镜像失败
- 如何拉取私库镜像: yaml中配置"imagePullSecrets"注意该标签是"spec"下的,在imagePullSecrets指定秘钥名
- 又引出一个问题这些秘钥是哪来的? 需要我们执行命令创建秘钥,在创建秘钥是指定私库的地址,访问用户名密码,然后使用"imagePullSecrets"设置对应的秘钥名(注意创建的秘钥名要与使用该秘钥名的资源在同一命名空间下)
//"-n hello": 指定当前创建的秘钥名所在命名空间为"hello"下
//"docker-registry my-aliyun": 秘钥名为"my-aliyun"
//docker-server: 私库地址(此处设置的值与containers.image指定的镜像registery地址相同,当配置多个私库时就是通过这两个位置匹配的)
//docker-username: 私库用户名
//docker-password: 私库密码
kubectl create secret -n hello docker-registry my-aliyun\
--docker-server=registry.cn-hangzhou.aliyuncs.com\
--docker-username=forsumlove\
--docker-password=lfy11223344
- 或者上方的命令添加/“–dry-run=client -o yaml”: 尝试创建(实际并不会真是创建出来)输出yaml,然后复制这个yaml使用yaml的方式创建秘钥名,应用这个yaml即可
- 获取k8s中秘钥资源"kubectl get secret -n 命名空间"
- 在编写pod的yaml时,通过设置使用指定秘钥,通过这个秘钥名中的信息连接私库下载镜像
kind: Pod
apiversion: v1
metadata:
name: my-container-test
namespace: hello
labels:
aa: bb
bb: dd
spec:
imagePullSecrets: #设置镜像的下载秘钥(例如使用私库下载镜像时,访问私库需要秘钥,就在该位置设置)
-name: my-aliyun #设置指定秘钥名
containers: #容器相关设置
- image: registry-ch-hangzhou.aliyuncs.com/aaa/nginx:v1.-0
name: my-nginx #自定义容器名称
imagePullPolicy: Always
- 一个pod中的多个container可以连接不同的库
4. 一个pod中可以设置多个容器
- 一个pod配置多个容器示例:
kind: Pod
apiversion: v1
metadata:
name: my-container-test
namespace: hello
labels:
aa: bb
bb: dd
spec:
imagePullSecrets: #设置镜像的下载秘钥(例如使用私库下载镜像时,访问私库需要秘钥,就在该位置设置)
-name: my-aliyun #设置指定秘钥名
containers: #容器相关设置
- image: registry-ch-hangzhou.aliyuncs.com/aaa/nginx:v1.-0
name: my-nginx #自定义容器名称
imagePullPolicy: Always
- image: nignx #默认从docker hub共有参考获取
name: my-test
imagePullPolicy: Always
- 上面解释了如何配置私库, 但是一个pod中多个容器使用的私库不同如何设置,
- 连接私库需要创建秘钥名, 在秘钥名中指定私库的连接地址,用户名,密码
- 通过spec.imagePullSecrets配置需要用到的秘钥名
- 当配置多个秘钥名时,实际是通过"containers.image"与秘钥名中的地址进行匹配的
- "containers.image"支持docker镜像指定规则,如果没有registery则使用doucker hub公共库下载,如果"containers.image"中设置了registry地址,则通过这个地址与秘钥名中的"docker-server"配置的地址匹配,使用对应的私库拉取镜像
二. 部署mysql演示containers.env环境变量
- 部署mysql pod yaml示例,在"containers.env"中设置了部署mysql需要的环境变量,evn中是一个数组map,通过name属性指定key,value属性指定对应key的vaule值,在部署服务时通常情况下key是固定的可以参考部署文档,也可以自定义
kind: Pod
apiversion: v1
metadata:
name: my-mysql
namespace: hello
spec:
containers: #容器相关设置
- image: mysql:5.7.34
name: mysql
imagePullPolicy: Always
env: #设置环境变量
- name: MYSQL_ROOT_PASSWORD #参考docker hub部署mysql环境变量相关
value: "1234" #密码值
- name: MYSQL_DATABASE #指定部署的mysql的库
value: demo-test
- env 环境变量可以设置指定的kv键值对,也可以通过valueFrom指定环境变量通过配置获取,例如通过configMapKeyRef, 或 secretKeyRef,再或者通过fieldRef属性,或通过resourceFieldRef等获取参考配置相关
spec:
containers:
- name: mycontainer
image: redis
resources: #限制当前容器使用资源
limit:
cpu: 10m
requests:
cpu: 5m
env: #设置环境变量
- name: key1
value: 111
- name: key2
valueFrom:
fieldRef: #使用某个属于,也就是获取当前yaml中定义的其它字段
fieldPath: metadata.name
- name: key3
resourceFieldRef: #上面设置里"resources"资源信息,此处可以获取资源信息中设置的数据
containerName: 指定容器名 #指定容器
resource: limit.cpu #获取资源中哪个位置的数据
- name: SECRET_USERNAME #指定环境变量中的key
valueFrom: #设置对应key的value
secretKeyRef: #指定value来自secret
name: mysecret #指定使用的secret的名字
key: username #指定使用secret中哪个key的value
- name: SECRET_USERNAME #指定环境变量中的key
valueFrom: #设置对应key的value
configMapKeyRef: #指定value来自config配置
name: mysecret #指定使用的config的名字
key: username #指定使用config中哪个key的value
三. containers.command 启动命令
- 通过command命令可以指定镜像的启动命令,containers中是一个字符串数组
kind: Pod
apiversion: v1
metadata:
name: my-nginx
namespace: hello
spec:
containers: #容器相关设置
- image: nginx
name: nginx-test
command: #指定镜像启动命令,启动容器时会执行此处编写的启动命令,并且此处的启动命令会覆盖默认的
- /bin/sh
- -c
- "echo $(msg));sleep 3600;"
env: #设置环境变量
- name: msg
value: "hello msg"
- 镜像启动存在默认的启动命令,当使用command自定义后,会覆盖默认的,如下图
- 下图中存在"镜像Entrypint"m默认启动命令, "镜像Cmd"默认启动参数,"容器command"指定的启动命令, "容器args"设置的容器参数
- 启动镜像时存在"镜像Entrypoint"默认启动命令与"镜像Cmd"默认的启动参数,默认情况下会通过这些命令启动一个镜像,例如"[ep-1 foo bar]"
- 如果设置了"容器command"命令与"容器args"参数,那么启动镜像时实际会执行command中的[ep-2],并且command中可以获取设置容器的args参数填充执行命令,此时会覆盖默认的执行命令参数
- 启动命令的应用场景,例如部署redis集群,主节点启动命令与从节点启动命令不同,或者自定义启动命令修改服务器属性等等
四. containers.lifecycle 容器的生命周期钩子
- 思考一个场景, pod中启动容器, 想在容器的创建成功后或关闭前进行指定操作该如何处理
- k8s为容器提供了两个hook钩子函数
- PostStart: 在容器启动后执行,该函数没有输入参数(并不能确定在容器启动前执行,可能容器还没运行成功)
- PreStop: 在容器被terminate(终止)之前执行,该函数没有输入参数,例如删除pod时要先结束pod中运行的容器,该函数的执行是同步的,k8s会在该函数完成执行之后才删除容器,如果容器已经被关闭或者进入了completed状态,preStop钩子函数的调用将失败
- 钩子中可以执行的三种方式
- exec: 通过钩子程序执行命令
- httpGet: 通过钩子发送http get请求
- tcpSocket: 容器创建之后连接tcp端口进行指定操作
kind: Pod
apiversion: v1
metadata:
name: my-nginx
namespace: hello
spec:
containers: #容器相关设置
- image: nginx
name: nginx-test
lifecycle:
postStart: #容器创建钩子
httpGet:
host: "127.0.0.1"
path: "/testeee"
port: 8080
httpHeaders: 请求头数组
scheme: HTTP
preStop: #容器关闭前钩子
exec:
command: ["/bin/sh","-c","echoworld;"]
env: #设置环境变量
- name: msg
value: "hello msg"
- 注意点:
- postStart事件在容器的EntryPoint之前执行,相对于容器中的进程来说是异步的(同时执行),然而Kubernetes在管理容器时将一直等到postStart事件处理程序结束之后才会将容器的状态标记为Running
- preStop事件处理程序是同步的在决定关闭容器时立刻发送preStop事件,将一直等到preStop事件处理程序结束或者Pod的–grace-period超时才删除容器
五. 探针
- 在容器的containers中存在三个属性: startupProbe启动探针, livenessProbe存活探针, readinessProbe就绪探针
- 探针支持的三种设置方法(与钩子相同)
- exec: 通过钩子程序执行命令
- httpGet: 通过钩子发送http get请求
- tcpSocket: 容器创建之后连接tcp端口进行指定操作
kind: Pod
apiversion: v1
metadata:
name: my-nginx
namespace: hello
spec:
containers: #容器相关设置
- image: nginx
name: nginx-test
startupProbe: #启动探针
exec:
httpGet:
tcpSXocket:
livenessProbe: #存活探针
readinessProbe: #就绪探针
- 探针是用来做什么的:
- startupProbe启动探针: 通过该探针来查看当前容器是否启动成功
- livenessProbe存活探针: 通过该探针判断当前容器是否存活,基于该探针如果探测到容器不再存活,则会重新拉起
- readinessProbe就绪探针: 通过该探针通知kubelet当前容器是否就绪,能否对外提供服务,以调用服务负载均衡为例,当接收到请求后如果通过该探针探测到某个服务节点不可用,则不会将该节点加入负载均衡
- 根据以上对探针的解释,可以理解到通过探针可以做到健康检查,0宕机
- 具体参考十二. Kubernetes Pod 与 探针
六. containers.resources 资源限制
- 限制containers容器占用内存, cup等资源设置,已下方示例为准在reesources下设置资源限制
kind: Pod
apiversion: v1
metadata:
name: my-nginx
namespace: hello
spec:
containers: #容器相关设置
- image: nginx
name: nginx-test
resources:
limits: #设置最大大小(对比java服务时等同于-Xmx)
memory: "200Mi"
cpu: "700m"
requests: #设置启动默认大小(对比java服务时等同于 -Xms)
memory: "200Mi"
cpu: "700m"
七. 与容器不同类型解释
- 上面都是在"spec.containers"中设置的容器,实际k8s中container容器分三种
- initContainers: 初始化容器,pod在启动containers下指定的实际容器前,先要运行完成的容器
- containers: 应用容器(实际部署的应用容器)
- ephemeralContainers: 临时容器
spec.initContainers 初始化类型容器
- 初始化容器与实际的应用容器设置方式大致相同,不同点是,实际部署的应用容器要一直正常运行,而初始化容器需要有终结,在通过pod部署的容器应用中存在初始化类型容器时,该初始化类型容器一般不要用一直启动的,k8s中当初始化容器部署运行完成拿到运行完成的终结结果后,才会开始部署实际的应用容器
可以理解为通过初始化容器做准备工作,当准备工作完成以后,再去部署实际的应用容器
ephemeralContainers 临时类型容器
- 通常情况下,临时容器是用来进行问题定位使用的,有些容器是一下基础镜像,如果线上出现问题不好定位,因为pod中多个容器间资源共享,临时容器提供了debug的功能,所以使用临时容器来充当线上容器进行问题定位使用,当问题定位完成后,只需要退出该临时容器即可
- 以java应用举例: 假设应用出现out of memory异常,我们通过dump获取堆栈内存快照获使用jstack分析内存使用情况进行排错等等,会发现一个问题,基础镜像无法使用jre,需要使用jdk, jdk又特别大, 那么就可以使用jdk作为临时容器去排错
- 注意使用临时容器要先开启"特性门控"
//1. 临时容器需要开启特性门控,所有组件,api-server、kubelet、scheduler、controller-manager都得配置
--feature-gates="EphemeralContainers=true"
- 编写一个声明临时容器需要的json文件
{
"apiVersion":"v1",
"kind":"EphemeralContainers",
"metadata":{
"name":"my-nginx666"//指定Pod的名字(也就是当前声明的临时容器要进入哪个pod)
},
"ephemeralContainers":[{
"command":["sh"],
"image":"busybox", //jre的需要jdk来调试
"imagePullPolicy":"IfNotPresent",
"name":"debugger",
"stdin":true,
"tty":true,
"terminationMessagePolicy":"File"
]}
}
- 应用这个临时容器即可,该命令执行完毕后,会进入到临时容器指定的目录下,根据上方声明临时容器的json编码看出,当前会进入到"ephemeralContainers.command"指定的目录,此时就可以执行debug相关命令进行问题排除
//解释: replace替换 my-nginx666【pod 名】pod中的容器,替换为通过fec.json这个文件创建的容器
kubectl replace--raw /api/v1/namespaces/default/pods/my-nginx666【pod 名】/ephemeralcontainers -fec.json
更多推荐
已为社区贡献2条内容
所有评论(0)