Kubernets ConfigMaps and Secrets

ConfigMaps vs Secrets (big picture)

Both are ways to inject configuration into Pods without baking it into container images.

FeatureConfigMapSecret
PurposeNon-sensitive configSensitive data
ExamplesURLs, feature flags, env namesPasswords, tokens, certs
Stored in etcdPlaintextBase64-encoded (not encrypted by default)
Size limit~1MB~1MB
Can be env varsYesYes
Can be mounted as filesYesYes

Let’s try it!

  1. Create new dotnet api

add configuration for configmap and secret in appsettings.json:

"AppConfig": {
    "ServiceName": "My Awesome API"
},
"UserConfig":{
    "SecretPassword": "User Secret"
},

In program.cs, let’s assign variables to the configurations

var serviceName = builder.Configuration["AppConfig:ServiceName"]; // Access the ConfigMap value
var userPassword = builder.Configuration["UserConfig:SecretPassword  "]; // Access the Secret value

var app = builder.Build();

Create a controller to view the configs:

app.MapGet("/getconfigs", () =>
{
    var response = new { 
        Version = "V1",  
        Service = serviceName, 
        Password = userPassword, 
        Machine = System.Environment.MachineName 
    };

    Console.WriteLine(response);
    
    return Results.Ok(response);
});

When you run the application, the resul should be:

$ curl http://localhost:5128/getconfigs
{"version":"V1","service":"My Awesome API","password":"User Secret","machine":"My-MacBook-Air"
  1. Build and image for the application

Create a Docker file:

# Build stage
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet restore
RUN dotnet publish -c Release -o /app/publish

# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "my-dotnet-api.dll"]

Build the image:

$ docker build --no-cache -t my-dotnet-api:latest .  --no-cache
  1. Create configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: dotnet-app-config
data:
  # Example non-sensitive key-value pairs
  SERVICE_NAME: "My Awesome API!!!"
  1. Create secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: dotnet-app-secret
type: Opaque
data:
  # Base64 encoded: "s3cretP@ssw0rd"
  PASSWORD: "czNyZXRQQHNzd2ByZA=="
  1. Create service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-dotnet-api-service
spec:
  type: LoadBalancer
  selector:
    app: my-dotnet-api
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  1. Create deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-dotnet-api-deployment
spec:
  replicas: 4
  selector:
    matchLabels:
      app: my-dotnet-api
  template:
    metadata:
      labels:
        app: my-dotnet-api
    spec:
      containers:
        - name: my-dotnet-api
          image: my-dotnet-api:latest
          imagePullPolicy: Always #Default: IfNotPresent
          ports:
            - containerPort: 8080
          env:
              # Get non-sensitive environment variables from the ConfigMap
            - name: APPCONFIG__SERVICENAME # .NET Core configuration format
              valueFrom:
                configMapKeyRef:
                  name: dotnet-app-config
                  key: SERVICE_NAME
              # Get sensitive environment variables from the Secret
            - name: USERCONFIG__SECRETPASSWORD
              valueFrom:
                secretKeyRef:
                  name: dotnet-app-secret
                  key: PASSWORD
  1. Let’s test our work, apply our yaml files and see the result:
$ kubectl apply -f configmap.yaml 
configmap/dotnet-app-config created
$ kubectl apply -f secret.yaml 
secret/dotnet-app-secret created
$ kubectl apply -f service.yaml
service/my-dotnet-api-service created
$ kubectl apply -f deployment.yaml 
deployment.apps/my-dotnet-api-deployment created
$ curl http://localhost/getconfigs
{"version":"V1","service":"My Awesome API!!!","password":"s3retP@ssw`rd","machine":"my-dotnet-api-deployment-7494d875f5-mmm42"} 

What if we have some changes in the Configmap? here’s what you can do:

We made some changes in the value for the SERVICE_NAME

configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: dotnet-app-config
data:
  # Example non-sensitive key-value pairs
  SERVICE_NAME: "My Awesome API Updated!"

We have 2 options to apply the changes:

  1. kubectl rollout restart deployment my-app
$ kubectl apply -f configmap.yaml 
configmap/dotnet-app-config configured
$ kubectl rollout restart deployment my-dotnet-api-deployment
deployment.apps/my-dotnet-api-deployment restarted
$ curl http://localhost/getconfigs
{"version":"V1","service":"My Awesome API Updated!","password":"s3retP@ssw`rd","machine":"my-dotnet-api-deployment-54bb4888f4-mnfd8"} 
  1. Delete all pods: kubectl delete pod <pod-name>

(New Pods will pick up the updated ConfigMap)

Note: When you re-applied the configmap, the result says: configured, meaning the changes were applied, however, if there are no changes, the result will be: configmap/dotnet-app-config unchanged

To Clean Up:

kubectl delete deployment my-dotnet-api-deployment
kubectl delete service my-dotnet-api-service
kubectl delete secret dotnet-app-secret
kubectl delete configmap dotnet-app-config

Leave a Reply

Your email address will not be published. Required fields are marked *

footer