やれ仮想化だ、やれクラウドだと、様々な単語が流行っていく中で、管理者が構築・運用しなければいけないサーバの数はどんどん増えています。今回はUbuntu Serverを「スケール」させるうえでとても便利なデプロイツールである「Juju」を紹介します。
Jujuとは
「Juju 」はCanonicalが開発している「サービスオーケストレーションツール」です。公式サイトやホワイトペーパーでは抽象的な表現が多すぎて「お前は何を言っているんだ」状態なJujuですが、簡単に言うと「Amazon EC2やOpenStack、Azure、LXC、MAASといったサービス上にUbuntu Serverを用意し、そこに既存の各種サービスをデプロイするための自動化ツール」です。
Ubuntuにはもともと強力なパッケージ管理システムであるAPTが存在します。APTシステムを使えば多種多様なソフトウェアの依存関係の解決やインストール、アップグレードを非常に簡単に行えます。しかしながら、ソフトウェアのインストールだけでサービスの構築作業が完了するとは限りません。他のソフトウェアとの連携やサイト特有の設定は、インストール後に管理者が自分で行う必要があります。
たとえば、WordPressでブログサイトを構築する場合を考えましょう。Ubuntuには「wordpressパッケージ 」が存在するので、これをapt-getコマンドでインストールすればWordPressのインストールは完了です。ところがこのままではWordPressは動作しません。なぜならWordPressのデータを保存するデータベースを用意していないからです[1] 。実際にWordPressを使うためには、Ubuntuのヘルプ にもあるようにデータベースパッケージのインストールや設定も別途「手動で」行う必要があります。
このような従来「手動で」行っていた作業を、自動化することがJujuの目的です。パッケージという個々のパートを、ひとつの調和のとれたサービスに「編成」するために、「 サービスオーケストレーションツール」と呼ばれています[2] 。
[1] なぜwordpressパッケージにデータベースのパッケージが依存していないかと言うと、データベースは必ずしもwordpressパッケージをインストールするマシン上に存在する必要はないからです。このためwordpressパッケージをインストールするとき、「 mysql-serverパッケージ」のインストールが「提案」されますが、自動的にはインストールされません。
Chefとの違い
サービス構築の自動化という意味では、ChefやPuppetを思い浮かべる方も多いでしょう。JujuとChefやPuppetは、標準でできることやその実現方法、ポリシーなど細かい違いは数多く存在しますが、「 サービスの構築で、できるだけ楽をしたい」という点では同じ方向を向いていますし、「 UbuntuにはJujuがあるからChefは使えない」というわけでもありません。
よってUbuntu上でどちらを使うかは、やりたいことや好みに合わせて選べば良いでしょう。あえてChefとの違いを挙げるなら、次のような相違点が存在します。
Jujuは構成スクリプトをBashやPythonなど好きな言語を使って記述できる
Jujuは構築の中でも、サービス間の動的な「Relation」や「Scale」の設定の自動化に注力している
Chefが数多くのプラットフォームに対応しているのに対して、JujuはUbuntuしかサポートしていない
もちろんJujuとChefを共存させることも可能です。Ubuntuインスタンスの生成とChefを動かすためのセットアップまでをJujuで、そこから先をChefで構築するという方法で、既存のChefのコードを流用することもできます。
Charm(構築手順書)を共有する
サービス構築にあたっての手順書を、Jujuでは「Charm」と呼びます。どんなパッケージをインストールするのか、インストール後にどんな設定を行うのか、設定が変更されたときはどうするのか、という手順はもちろんのこと、他のCharmに紐付けられたときにどういう動作をすべきかということもCharmに記載します。
これらの構築手順書は、再利用できて初めて真価を発揮するものです。もちろん個々の環境に特化したCharmでもかまわないのですが、より多くの環境でより汎用的に使えるCharmを作っておけば、サービス構築の試行錯誤に時間を割くことなく新しいサービスを運用できます。
そこでCanonicalでは「Charm Store 」というCharm登録・公開サイトを作成しています。ここで公開されたCharmはJujuコマンドから簡単に再利用できます。さらに他のUbuntuのソフトウェアやパッケージと同様にLaunchpad上でのバージョン管理やチケット管理もできるのです。
インストール方法
以前、「 Ubuntu Serverをさらっと用意する方法 」で、少しだけJujuの導入方法について触れました。今回はもう少し詳しく、そして最新のJujuに沿った形でインストール方法を紹介します。
Jujuを使ううえで最低限必要なのは、「 UbuntuもしくはOS Xがインストールされたマシン(クライアント) 」と「SSHの鍵」 、「 デプロイ先のマシン(サーバ) 」の3つです[3] 。
クライアントにはJujuを使うためのコマンド群をインストールします。明示的にJujuをインストールする必要があるのはこのクライアントだけです。
サーバとして使うマシンは物理マシンでも仮想マシンでもかまいません。仮想マシンは各種クラウドサービスを利用できますし、LXCを使ってクライアントとサーバを同じマシン上で実行することもできます。物理マシンを使う場合はMAAS を用いてUbuntuがインストールされている必要があります。
もしまだ持っていないようなら、まずはSSH鍵を作成しておきましょう。
$ ssh-keygen -t rsa -b 2048
この鍵は、Jujuで構築したサーバにログインするために必要となります。
次にJujuをクライアントにインストールします。Jujuは頻繁にリリースされており、できるだけ最新のJujuを使うためにもPPAからインストールしてください。
$ sudo add-apt-repository ppa:juju/stable
$ sudo apt-get update && sudo apt-get install juju-core
最後にJujuの設定ディレクトリと設定テンプレートを生成しておきましょう。次のコマンドは「~/.juju/」ディレクトリを作成し、そこに設定ファイルのひな形を保存します。
$ juju init
これでJujuのインストールは完了です。
[3] Jujuは最近、MacのOS X上にHomebrewを使ってインストールできるようになりました。詳しいインストール方法は公式のドキュメント を参照してください。ここではUbuntuのインストール方法のみを紹介しますが、インストール方法以外はOS X版と違いはありません。
はじめてのデプロイ
Jujuは「juju」コマンドを使って、各種操作を行います。今回はJujuで最もよく使われるサンプルである「Amazon EC2上にWordPressサービスを公開する」方法を使って、Jujuの基本的な使い方を紹介します。
ここでデプロイ先にAmazon EC2を使うのはそれが一番お手軽だからです。Jujuはサービスをデプロイするとき、まずはじめにUbuntuのインスタンスを作成します。インスタンスの生成には、デプロイ先に合わせてAmazon EC2やOpenStackのAPIを使ったり、LXCで仮想マシンをローカルに作成したりします。
Amazon EC2であればとりあえずアカウント(と支払い能力)さえあれば、他に環境を用意する必要はないので、はじめてのデプロイ先として選びました[4] 。もしこの手順を試す場合は、あらかじめAmazon Web Serviceのアカウントを作成しておいてください 。
デプロイ先の設定を行う
デプロイ先は「~/.juju/environments.yaml」ファイルを編集することで設定します。詳しい設定項目は公式ドキュメントの「Configuring for Amazon AWS 」を参考にしてもらうとして、今回はaccess-keyとsecret-key、regionの3つだけを変更しましょう。
## https://juju.ubuntu.com/get-started/amazon/
amazon:
type: ec2
admin-secret: (ここは変更せず)
# globally unique S3 bucket name
control-bucket: (ここは変更せず)
# override if your workstation is running a different series to which you are deploying
# default-series: precise
# region defaults to us-east-1, override if required
region: ap-northeast-1
# Usually set via the env variable AWS_ACCESS_KEY_ID, but can be specified here
access-key: (Access Key IDを入力)
# Usually set via the env variable AWS_SECRET_ACCESS_KEY, but can be specified here
secret-key: (Secret Keyを入力)
access-keyとsecret-keyには、AWSのコントロールパネル にある「Access Keys」からAccess Key IDとSecret Keyが記載されたファイルをダウンロードして、そこに書かれたIDをそれぞれ設定します。
regionはインスタンスを生成するリージョンです。東京リージョンだと「ap-northeast-1」になります。
2行目の「amazon」は環境を指定するラベルです。environments.yamlには複数のデプロイ先に合わせて複数の環境を記述できます。jujuコマンド実行時に「-e ラベル」を指定すると、その環境にデプロイできます。
オプションを指定しないときに使われる環境はswitchコマンドで確認・設定できます。
$ juju switch
(標準で使われる環境のラベル名が表示される)
$ juju switch amazon
(標準の環境を“amazon”に変更する)
bootstrapノードをデプロイする
Jujuの管理サービスであるbootstrapノードをデプロイしましょう。Jujuでこれから操作するサービスは、今後すべてこのbootstrapノード経由で設定や情報の取得を行います。このため、Jujuを使う場合は最低でも1つのインスタンスが必要になります。
$ juju bootstrap
ちなみにbootstrapノードさえ立ち上がれば、あとはどのクライアントからでも、Jujuが管理するサービスの設定変更が可能です。
今回の設定ではAmazon EC2を使うことになっているので、このコマンドはAmazon EC2上にUbuntuのクラウドイメージを使ってインスタンスを生成します。つまりここから先は料金が発生することに注意してください。試しにAWSのコンソールを確認すると、m1.smallのインスタンスが1つ立ち上がっていることがわかるはずです。
bootstrapノードが立ち上がるまで、数十秒から数分かかることがあります。立ち上がるとstatusオプションで状態を確認できます。
$ juju status
environment: amazon
machines:
"0":
agent-state: started
agent-version: 1.13.2
dns-name: ec2-54-248-35-144.ap-northeast-1.compute.amazonaws.com
instance-id: i-b48a7ab1
instance-state: running
series: precise
hardware: arch=amd64 cpu-cores=1 cpu-power=100 mem=1740M root-disk=8192M
services: {}
machinesには各インスタンスが表示されます。今のところbootstrapノードだけなので、インスタンスは1台、サービスは空です。agent-stateが「started」になったらすべての準備が完了した状態です。
WordPressに必要な各種サービスをデプロイし公開する
ここまできて、ようやくWordPressをデプロイできます。WordPressにはデータベースが必要です。今回はMySQLを使いますので、次のような作業を行います。
WordPressをデプロイする
MySQLをデプロイする
WordPressとMySQLを紐付ける
WordPressサービスを公開する
ここは単純に4つのコマンドを実行するだけです。
$ juju deploy wordpress
$ juju deploy mysql
$ juju add-relation wordpress mysql
$ juju expose wordpress
deployコマンドは新規にインスタンスを生成し、そこに指定したサービスをデプロイします。add-relationは2つのサービスを紐付けるためのコマンドです。これにより、WordPressはMySQL(がインストールされたインスタンス)をデータベースとして認識し、MySQL上にWordPressを動かすために必要な設定が行われます。exposeでサービスを公開します。Amazon EC2の場合なら、80番ポートの開放などもこのタイミングで行います。
これだけで、WordPressのサービス構築は完了です。実際にどのような設定が行われているかはstatusコマンドで確認しましょう。
$ watch juju status
bootstrapと同様に各インスタンスのデプロイ完了までは少し時間がかかります。deployコマンド直後にstatusを実行してもまだ準備はできていないかもしれません(たとえばagent-stateは「pending」の状態) 。watchコマンドで継続的にstatusを実行させることで、各インスタンスが徐々に設定されていくことがわかります。
最終的に「wordpress/0」のagent-stateが「started」になったらデプロイ完了です。少し長いですが、statusの結果を見てみましょう。
environment: amazon
machines:
"0":
agent-state: started
agent-version: 1.13.2
dns-name: ec2-54-248-35-144.ap-northeast-1.compute.amazonaws.com
instance-id: i-b48a7ab1
instance-state: running
series: precise
hardware: arch=amd64 cpu-cores=1 cpu-power=100 mem=1740M root-disk=8192M
"1":
agent-state: started
agent-version: 1.13.2
dns-name: ec2-54-238-44-109.ap-northeast-1.compute.amazonaws.com
instance-id: i-fa8a7aff
instance-state: running
series: precise
hardware: arch=amd64 cpu-cores=1 cpu-power=100 mem=1740M root-disk=8192M
"2":
agent-state: started
agent-version: 1.13.2
dns-name: ec2-54-248-147-25.ap-northeast-1.compute.amazonaws.com
instance-id: i-f88a7afd
instance-state: running
series: precise
hardware: arch=amd64 cpu-cores=1 cpu-power=100 mem=1740M root-disk=8192M
services:
mysql:
charm: cs:precise/mysql-27
exposed: false
relations:
cluster:
- mysql
db:
- wordpress
units:
mysql/0:
agent-state: started
agent-version: 1.13.2
machine: "2"
public-address: ec2-54-248-147-25.ap-northeast-1.compute.amazonaws.com
wordpress:
charm: cs:precise/wordpress-16
exposed: true
relations:
db:
- mysql
loadbalancer:
- wordpress
units:
wordpress/0:
agent-state: started
agent-version: 1.13.2
machine: "1"
open-ports:
- 80/tcp
public-address: ec2-54-238-44-109.ap-northeast-1.compute.amazonaws.com
まずはmachinesのところから。今回はbootstrapに加えて、wordpressとmysqlの3台をデプロイしたので、インスタンスの数も3つになっています。後述するように、この台数はdeployコマンド時のオプションでコントロール可能です。
さらに今回はservicesの項目が増えています。こちらはサービス名ごとに関係や使われたCharmなどがリストアップされています。「 units」にはそのサービスで使われている個々のインスタンスが表示されます。今回はmysqlもwordpressも1つずつしかデプロイしていないので、それぞれunitは1つです。machineのところには使われているインスタンスの番号が表示されていることがわかるでしょう。
さらにwordpressについてはopen-portsに開放したポート番号として80/tcpが表示されています。Amazon EC2の場合、ここに表示されているポートが、exposeコマンドによってセキュリティグループのInboundルールに追加されます。
wordpressサービスにはpublic-addressとしてインスタンスのアドレスが表示されています。そこへWebブラウザでアクセスすれば、WordPressの初期画面が表示されるはずです。
サービスの設定変更
ここまでの作業で無事、Amazon EC2上にWordPressサービスを公開できました。説明自体は長かったのですが、実際に行った作業はほとんどないはずです。ここからはさらに、クラウドの本領発揮であるスケールする方法について紹介しましょう。
スケールアウトする
まかり間違って(?)公開しているWordPressサービスへのアクセス数が増大してしまいました。そこでWordPressのインスタンスを2つ増やすことにして、サービスをスケールアウトしましょう。
$ juju add-unit -n2 wordpress
add-unitは指定したサービスを提供するインスタンスを増やすコマンドです。-nオプションに増やしたいインスタンスの数を指定します。少し待ってからstatusコマンドでmachinesのインスタンスの数とwordpressサービスのunitsの数を確認してみましょう。どちらも2つずつ増えているはずです。
さらに追加したインスタンスのpublic-addressにアクセスしてみてください。どちらのインスタンスもデータベースは同じmysqlサービスにつながっているので、元のインスタンスと同じコンテンツが表示されるでしょう。
リバースプロキシを追加する
これだけだとWordPressサーバが3つになっただけなので、これらをリバースプロキシでつないでみましょう。HAProxyを導入するCharmがあるのでそれを使います。
$ juju deploy haproxy
$ juju add-relation haproxy wordpress
$ juju expose haproxy
HAProxyは外部に公開するサービスなので、最後にexposeしています。
インスタンスタイプを指定する
単純にdeployコマンドを実行した場合、インスタンスタイプはm1.smallが選択されます。CPUやメモリを増強したい場合、deploy時にconstraints を使用することでインスタンスタイプを変更できます。
現在のインスタンスの設定値はstatusコマンドで確認できます。たとえばmysqlサービスで使われているインスタンスの設定値を見てみましょう。
$ juju status mysql
environment: amazon
machines:
"2":
(中略)
hardware: arch=amd64 cpu-cores=1 cpu-power=100 mem=1740M root-disk=8192M
このようにm1.smallインスタンスが使われていることがわかります。
deploy時にCPUコアの数を4に、メモリのサイズを8Gバイトに設定するには、次のオプションを指定します。
$ juju deploy --constraints "cpu-cores=8 mem=8G" mysql
スケールダウンする
比較的アクセスが落ち着いてきて、インスタンスを3つから1つに減らしても大丈夫な状態になりました。そんなときは、destroyコマンドでインスタンスを削除できます。
手順としてはまずdestroy-unitでunitを削除してから、destroy-machineでインスタンスの本体を削除します。今回はwordpress/1のマシン番号が3、wordpress/2のマシン番号が4なので、それぞれ次のように実行します。
$ juju destroy-unit wordpress/1
$ juju destroy-unit wordpress/2
$ juju destroy-machine 3
$ juju destroy-machine 4
これでインスタンスの数はスケールアウトする前の状態に戻っているはずです。最初のうちはAmazon EC2のコンソールから実際にインスタンスがterminatedになっているかどうかも確認しておくと良いでしょう。
デプロイするインスタンスを指定する
これまでdeployコマンドを実行する度にEC2のインスタンスが生成されてきました。しかしサービスの種類によってはわざわざインスタンスを分ける必要がないものも存在します。もし既に起動済みのインスタンスに別のサービスをデプロイしたいなら、--toオプションを使います。
たとえばwordpressをマシン番号1にデプロイしたあと、mysqlも同じマシンにデプロイするには、次のコマンドを実行します。
$ juju deploy --to 1 mysql
これにより、すべてのサービスを1つの仮想マシン上で動作させることも可能です。
サービスを削除する
個々のインスタンスではなくサービスそのものが不要になった場合は、destroy-serviceで一括して削除できます。
$ juju destroy-service wordpress
$ juju destroy-service mysql
$ juju destroy-service haproxy
インスタンス自体は削除されないので、個別にdestroy-machineを実行してください。bootstrapも含めてすべて削除する場合は、destroy-environmentを実行します。
$ juju destroy-environment
これによりすべてのインスタンスが削除され、最初にbootstrapコマンドを実行する前の状態に戻ります。
うまく動かないときは
最後に、期待どおりに動作しないときに調べるべきポイントを説明します。
verboseオプションを使用する
そもそもインスタンスが生成されない場合は、jujuコマンドにverboseオプション(-v)を付けて再度実行してみましょう。大抵の場合は、~/.juju/environments.yamlの設定ミスですので、何らかの構文エラーが表示されるはずです。
debug-logコマンドを使用する
debug-logコマンドには、jujuの各インスタンスの処理メッセージが表示されます。ここに何らかのエラーが表示されている可能性があります。
juju statusを確認する
サービス構築中にエラーが発生した場合は、agent-statusが「error」になり、エラーの理由が表示されることがあります。
$ juju status
(中略)
agent-state: error
agent-state-info: 'hook failed: "config-changed"'
これを足がかりにJujuコマンドのオプションが間違っていないか、Charmに何かの問題がないかを調べると良いでしょう。
ちなみにCharmの本体は~/.juju/charmcache/にZIP形式のアーカイブとしてキャッシュされます。これを適当な場所に展開して、実際に何をやっているか確認することができます。
sshでインスタンスに接続する
Jujuで作ったインスタンスはあらかじめsshログインできるようになっています。インスタンスのホスト名に対して、ユーザ名「ubuntu」でアクセスすれば、インスタンスを直接調べることができます。
ちなみに、jujuコマンドを使えばマシン番号やサービス名でもログインできます。ユーザ名も指定する必要がないので、こちらのほうが便利でしょう。
マシン番号0にログインする場合:
$ juju ssh 0
wordpress/1インスタンスにログインする場合:
$ juju ssh wordpress/1
インスタンスの中身は普通のUbuntuなので、apt-getコマンドでパッケージを追加インストールするなどの作業も行えます。
問題が解決したら
何らかの方法で無事に問題が解決した場合、Jujuが処理中の作業を再開させる必要があります。たとえばwordpress/1の問題が解決したのなら、次のコマンドを実行してください。
$ juju resolved wordpress/1
これにより、statusコマンドの状態が変化するはずです。
まとめ
Jujuを使えばクラウド時代のUbuntu Serverの構築を、非常にシンプルな操作で行えるようになります。とくにマシンの台数が増えれば増えるほど、この操作の違いが大きく効いてくるはずです。
もちろん、自分でCharmを書くことができればその利便性はさらに増大します。折しも現在、Charm Championship というコンテストが開催されていますので、大会への参加を動機付けに、普段よく使うサービスのCharmを書いてみてはいかがでしょうか。