
はじめに
この記事は CircleCI Advend Calendar 2019 の 15日目の記事です。
CircleCIってプライベートプロジェクトでも無料で使えるんだ!って知って早速設定したので書きます。
CIって何?
CI は Continuous Integration の略です。日本語だと「継続的インテグレーション」と言われたりします。インテグレーションは「改善」みたいなニュアンスでしょうか。継続的な改善のことです。
例えば、
ソースコードがGitHubにpushされたタイミングで自動的ユニットテストなどを実行してくれる
みたいな仕組みを CI と呼びます。
- GitHubにpushされたタイミングで自動的に → 継続的に実行される
- ユニットテストを実行してくれる → アプリケーションの品質を改善(担保)してくれる
ということでこれも CI になります。
CIについては下記書籍の5章にいい感じの説明が乗っています。CIに限らずDevOpsという開発と運用に関する手法がまとめられていて非常に良い本です。

DevOps導入指南 Infrastructure as Codeでチーム開発・サービス運用を効率化する (DEV Engineer’s Books)
- 作者:河村 聖悟,北野 太郎,中山 貴尋,日下部 貴章,株式会社リクルートテクノロジーズ
- 出版社/メーカー: 翔泳社
- 発売日: 2016/10/14
- メディア: 単行本(ソフトカバー)
なぜCIが必要なのか
CIが無い場合、ユニットテストが継続的に実行されないので、「誰かがユニットテストを実行した時に、たまたまテストが落ちていることに気づく」ことになります。これが本番デプロイ直前だった場合、非常に困ります。
また、テストは実行するのが面倒なので、次第にみんな実行しなくなっていきます。
例えば、クラスAを修正したとします。対応したクラスAのテストを修正して問題ないことを確認します。この時、もしかしたらこの変更でクラスBも影響を受けているかもしれませんが、クラスBのテストは実行しません。面倒だからです。
いやいや、自分はちゃんと実行するから。そう思うかもしれませんが、CIで実行されていないテストは通ることが担保されていないも同様と思ってもいいと思います。

DevOps導入指南 Infrastructure as Codeでチーム開発・サービス運用を効率化する (DEV Engineer’s Books)
- 作者:河村 聖悟,北野 太郎,中山 貴尋,日下部 貴章,株式会社リクルートテクノロジーズ
- 出版社/メーカー: 翔泳社
- 発売日: 2016/10/14
- メディア: 単行本(ソフトカバー)
無料で使えるCIは
無料で使えるCIで有名どころは2つあります。ビルド時間はテストを実行している時間の長さと考えてください。
- Travis CI
- https://travis-ci.org/
- オープンソース(パブリックリポジトリ)であれば無料でビルド時間制限も無い
- CircleCI
- https://circleci.com/
- 一週間あたり2500クレジット(250分)まで無料でビルドできる
- プライベートリポジトリでも可
OSS はほとんどが Travis CI を採用していると思います。商用プロダクトは CircleCI が多いです。小規模なプロダクトであれば250分もあれば十分です。*1
CircleCIの設定を書く
方針
GitHubにプッシュされた時点でDockerのビルド→それを使ってユニットテストの一連の流れを実行します。
WorkflowとJob
CircleCI には Workflow と Job という概念があります。
Job は、一連の流れみたいなものです。今回は「DockerビルドするJob」と「テストをするJob」を作成します。前者を build, 後者を test と呼ぶことにします
- build: DockerをビルドするJob
- test: テストを実行するJob
これら2ジョブを分ける理由ですが、
- build: Linuxマシン上でコマンドを実行
- test: Docker上でコマンドを実行
と、実行環境が違うので、これら2つの Job は分ける必要があります。*2
Workflow は複数の Job を組み合わせたものです。Jobを並列につなぎ合わせたり直列につなぎ合わせたりすることができます。実際の設定を見るとわかりやすいです。
Workflowの設定
CircleCIの .circleci/config.yml は以下のようになります。
version: 2.1
workflows:
version: 2.1
build_and_test:
jobs:
- build
- test:
# test は build が終わったあとに実行する
requires:
- build
jobs:
# build はテスト用の Docker image のビルドをするジョブ
build:
# build の中身は後述
test:
# test の中身は後述
DockerビルドのJob
事前にプロジェクトの設定から AWS Permissions を設定しておく必要があります。
build:
# CircleCI の machine を使ってジョブを実行する
# https://circleci.com/docs/ja/2.0/executor-types/
machine: true
steps:
# ソースコードをpull
- checkout
- run:
# AWS ECS にログインする
# AWS Permissions で設定した AWS の情報を使ってログインする
# $(...) は ... の実行結果をそのままコマンドとして実行するもので、
# get-loginの実行結果をそのまま叩くとログインが完了する
name: "AWS ECSにログイン"
command: $(aws ecr get-login --no-include-email --region ap-northeast-1)
- run:
# はじめに ECS からイメージを pull しておいて、
# 差分ビルドをすることでビルド時間を短縮する
# ただし、初回はimageがないのでpullに失敗してテストが落ちる
# なので予め適当なイメージをpushしておく
# コマンドがコケても無視する、という設定は面倒なので妥協でこうしている
name: "ECSからイメージをpullしてくる"
command: docker pull XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/app:test
- run:
name: "Dockerイメージをビルドする"
command: docker build --file="Dockerfile" --tag="XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/app:test" --cache-from="XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/app:test" .
- run:
name: "ビルドしたイメージをECRにpushする"
command: docker push XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/app:test
テストのJob
test:
# 先程はmachineを指定したが、今回はdockerを指定
docker:
- image: XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/app:test
environment:
# pythonの方で、環境変数を呼んでDB接続するようにしている
# circleci/mysql のイメージを使うので、その設定をする
RDS_DB_NAME: 'circle_test'
RDS_USERNAME: 'root'
RDS_PASSWORD: ''
RDS_HOSTNAME: '127.0.0.1'
RDS_PORT: '3306'
- image: circleci/mysql:5.7
steps:
- run:
# dockerize というツールを使って mysql の起動を待たないと、
# mysql が立ち上がる前にテストが実行されてしまい失敗する
name: 'docker の起動を待つための dockerize コマンドをインストール'
command: |
apt install wget -y \
&& wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
&& tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
&& rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
environment:
DOCKERIZE_VERSION: v0.6.1
- run:
name: 'DBコンテナの起動を待つ'
command: dockerize -wait tcp://localhost:3306 -timeout 1m
- run:
name: "テストを実行する"
command: ./manage.py test
今後
- 実はよく見ると AWS Permissions に「These project settings are no longer available. Please use the aws-cli orb instead.」と書いてありました。なので今回のやつはちょっと書き換える必要があります。。。やってるときに気づけよ
- まだテスト結果の収集ができてないのでやる必要があります

DevOps導入指南 Infrastructure as Codeでチーム開発・サービス運用を効率化する (DEV Engineer’s Books)
- 作者:河村 聖悟,北野 太郎,中山 貴尋,日下部 貴章,株式会社リクルートテクノロジーズ
- 出版社/メーカー: 翔泳社
- 発売日: 2016/10/14
- メディア: 単行本(ソフトカバー)
余談
この記事書くために Travis CI で調べたら CircleCI の広告出てきて
