一、containerd介绍

1.解释

containerd: 底层容器运行时(真正负责创建、启停容器的底层程序)。
容器运行时是实现容器生命周期管理、负责底层容器隔离与启停的底层组件统称.
containerd 是主流容器运行时实现产品之一。
属于【高级容器运行时】,放在整个容器栈底层,所以大家口头叫它"底层容器运行时".

2.containerd与docker

‌Docker 和 containerd 是包含与依赖关系,containerd 是 Docker 的底层核心组件,负责实际运行容器.
docker 是封装了containerd,额外增加了Dockerfile 构建、docker-compose、私有仓库、网络插件等上层工具。

3.containerd与K8S

在K8S 1.23版本以及以前是需要安装docker的。K8S的调用流程是这样:

K8S kubelet --> dockershim --> dockerd --> containerd --> runc

这里注意的是:
docker本身不是不兼容K8S标准的 CRI接口的,早期K8S是必须通过dockershim进行协议转换,中转调用docker

4.CRI(Container Runtime Interface)

CRI是K8s 官方定义的标准 gRPC 接口规范,目的是:【解耦 kubelet 和底层容器运行时】
K8S只认标准的CRI(Container Runtime Interface),K8S不绑定特定的CRI。
K8S中的kubelet(K8S代理节点)是通过CRI接口和底层进行通信的,
K8S支持两类运行时:
​ 第一种就是containerd(原生CRI,直接通信,无中间层,现在主流)
​ 第二种就是docker(需老旧 dockershim 转换,1.24+ K8s 彻底移除 dockershim,不再原生支持 Docker)

5.K8S现在标准架构

K8s kubelet → CRI 接口 → containerd → runc → Linux内核

1.kubelet 内置了CRI Client(gRPC 客户端),专门用来发送容器操作指令
2.containerd 启动 cri 插件,生成一个 gRPC 服务端,监听在 (/run/containerd/containerd.sock),等待接受请求。
3.kubelet 通过grpc客户端 发送标准 CRI 请求给 containerd
4.containerd 收到 CRI 请求后,转调用 OCI 工具链 runc 创建容器

注意的是:containerd.sock是containerd主进程创建的,由它内部的 cri插件绑定监听。
socket的作用是 传输数据,是电脑上一条无形的本地管道。不管是 kubelet 发消息,还是 containerd 回消息,全部走这个通道传递。

所以在安装K8S的时候所有服务器都需要统一安装containerd

yum install -y containerd.io

二、YAML文件

1.基本规范(硬性规范)

1.缩进只能用空格,禁止使用tab键,标准 2 空格缩进;缩进代表层级关系
2.区分大小写
3.# 为注释
4.短横线 + 空格 表示是数组元素

2.数据类型

2.1 字符串

字符串默认不用引号引起来. 单引号:不转义特殊字符。 双引号:识别转移字符 比如:\t \n

2.2 数字

整数、浮点数直接写

2.3 布尔型

true / false(小写)

2.4 空值

null ,~ ,不写也可以

2.5 对象

缩进表示层级,冒号分割键值

user:
  name: 李四
  info:
    phone: 13800001111

等价于json数据的

{
    "user": {
        "name":"李四",
        "info":
        	{"phone":"13800001111"}
     }
}

2.6.数组

fruits:              fruits:
  - 苹果				- 苹果
  - 香蕉				- 香蕉
  - 橘子              - 橘子

等价于json数据的

{
    "furits": ["苹果""香蕉","橘子"]
}

2.7 数组和对象嵌套

students:
  - name: 小明
    id: 001
  - name: 小红
    id: 002

等价于json数据的

{ 
	"student": [
        {"name": "小明", "id": 001},
        {"name": "小红", "id": 002},
	]
}

三、K8S YAML文件

在K8S的YAML文件中,pod service deploment 等它们的一级key几乎都一样。也是必不可少的

一级key名称含义
apiVersion资源版本
kind定义资源的类型
metadata定义元数据(名称、标签、命名空间等)
spec定义核心配置
status里面的内容不需要定义,由kubernetes自动生成

环境介绍

主机名IP地址操作系统
k8s-master192.168.65.128Rocky Linux release 9.8
k8s-node01192.168.65.129Rocky Linux release 9.8
k8s-node02192.168.65.131Rocky Linux release 9.8

安装方式使用kubeadm方式安装。网络插件使用的是calico

[root@k8s-master ~]# kubectl get nodes
NAME         STATUS   ROLES           AGE   VERSION
k8s-master   Ready    control-plane   57m   v1.28.2
k8s-node1    Ready    <none>          50m   v1.28.2
k8s-node2    Ready    <none>          49m   v1.28.2

四、deployment YAML文件

Deployment是最常用控制器,用于无状态应用(Nginx、Java微服务),支持弹性伸缩、滚动更新、回滚

