cloud-initでVPSの初期構築を自動化する

※本ページには広告(アフィリエイトプログラム等)が含まれます。

VPSを何台も借りていると、毎回同じ手順(ユーザー作成、SSH鍵登録、パッケージ更新、nginxインストール…)を手作業で繰り返すのが馬鹿らしくなってくる。cloud-initを使えば、VPS起動時にこの初期セットアップを自動で走らせられる。手順書をYAML1枚に落とし込んでおけば、次に同じ構成のサーバーを立てる時も同じファイルを渡すだけで済む。

cloud-initとは

cloud-initはクラウド環境向けの標準的なインスタンス初期化ツールで、AWS・GCP・さくらのクラウド/VPSなど多くのプロバイダがサポートしている。仕組みとしては、インスタンス起動時にプロバイダのメタデータサービス経由で「user-data」と呼ばれる設定ファイルを読み込み、それに従ってユーザー作成やパッケージインストールなどの初期化処理を1回だけ実行する。

重要なのは「初回起動時に一度だけ」という点。2回目以降のブートでは(設定を変えない限り)何もしない。サーバー構成を変更するための常時稼働ツール(AnsibleやChef)とは役割が違う、あくまで初期プロビジョニング専用の仕組みだと理解しておくとよい。

user-data(cloud-config)の基本

user-dataはYAML形式で書くのが一般的で、これを「cloud-config」形式と呼ぶ。ファイルの先頭に必ず次の1行を書く。

#cloud-config

これが無いとcloud-initはただのスクリプトやテキストとして扱ってしまい、意図した初期化が走らない。よくあるハマりどころなので最初に確認する癖をつけておくといい。

実際のcloud-config例

Debian 12を想定した、実務でよく使う項目をまとめたサンプルを載せる。ユーザー作成、SSH鍵登録、sudo権限付与、パッケージ更新、nginxインストール、タイムゾーン設定、任意コマンドの実行、ファイル書き出しを1本にまとめている。

#cloud-config
timezone: Asia/Tokyo

users:
  - name: deploy
    groups: sudo
    shell: /bin/bash
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... deploy@local

package_update: true
package_upgrade: true

packages:
  - nginx
  - mariadb-server
  - unzip
  - git

write_files:
  - path: /etc/nginx/conf.d/keepalive.conf
    content: |
      keepalive_timeout 65;
    owner: root:root
    permissions: '0644'

runcmd:
  - systemctl enable nginx
  - systemctl restart nginx
  - ufw allow OpenSSH
  - ufw allow 'Nginx Full'
  - ufw --force enable

usersセクションでは既存のrootとは別にデプロイ用ユーザーを作り、パスワードログインではなくssh_authorized_keysで鍵認証のみ許可するのが定石。sudo: ['ALL=(ALL) NOPASSWD:ALL']は初期構築を素早く終わらせるための設定なので、本番運用では必要に応じてパスワード必須に絞るなり範囲を狭めるなりの調整をしたほうがいい。package_update/package_upgradeはそれぞれapt update/apt upgrade相当で、packagesリストのインストール前に走る。write_filesは任意のファイルを任意のパーミッションで書き出せるので、nginxやアプリの設定ファイルを事前に仕込んでおくのに便利。runcmdは文字通り任意のシェルコマンドをリストの順番通りに実行する。

ログを確認する

cloud-initが期待通り動いたかどうかは、まず状態コマンドで確認する。

cloud-init status

status: doneと出れば正常終了。status: errorならどこかの処理でコケているので、詳細ログを見にいく。

less /var/log/cloud-init.log
less /var/log/cloud-init-output.log

cloud-init.logはcloud-init自体の詳細な処理ログ(モジュールの実行順序やエラーのスタックトレース)、cloud-init-output.logruncmdなどで実行したコマンドの標準出力・標準エラーがそのまま流れ込んでくるファイルだ。YAMLの構文ミスを疑うときは前者、runcmdのコマンドが失敗していないか疑うときは後者を見ると早い。

さくらVPSのスタートアップスクリプト

さくらのVPSにはコントロールパネルから「スタートアップスクリプト」を登録し、サーバー作成時に選択・実行できる機能がある。これは内部的にはcloud-initのuser-dataとして渡される仕組みで、上で書いたようなcloud-config YAMLをそのまま登録しておけば、新規にVPSを作成するたびに自動でユーザー作成〜パッケージインストールまで終わった状態で起動してくる。毎回同じ手順を手作業でやり直す必要がなくなるので、複数台構成やテスト用途で作り直しが多い環境では特に効果が大きい。

冪等ではない点に注意

cloud-initは「初回起動時に1回だけ」実行される設計なので、一度実行済みのインスタンスに対してuser-dataを書き換えても再実行はされない。動作確認のために何度もやり直したい場合は、cloud-init cleanで実行済み状態をリセットしてからcloud-init initcloud-init modules --mode=finalを叩くか、素直にVPSを作り直したほうが早い場合が多い。

cloud-init clean --logs
cloud-init init
cloud-init modules --mode=final

本番のサーバーで気軽にcloud-init cleanを実行するのは避けたほうがいい。usersモジュールなどが再実行されて意図しないユーザー再作成が走る可能性があるので、検証は使い捨てのVPSで行うのが安全だ。

まとめ

cloud-initを使えば、VPSの初期セットアップを手作業からYAML1枚の宣言的な設定に置き換えられる。ユーザー作成・SSH鍵登録・パッケージインストール・簡単な設定ファイル配置くらいまでならこれで十分カバーできる。「初回起動時のみ実行」という前提を理解した上で、さくらのVPSならスタートアップスクリプトに登録しておくと、次にサーバーを作る時の作業がぐっと楽になる。

読んで頂いて有り難うございます!