GitLab CIとランナーでデプロイする

タグ: Laravel5.3   GitLab   CI  

さて、GitLabをSSH設定後にrsyncでデプロイする例は、前ポストで紹介しました。今度は、実機上に設置したランナーを使い、デプロイする方法を紹介します。

なお、GitLabの最近の進化は凄まじい物があります。このポストは2016年9月19日現在記述していますが、近い将来でも大いに変更される可能性はあります。そのため、内容が古くなる可能性があります。ご注意ください。

事前準備

ローカル環境にLaravelプロジェクトをインストールしてください。それをgitlab.comの新しいプロジェクト(リポジトリ)へpushしてください。

ランナーとは

参照

PHPの組み込みサーバーをターミナル上で起動すると実行を続け、ローカルの指定したポートに対するhttp通信があれば処理します。

よりランナーに近いものとしては、LaravelのキューワーカーArtisanコマンドです。これを余計なオプションをつけずに実行すると、ターミナル上で実行しっぱなしになります。定期的にキューをチェックし、ジョブが投入されるとそれを処理します。

GitLab CIのランナーは、GitLab上のリポジトリ、GitLab用語のプロジェクトに対しgit pushされた時、.gitlab-ci.ymlファイルに記述されたジョブを処理する実行環境です。

どんなジョブでもDockerコンテナ上で実行できる「共有(shared)ランナー」をgitlab.comを使用する場合使用できます。自分の環境にGitLabを導入し、GitLab CIを使用したければ、この共有ランナーも用意する必要があるわけです。

間口の広い共有ランナーに対し、各ユーザが自分のプロジェクトのために、自分で起動するランナーもあります。これは"Specific(特定)"ランナーです。今回はこれを利用します。

ランナーはそのホストマシン上で仮想化を使わずそのままジョブを実行したり、Dockerイメージを利用してジョブを実行したり、SSHを使い他のサーバーで実行したりできます。

残念ながら、一つのランナーで自由にこれらを組み合わせて使用することはできません。どの方法でジョブを実行するかを最初に登録する必要があります。ただし、現在のところドキュメントが追いついていませんが、オプションとして「ssh, virtualbox, docker+machine, docker-ssh+machine, docker, docker-ssh, parallels, shell」が選択できるようです。

shellがランナーを動作させる環境で直接実行する方法です。dockerはその名の通り、Dockerコンテナ上で実行する方法、sshがSSH通信を使う利用する方法です。それ以外については名前で想像するしか、今のところありません。

今回はデプロイのため、shellを利用します。

ランナーの動作

GitLab CIは.gitlab-ci.ymlファイルに記述されている、ジョブの単位でランナーに実行を依頼します。

基本的にどの方法で実行するにせよ、ランナーがジョブを受け取ったら、そのプロジェクト(リポジトリ)へpushされ、GitLab CIへのビルドを起動したブランチの内容をフェッチ、もしくはクローンします。

それから、.gitlab-ci.ymlに記述されている内容に従い、該当するジョブを実行します。

実働サーバーでランナーをshellエグゼキュータで実行する場合、ジョブの環境はイコール、実働サーバーの環境です。つまり、もしデプロイする対象のファイルがブランチに含まれていれば、シェルコマンドでその内容を単純にコピーし、その他必要な処理を実行するだけで済みます。

ランナーのインストール

参照

上記で紹介されている、各環境でのインストール方法で基本行けるはずです。

私は最近、最新のMint Linuxに開発環境を切り替えました。Linux環境でのインストールページによると、Mintは含まれていません。ここで説明されている方法は、GitLabの公式リポジトリーから取得する方法です。

MintもUbuntuの仲間だから行けるかなと思いました。実際行ってみると、エラーになりませんが、パッケージを取得することはできませんでした。GItLabのリポジトリーを調べてみると、Mintもサポートされていますが、まだ最新のリリースには対応していませんでした。

実際、ランナーはGoで組まれたバイナリですので、パッケージ管理の自動アップデートを期待しなければ、バイナリでインストールする方法も用意されています。

参照

これにより、当方の最新Mintにもランナーをインストールできました。

注意:これ以降の説明では、まず自分でランナーをターミナル上で起動します。内容を実際に試してみたい方は、上記紹介ページの内容のsudo gitlab-ci-multi-runner start以降は、実行しないでください。サービスとして実行されますので、内容と異なる可能性があります。もちろん、実用的には、最終的にサービスとして起動することとなります。

registerコマンド

実行コマンドはgitlab-ci-multi-runnerという、長い名前です。このコマンドは、サブコマンドを付けて実行する、最近多いタイプのコマンドです。

最初にregisterコマンドを実行します。このランナーがどこにホストされているGitHubに実行予定のジョブがあるかを確認するかとか、それに利用するトークンとか、どのエグゼキューターを使用するかなどの情報を登録します。登録のサンプルです。