1.一级key结构

apiVersion: apps/v1 
kind: Deployment
metadata:               
  name: web-deploy
  namespace: dev
  labels:
    app: web
spec: 

注意:pod的apiVersion是: v1 控制器的是: apps/v1
这里的metadata里有一个labels属性,这是给控制器打标签,目的是能够通过标签来批量匹配控制器,进行批量操作。比如

# 只列出标签 app=web 的 Deployment
kubectl get deploy -l app=web

# 删除所有 app=web 的deployment
kubectl delete deploy -l app=web

如果不设置标签,只能通过name来进行精确匹配.
注意:通过标签匹配控制器,必须是在同命名空间下匹配,匹配同命名空间下的同标签的控制器,不能跨空间匹配

2.spce字段

字段作用
replicas设置副本数量,也就是启动pod的数量
selector匹配pod,也就是管理哪些pod
templatepod模板,
strategy更新策略
revisionHistoryLimit保留历史版本数(用于回滚)

spce的下的基本参数

spec:
	replicas: 定义副本的数量,副本就是pod的数量
	selector:
		matchlabels:
			app: 这里的"值"是控制器匹配nginx pod的"标签的名字",通过匹配这个标签才能管理对应标签的pod
	templates: 这个字段下就是定义pod的相关内容
		metadata:
			labels:
				app: 这里定义pod的标签,这里的标签就是上边要匹配的标签,所有上下要一致
		spec: 这个字段就是定义具体的pod中的容器的内容了
			containers:
			- name: 这里是给pod中的容器起一个名字
			  image:	
			  ports:
			  - containerPort: 容器服务启动的端口
	strategy: 定义pod的更新策略
		type:
	revisionHistoryLimit: 保留历史版本数量
		

2.1.spec.containers字段

------------------------------------
workingDir:容器启动后的默认工作目录
	1.容器一启动,自动切到该路径
	2.不写绝对路径的命令、文件读写、日志生成,都会默认以这个目录为基准
	3.覆盖镜像内置的默认工作目录

-----------------------------------
command: 
args:
这两个参数一般是同时出现,使用这两个命令的时候一定注意:
	现在使用的是nginx的镜像,nginx的启动命令默认是内置在了镜像当中的。
	在YMLA文件当中写了command参数,就会完全覆盖了镜像原始的ENTRYPOINT,镜像自带 CMD 直接作废
	只写 args 不写 command:用镜像原有 ENTRYPOINT,参数会替换成 args的内容。
	例子:
	command: ["/bin/sh","-c"]
	args:
	- mkdir -p /data/testdir && nginx -g "daemon off;"
	所以在使用nginx这种镜像时,使用command和args参数一定要注意

2.2 镜像的拉取策略

imagePullPolicy,用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:
(1)Always:总是从远程仓库拉取镜像(一直远程下载 )
(2)IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像(本地有就本地 本地没远程下载)
(3)Never:只使用本地镜像,从不去远程仓库拉取,本地没有就报错 (一直使用本地)

2.3 资源限制resources

配置资源限制的目的是:避免 Pod 抢占资源,防止单 Pod 耗尽节点资源
kubernetes提供了对内存和cpu的资源进行配额的机制,这种机制主要通过resources选项实现,他有两个子选项:
limits:用于限制运行时容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启
requests :用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动。

对于资源限制的标准是:
同时配置 requests 和 limits,requests < limits。
建议配比:CPU 1:2~1:3,内存 1:1.5~1:2

注意:
	cpu单位是m(毫核)  1cpu = 1000m
	例子:500m(0.5核)、1000m(1核)、2000m(2核)
	
	内存单位:Mi 是MB Gi是GB
	例子: 256Mi  1Gi

2.4 环境变量env

containers:
  env:
  - name: 变量名1
    value: 变量值1
  - name: 变量名2
    value: 变量值2

例子:
env:
- name: file_name
  value: /usr/share/nginx/html/index.html
- name: dir_name
  value: /usr/local/

进入容器查看变量

root@1726-nginx-deployment-7fbbf99964-cgldj:/data/testdir# echo $file_name
/usr/share/nginx/html/index.html
root@1726-nginx-deployment-7fbbf99964-cgldj:/data/testdir# echo $dir_name
/usr/local/

3.实例

来一份基本版的deployment的YAML文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: 1726-nginx-deployment
  namespace: dev
  labels:
    app: nginx-dep

spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: repos.taikangcloud.com/public-ecr-aws/docker/library/nginx:1.22
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh","-c"]
        args:
          - mkdir -p /data/testdir && nginx -g "daemon off;"
        workingDir: /data/testdir
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 200m
            memory: 256Mi
          limits:
            cpu: 500m
            memory: 512Mi
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  revisionHistoryLimit: 10

创建命名空间

kubectl create ns dev

部署yaml文件

