- Summary
- How to run containers
- For development environment
- Deployment
- Manage persistent data
- TIPS: Zero time deployment with CoreOS and vulcand
This repository is a example project by Rails with Resque worker. The structure of the project is following; quite simple:
███████████████████ ███████████████████
███████████████████ ███████████████████
███████Redis███████ ██████Postgre██████
███████████████████ ███████████████████
███████████████████ ███████████████████
┼ ▲ ▲
│ │ │
Load ┌─────────┘ │ │
information │ │ ┌─────────────────────┐
for job │ │ │ Rails │
╱│╲ │ │ Web application │
┌─────────────────┐ │ │ │
│ │ │ │ ┌──────────────┐ │
│ Rescue worker │ │ Register jobs │ │ │ │
│ │ └────────────────┼───│ Resque Task │ │
│ │ │ │ │ │
└─────────────────┘ │ └──────────────┘ │
└─────────────────────┘
- Rails
- Resque
- It can be used by Rails and also worker is run independently
- It is expected to be run as several workers
- Postgre
- DB for models of Rails
- Redis
- For Resque
- Data container
- data-only-container for persistent data like temporary file and data for DB
- This is mounted to containers
These are required to run it as Docker containers.
- docker
- docker-compose
All you have to do is bellow:
docker-compose up
For development environment, you can use docker-compose-development.yml
on your local machine.
It is basically same as docker-compose.yml
for staging or production environment but it shares your local Rails project with web container with using same image as staging/production.
When you update code, you can see changes for it as you run rails server
on your local too.
This is docker-compose-development.yml
:
web:
build: .
links:
- postgres
- redis
ports:
- "80:80"
# Following is development configuration
command: /bin/bash -c "rake db:migrate && rails server -b 0.0.0.0 -p 80"
environment:
RAILS_ENV: development
volumes_from:
- data
# ...
# omitted some lines...
# ...
data:
image: busybox
volumes:
- /tmp
# For postgres
- /var/lib/postgresql/data
- .:/usr/src/app
Currently, this example does not support hot-deployment. This example has deployment task by capistrano but it needs to restart all containers when you want to update application.
This is example to deploy these containers to a Ubuntu 14.04 droplet on DigitalOcean.
Install the latest Docker by following documentation: Ubuntu - Docker Documentation
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
sudo sh -c "echo deb https://get.docker.com/ubuntu docker main \
apt/sources.list.d/docker.list"
sudo apt-get update && \
apt-get install -y lxc-docker
Install Docker Compose
curl -L https://github.com/docker/compose/releases/download/1.1.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod a+x /usr/local/bin/docker-compose
It needs that deploy
user to deploy source code to this droplet.
sudo adduser deploy
sudo passwd -l deploy # Do this to make password string which is not able to input
Add deploy user to docker
group to be able to execute docker
command.
sudo gpasswd -a deploy docker
And create key for deploy user.
su deploy
ssh-keygen -t rsa -C "deploy"
Create deploy key of your repository with key of deploy user: Managing deploy keys | GitHub API
After set up deploy key of your repository, you can clone your repository via git command like this:
git clone [email protected]:your-username/your-repo.git
To deploy the application to droplet, it has capistrano file. Execute deployment manually by executing this command:
DEPLOY_TARGET_HOST=your.host.name bundle exec cap staging docker:deploy
docker.rake
has 3 tasks.
- update
- Update git repository of Rails project
- build
- Build Docker images
- deploy
- Run Docker containers
- This task executes 3 commands of
docker-compose
: stop, rm and up. You don't have to care of containers running as it stops all of running containers.
Building images and running containers works by execute docker-compose
.
See docker-compose.yml
You may meet this error while you build your Docker image:
Your compiler failed with the exit status 4. This probably means that it ran out of memory. To solve this problem, try increasing your swap space: https://www.digitalocean.com/community/articles/how-to-add-swap-on-ubuntu-12-04
You can upgrade space to add swap space following this procedure: How To Add Swap on Ubuntu 14.04 | DigitalOcean
I confirmed that swap 4GB works for this project.
This project has a sample circle.yml
to deploy it to DO's droplet.
This project uses data-only-container for portability of persistent data, for example, temporary file which is needed by the application, DB data and etc. It follows the instruction in Documentation of Docker: Managing data in containers - Docker Documentation and There's nothing new to the documentation.
This project has Resque job, FileCreator
. This is just to create file when the new post was created. And file is saved in /tmp
in production; this is sample so it is meaningless!. See config/settings/production.yml
and app/jobs/file_creator.rb
.
Following is the way to backup files which was saved in /tmp
and restore them.
In this case, it just needs to create backup file from container directory and extract it to container.
# Create backup as a tar file
docker run --volumes-from railsdockerexample_data_1 -v $(pwd)/backup:/backup busybox tar cvf /backup/backup.tar /tmp
# Restore it
docker run --volumes-from railsdockerexample_data_1 -v $(pwd)/backup:/backup busybox tar xvf /backup/backup.tar
If you need to backup and restore postgres DB data, you can do it by following:
# Create backup as a tar file
docker run --volumes-from railsdockerexample_data_1 -v $(pwd)/backup:/backup busybox tar cvf /backup/backup.tar /var/lib/postgresql/data
# Restore it
docker run --volumes-from railsdockerexample_data_1 -v $(pwd)/backup:/backup busybox tar xvf /backup/backup.tar
# Restart containers; As restarted container may have new ip address and Rails knows it only to read ENV --- it was set --link option and it will not update automatically
docker-compose restart
We can do zero time deployment by using CoreOS and mailgun/vulcand. This project has Vagrantfile
to up the environment for it.
Ref: Vulcand を使って Docker コンテナをブルーグリーンデプロイする - Qiita
Quite simple to do that. vulcand has the very simple system to handle some endpoints; Frontend
, Backend
and Servers
. In this case, the container is Server
.
We can build and start container with versioned source code with commit-id then switch endpoint like this:
# Create new Backend linked to new version
etcdctl set /vulcand/backends/8c5a86/backend '{"Type": "http"}'
# Create new Server linked to the Backend
etcdctl set /vulcand/backends/8c5a86/servers/srv1 '{"URL": "http://localhost:5000"}'
# Update Frontend with new Backend Id
etcdctl set /vulcand/frontends/f1/frontend '{"Type": "http", "BackendId": "8c5a86", "Route": "PathRegexp(`/.*`)"}'
┌───────────────────────────────────────────────────────────────────┐
│ FrontEnd │
│ {"Type": "http", "BackendId": "a43bd2", │
│ "Route": "PathRegexp(`/.*`)"} │
│ │
└───────────────────────────────────────────────────────────────────┘
│
Frontend forwards request to │ * Switch the target "Server" by set
the container which was linked │ backend Id of commit id via etcd
to backend │ API after the new container was
┌─────────────────┘ built and ready.
│
│
│
│
▼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ Backend │ │ Backend │
│ /vulcand/backends/a43bd2 │ │ /vulcand/backends/8c5a86 │
│ {"Type": "http"} │ │ {"Type": "http"} │
│ │ │ │
└───────────────────────────────┘ └───────────────────────────────┘
┼ ┼
│ │
┼ ┼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ Server │ │ Server │
│/vulcand/backends/a43bd2/server│ │/vulcand/backends/8c5a86/server│
│ s/srv1 │ │ s/srv1 │
│{"URL": "http://0.0.0.0:8080"} │ │{"URL": "http://0.0.0.0:8081"} │
└───────────────────────────────┘ └───────────────────────────────┘
┼ ┼
│ │
┼ ┼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ Docker container │ │ Docker container │
│ (built as a43bd2) │ │ (built as 8c5a86) │
│ 0.0.0.0:8080 │ │ 0.0.0.0:8081 │
│ │ │ │
└───────────────────────────────┘ └───────────────────────────────┘
NOTICE: This wouldn't fit production environment as it builds Docker image inside the only host. It may affects performance while users send request to the only host. For production, it needs to change to use Docker registry and run containers by pulling image from there.
Install vagrant dns plugin for local dns. Then run vagrant up
to up your local environment.
This plugin supports MacOS only
vagrant plugin install vagrant-dns
vagrant dns --install
vagrant ssh-config >> ~/.ssh/config
vagrant up
All needed tasks are already included in rails-docker-example/docker.rake at master · mookjp/rails-docker-example. You can deploy new containers with zero time deployment with Vagrant:
vagrant up
bundle exec cap local docker:deploy # `local` environment is for vagrant