Google Kubernetes Engineでアプリを動かしてみる

こんにちは、虎の穴ラボのM.Uです。

弊社が運用してるクリエイター支援プラットフォームである Fantia は Google Cloud Platform (以下,GCP)上で稼働しています。業務内では Google Compute Engine(以下,GCE)や Cloud Load Balancing などを利用していますが、今回はGCPの一つであるGoogle Kubernetes Engine(以下,GKE)を触ってみたので、その紹介をしてみたいと思います。

全体の流れ

  1. Kubernetesとは
  2. Node.jsで動く簡単なWebアプリを作成
  3. Docker image作成/ローカルで実行確認
  4. Google Cloud SDKの設定
  5. 作成した Docker imageをContainer Registryへpush
  6. GKEでアプリをデプロイする

1. Kubernetesとは

Kubernetesとは Dockerを使ってコンテナ化したアプリケーションのデプロイやスケーリングなどができるオープンソースのプラットフォームです。
複数サーバでのコンテナを管理する機能を持っていて、実際にコンテナが動作するノードとよばれるサーバーとノードのリソース使用状況を監視してコンテナを起動させるマスターサーバーがあります。その他にも、Dockerイメージを管理するレジストリサーバーも含まれます。
GKEは Kubernetes の機能をGCP内部で実現する仕組みです。例えば、ノードは実際にはGCEのインスタンスとして稼働しています。また Dockerのイメージファイルは Container Registryというサービスで push するようになっていますが、実際には Cloud Storage にバケットが作成されそこに保存されます。
Kubernetes の制御は kubectl コマンドが使えます。

今回はNode.jsで単純にテキストをブラウザに表示するアプリを作成したものをGKEでデプロイまで試します。

2. Node.jsで動く簡単なWebアプリを作成

Kubernetesは複数の Docker 環境をクラスタ化する仕組みです。まずは、Docker環境のWebサービスを動かすDockerイメージを用意する必要があります。
ネット上で一般公開しているNginxが入っている Dockerイメージを使ってもよいですが、せっかくなので簡単なアプリを実装してそれを Docker イメージにするところから初めてみましょう。
まずは、テキストを表示するだけの簡単なアプリを用意します。

main.js というファイルを作って"Google Kubernetes Engine"と表示させます。

var express = require('express');
var app = express();

var server = app.listen(8000, () => {
    console.log("Start express. port:" + server.address().port)
});

app.get('/', (req, res) => {
    res.send('Google Kubernetes Engine')
});


package.json ファイルの定義は以下のような具合で npmコマンドからモジュールのインストールが出来るようにします。 

