マイクロサービスのデプロイと運用-DockerとKubernetes

機械学習技術 人工知能技術 自然言語処理技術 セマンティックウェブ技術 オントロジー技術 検索技術 データベース技術 アルゴリズム デジタルトランスフォーメーション技術 Visualization & UX ワークフロー&サービス ITインフラ技術 暗号化とセキュリティ技術およびデータ圧縮技術 マイクロサービス技術 クラウド技術 DevOpsについて 本ブログのナビ

サマリー

「Microservice with Clojure」より。前回はマイクロサービスシステム運用監視の為のElasticStashの活用について述べる。今回はマイクロサービスのデプロイと運用としてDockerとKubernetesについて述べる。

マイクロサービスのデプロイをスケールさせる

マイクロサービスは、1つのコマンドで複製やデプロイができる自己完結型のアーティファクトとしてパッケージ化されている必要がある。また、サービスは数秒以内に稼働できるように、起動時間が短く軽量である必要もある。コンテナは、ホストOSと必要な依存関係を持つベアメタルマシンをセットアップするのに比べ、固有の実装により迅速にデプロイすることができる。また、コンテナ内にマイクロサービスをパッケージ化することで、開発から本番環境への移行をより速く、自動化することも可能となる。よってマイクロサービスはコンテナ内にパッケージ化することが推奨されている。

コンテナおよび Dockerについて

Linuxコンテナ(LXC)は、singleLinuxカーネルを使用したsingleホストOS上でコンテナとも呼ばれる複数の分離したLinuxシステムを実行できるような、OSレベルの仮想化手法となる。これは、仮想マシンを必要としないcgroupsを用いて、コンテナ間でリソースを共有する。各コンテナは既に起動しているホストOSのLinux Kernelに依存するため、Hypervisorで実行する仮想マシンに比べて起動時間が大幅に短縮される。

Docker はまた、Linux cgroups、カーネルネームスペース およびユニオンマウントオプション により、コンテナのリソース分離を行い、仮想マシン起動と維持のオーバーヘッドを回避するのに役立つ。マイクロサービスにDockerコンテナを使用することで、サービス全体とその依存関係をコンテナ内にパッケージ化し、任意のLinuxサーバー上で実行することが可能になる。

Dockerのセットアップ

Dockerは、1つまたは複数のコンテナを作成し、ホストOS上でそれを実行するために使用できるDockerイメージを作成するためのソフトウェアとなる。Dockerをセットアップする最も簡単な方法は、以下のようにDockerがコミュニティ版で提供するセットアップスクリプトを使用することとなる。

> wget -qO- https://get.docker.com/ | sh

上記のコマンドは、ホストのオペレーティングシステムに基づいてDockerをセットアップする。Dockerはまた、そのダウンロードセクションで、すべての一般的なオペレーティングシステム用の事前ビルドパッケージを提供している。インストールが完了したら、以下のように、現在のユーザをdockerグループに追加する。

> sudo usermod -aG docker $USER

グループのメンバーシップを考慮するために、新しいログインセッションを開始する必要がある場合がある。以上で、Dockerを起動することができる。Dockerをテストするには、以下のコマンドで実行中のコンテナをリストアップする。

> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

実行中のコンテナがないため、ヘッダのみがリストアップされる。コンテナの実行をテストするには、次の例のようにdocker runコマンドを使用します。hello-worldのDockerイメージをダウンロードし、コンテナで実行する。

> docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:66ef312bbac49c39a89aa9bcc3cb4f3c9e7de3788c944158df3ee0176d32b751 Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs
the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent
it
    to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
> docker run -it ubuntu bash
 Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/
 For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

  前述のコマンドは、hello-world イメージをダウンロードし、ローカルに保存した後、コンテナ内でそれを実行するものとなる。イメージは、メッセージを生成するために使用されたステップを含むメッセージをコンソールにダンプして終了するだけである。hello-world イメージは初めて使用されるため、ローカルマシンには存在せず、そのため docker コマンドはまずリモートの Docker Registry からダウンロードする。もう一度同じコマンドを実行してみると、今度は次の例のように、ローカルマシン内でイメージが見つかり、すぐに使用できるようになる。この場合、先ほどと同様に hello-world イメージの実行結果として、メッセージとインストール手順が出力されるだけです。

> docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs
the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent
it
    to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
 > docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
Docker Hub Container Image Library | App Containerization
For more examples and ideas, visit:
Docker daemon configuration overview
Configuring the Docker daemon

ローカルマシンで利用可能な Docker イメージを一覧表示するには、次の例のように docker images コマンドを実行する。

> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest f2a91732366c 7 weeks ago 1.85 kB

同様に、作成されたDockerコンテナを一覧表示するには、先ほどと同様にdocker ps -aコマンドを使用する。今回は、このようにhello-worldイメージを使用して起動されたコンテナがリストアップされる。

> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e0e5678ef80a hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago
happy_rosalind
ea9815d87660 hello-world "/hello" 8 minutes ago Exited (0) 8 minutes ago
fervent_engelbart

利用可能なコマンドとオプションの詳細については、Docker CLIコマンドリファレンスガイドを参照のこと。また、Dockerのセットアップと設定オプションの詳細については、Dockerポストインストールガイドを参照のこと。

Helping Hands用のDockerイメージの作成

以前作成したHelping Handsのサービスには、プロジェクトテンプレートの一部としてDockerfileが作成されている。例えば、次の例に示すような Auth サービスのディレクトリ構造を見てみると、Dockerコンテナ内で実行するには、helping- hands.auth.service 名前空間内のサービス定義の ::http/host キーに固定 IP アドレスまたは 0.0.0.0 を設定し、コンテナ内で利用可能なすべての IPv4 アドレスにバインドする必要がある。

% tree -L 1
.
├── Capstanfile 
├── config 
├── Dockerfile 
├── project.clj 
├── README.md 
├── resources 
├── src
├── target 
└── test
  
 5 directories, 4 files

Authサービス用のDockerfileの内容を、以下の例のように変更する。Helping HandsのAuthサービスのconfigディレクトリとスタンドアロンJARファイルの両方がコピーされる。スタンドアロンJARがターゲットフォルダに存在しない場合は、AuthプロジェクトのターゲットディレクトリにスタンドアロンJARを作成するlein uberjarコマンドを使用して作成する。

FROM java:8-alpine
MAINTAINER Helping Hands <helpinghands@hh.com>
COPY target/helping-hands-auth-0.0.1-SNAPSHOT-standalone.jar /helping-
hands/app.jar
COPY config/conf.edn /helping-hands/
EXPOSE 8080
CMD exec java -Dconf=/helping-hands/conf.edn -jar /helping-hands/app.jar

次に、以下の例のように、docker build コマンドを使用して Docker イメージを作成する。docker buildコマンドは、起動したディレクトリと同じディレクトリにあるDockerfileを探す。Dockerfileが他の場所にある場合は、Dockerfileへのパスを明示的に指定することができる。docker build コマンドの詳細については、使用方法を参照のこと。

# build the docker image
   % docker build -t helping-hands/auth:0.0.1 .
   Sending build context to Docker daemon 48.44 MB
Step 1/6 : FROM java:8-alpine
8-alpine: Pulling from library/java
709515475419: Pull complete
38a1c0aaa6fd: Pull complete
5b58c996e33e: Pull complete
Digest: sha256:d49bf8c44670834d3dade17f8b84d709e7db47f1887f671a0e098bafa9bae49f Status: Downloaded newer image for java:8-alpine
    ---> 3fd9dd82815c
   Step 2/6 : MAINTAINER Helping Hands <helpinghands@hh.com>
    ---> Running in dd79676d69a4
    ---> 359095b88f32
   Removing intermediate container dd79676d69a4
   Step 3/6 : COPY target/helping-hands-auth-0.0.1-SNAPSHOT-standalone.jar
   /helping-hands/app.jar
    ---> 952111f1c330
   Removing intermediate container 888323c4cc30
   Step 4/6 : COPY config/conf.edn /helping-hands/
    ---> 3c43dfd4af83
   Removing intermediate container 028df1e03d58
   Step 5/6 : EXPOSE 8080
    ---> Running in 8cf6c15cab9f
    ---> e79d993e2c67
   Removing intermediate container 8cf6c15cab9f
   Step 6/6 : CMD exec java -Dconf=/helping-hands/conf.edn -jar /helping-
   hands/app.jar
    ---> Running in 0b4549cf84f2
    ---> f8c9a7e746f3
   Removing intermediate container 0b4549cf84f2
   Successfully built f8c9a7e746f3
   # list the images to make sure it is available
   % docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
   helping-hands/auth 0.0.1 f8c9a7e746f3 17 seconds ago 174 MB
   hello-world latest f2a91732366c 7 weeks ago 1.85 kB
   java 8-alpine 3fd9dd82815c 10 months ago 145 MB

