【Live版Ubuntuへ移行】Dockerを公式チュートリアル”Get Started with Docker”で学ぶ【中編】

一連の流れのある【中編】になります。 ここまできてようやくチュートリアルのPart3が進められるような状況になりました。今回からはOSをChromeOSからUbuntu 18.02 LTSに変更して行っていきます。

【参考】

uepon.hatenadiary.com

uepon.hatenadiary.com

uepon.hatenadiary.com

以前のエントリの内容と重複はありますが、チュートリアルを進めていきます。 ここまで飛ばしていいという部分には【ここまで読み飛ばしていいです】という目印をつけておこうと思います。

Get Started, Part 3: Services

ここではServiceに関して学ぶことになります。

docs.docker.com

事前準備

事前準備としてはDockerのインストールは当然のことながらPart1とPart2を行ってきた環境(コンテナ)があることが必要です。

加えてDocker Composeのインストールが必要になります。Mac用のDockerデスクトップとWindows用のDockerデスクトップにはプレインストールされていますが、Linux系は別途インストールする必要があります。以下のサイトを参考にインストールを行います。

docs.docker.com

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

また、Part2で作成したfriendlyhelloイメージをレジストリにpushして公開することが必須になります。(ここではその共有イメージを使います。) 以下のようにDockerのイメージを実行し、http://localhost:8080/という感じでアクセスできることは確認しておいてください

※原文は4000ポートを使用していますがChromeOSではアクセスがNGなので8080に変更してありますので注意です。

【一般形】

$ docker run -p 8080:80 username/repo:tag

【前回の例で以下のように動作していました(ここでいうhogeは各自のユーザ名に変更してください)】

$ docker run -p 8080:80 hoge/get-started:part2

サービスとは?

このPartではアプリケーションを拡張し負荷分散を行います。そのために分散アプリケーションの階層を1レベル上に上げ、サービスという概念が必要になります。

階層的にはこんな感じ

  • Stack
  • Services (←いまここ)
  • Container (part2(前回)でやった部分)

分散アプリケーションはサービスという概念で構成されていて、例えばビデオ共有サイトでは、データベースサービス、ビデオをトランスコーディングするサービス、フロントエンド用のサービスから構成されているようなイメージになります。

サービスはコンテナから構成されます。その設定でイメージの実行方法、使用するポート、コンテナのレプリカをいくつ実行する必要があるかなどの体系化を行う必要があります。これらの設定を行う場合にはdocker-compose.ymlを記述することでこれらの定義、実行、拡張することが可能になります。

docker-compose.ymlを書いてみる

docker-compose.ymlでコンテナの動作を設定してみます。

以下に記載してymlファイルdocker-compose.ymlとして作成します。 このとき、Part2で作成したイメージをレジストリにpushしていることを確認して、自分の作成した username/repo:tagをイメージの詳細に置き換えてこの.ymlを更新します。 以下の例ではhoge/get-started:part2として設定しています。またポートも4000から8080へ変更しています。

【変更前(原文のまま)】

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "4000:80"
    networks:
      - webnet
networks:
  webnet:

【今回の変更後】

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: hoge/get-started:part2
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "8080:80"
    networks:
      - webnet
networks:
  webnet:

このdocker-compose.ymlでは次のような動きを記述しています。

  1. Part2で作成したイメージをリポジトリから取得。
  2. 取得したイメージから5つのインスタンスを生成して、webと呼ばれるサービスとして名づけます。それぞれに対してCPU資源は10%、50MBのRAMを割当て。
  3. コンテナでエラーがあった場合には再起動。
  4. webサービスの各インスタンスの80ポートはローカルホストからは8080ポート経由からアクセス可能。(オリジナルの記述は4000ポート)
  5. webnetと呼ばれる負荷分散ネットワークを生成し、ポート80を共有するようにwebのコンテナに指示します。 (内部的にはコンテナ自体が一時ポートでwebのポート80に発行)
  6. webnetネットワークをデフォルト設定(負荷分散オーバーレイネットワーク)で定義。

【ここまで読み飛ばしていいです】

