We will explore K8S functionalities further.
Prerequisites and objectives
We will assume here that you have followed the full Kubernetes(K8S) Workshop - Part 1
Let's do it
Start Minikube
$ minikube start
We have now a Deployment with 3 pods running
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5d59d67564-dw8zj 1/1 Running 0 87m
nginx-deployment-5d59d67564-ltj8s 1/1 Running 0 87m
nginx-deployment-5d59d67564-nrn9f 1/1 Running 0 87m
Some concepts
DEPLOYMENTS, PODS AND REPLICAS
Let's try something, what happens If we delete a pod and list them just after
$ kubectl delete pod nginx-deployment-5d59d67564-dw8zj
pod "nginx-deployment-5d59d67564-dw8zj" deleted
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5d59d67564-76885 1/1 Running 0 14s
nginx-deployment-5d59d67564-ltj8s 1/1 Running 0 88m
nginx-deployment-5d59d67564-nrn9f 1/1 Running 0 88m
The pod is recreated by K8S, because we specified 3 replicas (see the first one AGE : 14s)
K8S will always do its best to automatically computes changes to respect what you declared and apply with kubectl apply command
In our case we created a Deployment and asked 3 replicas, the Deployment object is still available, so K8S will create missing pods automatically to respect our specs.
$ kubectl get deploy # shortcut of deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 92m
# Delete the deployment
$ kubectl delete deployment nginx-deployment
deployment.apps "nginx-deployment" deleted
# List all deployments
$ kubectl get deploy
No resources found in default namespace.
# List all pods
$ kubectl get pods
No resources found in default namespace.
As you see we have no deployments/pods available anymore.
Now we will bring back the deployment and scale down some replicas.
- Apply the deployment
Apply deployment
$ kubectl apply -f nginx-deployment.yml
deployment.apps/nginx-deployment created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5d59d67564-mgqvl 1/1 Running 0 78s
nginx-deployment-5d59d67564-mvwt4 1/1 Running 0 78s
nginx-deployment-5d59d67564-phx64 1/1 Running 0 78s
- Modify the nginx-deployment.yml created earlier and set the replicas number to 2.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
- Apply It again and you will see pods decreasing to 2. The status of one pod will be Terminating, and It will be deleted after
$ kubectl apply -f nginx-deployment.yml
deployment.apps/nginx-deployment configured
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5d59d67564-mgqvl 1/1 Running 0 3m21s
nginx-deployment-5d59d67564-mvwt4 0/1 Terminating 0 3m21s
nginx-deployment-5d59d67564-phx64 1/1 Running 0 3m21s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5d59d67564-mgqvl 1/1 Running 0 4m28s
nginx-deployment-5d59d67564-phx64 1/1 Running 0 4m28s
VOLUMES & CONFIGMAPS
We have nginx pods running based on nginx image but how can we customize some files in runnings containers ?
ConfigMaps can be used to inject some config to container with environment variables for example, or files. When using file, we will also use VOLUMES to mount the file into the container.
Let's try to change the default index.html of the nginx docker image for each pod we created through our deployment.
- Edit the nginx-deployment.yml file and add a volume mount into it
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: custom-index
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
readOnly: true
volumes:
- name: custom-index
configMap:
name: custom-index-config-map
-
volumeMounts : is used to mount a volume into the container. The goal here is to mount a file to replace the default one provided by nginx docker image. More information above
-
mountPath: where we want to mount the volume
-
subPath : which file to use
List pods
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5d59d67564-mgqvl 1/1 Running 0 4m28s
nginx-deployment-5d59d67564-phx64 1/1 Running 0 4m28s
# Open a shell into one pod (container)
$ kubectl exec -it nginx-deployment-5d59d67564-mgqvl -- sh
# Navigate to /usr/share/nginx/html
$ cd /usr/share/nginx/html
$ ls
50x.html index.html
# We have the default index.html
# Display It
$ cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
- volumes : allow us to create volume, in our case a ConfigMap to let it be mounted to containers
Now create a new file called nginx-configmap.yml and paste the content below
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-index-config-map
data:
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>Hello World K8S</title>
</head>
<body>
<h1>K8S NGINX</h1>
</body>
</html>
- Apply It
$ kubectl apply -f . # We use here the dot to apply all files in current directory
configmap/custom-index-config-map created
deployment.apps/nginx-deployment unchanged
service/nginx unchanged
- List and observe pods
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-866857c45d-gn4xc 1/1 Running 0 61s
nginx-deployment-866857c45d-vkhbp 1/1 Running 0 59s
$ kubectl exec -it nginx-deployment-866857c45d-gn4xc -- bash # we use bash because it is installed in nginx docker image
$ cd /usr/share/nginx/html/
$ cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello World K8S</title>
</head>
<body>
<h1>K8S NGINX</h1>
</body>
</html>
- Let's try to use busybox to display it with the service
$ kubectl run -it --rm debug --image=busybox --restart=Never -- sh
$ wget http://nginx
Connecting to nginx (10.105.68.32:80)
saving to 'index.html'
index.html 100% |****************************************************************| 113 0:00:00 ETA
'index.html' saved
$ cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello World K8S</title>
</head>
<body>
<h1>K8S NGINX</h1>
</body>
</html>
SECRETS & ENVIRONMENT VARIABLES
We can inject env var into containers with keys values in the deployment file or with a ConfigMap.
We will never put sensitive data (api keys, secrets, etc.) into deployment file. Because these files are usually versioned, we will use K8S Secret Object to handle them.
- Edit nginx-deployment.yml and add env: block and envFrom: block
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: custom-index
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
readOnly: true
env:
- name: ENV_VAR_1
value: "Hello from the environment"
- name: ENV_VAR_2
value: "Hello 2 from the environment"
envFrom:
- configMapRef:
name: nginx-env-configmap
volumes:
- name: custom-index
configMap:
name: custom-index-config-map
- Create a new file called nginx-env-configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-env-configmap
data:
ENV_VAR_3: "Hello 3 from the environment"
ENV_VAR_4: "Hello 4 from the environment"
- Apply changes
$ kubectl apply -f .
configmap/custom-index-config-map unchanged
deployment.apps/nginx-deployment configured
configmap/nginx-env-configmap created
service/nginx unchanged
- Observe changes
$ kubectl exec -it nginx-deployment-54899785f6-294kh -- bash
# Display container's env vars
$ printenv
# Search your env vars
ENV_VAR_2=Hello 2 from the environment
ENV_VAR_3=Hello 3 from the environment
ENV_VAR_1=Hello from the environment
ENV_VAR_4=Hello 4 from the environment
To store sensitive data we will use secrets. Secrets are like a named bucket where we put inside key value pair data. Try to group your secrets together for example : service's credentials, api-secrets, etc.
- Generate secrets using the CLI with
kubectl create secret
$ kubectl create secret generic my-secret --from-literal=user=myUser --from-literal=password=myPass
secret/my-secret created
We use a generic type of secret with a name of my-secret, with then use --from-literal=
to specific key=value secret. Here we want
user = myUser
password = myPass
- Now we can use this secret inside our deployment, look for new env : entries
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: custom-index
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
readOnly: true
env:
- name: USER
valueFrom:
secretKeyRef:
name: my-secret
key: user
- name: PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: password
- name: ENV_VAR_1
value: "Hello from the environment"
- name: ENV_VAR_2
value: "Hello 2 from the environment"
envFrom:
- configMapRef:
name: nginx-env-configmap
volumes:
- name: custom-index
configMap:
name: custom-index-config-map
More information :
- name: USER
valueFrom:
secretKeyRef:
name: my-secret
key: user
-
name : is the name of the env var we want to create and put our secret inside
-
secretKeyRef : name of the secret we created
-
key : the key inside the secret for getting the value
Then we can apply changes, and observe the result
$ kubectl apply -f .
configmap/custom-index-config-map unchanged
deployment.apps/nginx-deployment configured
configmap/nginx-env-configmap unchanged
service/nginx unchanged
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-cd85d6486-7q6ws 1/1 Running 0 14s
nginx-deployment-cd85d6486-pr6ck 1/1 Running 0 12s
$ kubectl exec -it nginx-deployment-cd85d6486-7q6ws -- bash
# printenv and search your new env var
printenv
USER=plezi
PASSWORD=plezipass