[root@k8s-master yaml_file]# kubectl apply -f dep.yaml 
deployment.apps/1726-nginx-depolyment created

# 这里可以看出pod并没有启动成功
[root@k8s-master yaml_files]# kubectl get pod -n dev
NAME                                     READY   STATUS    RESTARTS   AGE
1726-nginx-deployment-5dc5d7768b-5pv7q   1/1     Running   0          17m
1726-nginx-deployment-5dc5d7768b-wfh27   1/1     Running   0          17m

3.1 查看创建的控制器

[root@k8s-master yaml_files]# kubectl get deploy -n dev
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
1726-nginx-deployment   2/2     2            2           51m

3.2 查看控制器的标签

[root@k8s-master yaml_files]# kubectl get deploy -n dev --show-labels
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE   LABELS
1726-nginx-deployment   2/2     2            2           52m   app=nginx-dep

3.3 查看pod的详细信息

# 查看pod的详细信息
[root@k8s-master yaml_file]# kubectl describe pod 1726-nginx-deployment-5dc5d7768b-5pv7q -n dev

3.4 查看所有pod的详细信息

[root@k8s-master yaml_file]# kubectl describe pod  -n dev

3.5 查看pod的IP地址

[root@k8s-master yaml_files]# kubectl get pod -n dev -o wide |awk '{print $6}'
IP
10.244.36.71
10.244.169.132

3.6 进入pod

kubectl -n dev  exec -it "Pod名称" -- /bin/bash

这里修改了index.html的内容。得到结论:在K8S中的任意服务上不论是apiserver 还是work node 都可以通过pod的IP 访问pod中的nginx服务
以下是分别在3台服务器上访问,都没有问题

[root@k8s-master ~]# curl 10.244.169.132
nginx02
[root@k8s-node1 ~]# curl 10.244.169.132
nginx02
[root@k8s-node2 ~]# curl 10.244.169.132
nginx02

4.pod更新策略(strategy)

strategy是 Deployment专属字段。常用的有两种类型:

4.1 RollingUpdate

rollingUpdate是滚动更新,生产环境常用。它有两个参数

 maxSurge:更新时最多超出期望副本数的 Pod 数量
 	例子: 比如现在有3个pod  这里的值设置为2,也就说更新的时候做最多有5个pod
 maxUnavailable: 更新时最多不可用的 Pod 数量
 	例子:比如这里的值设置为0 现在的副本数有3个,那么更新时候,一个pod的都不会被删除,
 	如果设置为1,最多删除1个pod 保证2个可以用

4.2 Recreate

先全部删除旧 Pod,再创建新 Pod,更新期间服务完全中断。

四 service YAML文件

通过以上知识得到结论:

1.K8S 中 Pod 会因重启、扩容、缩容、节点调度发生IP动态变化
2.无法提供固定的 IP 对外提供统一访问入口

1.service简介

Service 是 K8S 核心资源对象,作用是:为一组 Pod 提供固定、稳定的网络访问入口,实现 Pod 负载均衡、服务发现、流量转发,屏蔽后端 Pod 的动态变化
通过service的统一入口地址访问到 pod 中的服务.如下图所示

k8s-node01

k8s-node02

pod2

pod1

用户

service

2.核心工作机制

Service 通过 标签匹配(selector) 关联后端 Pod.

3.service代理模式

模式特性
iptables(默认)基于内核 iptables 规则转发,性能高,支持负载均衡
ipvs(高性能)支持大规模集群、多种负载均衡算法

4.service的类型

service通过对spec.type的定义访问类型。

1.CluseterIP(默认):
	分配集群内部虚拟固定 IP,仅集群内部 Pod、节点可访问,外网无法访问
	自动对后端多 Pod 实现轮询负载均衡
	使用场景:微服务内网互相调用(后端服务、数据库、缓存等内部服务)

2.NodePort:
	在所有集群节点上开放固定端口(NodePort),集群外部可以通过节点IP:nodeport 访问服务
	访问链路为: 集群外部--> "节点IP:NodePort"--> ClusterIP-->后端pod
	使用场景:测试环境、临时对外暴露服务,不适合生产大规模使用


3.LoadBalancer:
	基于 NodePort 扩展,云厂商(阿里云/腾讯云/AWS)会自动分配公网固定负载均衡 IP
	云环境生产环境对外暴露业务服务.裸金属集群无此能力,仅云 K8S 支持

5.YAML配置

5.1 一级字段

apiVersion: v1 这里的版本是固定的
kind: Service
metadate:
	name: nginx-svc-1726   这里要注意,svc的名字是不能以数字开头的
	namespave:dev
	labels:
		app: nginx-svc
spec:
	

5.2 spec字段

字段作用备注
type定义service的类型
selector根据标签来匹配pod
ports定义svc暴漏的端口
clusterIP如果不选,集群会自动分配可选

