spf13 / viper

Go configuration with fangs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

WatchConfig() does not work inside container

lylex opened this issue · comments

commented

viper version: v1.7.0
go version go1.14.3 darwin/amd64
OS version: MacOS 10.15.2

I am using WatchConfig() to do hot config job. I mount a config file to container, which is watching by the app. The expected behavior is, when I updated the config file, the app inside the container will feel about it. However, it failed in my test.

Here is how reproduce it:

(main.go)

package main

import (
	"log"

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

var Config config

type config struct {
	Name string `mapstructure:"name"`
}

func main() {
	viper.SetConfigFile("config.yaml")
	viper.AddConfigPath(".")
	viper.AddConfigPath("./config")
	viper.SetConfigType("yaml")
	if err := viper.ReadInConfig(); err != nil {
		log.Fatal(err)
	}

	if err := viper.Unmarshal(&Config); err != nil {
		log.Fatal(err)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(event fsnotify.Event) {
		if event.Op == fsnotify.Write {
			if err := viper.Unmarshal(&Config); err != nil {
				log.Fatal(err)
			}
			log.Printf("Change occurs %#v", Config)
		}
	})
	select {}
}

(Dockerfile)

FROM ubuntu:18.04

WORKDIR /

COPY ./config.yaml .

COPY ./m .

ENTRYPOINT ["/m"]

(docker-compose.yml)

version: '2.4'

services:

  mmmmm:
    image: mmmmm:latest
    container_name: mmmmm
    volumes:
      - ./config.yaml:/config.yaml
    restart: unless-stopped

The config.yaml mod set to 666.
After I build the docker image, and up the docker-compose, I edit the config.yaml file, and save it. The app inside the container does not feel it. I am sure that the inode of the config.yaml keeps the same both inside and outside the container, and the file is changed both inside and outside the container.

I am not sure whether this feature is used in a proper way, but I really have no idea about what is going on there. Much appreciated if someone can help me out.

commented

I just tested on CentOS 7, also failed.

The reason this happens is that viper sets a watch on the directory containing the file, not the file itself. In my case the solution was to mount the config directory instead of the file, but this won't work for everyone.

I'm running into similar issue where I do the following:

	viper.AddConfigPath(".")
	viper.SetConfigType("yaml")

	// config.yaml
	viper.SetConfigName("config")

	// other.yaml
	viper.SetConfigName("other")

	// watch config
	viper.OnConfigChange(func(e fsnotify.Event) {
		// something
	})
	viper.WatchConfig()

Viper isn't watching the main config (config.yaml) but only the secondary config (other.yaml). Is this normal behavior?

In Dockerfile, add "RUN add bash" before COPY,Using the way of bash to change config.yml can finish viper watch the operation of update config.yml file When docker image is running.

这个容器中如何才能成功监视配置文件?

Hello all, are there already solutions for this? Or another workaround than to read out the config in intervals?

I was looking at how to use WatchConfig and found this issue.
I did basically as @lylex did, and using the example below worked in my case.

viper.WatchConfig()
viper.OnConfigChange(func(in fsnotify.Event) {
	if in.Op == fsnotify.Write {
		err := viper.Unmarshal(config)
		if err != nil {
			log.Error("Error to unmarshal new config changes: ", err)
			return
		}
	}
})

for my Dockerfile:

WORKDIR /app
COPY . /app

and docker-compose:

 volumes:
      - ./:/app 

When I change the config file, it gets the new config... I put some logs to see if it works and it worked.
If someone wants to see more details, here is the repo:
https://github.com/diegoclair/go_boilerplate

As @kylrth said, may it have something with how you do the volume mount, to not mount the file, but the directory.

commented

@diegoclair Thanks for the suggested solution, I tried to do the same, but nothing works

commented

I had a similar problem, it was about the fact that I mounted a directory instead of a file (as inline docker volumes are black magic)

Maybe updating the error to "file is a directory" can be useful for later debugs.