Docker Compose とは
Docker Compose とは複数のコンテナを利用して一つのサービスを提供する場合に YAML 一発で構築出来るようにするツール(という認識)で、以前は同様なツールで fig というツールがあったと記憶しているがこの fig がそのまま Docker Compose に名前を変えたようだ。
Fig has been replaced by Docker Compose, and is now deprecated. The new documentation is on the Docker website.
なるほど、なるほど。
準備
Docker Compose のインストール
現状は Docker Compose 自体のインストーラーは存在せず、以下のようにインストールするしかないようだ。
curl -L https://github.com/docker/compose/releases/download/1.3.2/docker-compose-`uname -s`-`uname -m` > docker-compose sudo cp docker-compose /usr/local/bin/ sudo chmod +x /usr/local/bin/docker-compose
ヘルプ
$ docker-compose --help Define and run multi-container applications with Docker. Usage: docker-compose [options] [COMMAND] [ARGS...] docker-compose -h|--help Options: -f, --file FILE Specify an alternate compose file (default: docker-compose.yml) -p, --project-name NAME Specify an alternate project name (default: directory name) --verbose Show more output -v, --version Print version and exit Commands: build Build or rebuild services help Get help on a command kill Kill containers logs View output from containers port Print the public port for a port binding ps List containers pull Pulls service images restart Restart services rm Remove stopped containers run Run a one-off command scale Set number of containers for a service start Start services stop Stop services up Create and start containers migrate-to-labels Recreate containers to add labels
チュートリアル
サンプル各種
とりあえず rails を
こちらを写経する。
まずは Dockerfile を作る。
FROM ruby:2.2.0 RUN apt-get update -qq && apt-get install -y build-essential libpq-dev RUN mkdir /myapp WORKDIR /myapp ADD Gemfile /myapp/Gemfile RUN bundle install ADD . /myapp
Gemfile を作る。
source 'https://rubygems.org' gem 'rails', '4.2.0'
docker-compose.yml を作る。
db: image: postgres ports: - "5432" web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - .:/myapp ports: - "3000:3000" links: - db
一旦、rails new
する。
$ docker-compose run web rails new . --force --database=postgresql --skip-bundle
docker-compose.yml には bundle exec rails s -p 3000 -b '0.0.0.0'
と指定されているので、rails new . --force --database=postgresql --skip-bundle
で上書きするイメージで処理が終了するとカレントディレクトリに以下のようにファイルが展開されている。
$ ls -l total 68 -rw-rw-r-- 1 vagrant vagrant 178 Jul 18 12:20 Dockerfile -rw-rw-r-- 1 vagrant vagrant 1480 Jul 18 12:21 Gemfile -rw-r--r-- 1 root root 3819 Jul 18 12:25 Gemfile.lock -rw-r--r-- 1 root root 478 Jul 18 12:26 README.rdoc -rw-r--r-- 1 root root 249 Jul 18 12:26 Rakefile drwxr-xr-x 8 root root 4096 Jul 18 12:26 app drwxr-xr-x 2 root root 4096 Jul 18 12:26 bin drwxr-xr-x 5 root root 4096 Jul 18 12:26 config -rw-r--r-- 1 root root 153 Jul 18 12:26 config.ru drwxr-xr-x 2 root root 4096 Jul 18 12:26 db -rw-rw-r-- 1 vagrant vagrant 183 Jul 18 12:21 docker-compose.yml drwxr-xr-x 4 root root 4096 Jul 18 12:26 lib drwxr-xr-x 2 root root 4096 Jul 18 12:26 log drwxr-xr-x 2 root root 4096 Jul 18 12:26 public drwxr-xr-x 8 root root 4096 Jul 18 12:26 test drwxr-xr-x 3 root root 4096 Jul 18 12:26 tmp drwxr-xr-x 3 root root 4096 Jul 18 12:26 vendor
ちょっと Gemfile を修正。
gem 'therubyracer', platforms: :ruby
JavaScript の Runtime である therubyracer をインストールするようにアンコメントして最後に docker-compose build
を実行する。
$ docker-compose build
以下のように出力される。
db uses an image, skipping Building web... Step 0 : FROM ruby:2.2.0 ---> 51473a2975de Step 1 : RUN apt-get update -qq && apt-get install -y build-essential libpq-dev ---> Using cache ---> 76dbd0c53ce1 Step 2 : RUN mkdir /myapp ---> Using cache ---> c263028a071e Step 3 : WORKDIR /myapp ---> Using cache ---> 3172fc182c6c Step 4 : ADD Gemfile /myapp/Gemfile ---> 6b9bcc9f7ccb Removing intermediate container a5e6dcd92778 Step 5 : RUN bundle install ---> Running in 1482b35b5d74 Don't run Bundler as root. Bundler can ask for sudo if it is needed, and installing your bundle as root will break this application for all non-root users on this machine. Fetching gem metadata from https://rubygems.org/....... (略) Installing uglifier 2.7.1 Installing web-console 2.2.1 Your bundle is complete! It was installed into /usr/local/bundle ---> f30b4667c9f9 Removing intermediate container 1482b35b5d74 Step 6 : ADD . /myapp ---> 396b0def9cdf Removing intermediate container e711c5b5248e Successfully built 396b0def9cdf
config/database.yml を以下のように修正。
development: &default adapter: postgresql encoding: unicode database: postgres pool: 5 username: postgres password: host: db test: <<: *default database: myapp_test
最後にコンテナを起動する。
$ docker-compose up -d
-d
でデタッチモード。以下のように出力される。
$ docker-compose up -d Creating composerails_db_1... Creating composerails_web_1...
docker logs
で確認。
$ docker logs composerails_web_1 => Booting WEBrick => Rails 4.2.0 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options => Ctrl-C to shutdown server [2015-07-19 07:06:16] INFO WEBrick 1.3.1 [2015-07-19 07:06:16] INFO ruby 2.2.0 (2014-12-25) [x86_64-linux] [2015-07-19 07:06:16] INFO WEBrick::HTTPServer#start: pid=1 port=3000
ブラウザで確認。
おお。
少しひねる
Sinatra + Redis でなんちゃって API システム
こちらを参考させて頂いて、チョー簡単 API システムを作ってみたいと思う。
Dockerfile を作成、というか先ほどの Rails のものをそのまま。
FROM ruby:2.2.0 RUN apt-get update -qq && apt-get install -y build-essential RUN mkdir /myapp WORKDIR /myapp ADD Gemfile /myapp/Gemfile RUN bundle install ADD . /myapp
docker-compose.yml を以下のように。
redis: image: redis ports: - "6379" web: build: . command: bundle exec ruby app.rb -o 0.0.0.0 volumes: - .:/myapp ports: - "14567:4567" links: - redis environment: - REDIS_HOST=redis
アプリケーション(app.rb)は以下のような簡単スクリプト。
#!/usr/bin/env ruby # require 'sinatra' require 'redis' require 'json' r = Redis.new host: ENV["REDIS_HOST"], port:"6379" get '/value/:key' do value = r.get params[:key] v = { key: params[:key], value: value } v.to_json end post '/data/:key' do msg = request.body.read r.set params[:key], msg end
Gemfile は以下のように用意。
source 'https://rubygems.org' gem "sinatra" gem "redis"
docker-compose build
でビルド。
$ docker-compose build
以下のように出力される。
Building web... Step 0 : FROM ruby:2.2.0 ---> 51473a2975de Step 1 : RUN apt-get update -qq && apt-get install -y build-essential ---> Running in 8c1bc72000c3 Reading package lists... Building dependency tree... Reading state information... build-essential is already the newest version. The following package was automatically installed and is no longer required: libbison-dev Use 'apt-get autoremove' to remove it. 0 upgraded, 0 newly installed, 0 to remove and 160 not upgraded. ---> 2ebb189c25b1 Removing intermediate container 8c1bc72000c3 Step 2 : RUN mkdir /myapp ---> Running in 3ae7afaa1941 ---> f528a03f229b Removing intermediate container 3ae7afaa1941 Step 3 : WORKDIR /myapp ---> Running in 114d4e12d4a6 ---> 0cd25195c3ab Removing intermediate container 114d4e12d4a6 Step 4 : ADD Gemfile /myapp/Gemfile ---> 33430f3a8848 Removing intermediate container c9333ca6b80b Step 5 : RUN bundle install ---> Running in b3fac0dae84d Don't run Bundler as root. Bundler can ask for sudo if it is needed, and installing your bundle as root will break this application for all non-root users on this machine. Fetching gem metadata from https://rubygems.org/.......... (略) Your bundle is complete! It was installed into /usr/local/bundle ---> fd7d36d14b1e Removing intermediate container b3fac0dae84d Step 6 : ADD . /myapp ---> 5ab105adefab Removing intermediate container 2b7359c7add1 Successfully built 5ab105adefab
docker-compose up -d
でコンテナを起動。
$ docker-compose up -d Creating composesinatra_redis_1... Creating composesinatra_web_1...
各コンテナが起動していることを確認。
$ docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------------- composesinatra_redis_1 /entrypoint.sh redis-server Up 0.0.0.0:32845->6379/tcp composesinatra_web_1 bundle exec ruby app.rb -o ... Up 0.0.0.0:14567->4567/tcp
docker-compose logs
で確認。
$ docker-compose logs web Attaching to composesinatra_web_1 web_1 | [2015-07-19 07:29:10] INFO WEBrick 1.3.1 web_1 | [2015-07-19 07:29:10] INFO ruby 2.2.0 (2014-12-25) [x86_64-linux] web_1 | == Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from WEBrick web_1 | [2015-07-19 07:29:10] INFO WEBrick::HTTPServer#start: pid=1 port=4567 $ docker-compose logs redis Attaching to composesinatra_redis_1 redis_1 | 1:C 19 Jul 07:29:09.431 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf redis_1 | _._ redis_1 | _.-``__ ''-._ redis_1 | _.-`` `. `_. ''-._ Redis 3.0.3 (00000000/0) 64 bit redis_1 | .-`` .-```. ```\/ _.,_ ''-._ redis_1 | ( ' , .-` | `, ) Running in standalone mode redis_1 | |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 redis_1 | | `-._ `._ / _.-' | PID: 1 redis_1 | `-._ `-._ `-./ _.-' _.-' redis_1 | |`-._`-._ `-.__.-' _.-'_.-'| redis_1 | | `-._`-._ _.-'_.-' | http://redis.io redis_1 | `-._ `-._`-.__.-'_.-' _.-' redis_1 | |`-._`-._ `-.__.-' _.-'_.-'| redis_1 | | `-._`-._ _.-'_.-' | redis_1 | `-._ `-._`-.__.-'_.-' _.-' redis_1 | `-._ `-.__.-' _.-' redis_1 | `-._ _.-' redis_1 | `-.__.-' redis_1 | redis_1 | 1:M 19 Jul 07:29:09.432 # Server started, Redis version 3.0.3
以下のようにデータを登録。
$ curl -X POST 127.0.0.1:14567/data/foo -d 'bar'
以下のようにデータを取得。
$ curl -s -X GET 127.0.0.1:14567/value/foo | python -m json.tool { "key": "foo", "value": "bar" }
おお、簡単。
スケールアウト、スケールイン
以下のような状態。
$ docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------------- composesinatra_redis_1 /entrypoint.sh redis-server Up 0.0.0.0:32850->6379/tcp composesinatra_web_1 bundle exec ruby app.rb -o ... Up 0.0.0.0:32852->4567/tcp
Web サーバーをプラスで 2 台増やしたいなあと思ったら docker-compose scale
を利用すればさくっとスケールアウト、スケールインが出来る。
以下のように docker-compose.yml を修正する。
redis: image: redis ports: - "6379" web: build: . command: bundle exec ruby app.rb -o 0.0.0.0 volumes: - .:/myapp ports: - "4567" links: - redis environment: - REDIS_HOST=redis
以下のように docker-compose scale
の引数に web=3
のようにサービスに台数を指定して実行する。
$ docker-compose scale web=3
以下のように出力される。
$ docker-compose scale web=3 Creating composesinatra_web_2... Creating composesinatra_web_3... Starting composesinatra_web_2... Starting composesinatra_web_3...
確認。
$ docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------------- composesinatra_redis_1 /entrypoint.sh redis-server Up 0.0.0.0:32850->6379/tcp composesinatra_web_1 bundle exec ruby app.rb -o ... Up 0.0.0.0:32852->4567/tcp composesinatra_web_2 bundle exec ruby app.rb -o ... Up 0.0.0.0:32854->4567/tcp composesinatra_web_3 bundle exec ruby app.rb -o ... Up 0.0.0.0:32855->4567/tcp
おお、増えとる。
$ docker-compose logs Attaching to composesinatra_web_3, composesinatra_web_2, composesinatra_web_1, composesinatra_redis_1 web_3 | [2015-07-19 07:58:56] INFO WEBrick 1.3.1 web_3 | [2015-07-19 07:58:56] INFO ruby 2.2.0 (2014-12-25) [x86_64-linux] web_3 | == Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from WEBrick web_3 | [2015-07-19 07:58:56] INFO WEBrick::HTTPServer#start: pid=1 port=4567 web_2 | [2015-07-19 07:58:56] INFO WEBrick 1.3.1 web_2 | [2015-07-19 07:58:56] INFO ruby 2.2.0 (2014-12-25) [x86_64-linux] web_2 | == Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from WEBrick web_2 | [2015-07-19 07:58:56] INFO WEBrick::HTTPServer#start: pid=1 port=4567
ちゃんと web_2 と web_3 が起動している。ぢゃあ、次に減らしてみる。
$ docker-compose scale web=1 Stopping composesinatra_web_3... Stopping composesinatra_web_2... Removing composesinatra_web_3... Removing composesinatra_web_2... $ docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------------- composesinatra_redis_1 /entrypoint.sh redis-server Up 0.0.0.0:32850->6379/tcp composesinatra_web_1 bundle exec ruby app.rb -o ... Up 0.0.0.0:32852->4567/tcp
おお、サクッとコンテナが減ってる。
簡単にスケールインとスケールアウトが体験出来たけど...気になるのが外部に晒すポートを固定出来なくなる点をどうするか...。
ということで
参考
簡単、便利
複数の Docker コンテナでサービスを起動しようとした時にコンテナ同士の IP やポート等を意識しなくても良いのは嬉しい(Docker Links をちゃんと理解出来ていないけど見事にそれをラッピングしてくれていると思う)。また、YAML で各サービス毎のコンテナを定義しておくことで docker-compose up
一発で起動出来るのも嬉しい限り。