CircleCIを導入してCI/CDを簡単に始めよう!
こんにちは。開発チームの尾碕です。
ラクーンでは、「スーパーデリバリー」や「Paid」「T&G売掛保証」「URIHO」「COREC」などの様々なWEBサービスを提供しています。
サービスのシステムを高品質に保ち続けるためには継続的インテグレーション(CI)・継続的デリバリ(CD)は欠かせません。
弊社では、CI/CDツールの代表である「Jenkins」を利用していますが、最近よく名前を聞くCircleCIを調べてみましたので、ご紹介したいと思います。
今回は、CircleCIを使ってWebアプリケーションのテスト・デプロイ・ビルドまでの導入手順を説明します!
CircleCIとは?
CircleCIとは、ビルド・テスト・デプロイのCI/CDを自動で実行するクラウドサービスです。
クラウドサービスなので、Jenkinsなどのオンプレ型のようにCIサーバーを設置せずにすぐに利用することが可能です。
CircleCIは、コンテナと呼ばれる実行環境でビルドやテストを実施します。
実行環境では、Docker・VMマシン・MacOSを選ぶことができ、実行速度が速いDockerが主流となっています。
GitHubやBitbucketなどのリポジトリサービスと連携を行い、pushする度にコンテナ内で設定した処理を自動で実行します。
コンテナが複数あれば、並列処理でテストを実施できます。
無償版と有償版の比較
CircleCIではコンテナを1つまで無料で利用できますが、複数利用する場合は有償になります。
他にもMacOSやオンプレミス版の実行環境の料金プランがあります。この記事では、Linux実行環境での無料版を利用しています。
Linux実行環境での無償版と有償版の違い
機能 | 無料版 | 有償版 |
---|---|---|
リポジトリ数 | 無制限 | 無制限 |
ユーザー数 | 無制限 | 無制限 |
月間ビルド時間 | 1,000分まで無料 | 無制限 |
コンテナ数 | 1つ | 1つ追加する毎に50$ |
同時処理数 | 1回まで | コンテナの数だけ並列処理が可能 |
他の料金プランについての詳細はこちらをご覧ください。
CircleCIを動かす
実際にCircleCIを動してみましょう。
Gitアカウントの連携
CircleCIのTOPから登録をクリックしてユーザ登録画面を開きます。
CircleCIを利用するには「GitHub」か「Bitbucket」のアカウント連携が必要です。
連携が終わると、CircleCIのメニューが開きます。
日本語は未対応で英語しかサポートされていません。
JOBSのGetting Startedの中に、連携したGithubかBitbucketのアカウントが表示されています。
下の画面の時点ではリポジトリが存在しないので、リポジトリを追加します。
ページを更新すると追加したリポジトリが表示しています。
チェックボックスを入れてFollow をクリックすると完了です。
JOBSに追加したリポジトリの実行結果が表示されています!
ですが、CircleCIの設定ファイルが存在しないため失敗しています。
CircleCIでは、ビルドやテストなどの一連のプロセスをJobと呼びます。
JobはYAML形式の設定ファイルに定義します。.circleci/config.yml
を作成してリポジトリにpushします。
以下の設定は、実行環境に「Hello world!」と表示するJobになります。
.circleci/config.yml
version: 2
jobs:
build:
docker:
- image: circleci/openjdk:8-jdk
steps:
- run: echo 'Hello world!'
.circleci/config.yml
を追加してpushすると、定義したJobが実行されて成功しています。
Jobをクリックすると詳細画面を開くことができます。
実行結果のログでは「Hello world!」と出力されています。
CircleCIを実行できました!
ビルドからテストまで
CircleCIを動かせるようになったので、次はWebアプリケーションのビルド・テストを行います。
アプリケーション
今回はJava8+SpringBoot+GradleのWebアプリケーションでCI/CDを行います。
ビルド・テストを実施するJobの定義は以下の通りです。
.circleci/config.yml
version: 2
jobs:
build:
docker:
- image: circleci/openjdk:8-jdk
working_directory: ~/repo
steps:
- checkout
# 依存関係をダウンロードしてキャシュする
- restore_cache:
keys:
- v1-dependencies-{{ .Branch }}-{{ checksum "build.gradle" }}
- v1-dependencies-{{ .Branch }}-
- v1-dependencies-
- run: gradle dependencies
- run: gradle build -x test
- save_cache:
paths:
- ~/.gradle
key: v1-dependencies-{{ .Branch }}-{{ checksum "build.gradle" }}
- run:
name: テストの実施
command: gradle test
.circleci/config.yml
の説明
Key名 | 説明 |
---|---|
version |
CircleCIのバージョンを入力します。現時点では2.0 と2.1 のみ対応しています。 |
jobs |
Jobと呼ばれる実行環境や実際に実行されるステップを記述します。 必須項目で原則buildを指定します。 |
docker |
Jobの実行環境の1つであるDockerを指定します。 image でDockerイメージを指定します。CircleCIは様々なDockerイメージを提供しています。CircleCI提供Dockerイメージ一覧 |
working_directory |
stepsを実行するディレクトリを指定します。 |
steps |
Jobで実際に実行するコマンドを1つ以上定義します。 ユーザーが自由に指定できる run コマンドとCircleCIが用意したコマンドがあります。 |
checkout |
指定したworkspaceにリポジトリのソースコードのチェックアウトを行います。 |
restore_cache |
CircleCIから指定したkeyのキャッシュを読み込みます。 |
save_cache |
pathで指定したファイルをCircleCIのキャッシュに保存します。 |
run |
実際に実行するコマンドを指定します。name とcommand で実行するコマンドの名前を決めることも可能です。 |
Java8のSpringBootのWebアプリケーションのため、docker
のimage
をcircleci/openjdk:8-jdkに指定しています。
ダウンロードした依存関係をsave_cache
でキャッシュすることで、2回目以降にJobを実施するときにrestore_cache
でキャッシュした依存関係を読み込んでテスト時間を短縮します。
変更したソースコードと設定ファイルをpushするとJobが実行されます。
Jobの詳細画面を開くと、Jobのテストの実施のログに、ユニットテスト結果が出力されています。
これでリポジトリにpushする度にビルドとテストを実施できます!
デプロイする
ビルド・テストまで説明したので次はデプロイの方法を説明します。
今回はSpringBootのWebアプリケーションをjarにビルドしてデプロイします。
※実際の本番環境でデプロイする場合は、ブルーグリーンデプロイメントなどの手法でデプロイを行いますが、テストのため今回はビルドしたJarをテストサーバーにデプロイしています。
CircleCIにSSH秘密鍵を登録する
CircleCIからデプロイ先に接続する際、SSH接続をする場合があります。
その場合、CircleCIにSSH秘密鍵を登録します。
Projectの設定からSSH Permissionsを選んでAdd SSH Keyをクリックします。
ホスト名と秘密鍵を入力するモーダルが開くので、デプロイ先のホスト名とSSH秘密鍵を入力してAdd SSH Keyをクリックして登録します。
登録が終わると、Fingerprintがセットされます。この値は設定ファイルで利用します。
ビルド・テスト・デプロイを実施する
秘密鍵を追加したので、ビルド・テスト・デプロイを行うJobを定義します。
ビルド・テスト・デプロイを実行するJobの設定です。
.circleci/config.yml
version: 2
jobs:
build:
docker:
- image: circleci/openjdk:8-jdk
working_directory: ~/repo
environment:
BUILD_APP: build/libs/sample_app-*.jar # 成果物
HOST_NAME: host.name # デプロイ先のホスト名
USER_NAME: username # デプロイ先のユーザー名
APP_DIR: /home/sample_app/ #デプロイ先のディレクトリ
APP_NAME: sample-appd
steps:
- checkout
# 依存関係をダウンロードしてキャシュする
- restore_cache:
keys:
- v1-dependencies-{{ .Branch }}-{{ checksum "build.gradle" }}
- v1-dependencies-{{ .Branch }}-
- v1-dependencies-
- run: gradle dependencies
- run: gradle build -x test
- save_cache:
paths:
- ~/.gradle
key: v1-dependencies-{{ .Branch }}-{{ checksum "build.gradle" }}
- run:
name: テストの実施
command: gradle test
# 設定した秘密鍵のFingerPrintを追記する
- add_ssh_keys:
fingerprints:
- "XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX"
- deploy:
name: deployment
command: |
gradle build #ビルドを実行して成果物を作成する
ssh-keyscan ${HOST_NAME} >> ~/.ssh/known_hosts
sudo apt install -y rsync
ssh ${USER_NAME}@${HOST_NAME} "service ${APP_NAME} stop" # サービスを停止する
rsync -vc ${BUILD_APP} ${USER_NAME}@${HOST_NAME}:${APP_DIR} # 成果物をデプロイする
ssh ${USER_NAME}@${HOST_NAME} "service ${APP_NAME} start" # サービスを起動する
.circleci/config.yml
の説明
Key名 | 説明 |
---|---|
environment |
環境変数を設定します。 |
add_ssh_keys |
設定したSSH秘密鍵の設定を行います。 fingerprints に設定画面で表示されていたfingerprintの値を入力してください |
deploy |
デプロイを実施する時の処理です。 nameにデプロイ名、command にデプロイで実施するコマンドを入力してください。 |
先ほど設定した時に表示されていたfingerprintの値をadd_ssh_keys
のfingerprints
に入力してください。
deploy
のcommand
では、step
のrun
と同じように実行するコマンドを入力します。複数行のコマンドを実行する場合は1行目に|
を指定します。
今回、rsyncで成果物をデプロイするため、デプロイ先からAre you sure you want to continue connecting (yes/no)?と聞かれて止まらないようにssh-keyscan
コマンドを実行しています。
デプロイしたjarファイルをservice
で起動・停止するために以下の設定を行います
build.gradle
// デーモン化が可能なjarをビルドする
bootJar {
launchScript()
}
デプロイ先
# シンボリックリンクでサービスに登録する
$ sudo ln -s /home/sample_app/sample_app-X.X.X-SNAPSHOT.jar /etc/init.d/sample-appd
これでリポジトリにpushする度にビルド・テスト・デプロイが実施されるようになりました!
※今回はテスト環境のため、デプロイを行うとサービスが一瞬停止してしまいます。
WorkflowでJobを細分化
ビルドからデプロイまでの手順ができるようになりましたが、今の設定ではどのブランチでもデプロイしてしまいます。
CircleCIのWorkflow
を利用することで、masterブランチのみデプロイする設定も可能です。
Workflowとは
Workflowは、複数のJobを実行できる機能です。
Jobの実施は並列処理で実行されます。そのため、1つのJobが失敗しても他のJobが止まらずに実行されます。
Worflowの設定で、Jobの実行は直列処理で実行も可能です。
他にJob毎の実行条件を設定することができます。
manageブランチのみデプロイを実行する。
workflow
の機能を使って、ビルド→テスト→デプロイの順番でJobを実行するようにします。
また、masterブランチのみデプロイJobを実行するように定義します。
.circleci/config.yml
version: 2
jobs:
build:
docker:
- image: circleci/openjdk:8-jdk
working_directory: ~/repo
steps:
- checkout
# 依存関係をダウンロードしてキャシュする
- restore_cache:
keys:
- v1-dependencies-{{ .Branch }}-{{ checksum "build.gradle" }}
- v1-dependencies-{{ .Branch }}-
- v1-dependencies-
- run: gradle dependencies
- run: gradle build -x test
- save_cache:
paths:
- ~/.gradle
key: v1-dependencies-{{ .Branch }}-{{ checksum "build.gradle" }}
# 他のjobでも共有する
- persist_to_workspace:
root: ~/repo
paths:
- .
test:
docker:
- image: circleci/openjdk:8-jdk
working_directory: ~/repo
steps:
# 共有したworkspaceをアタッチする
- attach_workspace:
at: ~/repo
- run:
name: テストの実施
command: gradle test
deploy:
docker:
- image: circleci/openjdk:8-jdk
working_directory: ~/repo
environment:
BUILD_APP: build/libs/sample_app-*.jar # 成果物
HOST_NAME: host.name # デプロイ先のホスト名
USER_NAME: username # デプロイ先のユーザー名
APP_DIR: /home/sample_app/ #デプロイ先のディレクトリ
APP_NAME: sample-appd
steps:
# 共有したworkspaceをアタッチする
- attach_workspace:
at: ~/repo
# 設定した秘密鍵のFingerPrintを追記する
- add_ssh_keys:
fingerprints:
- "XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX"
- run : sudo apt install -y rsync
- run : ssh-keyscan ${HOST_NAME} >> ~/.ssh/known_hosts
- run : gradle build #ビルドを実行して成果物を作成する
- deploy:
name: masterをdeploy
command: |
ssh ${USER_NAME}@${HOST_NAME} "service ${APP_NAME} stop" # サービスを停止する
rsync -vc ${BUILD_APP} ${USER_NAME}@${HOST_NAME}:${APP_DIR} # 成果物をデプロイする
ssh ${USER_NAME}@${HOST_NAME} "service ${APP_NAME} start" # サービスを起動する
workflows:
version: 2
build_test_deploy: # workflow名
jobs:
- build
- test:
requires: # buildが成功したら
- build
- deploy:
requires: # buildとtestが成功したら
- build
- test
filters:
branches: # masterブランチのみ実行する
only:
- master
steps説明
Key名 | 説明 |
---|---|
persist_to_workspace |
workspaceを他のjobでも共有するように設定します。root でworkspaceのrootパスを指定します。path で共有するパスを指定します。 |
attach_workspace |
共有してあるworkspaceをアタッチします。 at を指定した階層のファイルが利用できるようになります。 |
workflows説明
Key名 | 説明 |
---|---|
workflows |
実行するJobの順序を設定します。workflows名を設定して、jobs にJobの設定を行います。 |
version |
バージョンはJobと同じく2.0か2.1を指定します。 |
jobs |
実行する各Jobの設定を行います。workflows の前に定義したjobs のJob名を指定します。 |
requires |
指定したJob名が実施して成功したら実施するように設定します。 |
filters |
Jobを実行する条件を指定します。branches で実行するブランチを設定できます。 |
workflows
で対象のJobにfilter: branches
で実行するブランチを指定できます。
- deploy:
requires: # buildとtestが成功したら
- build
- test
filters:
branches: # masterブランチのみ実行する
only:
- master
Workflowを利用することで、1回のpushで複数のJobを実行することができます。
masterブランチにpushすることで、buildJobとtestJobとdepoyJobが実行されています。
WORKFLOWSからmasterブランチの実行結果を見ると、Jobが設定した順番で実行されています。
developブランチでpushすると、buildJobとtestJobが順番に実行されています。
これでmasterブランチにpushした時だけデプロイするようになりました!
おわりに
CircleCIを利用すれば、設定ファイル1つで簡単にビルド・テスト・デプロイができました。
現在は英語しか対応していませんが、日本支社が最近設立されたので日本語対応も近いかもしれません。
CircleCIを利用して簡単に開発の品質と効率を向上しましょう!