Ubuntu Weekly Recipe

第288回デプロイツール「Juju」使って大魔導師を目指そう

やれ仮想化だ、やれクラウドだと、様々な単語が流行っていく中で、管理者が構築・運用しなければいけないサーバの数はどんどん増えています。今回は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]⁠。

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のインストールは完了です。

はじめてのデプロイ

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を書いてみてはいかがでしょうか。

おすすめ記事

記事・ニュース一覧