Rails
S3
aws-cli
gitbook
CircleCI2.0

[CircleCI2.0]Markdown仕様書をBasic認証付きURLで公開する

モチベーション

  • CircleCIをもっと活用したい
  • ドキュメント作成をプログラムちっくにしたい
  • ER図を毎回更新したくない
  • サーバレス(今回がサーバレスかは置いてといて)やりたい
  • ソースコードとドキュメントをプルリクの中で見れたら幸せと思う

使用技術

  • CircleCI 2.0
  • Rails 5.1.5
  • Mysql 5.7
  • AWS S3
  • AWS Lambda
  • AWS CloudFront
  • Gitbook

Railsアプリをサンプルにします。

全体構成

AWS Networking.png

Githubにpushすると、それをフックにCircleCIがBuild & Deployを行います。
S3にアップロードしたものをCloudFront経由で配信します。
Lambdaにbasic認証のコードを書いて、リクエストがきたら認証を求めます。
これで限定されたドキュメント公開ができます。

実装

前提条件

  • CircleCIのアカウントがある
  • Gitbookが使える
  • IAMユーザー作成済み

S3

  • S3のbucketを作成する
  • <bucket-name>-docsというプレフィックスを付ける(管理のため)
  • バケットポリシーやホスティング設定は不要なので何もしない(CloudFrontでやる)

CircleCI

  • Buildするリポジトリを追加
  • 追加したリポジトリの設定から「AWS Permissions」を選択してIAMのキーを設定する

Cursor_と_Project_settings_-_IJGN_mypo-web_-_CircleCI.png

Markdown

リポジトリのルートにdocsフォルダを作ってその中でgitbookを使います。

$ mkdir docs
$ cd docs
$ gitbook init
$ echo /docs/_book >> .gitignore

あとはMarkdownでゴリゴリ書きます。

注意:名前はdocsじゃなくてもいいですが、CircleCIの設定ファイルで指定しているので合わせる必要があります。

設定ファイル

以下の要件で設定ファイルを作ってみました。
1. Rspec実行
2. rails-erdからER図を生成し、docs/imgに移動する
3. gitbookでdocs配下のmdファイルからhtmlファイルを生成
4. S3にアップロード
5. 3,4は特定のbranchのみ動作させたい

circleci/config.yml
version: 2

workspace_root: &workspace_root
    ~/workspace

defaults: &defaults
  docker:
    - image: circleci/ruby:2.4.2-node-browsers
      environment:
        RAILS_ENV: test
        BUNDLE_JOBS: 3
        BUNDLE_RETRY: 3
        BUNDLE_PATH: vendor/bundle
        DB_HOST: 127.0.0.1
    - image: circleci/mysql:5.7
  working_directory: *workspace_root

attach_workspace: &attach_workspace
  attach_workspace:
    at: *workspace_root

jobs:
  build:
    <<: *defaults
    steps:
      - checkout

      # Restore bundle cache
      - restore_cache:
          keys:
            - bundle-{{ checksum "Gemfile.lock" }}
            - bundle

      - run:
          name: Bundle Install
          command: bundle check || bundle install

      # Store bundle cache
      - save_cache:
          key: bundle-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # Database setup
      - run:
          name: Database setup
          command: |
            bin/rails db:create
            bin/rails db:schema:load

      # Run rspec in parallel
      - run:
          name: Run tests
          command: |
            bundle exec rspec --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)

      # Save test results for timing analysis
      - store_test_results:
          path: test_results

      - persist_to_workspace:
          root: *workspace_root
          paths:
            - .

  docs:
    <<: *defaults
    steps:
      - <<: *attach_workspace

      - run:
          name: Install dependencies
          command: |
            sudo apt-get install graphviz
            sudo npm install gitbook-cli -g

      - run:
          name: ER diagram
          command: |
            bin/rails db:create
            bin/rails db:schema:load
            bundle exec erd --attributes=foreign_keys,primary_keys,content,timestamp --filename=erd --filetype=png
            mv -f erd.png docs/img/

      - run:
          name: Gitbook
          command: gitbook build docs docs/_book

      - persist_to_workspace:
          root: *workspace_root
          paths:
            - docs

  deploy_s3:
    <<: *defaults
    steps:
      - <<: *attach_workspace

      - run:
          name: Install dependencies
          command: sudo apt-get -y -qq install awscli

      - run:
          name: Deploy to S3 if tests pass and branch is Master
          command: aws s3 sync docs/_book s3://$S3_BUCKET --delete

workflows:
  version: 2
  workflows:
    jobs:
      - build
      - docs:
          requires:
            - build
          filters:
            branches:
              only: develop
      - deploy_s3:
          requires:
            - build
            - docs
          filters:
            branches:
              only: develop

Build

CircleCI2.0で追加されたworkflowsを使うと次のように複数のjobが連結された感じで実行されます。
何か気持ちいい。

CircleCI_-_CircleCI.png

Basic認証をかけて公開する

参考記事にあるこちらを参考にさせていただきました。
ありがとうございます!

ハマった点

awscliの使い方

S3にsyncするときにbucket名の指定にs3://を付けないといけないところ

CircleCI 2.0の設定ファイルの書き方

1.0と2.0が書き方が全然違うので学習コストかかるところ

Build中にxxxx command not found

apt-getしているはずが、コマンドがないと怒られました。
sudoを付けたら解決しました。

Railsでmysqlを使う場合

config/database.ymlを変更する必要がありました。

config/database.yml
test:
  <<: *default
  adapter: mysql2
  database: yourapp_test
  host: <%= ENV['DB_HOST'] || 'localhost' %> # 追加

このDB_HOSTにはCircleCIの設定ファイルで書いたDB_HOST: 127.0.0.1が入ります。
localhostだとエラーになるようです。

参考記事

gitbookで楽々ドキュメント作成
GitBook/GitHub/CircleCIでメンテ可能な仕様書を書く
CircleCIを使ってS3にブログをデプロイする
CircleCI 2.0 に移行しました
CloudfrontとS3でBasic認証をかける
Github, CircleCI, S3, CloudFront, Middlemanを活用して、https対応のサーバレスで自動deployなWEBサイト構築

成果物

https://github.com/TakuyaHarayama/gitbook-docs-template

CircleCIのデプロイ部分を一部コメントにしてるので、適宜変更してください。
erd生成はないです。

終わりに

これでソースコードと一緒にドキュメントも管理できて、クライアントにもbasic認証で共有できて
レビューもしやすくなる、そして幸せになるw