K8s Change config map and update app log level

9/14/2019

I want to change config of log on Golang application which run on K8S, I’ve tried the following code locally and it works as expected I'm using viper to watch for config file changes

This is the config map with the log configuration

apiVersion: v1
kind: ConfigMap
data:
  config.yaml: 'log.level: error'
metadata:
  name: app-config
  namespace: logger

In the deployment yaml I’ve added the following

...
spec:
  containers:
    - name: gowebapp
      image: mvd/myapp:0.0.3
      ports:
        - containerPort: 80
      envFrom:
        - configMapRef:
            name: app-config

This is the code

package configuration

import (
   "fmt"
   "os"
   "strings"

   "github.com/fsnotify/fsnotify"
   "github.com/sirupsen/logrus"
   "github.com/spf13/viper"
)

const (
   varLogLevel     = "log.level
"
   varPathToConfig = "config.file"
)

type Configuration struct {
   v *viper.Viper
}

func New() *Configuration {
   c := Configuration{
      v: viper.New(),
   }

   c.v.SetDefault(varPathToConfig, "./config.yaml")
   c.v.SetDefault(varLogLevel, "info")
   c.v.AutomaticEnv()
   c.v.SetConfigFile(c.GetPathToConfig())
   err := c.v.ReadInConfig() // Find and read the config file
   logrus.WithField("path", c.GetPathToConfig()).Warn("loading config")
   if _, ok := err.(*os.PathError); ok {
      logrus.Warnf("no config file '%s' not found. Using default values", c.GetPathToConfig())
   } else if err != nil { // Handle other errors that occurred while reading the config file
      panic(fmt.Errorf("fatal error while reading the config file: %s", err))
   }
   setLogLevel(c.GetLogLevel())
   c.v.WatchConfig()
   c.v.OnConfigChange(func(e fsnotify.Event) {
      logrus.WithField("file", e.Name).Warn("Config file changed")
      setLogLevel(c.GetLogLevel())
   })
   return &c
}

// GetLogLevel returns the log level
func (c *Configuration) GetLogLevel() string {
   s := c.v.GetString(varLogLevel)
   return s
}

// GetPathToConfig returns the path to the config file
func (c *Configuration) GetPathToConfig() string {
   return c.v.GetString(varPathToConfig)
}

func setLogLevel(logLevel string) {
   logrus.WithField("level", logLevel).Warn("setting log level")
   level, err := logrus.ParseLevel(logLevel)
   if err != nil {
      logrus.WithField("level", logLevel).Fatalf("failed to start: %s", err.Error())
   }
   logrus.SetLevel(level)
}

Now when I apply the yaml file again and changing the value from error to warn or debug etc Nothing change … any idea what I miss here ?

I see in the K8S dashboard that the config map is assigned to the application and when I change the value I see that the env was changed...

update

when run it locally I use the following config just for testing but when using config map I've used the data entry according to the spec of configmap ...

apiVersion: v1
kind: ConfigMap
log.level: 'warn'
#data:
#  config.yaml: 'log.level: error'
metadata:
  name: app-config

This is how the config env looks in k8s dashboard

enter image description here

-- Jenny M
go
kubernetes

3 Answers

9/14/2019

envFrom creates environment variables from the config map. There is no file that changes. If you exec into the container you'll probably see an environment variable named config.yaml or CONFIG.YAML or similar (don' t know if it works with dots).

You are probably better of if you mount config.yaml as a file inside your pods, like this Add ConfigMap data to a Volume

-- Andreas Wederbrand
Source: StackOverflow

9/14/2019

I understand that viper can help with live changing out of configuration without restarting your app using the OnConfigChange event, but have you tried setting the log level in your base ConfigMap and then starting up the app, just to make sure it's not an issue with the OnConfigChange event firing and your particular config in k8s (and not your local environment where you've tested it works).

Lastly, what is the difference between your local test environment (where this is working) and the other environment where this is not working?

Are there any environment variables that might be affecting this differently in the one environment?

-- Shogan
Source: StackOverflow

9/14/2019

If you mount a ConfigMap using a volume, whenever you update the ConfigMap, then the volume updates automatically.

However, if you mount a ConfigMap using an environment variable, even if you update the ConfigMap, your environment variables do not get updated inside the containers.

If you want the configurations to update inside your containers, I would suggest you either:

  • use volumes to mount ConfigMaps.
  • restart your containers every time the ConfigMap is updated if you use an environment variable to mount it.
-- Alassane Ndiaye
Source: StackOverflow