テックレポート - TechReport

一覧はこちら

  • now_btn.png
  • ameblo_btn.png

Dockerによる開発環境から本番環境までの一貫した管理 2014年6月

執筆者

執筆者:
劉春来
所属部署:
インフラ&コアテク本部
業務経歴:
2012年株式会社サイバーエージェント入社。プライベートクラウドの監視システムや自動化などのDevOpsを担当。現在はクラウドシステムのUI刷新とPaaS検証に従事。

 

概要

開発環境から本番環境までを Docker にて一貫性のある管理が可能であるかを検証しました。

尚、本レポートは Docker 管理に CoreOS を利用しております。

目次

 

 

1.タイトルについて

1-1.Docker

DockerはLinux Container技術のhigh levelツールです。VMはマシン仮想化に対してLinux Containerはプロセスの仮想化。

2013年3月にopen sourceしてから今や明らかにデベロッパコミュニティのスパースターになっています:

  • githubにdockerのstar数: 13256, Fork数: 2315(2014年6月30日)
  • githubのsearch結果の数:8429(2014年6月30日)
  • googleのtrend

Linux Containerは最新の技術ではないですがなぜDockerは大人気を集まっているのか、LXCとの違いは?

Dockerのcreatorからの回答です

Googleから十年程container運用実績の披露やGoogle Cloudのdockerの真剣対応など、 Docker熱をもっと上がっていると思います。

使いやすさの工夫とエコシステムを形成する能力を考えると、Dockerは今後の主流になっていくと見られる技術です。

1-2.CoreOS

単一ホスト(single-host)でdocker containerを管理するためのprocess managers(https://github.com/dotcloud/docker/blob/master/docs/sources/articles/host_integration.md):

  • systemd
  • upstart
  • supervisor

multi-hostsの場合、dockerを一元管理できるツールが欲しいです(distributed systemd/upstart/supervisorみたい)。

このようなdocker管理ツールは以下の機能を求めています:

  • コンテナの管理
  • 分散スケジューリング

関連ツール:

上記三つツールからCoreOSをpickupしました:

  • Kubernetesは今現在Google Cloud Platformしか使えません。
  • MesOSは独自のcontainer技術をnative使っていますがMarathonというツールでdockerもサポートできるようになります。MesOS自体はサーバー全体のリソースの最適化を目指す、次世代のデータセンター管理ツールと言えます。
  • CoreOSはDockerのための軽量OSです。普通のLinux distributionよりDockerのためのcluster frameworkという位置付けです。service discoveryやdistributed schedulingなどのCluster機能を持つ、osのatomic updateも目玉ポイントです。massive server deployを目指しています。

今回はDockerのためのCoreOSを検証してみよう。

本レポートはコンテナ管理と分散スケジューリングをメインにCoreOSの使い方をhandsonの形で検証してみます。

1-3.開発環境から本番環境まで

DockerはLinux ContainerだからLinux環境にしか動かないのでmac OS Xやwindowsの開発環境に以下の流行ツールはproxy vm(Virtual BoxでLinuxのVMを起動)の形でdockerを使えるようにする:

開発環境にdocker-osxを使う場合、figというツールを使ってdockerの管理をより簡単になります:

  • fig: docker-osxを使ってYAMLファイルを書いて「fig up」コマンドで全部containerをsingle-hostに起動、非常に便利。

上記の開発環境は全部single-hostですがテスト環境と本番環境はほぼmulti-hostです。

multi-hostsのdocker管理は先ほど紹介した通り、CoreOSは得意ですのでsingle-host環境からmulti-hosts環境まで一貫性のあるworkflowできるかなと思いまして、本レポートは CoreOSでsingle-hostからmulti-hostsまでDockerを試すことになります。

つまり、タイトルにある「開発環境から本番環境まで」、大体イコール「single-hostからmulti-hostsまで」。

2.Coreosのhandson

handson_coreosというプロジェクトを作りました。

2-1.環境の準備

このhandsonに開発環境は「mac OS X」を想定しています。 勿論Linuxなら簡単にVirtualBox/Vagrant環境を構築できますのでLinux環境の構築はここに割愛します。

簡単な手順は:

1) VirtualBoxとVagrantのインストール

  1.  VirtualBox(https://www.virtualbox.org/) 4.3.10 or greater.
  2.  Vagrant(http://www.vagrantup.com/downloads.html) 1.6 or greater.

2) single-hostの開発環境:

$ git clone https://github.com/coreos/coreos-vagrant.git
$ cd coreos-vagrant
$ cp user-data.sample user-data
$ vagrant up

以上です。core-01というCoreOSのvmを起動しました。

 

dockerコマンドを使う:

  • `vagrant ssh`でvmにログインしてdockerを使う
  • local laptopで`brew install docker`でdockerのclientをinstall、環境変数のDOCKER_HOSTを設定してlocalから使える

dockerコマンドを直接使えますがCoreOSではdockerコマンドを触らなくでもいいです。

CoreOSにdocker管理や分散スケジューリングをやっているツールはfleetですのでこのHandsonは主にfleetコマンドの使い方です。

local laptopからCoreOSのClusterを管理できますのでlocal laptopの配置:

  • fleetのcommand line clientであるfleetctlをインストール

    $ brew install fleetctl
    NOTES: fleet projectはactive devlopment状態なのでbrewのfleetctlのversionはCoreOSのfleetより古い時WARNINGが出ますので、https://github.com/coreos/fleet/releasesからmac用の最新zipファイルをdownloadしてbuildできます。
  • 設定

    $ ssh-add ~/.vagrant.d/insecure_private_key
    $ export FLEETCTL_TUNNEL=127.0.0.1:2222

以上です。今はlocal laptopからfleetctlコマンドを使えました:

$ fleetctl list-machines
MACHINE     IP      METADATA
e7a4172d... ${IPADDRESS1} -

 

3) multi-hostsの開発環境:

handson02からCoreOSのパワーをフルに発揮できるようにvagrantで三つノードのClusterを構築しましょう。

NOTES: 理想なDockerの使い方はpublic portを指定しないで、インフラを意識しないで自由にdeployできるだから、実の開発環境はsingle-nodeでも複雑な構成が行けます。 このhandsonだけのためにclusterの構築は必要になります。

handson01はsingle-hostで試してもいいですから、今はとりあえずmulti-hostsを構築しなくでもいいです。 後でmulti-hostの環境を構築する時、ここを参照ください。

$ git clone https://github.com/coreos/coreos-vagrant.git
$ cd coreos-vagrant
$ cp user-data.sample user-data
$ echo $(curl https://discovery.etcd.io/new)

上記のcurlコマンドでclusterのためのtokenを取得してuser-dataファイルに以下の行を書き換え:

discovery: https://discovery.etcd.io/<token>

次は起動したいVMの数を設定する:

$ cp config.rb.sample config.rb

config.rbに「$num_instances=3」を追加してから三つCoreOSのVMをlaunchする:

$ vagrant up 

以上です。core-01/core-02/core-03三つVMをlaunchできた。

local laptopのfleetctl設定はsingle-hostと同じ設定で行けます。single-host構築の時すでに設定済みの場合、不要です。 defaultではfleetctlが~/.fleetctl/known_hostsを使っていますのでもしknown_hostsの問題発生したらこのknown_hostsファイルから[127.0.0.1]:2222の行を削除してOKです。

fleetctlコマンドでも確認します:

$ fleetctl list-machines
MACHINE     IP      METADATA
e7a4172d... ${IPADDRESS1} -
34aa3ef6... ${IPADDRESS2} -
ba04d7eb... ${IPADDRESS3} -

2-2.handsonを試す

handson_coreosをgloneして:

$ git clone https://github.com/chuenlye/handson_coreos.git

handsonの詳細:

  • handson01_basic : fleetctlコマンドの使い方
  • handson02_scheduling : fleetctlコマンドで分散スケジューリング機能を試す
  • handson03_using_template : templateファイルを使ってportが異なるcontainerを複数launchする
  • handson04_sidekick_registry : classicな例です。LBはapp serversの情報を動的に取得、自動設定更新
  • handson05_ambassador_pattern : containerの"Dynamic link" を試す
  • handson06_yaml2coreos : fig2coreosツールでYAMLファイルから全部のserviceファイルを生成する

NOTES: clusterを体験するためこのhandsonはmulti-hostのclusterに設計したものですがhandson01/04/06はsingle-hostでも行けます。

2-2-1.handson01_basisc

まずsingle-hostでhandson01を試す:

$ cd handson01_basic

 

ファイルの説明:

$ cat myfirst.service 
[Service]
ExecStart=/usr/bin/docker run --rm --name bbox busybox /bin/sh -c "while true; do echo Hello World; sleep 3; done"
ExecStop=/usr/bin/docker stop -t 3 bbox

serviceの定義にExecStartとExecStopは実行したいdockerコマンドです。

 

次はこのサービスのdeploy:

$ fleetctl start myfirst.service
Job myfirst.service launched on e7a4172d.../${IPADDRESS1}

 

OK, fleetctl list-unitsで結果を確認しましょう:

$ fleetctl list-units
UNIT        STATE       LOAD    ACTIVE  SUB DESC    MACHINE
myfirst.service launched    loaded  active  running -   e7a4172d.../${IPADDRESS1}

serviceは正常にlaunched, running状態です。

 

fleetctl statusで詳細statusと最新10行のlogを確認しましょう:

$ fleetctl status myfirst.service
● myfirst.service
   Loaded: loaded (/run/fleet/units/myfirst.service; linked-runtime)
      Active: active (running) since Sun 2014-06-29 00:26:58 UTC; 5min ago
       Main PID: 1554 (docker)
          CGroup: /system.slice/myfirst.service
                     └─1554 /usr/bin/docker run --rm --name bbox busybox /bin/sh -c while true; do echo Hello World; sleep 3; done
 
                     Jun 29 00:32:17 core-01 docker[1554]: Hello World
                     Jun 29 00:32:20 core-01 docker[1554]: Hello World
                     Jun 29 00:32:23 core-01 docker[1554]: Hello World
                     Jun 29 00:32:26 core-01 docker[1554]: Hello World
                     Jun 29 00:32:29 core-01 docker[1554]: Hello World
                     Jun 29 00:32:32 core-01 docker[1554]: Hello World
                     Jun 29 00:32:35 core-01 docker[1554]: Hello World
                     Jun 29 00:32:38 core-01 docker[1554]: Hello World
                     Jun 29 00:32:41 core-01 docker[1554]: Hello World
                     Jun 29 00:32:44 core-01 docker[1554]: Hello World

 

serviceのlogを「tail -f」のように確認しましょう:

$ fleetctl journal -f  myfirst.service
(結果を省略する)

 

fleetctl destroy *.serviceでclean環境になったら全部のhandsonを繰り返し実行できます

他のfleetctlコマンドはhandson01_basic/README.mdを参照ください

2-2-2.handson02_scheduling

handson02からmulti-hostで試しましょう。multi-host環境の構築は上の「3) multi-hostの開発環境」を参照ください。

