ConfigMaps and Secrets
Configure all key-value pairs as environment variables
kubectl apply -f config-env-vars-envFrom.yaml
configmap/myapp-config created
secret/myapp-secret created
deployment.apps/my-app created
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-6594549577-7s7ks 0/1 Completed 3 (32s ago) 60s
kubectl logs -f my-app-6594549577-7s7ks
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=my-app-6594549577-7s7ks
SHLVL=1
username=admin
HOME=/root
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
password=admin
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
db_host=mysql-service
Configure defined environment variables in the command and args of a container using the $(VAR_NAME)
kubectl apply -f config-env-vars-valueFrom.yaml
configmap/myapp-config created
secret/myapp-secret created
deployment.apps/my-app created
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-6df7cd5d47-dhd2c 0/1 Completed 0 6s
kubectl logs -f my-app-6df7cd5d47-dhd2c
admin admin mysql-service
Configure as a Volume
kubectl apply -f config-volumes.yaml
configmap/mysql-config created
secret/mysql-secret created
deployment.apps/my-db created
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-db-569cdd7c6c-mrshr 0/1 ContainerCreating 0 3s
kubectl logs -f my-db-569cdd7c6c-mrshr
/mysql/db-config/mysql.conf
[mysqld]
port=3306
socket=/tmp/mysql.sock
key_buffer_size=16M
max_allowed_packet=128M
/mysql/db-config/secure-flag
ThiS_Is_FLagggggggggg_4U@@
/mysql/db-config/test.conf
ThiS_iS_0nLy_f0R_T3st!^^
/mysql/db-secret/secret.file
Sup3r_s3cure_F1agggggggggg!^^
Because we omit the items array entirely, every key in the ConfigMap and Secret becomes a file with the same name as the key. So we get 4 files, contain 3 files from ConfigMap and 1 file from Secret.
Configure as a Volume with items
kubectl apply -f config-volumes-with-items.yaml
kubectl get pods
kubectl logs -f my-db-5f9585df5f-8fzlc
configmap/mysql-config created
secret/mysql-secret created
deployment.apps/my-db created
NAME READY STATUS RESTARTS AGE
my-db-5f9585df5f-8fzlc 0/1 Completed 0 8s
/mysql/db-config/flag.txt
ThiS_Is_FLagggggggggg_4U@@
/mysql/db-config/test.conf
ThiS_iS_0nLy_f0R_T3st!^^
/mysql/db-secret/flag.txt
Sup3r_s3cure_F1agggggggggg!^^
We defined 2 arrays of keys from the ConfigMap (not contain mysql.conf) and 1 array from Secret to create as files, the filename was changed from key to path (default is key).
Configure Redis
kubectl apply -f config-redis.yaml
configmap/example-redis-config created
deployment.apps/my-redis created
service/my-redis-service created
kubectl get svc -o wide
kubectl get pods
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 65d <none>
my-redis-service NodePort 10.105.172.53 <none> 6379:30100/TCP 35s app=my-redis
NAME READY STATUS RESTARTS AGE
my-redis-6496f6bbf8-nsgjk 1/1 Running 0 40s
Access redis server to get config and data:
kubectl exec -it my-redis-6496f6bbf8-nsgjk -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "2097152"
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
127.0.0.1:6379> keys *
(empty array)
Now we will create python script test_redis.py to communicate with redis server:
# test_redis.py
import redis
r = redis.Redis(host="192.168.49.2", # host is url that kubernetes control plane is running.
port="30100",
db=0)
r.rpush('foo', 'bar')
r.rpush('foo', 'bar2')
Note that host argument is the url that kubernetes control plane is running. In this case, we use minikube and the url can find by the command minikube ip or kubectl cluster-info:
Kubernetes control plane is running at https://192.168.49.2:8443
CoreDNS is running at https://192.168.49.2:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Access redis server to get data after run python script:
python3 test_redis.py
kubectl exec -it my-redis-6496f6bbf8-nsgjk -- redis-cli
127.0.0.1:6379> keys *
1) "foo"
127.0.0.1:6379> lrange foo 0 -1
1) "bar"
2) "bar2"
Pass credentials for the Docker registry with Secret
First, creat a Secret holding the credentials for authenticating with a Docker registry:
kubectl create secret docker-registry mydockerhubsecret --docker-username=hoangph3 --docker-password=mypassword --docker-email=hoangph3@example.com
Let’s run pod with private image:
apiVersion: v1
kind: Pod
metadata:
name: private-pod
spec:
imagePullSecrets:
- name: mydockerhubsecret
containers:
- image: hoangph3/python-docker:v1.0
name: myapp
kubectl apply -f secret-private-image.yaml
kubectl describe pod private-pod
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 63s default-scheduler Successfully assigned default/private-pod to minikube
Normal Pulling 62s kubelet Pulling image "hoangph3/python-docker:v1.0"
Normal Pulled 46s kubelet Successfully pulled image "hoangph3/python-docker:v1.0" in 16.430969904s
Normal Created 2s (x4 over 45s) kubelet Created container myapp
Normal Started 2s (x4 over 45s) kubelet Started container myapp
Data Persistence
Volume
Share data between containers with emptyDir
Step 1: Create deployment with emptyDir volume:
kubectl apply -f emptydir-volume.yaml
Step 2: Tracking logs in pods:
kubectl get pods
kubectl logs -f my-app-68f4bfd84c-79wvl log-sidecar
NAME READY STATUS RESTARTS AGE
my-app-68f4bfd84c-79wvl 2/2 Running 0 9s
Thu Apr 7 14:44:10 UTC 2022 INFO some app data
Thu Apr 7 14:44:15 UTC 2022 INFO some app data
Thu Apr 7 14:44:20 UTC 2022 INFO some app data
Thu Apr 7 14:44:25 UTC 2022 INFO some app data
Thu Apr 7 14:44:30 UTC 2022 INFO some app data
Thu Apr 7 14:44:35 UTC 2022 INFO some app data
Thu Apr 7 14:44:40 UTC 2022 INFO some app data
PersistentVolumeClaims and PersistentVolumes
The PersistentVolumes is resource that communicate with Storage, and the PersistentVolumeClaims request resource from PersistentVolumes. In production environment, the administrator will create the cluster, install plugin, … while the developers will write yaml file to deploy application. So, the PersistentVolumes will created by the administrator, the developers only need to create PersistentVolumeClaims to use.
Suppose you are administrator, you will create the PersistentVolumes:
kubectl apply -f pv.yaml
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
data-pv 10Gi RWO Retain Available 59s
Note that the PersistentVolumes is not belong to any namespace, this is cluster resource, same as node. But the Pod, Deployment, … is the namespace resource.
Now, suppose you are developers, you need to create PersistentVolumeClaims to store persistent data. If exist any PersistentVolumes, the PersistentVolumeClaims you created will request storage from it.
kubectl apply -f pvc.yaml
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-data-pvc Bound pvc-e5d8e277-3831-4a1b-b9c4-351df960f58a 5Gi RWO standard 7s
The STATUS=Bound indicate that the mysql-data-pvc bounded pvc-e5d8e277-3831-4a1b-b9c4-351df960f58a volume, now let’s show the pv:
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
data-pv 10Gi RWO Retain Available 119s
pvc-e5d8e277-3831-4a1b-b9c4-351df960f58a 5Gi RWO Delete Bound default/mysql-data-pvc standard 31s
The default/mysql-data-pvc pvc was claimed resource from pvc-e5d8e277-3831-4a1b-b9c4-351df960f58a pv.
You can get full source code here: configmap-secret, data-persistence.