みなさん Docker 使ってますか?
とても便利なんですが、アプリケーションをコンテナ内に押し込むノウハウはまだまだ発展途上で、今まで本当に色んなアプローチが模索されています。
rails app に関しても既に色んな方法があるんですが。
はい。既にあるんですが。便利な capistrano が使いたいんじゃ! そのまま! ……というわけで、今回 capistrano がそのまま使えるようにしてみました。
手順
先に手順行きます。こんな感じで使えます。
まず Gemfile に以下を追加
gem 'capistrano-deploy_into_docker', '>= 0.2.0', group: :development
でもって bundle
$ bundle
Capfile でタスクの require
Capfile の後ろの方に以下を追加します。
require 'capistrano/deploy_into_docker'
デプロイ設定
デプロイ設定(config/deploy/docker.rb とか)は例えば以下のようにします。
set :sshkit_backend, SSHKit::Backend::Docker
set :stage, :production
set :branch, 'production'
set :deploy_to, '/var/local/app'
fetch(:default_env).merge!(rails_env: :production, SECRET_KEY_BASE: 'dummy', DEVISE_SECRET_KEY: 'dummy')
fetch(:linked_dirs, []).clear
fetch(:linked_files, []).clear
server docker: {
image: 'sugi/rails-base',
commit: 'myapp-web',
}, user: 'rails:rails', roles: %w{web app}
ポイントはサーバ定義と :sshkit_backend
設定です。
その他に関しては、ご自分の環境やイメージに合わせて変更して下さい。(ここで指定している sugi/rails-base
イメージはサンプルで、/var/local/app に rails:rails ユーザ/グループでアプリケーションを配置する構造になっています。)
これだけで docker のイメージからコンテナを立ち上げ、その中にデプロイし、終わったら commit までを自動で行います。
$ bundle exec cap docker deploy
もし、docker run にオプションを渡したい場合は、hash に書けば(一部を除き)大体何でも渡せます。
server docker: {
image: 'ruby:latest',
commit: 'new-image-name:tag',
volume: ['/storage/tmp:/tmp', '/storage/home:/home'],
network: 'my-net',
dns: '8.8.8.8',
dns_search: 'example.com',
cap_add: ['SYS_NICE', 'SYS_RESOURCE'],
}, user: 'nobody:nogroup', roles: %w{web app}
今回作ったもの
capistrano-deploy_into_docker
こちらは commit 用のタスクと、各種 require するだけの非常に小さなグルーツールです。
deploy:finished の後に :commit のキーを持つサーバ定義に対して、 docker commit を実行します。
sshkit-backend-docker
メインのライブラリです。このライブラリは SSHKit に Docker バックエンドを追加し、ssh を必要とせずコンテナ内でのコマンド実行をサポートします。
capistrano を経由せずに SSHKit を直接使っている場合でも利用できます。その場合は README を参照して下さい。
現状、SSHKit のバックエンドの変更は自動では行われません。capistrano の場合は :sshkit_backend
に、SSHKit 直接の場合は SSHKit.config.backend
に SSHKit::Backend::Docker
をセットする必要があります。
コメント求む
というわけで、ひとまず使える状態になったので公開してみました。
改善点や、アプローチそのものに関して何かありましたら是非コメント下さい。よろしくお願いします。