docker
tutum
DockerDay 13

Docker社の言う"Container as a Service"をやってみた

More than 3 years have passed since last update.

本記事はDocker Advent Calendar 2015の13日目の記事です。


概要

先日の DockerCon Europe 2015において、Docker社は「Container as a Service」という戦略を打ち出しました。詳しくはpublickeyさんの記事を見ていただければと思いますが、ここで紹介されているデモが非常に興味深かったので、再現してみることにしました。


作成するデモの内容

Github > Travis CI > Docker Hub > Tutum のCI/CDパイプラインを作ります。上記記事で紹介されているデモと少し流れが違いますが、やりたいことは同じです。git pushするだけで、テストが実行され、Dockerイメージがビルドされ、最終的にはアプリがデプロイされるという自動化フローを作ります。


Tutumについて

Docker社が今年の10月に買収したコンテナのデプロイサービスです。位置付け的にはKubernetesやMesosなどと同じくコンテナのスケジューリング機能を持つサービスですが、Dockerホストクラスタを直感的なGUIで簡単にクラウド上に用意できることから、より開発者フレンドリーなサービスだと言えると思います。VMから下の管理を全てTutumに任せることができるため、ユーザは開発に集中することができます。まだベータ版であることから、誰でも無料で試すことができます1

Tutumはそれ自体がクラウドを持っているわけではなく、Tutumを通してAWSやDigital Oceanといったクラウドサービス上にDockerホストクラスタを構築し、そのクラスタ上にコンテナを配置していくという形になります。今回はAWSを利用します。


デモに利用するアプリについて

AngularJSのチュートリアルで使用されているangular-phonecatというアプリを利用することにします。これを自分のGithubリポジトリにforkする形で進めていきます。


事前準備

以下の準備をしておいてください。なお、Macを前提とします。


  • Github上でangular-phonecatリポジトリをforkする

  • Homebrewをインストールする

  • Google Chromeをインストールする

  • Docker Toolboxをインストールし、dockerコマンドがたたける状態にする

  • AWSアカウントのアクセスキーとシークレットアクセスキーを取得しておく


    • TutumがEC2等を操作するため、適切な権限が付与されている必要があります。詳しくは公式ドキュメントを参照してください




nodebrewのインストール

angular-phonecatはnode.jsを使用します。以下の手順でnode.jsが使えるようにしておきます。

$ brew install nodebrew

$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile

$ nodebrew install-binary v0.12.9
$ nodebrew use v0.12.9

$ node -v
v0.12.9
$ npm -v
2.14.9


アプリの実行確認

angular-phonecatがどんなアプリなのか、まずは試しておきましょう。forkしたリポジトリをクローンし、アプリを実行してみます。

$ git clone https://github.com/tktk8924/angular-phonecat.git

$ cd angular-phonecat
$ npm install
$ npm start

ブラウザでhttp://localhost:8000/appにアクセスすると、アプリが表示されます。

今度はテストを実行してみます。このリポジトリにはユニットテストとE2Eテストが用意されています。E2Eテストは実際に稼働しているアプリに対してテストが行われるので、アプリは起動したままにしておいてください。

$ npm test

...
Chrome 47.0.2526 (Mac OS X 10.11.1): Executed 5 of 5 SUCCESS (0.077 secs / 0.073 secs)
Firefox 41.0.0 (Mac OS X 10.11.0): Executed 5 of 5 SUCCESS (0.06 secs / 0.058 secs)
TOTAL: 10 SUCCESS

$ npm run protractor
...
7 tests, 11 assertions, 0 failures

上記のように出力されていればテスト成功です。


Dockerコンテナ化

angular-phonecatは最終的にDockerコンテナとしてTutum上にデプロイされることになりますので、Dockerfileを作成してイメージをビルドできるようにします。


Dockerfileの作成

以下の内容でDockerfileを作成します。

FROM node:0.12

WORKDIR /app
COPY ./ .

RUN npm install
RUN node_modules/.bin/bower --allow-root install

EXPOSE 8000
CMD ["npm", "start"]

Dockerfileはクローンしたリポジトリのルートディレクトリに置いてください。

$ tree angular-phonecat -L 1

angular-phonecat
├── Dockerfile
├── LICENSE
├── README.md
├── app
├── bower.json
├── node_modules
├── package.json
├── scripts
└── test


コンテナの起動テスト

イメージをビルドして、アプリがコンテナで動作することを確認します。Dockerfileがあるディレクトリで以下のコマンドを実行します。

$ docker build -t angular-phonecat .

$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
angular-phonecat latest 88fd1db238cb 10 minutes ago 855.8 MB

イメージができたらコンテナを起動してみましょう。以下のコマンドを実行してください。

$ docker run -d -p 8000:8000 --name angular-phonecat angular-phonecat

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
58b967642168 angular-phonecat "npm start" 11 minutes ago Up 10 minutes 0.0.0.0:8000->8000/tcp angular-phonecat

