一、向容器传递命令行参数
1.1. 在 Docker 中定义命令与参数
容器中运行的完整指令由两部分组成:命令与参数。
ENTRYPOINT 与 CMD:
- ENTRYPOINT:定义容器启动时被调用的可执行程序。
- CMD:指定传递给 ENTRYPOINT 的参数。
尽管可以直接使用 CMD 指令指定镜像运行时想要执行的命令,正确的做法依旧是借助 ENTRYPOINT 指令,仅仅用 CMD 指定所需的默认参数。这样,镜像可以直接运行,无须添加任何参数:
docker run <image>
或者是添加一些参数,覆盖 Dockerfile 中任何由 CMD 指定的默认参数值:
docker run <image> <arguments>
shell 与 exec 形式的区别:
- shell 形式:如 ENTRYPOINT node app.js
- exec 形式:如 ENTRYPOINT [“node”, “app.js”]
两者的区别在于指定的命令是否是在 shell 中被调用。exec 形式的 ENTRYPOINT 指令是直接运行 node 进程;shell 形式的指令主进程(PID 1)是 shell 进程而非 node 进程,node 进程于 shell 中启动。shell 进程往往是多余的,因此通常可以直接采用 exec 形式的 ENTRYPOINT 指令。
实例:
luksa/fortune:args 镜像中的运行脚本:
1 | #!/bin/bash |
luksa/fortune:args 的 Dockerfile 内容:
1 | FROM ubuntu:latest |
测试:
1 | docker run -it luksa/fortune:args # 默认的 10 秒钟 |
1.2. 在 Kubernetes 中覆盖命令和参数
在 Kubernetes 中定义容器时,镜像的 ENTRYPOINT 和 CMD 均可以被覆盖,仅需要在容器定义中设置 command 和 args 的值:
1 | kind: Pod |
注意:command 和 args 字段在 pod 创建后无法被修改。绝大多数情况下,只需要设置自定义参数。命令一般很少被覆盖,除非针对一些未定义 ENTRYPOINT 的通用镜像。
二、为容器设置环境变量
在容器定义中指定环境变量:
1 | apiVersion: v1 |
在环境变量值中引用其他环境变量:
1 | env: |
三、利用 ConfigMap 解耦配置
Kubernetes 允许将配置选项分离到单独的资源对象 ConfigMap 中,本质上就是一个键/值对映射,值可以是短字面量,也可以是完整的配置文件。应用无须直接读取 ConfigMap,甚至根本不需要知道其是否存在。映射的内容通过环境变量或者卷文件的形式传递给容器,而并非直接传递给容器。
3.1. 创建 ConfigMap
3.1.1. 使用指令创建 ConfigMap
kubectl create configmap fortune-config --from-literal=sleep-interval=25
创建了一个叫 fortune-config 的 ConfigMap,只包含一个条目。也可以添加多个条目:
kubectl create configmap myconfigmap --from-literal=foo=bar --from-literal=bar=baz --from-literal=one=two
注意:ConfigMap 中的键名必须是一个合法的 DNS 子域,仅包含数字字母、破折号、下划线以及圆点。
查看创建的 ConfigMap 的 YAML 格式的定义描述:
kubectl get configmap fortune-config -o yaml
3.1.2. 从文件内容创建 ConfigMap 目录
kubectl create configmap my-config --from-file=config-file.conf
默认使用文件名作为键名,也可以手动指定键名:
kubectl create configmap my-config --from-file=customkey=config file.conf
多次使用 –from-file 参数可增加多个文件条目。
3.1.3. 从文件夹创建 ConfigMap
kubectl create configmap my -config --from-file=/path/to/dir
为文件夹中的每个文件单独创建条目,仅限于那些文件名可作为合法 ConfigMap 键名的文件
3.1.4. 合并不同选项
1 | kubectl create configmap my -config |
3.2. 给容器传递 ConfigMap 条目作为环境变量
1 | apiVersion: v1 |
在 pod 中引用不存在的 ConfigMap,如果没有设置 configMapKeyRef.optional: true 则容器会启动失败,如果之后创建了这个缺失的 ConfigMap,失败容器会自动启动,无须重新创建 pod
3.3. 一次性传递 ConfigMap 的所有条目作为环境变量
1 | spec: |
3.4. 传递 ConfigMap 条目作为命令行参数
1 | apiVersion: v1 |
3.5. 使用 ConfigMap 卷将条目暴露为文件
3.5.1. 创建 ConfigMap
新建文件夹 configmap-files 并将 my-nginx-config.conf 和 sleep-interval 放置在文件夹下:
1 | # my-nginx-config.conf |
1 | # sleep-interval |
先删除之前创建的 ConfigMap:
kubectl delete configmap fortune-config
新建 ConfigMap:
kubectl create configmap fortune-config --from-file=configmap-files
查看:
kubectl get configmap fortune-config -o yaml
3.5.2. 在卷内使用 ConfigMap 的条目
1 | # fortune-pod-configmap-volume.yaml |
创建:
kubectl create -f fortune-pod-configmap-volume.yaml
验证:
kubectl port-forward fortune-configmap-volume 8080:80 &
curl -H "Accept-Encoding: gzip" -I localhost:8080
输出:
1 | ... ... |
注意:挂载某一文件夹会隐藏该文件夹中已存在的文件
3.5.3. 卷内暴露指定的 ConfigMap 条目
1 | volumes: |
spec:
containers:
- image: some/image
volumeMounts:- name: myvolume
mountPath: /etc/someconfig.conf # 挂载至某一文件而不是文件夹
subPath: myconfig.conf #仅挂载指定的条目 myconfig.conf 并非完整的卷
- name: myvolume
1 |
|
volumes:
- name: html
emptyDir: {} - name: config
configMap:
name: fortune-config
defaultMode: 0660 # 设置所有文件的权限为 -rw-rw——… …1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
## 3.6. 更新应用配置且不重启应用程序
使用环境变量或者命令行参数作为配置源的弊端在于无法在进程运行时更新配置。将 ConfigMap 暴露为卷可以达到配置热更新的效果,无须重新创建 pod 或者重启容器。ConfigMap 被更新之后,卷中引用它的所有文件也会相应更新,进程发现文件被改变之后进行重载。Kubernetes 同样支待文件更新之后手动通知容器。
修改 ConfigMap:
```kubectl edit configmap fortune-config```
将 gzip on 改为 gzip off,ConfigMap 被更新不久之后会自动更新卷中的对应文件,查看:
```kubectl exec fortune-configmap-volume -c web-server -- cat /etc/nginx/conf.d/my-nginx-config.conf```
通知 Nginx 重载配置:
```kubectl exec fortune-configmap-volume -c web-server -- nginx -s reload```
# 四、使用 Secret 给容器传递敏感数据
Secret 的使用方法也与ConfigMap 相同,可以:
+ 将 Secret 条目作为环境变量传递给容器
+ 将 Secret 条目暴露为卷中的文件
Secret 只会存储在节点的内存中,永不写入物理存储,这样从节点上删除 Secret 时就不需要擦除磁盘
创建 Secret:
```kubectl create secret generic fortune-https --from-file=https.key --from-file=https.cert --from-file=foo```
https.key, https.cert, foo 文件内容见 [链接](https://github.com/luksa/kubernetes-in-action/tree/master/Chapter07/fortune-https)
查看:
```kubectl get secret fortune-https -o yaml```
Secret 条目的内容会被以 Base64 格式编码,这种区别导致在处理 YAML 和 JSON 格式的 Secret 时会稍许有些麻烦,可以通过 stringData 字段设置条目的纯文本值。
通过 secret 卷将 Secret 暴露给容器之后,Secret 条目的值会被解码并以真实形式(纯文本或二进制)写入对应的文件。通过环境变量暴露 Secret 条目亦是如此。在这两种情况下,应用程序均无须主动解码,可直接读取文件内容或者查找环境变量。
修改 fortune-config ConfigMap 以开启 HTTPS:
```kubectl edit configmap fortune-config```
server {
listen 80;
listen 443 ssl;
server_name www.kubia-example.com;
ssl_certificate certs/https.cert; # /etc/nginx 的相对位置
ssl_certificate_key certs/https.key; # /etc/nginx 的相对位置
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
… …
1 |
|
fortune-pod-https.yaml
apiVersion: v1
kind: Pod
metadata:
name: fortune-https
spec:
containers:
- image: luksa/fortune:env
name: html-generator
env:- name: INTERVAL
valueFrom:
configMapKeyRef:
name: fortune-config
key: sleep-interval
volumeMounts:
- name: html
mountPath: /var/htdocs
- name: INTERVAL
- image: nginx:alpine
name: web-server
volumeMounts:- name: html
mountPath: /usr/share/nginx/html
readOnly: true - name: config
mountPath: /etc/nginx/conf.d
readOnly: true - name: certs
mountPath: /etc/nginx/certs/ # 配置 Nginx 从 /etc/nginx/certs 中读取证书和密钥文件
readOnly: true
ports: - containerPort: 80
- containerPort: 443
volumes:
- name: html
- name: html
emptyDir: {} - name: config
configMap:
name: fortune-config
items:- key: my-nginx-config.conf
path: https.conf
- key: my-nginx-config.conf
- name: certs
secret:
secretName: fortune-https # secret 卷
```kubectl create -f fortune-pod-https.yaml```
测试:
```kubectl port-forward fortune-https 8443:443 &```
```curl https://localhost:8443 -k```