ファイルの説明:

  •  app1.service: deploy先を指定します。e.g. core-02のサーバーにapp1.serviceをdeployする
  •  app2.service: 他のserviceと同居。e.g. app2はapp1と同じサーバーにdeployを求める
  •  app3.service: 他のserviceと別居。e.g. app3はapp1と異なるサーバーにdeployを求める
  •  app4.service: customized情報によりdeploy先を決めます。e.g. 「instanceType==large and diskType==ssd」のサーバーにdeployする

 

$ cd handson02_scheduling
$ fleetctl start *.service
$ fleetctl list-units
UNIT        STATE       LOAD    ACTIVE  SUB DESC    MACHINE
app1.service    launched    loaded  active  running app1    17b2ac84.../${IPADDRESS2}
app2.service    launched    loaded  active  running app2    17b2ac84.../${IPADDRESS2}
app3.service    launched    loaded  active  running app3    40172041.../${IPADDRESS3}
app4.service    launched    loaded  active  running app4    17b2ac84.../${IPADDRESS2}

app1.serviceは指定したvmにdeploy、app2はapp1と同居、app3はapp1/app2と別居

詳しくhandson02_scheduling/README.mdを参照ください

2-2-3.handson03_using_template

ファイルの説明:

  • apache.service.template: reuseできるtemplateファイルです。以下の全部serviceファイルはこのtemplateファイルへのsymblic linkです。
     