6.ClusterIP YAML实例

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc-1726
  namespace: dev
  labels:
    app: nginx-svc 
spec:
  type: ClusterIP
  selector:
    app: nginx-pod  这个值就是 pod的标签,svc通过这个值来匹配pod
  ports:
  - port: 80   SVC暴漏的端口
    targetPort: 80  这是容器的端口

6.1 创建SVC(service)

[root@k8s-master ~]# kubectl apply -f svc.yaml 
service/nginx-svc-1726 created

6.2 查看SVC

这里可以看到svc的类型和IP地址、端口信息

[root@k8s-master ~]# kubectl get svc -n dev
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
nginx-svc-1726   ClusterIP   10.97.82.106   <none>        80/TCP    56s

6.3 修改pod内容

为了方便看到负载效果,这里将两个pod的nginx的首页内容修改。修改过程不再写了

[root@k8s-master ~]# kubectl get pod -n dev -o wide |awk '{print $6}'
IP
10.244.169.143
10.244.36.82

分别访问两个pod的内容

[root@k8s-master ~]# curl 10.244.169.143
nginx01
[root@k8s-master ~]# curl 10.244.36.82
nginx02

6.4 访问svc

分别在K8S-master 、k8s-node1、k8s-node2上妇访问SVC地址都可以访问到pod的服务,结果如下

[root@k8s-master ~]# curl 10.97.82.106
nginx02
[root@k8s-master ~]# curl 10.97.82.106
nginx01
[root@k8s-master ~]# curl 10.97.82.106
nginx02
[root@k8s-master ~]# curl 10.97.82.106
nginx02
[root@k8s-master ~]# curl 10.97.82.106
nginx02
[root@k8s-master ~]# curl 10.97.82.106
nginx01
[root@k8s-master ~]# curl 10.97.82.106
nginx01
[root@k8s-master ~]# curl 10.97.82.106
nginx02
[root@k8s-master ~]# curl 10.97.82.106
nginx01

7.修改代理模式方法

但是这里又一个问题,这里的负载效果并不是我们想象中的01–>02–>01–>02的那样轮询效果。
原因是:service默认的代理模式是iptables模式,负载均衡策略是随机分发(数据包随机哈希)
如果想要看到严格的轮询模式就需要用到,可以修改service的代理模式。步骤如下

7.1 修改kube-proxy配置文件

在k8s-master上执行

kubectl edit configmap kube-proxy -n kube-system

找到

mode: "ipvs"   修改为ipvs模式

7.2 滚动重启 kube-proxy 生效

kubectl rollout restart daemonset kube-proxy -n kube-system

7.3 验证效果

此时就是轮询模式了

[root@k8s-master ~]# curl http://10.97.82.106
nginx02
[root@k8s-master ~]# curl http://10.97.82.106
nginx01
[root@k8s-master ~]# curl http://10.97.82.106
nginx02
[root@k8s-master ~]# curl http://10.97.82.106
nginx01

8.NodePort YAML实例

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc-1726
  namespace: dev
  labels:
    app: nginx-svc
spec: 
  type: NodePort 这里的配置改为了nodeport模式
  selector:
    app: nginx-pod
  ports:
  - port: 80  SVC暴漏的端口
    targetPort: 80 对应pod的端口
	

8.1 可选参数

在ports下有两个可选参数,如果不写集群会默认分配

nodePort: 30080  定义节点对外开放的端口
protocol: TCP   定义节点端口的协议,此参数值就是TCP协议

8.2 创建SVC

[root@k8s-master ~]# kubectl apply -f svc.yaml 
service/nginx-svc-1726 configured

8.3 查看SVC

这里看到了svc的80对应节点的30184端口,默认协议为TCP

[root@k8s-master ~]# kubectl get svc -n dev
NAME             TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx-svc-1726   NodePort   10.97.82.106   <none>        80:30184/TCP   4h29m

8.4 访问结果

在任意服务器上执行都可以

[root@k8s-master ~]# curl 192.168.65.128:30184
nginx02
[root@k8s-master ~]# curl 192.168.65.128:30184
nginx01
[root@k8s-master ~]# curl 192.168.65.128:30184
nginx02
[root@k8s-master ~]# curl 192.168.65.128:30184
nginx01
[root@k8s-master ~]# 

通过K8S-node1的IP访问

[root@k8s-master ~]# curl 192.168.65.129:30184
nginx02
[root@k8s-master ~]# curl 192.168.65.129:30184
nginx01
[root@k8s-master ~]# curl 192.168.65.129:30184
nginx02
[root@k8s-master ~]# curl 192.168.65.129:30184
nginx01

通过K8S-node2的IP访问

