Agile育成ブログ
未来を変える喜びを
パソコン

CI/CD


Warning: count(): Parameter must be an array or an object that implements Countable in /home/xs638785/agile-software.site/public_html/wp-content/plugins/rich-table-of-content/functions.php on line 490

CIとは、Continuous Integrationの略で、継続的インテグレーションと呼ばれています。

CI(継続的インテグレーション)では、開発者が自分のコード変更を頻繁にセントラルリポジトリにマージし、その度に自動化されたビルドとテストを実行します。
小さなサイクルでインテグレーションを繰り返し行い、インテグレーションのエラーを素早く修正することによりチームは統合されたソフトウェアをより迅速に開発できるようになります。

CI(継続的インテグレーション)

CIツールを使うと?

CIツール導入以前は、開発者は長期間にわたって独立して作業し、自分の作業が完了したあと初めて、変更点をマスターブランチにマージしていました。このような開発プロセスでは、累積したコード変更をマージする作業は困難で時間のかかるものでした。また、バグが発生した場合も複数の変更が混在するため、影響範囲も広く特定と修正にかかるコストが大きくなってしまいます。

リードタイムを短縮するために、CIツールがあります。CIツールを導入し、ビルドパイプラインは最初は小さな単位でビルドと検証を行いながら、フェーズが進みにつれて大きな単位での検証が行われるように設計します。

CI(継続的インテグレーション)

そうすることで、エラーフィードバックが早くなり、影響範囲の小さなうちに修正されるようなプロセスとなります。

CIツールの1つが「Jenkins」

Jenkinsは、元々CI(継続的インテグレーション)のためのツールとして広く普及しました。テストやビルドを最後にまとめて行うのではなく、コミットされたらその度ビルドとテストを行うようにJenkinsでジョブを作成し、即座にビルドが成功した最新バージョンの特定や、影響範囲の小さいうちにエラーの修正をすることを容易にしました。


CI(継続的インテグレーション)のメリット

開発者の生産性を向上

CI(継続的インテグレーション)は、エラーを小さな単位で影響範囲を小さく修正するようになるため、修正コストを削減します。これまでプロジェクトの最終段階で見つかっていたエラーが早く小さなコストで修正されるようになるため、開発チームの生産性が向上し、品質の良いソフトウェアの開発に繋がります。

バグを短時間で発見して対処

テストの頻度が上がるため、開発チームでは、バグが後になって大きな問題に発展する前に発見して対処できます。

更新を迅速に配信

CI(継続的インテグレーション)は、常にビルドが通るリポジトリを維持し、リリースできる最新バージョンの特定を常に行うことができます。そのため、お客様に迅速かつ頻繁に更新を配信することが可能となります。

CD(継続的デリバリー)とは?


CDとは、Continuous Deliveryの略で、継続的デリバリーと呼ばれています。

継続的デリバリー(CD)は、継続的インテグレーション(CI)を拡張した手法で、ビルドやテストだけでなく、リリースプロセス全体を自動化します。実施の目的はDevOpsと同様で、リリーススピードを上げることで、素早く市場からフィードバックを得られ、ソフトウェアに反映させることができます。ビジネス戦略を細かく修正しながら進めることで、リスクの低減とソフトウェアの競争力向上を目的とします。

継続的デリバリー(CD)では、すべてのコード変更は、ビルドとテストを実行した後、テスト環境またはステージング環境にデプロイして、システムテストやUIテストを行います。開発者は、準備ができた時点で、最後のステップとして運用環境への更新を承認します。

この点は、運用環境へのデプロイが明示的な承認なしで自動的に行われる「継続的デプロイ」とは異なります。

CD(継続的デリバリー)

継続的デリバリー(CD)が行えるようになった背景には、クラウドやコンテナといった技術の普及や、インフラ環境をコードで管理できるようになった点があります。そのため、コミットからリリースまで全ての作業が自動で行うことができます。

CD実現のためのツールが「Jenkins」