sudo gitlab-ci-multi-runner register

Running in system-mode.

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/ci):
https://gitlab.com/ci <= 入力
Please enter the gitlab-ci token for this runner:
PXAmPChdiODkoxksoso <= 入力
Please enter the gitlab-ci description for this runner:
とある実働環境 <= 入力
Please enter the gitlab-ci tags for this runner (comma separated):
target,production <= 入力
Registering runner... succeeded                     runner=PXAmPChU
Please enter the executor: virtualbox, docker+machine, docker-ssh+machine, docker, docker-ssh, parallels, shell, ssh:                                           shell <= 入力
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

設定項目は以下のとおりです。

  1. "gitlab-ci coordinator URL"はプロジェクトのRunners設定項目のページに表示されています。gitlab.comを利用している場合は、https://gitlab.com/ユーザ名かグループ名/プロジェクト名/runnersです。gitlab.comを利用する場合は、https://gitlab.com/ciです。
  2. "gitlab-ci token"も、上記のRunnersページにトークンが表示されています。それを入力してください。
  3. "gitlab-ci description"は、このランナーの説明文です。日本語も使えます。ランナーを登録すると、上記のRunnersページの左側、"Specific runners"に一覧で表示されます。その時に判別しやすい名前を付けましょう。
  4. "gitlab-ci tags"は、ジョブをどのランナーで実行するかを指定する場合に利用します。のちほど利用しますので、今回は例のように"target,production"と指定してください。カンマ区切りで指定します。あとからRunnersページから変更できます。
  5. "executor"でエグゼキュータを指定します。今回のチュートリアルではshellを指定してください。

設定が終了したら、Runnersページで確認してください。ステップ3の説明文と、ステップ4のタグが表示されています。しかし、まだ実行していませんので、注意喚起の!アイコンがついています。

ランナーの実行

実際に、ランナーを起動しましょう。

このチュートリアルが終了したらまとめて消去しやすいように、一時的なディレクトリを作成してください。以下は、私のホームディレクトリ、/home/hiro下にtempディレクトリを作成した状況で説明しています。

では、ターミナルで新しい一時ディレクトリへ移動してください。そこで、ランナーを起動します。

sudo gitlab-ci-multi-runner run

Runnersページで確認しましょう。自動では変更されませんので、再読み込みが必要です。

!アイコンがグリーンの丸に変わり、実行中であることが分かります。

.git-ci.ymlファイル

最書に新しくインストールし、gitlab.comのプロジェクトへgit pushしたディレクトリで作業します。

.git-ci.ymlファイルを以下の内容で作成してください。

stages:
  - チェック

パスの表示:
  stage: チェック
  script:
    - pwd

1ステージ、1ジョブを定義しています。実際に行うのはpwdコマンド、現在の作業(ワーキング)ディレクトリを表示するだけのシェルコマンドです。

これを追加したら、pushしてみましょう。CIの実行結果を見てみましょう。

gitlab.comの上部ナビにある、Pipelinesリンクをクリックすると、実行されたジョブが表示されます。一番上が最近の実行結果です。問題なければ、緑の"passed"が表示されているはずです。それをクリックすると内容が確認できます。

Running with gitlab-ci-multi-runner 1.5.3 (fb49c47)
Using Shell executor...
Running on mint-kde...
Cloning repository...
Cloning into '/home/hiro/temp/builds/06f6929e/0/hirokws/ci-sample-php'...
Checking out a8a25085 as master...
$ pwd
/home/hiro/temp/builds/06f6929e/0/hirokws/ci-sample-php
Build succeeded

もしくは…

Running with gitlab-ci-multi-runner 1.5.2 (76fdacd)
Using Docker executor with image ruby:2.1 ...
Pulling docker image ruby:2.1 ...
Running on runner-30dcea4b-project-1686889-concurrent-0 via runner-30dcea4b-machine-1474273970-c8c31284-digital-ocean-4gb...
Cloning repository...
Cloning into '/builds/hirokws/ci-sample-php'...
Checking out ec6a1504 as master...
$ pwd
/builds/hirokws/ci-sample-php
Build succeeded

上が私が起動したランナーで実行された場合です。/home/hiro/temp/下にディレクトリを掘り、その中で実行されています。下はgitlab.comの用意した共有ランナー上のDockerコンテナの中で実行されています。

共有ランナーとプロジェクトで指定したSpecificランナーの両方が存在する場合、どちらが実行されるか決まっていないようです。

初めて、試した時は共有だけで実行されました。この記事を書くために再確認で実行している現在は、私が立ち上げたランナーだけで実行されています。