[root@k8s-master ~]# curl 192.168.65.131:30184
nginx02
[root@k8s-master ~]# curl 192.168.65.131:30184
nginx01
[root@k8s-master ~]# curl 192.168.65.131:30184
nginx02
[root@k8s-master ~]# curl 192.168.65.131:30184
nginx01

8.4 浏览器验证

通过任意一个都可以访问到pod中的服务

192.168.65.131:30184
192.168.65.129:30184
192.168.65.128:30184

但是这里有一个问题,通过浏览器中访问轮询效果不没有那么明显,那是因为浏览器的长连接问题

五、ingress

1.SVC两种类型的缺点

ClusterIP 的问题是 集群外部不能访问,只能集群内部访问
NodePort 的问题是 集群外部可以访问,但是需要占用节点服务器的端口。
基于这种现状,K8S提供了ingress对象

2.ingress 简介

2.1 ingress 资源(YAML)

用户通过YAML文件创建YAML规则,定义域名 路径 对应的service 本身不处理流量

2.2 ingress controller

它是一个实体pod,核心作用就是监听ingress规则,加载规则,实际处理,转发客户流量

2.3 ingress注意点

1)ingress是七层代理,不支持TCP 和 UDP转发
(2)ingress本身无端口,依赖ingress controller的80443端口对外提供服务
(3)域名解析必须指向ingress controller所在的节点IP,流量才能进入集群

3.ingress YAML配置

3.1 一级字段

注意:这里没有kind字段

apiVersion: networking.k8s.io/v1
metadata:
	name: ingress名字
	namespace: 命名空间
	annotations:  注解字段,不是注释的字段,是通过这里开启一些功能,比如地址重写,https强制跳转等
spec:

annotations例子:
比如要开启http强转https: ingress.cloud.tencent.com/auto-rewrite: ‘true’
这个参数是通过腾讯云蓝鲸蓝鲸平台页面配置 自动生成的参数。

annotations:
	 ingress.cloud.tencent.com/auto-rewrite: 'true'

3.2 spec字段

字段作用
tlshttps证书配置,实现443加密访问
rules核心路由规则
pathType路径配置规则

3.3 tls字段

spec:
	tls:
	- host: 域名,这里的域名必须要和rules.host中的域名完全配置。这里也支持泛域名"*.tkdental.com".但是证书必须也是通配符证书
	  secretName:  这里写"存储证书的Secret名称"
	rules:

3.4 pathType

1. Prefix:前缀匹配 
	比如:/test 就会匹配 /test 以及他的子路径

2.Exact: 精确匹配
	仅匹配路径完全一致的路径,区分大小写
	
3.ImplementationSpecific:控制器默认匹配规则,一般来讲使用默认匹配规则。

4 样例ingress YAML文件

spec:
	tls:
	  - hosts: xxx.xxxx.com
	    secretName:  这里是存储证书的Secret
	rules: 路由规则
	  - host: 域名
	    http:
	      paths:
	      - path: /
	        pathType: ImplementationSpecific  使用默认匹配规则
	        backend: 
	          service:
	          	name: 对应service的名称,就是转发到哪个service就写哪个
	          	port: 
	          	  number: svc端口,写service暴露的端口
	 	  - path: /api
          	pathType: ImplementationSpecific
          	backend:
          	  service:
          	  	name:
          	  	port:
          	  	  number: 
	  

六、secret

1.简介

secret是用于存储 “敏感数据”,比如:密码、密钥、数据库账号、TLS证书、私钥、API token等
secret 和confimap的区别就是 confimap是明文普通配置,secret是存放隐私设置。

2.注意点

1.secret仅作base64编码,不是加密,集群内可以直接解码
2.任何能get/list secret的账号都能拿到完整的敏感内容

3.type字段

type的值有4个类型

3.1 Opaque

此类型是默认类型,通用密钥,无格式限制,最常用。如果不声明type字段,默认就会使用这个类型

3.2 kubernetes.io/tls

此类型是专门存放TLS证书链与私钥,固定两个key。然后让ingress.tls引用。命令如下

kubectl create secret tls demo-tls --cert fullchain.pem --key privkey.pem

3.3 kubernetes.io/dockerconfigjson

存放私有镜像仓库登录账号密码,用于 imagePullSecrets

3.4 kubernetes.io/service-account-token

ServiceAccount 自动创建,存放访问集群 API 的 JWT token,无需手动创建。

4.data与stringData

4.1 data

如果使用data字段写入key和值,必须是base64后的值

4.2 stringData

如果使用stringdata字段写入key和值,直接填写明文即可,提交 API 时自动转为 base64 存入 data字段.
仅用于创建 / 更新资源,生效后此字段不会出现在 yaml中

5.YAML配置

apiVersion: v1
kind: Secret
metadata:
  name: secret-1726
  namespace: dev
stringData:
  db_user: root
  db_pass: '123456'
  system_user: admin
  system_pass: '654321'

应用配置

