Science and technology

Working with Kubernetes Secrets and ConfigMaps

Kubernetes has two varieties of objects that may inject configuration information right into a container when it begins up: Secrets and ConfigMaps. Secrets and ConfigMaps behave equally in Kubernetes, each in how they’re created and since they are often uncovered inside a container as mounted recordsdata or volumes or surroundings variables.

To discover Secrets and ConfigMaps, contemplate the next state of affairs:

You’re operating the official MariaDB container image in Kubernetes and should do some configuration to get the container to run. The picture requires an surroundings variable to be set for MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD, or MYSQL_RANDOM_ROOT_PASSWORD to initialize the database. It additionally permits for extensions to the MySQL configuration file my.cnf by inserting customized config recordsdata in /and so on/mysql/conf.d.

You might construct a customized picture, setting the surroundings variables and copying the configuration recordsdata into it to create a bespoke container picture. However, it’s thought-about a greatest follow to create and use generic pictures and add configuration to the containers created from them, as an alternative. This is an ideal use-case for ConfigMaps and Secrets. The MYSQL_ROOT_PASSWORD may be set in a Secret and added to the container as an surroundings variable, and the configuration recordsdata may be saved in a ConfigMap and mounted into the container as a file on startup.

Let’s attempt it out!

But first: A fast be aware about Kubectl

Make positive that your model of the kubectl consumer command is similar or newer than the Kubernetes cluster model in use.

An error alongside the strains of: 

error: SchemaError(io.k8s.api.admissionregistration.v1beta1.ServiceReference): invalid object would not have extra properties

might imply the consumer model is just too previous and must be upgraded.   The Kubernetes Documentation for Installing Kubectl has directions for putting in the newest consumer on numerous platforms.

If you are utilizing Docker for Mac, it additionally installs its personal model of kubectl, and that could be the difficulty. You can set up a present consumer with brew set up, changing the symlink to the consumer shipped by Docker:

$ rm /usr/native/bin/kubectl
$ brew hyperlink --overwrite kubernetes-cli

The newer kubectl consumer ought to proceed to work with Docker’s Kubernetes model.

Secrets

Secrets are a Kubernetes object meant for storing a small quantity of delicate information. It is price noting that Secrets are saved base64-encoded inside Kubernetes, so they don’t seem to be wildly safe. Make positive to have applicable role-based access controls (RBAC) to guard entry to Secrets. Even so, extraordinarily delicate Secrets information ought to most likely be saved utilizing one thing like HashiCorp Vault. For the foundation password of a MariaDB database, nevertheless, base64 encoding is simply tremendous.

Create a Secret manually

To create the Secret containing the MYSQL_ROOT_PASSWORD, select a password and convert it to base64:

# The root password will probably be "KubernetesRocks!"
$ echo -n 'KubernetesRocks!' | base64
S3ViZXJuZXRlc1JvY2tzIQ==

Make a be aware of the encoded string. You want it to create the YAML file for the Secret:

apiVersion: v1
variety
: Secret
metadata
:
  title
: mariadb-root-password
kind
: Opaque
information
:
  password
: S3ViZXJuZXRlc1JvY2tzIQ==

Save that file as mysql-secret.yaml and create the Secret in Kubernetes with the kubectl apply command:

$ kubectl apply -f mysql-secret.yaml
secret/mariadb-root-password created

View the newly created Secret

Now that you have created the Secret, use kubectl describe to see it:

$ kubectl describe secret mariadb-root-password
Name:         mariadb-root-password
Namespace:    secrets-and-configmaps
Labels:       <none>
Annotations:
Type:         Opaque

Data
====
password:  16 bytes

Note that the Data area incorporates the important thing you set within the YAML: password. The worth assigned to that key’s the password you created, however it isn’t proven within the output. Instead, the worth’s measurement is proven as a replacement, on this case, 16 bytes.

You may use the kubectl edit secret <secretname> command to view and edit the Secret. If you edit the Secret, you will see one thing like this:

# Please edit the thing beneath. Lines starting with a '#' will probably be ignored,
# and an empty file will abort the edit. If an error happens whereas saving this file will probably be
# reopened with the related failures.
#
apiVersion: v1
information:
  password: S3ViZXJuZXRlc1JvY2tzIQ==
variety: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
     
  creationTimestamp: 2019-05-29T12:06:09Z
  title: mariadb-root-password
  namespace: secrets-and-configmaps
  resourceVersion: "85154772"
  selfLink: /api/v1/namespaces/secrets-and-configmaps/secrets and techniques/mariadb-root-password
  uid: 2542dadb-820a-11e9-ae24-005056a1db05
