はじめに
RailsアプリをEC2上のdockerで動かしてみます。以下、一台のホストに必要なコンテナsを載せるシングルホスト構成での作業です。ステージング環境のような非production用途を想定しています。
ミドルウェアは以下です。
- Ruby 2.2.1
- Rails 4.2.1
- MySQL 5.6
- nginx
- unicorn
サンプルアプリのリポジトリは以下です
https://github.com/konpyu/rails-docker-sample
コンテナ構成はこんな感じです
- nginxコンテナ
- unicornコンテナ
- mysqlコンテナ
- データ共有コンテナ
ホストの起動と準備
EC2のインスタンスを適当に立てます。今回はCentOS7(ami-89634988)をホストOSとします。
# ログインしてrootになっておく
[centos@ip-10-0-x-xxx ~]$ sudo su -
[root@ip-10-0-x-xxx ~]#
gitとDockerをインストールしておきます
[root@ip-10-0-x-xxx ~]# yum -y install git docker
[root@ip-10-0-x-xxx ~]# docker -v
Docker version 1.6.2, build ba1f6c3/1.6.2
Dockerを起動します
[root@ip-10-0-x-xxx ~]# systemctl start docker
サンプルアプリをcloneしてきます
[root@ip-10-0-x-xxx ~]# mkdir /app
[root@ip-10-0-x-xxx ~]# cd /app
[root@ip-10-0-x-xxx app]# git clone https://github.com/konpyu/rails-docker-sample.git .
[root@ip-10-0-x-xxx app]# ls
app bin config config.ru db docker docker-compose.yml Dockerfile Gemfile Gemfile.lock lib log public Rakefile README.md README.rdoc vendor
appコンテナのビルド
Dockerfileでビルドします。RailsアプリのrootにDockefileを置いておけば、Railsのプロジェクトファイルをまるっとコンテナ内にCOPY
できます。
FROM ruby:2.2.1
RUN apt-get update && apt-get install -y nodejs mysql-client --no-install-recommends
# /appをコンテナ内のRails Appのディレクトリとする
RUN mkdir -p /app
WORKDIR /app
COPY Gemfile /app/
COPY Gemfile.lock /app/
RUN bundle install -j4 --without development test
COPY . /app
EXPOSE 3000
CMD ["bundle", "exec", "unicorn", "-c", "config/unicorn.rb"]
[root@ip-10-0-x-xxx app]# docker build -t todo/app .
MySQL, nginx, datastore用コンテナの起動
次にコンテナ間のファイル共有専用のデータストアコンテナと、DB用コンテナ、リバプロ用コンテナを起動します
まずは、コンテナ間でデータを共有するために、busyboxをベースに起動します。今回は、このコンテナ内にunicorn用のソケットを置いてコンテナ間で共有します
[root@ip-10-0-x-xxx app]# docker run -i -t -d -P --name data -v /share busybox /bin/sh
次に、MySQLの公式イメージを使ってDBコンテナを立てます。サンプルアプリ内の#{Rails.root}/docker/mysql/my.cnf
を設定ファイルとして注入しておきます
SELinuxを止めておきます (参考)
chcon -Rt svirt_sandbox_file_t /app/docker
[root@ip-10-0-x-xxx app]# docker run --name mysql -e MYSQL_ROOT_PASSWORD=test -v /app/docker/mysql:/etc/mysql/conf.d -d mysql:5.6
my.cnfはこんな感じです
[mysqld]
innodb_strict_mode
innodb_file_format = Barracuda
innodb_file_per_table
innodb_large_prefix = 1
リバプロ(nginx)のコンテナを公式イメージから立てます。unicornのsocketは先ほど立ててたbusyboxの中の/share/unicorn.sock
に置くものとします
upstream unicorn_server {
server unix:/share/unicorn.sock;
}
server {
listen 8080;
root /app/public;
location / {
if (!-f $request_filename) {
proxy_pass http://unicorn_server;
break;
}
}
}
nginxのコンテナを起動します
[root@ip-10-0-x-xxx app]# docker run --name nginx -p 80:8080 -v /app/docker/nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro --volumes-from data -d nginx
ここまでの段階で、ブラウザでアクセスすると502(Bad Gateway)が返ってくるはずです
最後に、unicornを立てて、nginxに来たアクセスをunicornにproxyしましょう
[root@ip-10-0-x-xxx app]# docker run --name unicorn --volumes-from data -e RAILS_ENV=production -e SECRET_KEY_BASE=ageman --link mysql:db -d todo/app
DBを作成します
[root@ip-10-0-x-xxx app]# docker exec -it unicorn bundle exec rake db:create
これで準備完了。ブラウザで見ると、TOPに表示されるはずです
今後の検討事項
本ポストは見通しを良くするために色々省略しています。シンプルなシングルホスト環境でも、以下にあげた事項は検討の価値/必要がアリです
- docker-composeでの起動
- Blue-Green デプロイ
- ディスクIOの最適化
- ログ収集
- rootを使わない