[初心者向け]IBM Cloud のKubernetesクラスタにNode.jsアプリをデプロイ

# はじめに
年が明けまして2020年を迎えましたが、皆様いかがお過ごしでしょうか。

2020年代は5Gの整備が完了し、IoTや自動運転技術が大いに浸透する10年であると言われていますが、2010年代も激動の１０年でした。
特に、2013年ごろから開発が始まったKubernetesがようやくGA段階となり、各クラウドベンダーでマネージドサービスとして展開されたことが大きかったと思います。
これによってコンテナ技術やマイクロサービスがより管理しやすくなり、これから様々なサービスが生まれ進化してくことでしょう。

今回は、初投稿ではありながら、これからKubernetesを触ってみたい！という方のために、私がいろんな文献や技術書を読み漁って勉強した、

<h4>Kubernetesでアプリケーションを外部公開する手順</h4>

を、IBM Cloudを用いて紹介しようと思います。

※なお、筆者も勉強し始めで、詳しい技術や論理は理解している途中でございますので、深く知りたい！という方はこの後の参考資料をご覧ください。
この記事はあくまでアプリを開発してKubernetesにデプロイするまでの流れを紹介するものです。

# Kubernetesとは?
|<img width="200px" alt="Kubernetesロゴ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/f6bdb634-33ae-ce9e-a935-ba2f0eaf518a.png">
|:-:|

###1. 読み方
そもそもどう読むの？くべ..くば..くばねってす？何語？ってなると思います。私もなりました。
いろんな動画を見ていると開発者の間ではクーバネ(ー)ティスと呼ばれているみたいです。クーバネティス。分かんねぇよ。
ギリシャ語で操舵手とか、航海長とかいう意味みたいですね。
では一体どういう技術何でしょうか？？

###2. Kubernetesとは
Wikipediaによれば
「<strong>コンテナ化したアプリケーションのデプロイ、スケーリング、および管理を行うための、オープンソースのコンテナオーケストレーションシステム</strong>」
とされています。

私が一番にお世話になった技術書(詳しくは後述の参考資料をご覧ください)にも
「<strong>コンテナ化されたアプリケーションを合理的に運用するために設計されたOSSのプラットフォーム</strong>」
として紹介されています。

すなわち、<strong>KubernetesはDockerなどでコンテナ化されたアプリケーションなどを運用、管理するために利用されるOSSのプラットフォーム</strong>ということですね。なんかすごそうですね。

それでは早速本題に入っていきます。

#開発環境
macOS
node.js 12.2.0
npm 6.13.4
docker cli 19.03.5

#前提条件
1. Node.js, npmがインストール済みである。
2. Gitコマンドが打てる。
3. Dockerアカウントを作成済みである。


#1. 事前準備
###1-1. IBM Cloudのアカウントを作成
まずはじめに、IBM Cloudのアカウントを作成しましょう。

Kubernetesの利用方法は数多くありますが、クラウドベンダーが提供するKubernetesマネージドサービスを利用すれば、必要なものが全て揃っているのでとても便利です。
これを使う手はありませんね。

**ここで注意ですが、IBM CloudのKubernetesサービス（以下、IKS）は、無料アカウントでは利用できず、クレジットカードの登録をして、<font color="Red">従量課金アカウントへアップグレードしなくてはいけません</font>。
しかし、だからと言って<font color="Red">お金がかかる訳ではなく</font>、1ヶ月間限定やワーカノードは１つのみなどの色々な制約はありますが、IKSにはフリークラスタの提供があり、Kubernetesを試すことは十分にできますのでご安心ください！**
サークルの仮入部みたいな感じですね。
やべ、Kubernetesサークル、ちょうたのちぃ...となれば会費払って正式に入部すればいい訳です。

