An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc).
MyRESTController.java includes a small chunk of code that looks to the environment
@RequestMapping("/configure")
public String configure() {
String databaseConn = environment.getProperty("DBCONN","Default");
String msgBroker = environment.getProperty("MSGBROKER","Default");
String hello = environment.getProperty("GREETING","Default");
String love = environment.getProperty("LOVE","Default");
return "Configuration: \n"
+ "databaseConn=" + databaseConn + "\n"
+ "msgBroker=" + msgBroker + "\n"
+ "hello=" + hello + "\n"
+ "love=" + love + "\n";
}
Environment variables can be manipulated at the Deployment level. Changes cause pod redeployment.
$ kubectl get pods -w
If you have more than one pod, tweak the replicas on the deployment descriptor
$ kubectl edit deployment myboot or $ kubectl scale --replicas=1 deployment/myboot
Ask the application for its configuration
$ curl $(minikube --profile 9steps ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/configure Configuration for : myboot-9bfc7b4b4-p69hr databaseConn=Default msgBroker=Default greeting=Default love=Default
Then set the env var at the Deployment
$ kubectl set env deployment/myboot GREETING="namaste"
and you should notice the associated pods being "reborn"
myboot-d79789574-8qpzb 0/1 Pending 0 0s myboot-578ff6dfc7-8krbb 1/1 Terminating 0 40s myboot-d79789574-8qpzb 0/1 Pending 0 0s myboot-d79789574-8qpzb 0/1 ContainerCreating 0 0s myboot-d79789574-8qpzb 1/1 Running 0 1s
and you can all the /configure endpoint
$ curl $(minikube --profile 9steps ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/configure Configuration: databaseConn=Default msgBroker=Default hello=namaste love=Default
Set the other variables
$ kubectl set env deployment/myboot LOVE="Aloha" $ kubectl set env deployment/myboot DBCONN="jdbc:sqlserver://45.91.12.123:1443;user=MyUserName;password=*****;"
You can see the set variables via the -o yaml trick
$ kubectl get deployment/myboot -o yaml # or $ kubectl get deployment/myboot -o json ... spec: containers: - env: - name: hello value: namaste - name: GREETING value: namaste - name: LOVE value: Aloha - name: DBCONN value: jdbc:sqlserver://45.91.12.123:1443;user=MyUserName;password=*****; image: 9stepsawesome/myboot:v1 ...
as well as via the describe command
$ kubectl describe deployment/myboot ... Requests: cpu: 250m memory: 300Mi Environment: hello: namaste GREETING: namaste LOVE: Aloha DBCONN: jdbc:sqlserver://45.91.12.123:1443;user=MyUserName;password=*****; Mounts: <none> Volumes: <none> ...
And you can unset the env vars with a "-"
$ kubectl set env deployment/myboot LOVE- $ kubectl set env deployment/myboot DBCONN- $ kubectl set env deployment/myboot GREETING-
Note: You if you are quick on your curl command, you might notice that you receive some errors while the pod is being restarted. The problem is replicas == 1 (there is a single pod/instance of your app) and you have not yet mastered the live/ready probe (coming in step 7).
Create a ConfigMap from a directory called config
$ kubectl create cm my-config --from-env-file=config/some.properties
$ kubectl get cm NAME DATA AGE my-config 2 6s
$ kubectl describe cm my-config Name: my-config Namespace: myspace Labels: <none> Annotations: <none> Data ==== GREETING: ==== jambo LOVE: ==== Amour Events: <none>
$ kubectl get cm my-config -o yaml apiVersion: v1 data: GREETING: jambo LOVE: Amour kind: ConfigMap metadata: creationTimestamp: 2018-08-02T03:15:01Z name: my-config namespace: myspace resourceVersion: "168479" selfLink: /api/v1/namespaces/myspace/configmaps/my-config uid: 3e52c2a7-9602-11e8-968e-08002783251f
Change the deployment to look for its env from the configmap
$ kubectl replace -f kubefiles/myboot-deployment-configuration.yml
Replacement of the Deployment should cause the pods to respawn, if not or just for good measure you can delete them and they will get recreated
$ kubectl delete pod -l app=myboot
$ curl $(minikube --profile 9steps ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/configure Configuration for : myboot-694954fc6d-fzzf4 databaseConn=Default msgBroker=Default hello=jambo love=Amour
and switch to the other properties file by recreating the CM
$ kubectl delete cm my-config $ kubectl create cm my-config --from-env-file=config/other.properties $ kubectl delete pod -l app=myboot $ curl $(minikube --profile 9steps ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/configure Configuration for : myboot-694954fc6d-nzdvx databaseConn=jdbc:sqlserver://123.123.123.123:1443;user=MyUserName;password=*****; msgBroker=tcp://localhost:61616?jms.useAsyncSend=true hello=Default love=Default
There are a lot more ways to have fun with ConfigMaps, the core documentation has you manipulate a Pod specification instead of a Deployment but the results are basically the same https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap
The CM example earlier had an example of a database connection string ("user=MyUserName;password=*"). Sensistive data like passwords can place in a different vessel known as a Secret.
$ kubectl create secret generic mysecret --from-literal=user='MyUserName' --from-literal=password='mypassword'
$ kubectl get secrets
The user & password are not immediately visible
$ kubectl describe secret mysecret Name: mysecret Namespace: myspace Labels: <none> Annotations: <none> Type: Opaque Data ==== password: 10 bytes user: 10 bytes
$ kubectl get secret mysecret -o yaml apiVersion: v1 data: password: bXlwYXNzd29yZA== user: TXlVc2VyTmFtZQ== kind: Secret metadata: creationTimestamp: "2019-10-08T19:34:43Z" name: mysecret namespace: myspace resourceVersion: "28240" selfLink: /api/v1/namespaces/myspace/secrets/mysecret uid: adce776c-ea02-11e9-a569-080027f773ed type: Opaque
It is base64 encoded
$ echo 'bXlwYXNzd29yZA==' | base64 --decode mypassword $ echo 'TXlVc2VyTmFtZQ==' | base64 --decode MyUserName
OR
$ kubectl get secret mysecret -o jsonpath='{.data.password}' | base64 --decode mypassword
Secrets are provided to the Pod via Volume Mounts
volumeMounts: - name: mysecretvolume mountPath: /mystuff/mysecretvolume
New deployment with the secret volume
$ kubectl replace -f kubefiles/myboot-deployment-configuration-secret.yml
Exec into the newly created pod, to see the volume mount
$ kubectl exec -it myboot-5d6ff444bd-x4bgh /bin/bash $ cd /mystuff/secretstuff $ cat user MyUserName $ cat password mypassword
You could provide the location of "/mystuff/mysecretvolume" to the pod via an environment variable so the application knows where to go looking.
More information on Secrets