負荷分散ネットワークアプリの起動

まずは以下のコマンドを起動します。コマンドの意味はPart4で説明がありますが、これを実行しないとエラーが発生します。

$ docker swarm init

【ログ】

$ docker swarm init
Swarm initialized: current node (nc03uv6m1z1dxgwxdilvh29rj) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-1dukwcs4w07qt835cw6o5w0aju191e93be2jtctejrndzj5jyd-25d5b683d7jx4hceptehbtrz9 192.168.0.7:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

つづいて以下のように実行します。この実行ではアプリはgetstartedlabと設定しています。

$ docker stack deploy -c docker-compose.yml getstartedlab

【ログ】

$ docker stack deploy -c docker-compose.yml getstartedlab
Creating network getstartedlab_webnet
Creating service getstartedlab_web

これで動作の確認になります。ここからはChromeOSではうまく動作しなかった部分になりますが… 以下のコマンドで確認します。

$ docker service ls

【ログ】

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                      PORTS
p1dyl3harlzm        getstartedlab_web   replicated          0/5                 hoge/get-started:part2   *:8080->80/tcp

お!あれ?だめなのか?

念の為、コンテナの動作状況を以下のコマンドで確認してみます。

$ docker service ps getstartedlab_web

【ログ】

$ docker service ps getstartedlab_web 
ID                  NAME                  IMAGE                      NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
lgz0af823dtz        getstartedlab_web.1   hoge/get-started:part2   ubuntu              Running             Running 50 seconds ago                       
n2bgt0wx11kg        getstartedlab_web.2   hoge/get-started:part2   ubuntu              Running             Running 22 seconds ago                       
0b1v6d8jy5lu        getstartedlab_web.3   hoge/get-started:part2   ubuntu              Running             Running 50 seconds ago                       
sm21dfefpfgw        getstartedlab_web.4   hoge/get-started:part2   ubuntu              Running             Running 32 seconds ago                       
isx43duompwd        getstartedlab_web.5   hoge/get-started:part2   ubuntu              Running             Running 11 seconds ago 

ステータスはRunningになっています!動作しているようです。念の為もう一度Serviceの動作状況の確認を調べてみると…

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                      PORTS
p1dyl3harlzm        getstartedlab_web   replicated          5/5                 hoge/get-started:part2   *:8080->80/tcp

無事に起動しているようです。ちょっとホッとしました。

今回の動作環境ではDockerでaufsを使用していないため、パフォーマンスが劇的に低くなっているため各コンテナの起動に時間がかかってしまったのではないかと考えます。(他の例でも、起動に関するパフォーマンスは明らかに落ちているのはわかります。)

ではブラウザでこの負荷分散サービスへアクセスしていきます。 アクセス先は同様にhttp://localhost:8080/になります。このURLにアクセスするとロードバランスを図ってくれるのでアクセスする度(リロードする度)に 表示されるHostIDが変化していくことを確認してください。

f:id:ueponx:20190322062553p:plain

f:id:ueponx:20190322062602p:plain

f:id:ueponx:20190322062611p:plain

$ docker swarm init
Swarm initialized: current node (nc03uv6m1z1dxgwxdilvh29rj) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-1dukwcs4w07qt835cw6o5w0aju191e93be2jtctejrndzj5jyd-25d5b683d7jx4hceptehbtrz9 192.168.0.7:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

$ docker stack deploy -c docker-compose.yml getstartedlab
Creating network getstartedlab_webnet
Creating service getstartedlab_web

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                      PORTS
p1dyl3harlzm        getstartedlab_web   replicated          0/5                 hoge/get-started:part2   *:8080->80/tcp

