CircleCIの書き方ノウハウまとめ 2019

CircleCIの設定が避けて通れないスキルになってきたのでここいらでざっくりまとめて置きます。
CircleCI 2.0 Dockerを利用します。コピペではなくてある程度は理解しながら進みたいと思います。
cronなどの設定もできるのでjenkinsや他のjobサーバーの代替としても利用できるはずです。
また、[CircleCIAPI](https://circleci.com/docs/2.0/build-processing/)を利用して特定のworkflowをトリガーする事も可能なのでこれからいろいろなユースケースに対応できます。Dockerで開発環境を作成してCircleCIでもDockerImageごと活用するなど一石二鳥。ただし。。。遅いというのは言うまでもないです。

[CircleCIの設定](https://circleci.com/docs/2.0/configuration-reference/)

検証環境： macOS Mojave / Rails 5.2.2 / Ruby 2.5.1

## 1. ファイルの設置場所
.circleci/config.yml

## 2. 書き方いろいろ
configファイルの中で[定義済みの変数](https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables)や[環境変数](https://circleci.com/docs/2.0/env-vars/#injecting-environment-variables-with-the-api)を利用する事が可能です。
[workflows](https://circleci.com/docs/2.0/workflows/
): jobのセットをワークフローとして管理できます。今回はbuildとdeployの2つのフェーズに分けています。Aのjobが完了していないとBのjobが動かないなど依存関係を設定できます。

### 2.0 workflowsの定義
```
workflows:
  version: 2
  build_and_deploy:
    jobs:
      - build
      - confirm_deploy:
          type: approval
          requires:
          - build
      - deploy:
          requires:
          - confirm_deploy
```

[jobs](https://circleci.com/docs/2.0/containers/#section=jobs): jobを定義します。Dockerイメージの定義 -> 環境の設定 -> コードのチェックアウト -> 実際に実行するstep -> テストの実行までセットで書かれている事が多いようです。
こちらのサンプルでは、buildタスクとconfirm_deployタスクとdeployタスクの3つのjobが設定されています。

### 2.1 それぞれのjobの定義
```
jobs:
  build:
    working_directory: ~/my-app
  deoloy:
```
jobsの一段落下に定義していきます。

### 2.2 Dockerイメージの利用の定義
circleci/ruby:2.5.1-node-browsersとpostgres:9.6のイメージを利用します。
[イメージの命名規則](https://circleci.com/docs/2.0/circleci-images/#language-image-variants)と[PostgreSQLのビルド済みイメージ](https://circleci.com/docs/2.0/circleci-images/#postgresql)を参照しながら適切なバージョンを選択します。environmentに環境変数を設定できます。

ビルド済みイメージ
https://github.com/CircleCI-Public/circleci-dockerfiles/tree/master/ruby/images/
https://github.com/docker-library/ruby/

[parameters](https://circleci.com/docs/2.0/reusing-config/)を使うと変数のように値を再利用する事もできます。

```
docker:
- image: circleci/ruby:2.5.1-node-browsers
  environment:
  - RAILS_ENV: test
  - PGHOST: 127.0.0.1
  - PGUSER: root
  - SELENIUM_CHROME_HEADLESS: true
- image: circleci/postgres:9.6
  environment:
  - POSTGRES_USER: root
  - POSTGRES_DB: ******
```

### 2.3 Docker以外のjobsの要素について
[steps](https://circleci.com/docs/2.0/configuration-reference/#steps)の中に実際のタスクを記載します。
[working_directory](https://circleci.com/docs/2.0/configuration-reference/#section=configuration)で作業ディレクトリを指定します。$CIRCLE_WORKING_DIRECTORYで参照する事も可能です。
```checkout```はworking_directoryにコードをチェックアウトする為のコマンドです。
```run```でコマンドを実行できます。
[save_cache](https://circleci.com/docs/2.0/configuration-reference/#save_cache)と[restore_cache](https://circleci.com/docs/2.0/configuration-reference/#restore_cache)で```bundle install```や```yarn install```などをキャッシュするのが一般的です。
[persist_to_workspace](https://circleci.com/docs/2.0/configuration-reference/#persist_to_workspace)を最後に宣言する事で次のworkspaceにテンポラリファイルの状態が引き継がれるのでjobを細かく区切りやすいです。同じコマンドを何度も実行する手間が省けます。

### 2.4 buildのtask定義例
```
build:
  docker:
  - image: circleci/ruby:2.5.1-node-browsers
    environment:
    - RAILS_ENV: test
    - PGHOST: 127.0.0.1
    - PGUSER: root
    - SELENIUM_CHROME_HEADLESS: true
    - ENECHANGE_PROFILER_SERVER_URL: http://enechange-profiler-sample2.a36rk5bkqp.ap-northeast-1.elasticbeanstalk.com/profile/
  - image: circleci/postgres:9.6
    environment:
    - POSTGRES_USER: root
    - POSTGRES_DB: *************
  working_directory: ~/repo
  steps:
  - checkout
  - run: |
      git submodule init
      git submodule update
  - restore_cache:
      keys:
      - v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "yarn.lock" }}
  - run:
      name: Install System Dependencies
      command: |
        sudo apt-get install fonts-migmix
  - run:
      name: Install Chrome
      command: |
        sudo apt install -y libappindicator3-1
        curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
        sudo dpkg -i google-chrome.deb
        sudo sed -i 's|HERE/chrome\"|HERE/chrome\" --disable-setuid-sandbox|g' /opt/google/chrome/google-chrome
        rm google-chrome.deb
        /opt/google/chrome/google-chrome --version
  - run:
      name: install dependencies
      command: |
        bundle install --jobs=4 --retry=3 --path vendor/bundle
  - run:
      name: install frontend dependencies
      command: yarn install
  - save_cache:
      key: v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "yarn.lock" }}
      paths:
        - vendor/bundle
        - node_modules
  - run:
      name: Wait for DB
      command: dockerize -wait tcp://127.0.0.1:5432 -timeout 120s
  - run:
      name: Database setup
      command: bin/rails db:create; bin/rake db:setup; bin/rake db:seed --trace
  - run: |
      mkdir /tmp/test-results
      bundle exec rspec --format progress \
                        $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
  - run: echo "Hello, world!" > test
  - persist_to_workspace:
      root: .
      paths:
      - tmp
      - vendor
      - node_modules
      - test
```

### 2.5 deployのtask定義例
今回はebを使っているのでebコマンドを直接利用してdeployを実施します。
cronなどのtaskも定義できるので定期的にバッチ処理を実行するなども可能です。

```
deploy:
docker:
- image: circleci/ruby:2.5.1-node-browsers
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
    at: ~/repo
- run: |
    git submodule init
    git submodule update
- run:
    name: Install eb Command
    command: |
      sudo apt-get -y -qq update
      sudo apt-get install python-pip python-dev build-essential
      sudo pip install awsebcli --upgrade
- run:
    name: Deploy Development
    command: |
      echo "Deploying.......$CIRCLE_BRANCH"
      eb deploy -l `date +%Y%m%d_%H%M%S` ***********
```

## 3. ローカルデバック方法
### インストール
```
brew install circleci
circleci update install
```

### 文法チェック
```
circleci config validate -c .circleci/config.yml
```

### ビルド
```
circleci build
```

とりあえずこんな感じで簡単なRails webアプリケーションのデフォルト設定が完了しました。