Few posts ago i wrote about rails sandbox and isolated development environment using Vagrant and Chef Solo. But there’s more options available. One of them is gets more and more traction and gains popularity. It’s the Docker.
Docker in it’s concept is similar to Vagrant but yet different. It also wrap your software in separated environment called container as Vagrant does with Virtual Machine. But the difference is that containers doesn’t posses it’s own OS but it’s share kernel with other containers. They run in isolated userspace on the host operating system.
If you haven’t worked with Docker before you should go through Docker tutorial. It explains all basic concepts of working with Docker.
Container configuration in concept is similar to Vagrant it sits in single file
Dockerfile. So let’s say we want to prepare container to work with Ruby on Rails.
Not digging into further details let’s describe what we’ll need to run rails application on Ubuntu machine
- basic development tools (build-essential package)
- nokogiri dependencies (libxml2-dev libxslt1-dev)
The we need add our application to container, install all necessary gems and we’re ready to go.
Let’s roll up sleeves define the
Now we need to build this image and it’ll be ready to use.
docker build -t image_name .
To run rails application we need to issue command
docker run image_name rails server.
But there are some problems. Code is embedded into image, we don’t know what ip has container and we cannot go through firewall at standard rails port 3000.
Docker client takes numerous of parameters but right now only few of them are needed.
-v /host/path:/container/pathwill mount path from host system into container
-p host_port:container_portwill expose ports to host
Now we need to run
docker run -p 3000:3000 -v ~/code/docker/rails-app:/app/rails_application image_name rails s -b 0.0.0.0
This will start rails application as you usually do but in docker container.
YAY! We could quote “That’s all folks!” but what if …
… what if we want to be more complex, have separate container for different parts of application. Let’s say we need separate containers for PostgreSQL and Redis. How to handle this?
I say we could use
docker-compose tool. All what it needs is another file that will hold whole configuration,
docker-compose.yml. But we need adjust out
Dockerfile first and install packages for postgres client.
Having that we can take care of
Each top level section defines separate container. 2nd level are docker parameters so for
web container we specify command to issue, mount volume, expose port (bonus points for being able to specify hostname/ip) and link with other containers.
As you can see if we remove new parts (linking and other containers) we are pretty much doing same things like command from previous section.
To spin up this configuration all we need is to execute
docker-compose up and off we go because
- if there is no image present locally composer will download it
- if there was changes in images composer will update them
- it there was changes in
Dockerfilecomposer will rebuild it
The Another But
Of course there will be some issues. There is always something. So things worth considering:
- is data persistent
- how to scale this solution
- deployment process
- what will happen when images will be updated
- configuration for multiple host OS (is this needed?)
- duplication of environment variables and how to reuse them
- gems caching (rails specific)
- testing and automation (rails specific, guard)