EC2インスタンスを自動構成する(1/2)

クラウド・コンピューティング」採用の正否は、様々な管理・保守作業の自動化の巧拙によって決まるような気がしています。せっかくクラウドを使っても、今までと同じように人手をかけていてはクラウドのメリットを十分に活かせているとは言いがたいでしょう。典型的には、クラウド・ベンダーの用意したAPIを通じてリソースの制御を行うアプローチがありますが、自動化に使えるのはAPIだけではありません。

ここでは、AWS標準で追加料金なしに利用できるCloudInitAWS CloudFormationの2つを使って、EC2の構成作業の一部を自動化する方法を考えてみます。
CloudInitでは、User Dataとして渡した情報などを元にEC2インスタンス起動時に様々な作業を自動的に行わせることができます。AWS CloudFormationでは、JSONで記述した内容に従って、単体のEC2インスタンスに留まらず、AWS各サービスの様々なリソースをアトミックに統御することができます。また、リソース作成時に動的に変更したい内容についてはパラメータとしてJSONから括りだしておき、実行時にGUIから簡単に指定したりといったことも可能です。

単純な例として、SSHtelnetインスタンスにログインすることなく、フォワーディング・プロキシ・サーバーを構成してみたいと思います。

プロキシ構成の手順

ここで、プロキシ・サーバーのソフトウェアとしては標準的なSquidを利用しますが、とりあえずであっても実際に使えるようになるまで以下のような手順が必要となります。

  1. YUMレポジトリーからSquidをインストール
  2. squid.confの編集
    1. 自分のIPアドレスを、Squidへのアクセスを許可するIPアドレスとして設定
    2. Squidがlistenするポート番号を設定
  3. 再起動時に自動でSquidデーモンが立ち上がるように設定

Squidのインストールだけであれば、あらかじめインストール済みのAMIを作成したり、起動時に最新版のインストールを実行するスクリプトを組み込んだAMIを作成すると言った代替手段がありますが、その場その場で異なるIPアドレスを動的に設定するのは面倒です。

CloudInitによってこれらの構成を一括して自動的に実行してみます。

CloudInitによるEC2インスタンスの自動構成

CloudInitUbuntu由来のソフトウェアですが、EC2上の標準Linux環境であるAmazon Linuxでも利用できます。CLoudInitで自動実行できる項目と設定例は、CloudInitのソースツリーに含まれていますが、securityに関するアップデートを初回起動時に自動適用すると言ったことも可能です。(Amazon Linuxの場合はデフォルトの動作です。)

CloudInitではUserDataにシェルスクリプトを指定して任意の操作を実行することもできるのですが、パッケージの追加といった典型的な作業であれば

yum install foo -y

といったコマンドを書き連ねることなく、所定の書式にしたがって簡単に指定できます。今回は、Squidの構成のために、yumパッケージのインストールと、squid.confの編集のためのコマンド実行の双方の機能を利用します。

パッケージのインストール(packages)

非常に単純ですが、以下のようにしてcloud-configにパッケージを指定すると自動的にインストールされます。ディストリのパッケージング・システム(Amazon Linuxの場合はYum)を利用しているので、その時点での最新バージョンがレポジトリーから取得され、依存関係も面倒を見てもらえます。

#cloud-config
packages:
- squid
コマンドの実行(runcmd)

コマンドを実行するためには、先ほどのpackagesと同様にcloud-configにruncmdに続けてコマンドを記述します。Squidの設定ファイルであるsquid.confのうち、アクセスを許可するネットワークを指定するacl localnet src行と、Squidがlistenするポート番号を指定するhttp_portを編集します。行の指定方法にエレガントさを欠きますが、sedによってソースIPアドレスを挿入し、ポート番号を書き換えます。また、デーモンの起動と、インスタンスを再起動した場合も自動的にSquidが起動するための設定も行います。

runcmd:
- [sed, -i, "/RFC 4291/a acl localnet src AAA.BBB.CCC.DDD/32", /etc/squid/squid.conf]
- [sed, -i, "/^http_port/c http_port 8080", /etc/squid/squid.conf]
- [chkconfig, squid, "on"]
- [service, squid, start]

リストとして渡すために、カンマで区切るのがポイントです。

User Dataは16384バイトに制限されているため、指定できる内容にも制限が生じますが、内容をgzipで圧縮したり外部のURLから読み込むといった手段にも対応しています。

