【リモートアクセス対応】Kubernetesクラスタ上で動くVue開発環境を自宅に構築する


## はじめに
### 記事の概要
ブラウザ上でVueアプリケーションを作成できる、リモートアクセス可能な開発環境を自宅に構築しました。
やったことと参考になった記事のまとめです。

---

今回作ったものは以下です。

![usecase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/0c154da3-e520-7cbd-f0e6-7ec57862b105.png)

- Vueプロジェクトの作成、ホットリロード可能なdev serverの起動ができる
- ブラウザ上で動くテキストエディタでコーディングできる
- ソースコードを個人用のリモートリポジトリにpushして管理できる
- 外出先からインターネット越しに接続して開発できる

---

### デモ
![demo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/668cad7f-4443-8937-f3e5-0ecb21827eea.png)

---

### それクラウドでよくない？
はい

AWS Cloud9やGCPのCloud Shellで同じことができます。
データ保管含め自宅内で完結する、運用コストが電気代だけで済む、などをメリットと言うこともできますが...あくまで趣味向けです。

---

### 筆者について
[GitHubアカウント](https://github.com/pb10005)

自己紹介はプロフィールページに書きました。興味があれば読んでいただけると幸いです。

---

## やったこと
以下の手順で実施しました。それぞれやったことと参考にした記事を書いていきます。
1.ハードウェア・ネットワークのセットアップ
2.OSインストール〜k8sクラスタ構築
3.NFSサーバの構築
4.クラスタへのアプリケーションのデプロイ
5.DNSサーバの構築
6.リバースプロキシサーバの構築
7.VPNサーバの構築

---

### 0.全体構成
以下の考えを踏まえて構成を決めました。

- IPアドレスとポートを指定して接続するのは煩わしいし、どのポートがどのサービスを指すかわかりにくいので、ドメイン名指定で接続できるようDNS兼リバースプロキシサーバを用意します。
- Vue CLIなどのサービスはKubernetesクラスタ上で動かします。
- サービス間でストレージを共有したいので、SSDをマウントしたファイルサーバを用意します。
- リモートアクセス用にVPNサーバを構築します。これにより外部に晒すポートは443(VPN用)のみでよくなります。

---

#### ネットワーク構成
ネットワーク構成は下図の通りです。

![network.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/b6f92b67-ee71-74a5-8724-e65933ab59f7.png)

---

#### サービス構成
サービスの構成は下図の通りです。

![service.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/0470177f-f319-6ff4-842d-1f011ea2d432.png)

---

構成が決まったので作っていきます。それぞれググったら良記事があったので、手順通りやっていけばできました。

---
### 1.ハードウェア・ネットワークのセットアップ
必要なハードウェアを買って組み立てと配線を行います。

Raspberry Pi 4でKubernetesクラスターを構築する【ハードウェア編】
https://qiita.com/butterv/items/4b7868a3007d5652fe2b

---

#### 用意したもの
総額は60,944円でした(もともと家にあったものはカウント外にしています)。

|用途|機器名|価格|
|:---:|:---:|---:|
|クラスタ|[Raspberry Pi4 model B](https://www.amazon.co.jp/gp/product/B081YD3VL5/ref=ppx_yo_dt_b_asin_title_o03_s01?ie=UTF8&psc=1)　×４|29,128円|
|クラスタ|[GeekPi Raspberry Pi クラスタケース](https://www.amazon.co.jp/gp/product/B083FCLLQV/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1)　×1|4,029円|
|OSインストール|[Samsung MicroSDカード(32GB)](https://www.amazon.co.jp/gp/product/B06XSV23T1/ref=ppx_od_dt_b_asin_title_s00?ie=UTF8&psc=1) ×４|7,282円|
|ファイルサーバ|Raspberry Pi3 model B　×1|-|
|ファイルサーバ|[SanDisk 2.5インチSSD(1TB)](https://www.amazon.co.jp/gp/product/B071KGRXRG/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)　×1|13,333円|
|VPN兼DNSサーバ|PC(Ubuntu 20.04インストール済み)　×1|-|
|インターネット接続|Buffalo AirStation 無線ルータ|-|
|LAN接続|[Buffalo スイッチングハブ(5ポート)](https://www.amazon.co.jp/gp/product/B07VND79X9/ref=ppx_od_dt_b_asin_title_s00?ie=UTF8&psc=1)　×1|1,280円|
|LAN接続|[Buffalo LANケーブル](https://www.amazon.co.jp/gp/product/B008RVY4GK/ref=ppx_od_dt_b_asin_title_s00?ie=UTF8&psc=1)　×5|1,345円|
|給電|[NIMASO USB typeC to USB typeAケーブル](https://www.amazon.co.jp/gp/product/B08CRDMTX5/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1)　×4|1,948円|
|給電|[Anker USB充電器(5ポート)](https://www.amazon.co.jp/gp/product/B01GRHQ5US/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) ×1|2,599円|

---

以下が組み立てと配線の終わった状態です。

![cluster.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/e5e66b3b-56d9-3f06-4f19-7e6a21b2889b.jpeg)

---

### 2.OSインストール〜 k8sクラスタ構築
Raspberry Pi 4台にRaspberry Pi OSをインストールして、masterノード1台、workerノード3台のk8sクラスタを構築します。

Raspberry Pi 4でKubernetesクラスターを構築する【ソフトウェア編】
https://qiita.com/butterv/items/93bd5e46e4ce71e8e5f5

SDカードにイメージを書き込む際は、公式の`Raspberry Pi Imager`を使いました。
https://www.raspberrypi.org/software/

---

### 3.NFSサーバの構築
開発環境の共有ストレージとしてファイルサーバを構築します。
家にあったRaspberry Pi3にSSDをマウントしてNFSサーバを起動します。

UbuntuでSSDをマウント
https://qiita.com/sasadango/items/fcb657d3b4bbd39c3497

ラズパイにNFSサーバを構築する
https://qiita.com/sosomasox/items/5106ea8ce110d9e2315e

---

### 4.クラスタへのアプリケーションのデプロイ
`Docker Hub`で使えそうなイメージを探してきてデプロイします。
Raspberry PiがARMアーキテクチャなので、ARMに対応したイメージを探しました。

- Vue CLI UI: 使えそうなイメージがなかったのでDockerfileを書きました。
- Eclipse theia: [keyglitch/theia-docker-armv6](https://hub.docker.com/r/keyglitch/theia-docker-armv6)
- Gitea: [kunde21/gitea-arm](https://hub.docker.com/r/kunde21/gitea-arm)
    - データの永続化方法はいくつか選択肢がありますが、今回はシンプルに`sqlite`にしました。

---

### 5.DNSサーバの構築
開発環境にブラウザからアクセスする際のURLとなるドメイン名を設定するために、
`Bind`を使ってDNSサーバを構築します。

CNAMEを使ってサービスごとにエイリアスを設定します。

|ドメイン名|レコード|サービス|
|---|---|---|
|proxy|A|Nginx|
|vuecli|CNAME|Vue CLI UI|
|vue|CNAME|Vue CLI UIでserveしたときに表示するページ|
|theia|CNAME|Eclipse theia|
|gitea|CNAME|Gitea|

BIND : 内部ネットワーク向けの設定
https://www.server-world.info/query?os=Ubuntu_20.04&p=dns&f=1

---

### 6.リバースプロキシサーバの構築
Ubuntuをリバースプロキシサーバとして使います。
80番ポートでリクエストを受けて、ドメイン名によって宛先を振り分けます。`Nginx`のリバースプロキシ機能を使って実現します。

【Nginx】リバースプロキシサーバ構築
https://qiita.com/OPySPGcLYpJE0Tc/items/1f4219a51980a75696b5

Vue CLIとtheiaではWebSocketを使うので、httpをWebSocketにupgradeする設定が必要です。

NginxのリバースプロキシでWebソケットを通す際の設定
https://qiita.com/YuukiMiyoshi/items/d56d99be7fb8f69a751b

---

### 7.VPNサーバの構築
自宅LANへのリモートアクセスを実現するために`OpenVPN`を使ってVPNサーバを構築します。
参考記事が長い！のですが上から順にやっていけば問題なく構築できました。

Ubuntu 20.04でOpenVPNサーバーをセットアップ・設定する方法
https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-ubuntu-20-04-ja

※一つだけ追加手順があります。VPNに接続したときに参照するDNSサーバを指定するため、`~/client-configs/base.conf`に以下を追記します。

```conf
dhcp-option DNS XXX.XXX.XXX.16
```
---

### 動作確認
外出先でChromebookから接続確認しました。

---

#### VPN接続
VPNクライアントアプリはPlayストアからイントールできます。

https://play.google.com/store/apps/details?id=net.openvpn.openvpn
![vpn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/009181fc-fe7d-5926-341c-e84edd4b9955.png)

---

#### Eclipse theia
theia.svrにアクセスします。DNSサーバの設定通りに名前解決できていることが確認できました。

![theia.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/4b3d260a-2886-0baa-a16c-7078d10c8d5b.png)

---

#### Gitea
gitea.svrにアクセスします。

![gitea-top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/f9aa6adb-b5e3-b80f-d9b2-bb45c6345440.png)

---

#### Vue CLI
vuecli.svrにアクセスします。

![vuecli.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164833/2c1af8d4-626f-6ceb-cd1d-706e467562f6.png)

---

## 以上です
最後まで読んでくださりありがとうございました！

---

## リンク
- [draw.io](https://app.diagrams.net/)：図を描くのに使いました。