Hacker News new | ask | show | jobs
by ddtaylor 1234 days ago
I use Docker from time to time, but one question I have is more about workflow. How are people editing files within existing containers without resorting to one of the following:

1. Rebuilding the entire container which often involves stopping and starting it, etc.

2. Manually running commands that copy the files into the container. This is irritating because if I forget which files I changed or forget to run the copy command I end up with a "half updated" container.

3. SSHing into the container. This is irritating because I have to modify the port layout and permissions of the container and later remember to "restore" them when I'm "done" making the container.

Thanks!

6 comments

Containers are supposed to contain the entire stack a program needs to run. When you want to update anything in there, the correct answer is to build a new image.

Of course, this means that you'll not just stop, but completely destroy the old container and start a new one (created from the new image). You can get this to happen without service downtime by using the very same techniques that you'd use on any high availability / multi-server enviornment (rolling upgrades, canary deployments, etc.).

If you need to have some files that persist across these upgrades, then you use volumes and/or bind mounts. These allow you to have folders that persist independently of the container's lifecycle. They are typically used to store things like a sqlite database that the container uses, the set of configuration files that you can edit on a per-instance basis, etc.

Finally, there's a big case where you ignore all of the above: when you use containers as a development tool. In that case, particuarly for "interpreted" languages (python, php, ruby, etc.) it becomes extremely useful to bind-mount your pograms' sources inside a development container. You can then develop normally but also change the entire system where your app runs extremely easily. You can also keep different environments (language version, libraries, configuration of all those) for different projects without any change for conflicts between them, etc.

You didn't specify, but it sounds like you're talking about from a development perspective, not a deployment one.

For development, you add a volume to the container and mount a location on that volume to a location on your host hard drive. There are different mount options that control which changes propagate in which direction, but two-way propagation is avaliable and works fine.

Once you have this set up, any changes you make on your host system are automatically reflected in your containers volume. It's very low stress and low overhead, honestly.

Volumes.

This works, however, only if you know beforehand which files you’re going to update frequently.

What kind of files would you like to change? Anything that comprises the environment within the container (image) is indeed changed by rebuilding the container, but not the whole - just the layers which changed. Layering in a smart way increases reuse. Also, this way you reflect versions (tags) of the environment. Configuration can be passed in via parameters.

The data you work with should be stored externally (volume, database, accessed via API, …). You don‘t keep persistent state of your workload in the container.

I generally put a Dockerfile.dev that creates a user with the same GID and UID as my own (injected through environment variables):

    RUN adduser -u $UID...
    USER node
Then in the docker-compose you bind mount your current directory.

    volumes:
      - ./:/app/
Don't do 2 - use a bind mount instead!