$ docker service ps getstartedlab_web 
ID                  NAME                  IMAGE                      NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
lgz0af823dtz        getstartedlab_web.1   hoge/get-started:part2   ubuntu              Running             Running 50 seconds ago                       
n2bgt0wx11kg        getstartedlab_web.2   hoge/get-started:part2   ubuntu              Running             Running 22 seconds ago                       
0b1v6d8jy5lu        getstartedlab_web.3   hoge/get-started:part2   ubuntu              Running             Running 50 seconds ago                       
sm21dfefpfgw        getstartedlab_web.4   hoge/get-started:part2   ubuntu              Running             Running 32 seconds ago                       
isx43duompwd        getstartedlab_web.5   hoge/get-started:part2   ubuntu              Running             Running 11 seconds ago                       

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                      PORTS
p1dyl3harlzm        getstartedlab_web   replicated          5/5                 hoge/get-started:part2   *:8080->80/tcp

f:id:ueponx:20190324071640p:plain


アプリケーションのスケールをしてみる

スケールをするのは簡単です。 docker-compose.ymlのレプリカの数を変更して保存し、再度docker stack deployコマンドを再実行するだけでアプリを拡張できます。 以下の例ではレプリカ数を5から3へ変更しています。非常にシームレスにスケールするのがわかります。

$ vim docker-compose.yml

$ docker stack deploy -c docker-compose.yml getstartedlab
Updating service getstartedlab_web (id: p1dyl3harlzm5ghawpj04noay)

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                      PORTS
p1dyl3harlzm        getstartedlab_web   replicated          3/3                 hoge/get-started:part2   *:8080->80/tcp

$ docker service ps getstartedlab_web 
ID                  NAME                      IMAGE                      NODE                DESIRED STATE       CURRENT STATE             ERROR               PORTS
7qeqrcn6etna        getstartedlab_web.1       hoge/get-started:part2   ubuntu              Running             Running 20 seconds ago                        
lgz0af823dtz         \_ getstartedlab_web.1   hoge/get-started:part2   ubuntu              Shutdown            Shutdown 24 seconds ago                       
y52g099pbi4f        getstartedlab_web.2       hoge/get-started:part2   ubuntu              Running             Starting 2 seconds ago                        
n2bgt0wx11kg         \_ getstartedlab_web.2   hoge/get-started:part2   ubuntu              Shutdown            Shutdown 2 seconds ago                        
0b1v6d8jy5lu        getstartedlab_web.3       hoge/get-started:part2   ubuntu              Running             Running 10 minutes ago

負荷分散させるアプリケーションがdocker-comporse.ymlの変更を行ってコマンド一発でスケールできるのは非常に便利です!

後片付け

Serviceの終了を指せる場合には以下のコマンドを使用します。

$ docker stack rm getstartedlab
$ docker swarm leave --force

これで今回の環境は完全に終了します。

【ログ】

$ docker stack rm getstartedlab
Removing service getstartedlab_web
Removing network getstartedlab_webnet

$ docker swarm leave --force
Node left the swarm.

f:id:ueponx:20190322062709p:plain

これでPart3は終了です。

Get Started, Part 4: Swarms

ここからはPart4でSwarmに関する部分になります。(Part3でもやってましたけど) Part4では、Swarmとはどういうものか、Swarm内のノードがマネージャまたはワーカーになる方法、Swarmを作成、その上にアプリをデプロイを行っていきます。 また、その環境下でPart3同様に異なるマシンで構成でDockerの基本機能、ネットワーク機能、負荷分散やスケールできることを実験してみます。

docs.docker.com

前提としてはPart3までが完了していればOKということになるのですが、新たにdocker-machineコマンドが必要になります。 WindowsOSXであればDocker環境をインストールするとすでに入るのですが、Linuxの場合には別途インストールが必要になります。 以下のサイトを見ながら作業となります。

docs.docker.com

抜粋すると以下のコマンドになります。(versionは0.16.0の場合)

f:id:ueponx:20190327055356p:plain

$ base=https://github.com/docker/machine/releases/download/v0.16.0 && curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine && sudo install /tmp/docker-machine /usr/local/bin/docker-machine

インストール後の動作チェックは以下で大丈夫です。

$ docker-machine version
docker-machine version 0.16.0, build 702c267f

f:id:ueponx:20190327055412p:plain

クラスタの作成

ドキュメントを読んでいくと…

