手軽な自動化から高度な管理まで。サーバー設定におけるシェルスクリプト、Ansible、cloud-initの特徴と選択肢
はじめに
西藤です。
AWSをはじめとするクラウドの恩恵で、たとえばウェブサイトを稼働させるWEBサーバーを立ち上げることはとても簡単です。ニーズによって自由な台数、自由なサイズのインスタンスを立ち上げることができます。
私自身もAWSのEC2を使って、動作検証用のWEBサーバーを立ち上げることはよくあり、まさにクラウドの恩恵を受けている一人です。
しかし、インスタンスの内部の設定はどうでしょうか?
ウェブサイト用のインスタンスを立ち上げた後には、次のような作業が必要です。
- ウェブサーバーのインストール
- ウェブサイトのコンテンツの配置・初期設定
- ウェブサーバーの起動・自動起動設定
そして、業務利用であれば、これらの作業はインスタンスの数が増えていくにつれて、その作業は大変なものになっていくほか、手動で行なっていたは設定のミスも発生しやすくなるものでしょう。
そういった課題を解決するために、さまざまな自動化ツールの活用が重要になってきます。
今回は、その中でも
- シェルスクリプト(ユーザーデータ)
- Ansible
- cloud-init
の3つを比較し、それぞれの特徴をまとめてみたいと思います。
やりたいこと・前提
今回、各ツールを使って自動化を行うにあたって、以下のような前提を設定します。
- Amazon EC2でインスタンスを立ち上げる
- OSはLinuxマシンを使用する
- サーバー内のタイムゾーンをAsia/Tokyoに設定する
- Nginxをインストールし、Webサーバーとして稼働させる
- index.htmlを任意の内容に書き換え、Webサーバーにアクセスしたら表示されるようにする
こういったシナリオをそれぞれのツールでどのように実現できるのか見ていきましょう。
シェルスクリプトでの設定内容
AWSのEC2インスタンスをインスタンスの起動時に「ユーザーデータ」の設定で任意の内容でシェルスクリプトを実行できます。
マネジメントコンソール上での詳細な利用方法の説明は省きますが、冒頭の前提を満たすためのユーザーデータは以下のようになるでしょう。
この内容で動作を検証してみます。
#!/bin/bash
# タイムゾーンをAsia/Tokyoに設定
timedatectl set-timezone Asia/Tokyo
# パッケージを最新化
yum update -y
# Nginxをインストール
yum install -y nginx
# Nginxを起動 および 自動起動設定
systemctl start nginx
systemctl enable nginx
# index.htmlを書き換え
echo 'Hello, World! This is Cloud Provisioning Test!' > /usr/share/nginx/html/index.html
シェルスクリプトの実行結果
ユーザーデータで設定された処理のログはEC2インスタンス起動時のログである/var/log/cloud-init-output.log
を開くことで確認できます。
その結果は以下のようになりました。(ログを全文記載すると冗長なので画像で記載します)
各ソフトウェアのインストールなどが問題なく実行された様子がログから確認できます。
そして、ブラウザからウェブサーバーにアクセスすると
のように問題なく表示されました。
(「安全ではありません」との表示が出ておりますが、今回はHTTP(80)でのアクセスで検証しているためです。)
シェルスクリプトでの設定は、その内容を理解できる人も多いかと思いますので、手軽に使える手段と言えるでしょう。
Ansibleでの設定内容
次に紹介するAnsibleは、構成管理ツールの1つです。設定はYAML形式で記述されます。
以下は、今回のシナリオを実現するための設定ファイルです。
---
- hosts: localhost
become: yes
tasks:
# タイムゾーンをAsia/Tokyoに設定
- name: set timezone
timezone:
name: Asia/Tokyo
# パッケージを最新化
- name: update yum
yum:
name: '*'
state: latest
# Nginxをインストール
- name: install nginx
yum:
name: nginx
state: latest
# Nginxを起動 および 自動起動設定
- name: start nginx
service:
name: nginx
state: started
enabled: yes
# index.htmlを書き換え
- name: write index.html
copy:
content: |
Hello, World! This is Cloud Provisioning Test!
dest: /usr/share/nginx/html/index.html
Ansibleは実行用の環境を別途設けて、複数台のサーバーに対して設定を一斉送信する際などに使われるイメージが強いツールですが、今回はローカルから実行する形としました。
Ansibleの実行結果
Ansibleの実行結果は以下のようになりました。
[ec2-user@ip-10-0-4-60 ~]$ ansible-playbook site.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] ****************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************
ok: [localhost]
TASK [set timezone] *************************************************************************************************************
changed: [localhost]
TASK [update yum] ***************************************************************************************************************
ok: [localhost]
TASK [install nginx] ************************************************************************************************************
changed: [localhost]
TASK [start nginx] **************************************************************************************************************
changed: [localhost]
TASK [write index.html] *********************************************************************************************************
changed: [localhost]
PLAY RECAP **********************************************************************************************************************
localhost : ok=6 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ログを見ると、各ステップごとの進捗がわかりやすく表示されています。
シェルスクリプトをユーザーデータで実行する例と比べると、Ansibleの実行環境を手配する必要があり手軽さは劣る部分があるのですが、複数台のサーバーに対して展開する時などに利便性を発揮することが期待できます。
そして、ウェブページも期待通りのページの表示となっています。
cloud-initでの設定内容
最後に、私が今回の記事を書きたいと思ったきっかけであるcloud-init
を使ってみましょう。
AWSにて使用する際には、EC2インスタンスのユーザーデータ欄に以下のような設定を記載します。
#cloud-config
# タイムゾーンをAsia/Tokyoに設定
timezone: Asia/Tokyo
# パッケージを最新化
package_update: true
# nginxをインストール
packages:
- nginx
# nginxを起動し、自動起動設定
runcmd:
- systemctl start nginx
- systemctl enable nginx
# index.htmlを書き換え
write_files:
- path: /usr/share/nginx/html/index.html
content: |
Hello, World! This is Cloud Provisioning Test!
owner: 'nginx:nginx'
defer: true
cloud-initの実行結果
cloud-init
の実行結果は以下のようになりました。
ユーザーデータの時と同様の結果になっています。
ウェブサーバーとしても期待通りのページの表示となっています。
YAML形式で記述しつつ、シェルスクリプトベースのユーザーデータと同じことができていることがわかります。
シェルスクリプトとの違い
YAML形式で記述できる、という違いだけでは、ただ単に「ユーザーデータ」欄で指定できるツールの違いになってしまいますので、cloud-init
の特徴をもう少し掘り下げてみましょう。
公式ドキュメントには以下のような記述があります。
Cloud-init is the industry standard multi-distribution method for cross-platform cloud instance initialisation. It is supported across all major public cloud providers, provisioning systems for private cloud infrastructure, and bare-metal installations.
https://cloudinit.readthedocs.io/en/latest/
プラットフォームを問わずに、インスタンスの起動設定を行うためのツールであることがわかります。
そして、今回はその中の例としてLinuxのOSの違いへの対応を取り上げてみたいと思います。
冒頭のシェルスクリプトの例では、yum
コマンドを使ってパッケージのインストールを行っていますが、Amazon Linux 2023においてパッケージマネージャーとしてyum
コマンドが使えるため有効な内容でした。
しかし、Ubuntuの場合はapt
コマンドを使う必要があります。Amazon Linux 2023用のシェルスクリプトをそのまま使うことはできません。apt
コマンドベースのシェルスクリプトを別途用意する必要があります。
一方で、cloud-init
の場合は、「どのパッケージをインストールしたいのか」という期待される状態を記述する形になるので、Amazon Linux 2023用に準備した記述を活かすことができます。
Ubuntu用の記述は以下のようになります。
#cloud-config
# タイムゾーンをAsia/Tokyoに設定
timezone: Asia/Tokyo
# パッケージを最新化
package_update: true
# nginxをインストール
packages:
- nginx
# nginxを起動し、自動起動設定
runcmd:
- systemctl start nginx
- systemctl enable nginx
# index.htmlを書き換え
write_files:
- path: /var/www/html/index.html
content: |
Hello, World! This is Cloud Provisioning Test!
owner: 'nginx:nginx'
defer: true
write_files
の部分だけUbuntu用のNGINXのデフォルト値の差が出てしまっておりますが、それ以外の部分はすべて同じ記述で対応できていることがわかります。
この値についてもNGINXのデフォルトのドキュメントRootのパスを明示的に指定する設定を入れるようにすれば、Amazon Linux 2023とUbuntuで共通した設定を使う運用ができます。
このように、cloud-init
はYAMLでAnsibleライクに記述することができながら、実行環境の準備も必要なく、プラットフォームの差を吸収してくれるため「いいとこ取り」ができるツールと言えるでしょう。
しかし、公式のドキュメントは充実しているものの、ユーザーの体験談などが少なく、他の2つのツールと比べると具体的なハウツーを得るのが難しくより複雑な処理を実現したい場合にはそのことが障壁となる可能性があります。
3者比較
それぞれの特徴をまとめると以下のようになります。
シェルスクリプト
- ユーザーデータ欄に記述するだけで実行できる
- 記述内容がシェルスクリプトなので、理解しやすい
- OSの違いによって記述方法を変える必要がある
Ansible
- 設定内容をYAML形式で記述できる
- 実行環境を別途用意する必要がある
- 複数マシンに対して一斉適用を行うときに利点がある
cloud-init
- ユーザーデータ欄に記述するだけで実行できる
- 記述内容をYAML形式で記述できる
- プラットフォームの差を吸収してくれるので、OSの違いによって記述方法を変える必要がない
- 他のツールと比べると、情報収集が難しい
まとめ
以上、シェルスクリプト、Ansible、cloud-initの3つのツールを使って、同じ内容の設定を行う方法を紹介しました。
各ツールは、手軽さと、機能の豊富さなど、それぞれに特徴があります。
個人的には、YAMLベースでありながら実行環境の準備などもいらないcloud-init
が、マッチしている状況が多く感じるのですが、利用者それぞれの状況に応じて使い分けができると思います。
本記事が、サーバー設定時の自動化のヒントになれば幸いです。
参考
Ansible: https://www.ansible.com/
cloud-init:https://cloudinit.readthedocs.io/en/latest