まだ間に合う！CircleCI 2.0へ移行する

Qiita初投稿です！
自分のブログにあげていた記事ですが、参考になればと思い転載します。

# はじめに
[CicleCI 1.0が終了する](https://circleci.com/sunset1-0/)まで１週間をきりましたね！
こんな時期まで移行をしていないのは、夏休みの宿題は後回しにするタイプの方と思われます。
私もつい先日に宿題を終わらせた人間なので、同志のために簡単な説明と参考になるサイトのまとめを。。

# 1.0と2.0の違い
大きなところだけ！（細かいことは知らない）

## Dockerベースになった
**Dockerベースで実行環境を作るようになった**というのが１番大きいかと思います。 
この時点で「Dockerをよく知らない」かつ「1.0で複雑な設定をしている」あなたは、悠長にしている余裕はありません。速攻とりかかってください。
日頃からDockerを使っているあなた。よかったですね。でもやりましょう。

## Workflowができた
これまでは「deployment」とか「test」とか、CircleCIが準備している箱に設定を書いていきましたが、これからは「Job」という概念を自分で定義し、「Workflow」という概念で管理していく形になります。  
実行順序も自由に決められるようになったし、並列処理もできるようになりました。
ただし、jobが一つだけであればworkflowを定義しなくても大丈夫です。
![workflows.png](https://qiita-image-store.s3.amazonaws.com/0/133447/b3356702-25c8-ccc1-0e41-04845b5a8b6f.png)


## 実行方法は？
configファイルを2.0系用にアップデート＆置き場所を変更して、いつも通りプッシュするだけでOK!
configファイルはプロジェクトルートから`.circle.yml`だったのを`.circleci/config.yml`に変更します。
あとローカルでも実行できるらしいですよ！(もっと早く知っていれば…)  

参考：[CircleCI 2.0はローカル環境で実行できるよ](https://qiita.com/ieee0824/items/28c7fa9e69cfc6ee7075)

## トランスレーターをあてにすると死ぬ
「でもconfigを書き換えてくれるAPIがあるんでしょ、知ってるよ」と油断している方。
私もそう考えていました。[config-translation](https://circleci.com/docs/2.0/config-translation/)があれば楽勝だと…！
でもそれは簡単な設定しかしていない一部のユーザーだけかと思います。私の場合、**１つ目のステップからコケまくる使えないconfigが出てきて、結局ゼロから作りました。**
こちらは構造を勉強するくらいにとどめておき、あてにしないほうが賢明かと思います。

# 概要
ここからは実際にどのような変更したかの説明です。
前提情報として、私が対応したプロジェクトだとこんな構成でした。

- やっているタスクは、テストの実行とデプロイのみ  
- staging環境とproduction環境の２つを持っており、developブランチがプッシュされた場合はstaging環境に、masterブランチがプッシュされた場合はproduction環境にデプロイする。  
- **ローカルの開発環境構築にdocker-composeを使っている**

３つめのおかげでだいぶ楽になりました！

## 1.0系での設定ファイル

```circle.yml
machine:
  timezone: Asia/Tokyo
  python:
    version: 2.7.13

dependencies:
  pre:
    - <デプロイ用のcliインストール>

database:
  override:
    - <テスト用データベース構築のためのコマンド>

test:
  override:
    - <テスト実行のためのコマンド ※出力先は"$CIRCLE_TEST_REPORTS/hoge.xml">

deployment:
  develop:
    branch: [develop]
    commands:
      - <stagingデプロイのためのコマンド>
  production:
    branch: [master]
    commands:
      - <productionデプロイのためのコマンド>
```
pythonのバージョン指定はデプロイに必要だったので。

## 2.0系での設定ファイル

```.circleci/config.yml
version: 2
jobs:
  build:
    machine: true
    steps:
      - checkout
      - restore_cache:
          key: docker-{{ checksum ".circleci/config.yml" }}-{{ checksum "docker-compose.yml" }}-{{ checksum "Dockerfile" }}
          paths: ~/caches/images.tar
      - run:
          name: Check cache file, if not exists then pull images and generate cache.
          command: |
            if [ ! -f ~/caches/images.tar ]; then
              docker-compose build
              mkdir -p ~/caches
              docker save $(docker images | awk 'NR>=2 && ! /^<none>/{print $1}') -o ~/caches/images.tar
            fi
      - save_cache:
          key: docker-{{ checksum ".circleci/config.yml" }}-{{ checksum "docker-compose.yml" }}-{{ checksum "Dockerfile" }}
          paths: ~/caches/images.tar

  test:
    machine: true
    steps:
      - checkout
      - restore_cache:
          key: docker-{{ checksum ".circleci/config.yml" }}-{{ checksum "docker-compose.yml" }}-{{ checksum "Dockerfile" }}
          paths: ~/caches/images.tar
      - run: <テスト用データベース構築のためのコマンド>
      - run: <テスト実行のためのコマンド　※出力先を"test_results/hoge.xml"に変更>
      - store_test_results:
                path: test_results

  deploy:
    working_directory: ~/<ユーザー名>/<プロジェクト名>
    parallelism: 1
    shell: /bin/bash --login
    environment:
      CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
      CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
    docker:
    - image: circleci/python:2.7.13
      command: /sbin/init
    steps:
      - checkout
      - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS
      - run: <デプロイ用cliのインストール>
      - run:
          name: Deploy
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              <productionデプロイのためのコマンド>
            else
              <stagingデプロイのためのコマンド>
            fi

workflows:
  version: 2
  build-test-deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - test
          filters:
            branches:
              only:
                - develop
                - master
```
うわー、めっちゃ長くなったー！
大丈夫、解説していきます！

# 解説
上記に貼り付けた2.0の設定ファイルを、各ブロックごとに解説していきます。

## workflow
まず一番下の`workflows`から見ていきましょう！

```
workflows:
  version: 2
  build-test-deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - test
          filters:
            branches:
              only:
                - develop
                - master
```
なんとなく読めばわかって頂けるかと思いますが、`build-test-deploy`という名前のworkflowを作成します。（名前は任意）
そこでは `build`、`test`、`deploy`という３種類のジョブを走らせていて、

- testはbuildが正常終了したら実行
- deoployはtestが正常終了し、かつブランチ名が「develop」または「master」のときのみ実行

という感じです。

## build
次に各ジョブを見ていきます。まずはbuildジョブから。

```
version: 2
jobs:
  build:
    machine: true
    steps:
      - checkout
      - restore_cache:
          key: docker-{{ checksum ".circleci/config.yml" }}-{{ checksum "docker-compose.yml" }}-{{ checksum "Dockerfile" }}
          paths: ~/caches/images.tar
      - run:
          name: Check cache file, if not exists then pull images and generate cache.
          command: |
            if [ ! -f ~/caches/images.tar ]; then
              docker-compose build
              mkdir -p ~/caches
              docker save $(docker images | awk 'NR>=2 && ! /^<none>/{print $1}') -o ~/caches/images.tar
            fi
      - save_cache:
          key: docker-{{ checksum ".circleci/config.yml" }}-{{ checksum "docker-compose.yml" }}-{{ checksum "Dockerfile" }}
          paths: ~/caches/images.tar
```

`machine`キーは実行タイプのを指定しています。
CircleCI2.0では実行タイプをdocker, machine(VM), macOS(macOSのVM)の３種類から選ぶ事ができます。
[公式サイト](https://circleci.com/docs/2.0/executor-types/)によるとdockerがベストプラクティスらしいですが、docker-composeでvolumeを使用する場合は実行タイプをmachineにしなければならないらしいので、そうしています。
volumeを使わない方はdockerタイプの方がいいかと！
**(※ machineタイプはそのうち有料になるらしいです)**

参考：[CircleCI 2.0 で docker-compose を動かすなら、Machine Executor にしないとハマる](https://qiita.com/kunit/items/85e869b9a0ff7a30ac79)

次の`restore_cache`→`run`→`save_cache`ではdockerイメージを作成してそれをキャッシュに保存しています。
こうすることで、２回目移行、時間のかかるイメージの作成をスキップし、次のtestジョブにすぐ移れるようになります。

参考：[CircleCi 2.0 で Dockerイメージをキャッシュしビルドを爆速で行う](https://qiita.com/takecore@github/items/366168694a7beb087418)
参考：[Caching Dependencies](https://circleci.com/docs/2.0/caching/)

## test
次にtestジョブです。

```
  test:
    machine: true
    steps:
      - checkout
      - restore_cache:
          key: docker-{{ checksum ".circleci/config.yml" }}-{{ checksum "docker-compose.yml" }}-{{ checksum "Dockerfile" }}
          paths: ~/caches/images.tar
      - run:
          name: Load Docker images
          command: docker load -i ~/caches/images.tar
      - run: <テスト用データベース構築のためのコマンド>
      - run: <テスト実行のためのコマンド　※出力先を"test_results/hoge.xml"に変更>
      - store_test_results:
                path: test_results
```

buildジョブでキャッシュしたimageファイルをロードし、テストの実行をしていきます。
その際、テストのログを出力するようにした方がいいでしょう。CircleCI上から見れるようになります。
1.0系では`$CIRCLE_TEST_REPORTS/hoge.xml`というところに吐いていましたが、2.0系では出力先を`store_test_results`キーで指定する必要があります。

参考：[Configuring CircleCI](https://circleci.com/docs/2.0/configuration-reference/#store_test_results)

## deploy
最後にデプロイです！

```
  deploy:
    working_directory: ~/<ユーザー名>/<プロジェクト名>
    parallelism: 1
    shell: /bin/bash --login
    environment:
      CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
      CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
    docker:
    - image: circleci/python:2.7.13
      command: /sbin/init
    steps:
      - checkout
      - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS
      - run: <デプロイ用cliのインストール>
      - run:
          name: Deploy
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              <productionデプロイのためのコマンド>
            else
              <stagingデプロイのためのコマンド>
            fi
```

私のプロジェクトではデプロイにpythonが必要だったので、dockerイメージを`circleci/python:2.7.13`に指定しています。そういうのがある方は参考にしてください。
また、最後のDeployステップで、ブランチがmasterのときとそれ以外のときでコマンドを変更するようにしています。

# 参考にしたサイト（再掲あり）
参考にさせていただきました！ありがとうございました！  

- [CircleCI 2.0はローカル環境で実行できるよ](https://qiita.com/ieee0824/items/28c7fa9e69cfc6ee7075)  
- [CircleCI 1.0 → 2.0 に設定ファイルをマイグレーションするために「config-translation API」を試した](https://kakakakakku.hatenablog.com/entry/2018/03/15/010820)
- [CircleCI 2.0 で docker-compose を動かすなら、Machine Executor にしないとハマる](https://qiita.com/kunit/items/85e869b9a0ff7a30ac79)
- [CircleCi 2.0 で Dockerイメージをキャッシュしビルドを爆速で行う](https://qiita.com/takecore@github/items/366168694a7beb087418)
- [CircleCI 2.0 に移行しました](http://tech.smarthr.jp/entry/2017/07/12/073000)
- [CircleCI 2.0 移行に潜む闇](http://tech.smarthr.jp/entry/2017/07/14/124400)

# おわりに
「宿題すべりこみタイプ」の同志の皆さん、参考になれば幸いです！
ではでは〜