Re:ゼロから始めるインフラ構築 〜はじめてのIaC・CI/CD〜

f:id:tippy3:20200707165719j:plain

はじめまして、SRE部の高塚です。新卒として4月に入社し、チーム研修ではBEARというSlackアプリを作成しました。

technote.zozo.com

BEARは社内システムとして正式に導入が決まり、準備期間として1か月半が用意されました。この記事では、その期間に行ったインフラの再構築について紹介します。

BEARとは

まずはBEARについて簡単にご説明します。なおこの章は読み飛ばすことも可能です。

BEARは本のレビューをRDBで管理し、SlackアプリとしてCRUDや検索が行えるシステムです。AIによる「あなたにおすすめの本」の推薦機能もあります。

f:id:tippy3:20200707170316j:plain

弊社には書籍購入補助制度があり、これまではSlackチャンネルに各自が本のレビューを投稿していましたが、以下のような問題がありました。

  • 検索しにくい
  • 過去のレビューを遡りにくい
  • 書籍名やAmazonの購入ページのリンクなど、入力項目が多い

BEARはこれらの問題を解決したSlackアプリです。

繰り返しで恐縮ですが、詳細は以下のカンパニーブログをご覧ください。

technote.zozo.com

かくして新卒研修の発表会のあと、BEARは正式な社内システムになることが決定したのですが、インフラを担当していた私は青ざめました。

なぜなら発表会で披露したデモアプリのインフラは、まったく本番運用を想定したものではなかったからです!(ハッカソンあるある?)

旧BEARが抱えていた問題点

デモ時点でのBEAR(以下、旧BEAR)は、2つのインフラの問題を抱えていました。

コード化されていないインフラ

旧BEARはAWSで稼働していますが、各リソースはマネジメントコンソールの画面から作っていたため、詳細な設定はインフラ担当の自分しか把握していませんでした。

もちろんドキュメント化を心がけてはいましたが、設定を変更したあとドキュメントの更新を忘れ、バックエンド担当に迷惑をかけたこともありました。変更前のレビューや変更履歴の管理もできていませんでした。

自動化されていないデプロイ

旧BEARはデプロイをすべて手動で行っていました。例えば基盤のAPIを更新する際は、社内VPNからEC2にSSHでログインし、git pulldocker-compose upをしていました。毎回とても面倒くさいことに加え、オペレーションミスも多発しました。また、デプロイのたびにダウンタイムが発生していました。

Re:ゼロから始めるインフラ構築

これらの問題を解決するため、新BEARではインフラをゼロから作り直しました。参考程度にアーキテクチャ図もご紹介します。基盤のAPIはECSに変えることで、ダウンタイムなしのデプロイを可能にします。

f:id:tippy3:20200707170329j:plain

また今までは私一人でインフラ周りの作業を行っていましたが、同じくSRE部の新卒・川津にも合流してもらい、インフラチームとして開発を進めました。

インフラをコード化する

まず取り組んだのがインフラのコード化です。一般にはInfrastructure as Code(IaC)と呼ばれています。IaCのメリットを以下に挙げます。

  • GitHubが使える。つまりバージョン管理ができ、変更履歴も残り、レビューもできる
  • 手順書や環境定義書が不要になり、それらに起因するヒューマンエラーを防げる
  • 雛形を作っておくことで、様々なプロジェクトでそれを使い回せる

AWSの場合はCloudFormationを使うことで、リソースの設定をYAML(またはJSON)で書くことができます。なおCloudFormation自体は無料で、実際に作ったリソースだけに料金がかかります。

例えばVPCにプライベートサブネットを作る場合は以下のようになります。

AWSTemplateFormatVersion: 2010-09-09

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.10.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: my-vpc

  PrivateSubnet1a:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC #上のVPCを参照している
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.10.10.0/24
      Tags:
        - Key: Name
          Value: my-private-subnet-1a

このファイルから実際にリソースを作るには、aws-cliの以下のコマンドを使用します。

# テンプレートの検証
aws cloudformation validate-template --template-body file://my-file.yml

