Exercise

In this exercise, you will use a Secret to connect to an external database.

The image registry.gitlab.com/lucj/messages:v1.0.5 contains a simple application that listens on port 3000 and allows, via HTTP requests, to create messages or list existing messages in a MongoDB database. The connection URL of this database must be provided to the application so that it can connect to it. We can provide it via an environment variable MONGODB_URL or via a file that must be accessible from /app/db/mongodb_url.

We will use the Mongo database with the following connection URL:

mongodb+srv://k8sExercice:k8sExercice@techwhale.hg5mrf8.mongodb.net/

This database is hosted on MongoDB Atlas.

  1. Creating the Secret

Create a Secret named mongo, its data field must contain the key mongo_url with the connection string specified above as its value.

Choose one of the following options:

  • Option 1: using the kubectl create secret generic command with the --from-file option

  • Option 2: using the kubectl create secret generic command with the --from-literal option

  • Option 3: using a specification file

  1. Using the Secret in an environment variable

Define a Pod named messages-env whose single container has the following specification:

  • image: registry.gitlab.com/lucj/messages:v1.0.5
  • an environment variable MONGODB_URL having the value linked to the mongo_url key of the mongo Secret created previously

Then create this Pod and expose it using the kubectl port-forward command by mapping port 3000 of your local machine to port 3000 of the messages-env Pod.

From another terminal, verify that you can create a message with the following command:

Note: make sure to replace YOUR_NAME with your first name

curl -H 'Content-Type: application/json' -XPOST -d '{"msg":"hello from YOUR_NAME"}' http://localhost:3000/messages
  1. Using the Secret in a volume

Define a Pod named messages-vol with the following specification:

  • a volume named mongo-creds based on the mongo Secret
  • a container with the following specification:
    • image: registry.gitlab.com/lucj/messages:v1.0.5
    • a volumeMounts instruction allowing to mount the mongo_url key of the mongo-creds volume in the /app/db/mongo_url file

Create the Pod and verify that you can create a message in the same way as in the previous point by exposing the Pod via a port-forward.

  1. Cleanup

Delete the various resources created.


Solution
  1. Creating the Secret
  • Option 1: using the kubectl create secret generic command with the --from-file option

Use the following command to create a mongo_url file containing the database connection string:

echo -n "mongodb+srv://k8sExercice:k8sExercice@techwhale.hg5mrf8.mongodb.net/" > mongo_url

Then we create the Secret from this file:

kubectl create secret generic mongo --from-file=mongo_url
  • Option 2: using the kubectl create secret generic command with the --from-literal option

The following command creates the Secret from literal values

kubectl create secret generic mongo --from-literal=mongo_url='mongodb+srv://k8sExercice:k8sExercice@techwhale.hg5mrf8.mongodb.net/'
  • Option 3: using a specification file

The first step is to encrypt the connection string in base64

$ echo -n 'mongodb+srv://k8sExercice:k8sExercice@techwhale.hg5mrf8.mongodb.net/' | base64

bW9uZ29kYitzcnY6Ly9rOHNFeGVyY2ljZTprOHNFeGVyY2ljZUB0ZWNod2hhbGUuaGc1bXJmOC5tb25nb2RiLm5ldC8=

Then we can define the mongo-secret.yaml specification file:

mongo-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mongo
data:
  mongo_url: bW9uZ29kYitzcnY6Ly9rOHNFeGVyY2ljZTprOHNFeGVyY2ljZUB0ZWNod2hhbGUuaGc1bXJmOC5tb25nb2RiLm5ldC8=

The last step is to create the Secret from this file

kubectl apply -f mongo-secret.yaml
  1. We define the following specification in the messages-env.yaml file
messages-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: messages-env
spec:
  containers:
  - name: messages
    image: registry.gitlab.com/lucj/messages:v1.0.5
    env:
    - name: MONGODB_URL
      valueFrom:
        secretKeyRef:
          name: mongo
          key: mongo_url

We can then create the Pod:

kubectl apply -f messages-env.yaml

The following command exposes the API running in the Pod container locally:

kubectl port-forward messages-env 3000:3000

From another terminal on the local machine, we can then send a POST request to the API:

Note: make sure to replace YOUR_NAME with your first name

curl -H 'Content-Type: application/json' -XPOST -d '{"msg":"hello from YOUR_NAME"}' http://localhost:3000/messages

The returned response is similar to the one below:

{"msg":"hello from USER_NAME","created_at":"2023-08-02T11:37:29.796Z"}

We can then stop the port-forward.

  1. We define the following specification in the messages-vol.yaml file
messages-vol.yaml
apiVersion: v1
kind: Pod
metadata:
  name: messages-vol
spec:
  containers:
  - name: messages
    image: registry.gitlab.com/lucj/messages:v1.0.5
    volumeMounts:
    - name: mongo-creds
      mountPath: "/app/db"
      readOnly: true
  volumes:
  - name: mongo-creds
    secret:
      secretName: mongo

:warning: if you gave the Secret key a name other than mongo_url (you named it mongo for example), you can make this key available with the following configuration:

messages-vol.yaml
  ...
  volumeMounts:
    - name: mongo-creds
      mountPath: "/app/db/mongo_url"
      subPath: "mongo"

We can then create the Pod:

kubectl apply -f messages-vol.yaml

The following command exposes the API running in the Pod container locally:

kubectl port-forward messages-vol 3000:3000

From the local machine, we can then send a POST request to the API:

curl -H 'Content-Type: application/json' -XPOST -d '{"msg":"hello from USER_NAME"}' http://localhost:3000/messages

We then get a response similar to the following:

{"msg":"hello from USER_NAME","created_at":"2023-08-02T11:40:26.765Z"}

Then stop the port-forward.

  1. Delete the various resources created
k delete po messages-env messages-vol
k delete secret mongo