kind: Opaque

Again, the information area with the password key’s seen, and this time you possibly can see the bottom64-encoded Secret.

Decode the Secret

Let’s say it is advisable view the Secret in plain textual content, for instance, to confirm that the Secret was created with the right content material. You can do that by decoding it.

It is simple to decode the Secret by extracting the worth and piping it to base64. In this case, you’ll use the output format -o jsonpath=<path> to extract solely the Secret worth utilizing a JSONPath template.

# Returns the bottom64 encoded secret string
$ kubectl get secret mariadb-root-password -o jsonpath=''
S3ViZXJuZXRlc1JvY2tzIQ==

# Pipe it to `base64 --decode -` to decode:
$ kubectl get secret mariadb-root-password -o jsonpath='' | base64 --decode -
KubernetesRocks!

Another technique to create Secrets

You may create Secrets straight utilizing the kubectl create secret command. The MariaDB picture permits organising a daily database consumer with a password by setting the MYSQL_USER and MYSQL_PASSWORD surroundings variables. A Secret can maintain multiple key/worth pair, so you possibly can create a single Secret to carry each strings. As a bonus, through the use of kubectl create secret, you possibly can let Kubernetes mess with base64 in order that you do not have to.

$ kubectl create secret generic mariadb-user-creds
      --from-literal=MYSQL_USER=kubeuser
      --from-literal=MYSQL_PASSWORD=kube-still-rocks
secret/mariadb-user-creds created

Note the –from-literal, which units the important thing title and the worth multi function. You can go as many –from-literal arguments as it is advisable create a number of key/worth pairs within the Secret.

Validate that the username and password have been created and saved accurately with the kubectl get secrets and techniques command:

# Get the username
$ kubectl get secret mariadb-user-creds -o jsonpath='' | base64 --decode -
kubeuser

# Get the password
$ kubectl get secret mariadb-user-creds -o jsonpath='.information.MYSQL_PASSWORD' | base64 --decode -
kube-still-rocks

ConfigMaps

ConfigMaps are just like Secrets. They may be created and shared within the containers in the identical methods. The solely large distinction between them is the bottom64-encoding obfuscation. ConfigMaps are meant for non-sensitive information—configuration information—like config recordsdata and surroundings variables and are a good way to create custom-made operating providers from generic container pictures.

Create a ConfigMap

ConfigMaps may be created in the identical methods as Secrets. You can write a YAML illustration of the ConfigMap manually and cargo it into Kubernetes, or you need to use the kubectl create configmap command to create it from the command line. The following instance creates a ConfigMap utilizing the latter technique however, as an alternative of passing literal strings (as with –from-literal=<key>=<string> within the Secret above), it creates a ConfigMap from an present file—a MySQL config meant for /and so on/mysql/conf.d within the container. This config file overrides the max_allowed_packet setting that MariaDB units to 16M by default.

First, create a file named max_allowed_packet.cnf with the next content material:

[mysqld]
max_allowed_packet = 64M

This will override the default setting within the my.cnf file and set max_allowed_packet to 64M.

Once the file is created, you possibly can create a ConfigMap named mariadb-config utilizing the kubectl create configmap command that incorporates the file:

$ kubectl create configmap mariadb-config --from-file=max_allowed_packet.cnf
configmap/mariadb-config created

Just like Secrets, ConfigMaps retailer a number of key/worth pairs of their Data hash of the thing. By default, utilizing –from-file=<filename> (as above) will retailer the contents of the file as the worth, and the title of the file will probably be saved as the important thing. This is handy from a company viewpoint. However, the important thing title may be explicitly set, too. For instance, when you used –from-file=max-packet=max_allowed_packet.cnf while you created the ConfigMap, the important thing could be max-packet slightly than the file title. If you had a number of recordsdata to retailer within the ConfigMap, you possibly can add every of them with a further –from-file=<filename> argument.

View the brand new ConfigMap and browse the information

As talked about, ConfigMaps usually are not meant to retailer delicate information, so the information isn’t encoded when the ConfigMap is created. This makes it simple to view and validate the information and edit it straight.

First, validate that the ConfigMap was, certainly, created:

$ kubectl get configmap mariadb-config
NAME             DATA      AGE
mariadb-config   1         9m