実際、どのランナーで実行されてもかまわないジョブもあれば、限定ランナーで必ず実行したいジョブもあります。たとえば、今回目的としている、実働環境で動かしているランナーを指定し、デプロイに利用する場合です。他に、自分のWindowsマシンでランナーを起動し、Windowsでしか行えないビルド作業をCIに組み込みたい場合もそうです。

どのランラーでジョブを実行するかは、タグで指定します。

既に、このチュートリアルで起動したランナーには、targetproductionのタグを付けています。ジョブに指定してみましょう。

stages:
  - チェック

パスの表示:
  stage: チェック
  script:
    - pwd
  tags:
    - target

これでコミットし、pushしてください。結果をPipelinesページで確認してください。必ず、自分で起動したランナーで実行されます。

targetというタグは、共有ランナーには付けられていません。共有ランナーに付いているタグは、Runnersページから確認できます。

targetというタグでランナーが限定できます。ですから、必ず自前のランナーで実行できるわけです。

  tags:
    - target
    - production

このようにタグを増やすと、AND条件で限定されます。ランナーにつけている2つのタグ以外に、タグを増やしてみましょう。

  tags:
    - target
    - production
    - local

コミットし、pushしてください。Pipelinesページで確認しましょう。

上記3つのタグを持つランナーは見つからないため、実行できません。ステータスは"Pending"になったまま変化しません。Cancel Runnningボタンで停止しましょう。

テストとデプロイ

これで、ランナーをデプロイ対象のサーバでshellエグゼキュータで立ち上げ、ブランチ内容をコピーすることでデプロイする手法の基本情報が理解できたと思います。

まあ、わざわざ書くこともないとはありませんが、PHPUnitを実行し、テストに合格したら、デプロイするジョブを定義してみます。

stages:
  - テスト
  - デプロイ

PHPUnit単体テスト:
  stage: テスト
  image: php:7.1-alpine
  cache:
    paths:
      - vendor
  before_script:
    - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
  script:
    - mv .env.example .env
    - rm composer.lock
    - composer install --prefer-dist --no-progress --ansi
    - php artisan key:generate
    - vendor/bin/phpunit


実働サーバー上のランナーからデプロイ:
  stage: デプロイ
  script:
    # 現在のディレクトリを保存しておく
    - origin=$(pwd)
    # 対象のディレクトリへ移動
    - cd /home/hiro/laravel51project
    - php artisan down
    - cp -R "${origin}/app/" .
    - cp -R "${origin}/database" .
    # その他必要に応じて…もしくは、rsyncかgit pullか…
    - php artisan migrate
    - php artisan up
  tags:
    - target

最初のテストジョブについては、前記事で紹介しています。違いは、イメージを指定しているところです。タグを指定せず、しかもDockerイメージを指定してありますので、共有サーバで実行されます。

デブロイジョブは、タグの指定により目的のサーバで実行します。

デプロイ方法については、このように既に取得されているプロジェクト構造をコピーするなり、内容を全く同一にしたければrsyncを使用するなり、git pullを使い更新するなり、別ディレクトリにgit cloneし、リンクを切り替えるなり、お好きな方法が取れると思います。

具体的なデプロイ手法のチュートリアルではないため、そこまで踏み込みません。

実行ユーザの問題

ランナーの実行ユーザについて注意を払う必要があります。

このチュートリアルで、たとえばappディレクトリ下に新しいファイルを作成すると、デプロイ対象ディレクトリのapp下にrootユーザの所有物として作成されてしまいます。

これは、Laravelでもよくはまる点です。Artisanコマンドを実行した結果として、あるファイルが作成されると、そのコマンドを実行した人が所有者になります。Webサーバの実行ユーザから、そうしたファイルがアクセスできずに、トラブルになりがちです。

たとえばUbuntuサーバの場合、Webサーバの実行ユーザはwww-dataです。LaravelプロジェクトはWebサーバからアクセスできる必要がありますから、ランナーもwww-dataで実行しておくのが簡単です。

sudo gitlab-ci-multi-runner run -u www-data

今回はtemp一時ディレクトリで実行しました。ユーザを帰る場合は、一度このディレクトリを削除し、再度作りなおしましょう。rootで作られたディレクトリやファイルが存在していますので、そのまま実行するとアクセスできずに、エラーが起きます。

サービスとして登録

実用的には、いちいちサーバを手動で起動するのはいまいちです。実用サーバがLinuxサーバであれば、サービスとして登録しておきましょう。

gitlab-ci-multi-runnerコマンドは、自身でサービスとして登録できます。

sudo gitlab-ci-multi-runner install --user=www-data --working-directory=/somewhere
sudo gitlab-ci-multi-runner start

runコマンドと同様に、installコマンドでも、実行ユーザは-u、作業ディレクトリは-dでも指定可能です。

登録を取り消すにはuninstallコマンドを使います。