継続的デリバリー(CD)を行う際は、継続的インテグレーション(CI)よりも複雑なビルドプロセスを頻繁に行うことになります。そのため、ツールによる自動化は必須で、そのプラットフォームとして多く利用されているのがJenkinsです。

Jenkinsは、継続的デリバリー(CD)のための機能やプラグインも多く準備されています。

気をつける必要があるのは、Jenkinsで全てのビルドプロセスの自動化を行うものではないということです。テストやデプロイなどの各フェーズはそれぞれ専用のツールで自動化を行い、Jenkinsはどういったタイミングでどのツールを呼び出すかを指示し、エラーが出たら即座にフィードバックするという処理を行うようにします。

Jenkinsの利用

継続的デリバリー(CD)のメリット

ソフトウェアのリリースプロセスの自動化

継続的デリバリー(CD)では、開発チームによるコード変更のビルド、テスト、運用環境へのリリースに向けた準備が自動化されるので、ソフトウェアの配信の効率が上がり、迅速に実施できます。

開発者の生産性を向上

こうした手法は、開発者を手動作業から解放することによって開発チームの生産性を向上し、お客様にデプロイする前にエラーやバグを減らす努力を奨励するために役立ちます。

バグを短時間で発見して対処できる

テストの頻度を上げ、その内容を充実させることにより、後になって大きな問題に発展する前に、バグを早期に発見して対処できます。また、継続的デリバリー(CD)によってプロセス全体が自動化されるので、自分のコードに付加的な種類のテストを簡単に実行できるようになります。

更新を迅速に配信

継続的デリバリー(CD)は、開発チームがお客様に迅速かつ頻繁に更新を配信するために役立ちます。継続的デリバリー(CD)を適切に実装すると、開発者は、標準化されたテストプロセスに合格し、デプロイ準備の整ったビルド成果物を常に手元に持つことになります。 

今度入社する会社では、JenkinsでなくCircleCIを使っているということなので、1から勉強した内容を初心者向けにまとめました。
また、最新バージョン2.1(2018/12時点)の新機能も本記事では触れています。

スクリーンショット 2018-12-20 17.04.20.png

※2019/8/8追記
Slack連携に関する記事も書きました。
SlackでCircleCIからカバレッジレポート通知を受け取る設定手順

※2020/4/2追記
https://twitter.com/CircleCIJapan/status/1245253320551399424
CircleCIさんより、本記事を紹介いただきました!
なお、本記事は初回投稿時(2018/12)の情報がメインのため、ご留意いただきますようお願いします。

前提知識

  • CI/CDに関する入門レベルの知識
  • ymlファイルに関する入門レベルの知識
  • コンテナに関する入門レベルの知識
    • 未学習の方は私の記事ですが、こちらを参考にしてください。

概要

CircleCIとは

一言でいえば、Saas型のCI/CDサービスです。Saas型であるという点が特徴です。
CircleCIはクラウド上のコンテナあるいはVMを実行環境として使用します。
コンテナかVMかはユーザーが選択可能ですが、コンテナの方が起動が速く、VMは今後有料になる可能性があります。CircleCIではコンテナの利用を推奨しているようです。
この記事では主にコンテナ寄りで説明することにします。

CircleCIでできること

CircleCIに限らないですが、一般的にCI/CDでやることはビルドとテストとデプロイの3点です。

ビルド

ソースコードから実行可能なアプリケーションを構築します。
具体的には、Dockerイメージのpull、依存パッケージのインストール、コンパイルなどです。

テスト

UTなどのテストコードを実行して動作確認をしたり、Rubocop(Ruby)などのコードスタイルチェックなどを行います。

デプロイ

ビルドしてテストが通ったものを本番環境や検証環境などにリリースします。

Jenkinsと比較して

多くのCIツールが世の中に存在しますが、最も有名なJenkinsと比べてCircleCIは以下の特徴があります。

