Secrets are a way to store things that you do not want floating around in your code.
It's things like passwords for databases, API keys and certificates.
Similarly configmaps are for configuration, that doesn't really belong in code but needs to change. Examples include loadbalancer configurations, jenkins configuration and so forth.
We will look at both these in this coming exercise.
Our maginificent app requries it's API key and language. Rather than hardcode this sensitive information and commit it to git for all the world to see, we source these values from environment variables.
The first step to fixing it, would be to make our variables as environmental variables.
We have sourced the values in the code like this:
const language = process.env.LANGUAGE;
const API_KEY = process.env.API_KEY;
Because we are reading from the env variables we can specify some default in the Dockerfile. We have used this:
FROM node:9.1.0-alpine
EXPOSE 3000
ENV LANGUAGE English
ENV API_KEY 123-456-789
COPY secretapp.js .
ENTRYPOINT node secretapp.js
This image is available as praqma/secrets-demo
. We can run that in our Kubernetes cluster by using the the deployment file. Notice the env values added in the bottom.
Set your namespace in the file and run the deployment by writing:
$ kubectl apply -f secrets/deployment.yml
deployment.extensions/envtest created
Expose the deployment on a nodeport, so you can see the running container.
You learned about exposing nodeports in the service discovery exercise. And remember that the application is running on port ´3000´
Despite the default value in the Dockerfile, it should now be overwritten by the deployment env values!
However we just moved it from being hardcoded in our app to being hardcoded in our Dockerfile.
Let's move the API key to a (generic) secret:
$ kubectl create secret generic apikey --from-literal=API_KEY=oneringtorulethemall
secret/apikey created
Kubernetes supports different kinds of preconfigured secrets, but for now we'll deal with a generic one.
Similarly for the language into a configmap:
$ kubectl create configmap language --from-literal=LANGUAGE=Orcish
configmap/language created
Similarly to all other objects, you can run "get" on them.
$ kubectl get secrets
NAME TYPE DATA AGE
apikey Opaque 1 4m
default-token-td78d kubernetes.io/service-account-token 3 3h
$ kubectl get configmaps
NAME DATA AGE
language 1 2m
Try to investigate the secret by using the kubectl describe command:
$ kubectl describe secret apikeyNote that the actual value of API_KEY is not shown. To see the encoded value use:
$ kubectl get secret apikey -o yaml
Last step is to change the Kubernetes deployment file to use the secrets.
Change:
env:
- name: LANGUAGE
value: Polish
- name: API_KEY
value: 333-444-555
To:
env:
- name: LANGUAGE
valueFrom:
configMapKeyRef:
name: language
key: LANGUAGE
- name: API_KEY
valueFrom:
secretKeyRef:
name: apikey
key: API_KEY
After you have edited the deployment.yml
file (or you can use the prepared one
secrets/final.deployment.yml
), you need to apply the new edition of the file
by issuing: kubectl apply -f deployment.yml
.
You should now see the variables being loaded from configmap and secret respectively.
Pods are not recreated automatically when serets or configmaps change, i.e. to hot swapping the values becomes a two step process:
$ kubectl create configmap language --from-literal=LANGUAGE=Elvish -o yaml --dry-run | kubectl replace -f -
configmap/language replaced
$ kubectl create secret generic apikey --from-literal=API_KEY=andinthedarknessbindthem -o yaml --dry-run | kubectl replace -f -
secret/apikey replaced
Then delete the pod (so it's recreated with the replaced configmap and secret) :
$ kubectl delete pod envtest-3380598928-kgj9d
pod "envtest-3380598928-kgj9d" deleted
Access it in a webbrowser again, to see the updated values.
$ kubectl delete deployment envtest
$ kubectl delete service envtest
$ kubectl delete configmap language
$ kubectl delete secret apikey