Docker on AWS OpsWorksチュートリアル

2014.06.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
6/9〜10に行われたDockerのカンファレンスイベントDockerCon 2014で、AWS OpsWorksの開発者Jonathan WeissさんによるRunning Docker on AWSというセッションが行われました。

動画

スライド

[slideshare id=35673267&doc=dockeronawswithopsworks-140609193626-phpapp02]

スライドを見ると、GitHubにあるDocker Cookbook(Opscode Community Cookbooksにもあります)を用いてOpsWorksのインスタンスでDockerコンテナを実行する雰囲気が紹介されているのですが、実際には一からCookbookを作ってしまっていて、アップデートが辛そうです。元のDocker Cookbookで動かそうとすると一筋縄では行かなかったので、こちらでチュートリアルとして共有しておきます。

0. Docker Cookbookを修正する

Docker CookbookのREADMEには、最近Amazon Linuxがexperimental扱いでサポートされたと記載があるのですが、動きませんでした(汗)ついでに 昨日OpsWorksでサポートされたUbuntu 14.04もやってみたのですが、エラーでダメでした。
しかし、ここでめげずにAmazon Linuxで動かしてみようと試行錯誤し、数点修正して動作させることができたので、フォークしたものをこちらのリポジトリ(otaki-ryuta/chef-docker)で公開し、プルリクエストを送りました。修正点を見たい方はプルリクを参照ください。

1. Dockerイメージとコンテナを定義するCookbookの作成

Docker Cookbookには、DockerをインストールするレシピとDockerの各コンポーネントに対応するLWRP(独自リソースの定義)があるので、実際にイメージやコンテナを操作するためには、LWRPで各リソースを定義する独自Cookbookを作成する必要があります。OpsWorksで使うためにCookbookのディレクトリはルートの1段下に作りつつ、Docker CookbookをBerkshelfでダウンロードするBerksfileと、独自Cookbookから呼び出せるようにmetadata.rbを追加します。今回は個人的にお決まりの、ブログツールGhostを実行するdocker-ghostコンテナを作成、実行するシンプルなコンテナ定義を以下のレイアウトで作ってみました。GitHubにアップしているので、このあとのチュートリアルで試していただくことが出来ます。

opsworks-docker-sample/
├── Berksfile
└── docker-ghost
    ├── attributes
    │   └── default.rb
    ├── metadata.rb
    └── recipes
        ├── deploy.rb
        └── undeploy.rb

簡単に解説します。

/Berksfile

BerkshelfでDocker Cookbookを指定します。今回は、修正した私のGitHubリポジトリを指定していますが、修正が必要なくなれば3行目はcookbook "docker"のみでOKです。Berkshelf 3.0からsource行が必須になったようなので、忘れずに1行目に記述します。

source "https://api.berkshelf.com"

cookbook "docker", github: "otaki-ryuta/chef-docker"

/docker-ghost/metadata.rb

Cookbookのメタデータを記載するファイルです。今回はレシピからDocker CookbookのLWRPを呼び出せるように、dependsを定義しています。OpsWorksでは、同時に実行するライブサイクルイベントのレシピを全部Convergeして実行するようなので、厳密にはdependsなしでも動いたりしますが、個別にレシピを実行するときに必要になるため書きました。

depends "docker"

/docker-ghost/attributes/default.rb

こちらは必須ではないのですが、東京リージョンでdocker pullを実行すると、us-east1のDocker HubからのDockerイメージのダウンロードに時間がかかり、Cookbookのデフォルトのタイムアウト5分を過ぎてしまうことがあるため、image_cmd_timeoutで15分(900s)に調節しました。

default['docker']['image_cmd_timeout'] = 900

/docker-ghost/recipes/deploy.rb

docker pullによるDockerイメージのダウンロードとdocker runでのDockerコンテナの作成、実行をdocker_imageリソース、docker_containerリソースでそれぞれ示します。プロパティを色々指定していますが、多くはdockerコマンドのオプションそのままなので、コマンドを使ったことのある方であれば違和感無く書けると思います。

docker_image 'dockerfile/ghost:latest' do
  action :pull
  notifies :redeploy,'docker_container[ghost]', :immediately
end
docker_container 'ghost' do
  image 'dockerfile/ghost'
  action :run
  port "80:2368"
  detach true
end

/docker-ghost/recipes/undeploy.rb

こちらは、docker stopdocker rmでのコンテナ削除を示すレシピです。が、実行中のコンテナのマッチング処理がうまく行かず、2014/06/28現在はエラーになります。Docker Cookbook本体の話だと思うので、今回は宿題とし、も少し調査してみます。

docker_container 'ghost' do
  action :remove
end

独自Cookbookの作成時にちょっと悩むのが、レシピと各リソースの対応づけです。
同一レシピにdocker_imageリソースとdocker_containerリソースを定義し、docker_imageにnotifiesで依存関係を設定するといい感じにdocker pull→docker runできるので今回は同一レシピにまとめてみました。OpsWorksライフサイクルイベントでdocker pulldocker runを別々に制御したいのであれば、レシピを分けてConfigureイベントにはdocker_imageリソース、Deployイベントにdocker_containerリソースを定義するのもいいかもしれません。

3. OpsWorksの構成

Cookbookの準備ができましたので、続いてOpsWorksを構成して行きます。

