Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WatchConfig() does not work inside container #920

Open
lylex opened this issue Jun 1, 2020 · 9 comments
Open

WatchConfig() does not work inside container #920

lylex opened this issue Jun 1, 2020 · 9 comments

Comments

@lylex
Copy link

lylex commented Jun 1, 2020

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.

@lylex
Copy link
Author

lylex commented Jun 2, 2020

I just tested on CentOS 7, also failed.

@kylrth
Copy link

kylrth commented Aug 11, 2020

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.

@ghost
Copy link

ghost commented Nov 22, 2021

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?

@t8426542
Copy link

t8426542 commented May 16, 2022

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.

@AzraelJi
Copy link

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

@gowizzard
Copy link

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

@diegoclair
Copy link

diegoclair commented Sep 22, 2022

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.

@Verteletsky
Copy link

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

@kantum
Copy link

kantum commented Jun 28, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants