“Why isn’t my Docker bind mounted file updating from host to container when I make changes with vim?”

The inodes have it

Table Of Contents
show

When setting up the TIG stack, I saw that Telegraf has an option to reload its configuration from telegraf.conf, which it does on receiving a SIGHUP signal. Since in Docker, it gets pid 1, reloading config is easy:

docker exec -it telegraf /bin/kill -HUP 1

Which worked well.

At least until some changes I made weren’t showing up in the telegraf Docker log output. Not only that, inspecting the file in the container shows the old contents. What gives?

The Problem

A bit of searching eventually led me to an article by Jonas Bunevičius (NB Medium link), which explained that if a file’s inode changes, Docker won’t see it.

When vim saves a file, it writes the contents to a new file (U&L link) at a different inode, and replaces the old file with the new one at the existing inode. We can see this happening:

the inode for telegraf.conf changes from 1573281 to 1573282 after vim saves

This makes sense of the behaviour we see- Docker still has a handle to the file at the old inode (which will remain unchanged if a new file replaces it) so the container will continue to see the old content.

The Solution for Vim

tl;dr: use a modeline to set backup options to write the changes to the current file

We have a number of options to get around this. One is to use an editor that doesn’t cause inode changes, such as nano. That’s an option, but I might forget to always use nano and then get confused when changes didn’t propagate.

Another option is to bind mount a directory to the container rather than a file. This isn’t a great option for telegraf, since there are other config files in /etc/telegraf in the container.

So we can change vim’s behaviour. As explained in the answer to the QA, changing the backup, backupcopy and writebackup options change what vim does during its save process. The options are summarised nicely in a table:

                                                        backup-table
'backup' 'writebackup'  action  
   off       off        no backup made
   off       on         backup current file, deleted afterwards (default)
   on        off        delete old backup, backup current file
   on        on         delete old backup, backup current file

But I don’t want to change behaviour globally, just for this file. So I can use a modeline to do so (provided both modeline is enabled and modelines is set to a positive integer- check via :verbose set modeline? modelines)

So, after some kind help from romainl in #vim who helped me track down my my modeline wasn’t being read (I had a missing end : when using the set: syntax, which I had thought was optional!), I ended up with:

# vim: bkc=yes bk wb

which keeps the inode for telegraf.conf intact.

Tell us what's on your mind