[root@k8s-master secret]# kubectl apply -f secret-1726.yaml 
secret/secret-1726 created

查看创建的secret

[root@k8s-master secret]# kubectl get secret -n dev 
NAME          TYPE     DATA   AGE
secret-1726   Opaque   4      3m11s

查看详细信息:
这里以yaml格式数据创建的secret,这里可以看到:
1.stringData没有了,自动将值合并到到了data字段中
2.data字段对key的值进行了base64编码
3.在输出的yaml信息中可以到原始的key的值

[root@k8s-master secret]# kubectl get secret -n dev -o yaml
......
  data:
    db_pass: MTIzNDU2
    db_user: cm9vdA==
    system_pass: NjU0MzIx
    system_user: YWRtaW4=
  kind: Secret
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"secret-1726","namespace":"dev"},"stringData":{"db_pass":"123456","db_user":"root","system_pass":"654321","system_user":"admin"}}
  type: Opaque
......

6.引用secret

生产环境推荐以 volumes的形式引用secret
具体步骤为:
1.在控制器中的yaml文件中定义一个volumes(卷),卷引用secret
2.在将卷挂载到容器当中
这种形式推荐生产使用,因为这种形式的好处是secret更新时,容器内自动滚动更新secret内容,无需重启Pod
这种形式还支持items映射key文件名、指定权限、单独挂载指定key

6.1 创建测试secret

[root@k8s-master secret]# vim test-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: test-secret
  namespace: dev
stringData:
  user: root
  password: '123456'
  
[root@k8s-master secret]# kubectl apply -f test-secret.yaml 
secret/test-secret created

[root@k8s-master secret]# kubectl get secret -n dev
NAME          TYPE     DATA   AGE
test-secret   Opaque   2      74s

6.2 创建测试deployment

[root@k8s-master yaml_files]# cat test-dep.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
  namespace: dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: test-nginx-pod
  template:
    metadata:
      labels:
        app: test-nginx-pod
    spec:
      volumes:   "在这里定义一个卷"
      - name: secret-vlomues   这里定义卷的名字,容器挂载卷的时候,引用的是这里的名字
        secret:
          secretName: test-secret  这里是引用的上边定义的secret的名字

      containers:
      - name: nginx-pod
        image: xxxxxxxxx.com/nginx:1.22
        ports:
          - containerPort: 80
        volumeMounts:    这里开始挂载卷
        - name: secret-vlomues   引用上边定义的的卷
          mountPath: /etc/userinfo  挂载路径,如果目录不存在会自动创建目录。目录下key会变成文件名,文件内容就是key的值
          readOnly: true
[root@k8s-master yaml_files]# kubectl apply -f test-dep.yaml 
deployment.apps/test-deployment created

6.3 进入容器,查看secret

[root@k8s-master yaml_files]# kubectl -n dev  exec -it test-deployment-5df97d6b5b-b7fbp -- /bin/bash
root@test-deployment-5df97d6b5b-b7fbp:/# ls /etc/userinfo/
password  user

root@test-deployment-5df97d6b5b-b7fbp:/etc/userinfo# cat user; echo -e "\n"
root

root@test-deployment-5df97d6b5b-b7fbp:/etc/userinfo# cat password; echo -e "\n"
123456

七、configMap

1.简介

configmap(配置映射),是K8S内置的非敏感配置资源对象,用于存储应用的配置信息,专门实现 “配置与容器解耦”。
简单说就是把应用的配置文件、环境变量、启动参数抽离出来统一管理,无需重新打包镜像、无需重启 Pod 即可更新配置。

2.特性

1.明文存储数据
2.数据结构为键值对
3.不能跨命名空间引用
4.pod只读configmap配置,无法修改写入
5.不支持大容量数据,单configmap大小不建议超过1M
6.支持热更新:文件挂载方式可以自动更新,环境变量方式不可以热更新

3.configmap使用场景

应用配置文件:nginx.conf appalication.yaml log配置等
通用环境变量,启动参数、域名、端口、超时时间等

4.创建configmap的方式

4.1 命令行

简单的configmap可以使用命令创建,适用与快速测试
语法:

kubectl create configmap 名称 --from-literal=key=value

例子:

[root@k8s-master yaml_files]# kubectl create configmap test-cmp --from-literal=name="zhangsan" -n dev
configmap/test-cmp created
    
[root@k8s-master yaml_files]# kubectl get configmap -n dev
NAME               DATA   AGE
kube-root-ca.crt   1      3d7h
test-cmp           1      10s


4.2 单个文件创建

直接将本地配置文件转为 ConfigMap,key 默认是文件名,value 是文件内容。
例子:

