虎の穴ラボ技術ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

EC2オートスケーリングで社内ツールサーバーを毎日作り直そう!

はじめに

こんにちは!虎の穴ラボの鷺山です。

業務の効率化のために社内用ツールサーバーを作って活用することは、よく行われる取り組みだと思います。
弊社も同様にツールサーバーで既製ツールや自製ツールのホスティングを行い、さまざまなタスクを効率化しています。

ただ、このようなツールサーバーは手動でセットアップされることが多いと思います。 SSHで接続し、コマンドを実行して構築するような方法です。 また、ツールサーバーは(顧客向けの本番サーバーと比べて)優先度が低く、バックアップの対応が後回しになりがちです。

その結果、何らかのトラブルでツールサーバーが使えなくなると手動で一から環境を再構築し直すことになり、復旧に手間と時間を要してしまいます。近年はランサムウェアなどの脅威も増加しており、社内用サーバーであっても攻撃リスクを軽視できなくなっています。

そこで今回は、この問題を解決する一つの方法として「AWSのEC2オートスケーリングを使ってツールサーバーを毎日自動で作り直す」アプローチを紹介します。

目次

前提

  • ツールサーバーはAWSのEC2を使用します。
    • 使用するAMIはAmazon Linux 2023です。
  • 1台のサーバーで複数のツールをホスティングします。
  • 各ツールのリソースはGitHubリポジトリに登録済みであると仮定します。

全体像

本記事で紹介する仕組みの全体像を示します。

本記事で紹介する仕組みの全体像
本記事で紹介する仕組みの全体像

今回のアプローチの利点

今回紹介する「ツールサーバーを毎日自動で作り直す」アプローチにはいくつかのメリットがあります。

  • いつでも再構築が可能な環境の実現
    • 環境を自動で再構築する仕組みを導入することで、トラブル発生時にも素早く復旧できるようになります。
    • 手作業による構築ミスを防止できます。
    • スクリプトや設定ファイルの不備があっても、毎日の再構築プロセスで早期発見できます。
  • セキュリティリスクの軽減
    • 毎日サーバーを新しくすることで、不正アクセスやランサムウェアによる攻撃の影響を最小化できます。
      • 仮に攻撃を受けても、翌日には新しい環境に置き換えられるため、継続的な被害を防げます。
    • 常に最新のOS、パッケージ、ライブラリを利用可能な状態を維持できます。
      • アップデートの遅れによるセキュリティホールを未然に防ぐことができます。

実現のためのポイント

「ツールサーバーを毎日自動で作り直す」仕組みを実現するための技術的なポイントは以下の3点です。

  1. 各ツールのセットアップコマンドの明確化
  2. EC2起動テンプレートの活用
  3. EC2オートスケーリングによる「サーバー再構築」のスケジュール化

次のセクションからそれぞれの詳細を解説します。

1. 各ツールのセットアップコマンドの明確化

各ツールのセットアップや起動に必要なコマンドを事前に明確化しておきます。
(例: npm install && npm run dev など)

あるいはDockerやDocker Composeで実行できるように、Dockerfiledocker-compose.yml を整備しておきます。

2. EC2起動テンプレートの活用

EC2の起動テンプレートに設定できるユーザーデータ(本記事では以降「初回構築スクリプト」と呼びます)を使うと、サーバーの初回起動時に指定したコマンドを自動実行できます。

ユーザーデータ(初回構築スクリプト)
ユーザーデータ(初回構築スクリプト)

これを使って、EC2起動後の初期化プロセス内で各ツールのセットアップと起動が自動で完了するようにします。

  1. まず、スクリプトの冒頭で必要なパッケージをインストールします。
  2. 次に、各ツールのリソースをGitHubリポジトリから取得 (git clone) します。
  3. そして「事前に明確化したセットアップコマンド」を使って、各ツールをセットアップして起動します。

以下は初回構築スクリプトの記述例です。

#!/bin/bash
set -euox pipefail

# システムアップデートと必要パッケージのインストール
dnf update -y
dnf install -y docker git

# Dockerのセットアップ
systemctl start docker
systemctl enable docker
usermod -aG docker ec2-user

# Docker Composeのセットアップ
su - ec2-user -c '
  COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4)
  mkdir -p ~/.docker/cli-plugins
  curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o  ~/.docker/cli-plugins/docker-compose
  chmod +x ~/.docker/cli-plugins/docker-compose
'

# GitHubへの接続準備
su - ec2-user -c '
  aws ssm get-parameter --name "github-deploy-key" --query "Parameter.Value" --output text --with-decryption > ~/.ssh/github_deploy_key
  aws ssm get-parameter --name "github-ssh-config" --query "Parameter.Value" --output text > ~/.ssh/config
  chmod 600 ~/.ssh/github_deploy_key
  chmod 600 ~/.ssh/config
  ssh -o StrictHostKeyChecking=accept-new git@github.com || true
