CircleCI 2.0とcodedeployでデプロイを自動化する

2017.12.22

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

オフィスの休憩室にあるNintendo Switchのマリオカートで遊ぶのが楽しすぎて、自宅にも欲しくなってきました。佐々木です。

最近自分のプロジェクトでCircle CIAWS CodeDeployを連携させて、デプロイを自動化したので、その時の手順について紹介します。

構成/要件

今回は以下のような構成と条件でセットアップを行いました。

  • ソースコードはGithub上に存在する
  • AWS CodeDeployを使って、AutoScalingGroup配下のEC2インスタンスへデプロイする
  • Circle CIでユニットテストを実行して、成功した時のみデプロイする
  • デプロイはビルドがdevelopブランチに対して実行された時のみ行う

やること

  1. AWS CodeDeploy上にデプロイメントグループを作成する
  2. デプロイ用のS3バケットを作成する
  3. デプロイ用のIAMユーザーを作成して、CircleCI上に認証情報を設定する
  4. デプロイ用のスクリプトをrake タスクとして作成する
  5. .circleci/config.ymlにビルドジョブを記述する

今回は対象がrailsアプリだったのでデプロイ用のスクリプトはrakeタスクで記述しましたが、シェルスクリプトやpythonなどでも問題ないです。 各言語のaws-sdkを使えば同じことが実現できるはずです。

上記1〜2の手順は「[公式チュートリアルではじめる]CircleCI+CodeDeployを使ったCD(継続的デプロイ)」で紹介されている手順と同じなので、ここでは省略します。

.circleci/config.ymlにビルドジョブを記述する

circleci/config.ymlは下記のようになります。 この設定ファイルは大きく分けて2つの部分で構成されています。

  • jobs: テストとデプロイの各ジョブの詳細を記述するパート
  • workflows: 各ジョブの実行順序や条件を記述するパート

Circle CIのドキュメントと合わせて読んでいただくとそれほど難しくないかと思いますが、下記の3点がポイントになります。

  • deployジョブでは後ほど紹介するデプロイ用のrakeタスクを実行している
  • テスト成功後にデプロイを実行するためにdeployジョブはbuildジョブに依存すると宣言している
  • developブランチのみデプロイするためにfiltersでブランチ名のチェックを行なっている
version: 2
jobs:
  build: #単体テストを実行するジョブ
    working_directory: ~/my-app
    docker:
      - image: ruby:2.4.0
    steps:
      - checkout
      - run: bundle install --path vendor/bundle
      - run:
          name: Run Test
          command: bundle exec rspec
  deploy: #デプロイするジョブ
    working_directory: ~/my-app
    docker:
    - image: ruby:2.4.0
    steps:
      - checkout
      - run: bundle install --path vendor/bundle
      - run: bundle exec rake deploy
workflows:
  version: 2
  build-deploy:
    jobs:
      - build
      - deploy: # deployはbuildのあとに実行
          requires:
            - build
          filters: # developブランチの場合のみデプロイする
            branches:
              only: develop

デプロイ用のスクリプトをrake タスクとして作成する

続いてデプロイ用のrakeタスクです。下記にスニペットを掲載していますが、概ね次のようなことをしています。

  1. git archiveでデプロイするファイルをZIPファイルにまとめる
  2. ZIPファイルをS3へアップロードする
  3. CodeDeploy上にリビジョンを作成する
  4. 作成したリビジョンをデプロイする

1でgit archiveを使っているのはvendor/bundleなどの不要なファイルがデプロイするファイルに含まれるのを防ぐためです。

# frozen_string_literal: true

require 'aws-sdk-codedeploy'
require 'aws-sdk-s3'

# Configs for codedeploy
APP_NAME = 'app_name'
S3_BUCKET = 'mybucket'
S3_PREFIX = 'app/versions/'
TAG = `git describe --tags`.strip
DEPLOY_GROUP_NAME = 'deploy_group_name'

desc "Deploy with codedeploy"
task :deploy do
  # upload files to s3
  zip_file = "#{APP_NAME}_#{TAG}.zip"
  s3_key = S3_PREFIX + '/' + zip_file
  `git archive HEAD --output=#{zip_file}`
  begin
    Aws::S3::Client.new.put_object(bucket: S3_BUCKET, key: s3_key, body: File.open(File.basename(zip_file)))
  ensure
    File.delete(zip_file)
  end
  # register revision
  revision = {
    revision_type: 'S3',
    s3_location: {
      bucket: S3_BUCKET,
      key: s3_key,
      bundle_type: 'zip',
    },
  }
  codedeploy = Aws::CodeDeploy::Client.new
  codedeploy.register_application_revision(application_name: APP_NAME, revision: revision)
  # deploy
  codedeploy.create_deployment(application_name: APP_NAME,
                               deployment_group_name: DEPLOY_GROUP_NAME,
                               revision: revision,
                               file_exists_behavior: 'OVERWRITE')
end

ここまで紹介した手順で環境設定を行って、設定ファイルをなどをgithubにPushすればCircleoCI上でデプロイジョブが実行されるはずです。 ワークフローの経過はCircleCI上からフローチャートで確認できます。

最後に

Circle CI 2.0とAWS CodeDeployを使ってデプロイを自動化するスクリプトと設定を紹介しました。

この記事で紹介したスクリプトや設定はそれほど量が多くないのでコピペですぐに作成できると思いますが、サンプルもgithubで公開していますので、よろしければそちらも参照してみてください。