前回はSwarm modeによるクラスタ構成にし、複数サーバの環境でも手軽に利用できることを説明した。では以下の図の構成はどうであろうか。

実運用においてアプリケーションに負荷が集中した場合、アプリケーションを複数にする=スケールアウトすることで、アプリケーションひとつあたりの負荷を分散する方法で回避でき、図1はその一例である。

図1:Databeseサーバ1台とWebサーバ2台構成

今回は、Docker環境でのスケールアウト方法について説明する。

Swarm modeでのスケールアウト

Swarm modeには、クラスタ機能のほかにもうひとつ重要な機能が実装されている。それはオーケストレーション機能だ。オーケストレーションとは、システムの立ち上げや変更を自動化する技術であり、Dockerではこの機能により追加したDockerホストに、起動しているコンテナを複製して起動することができる。

いままでのアプリケーションをスケールアウトするときは、サーバ環境を用意しアプリケーションとミドルウェアをインストールし、設定を行い、動作確認をして・・・と、とても手間がかかった。これに加えて、設定の間違いなどのミスが多く発生する作業であった。

それがオーケストレーション機能により、スケールアウトはおろかスケールインまで、コマンドひとつで実行可能となっている。例として前回のWordPress1台、DB1台の構成から、図1の構成に変更するためには以下の手順を行えばよい。

(1)Dockerホストを新たに作成した後、クラスタにWorkerとして追加する。
  docker service scaleコマンドを実行し、WordPressのコンテナを新たに追加したDockerホストにスケールアウトする。

docker service scale wordpress=2

これでWorkerとして登録されている2つのDockerホストに、WordPressのコンテナが起動することで、WordPressへの負荷を分散することができた。逆にスケールアウトしたコンテナが不要になった場合は、scaleの数を減らして稼働しているコンテナを減らせばよい。

このようにDockerでは、現在のバージョンまでにDocker multi-host networkingやオーケストレーション機能が実装されたことで、柔軟でかつ可用性のある環境を構築し、運用する手間を軽減する機能が加わっていった。

では、Dockerに上記の機能が加わる前はどのように構築し、運用していたのか。同様の機能を提供するコンテナ管理ツールは以前から存在している。代表的なアプリケーションはKubernetesだ。それではKubernetesの紹介とともに、Kubernetesを利用したスケールアウト方法を説明する。

Kubernetesを利用したスケールアウト

KubernetesはGoogleが開発し、正式版である1.0のリリース後からThe Linux Foundationの傘下のCloud Native Computing Foundation(CNCF)でバージョンアップが行われているコンテナ管理ツールである。

Kubernetesの構成は、複数のコンテナ実行環境をクラスタ化して、クラスタ内でコンテナ間通信やコンテナのオーケストレーションを実現している。これはDockerのSwarm modeと同様である。

では、Kubernetesを使用するメリットは何か。以下の内容が挙げられる。

コンテナソフトウェアの選択が可能

Kubernetesでは、Dockerの他にCoreOSが開発しているコンテナソフトウェアが選択でき、ひとつのコンテナソフトウェアにロックインせずにコンテナを管理することが可能である。

ネットワーク構成の自由度が高い

Kubernetesでネットワークを構成する時には、複数のネットワークアドオンから選択できる。これによりひとつのネットワークアドオンにロックインせず、かつプラグイン特有の機能を選んで構成できる。また、外部へのネットワークもコンテナと分離して設定できるので、グローバルIPアドレスとの紐付け、ロードバランサとしての利用など、柔軟にネットワークを構成できる。

ScheduledJobの実行、管理が可能

データのバックアップなどバッチ的な処理をワンタイム、または定期的に実行することができる。

WebUIの提供

KubernetesにはWebUIが提供されており、ブラウザ上で気軽にコンテナ管理できる。

Web UI (Dashboard) - Kubernetes

このように実際の運用において、かゆいところに手が届く魅力的な機能が取り揃えられている。では、デメリットは何か。以下の点が挙げられる。

コンテナソフトウェアのバージョンに依存

Kubernetesはコンテナソフトウェアのバージョンに追随はしているが、最新のバージョンに対応しているわけではないため、コンテナソフトウェアのバージョン管理が必要となる。

コマンドの入力形式が違う

Kubernetesでコンテナを管理し、実行するときにはkubectlコマンドを使用する必要があるが、 Dockerのコマンドと比べるといくつかの相違点がある。例えば、第3回で使用したmysqlのdocker container run コマンドをkubectlコマンドに書き換えると、このような形式となる。

$ kubectl run \
   wordpress-mysql \
   --env="MYSQL_ROOT_PASSWORD=mysql" \
   --image=mysql

その他の相違点については、以下のページにまとめられているので、興味がある方はチェックしてほしい。

kubectl for Docker Users - Kubernetes

このようにDockerを利用している方にとっては、Kubernetesの構築および学習にコストがかかることに注意してほしい。ただ、Kubernetesは、DockerCon EU 2017で統合およびサポートの公式発表があったことから、利用シーンが今後増えていくことが考えられるため、今から学習して損はないと言えよう。

Kubernetes | Docker

では、Kubernetesでのコンテナ管理およびスケールアウトについて説明する。今回はUbuntuにkubeadmというパッケージをインストールすることでKubernetesによるコンテナのクラスタ構成を構築する。Kubeadmに対応するDockerのバージョンは1.12を推奨しているので、以下のコマンドでUbuntuの標準パッケージにあるDockerをインストールすればよい。