CircleCIが優れている点

  • 環境構築コストが低い
    • Saasだから
    • Web-UIで初期設定を少しやるだけ
    • 冗長化とかも勝手にされている
    • Jenkinsの場合、自前でJenkins用のサーバを立てる必要がある
  • 運用コストが低い
    • Saasだから
    • サーバーメンテナンスや故障時の対応をやる必要がない
  • ymlファイルで設定できる
    • Jenkinsの場合、Web-UIで細かい設定までできるが、職人芸になりがち

CircleCIが劣っている点(気をつけるべき点)

  • バージョン管理でSVNを使っているプロジェクトでは使えない
    • GitHub/Bitbucket連携が前提
  • リアルタイムにビルド実行ができない
    • 定期実行はできる
  • CircleCIで故障が発生しても自分たちで原因解析や復旧をすることが困難
    • Saasだから
  • Saasの利用料には要注意

必要なもの

CircleCIを利用するにあたって必要なものはGitHubあるいはBitbucketのアカウントのみです。

料金

※2020年4月2日追記
最新の料金情報はこちらのようです。
https://circleci.com/ja/pricing/

無料枠(2018/12現在)

個人開発や試し使いには充分そう。

  • 1コンテナのみ
    • したがって、同時実行ジョブは1つのみ
  • 1ヶ月あたり1000分のビルド時間まで
    • 最近、1500分から減ってしまったらしい
  • リポジトリ数の制限なし
  • ユーザー数の制限なし

有料枠

  • コンテナ1つ増やす毎に50ドル。
  • 2コンテナ以上利用する場合は、ビルド時間の制限はなくなるようです。
  • 詳細は公式サイト

導入実績企業

海外企業、国内企業含め数千の企業で導入がされているようです。
有名どころでいうとこんなところ。

  • Facebook
  • Spotify
  • CyberAgent
  • ZOZOテクノロジーズ
  • DeNAなど

CI/CDの契機

CIとCDがそれぞれ走る契機をまとめました。

  • CI
    • pull-request作成した時
    • pull-request作成以降にpushした時
    • 定期実行時(cron)
  • CD
    • mergeした時
      • ブランチによってデプロイ先を変えられる
        • masterブランチへmergeされたら本番環境、developブランチへmergeされたら検証環境など
    • 定期実行時(cron)

config.yml

CI/CDの設定は全て .circleci/config.yml に記載します。(1.0系ではcircle.ymlという名前であった。)
間違えて、 config.yaml と書いてCircleCIでエラーになるケースはあるある(?)
なので、気をつけてください。
.circleci ディレクトリは対象Gitリポジトリのトップに置きます。

キー

config.ymlでよく使用するキーに絞って説明します。
その他のキーは公式リファレンスを参考にしてください。

必須キー

必ず設定必要なキー。

  • version: CircleCIのバージョンを指定する。現状、1か2か2.1を指定可能だが、これからCircleCI始める場合は2か2.1にする。
  • jobs: 1つ以上のjobを設定する。jobが1つだけの場合、job名は build でなければならない。各jobではCI環境設定などを行う。
    • <job_name>: 任意のjob名を設定する。
      • steps: CI環境上で動作させるコマンドや実行結果の保存、キャッシュ操作などを設定する。詳細は後述。

sample

version: 2.1
jobs:
  build:
    steps:
      (省略)

オプションキー

必須キーの子あるいは孫などとして設定可能なキー。
必要に応じてそれぞれを設定する。

イメージ系

CI環境で利用するDockerコンテナあるいはVMのイメージを指定する。
CircleCIではDockerの利用が推奨されている。
DockerHub上では既に各種言語やミドルウェアなどのインストールや設定が完了しているイメージが多く存在しているため、これらをベースにすることでビルド部分の構築稼働を削減できる。
docker / machine / macos のいずれかをconfig.ymlに記載する必要がある。

  • docker: CI環境にDockerを利用する場合の設定。
    • image: ベースとなるDockerイメージを指定する。複数指定することも可能。
    • auth: DockerHubのプライベートイメージを使用する場合の認証情報を指定する。
      • username: ユーザ名
      • password: パスワード
    • aws_auth: ECR(Amazon Elastic Container Registry)のプライベートイメージを使用する場合の認証情報を指定する。
      • aws_access_key_id: アクセスキーのID
      • aws_secret_access_key: アクセスキー