'

# ツールの起動
su - ec2-user -c '
  git clone --depth 1 git@github.com:XXXXX/my-tool-server.git
  cd my-tool-server
  docker compose up -d
'

それぞれのステップについて詳しく解説します。

2.1. 事前準備

#!/bin/bash
set -euox pipefail
  • ユーザーデータのシェルスクリプトは #!/bin/bash から始めます(※ Bashを使う場合)。
  • set -euox pipefail はスクリプトを安全に実行し、デバッグしやすくするための設定です。
  • Amazon Linux 2023の場合、初期化プロセスのログは /var/log/cloud-init-output.log に出力されます。このログからスクリプトの実行結果を確認できます。
# システムアップデートと必要パッケージのインストール
dnf update -y
dnf install -y docker git
  • システムアップデートを実施して、必要なパッケージ(DockerやGitなど)をインストールします。
  • もし他に必要なパッケージがあれば、ここに追加することができます。
dnf install -y docker git nodejs ...

2.2. DockerやDocker Composeのセットアップ

# Dockerのセットアップ
systemctl start docker
systemctl enable docker
usermod -aG docker ec2-user
# Docker Composeのセットアップ
su - ec2-user -c '
  COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4)
  mkdir -p ~/.docker/cli-plugins
  curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o  ~/.docker/cli-plugins/docker-compose
  chmod +x ~/.docker/cli-plugins/docker-compose
'
  • DockerおよびDocker Composeをセットアップしています。
    • Docker Composeは su でユーザーを切り替えて ec2-user にインストールしています。
    • 参考: Where to get Docker Compose
  • DockerやDocker Composeを使わない場合はスキップ可能です。

2.3. GitHubへの接続準備

ツールサーバーのリソースをGitHubリポジトリから取得するための準備をします。
対象がプライベートリポジトリの場合は、必要な認証を通す必要があります。

本記事ではデプロイキーによる認証方法を紹介します。ローカルで公開鍵と秘密鍵のペアを生成し、公開鍵を対象のGitHubリポジトリに、秘密鍵をAWS Systems Managerに登録します。

ローカルでの公開鍵と秘密鍵の生成には ssh-keygen コマンドなどを使用します。

ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/github_deploy_key

生成した公開鍵は、対象のリポジトリにデプロイキーとして登録します。

デプロイキーの登録
デプロイキーの登録

秘密鍵の方は、Systems Managerのパラメータストアに登録します。秘密鍵は秘匿性が高いので「安全な文字列 (SecureString)」として登録します。 パラメータ名は github-deploy-key を設定します。

github-deploy-key パラメータ
github-deploy-key パラメータ

あわせて、GitHubへのSSH接続に必要な設定ファイルもパラメータストアに登録します。パラメータ名は github-ssh-config を設定します。

Host github.com
  HostName github.com
  IdentityFile ~/.ssh/github_deploy_key
  User git

github-ssh-config パラメータ
github-ssh-config パラメータ

そして、初回構築スクリプトでGitHubへの接続設定を以下のように記述します。

# GitHubへの接続準備
su - ec2-user -c '
  aws ssm get-parameter --name "github-deploy-key" --query "Parameter.Value" --output text --with-decryption > ~/.ssh/github_deploy_key
  aws ssm get-parameter --name "github-ssh-config" --query "Parameter.Value" --output text > ~/.ssh/config
  chmod 600 ~/.ssh/github_deploy_key
  chmod 600 ~/.ssh/config
  ssh -o StrictHostKeyChecking=accept-new git@github.com || true
'
  • su コマンドでユーザーを切り替えて、ec2-user ユーザーとして実行します。
  • aws ssm コマンドで、パラメータストアに登録した github-deploy-keygithub-ssh-config を読み出し、それぞれをファイルパス ~/.ssh/github_deploy_key~/.ssh/config に保存します。
    • 「安全な文字列」を読み出す際は、--with-decryption オプションが必要です。
  • chmod 600 コマンドで、保存したファイルに適切な権限を設定します。
  • ssh -o StrictHostKeyChecking=accept-new git@github.com で github.com を known_hosts に登録します。

なお aws ssm コマンドの実行には、起動テンプレートのIAMインスタンスプロフィールに ssm:GetParameter の許可ポリシーを設定する必要があります。

{
    "Effect": "Allow",
    "Action": "ssm:GetParameter",
    "Resource": [
        "arn:aws:ssm:ap-northeast-1:123456789012:parameter/github-deploy-key",
        "arn:aws:ssm:ap-northeast-1:123456789012:parameter/github-ssh-config"
    ]
}