The contents of the ConfigMap may be seen with the kubectl describe command. Note that the total contents of the file are seen and that the important thing title is, actually, the file title, max_allowed_packet.cnf.

$ kubectl describe cm mariadb-config
Name:         mariadb-config
Namespace:    secrets-and-configmaps
Labels:       <none>
Annotations:  <none>

Data
====
max_allowed_packet.cnf:
----
[mysqld]
max_allowed_packet = 64M

Events:  <none>

A ConfigMap may be edited reside inside Kubernetes with the kubectl edit command. Doing so will open a buffer with the default editor displaying the contents of the ConfigMap as YAML. When adjustments are saved, they may instantly be reside in Kubernetes. While probably not the greatest follow, it may be useful for testing issues in improvement.

Say you desire a max_allowed_packet worth of 32M as an alternative of the default 16M or the 64M within the max_allowed_packet.cnf file. Use kubectl edit configmap mariadb-config to edit the worth:

$ kubectl edit configmap mariadb-config

# Please edit the thing beneath. Lines starting with a '#' will probably be ignored,
# and an empty file will abort the edit. If an error happens whereas saving this file will probably be
# reopened with the related failures.
#
apiVersion: v1

information:
  max_allowed_packet.cnf: |
    [mysqld]
    max_allowed_packet = 32M
variety: ConfigMap
metadata:
  creationTimestamp: 2019-05-30T12:02:22Z
  title: mariadb-config
  namespace: secrets-and-configmaps
  resourceVersion: "85609912"
  selfLink: /api/v1/namespaces/secrets-and-configmaps/configmaps/mariadb-config
  uid: c83ccfae-82d2-11e9-832f-005056a1102f

After saving the change, confirm the information has been up to date:

# Note the '.' in max_allowed_packet.cnf must be escaped
$ kubectl get configmap mariadb-config -o "jsonpath="

[mysqld]
max_allowed_packet = 32M

Using Secrets and ConfigMaps

Secrets and ConfigMaps may be mounted as surroundings variables or as recordsdata inside a container. For the MariaDB container, you have to to mount the Secrets as surroundings variables and the ConfigMap as a file. First, although, it is advisable write a Deployment for MariaDB so that you’ve one thing to work with. Create a file named mariadb-deployment.yaml with the next:

apiVersion: apps/v1
variety
: Deployment
metadata
:
  labels
:
    app
: mariadb
  title
: mariadb-deployment
spec
:
  replicas
: 1
  selector
:
    matchLabels
:
      app
: mariadb
  template
:
    metadata
:
      labels
:
        app
: mariadb
    spec
:
      containers
:
      - title
: mariadb
        picture
: docker.io/mariadb:10.four
        ports
:
        - containerPort
: 3306
          protocol
: TCP
        volumeMounts
:
        - mountPath
: /var/lib/mysql
          title
: mariadb-volume-1
      volumes
:
      - emptyDir
:
        title
: mariadb-volume-1

This is a bare-bones Kubernetes Deployment of the official MariaDB 10.four picture from Docker Hub. Now, add your Secrets and ConfigMap.

Add the Secrets to the Deployment as surroundings variables

You have two Secrets that must be added to the Deployment:

  1. mariadb-root-password (with one key/worth pair)
  2. mariadb-user-creds (with two key/worth pairs)

For the mariadb-root-password Secret, specify the Secret and the important thing you need by including an env listing/array to the container spec within the Deployment and setting the surroundings variable worth to the worth of the important thing in your Secret. In this case, the listing incorporates solely a single entry, for the variable MYSQL_ROOT_PASSWORD.

env:
   - title
: MYSQL_ROOT_PASSWORD
     valueFrom
:
       secretKeyRef
:
         title
: mariadb-root-password
         key
: password

Note that the title of the thing is the title of the surroundings variable that’s added to the container. The valueFrom area defines secretKeyRef because the supply from which the surroundings variable will probably be set; i.e., it can use the worth from the password key within the mariadb-root-password Secret you set earlier.

Add this part to the definition for the mariadb container within the mariadb-deployment.yaml file. It ought to look one thing like this:

spec:
   containers
:
   - title
: mariadb
     picture
: docker.io/mariadb:10.four
     env
:
       - title
: MYSQL_ROOT_PASSWORD
         valueFrom
:
           secretKeyRef
:
             title
: mariadb-root-password
             key
: password
     ports
:
     - containerPort
: 3306
       protocol
: TCP
     volumeMounts
:
     - mountPath
: /var/lib/mysql
       title
: mariadb-volume-1