$ cat apache.service.template
[Unit]
Description=Apache Frontend
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/bin/docker run --rm --name apache_%i -p %i:80 coreos/apache /usr/sbin/apache2ctl -D FOREGROUND
ExecStop=/usr/bin/docker stop -t 3 apache_%i
[X-Fleet]
X-Conflicts=*@%i.service

このhandsonのtemplateファイルに「%i」というsystemdの変数を使ってportを柔軟に指定できるようになりました。

 

fleetctlで試しよう:

$ cd handson03_using_template
$ fleetctl start *.service
$ fleetctl list-units
UNIT            STATE       LOAD    ACTIVE  SUB DESC        MACHINE
apache1@80.service  launched    loaded  active  running Apache Frontend 40172041.../${IPADDRESS3}
apache2@80.service  launched    loaded  active  running Apache Frontend 17b2ac84.../${IPADDRESS2}
apache3@80.service  launched    loaded  active  running Apache Frontend df4dae97.../${IPADDRESS1}
apache4@8001.service    launched    loaded  active  running Apache Frontend 40172041.../${IPADDRESS3}
apache5@8001.service    launched    loaded  active  running Apache Frontend df4dae97.../${IPADDRESS1}
apache6@8002.service    launched    loaded  active  running Apache Frontend 17b2ac84.../${IPADDRESS2}

OKです。六個Apacheサーバーをpublic portを指定してlaunchできました。

2-2-4.handson04_sidekick_registry

このhandsonはload balancerとapp serversの例です。app serverは複数、動的に変動。load balancerは自動設定が欲しい。

handson04はhandson03と違い、public portを指定しないので、ipとport両方の情報はCoreOS/Dockerにお任せ、柔軟性は一番高いですが自動化のためservice discoveryのような自動登録・自動発見は必要です。

ファイルの説明:

  • apache-worker1.registry.service: apache-worker1の「ip + port」情報をお知らせるための補助serviceです。
  • apache-worker1.service: apache container自体。
  • apache-worker2.registry.service
  • apache-worker2.service
  • apache-worker3.registry.service
  • apache-worker3.service
  • lb-config-from-container.service: lb demoです(簡単に最新のworkers情報を出力だけ、本物のlbではない)
  • lb-config-from-host.service: lb demoのもうひとつ実現です。CoreOSのhostから。上記のはlbのcontainer内部から。

fleetctlで試しよう:

まず、lb serverだけをdeploy、logを「journal -f」で監視:

$ cd handson04_sidekick_registry
$ fleetctl start lb*.service
$ fleetctl journal -f lb-config-from-host.service

 

lbのlog:

Jun 29 15:38:30 core-03 sh[4869]: --------- Workers List ----------
Jun 29 15:38:35 core-03 sh[4869]: --------- Workers List ----------

今はworkersがないです。

 

次はworker1とworker2をdeploy、lbのlogを確認:

$ fleetctl start apache-worker{1,2}*.service

 

lbのlogを確認:

Jun 29 15:40:10 core-03 sh[4869]: --------- Workers List ----------
Jun 29 15:40:10 core-03 sh[4869]: ${IPADDRESS1}:49153
Jun 29 15:40:10 core-03 sh[4869]: ${IPADDRESS1}:49154
Jun 29 15:40:15 core-03 sh[4869]: --------- Workers List ----------
Jun 29 15:40:15 core-03 sh[4869]: ${IPADDRESS1}:49153
Jun 29 15:40:15 core-03 sh[4869]: ${IPADDRESS1}:49154

 

最後はworker3をdeploy:

$ fleetctl start apache-worker3*.service

 

lbのlogを確認:

Jun 29 15:41:15 core-03 sh[4869]: --------- Workers List ----------
Jun 29 15:41:15 core-03 sh[4869]: ${IPADDRESS1}:49153
Jun 29 15:41:15 core-03 sh[4869]: ${IPADDRESS1}:49154
Jun 29 15:41:15 core-03 sh[4869]: ${IPADDRESS1}:49155
Jun 29 15:41:20 core-03 sh[4869]: --------- Workers List ----------
Jun 29 15:41:20 core-03 sh[4869]: ${IPADDRESS1}:49153
Jun 29 15:41:20 core-03 sh[4869]: ${IPADDRESS1}:49154
Jun 29 15:41:20 core-03 sh[4869]: ${IPADDRESS1}:49155

OKです。load balancerは自動的にworkers情報を取得できました。

このhandsonはapp serverのpublic portを指定しないのでsingle-hostの開発環境でも行けます。

2-2-5.handson05_ambassador_pattern

Ambassador_pattern: 今のdocker linkはsingle-host限定なので、multi-hostsでのdynamic linksはambassador_patternです。 例えば、app serverはdb serverへアクセスするためDBのipとportを知る必要です。ただDockerの世界、動的変動は普通なので動的に設定更新を以前より更に求めている。

簡単に言うと、以前はapp -> network -> dbですが、ambassador_patternは(app -> appのambassador) -> network-> (dbのambassador -> db)です。appとdbをlinkingする部分(設定やportのpublish)をambassadorのcontainerにお任せ、 つまり動的に設定更新はambassadorにお任せしました。技術的にはambassadorはport forwardingだけです。containerの形でservice containerの補助containerという役割と思います。

dockerのcreatorよりAmbassador patternはdockerのもう一つ貢献です。

このhandsonはoriginally from: Dynamic Docker links with an ambassador powered by etcd

ちょっと複雑なのでより簡単な例を考えています。

2-2-6.handson06_yaml2coreos

ここまでCoreOSで一番簡単なケースからより複雑なケースまで体験してみましたが使いやすさについては:

  • サービスファイルを書くためにsystemdの知識は必要
  • 簡単なケースでも複数サービスファイルを書くのは必要

紹介した「fig」より使いにくい(figはひとつだけのYAMLファイルを書いて、「fig up」でsingle-hostに自動deploy)。

使いやすさを改善するためfig2coreosというツールを検証しました。

使い方は:

figのYAMLファイルを書く --> fig2coreosでsystemdのservice fileへ変換 --> fleetctlで生成したservice filesをdeploy

ひとつのYAMLファイルだけを書く、systemdの知識も不要、より便利になります。

 

このhandsonには三つの例があります。一番簡単の例を例えます:

$ cat quickstart.yaml
web:
  image: ctlc/wordpress
  ports:
    - 80:80
  environment:
    DB_USER: root
    DB_PASSWORD: qa1N76pWAri9
  links:
    - db
db:
  image: ctlc/mysql
  ports:
    - 3306:3306
  environment:
    MYSQL_DATABASE: wordpress
    MYSQL_ROOT_PASSWORD: qa1N76pWAri9

systemdのservice fileに変換:

$ fig2coreos myapp quickstart.yaml quickstart
$ cd quickstart
db-discovery.1.service
db.1.service
web-discovery.1.service
web.1.service

 

ただfig2coreosの制限があります:

今現在fig2coreosもsingle-hostしか使えませんのでmulti-host環境に行けないです。 multi-hosts環境での使いやすさを改善するため、multi-hostsの対応は必要になります。

 

とりあえずsingle-hostの開発環境にはfig2coreosのツールでCoreOSを使うと便利です。

3.まとめ

 

  • single-host環境なら「fig」あるいはfig2coreosを使ってCoreOSでdockerを楽しめる、便利さはよい。
  • multi-hosts環境ならCoreOSはDockerのcluster管理ツールとして大きく期待できると思います。
  • single-host環境からmulti-hosts環境までCoreOSで一貫性のあるdocker管理には使いやすさの改善は必要、yaml2coreosのようなツールは解決案のひとつ。

CoreOSはまだActive development状態なので本番環境で使いたいならversion問題の取扱など要注意です。 

4.参考文献