{
    "name": "hello-server",
    "version": "1.0.0",
    "description": "",
    "main": "main.js",
    "scripts": {
        "start": "node main.js",
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "m.u",
    "license": "MIT",
    "dependencies": {
        "express": "^4.16.3"
    }
}


次に Dockerのimageファイルを作成するための定義ファイルを作ります。ファイル名は Dockerfile です。

FROM node:8

ADD package.json /app/package.json
RUN cd /app && npm install
ADD main.js /app/

CMD cd /app && npm start

3. Docker image作成/ローカルで実行確認

 
作成した DockerfileからDockerイメージを作成します。カレントディレクトリに Dockerfile がある事を確認し、次のコマンドを実行します。
ここで気をつけることは Google Container Registryへpushするためにタグ付きで作成することです。

$ docker build -t ホスト名/プロジェクト名/イメージ名:タグ .

ホスト名:push先のリージョンに当たります。他にも gcr.io などがありますが、今回は asia.gcr.io にします。
プロジェクト名:今回利用しているGCPのプロジェクト名です。今回動かすプロジェクト名は mu-sample です。
イメージ名タグ名は任意で命名できます。今回は hello-server:v1 とします。

$ docker build -t asia.gcr.io/mu-sample/hello-server:v1 .

Dockerイメージが出来ました。まずはローカルで動作できるか確認してみましょう。

$ docker run -p 8000:8000 -d hello-server:1.0

http://localhost:8000/でアクセスすると以下のように"Google Kubernetes Engine"と表示されることを確認します。

f:id:toranoana-lab:20181002194826p:plain

4. Google Cloud SDKの設定

Google Cloud SDKのコマンド gcloud を使用しますが、今回はSDKのインストール手順は割愛します。
以降の gcloudコマンドがどのアカウントで実行されるのかを設定します。

$ gcloud config set account アカウント名

※gcloud auth list で現在どのアカウントが設定されているのかが確認できます。

アカウント認証を行います。次のコマンドを実行するとブラウザが起動してログイン認証を求められます。
許可ボタンを押すとコンソール側ではログインに成功したメッセージが来ます。

$ gcloud auth login

gcloud configを使ってプロジェクトの設定を行います。

gcloud config set project mu-sample

先にGKEのデプロイを行うための kubectlコマンドをインストールしておきましょう。

gcloud components install kubectl

5. 作成した Docker imageをContainer Registryへpush

Docker認証ヘルパーについて

コンテナイメージをContainer Registryへpushする gcloud dockerコマンドが存在しましたが、こちらはDockerクライアントバージョンが1.13以前までとなるようです。
よって、gcloudコマンドではなくdockerコマンドで GCPへの認証を行う必要があります。
Authentication Methods  |  Container Registry  |  Google Cloud

Docker認証ヘルパー ツールをインストールします。

gcloud components install docker-credential-gcr

Container Registryが使えるように認証コマンドを実行します。

docker-credential-gcr configure-docker

次のコマンドでアクセストークンを取得し docker loginを実行させています。

gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://asia.gcr.io

成功すると Login Succeeded と返ってきます。
これで Container Registryへ pushできるようになります。

Container Registryへpush

docker push asia.gcr.io/mu-sample/hello-server:v1

GCPコンソール画面から Container Registry 画面を見てみましょう。
Dockerイメージがリポジトリに新たに作成されていれば成功です。

f:id:toranoana-lab:20180930012941p:plain

6. GKEでアプリをデプロイする

Kubernetes クラスタの作成

以下のコマンドでGKEコマンドで操作するインスタンスを作成します。
最初の説明でもありましたとおり、Kubernetesはコンテナが動作するサーバーをノードと読んでいます。
以下のコマンドの --num-nodesパラメータでノード数を3つにしています。

gcloud container clusters create sample-cluster --num-nodes=3

また、このサーバーはGoogle Compute Engine(以下、GCE)のインスタンスです。
コンソールからGCEの画面へいくとVMインスタンスが3つ立ち上がっているのが確認できます。

アプリケーションのデプロイ

ついにデプロイです。 hello-server は任意の名前です。
GKEのワークロードの名前として管理されます。ポートの指定は今回のアプリは8000番を指定しているので
コンテナーでも公開するポートを同一にします。

kubectl run hello-server --image=asia.gcr.io/mu-sample/hello-server:v1 --port 8000

アプリを外部に公開する

一時的に外部から接続できるようにしてみましょう。

kubectl expose deployment hello-server --type=LoadBalancer --port 80 --target-port 8000

GCPコンソールのネットワークを見ると新たにロードバランサーが作成されています。
kubectl get service コマンドでクラスターの情報を取得することが出来ます。

$ kubectl get service
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
hello-server   LoadBalancer   10.31.253.187   xxx.xxx.xxx.xxx   80:30680/TCP   57s

EXTERNAL-IP が外部向けのIPアドレスになります。
ブラウザでアクセスすると、ローカルで実行した時と同様「Google Kubernetes Engine」と表示されます。

サービスとクラスターの削除

このままだとインスタンスが起動したままなので、サービスの停止とクラスターの削除を行います。

$ kubectl delete service hello-server
$ gcloud container clusters delete sample-cluster

最後に

GKEがどのような操作を通してKubernetesのデプロイを実現しているのかを見ていきました。
今回はデプロイ作業のみに絞って Kubernetes の概要を割愛しています。
公式ドキュメントも充実していますので、Kubernetes をすぐに体験したいならば、GKEを使ってみてはいかがでしょうか。


10/30(火) に『とらのあな開発室』の採用説明会を秋葉原で開催します! Webエンジニアがメインの説明会となりますが、デザイナー、ディレクターもあわせて募集していますので、ぜひ気軽にご参加下さい!
yumenosora.connpass.com


虎の穴ではJavascriptエンジニアをはじめとして一緒に働く仲間を絶賛募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。
www.toranoana.jp