Dockerize your Development Env with Example
In the previous post, I wrote the basics and walkthrough on how to dockerize your local development environment. After that, I was requested to write a more concrete example, so this is a post with actual example from one of my personal rails projects.
For this application, I don’t use Docker for production (yet) so it is relatively simple to start with, becasuse I didn’t have to worry about production impact.
In case you haven’t yet, I recommend you check out previous post frist, because it will give you necessary technical backgrounds to understand each section below.
[Edit] One of my coworkers pointed out that we can use named volume for DB persistence instead of docker-syncing it. I will update the post once I confirm the updated setting works. [Edit2] I have been choosing setting up a DB on host and use host.docker.internal
when doing so is not difficult and there have been less pains.
Files
These files and the setup work for MacOS X, High Sierra and Mojavi. I haven’t confirmed any other version of MacOS. And I haven’t changed anything for publication purpose. So these are the real files I use.
- Dockerfile
- docker-compose.yml
- config/database.yml (partial)
- docker-sync.yml
- setup_local_docker.sh
Dockerfile
Here’s my Dockerfile.
I said it is not used in production, but it’s still nice to consider production usage as a future possibility. That’s why I used BUILD_ENV here.
I added git and less for dev environment. less is for a better paging on rails console.
Just in case the base image ruby:2.5.3 is Ubuntu based.
docker-compose.yml
Here’s my docker-compose.yml.
You should rename this to something like docker-compose.local.yml when you have to use docker-compose for production, which is not the case for me.
I also expose 13306 to the host machine, so I can easily interact with docker based mysql data.
“volumes” are the ones managed by docker-sync, which protects you from the hell of slowness of your local docker.
The options stdin_open
and tty
are for “binding.pry” which I will explain later.
config/database.yml (partial)
Since we need to provide docker MySQL host, I put DOCKER_DB
as an environment variable. Here’s a change I made so it tries to picks up the env var when exists.
docker-sync.yml
Like I mentioned in the previous post, without using docker-sync, the performance is atrocious. Docker’s solution of using cache
or delegate
does not help much at the point of this writing.
I have 2 volumes, one is for application source code, the other one is database data. It’s OK if you don’t volume-mount the database but docker-compose down
will wipe your data, so please keep that in mind.
setup_local_docker.sh
And I have a bash script that glues the whole build and preparation process for my local Docker env. By running this command, even on a new MacOS machine, I can recreate my local docker environment many times.
Don’t forget to do chmod +x
before running ./setup_local_docker.sh
How to do “binding.pry”
During the development, binding.pry is useful. Here’s how you can do it with local docker.
- Make sure your containers has started already.
- Type
docker ps
to check the app container name - Type
docker attach {your_container_name}
to attach to the docker process. - Now you can interact with Rails server process where you put
binding.pry
- Type
<ctrl> + p
then<ctrl> + q
to end the pry session. Do NOT do<ctrl> + c
because that would stop the container process itself.
For a little bit more complicated projects
My personal project is really simple so there is just one app container but I believe people do something more complicated. I actually dockerized Rails application with a sidekiq container (at work), too.
I had to have sidekiq
under services
which is very similar with app
section, but I don’t think it’s difficult for you to figure it out on your own :)
Happy local development with Docker!