[ISUCON用] 複数台同時デプロイスクリプト(Golang)


## はじめに

以下の記事を以前作成しました。

https://qiita.com/momotaro98/items/24cec11fc050c014057f

これで作成したうえで、実際のISUCONのようにEC2上に3台のサーバを使ってISUCONの練習をする際、またはISUCON本番時に、デプロイを複数台同時に可能にするスクリプトを作成しました。この記事でのスクリプトはGo言語のみを対象にしています。

## 環境

* AWS EC2
* Ubuntu 18.04.5 LTS

## サンプルのGitHubレポジトリ

https://github.com/momotaro98/isucon10-q

## 前提

### サーバにいるisuconユーザーはsshで他サーバへアクセスすることができる。

EC2上のisuconユーザー用の鍵ペアを作成し`authorized_keys`ファイルを持つことでパスワードなしで互いのサーバへisuconユーザーでSSHアクセスできるようにします。

手動で作成することも可能ですが、筆者は公式のAnsibleとPackerを修正しAMIへビルドする改修をしました。本記事の最後に「公式AnsibleとPackerを書き換える」の項目で記載しています。

### `/etc/hosts` を修正しisu2, isu3の名前を作成する。

スクリプト内で`isu2`,`isu3`というホスト名にしており環境ごとに1台目サーバの`/etc/hosts`ファイルへ設定する必要があります。

こちらもAnsibleかTerraformでの構築時に自動化されることが理想ですが現状(2021年7月4日)では筆者の方ではできていません。

他サーバ2台のプライベートIPを指定します。

```diff:/etc/hosts
127.0.0.1 localhost

+ 10.1.0.158 isu2
+ 10.1.0.181 isu3

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
```

## デプロイスクリプト

以下はISUCON10予選のisuumoアプリケーションを対象にしており、`isuumo`の部分を練習する過去問に合わせて変更する必要があります。

本来のISUCONではデプロイスクリプトではNginxやMySQLの設定ファイルも同時にデプロイしたり、ログをローテーションさせたりするチームが多いですが、この記事ではGoのアプリケーションのデプロイにフォーカスします。そのような処理もするようにデプロイスクリプトを各々がカスタマイズすることになると思います。

ディレクトリ構成

```
├── deploy-with-remote.sh
├── deploy.sh
└── webapp
    ├── go
    ├── ruby
....
```

はじめに1台目のサーバへデプロイスクリプトを含むレポジトリをcloneさせます。

```terminal
sudo su isucon
cd ~
git clone https://github.com/momotaro98/isucon10-q.git # 自身のISUCONレポジトリを指定すること
```

直接実行するスクリプトが以下です。

他サーバへはsshコマンドを利用することで同様にdeploy.shスクリプトを流すようにしています。

```bash:deploy-with-remote.sh
#!/bin/bash -eu

# 【変更する必要のある箇所】
repo=https://github.com/momotaro98/isucon10-q.git # 自身のISUCONレポジトリ
repo_path=/home/isucon/isucon10-q                 # Gitレポジトリへのパス

# 自身のサーバへデプロイ
echo 'running deploy to this server'
git -C ${repo_path} pull origin master
${repo_path}/deploy.sh

# 他2台のサーバへデプロイ
echo 'running deploy to other servers, isu2 and isu3'
echo ''
echo '[NOTE] Before expecting this process to work well, you need to prepare /etc/hosts for alias isu2, isu3'
echo ''
for srv in "isu2" "isu3"
do
  echo 'starting for '${srv}
  ssh isucon@${srv} git -C ${repo_path} pull origin master || ssh isucon@${srv} git clone ${repo}
  ssh isucon@${srv} ${repo_path}/deploy.sh
  echo 'finished for '${srv}
done
```

`deploy-with-remote.sh`のスクリプト内で実行しているビルド→デプロイ用のスクリプトが以下になります。

```bash:deploy.sh
#!/bin/bash

# スクリプトファイル置き場を起点する
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"

echo 'Restarting Go...'
cd $DIR/webapp/go/

# Goをビルド
/home/isucon/local/go/bin/go build -o isuumo # Goコマンドがあるバスを指定する必要がある

# Webアプリのサービスを再起動する
sudo systemctl stop isuumo.go.service
cp isuumo /home/isucon/isuumo/webapp/go/
cd $DIR
sudo systemctl restart isuumo.go.service
echo 'Restarted!'
```

## 実行したときの様子

1台目のサーバにログインし実行します。

```
$ ./deploy-with-remote.sh
running deploy to this server
From https://github.com/momotaro98/isucon10-q
 * branch            master     -> FETCH_HEAD
Already up to date.
Restarting Go...
Restarted!
running deploy to other servers, isu2 and isu3

[NOTE] Before expecting this process to work well, you need to prepare /etc/hosts for alias isu2, isu3

starting for isu2
From https://github.com/momotaro98/isucon10-q
 * branch            master     -> FETCH_HEAD
Already up to date.
Restarting Go...
Restarted!
finished for isu2
starting for isu3
From https://github.com/momotaro98/isucon10-q
 * branch            master     -> FETCH_HEAD
Already up to date.
Restarting Go...
Restarted!
finished for isu3
```

それぞれのサーバでソースコードがビルドされサービスが再開できることが確認できました。

## 公式AnsibleとPackerを書き換える

isuconユーザーに鍵ペアを生成させるため、ISUCON公式Ansibleファイルを改修し、matsuuさんが作成されたPackerでAMIをビルドするスクリプト郡のレポジトリをフォークし修正することで対応しました。

以下は変更分のコミットのURLです。

Ansible変更分

https://github.com/momotaro98/isucon10-q/commit/12e72469b9b0b4fa11cdca1a0be9e990dc235377

Packer変更分

https://github.com/momotaro98/aws-isucon/commit/2548dc18dba60cdb28f63acdd09fc009377d3b8c#diff-bb2c22d2d66c103511ccd6293a7ebb5acb4f0f70d71fb2020d685ce372111023