Raspberry Pi 4(1台)でKubernetes環境を構築 (Raspberry Pi 4 + Ubuntu 19.10 + MicroK8s) Part2 (Webアプリ編)

# 前回の記事

[Raspberry Pi 4(1台)でKubernetes環境を構築 (Raspberry Pi 4 + Ubuntu 19.10 + MicroK8s)](https://qiita.com/toyotoyo_/items/c58b8d318bee2c735793)

前回の記事では「Raspberry Pi 4」に「Ubuntu 19.10」OSを入れ、「MicroK8s」をインストールし、Kubernetes環境構築と簡単な動作確認するところまで行いました。


![Raspberry Pi 4 組み立て2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397682/fa8653b2-5d60-a561-bcb6-be094b03e084.jpeg)


# 今回の記事

今回の記事では実際にkubernetesのマニフェストファイルを作成し、ラズパイ上でWebアプリケーション(express)を動かしてみたいと思います。
環境については前回の記事まで出来ている前提で進めています。

## とりあえず何か動くもの？
試すWebアプリケーションは何でもよかったのですが、Dockerイメージ作成から行ってみたかったので
少し調べてみたところ、Node公式のexpressの記事が丁寧に書いていたのでこれをもとにdockerイメージを作成してみようと思います。


## docker のインストール
docker イメージ作成のため docker build を行いたいので、まずはdockerをインストールします。

```
sudo apt install docker.io
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
```

## Node.js Web アプリケーション の Docker イメージ作成
Node.js公式の
[Node.js Web アプリケーションを Docker 化する](https://nodejs.org/ja/docs/guides/nodejs-docker-webapp/)
を参考にDockerイメージを作成していきます。

### ファイルを準備
適当なフォルダを作成し、そこにファイルを作っていきます。
※ 文字コード: UTF-8 , 改行コード: LF 


```
$ mkdir docker_web_app
```

```package.json
{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "First Last <first.last@example.com>",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  }
}
```

```server.js
'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
```

Dockerイメージを作成するためのDockerfile

```Dockerfile
FROM node:12

# アプリケーションディレクトリを作成する
WORKDIR /usr/src/app

# アプリケーションの依存関係をインストールする
# ワイルドカードを使用して、package.json と package-lock.json の両方が確実にコピーされるようにします。
# 可能であれば (npm@5+)
COPY package*.json ./

RUN npm install
# 本番用にコードを作成している場合
# RUN npm install --only=production

# アプリケーションのソースをバンドルする
COPY . .

EXPOSE 8080
CMD [ "node", "server.js" ]
```

### dockerイメージを作成

```
ubuntu@ubuntu:~/node-web-app$ docker build -t node-web-app-test .
Sending build context to Docker daemon  4.608kB
Step 1/7 : FROM node:12
12: Pulling from library/node
84582781a9f0: Already exists
2aaedfc98967: Already exists
cfa6bb03021f: Already exists
6a4110ff81d0: Already exists
e867f7ebdcf1: Already exists
2f16af5fb418: Already exists
cfc1102c13fa: Pull complete
9e6855539b2a: Pull complete
b5c194de032e: Pull complete
Digest: sha256:46f4c17e1edbde36d60a9f6362db7912cfe301bac89afef7cc92421ab3e7ca18
Status: Downloaded newer image for node:12
 ---> 694bb044bce1
Step 2/7 : WORKDIR /usr/src/app
 ---> Running in 536f08e477ba
Removing intermediate container 536f08e477ba
 ---> 12ccd9c86b57
Step 3/7 : COPY package*.json ./
 ---> ef6d92e05eba
Step 4/7 : RUN npm install
 ---> Running in ce1481d407dc
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN docker_web_app@1.0.0 No repository field.
npm WARN docker_web_app@1.0.0 No license field.

added 50 packages from 37 contributors and audited 126 packages in 4.84s
found 0 vulnerabilities

Removing intermediate container ce1481d407dc
 ---> c83c3ed164a4
Step 5/7 : COPY . .
 ---> 1d1529685c13
Step 6/7 : EXPOSE 8080
 ---> Running in 4641a7aeda76
Removing intermediate container 4641a7aeda76
 ---> 667730c72077
Step 7/7 : CMD [ "node", "server.js" ]
 ---> Running in 28e2e97e3e4b
Removing intermediate container 28e2e97e3e4b
 ---> 8a4d60b76312
Successfully built 8a4d60b76312
Successfully tagged node-web-app-test:latest
```

### 作成できたイメージを、確認のため動かしてみる

```
ubuntu@ubuntu:~/node-web-app$ docker run -p 49160:8080 -d node-web-app-test
1ca0cb8ecb347fdc66ce1c1d6a6e9580f5733e58fa66bb3b34da68411aa0184a
```
### ブラウザでアクセスしてみる
私のラズパイのIPが192.168.11.20だったので
http://192.168.11.20:49160
で確認
![node-web-app-test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397682/be203b20-ffb3-fa0f-af9a-5b62568ac175.png)

アクセス出来ましたね

### とりあえず一度掃除します
docker stop と docker rm を実行

```
ubuntu@ubuntu:~/node-web-app$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                     NAMES
1ca0cb8ecb34        node-web-app-test       "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:49160->8080/tcp   lucid_dubinsky
ubuntu@ubuntu:~/node-web-app$ docker stop 1ca0cb8ecb34
1ca0cb8ecb34
ubuntu@ubuntu:~/node-web-app$ docker rm 1ca0cb8ecb34
1ca0cb8ecb34

```
これできれいになりましたね。

## MicroK8sでローカルのdockerイメージを使用
MicroK8sでローカルのdockerイメージを使用するためには一工夫いるみたいです。

### イメージ確認
```
ubuntu@ubuntu:~/node-web-app$ docker images | grep node-web-app
node-web-app-test           latest              8a4d60b76312        36 minutes ago      868MB
```

### イメージタグを:localに変更

```
ubuntu@ubuntu:~/node-web-app$ docker tag node-web-app-test:latest node-web-app-test:local
```

### イメージ確認

```
ubuntu@ubuntu:~/node-web-app$ docker images | grep node-web-app
node-web-app-test           latest              8a4d60b76312        37 minutes ago      868MB
node-web-app-test           local               8a4d60b76312        37 minutes ago      868MB
```

### イメージをセーブ

```
ubuntu@ubuntu:~/node-web-app$ docker save node-web-app-test:local > image.tar
```

### イメージを microk8s へロード

```
ubuntu@ubuntu:~/node-web-app$ microk8s ctr image import image.tar
unpacking docker.io/library/node-web-app-test:local (sha256:2e85de5a19c3cd98f07d8ae3f039ff6f47076e717a41a35b4da23ce0309d9243)...done
```

### microk8s のイメージを確認

```
ubuntu@ubuntu:~/node-web-app$ microk8s ctr images ls | grep node-web-app
docker.io/library/node-web-app-test:local
application/vnd.oci.image.manifest.v1+json
sha256:2e85de5a19c3cd98f07d8ae3f039ff6f47076e717a41a35b4da23ce0309d9243 856.4 MiB linux/arm64
io.cri-containerd.image=managed
```
これでローカルのdockerイメージを使用できるようになりました。

## kubernetesのマニフェストファイル作成

Deploymentを作成しておくと、何か障害が起きてシステムエラーでコンテナ(pod)が落ちても、コンテナ(pod)を再度起動してくれるようになります。
※ マニフェストファイル作成の単位の基準はないのですが、私はkindごとに分けるようにしています。

```deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-web-app-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-web-app-test
  template:
    metadata:
      labels:
        app: node-web-app-test
    spec:
      containers:
      - name: node-web-app-test
        image: node-web-app-test:local
        imagePullPolicy: Never # ローカルのイメージ使用の場合のみ
      restartPolicy: Always
```


```service.yaml
apiVersion: v1
kind: Service
metadata:
  name: node-web-app-test
spec:
  selector:
    app: node-web-app-test
  ports:
  - protocol: TCP
    port: 8080
    nodePort: 31200
  type: NodePort
```


## デプロイ実行

```
ubuntu@ubuntu:~/node-web-app$ kubectl apply -f deployment.yaml
deployment.apps/node-web-app-test created
```

ポッドの確認

```
ubuntu@ubuntu:~/node-web-app$ kubectl get po
NAME                                 READY   STATUS    RESTARTS   AGE
node-web-app-test-69f4c59b6f-bwsrv   1/1     Running   0          56m
```

## サービス実行
```
ubuntu@ubuntu:~/node-web-app$ kubectl apply -f service.yaml
service/node-web-app-test configured
```

サービスの確認

```
ubuntu@ubuntu:~/node-web-app$ kubectl get svc
NAME                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes          ClusterIP   10.152.183.1     <none>        443/TCP          35d
node-web-app-test   NodePort    10.152.183.157   <none>        8080:31200/TCP   74m
```

### ブラウザでアクセスしてみる
私のラズパイのIPが192.168.11.20だったので
http://192.168.11.20:31200
で確認
![node-web-app-test-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397682/90c11b21-7ef6-0c75-dcc1-4fd75437b7c9.png)

アクセス出来ましたね！！！

## まとめ
とりあえずWebアプリケーションを起動できましたね(●´ω｀●)

確認したソースも[github/microk8s-node-web-app-test](https://github.com/toyo-toyo/microk8s-node-web-app-test)にあげています。


少し調べるところもありましたが、比較的簡単に起動できました。
Dockerイメージはローカル分を使うのではなく、DockerHub にでもPushしたほうがもっと楽に出来そうですね(´・ω・｀)

気力があれば、ラズパイらしくGPIO周りも試していきたいと思います！！