You need a hypervisor that can create virtual machines (VMs), so install Oracle VirtualBox for your machine’s OS.

なんとvirtualboxをインストールしてVMを起動しろと言われます。(ChromeOSではここまで来ると本末転用のような状況…OS環境を変えて正解だったのかも) 仕方ないので、以下のリンクからUbuntu用のUbuntu 18.04 (Bionic) / Ubuntu 18.10 (Cosmic) / Debian Unstableパッケージをダウンロードします。

www.oracle.com

Ubuntuの場合、ブラウザ(Firefox)でダウンロードすると.debファイルを認識してパッケージのインストールを行ってくれますので、 そのままインストールしてしまいましょう。

インストールが完了したら、以下のように2台のVMを起動します。--driverで指定したVM環境が使用されVMが作成されます。

$ docker-machine create --driver virtualbox myvm1
$ docker-machine create --driver virtualbox myvm2

f:id:ueponx:20190327055425p:plain

f:id:ueponx:20190327055439p:plain

起動したVMmyvm1myvm2という名前で起動しています。このVMIPアドレスは以下のコマンドで調べることができます。

$ docker-machine ls
ubuntu@ubuntu:~$ docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER     ERRORS
myvm1   -        virtualbox   Running   tcp://192.168.99.101:2376           v18.09.3   
myvm2   -        virtualbox   Running   tcp://192.168.99.102:2376           v18.09.3   

f:id:ueponx:20190327055451p:plain

VMIPアドレスがわかったら、2つともIPアドレスを控えておきます。そのうちの1台(今回はmyvm1側)をSwarmのマネージャホストにします。 該当するホストでdocker-machine ssh経由でdocker swarm initコマンドを実行します。実行時に表示されるtokenはメモしておきます。というかコマンドそのものをコピーしておいたほうがいいかもしれません。(docker swarm join ほげほげの部分)

$ docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"
Swarm initialized: current node <node ID> is now a manager.

To add a worker to this swarm, run the following command:

  docker swarm join \
  --token <token> \
  <myvm ip>:<port>

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

f:id:ueponx:20190327055503p:plain

【ログ】

$ docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.101"
Swarm initialized: current node (76irf1ec7b14xfns1oym7638x) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0hdt9lh014fow8y0yrzw6sruqdzb275sw2ohwhiolzfy0ev05z-42bhd4wxtwd9hu7ndx9prrzzd 192.168.99.101:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

念の為、Swarmを使用する場合にはポート2377とポート2376を使用する可能性があるので、使用しないように注意が必要です。 また、上記のdocker-machine sshでコマンドを送信できない場合にはホストにネイティブにインストールされているsshコマンドを使用する事もできます その場合には--native-ssh sshオプションを追加設定します。具体的には以下のようになります。

$ docker-machine --native-ssh ssh myvm1  "docker swarm init --advertise-addr <myvm1 ip>"

続いて2台目のVM(今回はmyvm2)をワーカーとして登録します。その際は先程実行したdocker swarm initの戻りでtokenが表示されているので それをオプション指定してdocker swarm joinをホストに送信します。例のは適切なものに変更を行ってください。

$ docker-machine ssh myvm2 "docker swarm join --token <token> <ip>:2377"

f:id:ueponx:20190327055520p:plain

$ docker-machine ssh myvm2 "docker swarm join --token SWMTKN-1-0hdt9lh014fow8y0yrzw6sruqdzb275sw2ohwhiolzfy0ev05z-42bhd4wxtwd9hu7ndx9prrzzd 192.168.99.101:2377"
This node joined a swarm as a worker.

これでSwarmが生成できました。以下のコマンドで生成されたノードを表示してみます。

$ docker-machine ssh myvm1 "docker node ls"

f:id:ueponx:20190327055530p:plain

ここでもし最初からやり直す場合にはdocker swarm leaveを実行するとSwarmが終了し元に戻ります。

アプリのデプロイを行う

Swarmができあがったので、アプリをデプロイしていきます。

