一 背景引出
前面我们学习了一些'常用的资源对象'的使用,但是'单纯依靠'这些资源对象,还'不足以'满足我们的日常需求
一个'重要的需求'就是'应用的配置管理'、'敏感信息的存储和使用(passwd、token)'、'容器运行资源的配置'、'安全管控'、'身份认证'等等
二 ConfigMap
对于'应用的可变配置'在 Kubernetes 中是通过一个 'ConfigMap 资源对象'来实现的
我们知道'许多应用'经常会有从'配置文件'、'命令行参数'或者'环境变量中'读取一些'配置信息'的需求
这些配置信息我们肯定'不会直接写死到应用程序'中去的,比如你一个应用连接一个 redis 服务,下一次想更换一个了的,还得'重新去修改代码',重新'制作一个镜像',这肯定是'不可取'的
++++++++++++++++ '分割线' ++++++++++++++++
而ConfigMap 就给我们提供了'向容器中注入配置信息的能力',不仅可以用来保存'单个属性',还可以用来保存'整个配置文件',
应用场景举例: 比如我们可以用来'配置一个 redis 服务'的访问地址,也可以用来保存'整个 redis' 的配置文件
(1)帮助文档理解
(1)命令行创建
备注: 这是'最常用'的方式
① 基于目录创建
查看
将 '/tmp/' 目录下的'所有文件-->普通文件',也就是 'hpa-mem.yaml' 和 'hpa-mem-demo.yml' 打包到 'configmap1' ConfigMap 中
② 基于文件
基于'单个'文件或'多个'文件创建 ConfigMap
++++++++++++++++ '这个不再演示' ++++++++++++++++
你可以'定义'在 ConfigMap 的 data 部分出现键名,而'不是按默认行为'使用文件名
kubectl create configmap 'configmap_name' --from-file='<my-key-name>=<path-to-file>'
③ 基于字面量
注意的是如果文件里面的'配置信息很大'的话,'describe' 的时候可能'不会显示对应的值'
④ 从环境文件创建 ConfigMap
(2)yaml创建
kind: ConfigMap
apiVersion: v1
metadata:
name: cm-demo
namespace: default
data: '核心是这个字段'
data.1: hello
data.2: world
config: |
property.1=1
property.2=2
property.3=3
'yaml的一些高级语法在k8s中的体现'
使用竖线符'|'来表示该语法,每行的'缩进和行尾空白'都会被去掉,而'额外的缩进'会被保留
使用右尖括号' > '来表示该语法,--'和保留换行不同的是'-->只有'空白行'才会被'识别为换行',原来的'换行符'都会被转换成'空格',而'行首缩进'会被去除
(3)ConfigMap的使用
Pod的'使用方式':
1. 将ConfigMap中的数据'设置为容器的环境变量'
2. 将ConfigMap中的数据设置为'命令行参数'
3. 使用'Volume'将ConfigMap作为'文件或目录挂载(mount)'
4. 编写'代码'在 Pod 中运行,使用'Kubernetes API 来读取' ConfigMap
⑤ 环境变量使用
资源清单
需求: 将 ConfigMap 中的'所有键值对配置'为容器'环境变量'
备注: Kubernetes 'v1.6 和更高版本'支持此功能
kubectl create configmap cm2 --from-literal=JAVA_HOME=/usr/bin/java --from-literal=MAVEN_HOME=/usr/bin/maven
apiVersion: v1
kind: Pod
metadata:
name: busybox
spec:
containers:
- name: busybox
image: busybox
command: ['/bin/sh','-c','env']
envFrom:
- configMapRef:
name: cm2
⑥ 作为命令行参数
apiVersion: v1
kind: Pod
metadata:
name: testcm2-pod
spec:
containers:
- name: testcm2
image: busybox
command: [ "/bin/sh", "-c", "echo $(DB_HOST) $(DB_PORT)" ]
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.host
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.port
⑦ 将 ConfigMap 数据添加到一个卷中
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ] '查看是否挂载-->生成两个文件(以configmap的key为文件名)'
volumeMounts:
- name: config-volume '容器中使用哪个volume,进行挂载'
mountPath: /etc/config '容器中的挂载点'
volumes:
- name: config-volume
configMap:
name: cm1 '使用configmap类型的cm1作为volume'
restartPolicy: Never
⑧ 将 ConfigMap 数据添加到数据卷中的特定路径
使用 'path 字段'为特定的 ConfigMap 项目'指定预期的文件路径'
在这里'SPECIAL_LEVEL' 将挂载在 'config-volume' 数据卷中 '/etc/config/keys 目录下'
++++++++++++++++++ '注意事项' ++++++++++++++++++
使用 ConfigMap 作为 'subPath' 的数据卷将'不会收到' ConfigMap 更新
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: busybox
command: [ "/bin/sh","-c","cat /etc/config/keys" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config -->'挂载后-->/etc/config/${path}'
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: SPECIAL_LEVEL -->'使用configmap中的哪个key'
path: keys
⑨ 热更新
之有当 ConfigMap 以'数据卷的形式挂载'进 Pod 的时,才支持'热更新' -->'subPath'不支持
细节: '更新' ConfigMap或'删掉重建'ConfigMap,Pod 内挂载的'配置信息会热更新',这时可以增加一些'监测配置文件'变更的脚本,然后'重加载'对应服务就可以实现'应用的热更新'
核心: 让系统'感知配置文件'的'变化',让应用程序重'新加载配置'文件生效 -->'md5sum模拟'
++++++++++++++++++ '分割线' ++++++++++++++++++
配置文件的热更新'不等于'应用的热更新
ConfigMap可以通过'目录'或'文件'的方式进行挂载
⑩ 限制事项
1) 在 Pod 规范中'引用之前',必须'先创建一个 ConfigMap'-->'除非将 ConfigMap 标记为"可选"';如果引用的 ConfigMap '不存在',则 Pod '将不会启动';同样引用 ConfigMap 中'不存在的键'也会阻止 Pod 启动。
如果你使用 envFrom 基于 ConfigMap 定义环境变量,那么无效的键将被忽略。 可以启动 Pod,但无效名称将记录在事件日志中(InvalidVariableNames)。 日志消息列出了每个跳过的键。
2)ConfigMap 位于'特定的名字空间'中,每个 ConfigMap 只能被'同一名字空间中的 Pod 引用'
3)你不能将 ConfigMap 用于' 静态 Pod '
4)ConfigMap '文件大小限制'为 1MB-->'ETCD 的要求'
三 Secret
(1)概念引入
(2) Secret的类型
强调: pod对于kube-apiservre也是一个'client',要访问资源'也需要通过认证'-->'通过'kubernetes.io/service-account-token
(3)Opaque
特点:Opaque 类型的数据是一个 'map 类型',要求 value 必须是 'base64 编码'格式
+++++++++++++++++++ '分割线' +++++++++++++++++++
建一个'用户名为 admin','密码为 123456' 的 Secret 对象,首先我们需要先把用户名和密码'做 base64 编码'
echo -n 表示'不换行输出',添加了-n选项以后,'文本直接连着命令提示符'输出了,并没有换行
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque '重点'
data:
username: YWRtaW4= 'base64编码'
password: MTIzNDU2
用 'describe' 命令查看到的 Data '不会直接显示'出来 -->可以'get -o yaml'形式获取
(4)kubernetes.io/service-account-token
Service Account 是属于某个'具体的Namespace',给'Pod 里的进程'使用的
每个ServiceAccount下面都会拥有一个'加密过的secret作为Token'. 该token也叫service-account-token,该token才是'真正在API Server验证'(authentication)环节起作用的
当用户在该namespace下'创建pod'的时候都会'默认使用'这个service account
1) 每个Namespace下有一个'名为default'的默认的Service Account'sa'对象
2) 这个ServiceAccount下面都会拥有一个'加密过的secret'作为Token,可以'当作Volume'一样被Mount到Pod里
3)当Pod 启动时,这个'Secret会自动被Mount'到Pod的'指定目录下',用来'协助完成'Pod中的进程'访问API Server'时的'身份鉴权'过程
'ca.crt和token'就是提供给'开发者访问'apiservre的 -->利用'pod自带的'
'默认default的sa'没有对应的权限'比如get pods',除非'sa关联的secret'或者说'sevice accout有这个权限'就可以访问pod了
++++++++++++++++++ '另外一种方式' ++++++++++++++++++
kubeconfig -->集群内'不管pod还是节点'和集群外都可以访问
(5)kubernetes.io/dockerconfigjson
说明:如果'yaml文件的话',需要提前把'核心数据'进行'base64编码',每次都都要'手工操作',比较'麻烦' -->'自动帮我们做base64编码'
++++++++++++++++ '下面方式' ++++++++++++++++
如果非'80'端口或者'https-->默认是443可以省略'的形式,仓库地址需要加'port'
备注: 可以'加上-->可选'--type=kubernetes.io/dockerconfigjson
'利用docker login'生成的'.dockercfg'文件生成secret
kubectl create secret docker-registry myregistrykey --from-file="~/.dockercfg"
(6)Secret使用
1)以'环境变量'的形式
2)以'volume'的形式挂载
① 环境变量
创建Secret保存'mysql镜像'启动所需的'参数'
1)'创建Secret'-->属于'ns'的
kubectl create secret generic mysql-secret --from-literal=MYSQL_ROOT_PASSWORD='$!B@12zDhh' -n default
备注: 密码'格式不对'也可能无法创建成功
---
apiVersion: v1
kind: Pod
metadata:
labels:
name: java
name: mysql
namespace: default
spec:
containers:
- image: mysql:5.7.30
name: mysql-server
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_ROOT_PASSWORD '这个名字必须是固定的,mysql启动会找这个环境变量'
valueFrom:
secretKeyRef:
key: MYSQL_ROOT_PASSWORD
name: mysql-secret
---
kubectl apply -f mysql-secret.yml
测试ok
② Volume 挂载
1)创建一个'包含 SSH 密钥'的 Secret
kubectl create secret generic ssh-key-secret \
--from-file=ssh-privatekey=/root/.ssh/.ssh/id_rsa \
--from-file=ssh-publickey=/root/.ssh/id_rsa.pub
2)创建一个 Pod,令其'引用包含 SSH 密钥的 Secret',并通过'存储卷来使用'它
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
labels:
name: secret-test
spec:
volumes: 'pod中声明使用volum的类型'
- name: secret-volume
secret:
secretName: ssh-key-secret
containers:
- name: ssh-test-container
image: mySshImage
volumeMounts: 'containers使用volume'
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
③ imagePullSecrets
ImagePullSecrets 与 Secrets '不同',因为 Secrets 可以'挂载到 Pod 中',但是 'ImagePullSecrets 只能由 Kubelet 访问'
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: harbor.wzj.com/test:v1
imagePullSecrets: '说明: 这里只是认证-->必须保证该secret是对harbor.wzj.com的认证才能拉取' --> '针对pod里面所有的容器的'
- name: myregistry
备注: 除了设置 Pod.spec.imagePullSecrets 这种方式来'获取私有镜像'之外,我们还可以通过在 'ServiceAccount' 中设置 'imagePullSecrets',然后就会自动为'使用该 sa 的 Pod 注入' imagePullSecrets 信息
④ tls
后续补充: ingress'这块'做一个'认证'
⑤ 热更新和不可变
特点: 一旦一个 Secret 或 ConfigMap 被'标记为不可变','撤销'此操作或者'更改' data 字段的内容都是'不可能的', '只能删除'并'重新创建'这个 Secret;现有的 Pod 将维持对已删除 Secret 的挂载点 - 建议重新创建这些 Pod
三 Secret
和 ConfigMap
这两种资源对象的异同点
四 Secret最佳实践
五 Secret扩展
FEATURE STATE: Kubernetes 'v1.13 [beta]'
你可以为 Secret 数据开启'静态加密', 这样 Secret 数据就'不会以明文形式'存储到etcd 中