In this fashion, you have got explicitly set the variable to the worth of a particular key out of your Secret. This technique can be used with ConfigMaps through the use of configMapRef as an alternative of secretKeyRef.

You may set surroundings variables from all key/worth pairs in a Secret or ConfigMap to routinely use the important thing title because the surroundings variable title and the important thing’s worth because the surroundings variable’s worth. By utilizing envFrom slightly than env within the container spec, you possibly can set the MYSQL_USER and MYSQL_PASSWORD from the mariadb-user-creds Secret you created earlier, multi function go:

envFrom:
- secretRef
:
    title
: mariadb-user-creds

envFrom is an inventory of sources for Kubernetes to take surroundings variables. Use secretRef once more, this time to specify mariadb-user-creds because the supply of the surroundings variables. That’s it! All the keys and values within the Secret will probably be added as surroundings variables within the container.

The container spec ought to now seem like this:

spec:
  containers
:
  - title
: mariadb
    picture
: docker.io/mariadb:10.four
    env
:
      - title
: MYSQL_ROOT_PASSWORD
        valueFrom
:
          secretKeyRef
:
            title
: mariadb-root-password
            key
: password
    envFrom
:
    - secretRef
:
        title
: mariadb-user-creds
    ports
:
    - containerPort
: 3306
      protocol
: TCP
    volumeMounts
:
    - mountPath
: /var/lib/mysql
      title
: mariadb-volume-1

Note: You might have simply added the mysql-root-password Secret to the envFrom listing and let it’s parsed as effectively, so long as the password key was named MYSQL_ROOT_PASSWORD as an alternative. There isn’t any technique to manually specify the surroundings variable title with envFrom as with env.

Add the max_allowed_packet.cnf file to the Deployment as a volumeMount

As talked about, each env and envFrom can be utilized to share ConfigMap key/worth pairs with a container as effectively. However, within the case of the mariadb-config ConfigMap, your complete file is saved as the worth to your key, and the file must exist within the container’s filesystem for MariaDB to have the ability to use it. Luckily, each Secrets and ConfigMaps may be the supply of Kubernetes “volumes” and mounted into the containers as an alternative of utilizing a filesystem or block machine as the amount to be mounted.

The mariadb-deployment.yaml already has a quantity and volumeMount specified, an emptyDir (successfully a short lived or ephemeral) quantity mounted to /var/lib/mysql to retailer the MariaDB information:

...>

  volumeMounts
:
  - mountPath
: /var/lib/mysql
    title
: mariadb-volume-1

<...>

volumes
:
- emptyDir
:
title
: mariadb-volume-1

<...>

Note: This isn’t a manufacturing configuration. When the Pod restarts, the information within the emptyDir quantity is misplaced. This is primarily used for improvement or when the contents of the amount do not must be persistent.

You can add your ConfigMap as a supply by including it to the amount listing after which including a volumeMount for it to the container definition:

...>

  volumeMounts
:
  - mountPath
: /var/lib/mysql
    title
: mariadb-volume-1
  - mountPath
: /and so on/mysql/conf.d
    title
: mariadb-config

<...>

volumes
:
- emptyDir
:
  title
: mariadb-volume-1
- configMap
:
    title
: mariadb-config
    gadgets
:
      - key
: max_allowed_packet.cnf
        path
: max_allowed_packet.cnf
  title
: mariadb-config-volume

<...>

The volumeMount is fairly self-explanatory—create a quantity mount for the mariadb-config-volume (specified within the volumes listing beneath it) to the trail /and so on/mysql/conf.d.

Then, within the volumes listing, configMap tells Kubernetes to make use of the mariadb-config ConfigMap, taking the contents of the important thing max_allowed_packet.cnf and mounting it to the trail max_allowed_packed.cnf. The title of the amount is mariadb-config-volume, which was referenced within the volumeMounts above.

Note: The path from the configMap is the title of a file that may include the contents of the important thing’s worth. In this case, your key was a file title, too, however it would not need to be. Note additionally that gadgets is an inventory, so a number of keys may be referenced and their values mounted as recordsdata. These recordsdata will all be created within the mountPath of the volumeMount specified above: /and so on/mysql/conf.d.

Create a MariaDB occasion from the Deployment

At this level, it’s best to have sufficient to create a MariaDB occasion. You have two Secrets, one holding the MYSQL_ROOT_PASSWORD and one other storing the MYSQL_USER, and the MYSQL_PASSWORD surroundings variables to be added to the container. You even have a ConfigMap holding the contents of a MySQL config file that overrides the max_allowed_packed worth from its default setting.

