tom
tom

Reputation: 83

Kubernetes application run error when using env from ConfigMaps

I have an application written in Go which reads environmental variables from a config.toml file. The config.toml file contains the key value as

Server="mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo"
Database="nrfdb"
NRFAddrPort = ":9090"

In my application am reading the all the variables from the .toml file to my application as

// Represents database and server credentials
type Config struct {
    Server      string
    Database    string
    NRFAddrPort string
}

var NRFAddrPort string

// Read and parse the configuration file
func (c *Config) Read() {
    if _, err := toml.DecodeFile("config.toml", &c); err != nil {
        log.Print("Cannot parse .toml configuration file ")
    }
    NRFAddrPort = c.NRFAddrPort
}

I would like to deploy my application in my Kubernetes cluster (3 VMs, a master and 2 worker nodes). After creating a docker and pushed to docker hub, when deploy my application using configMaps to parse the variables, my application runs for a few seconds and then gives Error. It seems the application cannot read the env variable from the configMap. Below is my configMap and the deployment.

apiVersion: v1
kind: ConfigMap
metadata:
  name: nrf-config
  namespace: default
data:
  config-toml: |
    Server="mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo"
    Database="nrfdb"
    NRFAddrPort = ":9090"
apiVersion: apps/v1 
kind: Deployment
metadata:
  name: nrf-instance
spec:
  selector:
    matchLabels:
      app: nrf-instance
  replicas: 1 
  template:
    metadata:
      labels:
        app: nrf-instance
        version: "1.0"
    spec:
      nodeName: k8s-worker-node2
      containers:
      - name: nrf-instance
        image: grego/appapi:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9090
        volumeMounts:
        - name: config-volume
          mountPath: /home/ubuntu/appapi    
      volumes:
        - name: config-volume
          configMap:
            name: nrf-config

Also one thing I do not understand is the mountPath in volumeMounts. Do I need to copy the config.toml to this mountPath? When I hard code these variable in my application and deploy the docker image in kubernetes, it run without error. My problem now is how to parse these environmental variable to my application using kubernetes configMap or any method so it can run in my Kubernetes cluster instead of hard code them in my application. Any help.

Also attached is my Dockerfile content

# Dockerfile References: https://docs.docker.com/engine/reference/builder/

# Start from the latest golang base image
FROM golang:latest as builder

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

# Copy the source from the current directory to the Working Directory inside the container
COPY . .

# Build the Go app
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

######## Start a new stage from scratch #######
FROM alpine:latest

RUN apk --no-cache add ca-certificates

WORKDIR /root/

# Copy the Pre-built binary file from the previous stage
COPY --from=builder /app/main .

# Expose port 9090 to the outside world
EXPOSE 9090

# Command to run the executable
CMD ["./main"]

Any problem about the content?

Passing the values as env values as

apiVersion: apps/v1 
kind: Deployment
metadata:
  name: nrf-instance
spec:
  selector:
    matchLabels:
      app: nrf-instance
  replicas: 1 
  template:
    metadata:
      labels:
        app: nrf-instance
        version: "1.0"
    spec:
      nodeName: k8s-worker-node2
      containers:
      - name: nrf-instance
        image: grego/appapi:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9090
        env:
          - name: Server
            valueFrom:
              configMapKeyRef:
                name: nrf-config
                key: config-toml
          - name: Database
            valueFrom:
              configMapKeyRef:
                name: nrf-config
                key: config-toml
          - name: NRFAddrPort
            valueFrom:
              configMapKeyRef:
                name: nrf-config
                key: config-toml

Upvotes: 1

Views: 1141

Answers (2)

kool
kool

Reputation: 3613

You cannot pass those values as separate environment variables as it is because they are read as one text blob instead of separate key:values. Current configmap looks like this:

Data
====
config.toml:
----
Server="mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo"
Database="nrfdb"
NRFAddrPort = ":9090"

To pass it as environment variables you have to modify the configmap to read those values as key: value pair:

kind: ConfigMap 
apiVersion: v1 
metadata:
  name: example-configmap
data:
  Server: mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo
  Database: nrfdb
  NRFAddrPort: :9090

This way those values will be separated and can be passed as env variables:

Data
====
Database:
----
nrfdb
NRFAddrPort:
----
:9090
Server:
----
mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo

When you pass it to pod:

[...]   
 spec:    
      containers:
      - name: nrf-instance
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9090
        envFrom:
        - configMapRef:
            name: example-configmap

You can see that it was passed correctly, for example by executing env command inside the pod:

kubectl exec -it env-6fb4b557d7-zw84w -- env
NRFAddrPort=:9090
Server=mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo
Database=nrfdb

The values are read as separate env variables, for example Server value:

kubectl exec -it env-6fb4b557d7-zw84w -- printenv Server
mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo

Upvotes: 1

Chris
Chris

Reputation: 23171

What you currently have will create a file in the mountpoint for each key in your config map. Your code is looking for "config.toml" but the key is "config-toml" so it isn't finding it.

If you want the keep the key as-is, you can control what keys are written where (within the mount) like this:

volumes:
  - name: config-volume
    configMap:
       name: nrf-config
       items:
          - key: config-toml
            path: config.toml

Upvotes: 0

Related Questions