# 変更セットの作成
aws cloudformation create-change-set \
    --change-set-type "UPDATE" \ #初回はCREATE
    --stack-name "my-stack" \
    --change-set-name "my-stack-change-set" \
    --template-body "file://my-file.yml"

# 変更セットの実行
aws cloudformation execute-change-set --change-set-name "my-stack-change-set"

このようにCloudFormationを使い、すべてのAWSリソースをコード化しました。

しかし、せっかくIaCを実現しても、コマンドを人間が打ち間違えたら台無しです。

そこで、上記コマンドの実行を含む、すべてのデプロイ作業をコード化・自動化していきました。使ったのはGitHub Actionsというサービスです。

デプロイを自動化する

GitHub Actionsは、GitHubが用意する仮想マシン上で任意の処理を行えるサービスです。リポジトリへのプッシュやプルリクエスト、あるいは日時指定といったトリガー条件が用意されています。処理やトリガー条件をYAMLで書き、.github/workflows/に置くと自動で実行されます。

気になるお値段は、パブリックリポジトリでは無料、プライベートリポジトリでも一定量までは無料です!(詳細はGitHub公式サイトをご覧ください)

例えばプルリクエストをトリガーにechoするには以下のようにします。

name: my-actions
on:
  pull_request:
    branches:
      - master
    types: [opened, synchronize, closed]

jobs:
  Greet:
    name: Greet
    runs-on: ubuntu-latest #仮想マシンの種類
    steps:
      - name: Hello world
        run: | #コマンドは複数実行できる
          echo "Hello world!"
          echo "Hello world!!!"

  AnotherJob:
  # 以下省略

次に、GitHub Actionsでaws-cliを使う例として、画像のディレクトリをS3にアップロードするコードを示します(詳細はこちら)。この処理は新BEARにも組み込まれています。

- name: S3 sync
  working-directory: static #カレントディレクトリの指定
  run: aws s3 sync . s3://my-static-files --delete --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude "README.md"

以下のように自作のスクリプトを実行することもできるので、可能性は無限大です!ただし仮想通貨のマイニング等はGitHub利用規約で禁止されています。

- name: Execute script
  working-directory: scripts #カレントディレクトリの指定
  run: ./my-script.sh

新BEARでは、GitHub Actionsで主に以下の処理を行っています。

  • プルリクエストの作成や編集で実行
    • lint
    • ユニットテスト
  • プルリクエストがマージされたときのみ実行
    • CloudFormationの実行(=AWSリソースの作成)
    • Dockerイメージのビルド、プッシュ、ECSタスクの更新
    • ソースコードのアップロード、Lambda関数の更新

これにより、テストからビルド、デプロイまでを自動化できました。プルリクエストが作成されたらすぐに一連の処理が実行され、もしテストやビルドでエラーが発生したらGitHub上に通知されます。問題なくプルリクエストがマージされれば、すぐにAWS環境がダウンタイムなしで更新されます。

これは一般にCI/CD(継続的インテグレーション・継続的デリバリー)と呼ばれる手法です。BEARはCI/CDで開発効率を高め、リリースサイクルを短くできました。

まとめ

新卒研修で作ったSlackアプリのインフラを再構築し、IaCとCI/CDを実現しました。CloudFormationとGitHub Actionsを使うのは初めてで苦労しましたが、とても勉強になりました。

ちなみに、ここまで新卒研修についてご紹介しましたが、ZOZOTOWNのリプレイスプロジェクトではより高度なCI/CDを実現しています。よろしければこちらの記事もお読みください。CI/CDについてもっと詳しく学べます!

techblog.zozo.com

最後に

ZOZOテクノロジーズでは、SREをはじめ様々な職種で一緒に働く仲間を募集中です。ぜひ以下のページをご覧ください!

tech.zozo.com

また、7月16日には「案件別採用説明会」をオンラインで開催します!このイベントでは「ZOZOのやりたいことリスト」に掲載している10の案件について、今やっていること、今後やっていくことを赤裸々にお伝えする予定です。奮ってお申し込みください!

tech.zozo.com

zozotech-inc.connpass.com

カテゴリー