You even have a mariadb-deployment.yaml file that describes a Kubernetes deployment of a Pod with a MariaDB container and provides the Secrets as surroundings variables and the ConfigMap as a volume-mounted file within the container. It ought to seem like this:

apiVersion: apps/v1
variety
: Deployment
metadata
:
  labels
:
    app
: mariadb
  title
: mariadb-deployment
spec
:
  replicas
: 1
  selector
:
    matchLabels
:
      app
: mariadb
  template
:
    metadata
:
      labels
:
        app
: mariadb
    spec
:
      containers
:
      - picture
: docker.io/mariadb:10.four
        title
: mariadb
        env
:
          - title
: MYSQL_ROOT_PASSWORD
            valueFrom
:
              secretKeyRef
:
                title
: mariadb-root-password
                key
: password
        envFrom
:
        - secretRef
:
            title
: mariadb-user-creds
        ports
:
        - containerPort
: 3306
          protocol
: TCP
        volumeMounts
:
        - mountPath
: /var/lib/mysql
          title
: mariadb-volume-1
        - mountPath
: /and so on/mysql/conf.d
          title
: mariadb-config-volume
      volumes
:
      - emptyDir
:
        title
: mariadb-volume-1
      - configMap
:
          title
: mariadb-config
          gadgets
:
            - key
: max_allowed_packet.cnf
              path
: max_allowed_packet.cnf
        title
: mariadb-config-volume

Create the MariaDB occasion

Create a brand new MariaDB occasion from the YAML file with the kubectl create command:

$ kubectl create -f mariadb-deployment.yaml
deployment.apps/mariadb-deployment created

Once the deployment has been created, use the kubectl get command to view the operating MariaDB pod:

$ kubectl get pods
NAME                                  READY     STATUS    RESTARTS   AGE
mariadb-deployment-5465c6655c-7jfqm   1/1       Running   zero          3m

Make a be aware of the Pod title (on this instance, it is mariadb-deployment-5465c6655c-7jfqm). Note that the Pod title will differ from this instance.

Verify the occasion is utilizing the Secrets and ConfigMap

Use the kubectl exec command (together with your Pod title) to validate that the Secrets and ConfigMaps are in use. For instance, verify that the surroundings variables are uncovered within the container:

$ kubectl exec -it mariadb-deployment-5465c6655c-7jfqm env |grep MYSQL
MYSQL_PASSWORD=kube-still-rocks
MYSQL_USER=kubeuser
MYSQL_ROOT_PASSWORD=KubernetesRocks!

Success! All three surroundings variables—the one utilizing the env setup to specify the Secret, and two utilizing envFrom to mount all of the values from the Secret—can be found within the container for MariaDB to make use of.

Spot verify that the max_allowed_packet.cnf file was created in /and so on/mysql/conf.d and that it incorporates the anticipated content material:

$ kubectl exec -it mariadb-deployment-5465c6655c-7jfqm ls /and so on/mysql/conf.d
max_allowed_packet.cnf

$ kubectl exec -it mariadb-deployment-5465c6655c-7jfqm cat /and so on/mysql/conf.d/max_allowed_packet.cnf
[mysqld]
max_allowed_packet = 32M

Finally, validate that MariaDB used the surroundings variable to set the foundation consumer password and browse the max_allowed_packet.cnf file to set the max_allowed_packet configuration variable. Use the kubectl exec command once more, this time to get a shell contained in the operating container and use it to run some mysql instructions:

$ kubectl exec -it mariadb-deployment-5465c6655c-7jfqm /
bin/sh

# Check that the foundation password was set accurately
$ mysql -uroot -p$MYSQL_ROOT_PASSWORD -e 'present databases;'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+

# Check that the max_allowed_packet.cnf was parsed
$ mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "SHOW VARIABLES LIKE 'max_allowed_packet';"
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| max_allowed_packet | 33554432 |
+--------------------+----------+

Advantages of Secrets and ConfigMaps

This train defined the way to create Kubernetes Secrets and ConfigMaps and the way to use these Secrets and ConfigMaps by including them as surroundings variables or recordsdata inside a operating container occasion. This makes it simple to maintain the configuration of particular person cases of containers separate from the container picture. By separating the configuration information, overhead is diminished to sustaining solely a single picture for a particular kind of occasion whereas retaining the pliability to create cases with all kinds of configurations.

Most Popular

To Top