EC2インスタンスの起動時にUser Dataを指定する方法

GUIであるManagement Consoleを利用する場合、EC2を起動する際のウィザード内で以下のようにUser Dataを直接指定できます。(ファイルからアップロードすることも可能です。)
Management ConsoleからUser Dataを指定する

packagesとruncmdはつなげて書けるので、User Data全体としては以下の内容をウィザードに貼り付けることになります。

#cloud-config
packages:
- squid

runcmd:
- [sed, -i, "/RFC 4291/a acl localnet src AAA.BBB.CCC.DDD/32", /etc/squid/squid.conf]
- [sed, -i, "/^http_port/c http_port 8080", /etc/squid/squid.conf]
- [chkconfig, squid, "on"]
- [service, squid, start]

CLI(EC2 API tool)のec2-run-instancesコマンドの"-d"や"-f"オプションでもUser Dataを指定することができます。コマンドについて詳しくはCLI Reference

Squid(CloudInit)の動作確認

以上のようにUser Dataを指定して起動したEC2インスタンスのPublic DNSないしグローバルIPアドレスをプロキシ・サーバーとして指定してください。ブラウザでcheckip.amazonaws.comにアクセスするとHTTPリクエストのソースIPアドレスが表示されますが、自分の端末のアドレスの代わりにEC2インスタンスグローバルIPが表示されていればプロキシ経由でアクセスできていることが確認できます。

期待通りに動作しない場合、CloudInitの動作をチェックするためには以下のログが参考になります。

/var/log/messages

Sep  7 14:48:38 ip-nnn-nnn-nnn-nnn [CLOUDINIT] 2011-09-07 14:48:38,638 - cloud-init-cfg[INFO]: cloud-init-cfg ['package-setup']
Sep  7 14:48:53 ip-nnn-nnn-nnn-nnn yum: Installed: libtool-ltdl-2.2.10-1.8.amzn1.i686
Sep  7 14:48:53 ip-nnn-nnn-nnn-nnn yum: Installed: perl-DBI-1.609-4.4.amzn1.i686
Sep  7 14:48:54 ip-nnn-nnn-nnn-nnn yum: Installed: 7:squid-3.1.10-1.7.amzn1.i686
Sep  7 14:48:54 ip-nnn-nnn-nnn-nnn [CLOUDINIT] 2011-09-07 14:48:54,923 - cloud-init-cfg[INFO]: cloud-init-cfg ['runcmd']
(中略)
Sep  7 14:48:55 ip-nnn-nnn-nnn-nnn [CLOUDINIT] 2011-09-07 14:48:55,688 - cloud-init-run-module[INFO]: cloud-init-run-module ['once-per-instance', 'user-scripts', 'execute', 'run-parts', '/var/lib/cloud/data/scripts']
Sep  7 14:48:56 ip-nnn-nnn-nnn-nnn squid[949]: Squid Parent: child process 952 started

最後でSquidデーモンがが無事に起動しています。

/var/log/cloud-iinit.log

(略)
Dependencies Resolved

================================================================================
 Package           Arch      Version                    Repository         Size
================================================================================
Installing:
 squid             i686      7:3.1.10-1.7.amzn1         amzn-updates      1.9 M
Installing for dependencies:
 libtool-ltdl      i686      2.2.10-1.8.amzn1           amzn-main          31 k
(中略)
Starting squid: .[  OK  ]

こちらは標準出力の結果です。その他の処理が行われた後、YumによるSquidパッケージのインストールと、デーモンの起動が行われている様子が分かります。

まとめ

ここまでで、CloudInitを使うことで一切サーバーにログインすることなくSquidによるプロキシ・サーバーを構築することができました。ただ、自分のネットワークアドレスなどを元にUser Dataをイチイチ編集して指定し直す作業は不便です。また、Security Groupの設定などでは、Squidの構成に使ったソースIPやポート番号と行ったパラメーターを改めて指定する必要があり、いかにも二度手間です。

冒頭で書いたように、次回はAWS CloudFormationというサービスを使って、自分のネットワーク・アドレスとポート番号を、GUIであるManagement Consoleから指定できるパラメータとして括りだして、User Dataを直接編集せずにproxyを起動できるようにします。また、EC2インスタンス上の設定だけではなく、Security Groupの構成もCloudFormationによって自動化します。