これまではdocker-machine sshで実行していましたが、これではいちいちコマンドを実行していく必要があるので結構手間です。そこでdocker-machine envで得られる情報を元にローカルのdocker-compose.ymlファイルを使用してデプロイする方法もあります。今回はそれを使用してみます。

環境変数の設定はdocker-machine envで取得できるので

$ docker-machine env myvm1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.101:2376"
export DOCKER_CERT_PATH="/home/ubuntu/.docker/machine/machines/myvm1"
export DOCKER_MACHINE_NAME="myvm1"
# Run this command to configure your shell: 
# eval $(docker-machine env myvm1)

この情報をevalで取り込んで有効化します。

$ eval $(docker-machine env myvm1)

f:id:ueponx:20190327055542p:plain

すると、今回作成したmyvm1がアクティブ状態になります。

$ docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER     ERRORS
myvm1   *        virtualbox   Running   tcp://192.168.99.101:2376           v18.09.3   
myvm2   -        virtualbox   Running   tcp://192.168.99.102:2376           v18.09.3   

f:id:ueponx:20190327055552p:plain

Part3と同様にアプリのデプロイして、動作を確認してみます。

【注意】デプロイを行う前にdocker-compose.ymlファイルのあるパスに移動しておいてください。 myvm1のホスト上で以下のコマンドを実行すると

$ cd ./friendlyhello/
$ docker stack deploy -c docker-compose.yml getstartedlab

【ログ】

$ docker stack deploy -c docker-compose.yml getstartedlab
Creating network getstartedlab_webnet
Creating service getstartedlab_web

myvm1myvm2にアプリが分散配置されて起動されます。以下のコマンドで分散の状況を確認することができます。

$ docker stack ps getstartedlab

f:id:ueponx:20190327062929p:plain

$ docker stack ps getstartedlab
ID                  NAME                  IMAGE                      NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
886onhvdec3j        getstartedlab_web.1   ueponx/get-started:part2   myvm2               Running             Running 3 minutes ago                        
ukvh7zbk85e8        getstartedlab_web.2   ueponx/get-started:part2   myvm1               Running             Running 3 minutes ago                        
tgvo877hsaox        getstartedlab_web.3   ueponx/get-started:part2   myvm2               Running             Running 3 minutes ago                        
ffzmzokyv6v7        getstartedlab_web.4   ueponx/get-started:part2   myvm1               Running             Running 3 seconds ago                       
jq5q4ukq9w6b        getstartedlab_web.5   ueponx/get-started:part2   myvm1               Running             Running 3 seconds ago

ここまできたらブラウザなどを使ってmyvm1またはmyvm2IPアドレスにアクセスを行います。

【myvm1へのアクセス】

f:id:ueponx:20190327055657p:plain

f:id:ueponx:20190327055708p:plain

f:id:ueponx:20190327055721p:plain

【myvm2へのアクセス】

f:id:ueponx:20190327055612p:plain

f:id:ueponx:20190327055623p:plain

f:id:ueponx:20190327055633p:plain

f:id:ueponx:20190327055646p:plain

この環境でスケールさせる場合にはdocker-compose.ymlを修正し、docker stack deployを実行することでスケールが用意にできます。またノードの追加に関しても今回のmyvm2と同様に追加することでホスト単位のスケールも用意にできるようになります。

stackの終了方法

stackの終了方法は今回の場合は以下のようになります。

$ docker stack rm getstartedlab

環境変数のクリア

docker-machine envで設定した設定は以下のように行うとクリアできます。

$ eval $(docker-machine env -u)

ローカルホストを終了させればdockerのマシンも終了します。状態を確認する場合には以下のコマンドとなります。

$ docker-machine ls

停止したノードを再起動させる場合にはホスト名を指定して以下のように再起動ができます。

$ docker-machine start <machine-name>

おわりに

OSを変更することでようやくPart3とPart4がおわらせられました。しかし、このチュートリアルかなり事前準備の要求が高いですね。あともう少し頑張ってみます。

【参考エントリー】

uepon.hatenadiary.com

uepon.hatenadiary.com

uepon.hatenadiary.com

/* -----codeの行番号----- */