crafting (and) JavaScript

Docker vs. docker-compose

After clarifying why I use Docker for every project I set up let me try to clarify also: Why would I use a docker-compose setup over a single Dockerfile setup? I had been doing the single Dockerfile setup for quite a while. I was doing a lot of manual work, that made the setup work. But I don't regret it, it taught me a lot! But that was not sustainable, and it didn't scale.

How I Automate every Projects' Setup

My setup with one docker container always contained a run.sh file, and a Dockerfile. The run.sh file grew over time and taught me a lot of bash, but docker-compose does all I need without any bash scripting. More about that in a bit. The run.sh had the following purposes:

  1. start and enter a container - via ./run.sh bash I built, started, entered a container and landed on the command line inside that container
  2. enter a running container - the above command also detected if a container was already running and just entered it, basically opening a second shell inside the container (via docker exec)
  3. build the image on demand - when I changed the Dockerfile (the definition of the container) docker needs to rebuild the container, my run.sh did this (more or less well) on demand
  4. configure the docker runtime - when running a docker container you might need to expose a port (for a web server running inside the container) or you need to map a folders into the container, so you can work with the files inside the container. All these things were inside my run.sh.

docker-compose ftw

Long story short: docker-compose does all that. A bit different, maybe not as convinient, but in a standardized and consistent way. Additionally docker-compose does it for any number of containers!

For using docker-compose I use this docker-compose.yml file. All things I configured in my run.sh before are in this file. Using docker-compose I do the above like this:

  1. start and enter a container - this needs two commands with docker-compose, 1) docker-compose up -d starts the container(s) in the background and 2) docker-compose exec <name> bash opens a bash in the container with <name>
  2. enter a running container - just like before, docker-compose exec <name> bash opens a bash in the container with <name> the <name> is defined in the docker-compose.yml file as the service's name
  3. build the image on demand - docker-compose build this builds all docker containers as needed, docker-compose build --pull will try to find newer docker images, e.g. when you just used the image "node"
  4. configure the docker runtime - all the configuration of mapping ports or volumes are done in the docker-compose.yml file, normally located at the root of the project's directory.

In the README.md I also described how I am using docker-compose for this project.


I am quite happy with that setup now. Every project works the same. I am thinking of using the same name "app" for the main container, so I can always do docker-compose exec app bash to enter the app (or main) container. This could make it even more unified and easier. The docker-compose.yml file I use for this site the container is called "picostitch" right now, which I need to know. Not as ideal as using "app" every time.