複数imageのsample

jobs:
  build:
    docker:
      - image: circleci/golang:1.8
      - image: circleci/postgres:9.4

authのsample

jobs:
  build:
    docker:
      - image: acme-private/private-image:321
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD

aws_authのsample

jobs:
  build:
    docker:
      - image: account-id.dkr.ecr.us-east-1.amazonaws.com/org/repo:0.1
        aws_auth:
          aws_access_key_id: AKIAQWERVA
          aws_secret_access_key: $ECR_AWS_SECRET_ACCESS_KEY
  • machine: CI環境にVMを採用する場合の設定。 true を指定した場合、最新バージョンのVMイメージを利用する。
    • image: VMイメージの指定

sample

jobs:
  build:
    machine: true
  • macos: CI環境にVM(MacOS)を採用する場合の設定。
    • xcode: xcodeのバージョン指定

sample

jobs:
  build:
    macos:
      xcode: "9.2.0"
  • parallelism: jobを並列実行するコンテナ(VM)数を指定する。デフォルトは1。

sample

jobs:
  test:
    docker:
      - image: circleci/golang:1.8
    parallelism: 4

実行環境系

  • working_directory: 実行ディレクトリを設定する。デフォルトは ~/project

sample

jobs:
  build:
    working_directory: ~/work
  • checkout: CI環境上の working_directory の値の場所にGitリポジトリをコピーする。

sample

steps:
  - checkout
  • shell: 実行シェルを指定する。executors (後述)で指定しても jobs に直接指定してもよい。デフォルトは /bin/sh -eo pipefail

sample

executors:
  sample-executor:
    shell: /bin/bash

sample

jobs:
  build:
    shell: /bin/bash

コマンド操作系

  • run: コマンドを実行する
    • name: 任意のrunの名前
    • command: コマンドを設定する

sample

steps:
  - run:
    name: Test
    command: npm test

条件判定系

  • when: 真ならば実行する
    • condition: 条件判定
    • steps: (説明省略)
  • unless: 偽ならば実行する
    • condition: (説明省略)
    • steps: (説明省略)

sample

steps:
  - when:
    condition: <<parameters.custom_checkout>>
    steps:
      - run: echo \"my custom checkout\"
  - unless:
    condition: <<parameters.custom_checkout>>
    steps:
      - checkout

ファイル操作系

  • restore_cache: キャッシュが save_cache されていればリストアする(あれば速くなる)
    • key: リストアするキャッシュを指定する
    • keys: リストアするキャッシュを複数指定する
  • save_cache: パッケージなどのファイルをキャッシュする
    • key: キャッシュの名前を設定する
    • paths: キャッシュするファイルを指定する

key/keysに使用できるテンプレートは以下。

  • {{ .Branch }}: 対象のGitのブランチ名
  • {{ .Revision }}: 対象のGitのコミットのリビジョン
  • {{ .Environment.<環境変数> }}: 環境変数
  • {{ checksum “<ファイル名>” }}: ファイルのハッシュ値
  • {{ arch }}: OSとCPU情報

sample

steps:
  - checkout
  - run:
    name: Update npm
    command: 'sudo npm install -g npm@latest'
  - restore_cache:
    key: dependency-cache-{{ checksum "package.json" }}
  - run:
    name: Install npm wee
    command: npm install
  - save_cache:
    key: dependency-cache-{{ checksum "package.json" }}
    paths:
      - node_modules
  • store_artifacts: ログやカバレッジ、jarファイルなどのバイナリをS3にアップロードして保管する(3GBまで)。アップロードされたファイルはCircleCIのWeb-UI上で確認できる。
    • path: アップロードするファイル/ディレクトリのパスを指定する

sample

