Skip to content

Latest commit

 

History

History
300 lines (252 loc) · 7.67 KB

5_configuration.adoc

File metadata and controls

300 lines (252 loc) · 7.67 KB

Step 5: Configuration

Externalize Configuration

An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc).

Environment Variables

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).

ConfigMaps

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

Secrets

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