十一. Kubernetes 容器 container 设置详解

一. 基础解释

  1. pod是k8s的基本单位,用k8s部署的应用运行在container容器中,容器运行在pod中,pod又运行在k8s的节点上,一个pod内部可以启动多个container容器,所以pod又称为容器组(pod内部运行的docker容器,使用docker容器启动服务时一个容器只能启动一个服务,使用k8s后,pod是k8s的基本单位一个pod中可以运行多个容器,那么一个pod就可以运行多个服务)
  2. 查看yaml中如何这是容器
  1. 容器是设置到pod上的,我们查看pod的yaml即可,在yaml中存在"spec.containers"字段,是用来设置容器的
  2. 可以执行"kubectl explain pod.spec.containers"命令,解释container下的所有字段
  1. 一个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 镜像

  1. 在通过image指定镜像时,k8s中支持docker镜像指定规则

    在这里插入图片描述

  2. 并且如果使用hub.dokcer.com Registry中的镜像,可以省略registry地址和registry端口,例如:
spec: 
	containers: #容器相关设置
		- image: nginx:latest

2. containers.imagePullPolicy 镜像拉取策略

  1. 通过imagePullPolicy指定镜像下载策略,k8s中提供了3中策略,
  1. Always总是联网下载(默认)
  2. Never从不下载
  3. ifNotPresent本机不存在时下载

3. 配置拉取私库镜像(spec下的imagePullSecrets)

  1. 为什么会有这个问题: 在实际开发中k8s是通过我们私库拉取镜像的假设私库存访问时在秘钥怎么办等等,下图示例与解释
  1. 第一步执行"kubectl apply -f 名称.yaml" 对指定yaml命令应用生效,实际是一个部署pod的yaml
  2. 第二步执行"kubectl get pod -n hello",指定查询hello命名空间下的所有pod信息
  3. 发现my-container-test这个pod状态为"ImagePullBackOff" 拉取镜像失败
  4. 第三步执行"kubectl describe pod my-container-test -n hello": 描述hello命名空间下my-container-test该pod的详细信息获取异常详情
  5. 进入描述详情后发现是下载镜像失败

    在这里插入图片描述


    在这里插入图片描述

  1. 如何拉取私库镜像: yaml中配置"imagePullSecrets"注意该标签是"spec"下的,在imagePullSecrets指定秘钥名
  2. 又引出一个问题这些秘钥是哪来的? 需要我们执行命令创建秘钥,在创建秘钥是指定私库的地址,访问用户名密码,然后使用"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

在这里插入图片描述

  1. 或者上方的命令添加/“–dry-run=client -o yaml”: 尝试创建(实际并不会真是创建出来)输出yaml,然后复制这个yaml使用yaml的方式创建秘钥名,应用这个yaml即可

    在这里插入图片描述

  2. 获取k8s中秘钥资源"kubectl get secret -n 命名空间"

    在这里插入图片描述

  3. 在编写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 
  1. 一个pod中的多个container可以连接不同的库

4. 一个pod中可以设置多个容器

  1. 一个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
  1. 上面解释了如何配置私库,但是一个pod中多个容器使用的私库不同如何设置,
  1. 连接私库需要创建秘钥名,在秘钥名中指定私库的连接地址,用户名,密码
  2. 通过spec.imagePullSecrets配置需要用到的秘钥名
  3. 当配置多个秘钥名时,实际是通过"containers.image"与秘钥名中的地址进行匹配的
  4. "containers.image"支持docker镜像指定规则,如果没有registery则使用doucker hub公共库下载,如果"containers.image"中设置了registry地址,则通过这个地址与秘钥名中的"docker-server"配置的地址匹配,使用对应的私库拉取镜像

二. 部署mysql演示containers.env环境变量

  1. 部署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
  1. 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
  1. env环境变量官方解释

三. containers.command 启动命令

  1. 通过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"
  1. 镜像启动存在默认的启动命令,当使用command自定义后,会覆盖默认的,如下图
  1. 下图中存在"镜像Entrypint"m默认启动命令,"镜像Cmd"默认启动参数,"容器command"指定的启动命令,"容器args"设置的容器参数
  2. 启动镜像时存在"镜像Entrypoint"默认启动命令与"镜像Cmd"默认的启动参数,默认情况下会通过这些命令启动一个镜像,例如"[ep-1 foo bar]"
  3. 如果设置了"容器command"命令与"容器args"参数,那么启动镜像时实际会执行command中的[ep-2],并且command中可以获取设置容器的args参数填充执行命令,此时会覆盖默认的执行命令参数

    在这里插入图片描述

  1. 启动命令的应用场景,例如部署redis集群,主节点启动命令与从节点启动命令不同,或者自定义启动命令修改服务器属性等等

