ConfigMap和Secret
ConfigMap
和Secret
向容器传递命令行参数
在Docker
中定义命令与参数
容器中运行的完整指令由两部分组成, 命令与参数.
了解ENTRYPOINT
与CMD
ENTRYPOINT
定义容器启动时被调用的可执行程序.
CMD
指定传递给ENTRYPOINT
的参数.
了解shell
与exec
形式的区别
shell
形式–如ENTRYPOINT node app.js
.
exec
形式– 如ENTRYPONT ["node", "app.js"]
.
两者的区别在于指定的命令是否在shell
中被调用, 确定PID
为1的进程是谁.
在Kubernetes
中覆盖命令和参数
在Kubernetes
中定义容器时, 镜像的ENTRYPOINT
和CMD
均可以被覆盖, 仅需要在容器定义中设置属性command
和args
的值.
1 | kind: Pod |
绝大多数情况下, 只需要设置自定义参数. 命令一般很少被覆盖, 除非针对一些未定义ENTRYPINT
的通用镜像, 例如busybox
.
command
和args
字段在pod
创建后无法被修改.
为容器设置环境变量
Kubernetes
允许为pod
中每一个容器都指定自定义的环境变量集合.
与容器的命令和参数设置相同, 环境变量列表无法在pod
创建后被修改.
在容器定义中指定环境变量
1 | kind: Pod |
在每个容器中, Kubernetes
会自动暴露相同命名空间下每个service
对应的黄金变量. 这些环境变量基本上可以被看作自动注入的配置.
了解硬编码环境变量的不足之处
pod
定义硬编码意味着需要有效区分生产环境与开发过程中的pod
定义. 为了能在多个环境下复用pod
的定义, 需要将配置从pod
定义描述中解耦出来.
利用ConfigMap
解耦配置
应用配置的关键在于能够在多个环境中区分配置选项, 将配置从应用程序源码中分离, 可频繁变更配置值.
ConfigMap
介绍
Kubernetes
允许将配置选项分离到单独的资源对象ConfigMap
中, 本质上就是一个键/
值对映射, 值可以是短字面量, 也可以是完整的配置文件.
应用无须直接读取ConfigMap
, 甚至根本不需要知道其是否存在. 映射的内容通过环境变量或者卷文件的形式传递给容器, 而非直接传递给容器. 命令行参数的定义中可以通过$(ENV_VAR)
语法引用环境变量, 因而可以达到将ConfigMap
条目当作命令行参数传递给进程的效果.
当然, 应用程序同样可以通过Kubernetes Rest API
按需直接读取ConfigMap
的内容. 不过除非是需求如此, 应尽可能使你的应用保持对Kubernetes
的无感知.
创建ConfigMap
使用指令kubectl
创建ConfigMap
1 | kubectl create configmap <configMap的名字> --from-literal=<键>=<值> |
键只能包含数字, 字母, 破折号, 下画线以及圆点. --from-literal
参数用于指定多个条目.
1 | apiVersion: v1 |
从文件内容创建ConfigMap
条目
ConfigMap
同样可以存储粗粒度的配置数据, 比如完整的配置文件.
1 | kubectl create configmap <configmap的名字> --from-file=<配置文件名> |
运行上述命令时, kubectl
会在当前目录下查找配置文件, 并将文件内容存储在ConfigMap
中以配置文件名为键名的条目下. 也可以手动指定键名
1 | kubectl create configmap <configmap的名字> --from-file=<键>=<配置文件名> |
从文件夹创建ConfigMap
1 | kubectl create configmap <configmap的名字> --from-file=/path/to/dir |
这种情况下, kubectl
会为文件夹中的每个文件单独创建条目, 仅限于那些文件名可作为合法ConfigMap
键名的文件.
给容器传递ConfigMap
条目作为环境变量
1 | apiVersion: v1 |
引用不存在ConfigMap
的容器会启动失败. 当之后创建了这个缺失的ConfigMap
, 失败的容器会自动启动, 无须重新创建pod
.
可以标记对ConfigMap
的引用时可选的(设置configMapKeyRef.optional: true
). 这样, 即便ConfigMap
不存在, 容器也能正常启动.
一次性传递ConfigMap
的所有条目作为环境变量
1 | spec: |
前缀设置是可选的, 若不设置前缀值, 环境变量的名称与ConfigMap
中的键名相同.
传递Configmap
条目作为命令行参数
在字段pod.spec.containers.args
中无法直接引用ConfigMap
的条目, 但是可以利用ConfigMap
条目初始化某个环境变量, 然后再在参数字段中引用该环境变量.
使用ConfigMap
卷将条目暴露为文件
环境变量或者命令行参数值作为配置值通常适用于变量值较短的场景.
configMap
卷会将ConfigMap
中每个条目均暴露成一个文件. 运行在容器中的进程可通过读取文件内容获得对应的条目值.
1 | volumes: |
卷内暴露指定的ConfigMap
条目
1 | volumes: |
ConfigMap独立条目作为文件被挂载且不隐藏文件夹中的其他文件
假设拥有一个包含文件myconfig.conf
的configMap
卷, 希望能将奇添加为/etc
文件夹下的文件someconfig.conf
. 通过属性subPath
可以将该文件挂载的同时又不影响文件夹中的其他文件.
1 | spec: |
挂载任意一种卷时均可以使用subPath
属性. 可以选择挂载部分卷而不是挂载完整的卷. 捕获这种独立文件的挂载方式会带来文件更新上的缺陷.
为configMap
卷中的文件设置权限
configMap
卷中所有文件的权限默认被设置为644. 可以通过卷规格定义中的defaultMode
属性改变默认权限.
1 | volumes: |
更新应用配置且不重启应用程序
使用环境变量或命令行参数作为配置源的弊端在于无法在进程运行时更新配置. 将ConfigMap
暴露为卷可以达到配置热更新的效果, 无须重新创建pod
或者重启容器.
ConfigMap
被更新之后, 卷中引用它的所有文件也会相应更新, 进程发现文件被改变之后进行重载(这要进程自己实现).
挂载至已存在文件夹的文件不会更新
如果挂载的是容器中的单个文件而不是完整的卷, ConfigMap
更新之后对应的文件不会被更新.
如果现在你需要挂载单个文件并且在修改源ConfigMap
的同时会自动修改这个文件, 一种方案是挂载完整卷至不同的文件夹并创建指向文件的符号链接. 符号链接可以原生创建在容器镜像中, 也可以在容器启动时创建.
使用Secret
给容器传递敏感数据
Secret
与ConfigMap
相似, 均是键/
值对的映射, 但用于保存一些敏感数据.
默认令牌Secret
介绍
每个pod
都会默认自动挂载上一个Secret
卷, 引用一个默认的Secret
.
为二进制数据创建Secret
采用Base64
编码的原因很简单. Secret
的条目可以涵盖二进制数据, 而不仅仅是纯文本. Base64
编码可以将二进制数据转换为纯文本, 以YAML
或JSON
格式展示.
Secret
甚至可以被用来存储非敏感二进制数据, Secret
的大小限于1MB
.
stringData
字段介绍
由于并非所有敏感数据都是二进制形式, Kubernetes
允许通过Secret
的stringData
字段设置条目的纯文本值.
1 | apiVersion: v1 |
通过kubectl get -o yaml
查看Secret
时, stringData
会出现在data
字段.
在pod
中读取Secret
条目
通过secret
卷将Secret
暴露给容器之后, Secret
条目的值会被解码并以真实形式(纯文本或二进制)写入对应的文件. 通过环境变量暴露Secret
条目也是如此. 应用程序无序主动解码, 可直接读取文件内容或查找环境变量.
Secret
卷存储于内存
Secret
卷采用内存文件系统列出容器的挂载点, 由于使用的是tmpfs
, 存储在Secret
中的数据不会写入磁盘, 这就无法被窃取.
通过环境变量暴露Secret
条目
1 | env: |
kubernetes
允许通过环境变量暴露Secret
, 然而此特性的使用往往不是一个好注意. 应用程序通常会在错误报告时转储环境变量, 或者是在启动时打印在应用日志中, 无意中暴露了Secret
信息.