http://{Your Docker Host IP}:8000/appにアクセスして、アプリが表示されることを確認してください。


GithubとTravis CIの連携

まずはGithubとTravis CIを連携させ、git pushに対して自動でテストが実行されるようにしましょう。

Travis CIにログインし、プロファイルページで該当のリポジトリを有効にします。下記のようになればOKです。

Kobito.fWry8b.png


Docker Hub Automated Buildの設定

続いて、Docker Hubに自動ビルド(Automated Build)の設定を行います。Travis CIにてテストが成功したら、さきほど作成したDockerfileを使って自動でイメージがビルドされるようにします。

Docker Hubにログインし、Linked Accounts & ServicesページでGithubとリンクしておきます。途中で聞かれるアクセス権限については、Public and Private(Recommended)の方を選択してください。下記のようになればOKです。

Kobito.DfnPdr.png

次に、画面右上のCreate > Create Automated Buildをクリックします。するとGithubのリポジトリ一覧が表示されるので、angular-phonecatをクリックします。

ここではShort Descriptionにてきとうな文字列を入れ、Createをクリックします。

Kobito.teNDSX.png

これでDocker Hub上にangular-phonecatリポジトリが作成されました。

Kobito.2brQkd.png

Build Settingsに移動して、「When active, builds will happen automatically on pushes.」のチェックを外します。Githubへのプッシュではなく、Travis CIをビルド開始のトリガーにするためです。

Kobito.IFnkas.png

さらに画面下の方にあるBuild TriggerのところのActivate Triggersをクリックします。するとこのイメージのビルドを開始するためのTrigger URLが表示されます。Travis CIからこのURLにHTTP POSTすることで、イメージのビルドが開始されます。

Kobito.lvYzC3.png


Github > Travis CI > Docker Hub のフローを自動化する

それでは、git pushによってDockerイメージがビルドされるところまでを自動化しましょう。

angular-phonecatリポジトリにはTravis CIのビルド設定ファイルである.travis.ymlがすでに含まれていますが、これを以下のように変更したいと思います。


travis.yml

language: node_js

node_js:
- 0.12

before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- npm start > /dev/null &
- npm run update-webdriver
- sleep 3

script:
- node_modules/.bin/karma start test/karma.conf.js --no-auto-watch --single-run --reporters=dots --browsers=Firefox
- node_modules/.bin/protractor test/protractor-conf.js --browser=firefox

after_success: .travis/after_success.sh


after_successscriptのテストが成功したら実行されるスクリプトです。テストが成功したらDocker Hubでイメージをビルドするようにします。下記のスクリプトファイルを作成してください。Trigger URLはご自分の環境に合わせて修正してください。


travis/after_success.sh

#!/bin/bash

if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
curl -i -H "Content-Type: application/json" --data '{"source_type": "Branch", "source_name": "master"}' -X POST {Your Trigger URL}
fi


※このままではTrigger URLはGithub上で公開されることになってしまいます。Trigger URLが知られてしまうと誰でもイメージのビルドができてしまうので危険です。Travis CIではこのような秘密にしておきたいデータを暗号化して記述できるようにする機能がありますので、そちらを利用してください。

$TRAVIS_PULL_REQUESTはTravis CIによって提供される環境変数で、ビルドするコードのリビジョンがプルリクされたものかどうかを判別するために使います。Dockerイメージのビルドはmasterブランチにマージされたコードを使って行いたいのでこのような書き方をしています。

もともとあったscriptsディレクトリは不要なので削除します。また、after_success.shに実行権限をつけます。

$ rm -fr scripts

$ chmod +x .travis/after_success.sh

これで準備は完了です。これまでの変更をコミットしてgit pushしましょう。Travis CIでテストが実行され、Docker Hubでイメージがビルドされるはずです。

$ git add .

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: .travis.yml
new file: .travis/after_success.sh
new file: Dockerfile
deleted: scripts/private/README.md
deleted: scripts/private/old/README.md
deleted: scripts/private/old/ScrapeData.js
deleted: scripts/private/old/format-json.sh
deleted: scripts/private/old/goto_step.bat
deleted: scripts/private/old/goto_step.sh
deleted: scripts/private/old/snapshot.sh
deleted: scripts/private/push-to-github.sh
deleted: scripts/private/retag.sh
deleted: scripts/private/test-all.sh
deleted: scripts/private/update-gh-pages.sh
deleted: scripts/update-repo.sh

$ git commit -m "Add Dockerfile and integration with Docker Hub"

$ git push -u origin master

Travis CIのビルド完了画面

Kobito.Bk2uM1.png

Docker HubのBuild Details画面

Kobito.0twOon.png


Tutum利用準備

ようやくTutumを使うところまで来ました。さっそくログインしてみましょう。Docker Hubのアカウントでログインできます。

ログインしたら、まずはTutumをAWSとリンクさせます。画面右上のアカウントをクリックし、Account infoページに移動してください。

Kobito.TN9ZaJ.png