$ apt-get update
$ apt-get install -y docker.io

Dockerのインストール完了後、以下のコマンドを実行して、kubeadmおよびKubernetesの構成で必要なkubelet、kubectlパッケージをインストールする。

$ apt-get update && apt-get install -y apt-transport-https
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
$ cat </etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
$ apt-get update
$ apt-get install -y kubelet kubeadm kubectl

インストール完了後、Kubernetesを管理するMasterのDockerホストを選択し、以下のコマンドを実行してクラスタを初期化する。

$ kubeadm init

kubeadm initコマンド実行時に、ほかのDockerホストがこのクラスタにWorkerとして参加するためのコマンドが表示されるので、コピーしておく。

$ kubeadm join --token  : --discovery-token-ca-cert-hash sha256: 

クラスタ初期化後、以下のコマンドを実行してKubernetesで使用するネットワークアドオンをインストールする。

$ kubectl apply -f https://docs.projectcalico.org/v2.6/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml

※使用できるほかのネットワークアドオンは以下にまとめられている。

Installing a pod network | Using kubeadm to Create a Cluster

ネットワークのインストール完了後、先ほどコピーしたクラスタ参加用のコマンドをWorkerのDockerホストで実行する。その後に、MasterのDockerホストで以下のコマンドを実行して各Dockerホストがクラスタに参加していることを確認する。

$ kubectl get nodes

これでKubernetesクラスタは完成した。

次にMasterのDockerホストにMySQLコンテナを、WorkerのDockerホストにWordPressコンテナを起動する。事前作業として、DockerホストがMasterであるか、Workerであるか、を判断するためラベルを設定する。MasterのDockerホストにはtype=mysqlラベルを設定し、WorkerのDockerホストにはtype=wordpressラベルを設定する。

$ kubectl label nodes (MasterのDockerホスト名) type=mysql
$ kubectl label nodes (WorkerのDockerホスト名) type=wordpress

設定したラベルは、以下のコマンドで確認することができる。

$ kubectl get node -L type

あわせて以下のコマンドを実行し、MasterのDockerホストにコンテナを配置可能に変更する。

$ kubectl taint nodes --all node-role.kubernetes.io/master-

※Kubernetesではセキュリティ上の理由から、デフォルトでMasterのDockerホストにコンテナは配置できないようになっている。

事前準備が完了したら、Kubermetesの定義ファイルを作成する。

定義ファイルには、コンテナ構成のDeploymentsとネットワーク構成のServiceの情報を記載する。

MySQLを構成するmysql.ymlには以下の内容を記述する。

apiVersion: v1
kind: Service
metadata:
 name: mysql
 labels:
  app: wordpress
spec:
 ports:
  - port: 3306
 selector:
  app: wordpress
  tier: mysql
 clusterIP: None
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
 name: mysql
 labels:
  app: wordpress
spec:
 selector:
  matchLabels:
   app: wordpress
   tier: mysql
 template:
  metadata:
   labels:
    app: wordpress
    tier: mysql
  spec:
   nodeSelector:
    type: mysql
   containers:
   - image: mysql
    name: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
     value: mysql
    ports:
    - containerPort: 3306
     name: mysql

WordPressを構成するwordpress.ymlには、以下の内容を記述する。

apiVersion: v1
kind: Service
metadata:
 name: wordpress
 labels:
  app: wordpress
spec:
 ports:
  - protocol: "TCP"
   port: 8080
   targetPort: 80
 selector:
  app: wordpress
  tier: frontend
 type: LoadBalancer
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
 name: wordpress
 labels:
  app: wordpress
spec:
 selector:
  matchLabels:
   app: wordpress
   tier: frontend
 template:
  metadata:
   labels:
    app: wordpress
    tier: frontend
  spec:
   nodeSelector:
    type: wordpress
   containers:
   - image: wordpress
    name: wordpress
    env:
    - name: WORDPRESS_DB_PASSWORD
     value: mysql
    ports:
    - containerPort: 80
     name: wordpress

※DeploymentsとServiceの記載内容の詳細については、以下を参照。

Deployments - Kubernetes

Services - Kubernetes

後は、以下のコマンドでコンテナを起動すればよい。

$ kubectl create -f mysql.yml
$ kubectl create -f wordpress.yml

これで、第6回のWebサーバ1台、Databaseサーバ1台の構成をKubernetesで作成完了だ。 最後に、WordPressをスケールアウトするには、以下のコマンドを実行すればよい。

kubectl scale deployment wordpress --replicas=2

このようにKubernetesでもSwarm modeと同様に、コマンドひとつで簡単にスケールアウトできた。ただ、そもそもの話として、CLIでの作業に慣れていない方にとってはいままでの構成などをできるだけコマンドではなくGUIでの操作で完結したいと考える人もいるだろう。そのような便利なツールは存在するのか。これについては次回の「DockerをWebUIで管理しよう」で説明する。

CloudGarage開発担当
IaaS型パブリッククラウドサービス「CloudGarage」の開発エンジニア。バックエンドのサーバ構築からフロントのアプリケーション開発まで幅広く行う。「Docker」は実務でも頻繁に利用するため、実際に使っている立場から「Docker」について解説をする。