steps:
  - run:
    name: Creating Dummy Artifacts
      command: |
        echo "This is a sample artifact" > /tmp/artifacts;
  - store_artifacts:
      path: /tmp/artifacts
  • persist_to_workspace: 一時的にファイルをjob間で共有できるようにする(最大30日間)
    • root: 共有する場所の指定をルートディレクトリ配下のパスで行う
    • paths: 共有対象ファイルのパスをrootで指定したパスからの相対パスで指定する
  • attach_workspacepersist_to_workspace で共有されたファイルを取得する
    • atpersist_to_workspace で指定した root の値を指定する

persist_to_workspaceのsample

steps:
  - persist_to_workspace:
    root: /tmp/dir
    paths:
      - foo/bar
      - baz

attach_workspaceのsample

steps:
  - attach_workspace:
    at: /tmp/dir

DRY(Don’t Repeat Yourself)系

ver2.1から導入されたymlファイルをDRYに書くための機能。

  • commands: jobsで再利用可能なcommandを定義する。関数のように扱える。
    • <command_name>: 任意のcommand名を指定する。
      • description: 定義するcommandの説明を記載する。
      • parameters: commandに与えるパラメータを定義する。
        • <parameter_name>: 任意のparameter名を指定する。
          • type: 型を定める。string/boolean/enumから選択する。
          • default: パラメータのデフォルト値を設定する。
      • steps: (説明省略)
        • run: (説明省略)

sample

commands:
  sayhello:
    description: "A very simple command for demonstration purposes"
    parameters:
      to:
        type: string
        default: "Hello World"
    steps:
      - run: echo << parameters.to >>

jobs:
  myjob:
    docker:
      - image: "circleci/node:9.6.1"
    steps:
      - sayhello:
          to: "James"
  • executors: jobsで再利用可能な実行環境を定義する
    • <executor_name>: 任意のexecutor名を指定する
      • docker: dockerを使用する場合に指定する
        • (説明省略)
      • machine: VMを使用する場合に指定する
        • (説明省略)
      • macos: VM(macos)を使用する場合に指定する
        • (説明省略)
      • shell: (説明省略)
      • working_directory: (説明省略)
      • environment: (説明省略)

sample

executors:
  my-executor:
    docker:
      - image: circleci/ruby:2.5.1-node-browsers

jobs:
  my-job:
    executor: my-executor
    steps:
      - run: echo outside the executor

workflows系

ver2.0以降に導入されたビルドパイプライン機能。

ビルドパイプラインの種類
  • パラレル
    • デフォルト設定。jobがパラレルに実行される。
  • シーケンシャル
    • 1つ前のjobの完了を待って次の1つのjobを実行する。 requires を利用して実現する。
  • ファンアウト
    • 1つ前のjobの完了を待って複数のjobを実行する。 requires を利用して実現する。
  • ファンイン
    • 複数のjobの完了を待って1つのjobを実行する。 requires を利用して実現する。
  • スケジューリング
    • 定期実行する(cron)。 triggers を利用して実現する。
各workflowのステータス一覧
  • RUNNING: 進行中
  • NOT RUN: 開始されなかった
  • CANCELLED: 進行途中でキャンセルされた
  • FAILING: 進行途中でworkflow内のあるjobが失敗している
  • FAILED: workflow内の1つ以上のjobが失敗した
  • SUCCESS: workflow内の全てのjobが成功した
  • ON HOLD: workflow内のあるjobが承認待ち
  • NEEDS SETUP: config.ymlに文法的な誤りがある
基本的な書き方
  • workflows: 1つ以上のワークフローを設定する
    • version: (説明省略)
    • <work_flow_name>: 任意のワークフロー名
      • jobs: workflowで管理する対象jobの設定をする
      • <job_name>: 対象jobのjob名を指定する

sample

workflows:
  version: 2
  sample_workflow:
    jobs:
      - build
シーケンシャル
  • requires: 完了前提のjobを指定することでシーケンシャルにする。指定しない場合、jobはパラレルで動作する。
    • <job_name>: 完了前提のjob名を指定する

sample

jobs:
  - build
  - test1:
    requires: 
      - build

