ゴマちゃんフロンティア

アザラシが大好きなエンジニアの開発日記です

CircleCIでWebアプリのユニットテストとデプロイを自動化したお話

time 2019/05/22

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

down

コメントする