Kubernetes ConfigMap and Secret

Introduction

This article will guide you on how to use ConfigMap and Secret to pass environment variables. As you know, during software development, you need to deploy on different environments such as development, staging, and production. We aim to use the same codebase across these environments but sometimes need to pass different environment variables for specific configurations. Kubernetes (K8s) supports ConfigMap and Secret to address this need.

If you've used Docker before, configuring environment variables in K8s will feel similar.

  • ConfigMap is an object that stores data in key-value pairs, intended for non-sensitive information (i.e., values that can be displayed when viewing the configuration of K8s resources). Supported data types include number, boolean, and string (it can store a string of characters or the contents of a text file).
  • Secret has several types, with type=Opaque being the most commonly used. It works similarly to ConfigMap but is used for sensitive information such as database connections, passwords, API keys, and other secret data.

Prepare Docker Image

You can use the following code block to build a NodeJS TypeScript application for this article:

import express from 'express'

const port = 3000
const title = 'This is NodeJS Typescript Application'
const name = 'Anonymous'
const app = express()

app
.use('/data', express.static('data'))
.get('/', (_, res) => {
res.json({
title: process?.env?.TITLE ?? title,
name: process?.env?.NAME ?? name,
apiKey: process?.env?.API_KEY,
password: process?.env?.PASSWORD,
currentTime: Date.now(),
})
})
.listen(port, () => {
console.log(`Server is running http://localhost:${port}`)
})

Note: You need to create a `data` folder to mount the volume when starting the Pod.

Next, build your Docker image and push it to Google Container Registry or Docker Hub. You can also use an existing Docker image with the same functionality.


Practice K8s

To start creating resources, you first need to set up a cluster. You can use Google Kubernetes Engine (GKE) or a local K8s setup with Kind.

After that, create a `deployment.yml` file with the following content:

apiVersion: v1
kind: ConfigMap
metadata:
name: config-map-name
data:
TITLE: Title from K8s # `key: value`
NAME: Name from K8s
data.txt: | # long text content
This is content of data file
End of file
---
apiVersion: v1
kind: Secret
metadata:
name: secret-name
type: Opaque
stringData: # raw data
API_KEY: API key value
secret.txt: |
This is secret content like API key or Password
End of file
data: # base64 encoded
PASSWORD: UGFzc3dvcmQgdmFsdWU=
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-name
spec:
replicas: 1
selector:
matchLabels:
app: label-name
template:
metadata:
labels:
app: label-name
spec:
restartPolicy: Always
containers:
- name: express-ts
image: express-ts # replace your image
ports:
- containerPort: 3000
name: deployment-port
env:
- name: TITLE
valueFrom:
configMapKeyRef:
name: config-map-name
key: TITLE
- name: NAME
valueFrom:
configMapKeyRef:
name: config-map-name
key: NAME
- name: API_KEY
valueFrom:
secretKeyRef:
name: secret-name
key: API_KEY
- name: PASSWORD
valueFrom:
secretKeyRef:
name: secret-name
key: PASSWORD
volumeMounts:
- name: config-map-volume
mountPath: /app/data/data.txt
subPath: data.txt
readOnly: true
- name: secret-volume
mountPath: /app/data/secret.txt
subPath: secret.txt
readOnly: true
volumes:
- name: config-map-volume
configMap:
name: config-map-name
items:
- key: data.txt
path: data.txt
- name: secret-volume
secret:
secretName: secret-name
items:
- key: secret.txt
path: secret.txt
---
apiVersion: v1
kind: Service
metadata:
name: service-name
spec:
type: LoadBalancer
selector:
app: label-name
ports:
- protocol: TCP
port: 80 # port service
targetPort: deployment-port # port pod

Explanation:

  • ConfigMap: This holds information defined as key-value pairs in the `data` field.
  • Secret: This is defined similarly to ConfigMap. Just remember:
    • The `stringData` field takes raw data.
    • The `data` field requires base64 encoded values. When you get resource info, the results are displayed in base64.
  • I've already provided a guide on creating Deployment and Service here.
  • For Deployment, you'll need to define the following:
    • volumes: Similar to defining volumes in Docker. Just make sure to correctly map the `name` field to the ConfigMap and Secret you created earlier.
    • volumeMounts: This is used to mount the volumes into the Deployment created from the Docker image. Here, I'm mounting two files, `data.txt` and `secret.txt`, into the `data` folder within the Docker image.
    • env: Maps values from ConfigMap and Secret to create environment variables.


Apply to create resource:

kubectl apply -f deployment.yml

Note: I've defined all resources in a single file for simplicity, but in practice, you should separate each resource into individual YAML files for better management.


Checking resource provisioning


View the information for the created ConfigMap and Secret. Note that the Secret will display its value in base64 encoded format.




Application results after deployment



See you in the next articles!

Comments

Popular posts from this blog

Kubernetes Practice Series

NodeJS Practice Series

Docker Practice Series

React Practice Series

Sitemap

Setting up Kubernetes Dashboard with Kind

Deploying a NodeJS Server on Google Kubernetes Engine

Create API Gateway with fast-gateway

DevOps Practice Series

Explaining Async/Await in JavaScript in 10 Minutes