上記のsampleでは、test1はbuildが完了するまで実行されない。(これがシーケンシャル)

ファンアウト/ファンイン

例えば、ビルドjobが1つ、テストjobが複数、デプロイjobが1つなどの一般的によくあるパターンで、ファンアウト/ファンインを利用すると効率的にCI/CDを回せる。

スクリーンショット 2018-12-28 18.11.08.png

sample

jobs:
  - build
  - acceptance_test_1:
    requires:
      - build
  - acceptance_test_2:
    requires:
      - build
  - acceptance_test_3:
    requires:
      - build
  - acceptance_test_4:
    requires:
      - build
  - deploy:
    requires:
      - acceptance_test_1
      - acceptance_test_2
      - acceptance_test_3
      - acceptance_test_4

上記のsampleでは、build⇨acceptance_test_1~4⇨deployでファンアウト/ファンインしている。

スケジューリング
  • triggers: スケジュール指定で実行トリガーを設定する。デフォルトではbranchへpushされたタイミング。
    • schedule: UTC時刻でスケジュール設定する
      • cron: cron設定

sample

triggers:
  - schedule:
    cron: "0 0 * * *"
ブランチ指定/タグ指定
  • filters: ブランチ名かタグ名で実行条件をつける
    • branches: ブランチ名でフィルタリングする
      • only: 許可するブランチ名を指定する
        • <branch_name>: 任意のブランチ名を指定する
      • ignore: 許可しないブランチ名を指定する
        • <branch_name>: (説明省略)
    • tags: タグ名でフィルタリングする
      • only: (説明省略)
      • ignore: (説明省略)

sample

filters:
  branches:
    only:
      - master
      - develop

sample

filters:
  tags:
    ignore:
      - 1.0
      - 2.0

ON HOLD(一時停止)にする

  • typeapproval を指定することで次のjobを続けて実行せずに一時停止する。続行するためにはWeb-UI上でApproveボタンを押下する必要がある。

sample

jobs:
  - request-testing
    type: approval
  - build
    requires: 
      - request-testing  
  - build-mab-:
    requires: 
      - request-testing
  - build-mab-aws:
    requires:
      - request-testing
  - test-aws:
    requires:
      - build
      - build-mab-
      - build-mab-aws
  - test:
    requires:
      - build
      - build-mab-
      - build-mab-aws

type:approve のjobが完了すると、statusがON HOLDで一時停止する。

スクリーンショット 2018-12-28 17.37.18.png

対象jobを押下すると、以下の画面がでてくるため、Approveボタンを押下するとworkflowが続行される。

スクリーンショット 2018-12-28 17.38.26.png

DRYに書く

  • pre-steps: 指定したjobの実行前に必ず実行するstepを指定する。ver2.1以降で利用可能。
    • run: (説明省略)
    • command: (説明省略)
  • post-steps: 指定したjobの実行後に必ず実行するstepを指定するver2.1以降で利用可能。
    • run: (説明省略)
    • command: (説明省略)

sample

version: 2.1
jobs:
  bar:
    machine: true
    steps:
      - checkout
      - run:
        command: echo "building"
      - run:
        command: echo "testing"
workflows:
  build:
    jobs:
      - bar:
        pre-steps:
          - run:
            command: echo "install custom dependency"
        post-steps:
          - run:
            command: echo "upload artifact to s3"

環境変数

環境変数を利用することで、環境に依存する情報や秘匿情報をソースコードから分離しデプロイを簡単かつ安全に行うことができる。
例えば、環境名やIPアドレス情報、鍵情報などを環境変数として設定する。
環境変数にはCircleCI側で元から用意されているビルドイン環境変数と自分で任意に設定する環境変数の2種類がある。

ビルドイン環境変数