四. containers.lifecycle 容器的生命周期钩子

  1. 思考一个场景,pod中启动容器,想在容器的创建成功后或关闭前进行指定操作该如何处理
  2. k8s为容器提供了两个hook钩子函数
  1. PostStart: 在容器启动后执行,该函数没有输入参数(并不能确定在容器启动前执行,可能容器还没运行成功)
  2. PreStop: 在容器被terminate(终止)之前执行,该函数没有输入参数,例如删除pod时要先结束pod中运行的容器,该函数的执行是同步的,k8s会在该函数完成执行之后才删除容器,如果容器已经被关闭或者进入了completed状态,preStop钩子函数的调用将失败
  1. 钩子中可以执行的三种方式
  1. exec: 通过钩子程序执行命令
  2. httpGet: 通过钩子发送http get请求
  3. 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"
  1. 注意点:
  1. postStart事件在容器的EntryPoint之前执行,相对于容器中的进程来说是异步的(同时执行),然而Kubernetes在管理容器时将一直等到postStart事件处理程序结束之后才会将容器的状态标记为Running
  2. preStop事件处理程序是同步的在决定关闭容器时立刻发送preStop事件,将一直等到preStop事件处理程序结束或者Pod的–grace-period超时才删除容器

五. 探针

  1. 在容器的containers中存在三个属性: startupProbe启动探针,livenessProbe存活探针,readinessProbe就绪探针
  2. 探针支持的三种设置方法(与钩子相同)
  1. exec: 通过钩子程序执行命令
  2. httpGet: 通过钩子发送http get请求
  3. 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: #就绪探针 
  1. 探针是用来做什么的:
  1. startupProbe启动探针: 通过该探针来查看当前容器是否启动成功
  2. livenessProbe存活探针: 通过该探针判断当前容器是否存活,基于该探针如果探测到容器不再存活,则会重新拉起
  3. readinessProbe就绪探针: 通过该探针通知kubelet当前容器是否就绪,能否对外提供服务,以调用服务负载均衡为例,当接收到请求后如果通过该探针探测到某个服务节点不可用,则不会将该节点加入负载均衡
  1. 根据以上对探针的解释,可以理解到通过探针可以做到健康检查,0宕机
  2. 具体参考十二. Kubernetes Pod 与 探针

六. containers.resources 资源限制

  1. 限制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"

七. 与容器不同类型解释

  1. 上面都是在"spec.containers"中设置的容器,实际k8s中container容器分三种
  1. initContainers: 初始化容器,pod在启动containers下指定的实际容器前,先要运行完成的容器
  2. containers: 应用容器(实际部署的应用容器)
  3. ephemeralContainers: 临时容器

spec.initContainers 初始化类型容器

  1. 初始化容器与实际的应用容器设置方式大致相同,不同点是,实际部署的应用容器要一直正常运行,而初始化容器需要有终结,在通过pod部署的容器应用中存在初始化类型容器时,该初始化类型容器一般不要用一直启动的,k8s中当初始化容器部署运行完成拿到运行完成的终结结果后,才会开始部署实际的应用容器

可以理解为通过初始化容器做准备工作,当准备工作完成以后,再去部署实际的应用容器

在这里插入图片描述

ephemeralContainers 临时类型容器

  1. 通常情况下,临时容器是用来进行问题定位使用的,有些容器是一下基础镜像,如果线上出现问题不好定位,因为pod中多个容器间资源共享,临时容器提供了debug的功能,所以使用临时容器来充当线上容器进行问题定位使用,当问题定位完成后,只需要退出该临时容器即可
  2. 以java应用举例: 假设应用出现out of memory异常,我们通过dump获取堆栈内存快照获使用jstack分析内存使用情况进行排错等等,会发现一个问题,基础镜像无法使用jre,需要使用jdk,jdk又特别大,那么就可以使用jdk作为临时容器去排错
  3. 注意使用临时容器要先开启"特性门控"
//1. 临时容器需要开启特性门控,所有组件,api-server、kubelet、scheduler、controller-manager都得配置 
--feature-gates="EphemeralContainers=true" 
  1. 编写一个声明临时容器需要的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"
    	]}
}
  1. 应用这个临时容器即可,该命令执行完毕后,会进入到临时容器指定的目录下,根据上方声明临时容器的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

相关文章

文章浏览阅读942次。kube-controller-manager 和 kubelet 是...
文章浏览阅读3.8k次。上篇文章详细介绍了弹性云混部的落地历...
文章浏览阅读897次。对于cpu来说,这种分配方式并不会有太大...
文章浏览阅读796次,点赞17次,收藏15次。只要在Service定义...
文章浏览阅读763次。但是此时如果配置成 NONE, 租户创建成功...
文章浏览阅读2.7k次,点赞2次,收藏13次。公司使用的是交老的...