3-1. スタックの作成

まずは、基本設定となるスタックを[Add Your First Stack]をクリックし作成します。

docker-opsworks-tutorial01

[Add Stack]画面が表示されたら、「Name」に任意のスタック名(例:「Docker」)と入力、「Region」も任意でOKです(例:Asia Pacific(Tokyo))。「VPC」も任意で構いませんが、Default VPCでない場合には、レイヤー設定で[Public IP Addresses]を有効にします(後述)。「Default SSH Key」はあらかじめ作成済みのSSHキーペアを指定しましょう。

docker-opsworks-tutorial02

フォーム下方の「Advanced >>」をクリックし、「Configuration Management」を表示します。

docker-opsworks-tutorial03

「Use Custom Chef cookbooks」を[Yes]に変更し、「Repository URL」に以下を入力します。

https://github.com/classmethod-aws/opsworks-docker-sample.git

「Manage Berkshelf」を[Yes]に変更し、[Add Stack]をクリックしてスタックが作成されます。

3-2. レイヤーの作成

続いて、Dockerを実行するインスタンスのグループ設定を行う、Dockerレイヤーを作成します。[Add a Layer]リンクをクリックします。

docker-opsworks-tutorial04

「Layer Type」は[Custom]を選択、「Name」と「Short Name」は任意(例:Docker/docker)を入力、[Add Layer]でレイヤーが作成されます。

Dockerレイヤーのインスタンスで実行するレシピを設定します。[Recipes]リンクをクリックします。

docker-opsworks-tutorial06

画面中程の、「Custom Chef Recipes」にある[edit]をクリックし、レシピ選択フォームを表示します。

docker-opsworks-tutorial07

OpsWorksのライフサイクルイベントに対応させるレシピを以下3つ、入力し[+]のクリックで登録します。

ライフサイクルイベント名 レシピ
Setup docker::default
Deploy docker-ghost::deploy
Undeploy docker-ghost::undeploy

docker-opsworks-tutorial08

[Save]をクリックし、保存します。

スタックで選択したVPCがDefault VPCでない場合は、インスタンスにインターネットから直接接続するために[Network]カテゴリーの[Public IP Addresses]を[Yes]に変更しておきましょう。

これで、準備OKです!

4. インスタンスの起動

OpsWorksのメニューから[Instances]をクリックします。

docker-opsworks-tutorial09

[Add an instance]をクリックし、インスタンスを追加します。

docker-opsworks-tutorial10

「Size」は課金が気になるのであれば別のインスタンスタイプでも良いですが、t1.microだとメモリ不足で完走できないことがあるので、m1.small以上がお奨めです。「Subnet」は、インターネットから接続できるPublicなサブネットを選択しましょう。

docker-opsworks-tutorial11

[Add Instance]をクリックするとインスタンスが追加されます。ちなみに、OpsWorksではインスタンスを作成した時点ではまだEC2インスタンスは作成されません。このあとの[start]をクリックすることでEC2インスタンスが起動します。

docker-opsworks-tutorial12

インスタンスの初回起動時には、ライフサイクルイベントのSetup、Configure、Deployに指定したレシピが実行されます。今回はDockerのインストール、Dockerイメージのダウンロード、Dockerコンテナの実行まで一気に進みます。onlineになったらデプロイ完了です!

docker-opsworks-tutorial13

[Public IP]のリンクをクリックしてブラウザからアクセスしてみます。

docker-opsworks-tutorial14

動きました!
SSHでログインし、Dockerの状態も確認してみます。

ikkomon:opsworks-docker-sample ryuta$ ssh ec2-user@54.92.XX.XX
Last login: Fri Jun 27 06:36:31 2014 from XXXX
 This instance is managed with AWS OpsWorks.

   ######  OpsWorks Summary  ######
   Operating System: Amazon Linux AMI release 2014.03
   OpsWorks Instance: docker1
   OpsWorks Instance ID: f7f95f9c-9287-4a21-a7d3-f732ed51b5c1
   OpsWorks Layers: Docker
   OpsWorks Stack: Docker
   EC2 Region: ap-northeast-1
   EC2 Availability Zone: ap-northeast-1a
   EC2 Instance ID: i-XXXXXXXX
   Public IP: 54.92.XX.XX
   Private IP: 172.31.8.131
   VPC ID: vpc-965a82fe
   Subnet ID: subnet-685b8300

 Visit http://aws.amazon.com/opsworks for more information.
[ec2-user@docker1 ~]$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
dockerfile/ghost    latest              77f447f8ef74        5 weeks ago         775 MB
[ec2-user@docker1 ~]$ sudo docker ps
CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS              PORTS                  NAMES
6c5785bdbab1        dockerfile/ghost:latest   bash /ghost-start   18 hours ago        Up 18 hours         0.0.0.0:80->2368/tcp   ghost
[ec2-user@docker1 ~]$

動いていますね!

まとめ

Community Cookbookをベースに、OpsWorksでDockerコンテナを実行する方法をご紹介しました!コンテナの他の操作をするためにはまだ足りないところが多くありますが、足がかりとして見ていただければ幸いです。
次はDockerコンテナの状態を監視する仕組みが欲しいところですね。OpsWorks組み込みのGangliaと連携できたりするとかっこいいなぁ、など妄想は膨らむばかりですw