spf13 / viper

Go configuration with fangs
MIT License
26.39k stars 2.01k forks source link

can't watch the file when the config file volume mount in docker. #1529

Open lr638638 opened 1 year ago

lr638638 commented 1 year ago

Preflight Checklist

Viper Version

1.8.1

Go Version

1.16

Config Source

Files

Format

JSON

Repl.it link

No response

Code reproducing the issue

No response

Expected Behavior

My programs is running in docker (Docker version 19.03.5, build 633a0ea838)

docker run -it -v /etc/config.json:/etc/config/config.json

have add the code as bellow: c.Viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("abc:OnConfigChange") c.Update() }) c.Viper.WatchConfig()

modify /etc/config.json in local host

can't print log "abc:OnConfigChange"

modify the codes in viper.go:498 watcher.Add(configDir) watcher.Add(configFile) //add by me

Do step 1 and 3 again

print the log "abc:OnConfigChange"

It's have bug when the config file volume mount in docker.

Actual Behavior

My programs is running in docker (Docker version 19.03.5, build 633a0ea838)

docker run -it -v /etc/config.json:/etc/config/config.json

have add the code as bellow: c.Viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("abc:OnConfigChange") c.Update() }) c.Viper.WatchConfig()

modify /etc/config.json in local host

can't print log "abc:OnConfigChange"

modify the codes in viper.go:498 watcher.Add(configDir) watcher.Add(configFile) //add by me

Do step 1 and 3 again

print the log "abc:OnConfigChange"

It's have bug when the config file volume mount in docker.

Steps To Reproduce

My programs is running in docker (Docker version 19.03.5, build 633a0ea838)

docker run -it -v /etc/config.json:/etc/config/config.json

have add the code as bellow: c.Viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("abc:OnConfigChange") c.Update() }) c.Viper.WatchConfig()

modify /etc/config.json in local host

can't print log "abc:OnConfigChange"

modify the codes in viper.go:498 watcher.Add(configDir) watcher.Add(configFile) //add by me

Do step 1 and 3 again

print the log "abc:OnConfigChange"

It's have bug when the config file volume mount in docker.

Additional Information

My programs is running in docker (Docker version 19.03.5, build 633a0ea838)

docker run -it -v /etc/config.json:/etc/config/config.json

have add the code as bellow: c.Viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("abc:OnConfigChange") c.Update() }) c.Viper.WatchConfig()

modify /etc/config.json in local host

can't print log "abc:OnConfigChange"

modify the codes in viper.go:498 watcher.Add(configDir) watcher.Add(configFile) //add by me

Do step 1 and 3 again

print the log "abc:OnConfigChange"

It's have bug when the config file volume mount in docker.

github-actions[bot] commented 1 year ago

👋 Thanks for reporting!

A maintainer will take a look at your issue shortly. 👀

In the meantime: We are working on Viper v2 and we would love to hear your thoughts about what you like or don't like about Viper, so we can improve or fix those issues.

⏰ If you have a couple minutes, please take some time and share your thoughts: https://forms.gle/R6faU74qPRPAzchZ9

📣 If you've already given us your feedback, you can still help by spreading the news, either by sharing the above link or telling people about this on Twitter:

https://twitter.com/sagikazarmark/status/1306904078967074816

Thank you! ❤️

josmartin commented 7 months ago

This issue is a confluence of some choices viper has made along with the behaviour of docker. The choice viper made was to watch folders and not specific config files in viper.go

configFile := filepath.Clean(filename)
configDir, _ := filepath.Split(configFile)
realConfigFile, _ := filepath.EvalSymlinks(filename)
...
watcher.Add(configDir)

Inside a docker container where you ONLY mount a file, not a folder

docker run -it --rm -v /etc/config.json:/etc/config/config.json container

folder based inotify events are NOT triggered for folder /etc/config when config.json is changed (assuming that /etc/config already exists in the container). You can fairly trivially observe this by compiling up the code below and running against a docker container

package main

import (
    "log"
    "os"

    "github.com/fsnotify/fsnotify"
)

func main() {
    // Create new watcher.
    watcher, err := fsnotify.NewWatcher()
    if err != nil {
        log.Fatal(err)
    }
    defer watcher.Close()
    // Start listening for events.
    go func() {
        for {
            select {
            case event, _ := <-watcher.Events:
                log.Println("event:", event)
            case err, _ := <-watcher.Errors:
                log.Println("error:", err)
            }
        }
    }()

    log.Println("Watching: " + os.Args[1])
    err = watcher.Add(os.Args[1])
    if err != nil {
        log.Fatal(err)
    }
    // Block main goroutine forever.
    <-make(chan struct{})
}

Building this into a docker container

FROM ubuntu
COPY fsnotify-test /fsnotify-test
ENTRYPOINT ["/fsnotify-test"]

And running it against files and folders will show the difference. First cross-mount test as a file, watch it directly and on the host touch test once the container is running.

$ docker run -it --rm -v ./test:/test fsnotify-test /test
2023/11/22 14:51:14 Watching: /test
2023/11/22 14:52:46 event: CHMOD         "/test"

Now watch / rather than the file specifically and touch test

$ docker run -it --rm -v ./test:/test fsnotify-test /
2023/11/22 14:53:37 Watching: /

No notification.

Finally, cross-mount whole folder and watch whole folder, and touch test

$ docker run -it --rm -v ./:/config/ fsnotify-test /config
2023/11/22 14:54:55 Watching: /config
2023/11/22 14:54:59 event: CHMOD         "/config/test"

@lr638638 This allows a temporary workaround to your issue which is to ensure that in a docker container you mount whole folders with your config in and not just a single file. If you do this you will see the modifications to the config files.

However, for viper, it would either be good to document that it ONLY really supports whole folder watching inside docker container (where many of your users will end up), or consider revisiting the choices in WatchConfig and perhaps watching the specific files that you know hold the config rather than the folders.