GitLab Runner の使い勝手がなかなか良くなったそうなので、Capistrano3 と組み合わせたデプロイ環境を作成しました。
実現したいこと
- staging または master ブランチへの push イベントをトリガーとして GitLab 上の Pipeline を回す。
- Pipeline ではテスト ジョブとデプロイ ジョブを実行するが、デプロイ ジョブの実行は手動とする(GitLab の Web UI 上でジョブを実行させて結果の成功/失敗を確認したいため)。
- デプロイ ジョブでは Capistrano のタスクを実行し、リモート環境(ステージング または プロダクション環境)にコードをデプロイする。
- Capistrano では SSH エージェント転送を有効にして、タスク実行元に保管された秘密鍵をデプロイ先サーバーに転送し、この鍵を使って GitLab に SSH 接続を行いコードを取得する。
- デプロイしたコードに問題があった場合に備え、ロールバック ジョブも用意する(ロールバックも手動実行とする)。
各種バージョン
- gitlab-ci-multi-runner: 1.7.1
- Capistrano: 3.6.1
- GitLab CE: 8.14.0
- Runner サーバー(※)OS: Ubuntu 16.04
※以降、gitlab-ci-multi-runner をインストールするサーバーを Runner サーバーと呼ぶこととします。
各アカウントおよびドメイン名
サーバー種別 | ドメイン名(※) | タスク or デプロイ実行アカウント名 |
---|---|---|
Runner サーバー | runner-svr.example.com | gitlab-runner |
ステージング サーバー | staging.examle.com | deploy-user |
プロダクション サーバー | production.examle.com | deploy-user |
※実際のドメイン名ではなく、説明するための例として記載します。
処理フロー イメージ
環境構築手順
SSH 公開鍵認証用の設定
秘密鍵/公開鍵の生成
GitLab から Runner に対し処理実行を命じるとき、自動的に Runner サーバー上に gitlab-runner アカウントが追加されます。
今回 Runner + Capistrano + SSH エージェント転送を実現するに当たって、gitlab-runner アカウントが利用可能な秘密鍵を用意する必要があるため、あらかじめ gitlab-runner アカウントを Runner サーバー上に追加し、この gitlab-runner のホームディレクトリ以下に秘密鍵と公開鍵を保管しておきます。
$ hostname
runner-svr
$ sudo -s
# adduser gitlab-runner
// gitlab-runner アカウント情報を入力
# su - gitlab-runner
$ ssh-keygen -t rsa -N "" -C "gitlab-runner@runner-svr.example.com"
デプロイ先サーバーへの公開鍵配布
Capistrano スクリプト実行時、SSH 公開鍵認証でステージングまたはプロダクション環境にログインさせるため、作成した公開鍵(/home/gitlab-runner/.ssh/id_rsa.pub)を、ssh-copy-id で各サーバー上の(デプロイ用アカウントのホームディレクトリ)/.ssh/authorized_keys に登録します。
$ hostname
runner-svr
$ whoami
gitlab-runner
// リモートのステージングおよびプロダクション サーバーに公開鍵を登録する
$ ssh-copy-id -i /home/gitlab-runner/.ssh/id_rsa.pub deploy-user@staging.example.com
$ ssh-copy-id -i /home/gitlab-runner/.ssh/id_rsa.pub deploy-user@production.example.com
GitLab にデプロイ キーを登録する
生成した公開鍵を使って GitLab からソースコードを取得してデプロイするため、この鍵をデプロイ専用の鍵として GitLab に登録します。
登録は GitLab Web UI 上のプロジェクト > "設定" ドロップダウンリスト > Deploy Keys から行います。
もしプロジェクト共通のデプロイ キーとして登録したい場合は、管理者権限を持つユーザーで Web UI にログインし、"Admin Area" > "設定" ドロップダウンリスト > Deploy Keys から登録してプロジェクトの Deploy Keys ページで対象キーを「Enable」にします。
Capistrano のインストール & 設定
インストール
Runner サーバー上に gem を利用して Capistrano をインストールします。
$ hostname
runner-svr
$ sudo -s
# apt-get update && apt-get install ruby -y
# gem install bundler net-ssh capistrano
Capistrano スクリプト実行環境の作成
gitlab-runner アカウントで Runner サーバーにログインし、任意のディレクトリを作成します。
このディレクトリ内に Gemfile を保管して bundle install と cap install コマンドを実行します。
$ hostname
runner-svr
$ whoami
gitlab-runner
$ mkdir ~/capistrano
$ cd ~/capistrano
// capistrano ディレクトリの中に Gemfile を作成またはコピーする
$ ls -l
-rw-rw-r-- 1 gitlab-runner gitlab-runner 125 Nov 7 18:06 Gemfile
$ bundle install --path vendor/bundle
$ cap install
(必要なファイル、ディレクトリのひな形が自動生成される)
capistrano ディレクトリ構成イメージ
/home/gitlab-runner/capistrano
├── Capfile
├── config
│ ├── deploy
│ │ ├── production.rb
│ │ └── staging.rb
│ └── deploy.rb
├── Gemfile
├── Gemfile.lock
├── log
├── vendor
└── lib
└── capistrano
└── tasks
設定ファイルの編集
deploy.rb ファイル
cap コマンドでデプロイを実行するとき、コマンド オプションでデプロイするブランチを指定できるようにするため、次の設定を追加します。
# もし環境変数 BRANCH に値がセットされていなかった場合、ブランチ名の確認プロンプトが表示されます
set :branch, ask('Branch: ', nil) unless ENV['BRANCH']
※注意
後述する .gitlab-ci.yml のジョブ内で環境変数 BRANCH にブランチ名をセットしますが、もし BRANCH に値がセットされていなかった場合でも Runner のジョブの実行結果は "Build succeeded" と表示されます。しかしデプロイ自体はなされません(Capistrano の以降のタスクがスキップされます)。
staging.rb と production.rb ファイル
デプロイ時に SSH 公開鍵を使ってデプロイ先サーバーにログインし、また SSH エージェント転送を有効にするため以下のオプションを追加します。
set :ssh_options, {
user: 'deploy-user',
keys: %w(/home/gitlab-runner/.ssh/id_rsa),
forward_agent: true,
auth_methods: %w{publickey}
}
その他の Capistrano 設定項目については、公式ドキュメントを参照し設定します。
デプロイ テスト
Capistrano スクリプトが成功するか一旦テストします。
$ hostname
runner-svr
$ whoami
gitlab-runner
$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rsa
$ cd ~/capistrano
$ BRANCH=staging bundle exec cap production deploy
エラーが出ず、成功した場合は Capistrano の準備は完了です。
gitlab-ci-multi-runner のインストール
Runner サーバーに gitlab-ci-multi-runner をインストールします。
手順は公式マニュアルの通りに実行するだけです。
$ hostname
runner-svr
$ sudo -s
# curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash
# apt-get install gitlab-ci-multi-runner
Runner の登録
Runner を登録します。
# hostname
runner-svr
# gitlab-ci-multi-runner register
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://(使用している GitLab のドメイン名)/ci ---- (1)
Please enter the gitlab-ci token for this runner:
(GitLab 上で表示されるトークン) ---- (2)
Please enter the gitlab-ci description for this runner:
myrunner ---- (3)
Please enter the gitlab-ci tags for this runner (comma separated):
myproject ---- (4)
Registering runner... succeeded runner=xxxxxxxx
Please enter the executor: shell, virtualbox, docker+machine, docker-ssh+machine, kubernetes, docker, docker-ssh, parallels, ssh:
shell ---- (5)
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Register オプション
-
(1) gitlab-ci coordinator URL
GitLab Web UI 上で何らかのプロジェクト > "設定" ドロップダウンリスト > Runner ページを開くと、"Specific Runners" に Runner 設定用の値が記載されています。
その内の "Specify the following URL during the Runner setup: " で示された URL を指定します(現状 GitLab の URL + /ci で規定されているようです)。 -
(2) gitlab-ci token
同じくプロジェクトの Runner ページに表示されたトークンを指定します。
Shared Runner (プロジェクト共通で利用可能な Runner)を登録する場合は、GitLab に管理者権限のあるユーザーでログインし、Admin Area > Overview > Runners ページに表示されたトークンを指定します。 -
(3) gitlab-ci description for this runner
Runner の表示名を指定します。ここで指定した名称は GitLab Web UI 上にも表示されます。 -
(4) gitlab-ci tags for this runner
ジョブと Runner を紐付けるためのタグを指定します。カンマ区切りで複数タグが指定できます。
指定しなくても構いませんが、タグを付けることでジョブの管理がしやすくなります。 -
(5) executor
プロジェクト ビルド環境を指定します。たとえば、docker を選択すると Docker コンテナ上で各ジョブが実行されることとなります。
docker+machine を選択すると更にコンテナの auto scale もできるそうですが、今回は shell を指定し Runner サーバー上でスクリプトを実行させることとします。
executor についての詳しい説明は、こちらのページを参照ください。
GitLab Web UI 上で Runner の状態を確認する
Runner の登録が成功すると、GitLab Web UI のプロジェクト > "設定" ドロップダウンリスト > Runner ページに、有効な Runner として表示されるようになります。
このとき、「Enable for this project」ボタンをクリックしないと Runner が有効化されないため必ずクリックしておきます。
.gitlab-ci.yml の作成
Runner を動かすための設定ファイルとして、.gitlab-ci.yml をプロジェクト リポジトリのルート直下に作成します。
最新の GitLab CE では、Web UI のプロジェクト トップページにある「Set Up CI」ボタンをクリックすると .gitlab-ci.yml の作成 & 編集をブラウザからできるようになっているので、こちらを利用するのが手っ取り早いです。
.gitlab-ci.yml 記述例
stages:
- test
- deploy
- rollback
test_job:
stage: test
script:
- (テスト スクリプト実行コマンド)
tags:
- myproject
deploy_to_staging_job:
stage: deploy
script:
- eval `ssh-agent`
- ssh-add /home/gitlab-runner/.ssh/id_rsa
- cd /home/gitlab-runner/capistrano
- BRANCH=staging bundle exec cap staging deploy
only:
- staging
tags:
- myproject
when: manual
deploy_to_production_job:
stage: deploy
script:
- eval `ssh-agent`
- ssh-add /home/gitlab-runner/.ssh/id_rsa
- cd /home/gitlab-runner/capistrano
- BRANCH=master bundle exec cap production deploy
only:
- master
tags:
- myproject
when: manual
rollback_staging_job:
stage: rollback
script:
- eval `ssh-agent`
- ssh-add /home/gitlab-runner/.ssh/id_rsa
- cd /home/gitlab-runner/capistrano
- BRANCH=staging bundle exec cap staging deploy:rollback
only:
- staging
tags:
- myproject
when: manual
rollback_production_job:
stage: rollback
script:
- eval `ssh-agent`
- ssh-add /home/gitlab-runner/.ssh/id_rsa
- cd /home/gitlab-runner/capistrano
- BRANCH=staging bundle exec cap production deploy:rollback
only:
- master
tags:
- myproject
when: manual
.gitlab-ci.yml の各パラメーターについて
-
stages
テスト、ビルドまたはデプロイなど各ジョブのステージを登録します。ステージ名("deploy" など)は任意に指定できます。
ステージの進め方(Pipeline の回り方)は基本的に書いてある順で進んで行き、前のジョブが成功したら次のステージのジョブが実行されます。
-
script
処理したいコマンドを記述します。 -
only
git ref の内容によって、ジョブを実行するかどうか判定します。今回は "staging" または "master" ブランチに push されたときのみにジョブが実行されるように、ブランチ名を指定しました。 -
tags
Runner 登録時に設定したタグを追加します。タグを追加することで、複数の Runner が登録されていてもジョブの実行先 Runner を明示的に指定することができます。 -
when
ジョブの実行タイミングを指定します。ここではデプロイとロールバックジョブは手動実行にしたかったため "manual" と記述しましたが、指定が無い場合は自動実行となります。
※test_job や deploy_to_staging_job などのジョブ名は適当につけています。ジョブ名は任意に指定できるので、ジョブの内容に合わせて適宜変更します。
※パラメーターのより詳しい説明はGitLab のドキュメントを参照してください。
デプロイ実行
準備が整ったのでいよいよ Pipeline を回します。
staging ブランチを push し、Web UI 上で対象プロジェクトの Pipelines ページから最新の Pipeline の Status をクリックします。
Deploy ジョブは「skipped」になっているため、実行ボタンをクリックしジョブを開始させます。
処理が開始されるとコンソール画面が表示され、最後に "Build succeeded" と出力されると成功です。
もしコードをロールバックしたい場合は、同じく Rollback ジョブを Web UI 上から実行します。
※補足
- git push の度に新しい Pipeline が追加されて行きますが、数代前の Pipeline の、未実行の manual ジョブを任意のタイミングで実行することもできます。
今回は「常に staging または master ブランチの最新ソースをデプロイする」ように Capistrano 設定を書いていますので、ジョブの古さに関わらずジョブを実行した時点での最新ソースがデプロイされます。 - GitLab 8.14 から Pipeline の結果がメールで送信されるようになりました。自動実行ジョブが失敗したときのリカバリがしやすくなりますね。