ENECHANGE Developer Blog

ENECHANGE開発者ブログ

CircleCI 2.0に承認フロー追加

こんにちわ。 エンジニアのMariMurotaniです。 最近、リポジトリの数が多くなってきたのですが、CircleCIの設定はいろいろな書き方があって混乱するのとworkflowsやcronなどの便利機能を使いこなせていない部分があったので一旦整理してみました。今回はbuildとdeployの両方をCircleCI側で行います。buildに関しては今まで通りなのですがdeployに関してはCircleCIの画面上でconfirm_deployという手動の承認タスクを必要とします。コンテナの実行が渋滞してたときにテストが正常終了して承認をしても一旦待ち行列に入るので即時にデプロイされる訳ではない所で注意が必要です。

また、ebを利用してデプロイを行っているのですがその際に利用するsshのキーはCircleCIのコンソール上から登録を行っています。 CircleCIの設定

検証環境: MAC Mojave / Rails 5.2.2 / Ruby 2.5.1

1. ファイルの設置場所

.circleci/config.yml

2. 書き方いろいろ

configファイルの中で定義済みの変数や環境変数を利用する事が可能です。 workflows: jobのセットをワークフローとして管理できます。今回はbuildとdeployの2つのフェーズに分けています。Aのjobが完了していないとBのjobが動かないなど依存関係を設定できます。

workflows: jobのセットをワークフローとして管理できます。今回はbuildとdeployの2つのフェーズに分けています。Aのjobが完了していないとBのjobが動かないなど依存関係を設定できます。

2.0 workflowsの定義

f:id:mari-murotani:20190412185918p:plain

workflows:
  version: 2
  build_and_deploy:
    jobs:
      - build
      - confirm_deploy:
          type: approval
          requires:
          - build
      - deploy:
          requires:
          - confirm_deploy

jobs: jobを定義します。Dockerイメージの定義 -> 環境の設定 -> コードのチェックアウト -> 実際に実行するstep -> テストの実行までセットで書かれている事が多いようです。

confirm_applyタスクにapprovalを指定しているのでClickすると下記の図のようなポップアップが表示され「Approve」を押すと次のタスクに進みます。 f:id:mari-murotani:20190412162717p:plain

2.1 それぞれのjobの定義

jobs:
  build:
    working_directory: ~/my-app
  deoloy:

2.2 Dockerイメージの利用の定義

circleci/ruby:2.5.1-node-browsersとpostgres:9.6のイメージを利用します。 イメージの命名規則PostgreSQLのビルド済みイメージを参照しながら適切なバージョンを選択します。environmentに環境変数を設定できます。parametersを使うと変数のように値を再利用する事もできます。

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

2.3 Docker以外のjobsの要素について

stepsの中に実際のタスクを記載します。 working_directoryで作業ディレクトリを指定します。$CIRCLE_WORKING_DIRECTORYで参照する事も可能です。 checkoutはworking_directoryにコードをチェックアウトする為のコマンドです。 runでコマンドを実行できます。 save_cacherestore_cachebundle installyarn installの結果などをキャッシュするのが一般的です。 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
  - image: circleci/postgres:9.6
    environment:
    - POSTGRES_USER: root
    - POSTGRES_DB: ************
  working_directory: ~/repo
  steps:
  - checkout
  - run: 
name: Update submodule 
Command: |
      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: 
      name: Execute test
      command: |
      bundle exec rspec --format progress \
                        $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
  - persist_to_workspace:
      root: .
      paths:
      - tmp
      - vendor
      - node_modules

2.5 deployのtask定義例

今回はebを使っているのでebコマンドを直接利用してdeployを実施します。 ebの細かい説明については割愛しますが、ローカルのPCからebコマンドを利用してデプロイするのと同じ方式で動作する事が前提となっています。デプロイ時に必要なSSHキーはCircleCIの管理画面上から登録し、add_ssh_keysのfingerprints で参照しています。cronなどのtaskも定義できるので定期的にバッチ処理を実行するなども可能です。

deploy:
docker:
- image: circleci/ruby:2.5.1-node-browsers
working_directory: ~/repo
steps:
- add_ssh_keys:
   fingerprints:
   - "***************************************"
- attach_workspace:
   at: ~/repo
- run: |
   git submodule init
   git submodule update
- attach_workspace:
    at: ~/repo
- run: |
    name: Update Submodule
    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

とりあえずこんな感じでCircleCIを使ってbuild -> 承認 -> deployのワークフローを作成できました。デプロイまで全自動にしてもいいですし、デプロイ先まで動的に作成してもいいですし、やっている業務によっていろいろカスタマイズできる所がいいと思っています。