まずは[ここ](https://www.ibm.com/jp-ja/cloud)にアクセスして、IBM Cloudのアカウント作成ページに飛んでください。

順調にアカウント作成が進んだら以下の画面に進むと思います。

|![コンソール画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/d15bdf7f-4200-8c7f-699c-de4d41fc0a93.png)
|:-:|

ここから、右上にある<font color="Red">アカウントのアップグレード</font>をポチりしてください。
必要な情報を入力して、`I accept the Cloud Service term`にチェックを入れたら完了です。はい、早い。

このダッシュボード画面はあとで操作するのでこのままにしておいてください。

###1-2. IBM Cloud CLIのインストール
続いてIBM Cloud CLIをインストールしましょう。

これは、ご自身のPCのターミナルやコマンドプロンプトでIBM Cloudのリソースを管理することができるコマンドラインインタフェースであり、同時にKubernetes CLIもインストールされるため、Kubernetesの操作がコマンドで可能になります。
基本的にこの先Kubernetesをコマンドで操作していくことになるので是非ともIBM Cloud CLIのインストールを完了させておいてください。

私はすでにインストールを済ませてあるのでインストールコマンドだけ載せておきます。(詳しくは[こちら](https://cloud.ibm.com/docs/cli?topic=cloud-cli-getting-started&locale=ja)をご覧ください。)

```bash:Terminal
#Mac, Linux用
$ curl -sL https://ibm.biz/idt-installer | bash
```

環境によってはインストールにかなり時間がかかると思います。

```bash:Terminal
$ ibmcloud -v
ibmcloud version 0.21.0+f5d1134-2019-12-16T07:34:45+00:00
```

```bash:Terminal
$ kubectl version --short
Client Version: v1.14.8
```
上記２つのコマンドを叩いてバージョンがうまく出ていればインストールは完了です！

#2. Webアプリケーションを作成
###2-1. Node.jsでアプリケーションを作成
事前準備が済んだら、早速デプロイするためのアプリケーションを作りましょう！
今回は<a href="https://github.com/rikkyrice/kube-sample-app">GitHub</a>に演習用の簡単なアプリケーションを作成しておきました。
是非使ってみてください。
Node.jsのアプリケーションです。
※Node.jsとnpmはインストール済みであることが前提条件です。

```bash:Terminal
$ git clone https://github.com/rikkyrice/kube-sample-app
Cloning into 'kube-sample-app'...
remote: Enumerating objects: 14, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 14 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (14/14), done.
```
これで簡単にkube-sample-appというNode.jsアプリケーションのディレクトリが作成されました。
アプリケーション自体はいたってシンプルで、以下のようなサイトが表示されます。

|![0.0.0.0-8080.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/b10ba142-05fc-85c1-7bba-a07cd3fd084a.png)
|:-:|

これでWebアプリケーションの作成は終了です。はやっ

#3. Dockerコンテナを作成する
続いてDockerにて生成したアプリケーションのコンテナを作成します。
Dockerはインストール済みであることが前提です。

###3-1. Dockerfileの作成
それでは、コンテナ化する際に必要になるDockerfileを作成しましょう。
Dockerfileにはコンテナを動作させる構成情報を記載していきます。
`kube-sample-app`をGitHubからcloneしてきた人はすでにディレクトリに`Dockerfile`があると思います。

```dockerfile:Dockerfile
FROM node:12
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD ["node", "app.js"]
```
###3-2. コンテナのイメージを作成し、DockerHubへpush
続いてTerminalにて、kube-sample-appディレクトリのファイルからコンテナのイメージを作成します。
以下のコマンドを`kube-sample-appディレクトリ`上で行ってください。
${ユーザ名}にはあなたのDockerHubのユーザ名を入力してください。
私の場合は`rikkyrice/kube-sample-app:0.1`となります。

```bash:Terminal
$ docker build --tag ${ユーザ名}/kube-sample-app:0.1 .
Sending build context to Docker daemon    106kB
Step 1/7 : FROM node:12
 ---> 6b5991bf650f
Step 2/7 : WORKDIR /usr/src/app
 ---> Running in 02ac3c501da8
Removing intermediate container 02ac3c501da8
 ---> 7e8b2f94b323
Step 3/7 : COPY package*.json ./
 ---> 90cd726f65d3
Step 4/7 : RUN npm install
 ---> Running in 3abe5e4c5677

> ejs@3.0.1 postinstall /usr/src/app/node_modules/ejs
> node ./postinstall.js

Thank you for installing EJS: built with the Jake JavaScript build tool (https://jakejs.com/)

added 64 packages from 39 contributors and audited 139 packages in 3.197s
found 2 moderate severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details
Removing intermediate container 3abe5e4c5677
 ---> 6882306b5a87
Step 5/7 : COPY . .
 ---> 4085a1edc12c
Step 6/7 : EXPOSE 8080
 ---> Running in 794847f8f427
Removing intermediate container 794847f8f427
 ---> f8147522bc79
Step 7/7 : CMD ["node", "app.js"]
 ---> Running in dadc7ad0b91e
Removing intermediate container dadc7ad0b91e
 ---> 1d08c3fe706c
Successfully built 1d08c3fe706c
Successfully tagged ${ユーザ名}/kube-sample-app:0.1

```
これでDockerイメージが`${ユーザ名}/kube-sample-app:0.1`という名前で作成され、ローカルリポジトリへ保存されました。
そこからDockerにログインし、ご自身のDockerHubのリモートリポジトリへイメージをpushします。
以下のコマンドを実行してください。

```bash:Terminal
$ docker login
Authenticating with existing credentials...
Login Succeeded
$ docker push ${ユーザ名}/kube-sample-app:0.1
The push refers to repository [docker.io/${ユーザ名}/kube-sample-app]
485558bdae5c: Pushed 
fe34ac93a512: Pushed 
91da8ffeb073: Pushed 
e204a1f85920: Pushed 
af817f759558: Pushed 
b5aa4fb76f12: Pushed 
f68782bbfa17: Pushed 
42f9c2f9c08e: Pushed 
99e8bd3efaaf: Pushed 
bee1e39d7c3a: Pushed 
1f59a4b2e206: Pushed 
0ca7f54856c0: Pushed 
ebb9ae013834: Pushed 
0.1: digest: sha256:15270113aa252fedf81d41066dd21a2cd7143fed7dc27649971bd9a6f2901ded size: 3051
```
これでご自身のDockerHubへイメージが格納されました。

<h4>いよいよKubernetesを触っていきます！</h4>

#4. Kubernetesクラスタの作成
それではKubernetesのクラスタを作成しましょう。
基本的にアプリケーションはこのKubernetesクラスタのワーカノードが実行していきます。

###4-1. IBM CloudからKubernetesクラスタを作成
先ほど事前準備で行ったIBM Cloudのアカウントダッシュボードを再度開いてください。

|![ダッシュボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/663eef5b-bbaa-d18b-a2c5-9e485c38fddb.png)
|:-:|

この右上にある`リソースの作成`または`カタログ`を押すと、IBM Cloudのサービスを選択できる画面に進みます。
そこから`カタログの検索`に`kubernetes`と入力し、<font color="blue">Kubernetes Service</font>を選択しましょう。

|![カタログ-kubernetes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/840c1f48-4a80-b810-c419-6c11c0ac99c3.png)
|:-:|

画面が移動したらそのまま`Create`を押しましょう。

|![Kubernetes説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/5cd5867c-43e1-d486-d67e-917359e81a1c.png)
|:-:|

クラスタの作成画面に移ります。
初期設定では`Standard`が選択されていると思いますが、`Free`を選択しましょう。
アカウントごとに一意の名前を自由に決められますが、今回は`mycluster`としておきます。
`Create cluster`を押してKubernetesクラスタを作成します！

|![cluster作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/7f16bc9f-65e8-7667-a44f-7ea431c77e59.png)
|:-:|

Kubernetesクラスタの作成は約10分ほどかかります。
正月に余ったお餅でも食べながら気長に待ちましょう。

これでクラスタの作成は終了です。
次からはついにコンテナをクラスタへデプロイしていきます！

#5. Kubernetesへコンテナをデプロイ
さぁついに最終章です。
Kubernetesにコンテナをデプロイしていきます！

###5-1. ibmcloudへログイン
まずはターミナルを開いて、ibmcloudへログインしてください。

```bash:Terminal
$ ibmcloud login
```
このコマンドを叩くと、対話型のログインプロセスが起動します。
事前準備で作成したご自身のIBM Cloudアカウントのメールアドレスとパスワードを入力して、ログインを完了させてください。
<font color="#60C60D">OK</font>と出れば、ログイン成功です。

###5-2. Kubernetesをターミナルで操作
これから、IBM Cloudのダッシュボードで作成したKubernetesクラスタをターミナルで操作していくための準備をしていきます。
まず、作成したIBM CloudのKubernetesクラスタの画面の`Access`タブを開き、次に`After your cluster provisions, gain access`を順に実行していきます。

|![clusterダッシュボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/9f8e60a3-dc84-6546-e8f5-9c46a7dea6d1.png)
|:-:|

ターミナルを開いて、以下のコードを叩いてください。
Kubernetesクラスタの画面のコードをコピペすれば大丈夫です。

```bash:Terminal
$ ibmcloud ks cluster config --cluster ${クラスタid}
```
正常に動作すると、環境変数が吐き出されると思います。
これをexportします。

```bash:Terminal

OK
mycluster の構成は正常にダウンロードされました。

環境変数をエクスポートして Kubernetes の使用を開始してください。

export KUBECONFIG=/Users/hashikiriku/.bluemix/plugins/container-service/clusters/mycluster/kube-config-hou02-mycluster.yml

$ export KUBECONFIG=/Users/hashikiriku/.bluemix/plugins/container-service/clusters/mycluster/kube-config-hou02-mycluster.yml
```
これで、指定したKubernetesクラスタを端末で操作することができるようになりました！
試しに以下のコマンドを叩いてみましょう。

```bash:Terminal
$ kubectl get node
NAME            STATUS   ROLES    AGE     VERSION
10.76.215.133   Ready    <none>   6m45s   v1.14.9+IKS
```
うまくワーカノードが表示されていますね。

###5-3. deployment.ymlとservice.ymlを作成、実行
さぁ、Kubernetesクラスタにアクセスできるようになったので、いよいよコンテナをデプロイしていきます。

コンテナをデプロイするためにはポッドを作成し、そこにコンテナを配置する必要があります。
そのポッドを作成したり、稼働数を管理するのに用いられるのがデプロイメントです。
今回はこのデプロイメントをdeployment.ymlというマニフェストファイルに記述していきます。
GitHubからkube-sample-appをcloneしてきた方はすでにディレクトリに存在していると思います。
deployment.ymlのspec.template.spec.containers[1].imageの${ユーザ名}は、ご自身のDockerHubアカウントのユーザ名に書き換えてください。

```yml:deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-sample-app
spec:
  replicas: 5
  selector:
    matchLabels:
      app: kube-sample-app
  template:
    metadata:
      labels:
        app: kube-sample-app
    spec:
      containers:
      - name: kube-sample-app
        image: ${ユーザ名}/kube-sample-app:0.1
        command:
        ports:
        - containerPort: 8080
```

これをターミナルで実行します。

```bash:Terminal
$ kubectl apply -f deployment.yml
deployment.apps/kube-sample-app created
```
これでポッドが作成されました。
今回はreplicasを5と設定し、稼働するポッドを5個生成するようにしました。
試しにポッドが5個作動しているか見てみます。

```bash:Terminal
$ kubectl get pod
NAME                              READY   STATUS    RESTARTS   AGE
kube-sample-app-f6478fbcc-74s4t   1/1     Running   0          3m18s
kube-sample-app-f6478fbcc-bbncl   1/1     Running   0          3m18s
kube-sample-app-f6478fbcc-lgk79   1/1     Running   0          3m18s
kube-sample-app-f6478fbcc-tplh6   1/1     Running   0          3m18s
kube-sample-app-f6478fbcc-znxq5   1/1     Running   0          3m18s
```
うまく動いているのがわかります。

しかし、これだけではブラウザからアクセスできません。
そこで、クライアントからのリクエストを受けるために必要なのがサービスです。
サービスにはいくつかタイプがあるのですが、今回はNodePortというタイプを用いて、ノードのIPアドレスに公開用ポート番号を開きます。
これで外部クライアントもポッドへアクセスすることができます。
今回はservice.ymlに設定を書き込んでいます。

```yml:service.yml
kind: Service
apiVersion: v1
metadata:
  name: kube-sample-app-service
spec:
  type: NodePort
  selector:
    app: kube-sample-app
  ports:
  - name: webserver
    protocol: TCP
    port: 8080
```
これをターミナルで実行します。

```bash:Terminal
$ kubectl apply -f service.yml
service/kube-sample-app-service created
```
これで外部ネットワークへ公開する準備が整いました。
アクセスURLはKubernetesクラスタが持つパブリックIPアドレスに公開用ポートが付与された形で提供されています。
KubernetesクラスタのパブリックIPアドレスはIBM CloudのKubernetesクラスタの管理画面でも確認できますが、以下のコマンドでも確認することができます。

```bash:Terminal
$ ibmcloud ks workers ${クラスタ名}
OK
ID                                                     パブリック IP       プライベート IP      フレーバー    状態     状況     ゾーン     バージョン   
kube-bo6of95d0e80ipchv6ag-mycluster-default-000000a8   184.***.***.**   10.76.215.133     free       normal   Ready   hou02    1.14.9_1544   
```
このパブリック IPというのがKubernetesクラスタのパブリックIPアドレスになります。
さらに以下のコマンドで、サービスがどの公開用ポートで開いているかを確認することができます。

```bash:Terminal
$ kubectl get service kube-sample-app-service
NAME                      TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kube-sample-app-service   NodePort   172.21.213.190   <none>        8080:32175/TCP   28s
```
このPORT(S)にある、32175というのが公開用ポート番号です。
これで公開されているURLがわかりました。
私の環境では`http://184.***.***.**:32175/`でアプリケーションが公開されています。
早速ブラウザで動作を確認してみましょう。

|![ブラウザ-アプリ確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/8ca281b5-be90-4e64-e0b7-9c175665a72f.png)
|:-:|

<h4>うまくアクセスできましたね！</h4>

他にもKubernetesには様々な機能があります。
例えばイングレスという機能を使えば、公開用のURLのパスへアプリケーションをマッピングしたり、HTTPS通信を実装したりすることもできます。
しかし、イングレスは標準クラスタのみでしか利用できません...残念っ
もし利用したかったら新しくフリークラスタではなく、標準クラスタを作成しましょう！

これ以外にもKubernetesには様々な機能があります。
私も今後もっともっと勉強して様々な技術をQiitaを通して紹介していこうと思います。

#参考資料
###・15Stepで習得 Dockerから入るKubernetes 高良真穂(著)<br>
 <img width="200px" alt="Dockerから入るKubernetes" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/87e73932-4134-22c1-6b7e-c5c1dcc9b579.jpeg">
<strong>私がもっともお世話になった技術書です。</strong>Kubernetesのことはもちろん、Dockerのことについても詳しく紹介されており、大変参考になります。今も隣にあります。私のこのQiita記事はこの本を参考に書いてありますので、もっともっと詳しく知りたい！という方は是非ともこの本を買って読んでください。個人開発から法人のシステム開発まで幅広く適用できる技術書です。また、IBM Cloud以外にも、GCPでのKubernetesの利用方法も書かれていますので、多くの方をターゲットにされた本だと思います。
amazonリンク (https://www.amazon.co.jp/dp/B08221TFBH/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

###・IBM Japan Channel(Youtube)
<img width="300px alt="IBM Japan Channel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544053/5812c501-4da0-851b-660e-c4165c0d0711.png">
<strong>Youtubeチャンネルですね。</strong>これも大変お世話になっています。Kubernetesのハンズオンの紹介や、概念の説明をしたり、Kubernetesを小人の世界に例えて紹介されたりしています。是非ご覧ください。
URL(https://www.youtube.com/channel/UCR5bQwLkDls81oOkKbx45dw)

他にも色々参考にさせていただきましたが（例えばIBM公式の資料など）、最も参考にさせていただいた2点を紹介させていただきました。

#終わりに
今回初めてQiitaの記事を書かせていただきました。
色々至らぬ点があると思います。
ここ間違ってるよ、とか、ここおかしいよ、とか。
是非ともご指摘いただければと存じます。
すぐに修正し、これからの励みにさせていただきます。
最後まで読んでいただきまして誠にありがとうございました。
良いお年を。