2.4. 各ツールのセットアップと起動

各ツールのリソースをGitHubから取得し、セットアップと起動を行います。

リポジトリのクローンは以下のコマンドで実行します(対象のリポジトリを XXXXX/my-tool-server と仮定します)。

git clone --depth 1 git@github.com:XXXXX/my-tool-server.git

リポジトリをクローンしたら「事前に明確化したセットアップコマンド」を使って、各ツールをセットアップして起動します。

ツールがDocker Composeに対応している場合は、以下のように記述します。

su - ec2-user -c '
  git clone --depth 1 git@github.com:XXXXX/my-tool-server.git
  cd my-tool-server
  docker compose up -d
'

Node.jsアプリケーションの場合は、たとえば以下のように記述します。

su - ec2-user -c '
  git clone --depth 1 git@github.com:XXXXX/my-tool-server.git
  cd my-tool-server
  npm install
  nohup npm run dev > output.log 2>&1 &
'

参考: cron の設定方法

cron を使用して、ツールサーバーで何らかの処理をスケジュール実行させるケースは多いと思います。
初回構築スクリプトでそれを設定する方法を紹介します。

タイムゾーンの設定

まず、サーバーのタイムゾーンをローカル時間に合わせておきます。 AWSのEC2はデフォルトがUTC時間になっており、ローカル時間と異なると設定ミスや混乱を招く可能性があります。 以下は日本時間に合わせるための例です。

timedatectl set-timezone Asia/Tokyo

cronie のセットアップ

Amazon Linux 2023はデフォルトではcronを使用できません。このため、同機能を提供するcronieパッケージをインストールする必要があります。

dnf install -y cronie

インストール後は、crondサービスを起動する必要があります。

systemctl start crond
systemctl enable crond

crontab エントリーの登録

初回構築スクリプトの中でcrontabのエントリーを記述して登録できます。

su - ec2-user -c "
  echo \"0-58/2 * * * * echo 'Hello!' >> ~/greetings.txt\" >> mycron
  echo \"1-59/2 * * * * echo 'Goodbye!' >> ~/greetings.txt\" >> mycron
  crontab mycron && rm mycron
"

あるいは、crontabの設定ファイルをあらかじめGitHubリポジトリに登録しておき、それを使うこともできます。

su - ec2-user -c '
  git clone --depth 1 git@github.com:XXXXX/my-tool-server.git
  ...
  crontab my-tool-server/mycron
'

まとめると以下のようになります。

timedatectl set-timezone Asia/Tokyo

dnf install -y cronie
systemctl start crond
systemctl enable crond

su - ec2-user -c "
  echo \"0-58/2 * * * * echo 'Hello!' >> ~/greetings.txt\" >> mycron
  echo \"1-59/2 * * * * echo 'Goodbye!' >> ~/greetings.txt\" >> mycron
  crontab mycron && rm mycron
"

3. EC2オートスケーリングによる「サーバー再構築」のスケジュール化

EC2オートスケーリングの予定されたアクション (Scheduled Scaling) と前述の起動テンプレート(初回構築スクリプト)を組み合わせることで、「ツールサーバーを毎日自動で作り直す」仕組みを構築できます。

まず、ツールサーバー用のオートスケーリンググループを作成します。このとき、起動テンプレートには前のセクションで作成したものを指定します。

オートスケーリンググループを作成後、オートスケーリングタブ内の予定されたアクションから、ツールサーバーの構築と破棄をスケジューリングできます。スケジュールは予定されたアクションを作成するから追加できます。

ここで、希望するキャパシティ(サーバー台数)を「業務時間外は 0」「業務時間内は 1」に設定することで、夜間はサーバーを落としつつ、毎朝の始業時にサーバーが自動構築される仕組みを実現します。
これにより、毎日のサーバー再構築プロセスを自動化すると同時に、夜間の稼働コストも削減できます。

以下は「21時に停止」して「9時に起動」するための設定例です。
(セットアップにかかる時間を考慮して開始時間を8時55分に設定しています。)

21:00に停止して08:55に起動する設定例
21:00に停止して08:55に起動する設定例

⚠注意点

オートスケーリングを使用すると、EC2インスタンスのIPアドレスが固定されなくなる点にご注意ください。固定のURLが必要な場合はロードバランサーの導入などが必要になります。

まとめ

起動テンプレートとオートスケーリングを活用した「ツールサーバーを毎日自動で作り直す」仕組みの構築方法を紹介しました。
すでにGitHubにツール類を登録してある場合には、導入しやすいアプローチなのではないかと思います。

本記事が皆様の社内環境効率化の一助になれば幸いです!

採用情報

虎の穴ラボでは一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧ください。
toranoana-lab.co.jp