Overview

Skill Level: Intermediate

This recipe describes how to use Kubernetes secrets to make your applications more portable across Kubernetes-based clouds.

Ingredients

  • IBM Cloud Private (get it here).
  • kubectl command line (get it here).
  • Developer’s application
  • Service running in IBM Cloud Private that the developer wants to use

Step-by-step

  1. Why Use Secrets

    Our team developed a Stock Trader application we wanted to run in multiple instances of IBM Cloud Private. The problem was that when we use Helm charts to deploy the needed services, each Kubernetes cloud generated different endpoint names for each service (Figure 1).

    Multi-Private-Cloud

    Figure 1 – How we used GitHub Enterprise to build our app on multiple private clouds.

     

    As a result, our developer had to hard code these environment variables for each cloud he deployed his app into.

    It became cumbersome to change these values every time we deployed into a new cloud. Further, as the cloud admin, if I needed to deploy a new instance of the service, change the port, or change the password, it would break the application and the developer have to change his code yet again.

    We needed a way to abstract the service names (and user IDs and passwords) so his app could pick up unique details about the service when it was deployed without me having to send him specific names and re-build the app.

    Using Kubernetes secrets, I am now able to give him a well-defined secret name along with parameters within each secret, and now his code works in any of my clouds without any code changes.

    Note: Kubernetes provides two mechanisms to decouple configuration data from a running pod, configmaps and secrets. Rather than splitting related endpoint information based upon whether the value was sensitive, we chose to keep all of our endpoint information in one place, in a secret.

  2. Deploy the Services

    The first step was for me to deploy the services we needed. In our case, we needed to install DB2, MQ, and Redis. Here are two recipes to help you if you want to install DB2 and MQ.

    DB2 recipe

    MQ recipe

     

  3. Define and Communicate the Secret

    Once the services are installed, chat with your developer on what they need to successfully use the service. In our case, since we were using Liberty, he was using the JDBC Datasource defined in his Liberty server.xml.

    To make it work, he needed the user ID, password, the endpoint, port, and the database name. We ended up defining the secret like this:

    Name:         db2
    Namespace:    default

    Data
    ====
    id
    pwd
    host
    port
    database name

     

    Now that we had the layout of the secret, we could create the secret.

  4. Create the Secret

    Creating the secret is pretty simple. Here are examples of secrets I created using kubectl. Remember, for using Kubectl command line with IBM Cloud private, open the UI first, click the user menu on the upper right, and select “Configure Client” (Figure 2).

    Set-Context

    Figure 2: User menu where you can see the commands to set context

     

    The “Configure Client” menu will show you the commands to run to set context from your kubectl client to IBM Cloud private. Once you have kubectl set to your IBM Cloud private instance, you are ready to create the secrets.

     

    DB2 secret

    What the developer needed:

    • Default user ID: db2inst1
    • Default password: password
    • DB2 kube service name: callous-nightingale-db2
    • DB2 default port: 50000
    • DB2 database: sample

     

    Secret I created:

    kubectl create secret generic db2 --from-literal=id=db2inst1 --from-literal=pwd=password --from-literal=host=callous-nightingale-db2 --from-literal=port=50000 --from-literal=db=sample

     

    MQ secret

    What the developer needed:

    • Default user ID: app
    • Default password: no default password (null)
    • MQ kube service name: default-mq-mq  
    • MQ default API port: 1414
    • MQ channel: DEV.APP.SVRCONN  
    • MQ queue manager: qm1
    • MQ queue the app should use: NotificationQ

     

    Secret I created:

    kubectl create secret generic mq --from-literal=id=app  --from-literal=pwd= --from-literal=host=default-mq-mq   --from-literal=port=1414   --from-literal=channel=DEV.APP.SVRCONN   --from-literal=queue-manager=qm1  --from-literal=queue=NotificationQ     

     

    Public Bluemix secret

    In this case, the developer needed to call our Bluemix service that triggered OpenWhisk to run an action. To do this he neeed the URL and credentials to call it. What the developer needed:

    • OpenWhisk URL
    • Bluemix API ID
    • Bluemix API password

     

    Secret I created:

    kubectl create secret generic openwhisk --from-literal=url=https://openwhisk.ng.bluemix.net/api/v1/namespaces/<mybluemixID>_dev/actions/<myAction> --from-literal=id=<longServiceID> --from-literal=pwd=<longPassword>

     

  5. Retrieve the Secret Content

    For our developer, he updated his deploy.yaml file to get the secret content from Kubernetes and add it as environment variables, then he updated his server.xml to access the environment variables so his code could use it.

    deploy.yaml snapshot:

    deploy-yaml

     

    server.xml snippet:

    <properties.db2.jcc serverName="${env.JDBC_HOST}" portNumber="${env.JDBC_PORT}" databaseName="${env.JDBC_DB}" user="${env.JDBC_ID}" password="${env.JDBC_PASSWORD}"/>

     

     If you want to pull the environment variables directly into your Java code, you can do it like this:

    url = System.getenv("OW_URL");
    id = System.getenv("OW_ID");
    pwd = System.getenv("OW_PASSWORD");

  6. Tips

    If you change your secret, make sure you restart the app so it picks it up. Actually, in Kubernetes, the term ‘restart’ isn’t really accurate. Just go kill the pod, and Kubernetes will spin another one up in its place almost instantly and that will force the app to read in the changed secret.

    As I mentioned earlier, you could use secrets just for the ‘secret’ stuff like user ID and password, and use config maps for links and other ‘non-secret’ items. However, we chose to keep it all in the same secret since it was easier to manage.

  7. Conclusion

    By using secrets, we were able to greatly reduce the time it took to move between clouds, and reduce user error. Now I can change out services, IDs, passwords, even change to another database service, and his code does not need to change.

    Good luck!

Join The Discussion