ビルドイン環境変数で主要なものは以下です。
これらの具体的な値はCircleCIのWeb-UI上の実行結果などから確認できます。

  • CI: CI環境であるかどうか
  • CIRCLE_BRANCH: Gitのブランチ名
  • CIRCLE_BUILD_NUM: プロジェクト内のビルド番号
  • CIRCLE_PROJECT_REPONAME: Gitのリポジトリ名
  • CIRCLE_SHA1: Gitの最終コミットのハッシュ値
  • CIRCLE_NODE_TOTAL: インスタンスの数
  • CIRCLE_NODE_INDEX: インスタンスの番号(0から始まる)

自分で設定する環境変数

設定方法は config.yml で設定する方法とWeb-UIで設定する方法の2通りがある。

config.ymlで設定する場合

environment で環境変数の設定をする。
jobs配下でもsteps配下でもdocker配下でも色々なところで宣言可能。

jobs:
  build:
    environment:
      FOO: bar

Web-UIで設定する場合

プロジェクト設定のBUILD SETTINGS > Environment Variables > Add Variable から設定する。
秘匿情報の場合は、config.ymlではGitで公開されてしまうためWeb-UIで設定する。

動かしてみる

ローカルで動かしてみる

CircleCIはローカル環境でも実行可能。
config.yml の文法チェック、jobの動作確認などをわざわざリモートリポジトリにpushしなくてもローカルで手軽に確認できる。
ここでの動作環境はMacOSを前提とします。

(Step1) Dockerインストール

動作環境用にDockerを公式サイトにしたがってインストールしてください。

(Step2) CircleCIインストール

$ curl https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh --fail --show-error |bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1309  100  1309    0     0   1225      0  0:00:01  0:00:01 --:--:--  1225
Installing CircleCI CLI
Finding latest release.
Downloading CircleCI v0.1.4427
Installing to /usr/local/bin
/usr/local/bin/circleci

$ circleci update check
Already up-to-date.

(Step3) config.yml作成

今回は動作確認用に、golangのDockerイメージを使って、単にechoするだけの簡単なconfig.ymlの例です。

$ mkdir .circleci

$ vi .circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.11.2
    steps:
      - run: echo "hello world"

(Step4) CircleCI動作確認

まずは文法チェック。問題ないことを確認。

$ circleci config validate
Config file at .circleci/config.yml is valid.

蛇足ですが、動作中のコンテナは存在せず、Dockerイメージも無い状態であることを確認。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

ローカルでcircleci実行。

$ circleci local execute
(省略)
Using build environment variables:
  BASH_ENV=/tmp/.bash_env-localbuild-1544496655
  CI=true
  CIRCLECI=true
  CIRCLE_BRANCH=
  CIRCLE_BUILD_NUM=
  CIRCLE_JOB=build
  CIRCLE_NODE_INDEX=0
  CIRCLE_NODE_TOTAL=1
  CIRCLE_REPOSITORY_URL=
  CIRCLE_SHA1=
  CIRCLE_SHELL_ENV=/tmp/.bash_env-localbuild-1544496655
  CIRCLE_WORKING_DIRECTORY=~/project

====>> echo "hello world"
  #!/bin/bash -eo pipefail
echo "hello world"
hello world
Success!

見事、成功!
蛇足ですが、circleci実行中にコンテナが起動し、実行完了後は消えたことを確認できた。CI実行中

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
fe36f90355b9        circleci/picard     "circleci build"    About a minute ago   Up About a minute                       stoic_noyce

CI実行完了後

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

蛇足ですが、Dockerイメージが増えていることが確認できた。

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
circleci/golang     1.11.2              30d34aa355de        3 hours ago         1.13GB
circleci/picard     <none>              b1f2c41821a8        3 days ago          83.8MB

GitHubとCircleCIを連携して動かす

基本的にこちらの記事に沿って説明していきます。
golangで簡単な関数とUTを実装し、CI/CDする簡単な例です。

(Step1)設定

[必須]初期設定

GitとCircleCIの連携に関する初期設定は多くの記事で紹介されているので省略します。
基本的には、Authorizeして、Gitのリポジトリごとに対応するCircleCIのプロジェクトを作成するだけです。

[任意]CIに成功しないとマージができないようにしたい(GitHub側の設定)

