コンテナ技術が使われるはじめてから何年かたちました。企業や開発者の多くがアプリを配布するのにコンテナを使っています。使いやすいインターフェイスでコンテナ技術を広めたのがDockerです。
1つのコンテナで済むアプリケーションは稀で、いくつかのコンテナを複数のホストにデプロイします。この記事では、オープンソースシステムで、コンテナ化されたアプリケーションの自動デプロイ、スケーリング、管理ができるKubernetesを紹介します。
前提条件:この記事は、Dockerの知識がある読者を対象とします。Dockerについて復習が必要だと思う人は、Understanding Docker, Containers and Safer Software Deliveryを読んでください。
Kubernetesで解決できる問題
Dockerは、コンテナを起動したり、停止したりするのに、コマンドdocker runやdocker stopを使います。単一のコンテナなら十分ですが、複数のホストに新しくイメージを入れ込むdocker deployコマンドはありません。
「コンテナの協調」を解決するツールが多くあります。有名なツールは、Dockerエンジンに含まれているMesos、Docker Swarm、Nomad、そしてKubernetesです。それぞれ長所と短所がありますが、現時点ではKubernetesが一番使われています。
Kubernetes(k8sとも呼ばれます)では、デプロイやスケーリングなどのアプリケーション操作が、基礎となるインフラ操作から完全に独立しています。従って、Kubernetesを使うと、別々のホストや仮想マシンでコードを走らせる必要がなくなります。Kubernetesでは基礎となるインフラを、コンテナを置く計算の海と呼びます。
Kubernetesのコンセプト
Kubernetesはクライアント・サーバー構造を採用しています。Kubernetesサーバーがクラスター(1群のホスト)上で稼働し、アプリをデプロイします。具体的には、kubectl CLIから、クライアントを使ってクラスターとやり取りします。
Pods
PodはKubernetesが扱う基本的な単位であり、複数のコンテナからなるグループです。2つ以上のコンテナが常に協働して、同じマシンになければならない場合はpodとします。Podは便利な抽象化なので、第1級のdockerオブジェクトにすべきだと提案もあったくらいです。
ノード
ノードは、Kubernetesを走らせている物理的、あるいは仮想マシンです。ノード上でpodをスケジューリングできます。
ラベル
ラベルは、リソースを識別するのに用いるkey/valueのペアです。たとえば、productionトラフィックの役目をしているpodに、role=productionのラベルがつきます。
セレクター
セレクターを使うと、ラベルによりリソースの検索・フィルタリングができます。production podをすべて集めるには、セレクターはrole=productionとします。
サービス
podの集合(具体的には、セレクタで選択されたpod)を定義し、アクセスする手段を定義します。たとえば、単一固定のIPアドレスや対応するDNS名で定義します。
KubernetesでGKEにNode.jsアプリをデプロイする
Kubernetesの基本的なコンセプトを理解したところで、Google Container Engine(GKEと呼ばれます)にNode.jsのアプリケーションをデプロイして、Kubernetesの挙動を確認します。Google Cloud Platformアカウントが必要です($300相当のクレジットつきの無料トライアルがあります)。
1.Google Cloud SDKとKubernetesをインストールする
kubectlは、Kubernetesクラスターに対してコマンドを走らせるコマンドラインインターフェイスです。Google Cloud SDKの一部としてインストールできます。Google Cloud SDKがインストールできたら、次のコマンドを走らせてkubectlをインストールします。
$ gcloud components install kubectl
Macは、brew install kubectlとします。インストールがうまくいったか確かめるには、kubectl versionを実行します。
GoogleクラウドアカウントでGoogle cloud SDKを設定します。gcloud initを実行して、指示に従えば大丈夫です。
2.GCPプロジェクトを作成する
Google Cloudプラットホームのリソースはすべて、プロジェクトの下に作るので、web UIからプロジェクトを作ります。
CLIから以下を走らせて、デフォルトのプロジェクトIDを設定します。
gcloud config set project {PROJECT_ID}
3.アプリケーションのDockerイメージを作成する
ここではexpress-hello-worldを例に解説します。Dockerfileを見ると、dockerhubから既存のNode.jsイメージを使っているのが分かります。以下を走らせて、アプリケーションイメージを作ります。
$ docker build -t hello-world-image .
アプリをローカルで実行します。
docker run --name hello-world -p 3000:3000 hello-world-image
localhost:3000で、実行結果を確認します。
4.クラスターを生成する
3つのインスタンス(仮想マシン)を持つクラスターを作り、アプリケーションをデプロイします。直観的なweb UIのContainer engine pageでデプロイできます。または以下のコマンドで実行します。
$ gcloud container clusters create {NAME} --zone {ZONE}
以下を走らせて、us-east1-bにhello-world-clusterというクラスターを作成します。
$ gcloud container clusters create hello-world-cluster --zone us-east1-b --machine-type f1-micro
3つのノードからなるクラスターを起動できます。マシンタイプにf1-microを用いていますが、使えるもののうちで最小のものを使って、コストを最小限にするためです。
次を走らせて、kubectlクライアントをクラスターに接続します。
gcloud container clusters get-credentials hello-world-cluster --zone us-east1-b
dockerイメージとクラスターができました。Dockerイメージをクラスターに配置してコンテナを開始すれば目的達成です。
5.DockerイメージをGoogleコンテナイメージレジストリにアップロードする
Googleコンテナイメージレジストリはクラウドレジストリなので、イメージを保存できます。イメージは、コンテナエンジンクラスターで自動的に使えます。イメージを保存するには、適切な名前でビルドする必要があります。
アプリケーションのコンテナイメージを作り、アップロード用のタグをつけます。
$ docker build -t gcr.io/{PROJECT_ID}/hello-world-image:v1 .
v1がイメージのタグです。
いま作成したイメージをアップロードします。
$ gcloud docker -- push gcr.io/{PROJECT_ID}/hello-world-image:v1
6.初回のデプロイ
クラウドにクラスターとイメージができました。Kubernetesを使って、イメージをクラスターにデプロイするために、deploymentスペックファイルを作ります。デプロイメントはkubernetesリソースであり、kubernetesリソースはすべてスペックファイルで宣言的に定義できます。このスペックファイルで求めるリソース状態を規定すると、Kubernetesが現在の状態からその状態までリソースを移行させる方法を考えます。
初回のデプロイのためにスペックファイルを作ります。
スペックファイルの中身です。与えられたpodスペックで定義された2つのpodをスタートさせます。各podはhello-world-image:v1が入っているコンテナを1つずつ持っています。
kubectl get deploymentsを走らせると、デプロイ状態が分かります。デプロイで作られたpodは、kubectl get podsを走らせると、実行中のpodが分かります。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-world-deployment-629197995-ndmrf 1/1 Running 0 27s
hello-world-deployment-629197995-tlx41 1/1 Running 0 27s
deployment.ymlファイルで、レプリカを2に設定したため、Podの数は2つになります。
サーバーの起動を確認します。以下を走らせてログをチェックします。
$ kubectl logs {pod-name} # kubectl logs hello-world-deployment-629197995-ndmrf
7.サービスをインターネットに公開する
サービスをインターネットに公開するには、ロードバランサーを作成してVMを登録します。Kubernetes Serviceを作成します。
$ kubectl expose deployment hello-world-deployment --type="LoadBalancer"
裏で、サービスオブジェクト(サービスはデプロイメントと同様、Kubernetesのリソース)が生成され、Google Cloudロードバランサーも作成されます。
kubectl get servicesを走らせて、サービスのパブリックIPを確認します。コンソール出力はこ以下の通りです。
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world-deployment 10.103.254.137 35.185.127.224 3000:30877/TCP 9m
kubernetes 10.103.240.1 <none> 443/TCP 17d
サービスにアクセスするにはhttp://<EXTERNAL-IP>:<PORT>を確認します。専用のドメインを買って、このIPを指定します。
8.サービスをスケーリングする
サービスのトラフィックが増えて、アプリケーションのインスタンスを増やす必要が出てきたら、deployment.ymlファイルを編集して、replicasの数を変更します(たとえば3に)。それからkubectl apply -f deployment.ymlを実行すると、3つのpodが走ります。自動スケーリングの設定もできますが、チュートリアルの範囲外とします。
9.クリーンアップ
リソースのクリーンアップを忘れてはいけません。Googleクレジットがどんどんなくなります!
$ kubectl delete service/hello-world-deployment
$ kubectl delete deployment/hello-world-deployment
$ gcloud container clusters delete hello-world-cluster --zone us-east1-b
まとめ
幅広くカバーしましたが、Kubernetesは1つのコマンドでより多くのpodのサービスをスケーリングしたり、AWS認証などのためにpodにsecretをマウントしたりと、いろいろなことができます。しかし、最初はこのチュートリアルの内容で十分だと思います。もっとやってみたい人は、kubernetes.ioに挑戦してください。
本記事はGraham Coxが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。
(原文:Introduction to Kubernetes: How to Deploy a Node.js Docker App)
[翻訳:関 宏也/編集:Livit]