2020/11/09
最近webアプリの開発にハマっていた流れで、自動デプロイに挑戦してみました。
今回はソースをGitHubのプライベートリポジトリに挙げていたこと、また相談した仲間からCircleCIを紹介されたので、CircleCIを用いてのトライです。
しかしいざやってみると、あれやこれやでかなり詰まりました!
CircleCIの実行ログを見返すと、失敗がこんなにたくさん…。
初歩的なことから解決に時間が掛かったものまで、今後のために書き残しておきますよ!
目次
環境
今回デプロイを行ったWebアプリケーションの環境です。
デプロイしたいWebアプリのソースコードはGitHubのリポジトリにプッシュ済みです。
・Apache: 2.4
・PHP: 7.2
・Laravel: 5.7
基礎知識
GitHubとの連携や設定ファイルの書き方など、基本的な知識は他のサイトに載っているので、そちらを参照ください。
特に参考になったサイトをご紹介します。
https://esnetk6.com/2018/04/circle-ci-deployment/
https://www.findxfine.com/programming/995561878.html
作成したCircleCI設定ファイル
私が作成・使用したCircleCIのconfig.ymlは以下になります。
version: 2
jobs:
deploy:
docker:
- image: circleci/php:7.2.9
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "composer.json" }}
- v1-dependencies-
- run: echo $ENV | base64 --decode > .env
- run: sudo composer install -n --prefer-dist
- save_cache:
key: v1-dependencies-{{ checksum "composer.json" }}
paths:
- ./vendor
- restore_cache:
keys:
- node-v1-{{ checksum "package.json" }}
- node-v1-
- save_cache:
key: node-v1-{{ checksum "package.json" }}
paths:
- node_modules
- run: sudo php artisan key:generate
- run: ./vendor/bin/phpunit tests/
- add_ssh_keys:
fingerprints:
- "[SSHキーのフィンガープリント]"
- run: ssh -o "StrictHostKeyChecking=no" $SSH_USER@$SSH_HOST "~/deploy.sh"
workflows:
version: 2
test:
jobs:
- deploy
動くこと優先で作ったので、workflowやキャッシュはネットで拾ったサンプルのままです。
後述しますがデプロイはシェルスクリプト1つで行うため、デプロイツール等も使用していません。
[SSHキーのフィンガープリント] の部分はCircleCIに秘密鍵を登録後、プロジェクト設定の「SSH Permissions」画面から確認して入力します。
詰まったこと
設定ファイルで指定するDockerについて
CircleCIの設定ファイルを見ると、Dockerに関する設定があります。
docker:
- image: circleci/php:7.2.9
これはCircleCI自体の実行環境のことであり、デプロイ先のアプリがDockerを使っているかどうかとは無関係です。
このコンテナの上でGitHubからソースを落としてユニットテストを走らせたり、SSHコマンドでデプロイ先のスクリプトを実行したりします。
指定可能なイメージは公式の以下のページに載っています。
https://circleci.com/docs/2.0/circleci-images/
デプロイの実行について
runコマンドを実行する環境はCircleCIのDockerコンテナ上です。
なので実行するコマンドはデプロイ先のサーバには何も影響しません。言い換えれば、runコマンドで本番環境向けのコマンドを実行しても反映されません。
このことを認識していなかった私は、runコマンドにsudo npm run productionとか書いていたりしました。
デプロイを実行する方法はいくつかありますが、今回はシンプルに「デプロイ先のサーバ上にあるシェルスクリプトを実行する」だけにしました。
#! /bin/bash cd /var/www/html/AzarashiPhotoCollection git pull npm run production echo "complete!"
中身もシンプルで、cdしてpullしてnpmでビルドするだけです。
これを接続ユーザーのホームディレクトリに配置し、実行権限を与えておきます。一度実行して問題ないか確認しておくと安心です。
あとは設定ファイルのrunコマンドでsshを行い、上記のシェルスクリプトを実行します。
- run: ssh -o "StrictHostKeyChecking=no" $SSH_USER@$SSH_HOST "~/deploy.sh"
上の例ではCircleCI上に環境変数SSH_USER``SSH_HOSTを登録して参照するようにしています。環境に依存する部分はなるべく外出ししておくと、他で必要になったときに使いまわしやすくなりますね。
GitHubからのpull
デプロイ先のサーバからgit pullコマンドを打った際、パスフレーズなしで取れるようにする必要があります。pull実行時にパスワードを聞かれるとそこで止まってしまうためです。
これを解決するため、サーバ側で秘密鍵を作成し、公開鍵をGitHubに登録します。手順については検索すると沢山ヒットするので、本記事では割愛します。
1つ詰まったのは、git pullをsudoで実行していたために、登録した秘密鍵が参照されなくなってしまったことがあります。
鍵の設定後はssh -T git@github.comで接続できるか確認してみましょう。
一般ユーザーでも実行できるようにパーミッションを設定するのも重要です。私の場合は実行ユーザーをapacheグループに入れ、各ディレクトリとファイルのパーミッションを775に設定しました。
ユニットテスト実行時の.envファイル
ユニットテストを実行しようとしたら、No application encryption key has been specified.というエラーが出力されていました。
暗号化キーを作成するため、artisanのkey:generateを実行する必要があったのですが、.envファイルがないためエラーになってしまいます。
なのでローカルで使っている.envファイルの中身をPHPのbase64_encode()関数でエンコードし、CircleCIの環境変数にキー名「ENV」として設定します。
私の場合、以下のようなPHPプログラムをLaravelプロジェクト直下に配置し、コマンドラインから直接呼び出して出力しました。
<?php
$env = file_get_contents('.\.env');
$encoded_env = base64_encode($env);
echo $encoded_env;
exit;
あとはconfig.ymlのrunコマンドでデコードし、.envファイルを作成するようにします。
前述した設定ファイルの以下の部分ですね。
- run: echo $ENV | base64 --decode > .env
ローカルの.envであれば重要なデータはないかと思いますが、気になる方は専用の.envファイルを作り、それをbase64エンコードして使用しましょう。
また、ユニットテストにはインメモリDBを使うよう指定すると、DB接続周りの設定も適当でよくなるのでおすすめです。
あとがき
そんなわけで、CircleCIを用いて自動デプロイの構成を作ってみました。
慣れていないのもあってかなり時間が掛かってしまいましたが、使ってみるとかなり便利で、ユニットテストも自動化されるため安心感もあります。
個人利用くらいなら無料枠でも十分使える上、GitHub側はプライベートリポジトリでもOKなので、興味があったら使ってみてください。






