Difference between revisions of "Kubernetes/ConfigMap and Secrets"
| (10 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
= ConfigMap = | |||
ConfigMap object allows to manage application's configuration using Kubernetes primitives. YAML below: | ConfigMap object allows to manage application's configuration using Kubernetes primitives. YAML below: | ||
<source lang=bash> | <source lang=bash> | ||
| Line 15: | Line 16: | ||
</syntaxhighlightjs> | </syntaxhighlightjs> | ||
= ConfigMap changes behaviours = | |||
There are four possible scenarios in response to ConfigMap changes, so you can choose your implementation: | |||
1. <code>ConfigMap</code> that is mounted as a <code>subPath</code> volume has been modified. | |||
* The effect: the config file on the container won’t be updated. | |||
2. <code>ConfigMap</code> had been modified and deployed in the cluster, then we deleted the pod manually. | |||
* The effect: the new pod will mount the updated version of the resource by itself. | |||
3. <code>ConfigMap</code> has been modified; we used its hash sum in one of the Deployment annotations. | |||
* The effect: even though we updated the ConfigMap only, the Deployment has also changed. Therefore, the old pod will be automatically replaced with the new one containing the updated version of the resource. Note it will work only if you use Helm - [https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments Automatically Roll Deployments] from Helm Tip&Tricks. | |||
4. <code>ConfigMap</code> mounted as a directory has been modified. | |||
* The effect: the config file in the pod will be updated automatically, without restarting/rescheduling the pod. | |||
= ConfigMap mounted as a volume = | |||
ConfigMap mounted as <code>subPath</code> it won’t update until the pod restarts. The files are not-symlnks: | |||
<source lang=bash> | |||
$ kubectl -n production exec go-conf-example-6b4cb86569-22vqv -- ls -lha /app/configfiles | |||
total 20K | |||
drwxr-xr-x 1 root root 4.0K Mar 3 19:34 . | |||
drwxr-xr-x 1 app app 4.0K Mar 3 19:34 .. | |||
-rw-r--r-- 1 root root 42 Mar 3 19:34 config.json | |||
-rw-r--r-- 1 root root 47 Mar 3 19:34 database.yml | |||
</source> | |||
Mount it as a <code>directory</code> (without subPath), your container will get a continuously up-to-date config file. Notice in this case the files are actually the <code>sym-links</code>: | |||
<source lang=bash> | |||
$ kubectl -n production exec go-conf-example-67c768c6fc-ccpwl -- ls -lha /app/configfiles | |||
total 12K | |||
drwxrwxrwx 3 root root 4.0K Mar 3 19:40 . | |||
drwxr-xr-x 1 app app 4.0K Mar 3 19:34 .. | |||
drwxr-xr-x 2 root root 4.0K Mar 3 19:40 ..2020_03_03_16_40_36.675612011 | |||
lrwxrwxrwx 1 root root 31 Mar 3 19:40 ..data -> ..2020_03_03_16_40_36.675612011 | |||
lrwxrwxrwx 1 root root 18 Mar 3 19:40 config.json -> ..data/config.json | |||
lrwxrwxrwx 1 root root 19 Mar 3 19:40 database.yml -> ..data/database.yml | |||
</source> | |||
= ConfigMap and Secrets mounted as a volume and $ENV = | |||
{| class="wikitable" | {| class="wikitable" | ||
|+ ConfigMap | |+ ConfigMap | ||
|- | |- style="vertical-align:top;" | ||
! | ! ConfigMap value read into environment var | ||
! | ! ConfigMap mounted as a volume | ||
! Secrets mounted volume | ! Secrets mounted as a volume | ||
|- | |- style="vertical-align:top;" | ||
| <syntaxhighlightjs lang=yaml> | | <syntaxhighlightjs lang=yaml> | ||
# cat pod-configMap-env.yaml | |||
apiVersion: v1 | apiVersion: v1 | ||
kind: Pod | kind: Pod | ||
metadata: | metadata: | ||
name: | name: pod-configMap-env | ||
spec: | spec: | ||
containers: | containers: | ||
| Line 40: | Line 85: | ||
key: value1 | key: value1 | ||
</syntaxhighlightjs> | </syntaxhighlightjs> | ||
| <syntaxhighlightjs lang=yaml>apiVersion: v1 | | <syntaxhighlightjs lang=yaml> | ||
# cat pod-configMap-volume.yaml | |||
apiVersion: v1 | |||
kind: Pod | kind: Pod | ||
metadata: | metadata: | ||
name: | name: pod-configMap-volume | ||
spec: | spec: | ||
containers: | containers: | ||
| Line 58: | Line 105: | ||
</syntaxhighlightjs> | </syntaxhighlightjs> | ||
| <syntaxhighlightjs lang=yaml> | | <syntaxhighlightjs lang=yaml> | ||
# cat pod-secret-volume.yaml | |||
apiVersion: v1 | apiVersion: v1 | ||
kind: Pod | kind: Pod | ||
metadata: | metadata: | ||
name: | name: pod-secret-volume | ||
spec: | spec: | ||
containers: | containers: | ||
| Line 80: | Line 128: | ||
Deploy configMap | Deploy configMap | ||
<source lang=bash> | <source lang=bash> | ||
kubectl apply -f | kubectl apply -f pod-configMap-env.yaml # pod-configMap-volume.yaml | pod-secret-volume.yaml | ||
kubectl logs configmap-pod #Get the logs from the pod displaying the value | kubectl logs configmap-pod #Get the logs from the pod displaying the value | ||
</source> | </source> | ||
= configMap mounted as a volume with <tt>subPath</tt> = | |||
{| class="wikitable" | |||
|+ ConfigMap | |||
|- style="vertical-align:top;" | |||
! Pod manifest | |||
! ConfigMap | |||
|- style="vertical-align:top;" | |||
| <syntaxhighlightjs lang=yaml> | |||
# cat cm-configmap.yaml | |||
apiVersion: v1 | |||
kind: ConfigMap | |||
metadata: | |||
name: cm-configmap | |||
data: | |||
file1: | | |||
Line 1 in file1 | |||
file2: | | |||
Line 1 in file2 | |||
Line 2 | |||
</syntaxhighlightjs> | |||
| <syntaxhighlightjs lang=yaml> | |||
# cat pod-configMap-volume.yaml | |||
--- | |||
apiVersion: v1 | |||
kind: Pod | |||
metadata: | |||
name: centos-1 | |||
namespace: pipaw | |||
spec: | |||
containers: | |||
- name: centos | |||
image: centos:7.6.1810 | |||
command: | |||
- sleep | |||
- "7200" | |||
volumeMounts: | |||
- name: configmap-volume | |||
mountPath: /etc/file1 | |||
subPath: file1 # lookup on CM data, the filename is \ | |||
- name: configmap-volume # a data.address key here 'address' | |||
mountPath: /file2 | |||
subPath: file2 | |||
- name: configmap-volume | |||
mountPath: /etc/file2 | |||
subPath: file2 | |||
volumes: | |||
- name: configmap-volume | |||
configMap: | |||
name: cm-configmap | |||
</syntaxhighlightjs> | |||
|} | |||
{{Note|<code>SubPaths</code> are not automatically updated when a ConfigMap is modified. Changes to a ConfigMap will need to be a new deployment which would result in the pods being recreated with the updated ConfigMap content.|info}} | |||
| Line 90: | Line 196: | ||
kubectl exec configmaps-volume-kube -- cat /etc/config/key1 | kubectl exec configmaps-volume-kube -- cat /etc/config/key1 | ||
</source> | </source> | ||
= Secrets = | = Secrets = | ||
| Line 153: | Line 258: | ||
{| class="wikitable" | {| class="wikitable" | ||
|+ ConfigMap | |+ ConfigMap | ||
|- | |- style="vertical-align:top;" | ||
! As a environment | ! As a environment | ||
! Secrets mounted volume | ! Secrets mounted volume | ||
|- | |- style="vertical-align:top;" | ||
| <syntaxhighlightjs lang=yaml> | | <syntaxhighlightjs lang=yaml> | ||
apiVersion: v1 | apiVersion: v1 | ||
| Line 166: | Line 271: | ||
- name: busybox | - name: busybox | ||
image: busybox | image: busybox | ||
command: ['sh', '-c', " | command: ['sh', '-c', 'echo \"secret env variable VAR=$VAR\" && sleep 3600'] | ||
env: | env: | ||
- name: VAR | - name: VAR | ||
valueFrom: | valueFrom: | ||
secretKeyRef: | |||
name: user-creds | name: user-creds | ||
key: password | key: password | ||
</syntaxhighlightjs> | </syntaxhighlightjs> | ||
| <syntaxhighlightjs lang=yaml>apiVersion: v1 | |||
Verify | |||
<source lang=bash> | |||
kubectl logs busybox-with-secret-env | |||
"secret env variable VAR=pass123" | |||
kubectl exec -it busybox-with-secret-env -- /bin/env | grep VAR | |||
VAR=pass123 | |||
</source> | |||
| <syntaxhighlightjs lang=yaml> | |||
apiVersion: v1 | |||
kind: Pod | kind: Pod | ||
metadata: | metadata: | ||
name: busybox-with-secret-mounted | name: busybox-with-secret-volume-mounted | ||
spec: | spec: | ||
containers: | containers: | ||
- name: busybox | - name: busybox | ||
image: busybox | image: busybox | ||
command: ['sh', '-c', "echo $(cat /etc/ | command: ['sh', '-c', "echo \"Secret in the password file: $(cat /etc/user-creds/password)\" && sleep 3600"] | ||
volumeMounts: | volumeMounts: | ||
- name: | - name: secretvolume | ||
mountPath: /etc/ | mountPath: /etc/user-creds # this will be a directory | ||
readOnly: true # optional | |||
volumes: | volumes: | ||
- name: secretvolume | |||
secret: # key will be a file name | |||
secretName: user-creds # with value in the content | |||
</syntaxhighlightjs> | </syntaxhighlightjs> | ||
Verify | |||
<source lang=bash> | |||
kubectl logs busybox-with-secret-volume-mounted | |||
Secret in the password file: pass123 | |||
kubectl -n secrets exec -it busybox-with-secret-volume-mounted -- /bin/ls -la /etc/user-creds | |||
total 4 # note symlinks, these cause issues if you think to do cat /etc/user-creds/* | |||
drwxrwxrwt 3 root root 120 Oct 20 20:08 . | |||
drwxr-xr-x 1 root root 4096 Oct 20 20:08 .. | |||
drwxr-xr-x 2 root root 80 Oct 20 20:08 ..2019_10_20_20_08_32.538523033 | |||
lrwxrwxrwx 1 root root 31 Oct 20 20:08 ..data -> ..2019_10_20_20_08_32.538523033 | |||
lrwxrwxrwx 1 root root 15 Oct 20 20:08 password -> ..data/password | |||
lrwxrwxrwx 1 root root 11 Oct 20 20:08 user -> ..data/user | |||
kubectl exec busybox-with-secret-volume-mounted -- /bin/cat /etc/user-creds/{user,password}; echo | |||
johnpass123 | |||
</source> | |||
|} | |} | ||
= Patch a secret content = | |||
<source lang=bash> | |||
cat >cert-1.pfx <<-EOF | |||
foo | |||
EOF | |||
k create secret generic cert.pfx --from-file=cert-1.pfx | |||
k get secret cert.pfx -ojson | jq -r '.data."cert-1.pfx"' | base64 -d | |||
Piotr | |||
cat >cert-2.pfx <<-EOF | |||
bar | |||
EOF | |||
# Patch with base64 | |||
kubectl patch secret cert.pfx -p="{\"data\":{\"cert-1.pfx\": \"$(base64 cert-2.pfx)\"}}" -v=1 | |||
k get secret cert.pfx -ojson | jq -r '.data."cert-1.pfx"' | base64 -d | |||
bar | |||
# Patch with clear text | |||
kubectl patch secret cert.pfx -p="{\"stringData\":{\"cert-1.pfx\": \"No Base64 updade string\"}}" -v=1 | |||
k get secret cert.pfx -ojson | jq -r '.data."cert-1.pfx"' | base64 -d | |||
No Base64 updade string | |||
</source> | |||
= configMap reload = | |||
* [https://github.com/jimmidyson/configmap-reload Kubernetes ConfigMap Reload] - trigger a reload when Kubernetes ConfigMaps are updated. It watches mounted volume dirs and notifies the target process that the config map has been changed. Used by prometheus as a sidecar | |||
<syntaxhighlightjs lang="powershell"> | |||
kind: Pod | |||
apiVersion: v1 | |||
metadata: | |||
name: prometheus-788c945c9c-vpv4s | |||
#... | |||
spec: | |||
volumes: | |||
- name: config-volume | |||
configMap: | |||
name: prometheus | |||
defaultMode: 420 | |||
#... | |||
containers: | |||
- name: prometheus-server-configmap-reload | |||
image: 'jimmidyson/configmap-reload:v0.3.0' # latest v0.4.0 | |||
args: | |||
- '--volume-dir=/etc/config' | |||
- '--webhook-url=http://127.0.0.1:9090/-/reload' | |||
resources: {} | |||
volumeMounts: | |||
- name: config-volume | |||
readOnly: true | |||
mountPath: /etc/config | |||
</syntaxhighlightjs> | |||
=References= | =References= | ||
*[https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ configure-pod-configmap] | *[https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ configure-pod-configmap] | ||
*[https://kubernetes.io/docs/concepts/configuration/secret/ Secretes] | *[https://kubernetes.io/docs/concepts/configuration/secret/ Secretes] | ||
Latest revision as of 11:22, 11 January 2021
ConfigMap
ConfigMap object allows to manage application's configuration using Kubernetes primitives. YAML below:
kubectl create configmap my-config-map --namespace=web -oyaml --dry-run > config-map.yml
<syntaxhighlightjs lang=yaml> apiVersion: v1 kind: ConfigMap metadata:
creationTimestamp: null name: my-config-map namespace: web
data: # added when editing
myKey: myValue1 anotherKey: myValue2
</syntaxhighlightjs>
ConfigMap changes behaviours
There are four possible scenarios in response to ConfigMap changes, so you can choose your implementation:
1. ConfigMap that is mounted as a subPath volume has been modified.
- The effect: the config file on the container won’t be updated.
2. ConfigMap had been modified and deployed in the cluster, then we deleted the pod manually.
- The effect: the new pod will mount the updated version of the resource by itself.
3. ConfigMap has been modified; we used its hash sum in one of the Deployment annotations.
- The effect: even though we updated the ConfigMap only, the Deployment has also changed. Therefore, the old pod will be automatically replaced with the new one containing the updated version of the resource. Note it will work only if you use Helm - Automatically Roll Deployments from Helm Tip&Tricks.
4. ConfigMap mounted as a directory has been modified.
- The effect: the config file in the pod will be updated automatically, without restarting/rescheduling the pod.
ConfigMap mounted as a volume
ConfigMap mounted as subPath it won’t update until the pod restarts. The files are not-symlnks:
$ kubectl -n production exec go-conf-example-6b4cb86569-22vqv -- ls -lha /app/configfiles total 20K drwxr-xr-x 1 root root 4.0K Mar 3 19:34 . drwxr-xr-x 1 app app 4.0K Mar 3 19:34 .. -rw-r--r-- 1 root root 42 Mar 3 19:34 config.json -rw-r--r-- 1 root root 47 Mar 3 19:34 database.yml
Mount it as a directory (without subPath), your container will get a continuously up-to-date config file. Notice in this case the files are actually the sym-links:
$ kubectl -n production exec go-conf-example-67c768c6fc-ccpwl -- ls -lha /app/configfiles total 12K drwxrwxrwx 3 root root 4.0K Mar 3 19:40 . drwxr-xr-x 1 app app 4.0K Mar 3 19:34 .. drwxr-xr-x 2 root root 4.0K Mar 3 19:40 ..2020_03_03_16_40_36.675612011 lrwxrwxrwx 1 root root 31 Mar 3 19:40 ..data -> ..2020_03_03_16_40_36.675612011 lrwxrwxrwx 1 root root 18 Mar 3 19:40 config.json -> ..data/config.json lrwxrwxrwx 1 root root 19 Mar 3 19:40 database.yml -> ..data/database.yml
ConfigMap and Secrets mounted as a volume and $ENV
| ConfigMap value read into environment var | ConfigMap mounted as a volume | Secrets mounted as a volume |
|---|---|---|
<syntaxhighlightjs lang=yaml>
apiVersion: v1 kind: Pod metadata: name: pod-configMap-env spec: containers:
- name: nginx
image: nginx
command: ['sh', '-c', "echo $(VAR) && sleep 600"]
env:
- name: VAR
valueFrom:
configMapKeyRef:
name: kubeapp-config
key: value1
</syntaxhighlightjs> |
<syntaxhighlightjs lang=yaml>
apiVersion: v1 kind: Pod metadata: name: pod-configMap-volume spec: containers:
- name: nginx
image: nginx
command: ['sh', '-c', "echo $(cat /etc/config/myKey && sleep 3600"]
volumeMounts:
- name: configmapvolume
mountPath: /etc/config # this will be a directory
volumes:
- name: configmapvolume
configMap: # key will be a file name
name: kube-configmap # with value in content
</syntaxhighlightjs> |
<syntaxhighlightjs lang=yaml>
apiVersion: v1 kind: Pod metadata: name: pod-secret-volume spec: containers:
- name: nginx
image: nginx
command: ['sh', '-c', "echo $(MY_VAR) && sleep 3600"]
volumeMounts:
- name: secretvolume
mountPath: /etc/certs
volumes:
- name: secretvolume
secret:
secretName: kube-secret
</syntaxhighlightjs> |
Deploy configMap
kubectl apply -f pod-configMap-env.yaml # pod-configMap-volume.yaml | pod-secret-volume.yaml kubectl logs configmap-pod #Get the logs from the pod displaying the value
configMap mounted as a volume with subPath
| Pod manifest | ConfigMap |
|---|---|
<syntaxhighlightjs lang=yaml>
apiVersion: v1 kind: ConfigMap metadata: name: cm-configmap data: file1: | Line 1 in file1 file2: | Line 1 in file2 Line 2 </syntaxhighlightjs> |
<syntaxhighlightjs lang=yaml>
--- apiVersion: v1 kind: Pod metadata: name: centos-1 namespace: pipaw spec: containers:
- name: centos
image: centos:7.6.1810
command:
- sleep
- "7200"
volumeMounts:
- name: configmap-volume
mountPath: /etc/file1
subPath: file1 # lookup on CM data, the filename is \
- name: configmap-volume # a data.address key here 'address'
mountPath: /file2
subPath: file2
- name: configmap-volume
mountPath: /etc/file2
subPath: file2
volumes:
- name: configmap-volume
configMap:
name: cm-configmap
</syntaxhighlightjs> |
Note: SubPaths are not automatically updated when a ConfigMap is modified. Changes to a ConfigMap will need to be a new deployment which would result in the pods being recreated with the updated ConfigMap content.
Another way to provide values from a ConfigMap is to mount as a container's volume. The keys you can see within the container
kubectl exec configmaps-volume-kube -- ls /etc/config kubectl exec configmaps-volume-kube -- cat /etc/config/key1
Secrets
Secrets types:
SecretType = "Opaque" // Opaque (arbitrary data; default) SecretType = "kubernetes.io/service-account-token" // Kubernetes auth token SecretType = "kubernetes.io/dockercfg" // Docker registry auth SecretType = "kubernetes.io/dockerconfigjson" // Latest Docker registry auth
Create secrets
kubectl create secret generic user-creds --from-literal=pass=pass123 --from-literal=user=john --save-config -oyaml --dry-run=true --type=Opaque > secrets.yaml
<syntaxhighlightjs lang=yaml> apiVersion: v1 kind: Secret metadata:
creationTimestamp: null name: user-creds
data: # keys contain b64 encoded values
pass: cGFzczEyMw== user: am9obg==
type: Opaque </syntaxhighlightjs>
Another secret. stringData: specifying non-binary secret data in string form. It is provided as a write-only convenience method. All keys and values are merged into the data field on write.
<syntaxhighlightjs lang=yaml>
apiVersion: v1
kind: Secret
metadata:
name: kube-secret
stringData: # literal string, keys' values will be b64 encoded on write
cert: 1234abc key: ca.crt
</syntaxhighlightjs>
Describe secrets
kubectl describe secrets kube-secret Name: kube-secret Namespace: default Labels: <none> Annotations: Type: Opaque Data ==== cert: 5 bytes key: 5 bytes
Reference secrets in pod spec
kubectl create secret generic user-creds --from-literal=user=john --from-literal=password=pass123 --save-config -oyaml --type=Opaque --dry-run=true
| As a environment | Secrets mounted volume |
|---|---|
| <syntaxhighlightjs lang=yaml>
apiVersion: v1 kind: Pod metadata: name: busybox-with-secret-env spec: containers:
- name: busybox
image: busybox
command: ['sh', '-c', 'echo \"secret env variable VAR=$VAR\" && sleep 3600']
env:
- name: VAR
valueFrom:
secretKeyRef:
name: user-creds
key: password
</syntaxhighlightjs>
kubectl logs busybox-with-secret-env "secret env variable VAR=pass123" kubectl exec -it busybox-with-secret-env -- /bin/env | grep VAR VAR=pass123 |
<syntaxhighlightjs lang=yaml>
apiVersion: v1 kind: Pod metadata: name: busybox-with-secret-volume-mounted spec: containers:
- name: busybox
image: busybox
command: ['sh', '-c', "echo \"Secret in the password file: $(cat /etc/user-creds/password)\" && sleep 3600"]
volumeMounts:
- name: secretvolume
mountPath: /etc/user-creds # this will be a directory
readOnly: true # optional
volumes:
- name: secretvolume
secret: # key will be a file name
secretName: user-creds # with value in the content
</syntaxhighlightjs> Verify kubectl logs busybox-with-secret-volume-mounted
Secret in the password file: pass123
kubectl -n secrets exec -it busybox-with-secret-volume-mounted -- /bin/ls -la /etc/user-creds
total 4 # note symlinks, these cause issues if you think to do cat /etc/user-creds/*
drwxrwxrwt 3 root root 120 Oct 20 20:08 .
drwxr-xr-x 1 root root 4096 Oct 20 20:08 ..
drwxr-xr-x 2 root root 80 Oct 20 20:08 ..2019_10_20_20_08_32.538523033
lrwxrwxrwx 1 root root 31 Oct 20 20:08 ..data -> ..2019_10_20_20_08_32.538523033
lrwxrwxrwx 1 root root 15 Oct 20 20:08 password -> ..data/password
lrwxrwxrwx 1 root root 11 Oct 20 20:08 user -> ..data/user
kubectl exec busybox-with-secret-volume-mounted -- /bin/cat /etc/user-creds/{user,password}; echo
johnpass123
|
Patch a secret content
cat >cert-1.pfx <<-EOF
foo
EOF
k create secret generic cert.pfx --from-file=cert-1.pfx
k get secret cert.pfx -ojson | jq -r '.data."cert-1.pfx"' | base64 -d
Piotr
cat >cert-2.pfx <<-EOF
bar
EOF
# Patch with base64
kubectl patch secret cert.pfx -p="{\"data\":{\"cert-1.pfx\": \"$(base64 cert-2.pfx)\"}}" -v=1
k get secret cert.pfx -ojson | jq -r '.data."cert-1.pfx"' | base64 -d
bar
# Patch with clear text
kubectl patch secret cert.pfx -p="{\"stringData\":{\"cert-1.pfx\": \"No Base64 updade string\"}}" -v=1
k get secret cert.pfx -ojson | jq -r '.data."cert-1.pfx"' | base64 -d
No Base64 updade string
configMap reload
- Kubernetes ConfigMap Reload - trigger a reload when Kubernetes ConfigMaps are updated. It watches mounted volume dirs and notifies the target process that the config map has been changed. Used by prometheus as a sidecar
<syntaxhighlightjs lang="powershell"> kind: Pod apiVersion: v1 metadata:
name: prometheus-788c945c9c-vpv4s
- ...
spec:
volumes:
- name: config-volume
configMap:
name: prometheus
defaultMode: 420
- ...
containers:
- name: prometheus-server-configmap-reload
image: 'jimmidyson/configmap-reload:v0.3.0' # latest v0.4.0
args:
- '--volume-dir=/etc/config'
- '--webhook-url=http://127.0.0.1:9090/-/reload'
resources: {}
volumeMounts:
- name: config-volume
readOnly: true
mountPath: /etc/config
</syntaxhighlightjs>