[root@k8s-master nginx-config]# cat nginx.conf 
worker_processes  auto;
events {
    worker_connections  10240;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server_tokens off;
    server_names_hash_bucket_size 64;
    server_names_hash_max_size 512;
    include vhosts/*.conf;
}

nginx-config是创建的configmap名称

[root@k8s-master nginx-config]# kubectl create configmap nginx-config --from-file=./nginx.conf 
configmap/nginx-config created

这里可以看到,data字段中的key-value内容
key: nginx.conf 文件名自动作为key
value: nginx.conf的内容作为key的value

[root@k8s-master nginx-config]# kubectl get configmap nginx-config -o yaml
apiVersion: v1
data:
  nginx.conf: |    "这里的 | 是保留缩进和换行,是多文本必填符号,不能省略"
    worker_processes  auto;
    events {
        worker_connections  10240;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server_tokens off;
        server_names_hash_bucket_size 64;
        server_names_hash_max_size 512;
        include vhosts/*.conf;
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2026-07-16T15:51:19Z"
  name: nginx-config
  namespace: default
  resourceVersion: "441751"
  uid: a64e9016-5fec-4eb1-82f1-b9b026450a32

4.3 从整个目录创建

批量加载目录下所有配置文件,每个文件对应一个 key。

kubectl create configmap app-config --from-file=./config/

4.4 YAML文件清单创建

这里一定要注意value内容的格式,一定是在key的子层级,否则会格式错误.在粘贴nginx配置的内容时一定要注意格式

apiVersion: v1
kind: ConfigMap
metadata:
  name: test1-nginx-configmap
  namespace: dev
data:
  nginx.conf: |   
    worker_processes  auto;
    events {
        worker_connections  10240;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server_tokens off;
        server_names_hash_bucket_size 64;
        server_names_hash_max_size 512;
        include vhosts/*.conf;
    }

创建configmap

[root@k8s-master nginx-config]# kubectl apply -f test1-configmap.yaml 
configmap/test1-nginx-configmap created

5.引用configmap

引用方法和引用secret的方法一样,推荐使用volumes的方式,因为这种方式支持热更新.这里写了一个nginx配置文件的实例
这里的test1-nginx-configmap应用了上边4.4中例子
下边是定义了另外一个vhosts下载的配置文件的confimap: vhost-admin-configmap

apiVersion: v1
kind: ConfigMap
metadata:
  name: vhost-admin-configmap
  namespace: dev

data:
  admin500.conf: |
    server {
      listen 80;
      server_name admin500.test.com;

      root /data/wwwroot/dental-city-web/admin; # 指向 admin 目录
      index index.html;

      location / {
          try_files $uri $uri/ /index.html;
      }
    }

定了控制器deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
  namespace: dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: test-nginx-pod
  template:
    metadata:
      labels:
        app: test-nginx-pod
    spec:
      volumes: 
      - name: nginxconf-configmap-vlomues     定义第一个卷,将configMap定义成卷的形式
        configMap: 
          name: test1-nginx-configmap    引用configMap的名字,不是configMap中key的名字

      - name: admin500conf-configmap-volumes  定义第二卷,,将configMap定义成卷的形式
        configMap:
          name: vhost-admin-configmap    引用configMap的名字,不是configMap中key的名字

      containers:
      - name: nginx-pod
        image: xxxxxxxx/nginx:1.22
        ports:
          - containerPort: 80
          
        volumeMounts:   挂载卷
        - name: nginxconf-configmap-vlomues       引用定义的第一个卷的名字
          mountPath: /usr/share/nginx/nginx.conf  挂载点,挂载点必须是一个文件,文件可以不存在,如果是目录镜像启动失败
          subPath: nginx.conf   这里的名字是configmap中key的名字,这个key定义的时候定义为了配置文件的名称,这样就见名知意了
          
        - name: admin500conf-configmap-volumes  引用定义的第二个卷的名字
          mountPath: /usr/share/nginx/vhosts/admin500.tkdental.conf 
          subPath: admin500.conf  这里的名字是configmap中key的名字,这个key定义的时候定义为了配置文件的名称,这样就见名知意了

6.subPath机制

subpath的字面意思是子路径的意思。这里的子路径是指的"卷"内的 "子文件/目录"或者 “key”。不是指的挂载目标的子路径,不要理解错误
如果 mountPath 结尾是目录,不能用 subPath 挂载单个文件到这个目录路径上
subPath 文件只能挂载到文件路径,不能挂载到目录
错误例子:

volumeMounts:
- name: nginxconf-configmap
  mountPath: /usr/share/nginx/    # 目标是目录,这里就会报错
  subPath: nginx.conf  

注意:

subPath 坑:configMap/secret 用 subPath 时,不会自动热更新;不使用 subPath 才会自动更新

7.多个key挂载到目中

上边的subPath 是指定一个key挂载到指定文件中,这样挂载稍微有点繁琐,因为nginx下如果有多个server,就要创建多个configmap 挂载多次
我们可以创建一个configmap,其中创建多个对应server的key,然后这个configmap作为一个目录整个挂载到容器当中

7.1 创建两个configmap

nginx.conf的configmap

[root@k8s-master nginx-config]# cat nginx-configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-nginx-main
  namespace: dev
data:
  nginx.conf: |
    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log warn;
    pid /var/run/nginx.pid;
    events {
        worker_connections 1024;
    }
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
        access_log /var/log/nginx/access.log;
        sendfile on;
        keepalive_timeout 65;
        # 统一加载vhost目录
        include /usr/share/nginx/vhosts/*.conf;
    }

7.2 创建vhosts目录对应的confimap

[root@k8s-master nginx-config]# cat nginx-vhost-configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-nginx-vhosts
  namespace: dev
data:
  a.com.conf: |
    server {
      listen 80;
      server_name a.com;
      location / { root /html; }
    }
  b.com.conf: |
    server {
      listen 80;
      server_name b.com;
      location / { root /html; }
    }
  c.com.conf: |
    server {
      listen 80;
      server_name c.com;
    }
[root

7.3 创建控制器

[root@k8s-master yaml_files]# cat test-dep.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
  namespace: dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: test-nginx-pod
  template:
    metadata:
      labels:
        app: test-nginx-pod
    spec:
      volumes:
      - name: nginxconf-configmap-vlomues  定义主配置文件的configmap的卷
        configMap:
          name: cm-nginx-main    引用configmap的名称

      - name: nginxvhost-configmap-volumes 定义vhost目录对应的configmap的卷
        configMap:
          name: cm-nginx-vhosts  引用configmap的名称

      containers:
      - name: nginx-pod
        image: xxxxxx/nginx:1.22
        ports:
          - containerPort: 80
        volumeMounts:
        - name: nginxconf-configmap-vlomues  调用卷的名称
          mountPath: /usr/share/nginx/nginx.conf   挂载到的目标文件
          subPath: nginx.conf  这是configmap中key的名称

        - name: nginxvhost-configmap-volumes  调用卷的名称
          mountPath: /usr/share/nginx/vhosts  直接挂载到目录下,没有使用subPath参数,使用就会报错

7.4 验证

这里看到cm-nginx-vhosts的configmap中的多个key被映射到了vhosts目录下,以多个文件的形式存在。

root@test-deployment-7f4797489d-8jmnn:/usr/share/nginx/vhosts# ls
a.com.conf  b.com.conf	c.com.conf
root@test-deployment-7f4797489d-8jmnn:/usr/share/nginx/vhosts# pwd
/usr/share/nginx/vhosts

8.items 选择性挂载

缺点:

items 也不支持configmap配置的热更新,以下只是演示items的用法

8.1 configmap

configmap内容如下:

[root@k8s-master nginx-config]# cat nginx-vhost-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-vhost-configmap
  namespace: dev
data:
  a.com.conf: |
    server {
      listen 80;
      server_name a.com;
      location / { root /html; }
    }
  b.com.conf: |
    server {
      listen 80;
      server_name b.com;
      location / { root /html; }
    }
  c.com.conf: |
    server {
      listen 80;
      server_name c.com;
    }

8.2 创建configmap

[root@k8s-master nginx-config]# kubectl  apply -f nginx-vhost-configmap.yaml 
configmap/nginx-vhost-configmap created

[root@k8s-master nginx-config]# kubectl get configmap -n dev
NAME                    DATA   AGE
nginx-vhost-configmap   3      2m6s

8.3 创建对应的deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: 1726-nginx-deployment
  namespace: dev
  labels:
    app: nginx-dep

spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      volumes:   创建卷
        - name: nginx-cfm-volumes  给卷起一个名称
          configMap:
            name: nginx-vhost-configmap  引用configmap
            items: items选项是可以不写,像上边的例子中就是,如果不写就是挂载configmap中全部的key。
            - key: a.com.conf  挂载第一个key
              path: administrator.com.conf  
            - key: b.com.conf  挂载第二个key
              path: benet.com.conf  这两处的path不是挂载路径,千万要注意,这里给key做了一个重命名,但也可以和key保持一致。这里特意不一样,来验证重命名的效果
      containers:
      - name: nginx
        image: xxxxxxx/nginx:1.22
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts: 挂在卷
          - name: nginx-cfm-volumes  引用要挂载的卷的名名称
            mountPath: /etc/nginx/conf.d  挂载的目录,这里就没有使用subpath

8.4 验证

root@1726-nginx-deployment-59668458b6-jt2qj:/etc/nginx/conf.d# pwd
/etc/nginx/conf.d

这里可以看到成功挂载了两个key,并且给key做了重命名
root@1726-nginx-deployment-59668458b6-jt2qj:/etc/nginx/conf.d# ls
administrator.com.conf	benet.com.conf

更多推荐