こちらは、CircleCIというよりGitHub上で行う設定ですが、よく利用すると思いますので掲載しておきます。

  • Braches > Branch protection rule へ移動
  • Apply rule to にブランチ名を入力
  • Require status checks to pass before merging と Require branches to be up to date before merging にチェックをつける
スクリーンショット 2018-12-13 17.13.28.png

[任意]Slack連携

設定方法はこちらの記事に譲ります。
上記の設定により、ビルド結果の通知は自動で行われます。
ただし、デプロイ結果の通知は別途、下記のようにconfig.ymlのjobsに定義が必要です。(workflowのrequiresも要)

jobs:
  deploy_notify:
    executor: default
      steps:
        - run:
          name: デプロイ通知
          command: |
            curl -X POST -H 'Content-type: application/json' --data \
            "{'text': 'DEPLOY DONE! ${CIRCLE_PROJECT_REPONAME}'" \
            ${SLACK_WEBHOOK_URL} 

(Step2)対象コードを書く

単純にGolangで文字列を返すだけの関数です。sample01.go

package sample01

func HelloWorld(s string) string {
  return "hello world, " + s
}

上記の関数が期待通りのレスポンスをするかを確認するUTです。sample01_test.go

package sample01

import (
  "testing"
)

func TestHelloWorld(t *testing.T) {
  actual := HelloWorld("hoge")
  expected := "hello world, hoge"
  if actual != expected {
    t.Errorf("actual %v\nwant %v", actual, expected)
  }
}

(Step3)config.ymlを書く

基本的に、公式サイドのサンプルそのままですが、 working_directory の値は適切なものに編集します。

version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.8
    working_directory: /go/src/github.com/gold-kou/go-test-circleci-sample
    steps:
      - checkout
      - run: go get -v -t -d ./...
      - run: go test -v ./...

(Step4)pull-request作成してCIを走らせる

pull-requestを作成すると、自動でUTが実行されます。
UTが正常に完了していれば、下記の通り All checks have passed となり、マージ可能となる。
これは、GitHubとCircleCIが連携し、pull-requestされるとCircleCIが config.yml を自動で読み込むから。CIって素晴らしい!!!
pull-request作成後は、push契機でCI/CDが走る。

スクリーンショット 2018-12-27 16.41.45.png

その他Tips

CIをスキップしたい

ソースコードに関係のない変更(例えばREADME.mdの編集)をpushした時など、pushしたけどCIを実行したくない場合がある。
2通りの方法がある。

Gitのコミットメッセージで指定する方法

Gitのコミットメッセージに[ci skip]あるいは[skip ci]を埋め込む。

$ git commit -m "<コミットメッセージ> [ci skip]"

Web-UIで指定する方法

プロジェクトの設定(歯車) > BUILD SETTINGS > Advanced Settings > Auto-cancel rudundant buildsをON

スクリーンショット 2018-12-13 14.47.30.png

CI再実行したい

該当Jobで Rerun workflow を押下する。

スクリーンショット 2018-12-13 14.40.06.png

CI実行したコンテナにSSHしたい

デバッグなどを目的にコンテナに入りたい場合もある。
Web-UIで該当jobで以下の操作方法で10分間SSHが可能になる。
Rerun workflow > Rerun job with SSH

スクリーンショット 2018-12-13 14.57.45.png

画面が切り替わり、ポート番号とIPアドレスが併記されたSSHコマンドが案内されるため、鍵が適切に設定されていればSSHできる。

まとめと感想

  • CircleCIはSaas型のため始めるハードルが低い
  • 個人開発では無料枠で充分そう
  • config.yml の文法を覚える学習ハードルがある。とはいえJenkinsの職人芸よりはマシそう。
  • ver2.0で大きく変わった模様。2.1でも新機能がいくつか追加され、まだまだ成長途中である印象を受けた。特に、 config.yml の記載方法は今後も大きく変わる予感を感じた。例えば、よりDRYに書くための機能やenvファイルの切り出し、ファイル分割などは今後追加されていくのではないだろうか。

You cannot copy content of this page