Multi tier apps in Docker.io
Docker provides the means to link containers, which comes in two parts:
- Outside the container (on the docker command line) a ‘-link name:ref’ is used to create a link to a named container.
- Inside the container environment variables REF_… are populated with IP addresses and ports.
Having linked containers together it’s then necessary to have a little plumbing inside the containers to get the contents of those environment variables to the right place.
My example application
A while ago a saw a demo of Apcera, which used a little ToDo list application as a means to show off the capabilities of the platform. I thought a similar demo would be useful for CohesiveFT’s VNS3[1], and I found a suitable basis with theponti‘s sinatra-ToDoMVC app. My version of the app has been modified to use MySQL as a back end, and I also add Nginx as a front end to make a 3 tier demo.
If you want to just dive in
I’ve put my app into github, and it’s available as a trusted build from my page on the Docker public index. To just run it up start each tier in turn:
# first create the directory for persistent data: sudo mkdir -p /data/mysql # start the database sudo docker run -d -p 3306:3306 -name todomvc_db \ -v /data/mysql:/var/lib/mysql cpswan/todomvc.mysql # start the app server sudo docker run -d -p 4567:4567 -name todomvc_app \ -link todomvc_db:db cpswan/todomvc.sinatra # start the web server sudo docker run -d -p 443:443 -name todomvc_ssl \ -link todomvc_app:app cpswan/todomvc.ssl
The database
The MySQL database is the base dependency, so nothing happening here in terms of linking. I’ve adapted Ben Schwartz’s scripts for creating a MySQL Docker container to add in the creation of the ToDoMVC database.
The only other noteworthy thing happening here is the externalisation of the MySQL database storage back to the host machine using the -v flag.
The app server
This is linked back to the database with ‘-link todomvc_db:db’. Inside the container this gives various environment variables starting DB_. The appropriate one is parsed into the database URL within the Sinatra application using the following couple of lines of Ruby:
dburl = 'mysql://root:[email protected]' + ENV['DB_PORT_3306_TCP_ADDR'] + '/todomvc' DataMapper.setup(:default, dburl)
Note that the Dockerfile for the app server is grabbing the Ruby code straight from the docker branch of my fork of the sinatra-ToDoMVC application. If you want to see that database URL in context then take a look at the source for app.rb. The credentials being used here are what was set back in the database start script.
The web server
This is linked back to the app server with ‘-link todomvc_app:app’. Inside the container this gives various environment variables starting APP_. As Nginx can’t do anything useful with those variables it’s necessary to parse them into nginx.conf before starting the server, which is what the start_nginx.sh script is there to do:
#!/bin/bash cd /etc/nginx cp nginx.conf.template nginx.conf eval "echo \"`cat upstream.template`\"" >> nginx.conf service nginx start
The nginx.conf has been split into two templates. For the bulk of it (nginx.conf.template) there’s no need to environment substitution, in fact doing so will strip out env variables that need to be there. Only the upstream section is required so that:
upstream appserver { server $APP_PORT_4567_TCP_ADDR:$APP_PORT_4567_TCP_PORT; } }
Gets turned into something like:
upstream appserver { server 172.17.0.62:4567; } }
The trailing brace is there to complete the unfinished http section from the main nginx.conf.template.
That’s it :)
Browsing to https://docker_host/todos should get the todo list up.
Note
[1] For my demo with VNS3 I spread the tiers of the app across multiple clouds – almost the exact opposite of what’s happening here with all three tiers on the same host. In that case VNS3 provides the linking mechanism via a cloud overlay network – so there’s no need to tinker with the application config to make it aware of it’s environment – hard coded IPs are fine (even if they’re generally a config antipattern).
Filed under: code, Docker, howto | 3 Comments
Tags: address, app server, database, Docker, Docker.io, Dockerfile, enviornment, link, linking, MySQL, Nginx, port, Ruby, Sinatra, SSL, ToDoMVC, web server
Hi Chris!
thanks for sharing your docker experiences. i’ve been playing with it for a couple of months already but didn’t have the right amount of time necessary to write about it eheh
on the webserver part, instead of that cucumbersome setup, give a try to crosbymichael skydock (service discovery dns-based)! https://github.com/crosbymichael/skydock
Cheers,
Tiago.