CircleCI2.0導入まとめ

CircleCIを以下のような構成で導入してみた際のまとめ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/257568/30344b8b-6785-72fd-1ed3-b29091199ca0.png)


# 事前準備
- githubにリポジトリがある
- githubの秘密鍵・公開鍵を持っている
- githubに公開鍵が登録されている
- ec2の秘密鍵を持っている
- ec2に公開鍵が登録されている(authorized_keys)

# 必要な作業
1. CircleCIに登録する
2. 管理画面から該当のリポジトリを追加する
3. CircleCIに公開サーバのssh keyを登録する
4. .circleci/config.yml作る
5. プッシュする
6. ビルドを確認する

##1. CircleCIに登録する
今回はGitHubでSign Upし連携します。
https://circleci.com/signup/

##2. 該当のプロジェクトを追加する
ADD PROJECTから追加します。

##3. CircleCIに公開サーバのssh keyを登録する
今回はec2になるので、ec2のホスト名と秘密鍵を登録します。
秘密鍵をサーバー上に登録するのって良いんだっけ。と思いましたがprivate keyなのでそのようです。(CircleCIを信じる)
https://circleci.com/docs/2.0/add-ssh-key/

fingerprintが発行されます。

fingerprintは公開鍵を元に発行されるものなので、内部ではそのようになっているのだと思います。

##4. .circleci/config.yml作る
公開するサーバーにデプロイできるymlファイルを作ります。
内容としては下記のようになります。

- デプロイ環境のイメージ作成
- デプロイ環境のコンテナを起動
- コンテナ内で行う処理を定義

今回はCapistranoからDockerを動かす仕組みになっているので、これら2つを動かす環境のコンテナを用意すれば良いということになります。
まだテストを導入できていないので、テストを実行する処理は除いています。

##5. プッシュする
変更をプッシュします。
プッシュをするとフックしてCI上でymlに定義した処理を読み始めます。
1回プッシュした後はCircleCI画面から再実行することもできます。

##6. ビルドを確認する
最後まで実行が終わりSuccessとなっていれば成功です。


スムーズに行くとこのようになります。


以下、ポイントや詰まった所について
## 導入前
1度ローカルから直接デプロイできる事を確認するのが良さそうです。
capistranoからデプロイ、ロールバックを確認した後に着手しました。
その際に必要になったモジュールや作業を残しておくと、それを基本的にCI上で行う感じなので捗ります。

## config.yml
```yml:.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: ruby:2.4-alpine
    working_directory: ~/repo
    steps:
      - setup_remote_docker:
          reusable: true
      - run:
          name: システム依存関係のインストール
          command: apk add --update --no-cache linux-headers git sudo openssh-client tar gzip build-base tzdata postgresql-dev
      - checkout
      - restore_cache:
          name: Bundleキャッシュの復元
          keys:
            - gems-{{ .Environment.CACHE_KEY }}-{{ checksum "Gemfile.lock" }}
            - gems-{{ .Environment.CACHE_KEY }}-
      - run:
          name: Ruby依存関係のインストール
          command: bundle check || bundle install --jobs=4 --retry=3
      - save_cache:
          name: Bundleキャッシュの保存
          key: gems-{{ .Environment.CACHE_KEY }}-{{ checksum "Gemfile.lock" }}
          paths:
            - /usr/local/bundle
      - add_ssh_keys:
          fingerprints:
            - "hage:hage:hoge:hoge:huga:huga:hage:hoge"
      - run:
          name: ssh-agent登録
          command: |
            ssh-agent -s > ~/.ssh_agent_conf
            source ~/.ssh_agent_conf
            chmod -R 700 ${HOME}
            for _k in $(ls ${HOME}/.ssh/id*); do
              ssh-add ${_k} || true
            done
            cat <<EOF >> ${HOME}/.ssh/config
              Host github github.com
                HostName github.com
                IdentityFile ~/.ssh/id_rsa_hagehagehogehogehugahugahagehoge
                User git
            EOF      
      - deploy:
         name: Capistranoデプロイ
         command:
           bundle exec cap production deploy --trace
```
### CIコンテナ内のOSについて
サービスが動くDockerのOSはUbuntuですが、軽量で早くて良いということでCI上の実行環境はalpine-linuxにしました。今後Dockerで使用する際は主流になるそうです。まだパッケージ管理が弱かったりで、色々入れようとし始めると面倒なようですが、今回はcapistranoで必要なものだけということで使ってみています。
本格的なシステムとかでコンテナ何十個もデプロイする時などに違いが出てくるようです。
あと、ありがちな構成のシステムであればDockerHubで配布されているイメージを使う方がもっと早そうです。

### CACHE_KEYについて
CircleCIのキャッシュは現状不変のもののようで、明示的にクリアをするために使用します。管理画面から環境変数を登録する方法で行っています。

### checksumについて
Gemfileのキャッシュを使用するかしないかの判断のために使用しています。

### sshキーについて
基本的にCircleCIとGithubの連携ができているので、3.で発行したfingerprintを登録すれば必要なキーの情報は揃います。
https://circleci.com/docs/2.0/gh-bb-integration/#permissions-overview

### ssh-agentについて
セキュリティ上の観点からで、気にならなければ公開サーバー上にGithubの秘密鍵置けばする必要はないと思います。
実行ログを見ると分かるのですが、CIコンテナ内で作成される鍵の名前末尾に、fingerprintのコロンを省略した文字列が付与されます。

自分の場合、railsでcapistranoを使っていたので、capistranoの方で接続設定している部分も併せて修正する必要がありました。

```cofig/deploy/production.rb
ssh_options: {
    user: "deploy",
    keys: %w(~/.ssh/id_rsa_hagehagehogehogehugahugahagehoge),
    forward_agent: true,
    auth_methods: %w(publickey)
}
```
ローカルでも行っていたように~/.ssh/configも設定します。

最後にデプロイコマンドを定義するといった感じです。

## CLIについて
ローカルで検証するようとして提供されています。
https://circleci.com/docs/2.0/local-cli/#run-a-job-in-a-container-on-the-local-machine
ただ最初こちらを使用していたのですが、
add_ssh_keysのローカルでの実行はサポートされていないようで、デプロイまでを確認する事はできません。
という事はデプロイまで確認したいという目的のために使用するものではないと判断し、以降はpushして検証しました。

また、以下のような事が分かりました。

- circleci config validate -c .circleci/config.yml  
  - 構文チェックだけなのでこちらがvalidでも実行時ほかで普通にエラーでる

- circleci buildとcircleci local excecuteはほぼ同じ
  - ゆえにcircleci buildはもうなくなるみたい(https://github.com/CircleCI-Public/circleci-cli/pull/53)

まだ色々本格的に使う用ではない感じがします。
ユニットテストとかあると、ymlを元に生成したコンテナで実行できて役に立ちそうだから、それ用なのかな