概述
本文的核心是:如何處理應用程式的資料配置。
配置應用程式可以使用以下幾種途徑:
- 向容器傳遞命令列引數
- 為每個容器配置環境變數
- 通過特殊的卷將配置檔案掛載到容器中
向容器傳遞命令列引數
在Kubernetes中定義容器時,映象的ENTRYPOINT和CMD都可以被覆蓋(但是在Docker中,映象的ENTRYPOINT是不能覆蓋的)。僅需在容器定義中設定command和args的值。
構建一個映象
loopechodate.sh:接收一個時間間隔的引數,追加輸出當前時間到 /tmp/a.txt
#! /bin/sh
trap "exit" SIGINT
echo "interval is : $1"
while :
do
echo -e "$(date)" >> /tmp/a.txt
sleep $1
done
Dockerfile
FROM alpine
COPY loopechodate.sh /bin/
ENTRYPOINT ["/bin/loopechodate.sh"]
CMD ["5"]
構建、推送
-> [root@kube0.vm] [~] docker build -t registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate .
-> [root@kube0.vm] [~] docker push registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate
執行Pod
# cat config-cli.yaml
apiVersion: v1
kind: Pod
metadata:
name: config-cli
spec:
containers:
- name: config-cli
image: registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate
args: ["2"] # 間隔時間2s
建立這個pod,然後檢視一下logs
-> [root@kube0.vm] [~] k create -f config-cli.yaml
pod/config-cli created
-> [root@kube0.vm] [~] k exec -it config-cli cat /tmp/a.txt
Sun May 24 15:49:37 UTC 2020
Sun May 24 15:49:39 UTC 2020
為容器設定環境變數
Kubernetes中通過容器的env屬性定義環境變數,採用$(VAR)語法在環境變數值中引用其他變數。
定義了兩個環境變數FIRST_VAR,和引用了FIRST_VAR的SECOND_VAR。
# config-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: config-env
spec:
containers:
- name: config-env
image: nginx:alpine
env:
- name: FIRST_VAR
value: "Hello"
- name: SECOND_VAR
value: "$(FIRST_VAR) World!"
建立檢視
-> [root@kube0.vm] [~] k create -f config-env.yaml
pod/config-env created
-> [root@kube0.vm] [~] k exec config-env env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=config-env
FIRST_VAR=Hello
SECOND_VAR=Hello World!
.......
ConfigMap
ConfigMap本質上是一個鍵值對,值可以使短字面量,也可以是檔案
建立ConfigMap
kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run] [options]
kubectl create命令支援從字面量(--from-literal),檔案、目錄(--from-file)、以及環境變數檔案(--from-env-file)建立。而且不同選項可以合併,但是--from-env-file不能與--from-literal和--from-file一起指定。
下面是使用字面量、檔案、目錄合併建立。
-> [root@kube0.vm] [~] k create configmap mycm --from-literal=interval=3 --from-file=Dockerfile --from-file=/root/configdir
configmap/mycm created
-> [root@kube0.vm] [~] k describe cm mycm
Name: mycm
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
Dockerfile:
----
FROM alpine
COPY loopechodate.sh /bin/
ENTRYPOINT ["/bin/loopechodate.sh"]
CMD ["5"]
a.txt:
----
this is configdir/a.txt
b.txt:
----
this is configdir/b.txt
interval:
----
3
Events: <none>
使用環境變數檔案建立
-> [root@kube0.vm] [~] echo -e "env1=1111\nenv2=2222" | tee test.env
env1=1111
env2=2222
-> [root@kube0.vm] [~] k create cm envcm --from-env-file=test.env
configmap/envcm created
-> [root@kube0.vm] [~] k describe cm envcm
Name: envcm
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
env1:
----
1111
env2:
----
2222
Events: <none>
傳遞ConfigMap條目作為環境變數
定義一個Pod,引用了mycm中的兩個key。
# config-env-cm.yaml
apiVersion: v1
kind: Pod
metadata:
name: config-env-cm
spec:
containers:
- name: config-env-cm
image: nginx:alpine
env:
- name: INTERVAL
valueFrom:
configMapKeyRef: # 引用configMap中的內容
name: mycm # configMap的名字
key: interval # 引用哪個鍵
- name: ATXT
valueFrom:
configMapKeyRef:
name: mycm
key: a.txt
建立檢視
-> [root@kube0.vm] [~] k create -f config-env-cm.yaml
pod/config-env-cm created
-> [root@kube0.vm] [~] k exec config-env-cm env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=config-env-cm
INTERVAL=3
ATXT=this is configdir/a.txt
....
一次性傳遞ConfigMap所有條目作為環境變數
# config-env-cmall.yaml
apiVersion: v1
kind: Pod
metadata:
name: config-env-cmall
spec:
containers:
- name: config-env-cmall
image: nginx:alpine
envFrom:
- prefix: CONFIG_
configMapRef:
name: mycm
建立檢視
-> [root@kube0.vm] [~] k create -f config-env-cmall.yaml
pod/config-env-cmall created
-> [root@kube0.vm] [~] k exec config-env-cmall env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=config-env-cmall
CONFIG_interval=3
CONFIG_Dockerfile=FROM alpine
COPY loopechodate.sh /bin/
ENTRYPOINT ["/bin/loopechodate.sh"]
CMD ["5"]
CONFIG_a.txt=this is configdir/a.txt
CONFIG_b.txt=this is configdir/b.txt
........
傳遞ConfigMap條目作為命令列引數
containers.args
無法直接引用ConfigMap,但是可以通過$(ENV_VAR_NAME)引用環境變數,間接引用ConfigMap。
# config-cli-cm.yaml
apiVersion: v1
kind: Pod
metadata:
name: config-cli-cm
spec:
containers:
- name: config-cli-cm
image: registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate
env:
- name: INTERVAL
valueFrom:
configMapKeyRef:
name: mycm
key: interval
args: ["$(INTERVAL)"]
建立檢視
-> [root@kube0.vm] [~] k create -f config-cli-cm.yaml
pod/config-cli-cm created
-> [root@kube0.vm] [~] k logs config-cli-cm
interval is : 3
-> [root@kube0.vm] [~] k exec config-cli-cm cat /tmp/a.txt
Mon May 25 05:11:14 UTC 2020
Mon May 25 05:11:17 UTC 2020
Mon May 25 05:11:20 UTC 2020
將ConfigMap條目暴露為卷
環境變數和命令列引數作為配置值通常適用於變數值較短的場景。如果想暴露ConfigMap中配置檔案,可以將ConfigMap或者其條目通過卷的形式掛載到容器。
# config-volume-cm.yaml
apiVersion: v1
kind: Pod
metadata:
name: config-volume-cm
spec:
containers:
- name: config-volume-cm
image: nginx:alpine
volumeMounts:
- name: config
mountPath: /tmp/mycm
readOnly: true
volumes:
- name: config
configMap:
name: mycm
建立檢視
-> [root@kube0.vm] [~] k create -f config-volume-cm.yaml
pod/config-volume-cm created
-> [root@kube0.vm] [~] k exec config-volume-cm ls /tmp/mycm
Dockerfile
a.txt
b.txt
interval
如果只想暴露指定的條目,可以指定volumes.configMap.items
。
volumes:
- name: config
configMap:
name: mycm
items:
- key: interval
path: interval2
輸出結果是:
-> [root@kube0.vm] [~] k exec config-volume-cm ls /tmp/mycm
interval2
configMap.defaultMode
設定訪問許可權
掛載資料夾會隱藏該資料夾中已存在的檔案,掛載ConfigMap的單獨條目不會隱藏其他檔案
Secret
Secret與ConfigMap一樣都是鍵值對,也可以作為環境變數傳遞給容器,條目也能暴露稱為卷中的檔案。但是為了安全起見,請始終使用Secret卷暴露Secret。Secret只會儲存在記憶體中,永不寫入物理儲存。Secret條目的內容會被進行Base64編碼。
預設令牌
每個pod預設都會掛載一個Secret,該Secret包含ca.crt、namespace、token,包含了從Pod內部安全訪問Kubernetes Api伺服器所需的全部資訊。
先隨便找一個pod檢視。
-> [root@kube0.vm] [~] k describe pod config-volume-cm
Name: config-volume-cm
Namespace: default
......
Mounts:
/tmp/mycm from config (ro)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5g447 (ro)
......
Volumes:
......
default-token-5g447:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-5g447
Optional: false
......
再檢視一下詳情
-> [root@kube0.vm] [~] k describe secrets default-token-5g447
Name: default-token-5g447
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: bd92a729-ed0a-491d-b600-0f86824ad588
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1....
使nginx支援https
建立私鑰和證書
-> [root@kube0.vm] [~/cert] openssl genrsa -o https.key 2048
-> [root@kube0.vm] [~/cert] openssl req -new -x509 -key https.key -out https.cert -days 3650 -subj /CN=www.mysecret.com
建立Secret
建立一個型別為generic的Secret,其他兩個型別是docker-registry、tls。
-> [root@kube0.vm] [~/cert] echo bar > foo # 後面會用到
-> [root@kube0.vm] [~/cert] k create secret generic mysecret --from-file=./
secret/mysecret created
將ssl.conf放入ConfigMap中
# ssl.conf
server {
listen 80;
listen 443 ssl;
server_name www.mysecret.com;
ssl_certificate certs/https.cert;
ssl_certificate_key certs/https.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
-> [root@kube0.vm] [~] k create configmap sslcm --from-file=ssl.conf
configmap/sslcm created
建立檢視
先看一下描述檔案
# https-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: https-nginx
spec:
containers:
- name: https-nginx
image: nginx:alpine
env:
- name: FOO
valueFrom:
secretKeyRef:
name: mysecret
key: foo
volumeMounts:
- name: sslcm
mountPath: /etc/nginx/conf.d/
readOnly: true
- name: mysecret
mountPath: /etc/nginx/certs/
readOnly: true
ports:
- containerPort: 80
- containerPort: 443
volumes:
- name: sslcm
configMap:
name: sslcm
items:
- key: ssl.conf
path: https.conf
- name: mysecret
secret:
secretName: mysecret
建立、設定埠轉發
-> [root@kube0.vm] [~] k create -f https-nginx.yaml
pod/https-nginx created
-> [root@kube0.vm] [~] k port-forward https-nginx 443:443
Forwarding from 127.0.0.1:443 -> 443
新開視窗,傳送請求
-> [root@kube0.vm] [~] curl -k https://localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
.....
檢視Secret通過環境變數暴露的條目
-> [root@kube0.vm] [~] k exec https-nginx env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=https-nginx
FOO=bar
.......
使用私有的映象倉庫
使用方法:建立一個docker-registry型別的secret,然後
建立一個docker-registry型別的secret。 --docker-server 用於指定倉庫服務的地址。
k create secret docker-registry dockerregsecret --docker-username=zhangsan --docker-password=123 --docker-email=zhangsan@163.com
在Pod中的containers.imagePullSecrets.name
中引用。
apiVersion: v1
kind: Pod
metadata:
name: private-pod
spec:
imagePullSecrets:
- name: dockerregsecret
containers:
- image: username/private:tag
name: main
StringData與二進位制資料
採用Base64編碼,使Secret也能儲存二進位制資料,而純文字值可以在secret.StringData
中定義,但StringData欄位是隻寫的,kubectl get -o yaml
檢視時會被Base64編碼顯示在data下。
注意事項
- 在Kubernetes中定義容器時,映象的ENTRYPOINT和CMD都可以被覆蓋。但是在Docker中,映象的ENTRYPOINT是不能覆蓋的。
- 可以將
configMapKeyRef.optional
設定為true,這樣即使ConfigMap不存在,容器也能啟動。
小結
- 對於環境變數:使用
valueFrom.configMapKeyRef
引用一個ConfigMap條目;使用envFrom.configMapRef
引用全部,envFrom.prefix
設定字首。 - 對於命令列引數:
containers.args
無法直接引用ConfigMap,但是可以通過$(ENV_VAR_NAME)引用環境變數,間接引用了ConfigMap。 - 掛載資料夾會隱藏該資料夾中已存在的檔案,掛載ConfigMap的單獨條目不會隱藏其他檔案
- 將ConfigMap暴露為卷可以達到熱更新的效果。
- 每個pod預設都會掛載一個Secret,該Secret包含ca.crt、namespace、token,包含了從Pod內部安全訪問Kubernetes Api伺服器所需的全部資訊。
- 採用Base64編碼,使Secret也能儲存二進位制資料,而純文字值可以在
secret.StringData
中定義,但StringData欄位是隻寫的,kubectl get -o yaml
檢視時會被Base64編碼顯示在data下。