Docker for Local Development
The requirements for local Docker is different from production. Also there are unique difficulties of running Docker on your local, too. This post is about what I learned so far regarding how to use Docker comfortably for our daily development after trial and error.
(Edit) I added a link to real files I use at the bottom of this post, but first please read through this!
First I’d like to mention some assumptions here.
- You do daily development on your local machine
- Nowadays you are likely to use Docker for production through some sort of container services such as AWS ECS, so docker-compose is only for local (and/or non-production) environment.
- This post is about MacOS X as your local host, although you should be able to have local Docker setup on other platforms in a similar way.
- This post uses Ruby on Rails, PostgreSQL, Sidekiq and Redis as services.
Requirements Unique to Local Development
- Debug: You might want to use pry or pry-byebug here.
- You want to mount the source code from your host machine and if you make changes on the host machine, you want to see the changes on the service on Docker containers seamlessly.
- You want to have a shell access to your local containers.
- You want to access to your application with http://localhost:3000
Basic Setup
This basic setup is taken from https://docs.docker.com/compose/rails/, in which case the base OS seems to be Ubuntu. I won’t include database.yml here so check it on the link!
Dockerfile
Change directory paths appropriately.
docker-compose.yml
Change directory paths appropriately here also.
Maybe you have noticed that some unfamiliar things have been added here, such as BUILD_ENV
or automatically bundle install
, removing pid file, enabling tty and stdio from app container.
BUILD_ENV is a way to specify a env the current Docker build is built for. You specify the default value in Dockerfile itself, but you can override the value in docker-compose.yml for local environment as above. The next section explains about it.
Also sometimes container stops accidentaly before it deletes the Rails pid file. After that happens, Rails won’t start because there is an old pid file remaining from the previous container start.
tty
and stdin_open
options are necessary if you want to debug with pry.
What if you want something special only for local on Dockerfile?
ARG is useful when you want to do something special for your local development only, and that’s what you saw in docker-compose.yml above. So add something like the following to the Dockerfile above.
The docker-compose.yml above takes care of BUILD_ENV
automatically but when you build image for development manually, specify BUILD_ENV=dev
and development necessities will be installed.
Discussions
1. Development DB vs Test DB
Although you should have one service per container based on Docker philosophy, you might feel too much having 2 databases (dev and test) running for one application on your local machine. In fact, we put them together, but that means you have to do rake db:setup RAILS_ENV=test
when necessary.
2. Speed up your local
You might find your local Docker application is sluggish when you access to it on your blowser. First try the Docker mount option delegated
in docker-compose.yml as documented here: https://docs.docker.com/compose/compose-file/#caching-options-for-volume-mounts-docker-for-mac
If you think that’s not enought, docker-sync is a very powerful tool so you can have native file access speed. But sometimes it causes troubles which was the case for me, too. So there is a tradeoff. If I have a chance, I will write another post about docker-sync.
3. Downside of putting the production/local Docker together
I had those two files (Dockerfile, Dockerfile.local) separated at the beginning since there were significant differences due to our own unique requirements related to Terraform, but thanks to some requirement change I put them together with the help of ARG at one point. But after that, every time I made changes on Dockerfile for local development I had to worry about the impact on production Docker image. So in my opinion, it still makes sense to have a separate Dockerfile.local, if you make a lot of changes and experiments for your development. And hey, even if you make duplication of codes which you and I don’t like, it’s always just two of them, guaranteed (or at least constant number).
Useful Bash Commands for Local Docker
Now I think you have all the necessary information for local docker setup. Congratulations!
Lastly these are the bash commands (mainly docker-compose commands) I use for daily local development. Hope this is useful to you, too.
Also, you can always use docker
commands, of course, whenever nencessary.
Happy local development with Docker!
[Edit] Added a post with a real example here.