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なので、興味があったら使ってみてください。