Circleciと学ぶContinuous Integration

circleciのロゴ
circleciのロゴ
日本語だと継続的インテグレーションとも言われるContinuous Integrationについて。

Continuous Integrationとは

Continuous Integration(継続的インテグレーション)とは、従来のデベロッパがそれぞれ独立で開発を行い開発サイクルの最後にインテグレーションを行う方法ではなく、日に何度もそれぞれのデベロッパがmasterブランチにインテグレーションするやり方。

何をするの?

デベロッパは書いたコードを一日のうちに何度でもシェアでき、コミットのたびに自動でビルドとテストが実行され、ビルドあるいはテストが失敗した場合は、それをすぐに修正する。

どうしてするの?

開発チームをより生産的に、より効率的に、よりハッピーになるため。問題を見つけてそれらを素早く解決する。高品質かつより安定したプロダクトをリリースするため。

CircleciのOverviewより引用でした。 Overview - CircleCI

プライベートプロジェクトで使ってみた

普段からちょくちょくいじってはアップデートしている自分のウェブサイトを題材にCircleciを使ってみる。プロジェクトで使用している技術はフロントがVue.jsでサーバにExpressを使っている。

.ymlファイルを追加

はじめに、プロジェクトのルートに.circleciフォルダを作成し、そのフォルダにconfig.ymlというファイルを追加する。

.circleci/config.yml

次に、.ymlファイルにCircleciのための設定を記述する。この設定は、CircleciでGithubと連携し、利用するレポジトリを選択したあと、使用する言語を選択すると自動でサンプルが作られるのでそれを利用する。僕の環境だと以下の.ymlファイルが提供された。

# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/node:7.10

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/mongo:3.4.4

    working_directory: ~/repo

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}
          # fallback to using the latest cache if no exact match is found
          - v1-dependencies-

      - run: yarn install

      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

      # run tests!
      - run: yarn test

というわけで、とりあえずpushしちゃえ!と思ってpushした。

初コミットで学んだこと

f:id:kai1233:20180827111231p:plain

まずひとつ目はなぜか僕はCicleCI 1.0を使っていたようで警告がでていた。(公式の設定どおりにしたんだけど。。。) バージョン1.0のサポートは2018年8月31日までとのこと。それってつまり4日後。すばらしい100時間後にはゴミになる知識を一部吸収していたようだ。CircleCI 2.0に移行しよう。

f:id:kai1233:20180827113002p:plain
CircleCI 1.0の余命が公式サイトでカウントダウンされていた

CircleCIがしてくれること(の一部)

僕の人生初CircleCI体験で、確認できた工程は以下の通り。(失敗で終わってます)

インフラストラクチャ

  • ビルドのjobをスタート
  • コンテナを起動させる
  • SSHを有効化する

チェックアウト

  • ソースキャッシュの復元
  • デプロイキーの確認

マシーン

  • ビルドされたものの設定
  • キャッシュの復元

依存関係

  • NODE_ENVをexportする
  • PATHを通す
  • npm installする

データベース

  • キャッシュを保存

ティアダウン(取り壊し)

以上。

失敗してました💧

気軽にコミットしただけでconfig.ymlだってちゃんといじってないから、まぁそうよね。今回は「テストが見つからないよ〜〜><」って言われて作業が終了していました。(そういえばこのプロジェクト規模が小さすぎてテスト書いてない!)

正常終了するために

config.ymlにすべての答えがあるはずだ。でも、そもそもCircleCI 2.0じゃないよと怒られているので、上に貼ったconfig.ymlは忘れて、警告に載ってたリンク先にあったconfig.ymlを見てみよう。

version: 2
jobs:
  build:
    docker:
      - image: circleci/<language>:<version TAG>
    steps:
      - checkout
      - run: <command>
  test:
    docker:
      - image: circleci/<language>:<version TAG>
    steps:
      - checkout
      - run: <command>
workflows:
  version: 2
  build_and_test:
    jobs:
      - build
      - test

内容はなんの難しいこともない。(たぶん)version指定から始まり、実行したい処理をjobsのインデント下に書いていく。見て分かる通り、buildtestがある。

そのあとworkflowsに処理を行う流れを書いていくと。CircleCIはこの順番で処理を行うみたいだね。なるほど。つまり、今回の僕のばあい、本当はよくないけどテストが無いから💧テストの処理をここに書かなければ正常終了までたどり着けるはず。

テストを含まないContinuous Integrationって論外だけど、まぁまずはBuildだけうまくいってからテスト追加してもいいんじゃないかな!!

数時間後……

たどり着いた正常終了

なんとかちゃんと動くconfig.ymlが完成しました。$HEROKU_API_KEY$HEROKU_APP_NAMEはCircleCIのサイトから環境変数に追加できます。Herokuにデプロイするばあいは、チェックして設定しましょう。

最終的なconfig.yml

version: 2
jobs:
  build:
    docker:
      - image: circleci/node:10

    working_directory: ~/repo

    steps:
      - checkout
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}
      - run: npm install
      - run: npm run build
      - persist_to_workspace:
          root: .
          paths: dist
      - save_cache:
          paths:
            - node_modules
            - dist
          key: v1-dependencies-{{ checksum "package.json" }}
  deploy:
    docker:
      - image: circleci/node:10

    working_directory: ~/repo
    steps:
      - checkout
      - attach_workspace:
          at: ~/repo
      - restore_cache:
          key: v1-dependencies-{{ checksum "package.json" }}
      - run: git config user.name "ユーザ名"
      - run: git config user.email "メールアドレス"
      - run: git add .
      - run: git commit -m "from CircleCI"
      - run:
          name: Deploy Master to Heroku
          command: |
            git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP_NAME.git master
workflows:
  version: 2
  build-deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: master

jobsbuilddeployを設定してworkflowでビルド後にデプロイするように設定。

大事な箇所はキャッシュ周りの記述。

     - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}

ビルドする前に、前回のビルドしたときのキャッシュを復元している。このキャッシュを管理する際に、keysを用いる。package.jsonのchecksumを使って一意なkeyにしている。その後、依存関係を解消して、キャッシュを保存してビルドが行われる。

最後に

キャッシュ周りの設定は本来、ビルドファイルと依存関係を分けたほうがいいと思う。まだ雑な部分が多い。またdeploy部分については、gitの箇所は多分調べればもっと良いやりかたがあるはず。

まぁ、何はともあれ、これでひとまずpushするだけで自動でbuildされてHerokuにpushされる環境が出来上がったのでよしとする。引き続き、CircleCIについて学んでいこうと決心した。