※本記事は嘉数の個人ブログ(Gitlab CI/CDでLaravelプロジェクトのテスト及びデプロイをする - けけずんセルフハッキング)からの転載になります
概要
LaravelプロジェクトをGitlabにPushした際、Pushしたブランチに応じて自動でテストやデプロイを行うようにする。ついでに、テストが通らなかったブランチはメインのブランチに対するマージリクエストを行えないようにする。
ブランチ毎に行う処理
master
:テスト、本番環境へのデプロイdeploy
:テスト、ステージング環境へのデプロイ- 上記以外のブランチ:テスト
処理の流れ
以下はPushからデプロイまでの処理の流れ図。
- LocalからGitlabにPushする
- GitlabCIが実行される
- Unitテスト用のDockerコンテナが起動される
- Unitテストが実行される
- デプロイ用のDockerコンテナが起動される
- Envoyコマンドが実行される
- デプロイ先(本番環境orステージング環境)でPullされる
実装手順
結構やること多い。やることを列挙しとく。
- ローカルでやること
- Gitlabからデプロイ先に接続するための鍵組の作成
- Dockerの準備
- Dockerfileの作成
- Dockerfileをビルドしてイメージを作成
- DockerイメージをGitlab Container Registryに登録
- Gitlab-CI設定ファイルの作成
- デプロイ用タスクランナー設定ファイルの作成
- デプロイ先(本番環境orステージング環境)でやること
- デプロイ用ユーザの作成と設定
- GitlabからClone・Pullするための鍵組の作成
- リポジトリのCloneと設定
- Gitlabからデプロイ先に接続するための鍵の設置
- Gitlabでやること
- GitlabからClone・Pullするための鍵を登録
- Gitlabからデプロイ先に接続するための鍵の登録
- ブランチをProtected branch化
こんな感じでやっていく。
ローカルでやること
Gitlabからデプロイ先に接続するための鍵組の作成
ローカルの任意の場所(以下/path/to/mykeys
とする)で以下のコマンドを実行し、Gitlabからデプロイ先へ接続を行うための鍵組を作成する。
$ cd /path/to/mykeys $ ssh-keygen -t ecdsa -b 521 -f gitlab-deploy-key -C "deploy-key@gitlab.com" (色々聞かれるので全てEnter)
暗号スイートはECDSAを指定、鍵長は521bitを指定、コメントは任意のコメントを入力する。以下のコマンドで鍵組(秘密鍵、公開鍵)が作成されたことを確認する。
$ ls -l /path/to/mykeys gitlab-deploy-key gitlab-deploy-key.pub
これ失くしたらヤバイので、紛失しないようにちゃんと管理すること。
Dockerの準備
Gitlab-CI実行時に起動されるDocekrの準備をする。Dockerイメージの登録先として、Gitlabにmydocker
というリポジトリを作成しておくこと。
Dockerfileの作成
ローカルの任意の場所(以下/path/to/mydocker
とする)で以下のコマンドを実行し、Dockerfile
ファイルを作成する。
$ touch /path/to/mydocker/Dockerfile
上記で作成したファイルに以下の内容を記述する。
FROM centos:7 MAINTAINER myname <myname@my_email_address> RUN echo "include_only=.jp" >>/etc/yum/pluginconf.d/fastestmirror.conf && \ rpm --import http://ftp.riken.jp/Linux/centos/RPM-GPG-KEY-CentOS-7 && \ rpm --import http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 && \ rpm --import http://rpms.famillecollet.com/RPM-GPG-KEY-remi RUN yum -y install epel-release && \ yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm && \ yum-config-manager --enable remi-php72 && \ yum -y update RUN yum -y install wget git unzip RUN yum -y install php php-mbstring php-pdo php-mysqlnd php-dom php-posix RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN composer global require "laravel/envoy=~1.0"
今回のDockerfile
はLaravelプロジェクトとEnvoyコマンドが動く最低限の環境を構築するための内容になっている。他に必要なものがあれば上記のファイルに適宜追加してね。
Dockerfileをビルドしてイメージを作成
作成したDockerfile
から以下のコマンドでDockerイメージを作成する。
$ cd /path/to/mydocker $ docker build -t registry.gitlab.com/[Gitlabアカウント名]/mydocker .
-t
オプションには作成するイメージ名を指定してる。ビルドに少し時間かかるかも(3〜5分くらい)。
DockerイメージをGitlab Container Registryに登録
GitlabにDockerイメージを登録するために以下のコマンドでGitlabにログインする。
$ docker login registry.gitlab.com (Gitlabアカウント名、パスワードの入力を要求される)
ログイン後、以下のコマンドでDockerイメージを登録する。
$ docker push registry.gitlab.com/[Gitlabアカウント名]/mydocker
ここでも少し時間がかかる(3〜5分くらい)。特にエラーがなければ正常に登録されているはず。
なお、Gitlab公式ページではLaravelプロジェクト直下にDockerfile
を作成してビルドしたDockerイメージをLaravelプロジェクトのGitlabリモートリポジトリに登録しているが、今回はDocker用にGitlabリモートリポジトリに作成してそこに登録している。こうすることで、他のプロジェクトでもDockerを利用することが出来る(こういう使い方していいのか分からんけど)。
Gitlab-CI設定ファイルの作成
Gitlab-CIではGitlab-CI設定ファイル.gitlab-ci.yml
に記述された内容に沿ってCIが実行される。以下のコマンドでLaravelプロジェクト直下(以下/path/to/myapp
とする)に.gitlab-ci.yml
ファイルを作成する。
$ touch /path/to/myapp/.gitlab-ci.yml
上記で作成したファイルに以下の内容を記述する。
image: registry.gitlab.com/[Gitlabアカウント名]/mydocker stages: - test - deploy test_pupunit: stage: test services: - mysql:latest variables: DB_HOST: mysql DB_USERNAME: root MYSQL_DATABASE: homestead MYSQL_ROOT_PASSWORD: secret script: - cp .env.example .env - composer install - php artisan key:generate - php artisan migrate - vendor/bin/phpunit .shared_hidden_key: &before_deploy before_script: - 'type ssh-agent || yum -y install openssh-clients' - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") - mkdir -p ~/.ssh - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >~/.ssh/config' deploy_stg: stage: deploy <<: *before_deploy script: - ~/.composer/vendor/bin/envoy run deploy_stg environment: name: staging url: [ステージング環境で公開してるURL] when: on_success only: - develop deploy_prd: stage: deploy <<: *before_deploy script: - ~/.composer/vendor/bin/envoy run deploy_prd environment: name: production url: [本番環境で公開してるURL] when: manual only: - master
image
項目では先ほどGitlabに登録したDockerイメージを参照してあげる。あとはテストの項目、デプロイの項目が順に記述されている感じ。あとデプロイ先毎に同じ内容の処理を記述するのがダサい感じがしたので、.shared_hidden_key: &before_deploy
の項目に処理をまとめて記述しておいて、各デプロイ先の処理部(deploy_stg
, deploy_prd
)に <<: *before_deploy
を記述しておく。これでなんとなくスマートな感じがする。
.gitlab-ci.yml
がローカルリポジトリに存在する状態でGitlabにPushするとGitlab-CIが実行されるようになる。しかし今の段階ではちゃんと動かないので、本ブログの手順を全て終えてから最後にPushしてね。
デプロイ用タスクランナー設定ファイルの作成
Gitlab-CIから呼び出されるデプロイ用タスクランナー設定ファイルEnvoy.blade.php
を/path/to/myapp
直下に作成する。
$ touch /path/to/myapp/Envoy.blade.php
上記で作成したファイルに以下の内容を記述する。
@servers(['stg-host' => 'deployer@[ステージング環境のIPアドレス]', 'prd-host' => 'deployer@[本番環境のIPアドレス]']) @setup $app_dir = '/var/www/myapp' @endsetup @story('deploy_stg', ['on' => 'stg-host']) pull_repository run_composer run_artisan run_npm @endstory @story('deploy_prd', ['on' => 'prd-host']) pull_repository run_composer run_artisan run_npm @endstory @task('pull_repository') echo 'Pull repository' cd {{ $app_dir }} git pull @endtask @task('run_composer') cd {{ $app_dir }} composer update composer install --no-dev --optimize-autoloader @endtask @task('run_artisan') cd {{ $app_dir }} php artisan down php artisan migrate php artisan cache:clear php artisan config:cache php artisan view:clear php artisan up @endtask @task('run_npm') cd {{ $app_dir }} npm run production @endtask
デプロイ先(本番環境orステージング環境)でやること
デプロイ先(本番環境、ステージング環境)それぞれにログインして以下の作業を行う。
デプロイ用ユーザの作成と設定
rootユーザで以下のコマンドを実行し、デプロイ用のユーザを作成する。
root$ adduser deployer
どうせ公開認証方式でしかログインしないだろうからパスワードの設定しなくてもいいんだけど、念のため設定しておく。
root$ passwd deployer (任意のパスワードを入力)
deployerユーザが/var/www
下でリポジトリをClone・Pull出来るよう、以下のコマンドで権限を与える。/var/www
がない場合は作成すること。
root$ setfacl -R -m u:deployer:rwx /var/www
GitlabからClone・Pullするための鍵組の作成
deployerユーザで以下のコマンドを実行し、GitlabからClone・Pullを行うための鍵組を作成する。
deployer$ mkdir -p ~/.ssh deployer$ chmod 700 ~/.ssh deployer$ ssh-keygen -t ecdsa -b 521 (色々聞かれるので全てEnter)
以下のコマンドで鍵組(それぞれ秘密鍵、公開鍵)が作成されたことを確認する。
deployer$ ls -l ~/.ssh id_ecdsa id_ecdsa.pub
リポジトリのCloneと設定
deployerユーザで以下のコマンドを実行し、GitlabからLaravelプロジェクトをCloneする。
deployer$ cd /var/www deployer$ git clone git@gitlab.com:[Gitlabアカウント名]/myapp.git
CloneしてきたLaravelプロジェクト下にあるstorage
にのみ書き込み権限を与える。
deployer$ chmod -R 777 /var/www/myapp/storage
chmod
コマンドで-R
オプションつけて777って場所間違えたら大変なことになるので注意。
Gitlabからデプロイ先に接続するための鍵の設置
ここが少しややこしい。手順「ローカルでやること/Gitlabからデプロイ先に接続するための鍵の作成」で作成した鍵のうち公開鍵gitlab-deploy-key.pub
をデプロイ先に設置する。以下のコマンドをローカルで実行し、公開鍵を転送する。
$ scp /path/to/mykeys/gitlab-deploy-key.pub deployer@[デプロイ先のIPアドレス]:~/
公開鍵認証使ってる人は上記のコマンドを実行すると特に何も聞かれずに実行完了するけど、使ってない人はパスワード求められるのでパスワードを入力する。さっき設定したパスワードがここで活きるというね、設定しててよかった(小並感)。
次に以下のコマンドをデプロイ先で実行し、転送されてきた公開鍵をauthorized_keys
に記述する。あとは適切なアクセス権を付与することで、Gitlabからデプロイ先へ接続可能な状態になる。最後に、転送されてきた公開鍵を削除するのを忘れずに。
deployer$ cat ~/gitlab-deploy-key.pub >> ~/.ssh/authorized_keys deployer$ chmod 600 ~/.ssh/authorized_keys deployer$ rm ~/gitlab-deploy-key.pub
コマンドの実行場所(ローカルとデプロイ先)を間違えないように注意しよう。
Gitlabでやること
ここからはブラウザでGitlabのページを開いて作業を行う。ローカルにあるLaravelプロジェクト/path/to/myapp
のリモートリポジトリはGitlabに作成済みであるとする。
GitlabからClone・Pullするための鍵を登録
ここもややこしい。手順「デプロイ先でやること/GitlabからClone・Pullするための鍵の作成」で作成した鍵のうち公開鍵id_ecdsa.pub
をGitlabに登録する。以下のコマンドをデプロイ先で実行し、出力された値をコピーする。
deployer$ cat ~/.ssh/id_ecdsa.pub (なんか出力されるので範囲選択してコピーする)
LaravelプロジェクトのGitlabリモートリポジトリページからProject > Settings > Repositoryと辿っていき、Deploy Keysの項目で登録する鍵のタイトルを任意で入力、それと先ほどコピーした公開鍵の内容をペーストする。以下のような感じ。入力後はAdd keyボタンを押して登録する。
Gitlabからデプロイ先に接続するための鍵の登録
またもやここもややこしい。手順「ローカルでやること/Gitlabからデプロイ先に接続するための鍵の作成」で作成した鍵のうち秘密鍵gitlab-deploy-key
をGitlabに登録する。以下のコマンドをローカルで実行し、出力された値をコピーする。
$ cat /path/to/mykeys/gitlab-deploy-key (なんか出力されるので範囲選択してコピーする)
LaravelプロジェクトのGitlabリモートリポジトリページからProject > Settings > CI/CDと辿っていき、Secret variablesの項目で登録する鍵のタイトルに「SSH_PRIVATE_KEY」と入力し(重要!!)、先ほどコピーした秘密鍵の内容をペーストする。「Protected」のトグルはよく分からんけどオンにしておく。以下のような感じ。入力後はSave variablesボタンを押して登録する。
鍵のタイトルに「SSH_PRIVATE_KEY」を入力したのは、手順「ローカルでやること/Gitlab-CI設定ファイルの作成」で作成したGitlab-CI設定ファイル内で環境変数として使用するため。鍵のタイトルとGitlab-CI設定ファイルに記述した環境変数名は統一すれば何でも良いのだけど、分かりやすいように今回はこのタイトルにした。
特定のブランチをProtected branch化
うおーーーーーそしてこれが最後の手順!Gitlab-CIでテストを実行した後、テストが通ったブランチをメインのブランチにマージしないよう設定する(正確にはマージリクエストが出来ないようにする、かな?)。
LaravelプロジェクトのGitlabリモートリポジトリページから、Project > Settings > Repositoryと辿っていき、Protected Branchesの項目でProtected branch化したいブランチを選択する。おそらく本番環境で使用するmasterブランチはデフォルトでProtected branchになってるので、今回はステージング環境で使用するdevelopブランチ辺りをProtected branch化する。以下のような感じ。
Gitlab-CI実行
ここまで長い工程をお疲れ様でした。最後に、ローカルからLaravelプロジェクト/path/to/myapp
をPushし、Gitlab-CIが実行されるか確認しよう。このとき、本番環境にデプロイするならmasterブランチ、ステージング環境にデプロイするならdevelopブランチでPushする。最初に説明したが、developブランチはPushすると自動でデプロイされるが、masterブランチはPushしても自動でデプロイはされない。masterブランチをデプロイする際はLaravelプロジェクトのGitlabリモートリポジトリページからテストが通っていることを確認し、手動でデプロイすること。
$ cd /path/to/myapp $ git push -u origin master
感想
主にGitlab公式ページを参考に作業を行ったが、実際に手を動かして理解できた。作業自体も時間がかかったが、この記事を書くのにも時間かかった...。自分のための記録として、また他の人の参考として、本記事が役に立つと嬉しい。間違い等があれば指摘おなしゃす、