指定された名前とタグでイメージを作成し登録すると、このように同じイメージから新しいコンテナを作成することができる。

# create a new container from the tagged image
   % docker run -d -p 8080:8080 --name hh_auth_01 helping-hands/auth:0.0.1
   286f21a088dd8b6b6d814f1fb5e4d27a59f46b6d8c474160628ffe72d3de2b56
   # verify that the container is running
% docker ps -a
   CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
286f21a088dd helping-hands/auth:0.0.1 "/bin/sh -c 'exec ..." 5 seconds ago Up 3 seconds 0.0.0.0:8080->8080/tcp hh_auth_01
e0e5678ef80a hello-world "/hello" 51 minutes ago Exited (0) 50 minutes ago happy_rosalind
   ea9815d87660 hello-world "/hello" 54 minutes ago Exited (0) 53 minutes ago
   fervent_engelbart

Dockerが生成するログメッセージを確認し、このようにAuthサービスが稼働していることを確認する。

% docker logs 286f21a088dd
   Creating your server...
   Omniconf configuration:
    {:conf #object[java.io.File 0x47c40b56 "/helping-hands/conf.edn"]}

次の例に示すように、Auth サービスは 8080 ポートで直接アクセスできるようになる。このポートは、コンテナの作成時に使用したように、docker runコマンドで-pフラグを使用してマッピングされている。

% curl -i "http://localhost:8080/tokens?uid=hhuser&pwd=hhuser"
   HTTP/1.1 200 OK
   ...
   Authorization: Bearer
   eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTEyOEtXIn0.1enLmASKP8uqPGvW_bOVcGS
   8-0wtR3AS0xxGolaNixXCSXaY_7LKqw.RcXp4s0397a3M_EB-
   DyFAQ.B6b93-1_grZa7HJee6nkcT4LM3gV7QxmR3CIHxX9ngzFqPyyJTcBWvo2N4TTlY4gJYgeN
   tIyaJsAmvVYCEi7YKyp47bF1wzgFbpjkfVen6y-580kmf5JqaP2vXQmNpFiVRB6FGGqldnAaDKd
   BCCrv0HRgGbaxyg_F_05j4G9AktO26hUMfXvmd9woh61Id-lV4xvRZOcn57X6aH-
   HL2JuA.hUWvDD6lQWmXaRGYCf3YOQ
   Transfer-Encoding: chunked

コンテナを停止するにはdocker stopコマンドを、コンテナを削除するにはこのようにdocker rmコマンドを使用する。

% docker stop hh_auth_01
hh_alert_01
   % docker rm hh_auth_01
hh_alert_01
% docker ps -a
   CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
   e0e5678ef80a hello-world "/hello" 54 minutes ago Exited (0) 54 minutes ago
   happy_rosalind
   ea9815d87660 hello-world "/hello" 57 minutes ago Exited (0) 57 minutes ago
   fervent_engelbart

効果的なDockerfileの作成方法の詳細については、Dockerfilesの書き方のベストプラクティスを参照のこと。

Kubernetesの導入

Helping Hands アプリケーションのサービスをコンテナ化すると、複数のマシンに迅速にデプロイできるが、そのスケーリングには手作業が必要で、DevOps チームが関与してスケールアップとスケールダウンを行う必要がある。また、サービスがマシンのクラスタ全体でコンテナを実行する数百のインスタンスにスケールする可能性があるため、実行中のすべてのコンテナを監視することは、時間の経過とともに負担になる可能性がある。サービスやコンテナに障害が発生した場合は、チームにアラートを送ることができるが、それらを手動で実行するのは退屈な作業となる。さらに、効果的なリソース利用を推定して達成し、各サービスの実行インスタンス数を最適にバランスさせるために手動で行うのは、網羅的であり、しばしばエラーが発生しがちである。

このような手作業を避け、設定された数のサービスが常に稼働し、利用可能なリソースを有効に活用するためには、コンテナ・オーケストレーション・エンジンが必要となる。Kubernetesは、そのようなオープンソースのコンテナオーケストレーションエンジンの1つで、助け合いアプリケーションのサービスのようなコンテナ化されたアプリケーションの自動展開、スケーリング、管理に広く使用されている。

Kubernetesのデプロイでは、MasterとNode(以前はMinionsと呼ばれていた)の2種類のマシンが存在する。MasterインスタンスはKubernetesエンジンの頭脳であり、コンテナのデプロイに関するすべての決定を行い、障害や新規割り当て要求などのさまざまなイベントにも対応する。マスターインスタンスは、kube-apiserver, etcd, kube-controller- manager, kube- scheduler を実行している。また、ノードと同じオーバーレイネットワーク内で動作させるために、kube-proxyも実行する。Masterはクラスタ管理タスクのみに特化した別のマシンで実行することが推奨される。

一方、NodesはKubernetesクラスタのワーカーマシンであり、Podを実行する。Podは、Kubernetesクラスターで作成および管理できるコンピューティングの最小単位となる。ネットワーク、ストレージ、および共通の仕様セットを共有する、1つまたは複数のコンテナのグループとなる。各Nodeは、Dockerサービス、kubelet、kube-proxyを実行し、マスターコンポーネントによって管理されます。kubeletエージェントは、各Node上で動作し、Nodeに割り当てられたPodを管理し、Podの状態をKubernetesクラスタに報告する。

Kubernetesは、Dockerコンテナをサポートする機能を内蔵している。リソースを有効活用するための自動ビンパッキング、サービスを上下にスケールするための水平スケーリングによるサービスのスケールアップとスケールダウン、CPU使用率などの要因に基づく自己回復による失敗時の自動コンテナ再起動のサービスは、そのままでKubernetesで提供される。

Kubernetesは、コンテナに独自のIPアドレスを割り当てることで、Service Discoveryとロードバランシングもサポートしている。また、コンテナ群に共通のDNS名を割り当てることで、他の外部サービスがDNS名を知るだけで、同じものを使ってサービスにアクセスできるようにする。Kubernetesは、指定された名前でDNSに登録されているコンテナ内で実行されているサービス間で、リクエストを内部的にバランスさせる。ローリングアップグレードも、コンテナを新しいものにインクリメンタルにアップグレードすることでKubernetesが提供する。すべてのアップデートはKubernetesによってバージョン管理され、以前の任意の安定バージョンにロールバックすることができる。

Kubernetesを始める

Kubernetesを使い始め、1台のマシンでローカルに実行する最もシンプルな方法は、Minikubeを使用することとなる。Minikubeをセットアップするには、以下のインストールスクリプトを使用する。

% curl -Lo minikube
   https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd6
   4 && chmod +x minikube && sudo mv minikube /usr/local/bin/

先のコマンドは、Minikubeスクリプトの最新リリースをダウンロードし、/usr/local/binディレクトリにコピーすることでパス上で利用できるようにするものとなる。また、MinikubeはKubernetesクラスタとやり取りするためにkube-ctlを必要とする。kube-ctlのセットアップには、以下のようにkube-ctlのインストールスクリプトを使用する。

# download kube-ctl script
   % curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl
   -s
   https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/l
   inux/amd64/kubectl
   # make the script executable
   % chmod +x ./kubectl
   # make it available on the path
   % sudo mv ./kubectl /usr/local/bin/kubectl

minikubeコマンドによるKubernetesクラスタの作成方法、kube-ctlによるMasterとのやり取りやコンテナのデプロイ方法の詳細についてはMinikubeプロジェクトドキュメントを参照のこと。

コメント

タイトルとURLをコピーしました