次に、Amazon Web ServicesのAdd credentialsボタンをクリックして、アクセスキーとシークレットアクセスキーを入力します。これでAWSとのリンクは完了です。

それでは、Dockerホストクラスタを構築します。TutumではDockerホストをNodeと呼んでいます。Launch new node clusterをクリックしてください。

Kobito.ub7cn2.png

とりあえずNode cluster nameだけ入力し、Launch node clusterをクリックします。するとNodeが1台EC2上に構築されます。VPCやセキュリティグループなど、必要な設定はTutumが全てやってくれます。

Kobito.fPw3oh.png

Nodeが構築されました。

Kobito.EdVZV5.png


アプリのデプロイ

Nodeが構築され、コンテナをデプロイする準備ができました。いよいよangular-phonecatアプリをデプロイします。あんまり面白くありませんが、とりあえずangular-phonecatコンテナを1台デプロイしてみることにします。

Tutumでは同じイメージから起動されたコンテナの集まりをServiceと呼びます。Create serviceをクリックしてください。

Kobito.IWrtl4.png

まずはイメージを選択します。Public repositories > Search Docker hubと進んで、さきほど作成した自分のangular-phonecatイメージリポジトリ名を入力します。そしてSelectをクリックしてください。

Kobito.79xK2B.png

続いてServiceの設定です。一箇所だけ、Portsの設定を修正します。Publishedにチェックを入れて、Node portに80を指定します。これでangular-phonecatコンテナに対してインターネット上からポート80番でアクセス出来るようになります。docker run -p 80:8000と同じ意味ですね。修正できたらCreate and deployをクリックしてください。

Kobito.6th9w7.png

これでコンテナのデプロイが始まります。Docker Hubからイメージをpullし、AWS上のNode内にコンテナが起動します。デプロイが完了するとこんな感じの画面が確認できると思います。

Kobito.hI0h7t.png

それではangular-phonecatアプリにアクセスしてみましょう。Endpointsタブを開いてください。

Kobito.sJ1WSa.png

するとService endpointsというところにServiceのURLが表示されています。このURL(に/appを加えて)をブラウザで開いてください。

Kobito.A8Znif.png

angular-phonecatアプリが表示されました。これでアプリのデプロイは完了です。


Docker Hub > Tutum Redeployのフローを自動化する

最後に、Docker HubとTutumを連携させます。Docker Hubにてイメージが更新されたら、さきほどデプロイしたコンテナを自動でRedeploy(コンテナを停止し、最新のイメージをpullして新しいコンテナをデプロイする)します。こうすることですぐに変更が反映されるようになります。

さきほどデプロイしたコンテナ(Service)の画面からTriggersタブに移動します。ここでTriggersというものを登録します。TriggersというのはTutumのAPIの一つであり、外部のプログラムからこのAPIにHTTP POSTすることで、ServiceをRedeployさせることができます。Add trigger欄に任意の文字列を入力し、+Addをクリックします。

Kobito.mwmGOc.png

Triggerが登録されました。このURLをDocker Hub側からPOSTすることで、Serviceの自動Redeployを可能にします。URLはコピーしておいてください。

今度はDocker Hub側にWebhookの設定を追加します。Docker Hub上のangular-phonecatリポジトリページに行き、その中のWebhooksというタブに移動してください。

Kobito.Mt9jAg.png

Add Webhookをクリックし、さきほどコピーしたURLを登録します。

Kobito.10iNOv.png

Kobito.BV0rfA.png

Webhookが登録されました。これでDockerイメージが更新されるたびにコンテナがRedeployされ、変更が自動で反映されるようになります。

お疲れ様でした。これで全ての設定が完了しました。


Git Push!!

アプリに変更を加えてgit pushしてみましょう。app/partials/phone-list.htmlの6行目に以下のコードを追記してください。検索ボックスの上に見出しをつけます。

<h1>Angular Phonecat</h1>

コミットしてgit pushしましょう。

$ git commit -am "Add heading"

$ git push origin master

ServiceのURLにアクセスしてみましょう。下記のような画面になっていれば成功です。

Kobito.v2ftgE.png


おわりに

今回はGithub>Travis CI>Docker Hub>TutumというCI/CDパイプラインを作ってみましたが、このパイプラインの組み合わせは色々なパターンがあると思います。特に企業のプロダクションで利用するということであれば、イメージをprivateにしておきたいはずです。実はTutumにはPrivate Registryの機能があって、直接Tutumにイメージをプッシュすることで、イメージをprivateに利用できるようになっています。

本記事ではDockerコンテナベースの自動化フローの構築を目的としていたので、コンテナ1台立ち上げただけのシンプルな構成でしかTutumを使用しませんでした。しかし、Tutumはすでにプロダクションで利用できるだけの非常に多岐に渡る機能を持っていて、今後注目されていくサービスになることは間違いないでしょう。





  1. 2015年Q3にプロダクションレディーになるということなので今すぐ試しましょう!