More and more companies switch to using Docker in the development process. The easiness to set up the whole environment is really astonishing. That’s why I wanted to give you a quick recipe how to set up Rails and Postgresql containers to work with each other. This is especially useful when you hire a new developer who instead of setting the whole thing up on his own can depend on the configuration that is defined in one file and run it with one easy command.
If you didn’t see my previous article which takes you through a Rails application in Docker set up go and read it first, as this tutorial is a continuation.
So you have your Rails application set up. You can use your host’s Postgresql server for this application, but if you already have Docker installed it would be beneficial to have the database also run as a container. That way you can have separate server for each of your applications. This is especially useful when you develop multiple applications and each of them works on a different version of the database server.
Normally you would start a docker container with
docker run command but this becomes to be tedious very quickly, when you need to pass more arguments to it (for example database set up). It gets even more complicated when your application needs some other services to like RabbitMQ, Elasticsearch or any other external service.
For that purpose we’ll use a handy tool which comes with the Docker -
docker-compose. It will let you specify all the services and arguments to run your application.
Let’s get to it!
Go to your project’s root directory and create
version: '2' services: hello_docker: build: context: . dockerfile: Dockerfile image: hello_docker ports: - 3000:3000 links: - postgres:postgres environment: DATABASE_NAME: hello_docker DATABASE_USER: my_user DATABASE_PASSWORD: my_password DATABASE_HOST: postgres command: dockerize -timeout 30s -wait tcp://postgres:5432 bash -c "bundle exec rake db:migrate && bundle exec rails s" postgres_data: image: busybox container_name: postgresql_data volumes: - /var/lib/postgresql/data postgres: image: postgres container_name: postgresql environment: POSTGRES_DB: hello_docker POSTGRES_USER: my_user POSTGRES_PASSWORD: my_password volumes_from: - postgres_data
This is how
docker-compose.yml should like. It starts three containers: our Rails application, Postgresql server and one data container for postgres data (thanks to that we won’t lose data when new postgres container is started).
One thing worth noting is
links: - postgres:postgres
This will make
postgres container available in our Rails application container under
postgres host i.e. when you run
ping postgres from the Rails container you should get a positive response.
The other thing is
command. This runs
rails s through
dockerize which is a handful tool to specify that we want to wait a while before starting Rails application. In this case we will wait at most 30 seconds for the Postgres server to boot up. This way we will avoid starting Rails application before the database server which would result in an error.
dockerize won’t work out of the box - you need to install it. To do so edit
Dockerfile and add this somewhere at the top.
RUN apt-get install -y wget && \ wget https://github.com/jwilder/dockerize/releases/download/v0.2.0/dockerize-linux-amd64-v0.2.0.tar.gz && \ tar -C /usr/local/bin -xzvf dockerize-linux-amd64-v0.2.0.tar.gz
OK! We are almost ready. Two more things to do.
a) You need to pass a database configuration to the
database.yml. This is easy to do, because you can use erb there. This means you can execute Ruby in
database.yml, and this means you have an access to the
Look at the
docker-compose.yml file. We told our
docker_hello container to set few envs like:
They all hold information of the database connection.
Let’s use those in the
development: adapter: postgresql encoding: unicode database: <%= ENV["DATABASE_NAME"] %> pool: 5 username: <%= ENV["DATABASE_USER"] %> password: <%= ENV["DATABASE_PASSWORD"] %> host: <%= ENV["DATABASE_HOST"] %> test: adapter: postgresql encoding: unicode database: <%= ENV["POSTGRES_DB"] %> pool: 5 username: <%= ENV["POSTGRES_USER"] %> password: <%= ENV["POSTGRES_PASS"] %> host: <%= ENV["POSTGRES_HOST"] %> production: adapter: postgresql encoding: unicode database: <%= ENV["POSTGRES_DB"] %> pool: 5 username: <%= ENV["POSTGRES_USER"] %> password: <%= ENV["POSTGRES_PASS"] %> host: <%= ENV["POSTGRES_HOST"] %>
b) You need to install
pg gem. Add it into the Gemfile.
Now you need to rebuild the
hello_docker image in order to copy new
database.yml configuration, install
After rebuilding the
hello_docker image we are ready execute
docker-compose up command which will start all the containers with a configuration specified in
docker-compose.yml. Do it now.
If everything went as expected you should be able to go to
localhost:3000 in your browser and see working Rails welcoming screen.