アプリケーションの更新のたびに発生するデプロイ作業。
そのデプロイをCapistranoで自動化するということを目標とし、EC2+Jenkins+Capistranoでデプロイ環境を構築する。
目次
Capistranoとは
Rubyで作られたデプロイメントツール。
高度な設定まで対応しており、学習コストが比較的高いが、いろいろ出来て便利。
何が出来るの?
設定ファイルを作成し、そのメソッド的なものを叩くことで汎用性の高いデプロイメントを行える。
デプロイはsshによるcopyや、gitなどのソースダウンロードが出来る。
今回はデプロイ先サーバにgitでソースをデプロイさせることとする。
EC2上にセットアップしたJenknsサーバにSSHで接続する
先回セットアップしたJenkinsサーバにログインを行う。
$ ssh ec2jenkins Last login: Sun Apr 12 03:11:12 2015 from xxx __| __|_ ) _| ( / Amazon Linux AMI ___|\___|___|
JenkinsサーバにCapistranoをインストール
capistranoは転送元サーバーにのみインストールされていれば良い。
今回はJenkinsサーバにそのままインストールすることとする。
Capistranoのインストール
gemで一発。
$ sudo gem install capistrano $ sudo gem install capistrano_colors $ sudo gem install capistrano-ext $ sudo gem install railsless-deploy
capistrano-colorsは見やすくなるので、入れておいたら便利
railsless-deployはRailsアプリ以外のDeployでは必須。
#今回はPHPのLaravel5アプリを想定しているため必須。
SSHのユーザ設定を行う
転送元サーバと転送先サーバに同じユーザを作る
転送元サーバ(Jenkins)と転送先サーバ(Develop)に双方同じユーザを作成する必要がある。
# そのユーザがSSHログイン等を行ないデプロイを行うため。
Jenkinsサーバ・Developサーバ両方
# useradd deployuser # passwd deployuser
両方に同名ユーザを作ります。
次に、転送元サーバのSSH鍵を生成します。
転送元サーバユーザで鍵を生成
# su - deployuser $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/deployuser/.ssh/id_rsa): Created directory '/home/deployuser/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/deployuser/.ssh/id_rsa. Your public key has been saved in /home/deployuser/.ssh/id_rsa.pub. The key fingerprint is: xxx deployuser@xxx The key's randomart image is: +--[ RSA 2048]----+ | ...| | . . oE| | . o + ....| | + =. . . | |. = + S... | | o + * .. | | o = . | | . .. | | .. | +-----------------+
公開鍵の取得
$ cd ~/.ssh/ $ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDwGgynlLOIgA0GH0N0mCuVHhCC/n2UN5mSxv1kfCJeSsgk+2cEd3eWAqLoaD8oJhY7AT2nKdMh~ deployuser@xxx
鍵の内容(上記の最終行)をコピーする。
転送先サーバに転送元ユーザの鍵を登録する
まずはホスト情報を作る。面倒なんで、自分自身にSSHアクセスしてベース作る。
su - deployuser $ ssh deployuser@localhost The authenticity of host 'localhost (127.0.0.1)' can't be established. RSA key fingerprint is xx:xx:xx:xx:xx:xx. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'localhost' (RSA) to the list of known hosts. Permission denied (publickey).
次に、転送元サーバの公開鍵を既知ホストとして登録する。
$ cd ~/.ssh $ vi authorized_keys
上記ファイルの最終行に公開鍵情報をペーストし、上書き保存。
そして権限情報を最適化。
$ chmod 600 authorized_keys
これで転送元→転送先のSSH設定は終わりです。
上手く設定出来たか確認してみましょう。
転送元サーバから転送先サーバへSSHで接続確認
# su - deployuser $ ssh deployuser@[転送先サーバのIP] Last login: Sun Apr 12 04:13:22 2015 from xxx __| __|_ ) _| ( / Amazon Linux AMI ___|\___|___|
すらすら書いているけど、権限関連でかなり詰まった・・・。
両方のサーバにGitをインストール
基本的にインストールされている可能性もありますが、年の為記載。
今回、デプロイはGitを活用するため、インストールしていないと「git clone」が行えないため、当然コケる。
転送元サーバ、転送先サーバにgitをインストール
$ sudo yum install -y git
JenkinsサーバにCapistranoを設定
Capistranoの設定ファイル群を作成していく。
ここがデプロイプロジェクトの肝となる。
$ su -deployuser $ mkdir ~/deploy_setting $ cd ~/deploy_setting/ $ cap install mkdir -p config/deploy create config/deploy.rb create config/deploy/staging.rb create config/deploy/production.rb mkdir -p lib/capistrano/tasks create Capfile Capified
「cap install」で基本系のファイル群がジェネレートされる。
# Capistrano2では「capify [dir]」だったが、Capistrano3からは「cap install」に変わっているため注意。
Capistranoの設定ファイルを記述
プロジェクト共通設定ファイル(/home/deployuser/deploy_setting/config/deploy.rb)
# config valid only for current version of Capistrano lock '3.4.0' set :use_sudo, true set :pty, true namespace :environment do desc "Copy Environment Variables" task :sync do on roles(:app), in: :sequence, wait: 5 do execute :echo, "-n /etc/environment", raise_on_non_zero_exit: false fetch(:default_environment).each do |key, value| execute :sudo, :echo, "'#{key}=\"#{value}\"' >> sudo /etc/environment" end execute :sudo, :service, "httpd restart" end end end namespace :composer do desc "Running Composer Self-Update" task :update do on roles(:app), in: :sequence, wait: 5 do execute :sudo, :composer, "self-update" end end desc "Running Composer Install" task :install do on roles(:app), in: :sequence, wait: 5 do within release_path do execute :sudo, :composer, "install --no-dev --quiet" end end end end namespace :laravel do desc "Setup Laravel folder permissions" task :permissions do on roles(:app), in: :sequence, wait: 5 do within release_path do execute :sudo, :chmod, "u+x artisan" execute :sudo, :chmod, "-R 777 storage/" execute :sudo, :chown, "-R deployuser ." execute :sudo, :chgrp, "-R deployuser ." end end end desc "Run Laravel Artisan migrate task." task :migrate do on roles(:app), in: :sequence, wait: 5 do within release_path do execute :php, "artisan migrate" end end end desc "Run Laravel Artisan seed task." task :seed do on roles(:app), in: :sequence, wait: 5 do within release_path do execute :php, "artisan db:seed" end end end desc "Optimize Laravel Class Loader" task :optimize do on roles(:app), in: :sequence, wait: 5 do within release_path do execute :php, "artisan clear-compiled" execute :php, "artisan optimize" end end end end namespace :deploy do after :published, "composer:update" after :published, "composer:install" after :published, "environment:sync" after :published, "laravel:permissions" after :published, "laravel:optimize" after :published, "laravel:migrate" after :published, "laravel:seed" end
env毎の設定ファイル(/home/deployuser/deploy_setting/config/deploy/develop.rb)
# Develop Settings # Git Repository set :scm, "git" set :repository, "[github address(ex git@github.com/aaa/)]" set :branch, "[develop]" # Server Setting ec2server = "deployuser@xxx.compute.amazonaws.com" role :app, ec2server role :web, ec2server role :db, ec2server, :primary => true server 'xxx.compute.amazonaws.com' set :user, "deployuser" set :ssh_options, { user: 'deployuser', keys: %w{/home/deployuser/.ssh/id_rsa}, # forward_agent: true #auth_methods: %w{publickey} } set :deploy_to, "/var/www/laravel5-project" set :default_environment, { "PR_ENV" => "localhost", "APP_DEBUG" => "true", "APP_KEY" => "[hogehogehoge]", "DB_HOST" => "[db_host]", "DB_DATABASE" => "[db_name]", "DB_USERNAME" => "[db_user]", "DB_PASSWORD" => "[db_pass]", "CACHE_DRIVER" => "file", "SESSION_DRIVER" => "file", }
書き終わったらチェックする。
デプロイ先サーバでsudoを実行できるよう権限付与。
$ sudo vi /etc/sudoers
#Defaults requiretty Defaults:deployuser !requiretty # デプロイユーザーの指定 deployuser ALL=(ALL) NOPASSWD:ALL # no password
デプロイテストの実行
コマンド一覧の確認
$ cap -T cap composer:install # Running Composer Install cap composer:update # Running Composer Self-Update cap deploy # Deploy a new release cap deploy:check # Check required files and directories exist cap deploy:check:directories # Check shared and release directories exist cap deploy:check:linked_dirs # Check directories to be linked exist in shared cap deploy:check:linked_files # Check files to be linked exist in shared cap deploy:check:make_linked_dirs # Check directories of files to be linked exist in shared cap deploy:cleanup # Clean up old releases cap deploy:cleanup_rollback # Remove and archive rolled-back release cap deploy:finished # Finished cap deploy:finishing # Finish the deployment, clean up server(s) cap deploy:finishing_rollback # Finish the rollback, clean up server(s) cap deploy:log_revision # Log details of the deploy cap deploy:published # Published cap deploy:publishing # Publish the release cap deploy:revert_release # Revert to previous release timestamp cap deploy:reverted # Reverted cap deploy:reverting # Revert server(s) to previous release cap deploy:rollback # Rollback to previous release cap deploy:set_current_revision # Place a REVISION file with the current revision SHA in the current release path cap deploy:started # Started cap deploy:starting # Start a deployment, make sure server(s) ready cap deploy:symlink:linked_dirs # Symlink linked directories cap deploy:symlink:linked_files # Symlink linked files cap deploy:symlink:release # Symlink release to current cap deploy:symlink:shared # Symlink files and directories from shared to release cap deploy:updated # Updated cap deploy:updating # Update server(s) by setting up a new release cap environment:sync # Copy Environment Variables cap install # Install Capistrano, cap install STAGES=staging,production cap laravel:migrate # Run Laravel Artisan migrate task cap laravel:optimize # Optimize Laravel Class Loader cap laravel:permissions # Setup Laravel folder permissions cap laravel:seed # Run Laravel Artisan seed task
テスト実行
$ sudo -u deployuser cap develop deploy:check
ここでエラーチェックを行う。
エラーの大半は権限関係やインストール不足なので、ひとつずつ確認して潰していく。
JenkinsにCapistranoの実行を紐付け
ここまで来るとなんということは無いですね。
ビルドが成功した後のシェルの実行に下記のようにしてcapistranoのトリガを紐付け
cd $[deploy_dir] && sudo -u deployuser cap develop deploy
上手く実行出来ないと思ってたら、Jenkinsユーザがsudoを実行出来なかったためでした。
sudoersにJenkinsユーザも追記
$ sudo vi /etc/sudoers
#Defaults requiretty Defaults:jenkins !requiretty # デプロイユーザーの指定 jenkins ALL=(ALL) NOPASSWD:ALL # no password
これでひとまず設定完了です。
しかし、もう少しenv設定などの取り回しを柔軟にしたいなーと思っています。
しばらくこれで回してみて問題が見えたらHackしていきましょう。
みなさん、よいCIを。