Kubernetes入門としてのRancher Server ～ステップバイステップでリバースプロキシとVPNを立ててみる～

# はじめに

Kubernetes、流行っていますね。
仕事上関わらない人も、そろそろ一般知識として知っておいた方が良いと焦っている方も
多いのではないでしょうか。
ただ、いざ勉強を始めてみると、yamlとCUIベースなのでいまいち敷居が高い。
せめて入門の間だけでもGUIベースで使えたらと思いませんか？
その用途としてRancher Server 2.xが良さそうだったので紹介します。

(追記)
知り合いに教えてもらいましたがGKE(Google Kubernetes Engine)もWeb画面があり、かなり良さそうでした。
GKEと比較するとRancher Serverのメリットはオンプレミスであること、でしょうか。

# 想定読者

* Kubernetesの概念や用語を理解している人
* kubectlを使って少し練習したが、よくわからなかった人
* LinuxサーバーやDockerを自分で構築できる人

# Rancher Server 2.x の特徴

* Web GUIを使ってKubernetesを操作可能
* オンプレミス
* 日本語化がなかなか良い


# Rancher Server 2.xのセットアップ

環境構築は、ここでは扱いません。ほかのサイトを参考に構築してください。
以下あたりの記事が良さそうでした。
https://qiita.com/o_sol/items/836cddf0e77c835866b9

注意点としては、 Ver.1.xとVer.2.xでDockerイメージが違うので注意してください。

ここでは、Rancher Server、Kubernetesのマスターノード、NFSサーバーの3つが
稼働している想定で説明します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/41a04177-78de-8c31-37b4-f5bfdc12ff2e.png)

IPは、自分の環境に合わせて適時読み替えてください。
また、example.comというドメインが出てきますが、仮のものなので
適切なドメインに読み替えてください。


# ステップバイステップでRancher Serverを使ってみる

ただ、画面を紹介するだけだと面白くないので、
Nginxでのリバースプロキシ構築、PritunlでのVPNサーバー構築、を想定して実際に操作しながら
操作方法を紹介します。

## Nginxによるリバースプロキシ

### Nginxを立てる

とりあえず、必要最低の設定でNginxを立ててみます。

**1. ワークロード画面から、「デプロイ」をクリックして、以下を設定します**

* 名前: `mynginx`
* ワークロードタイプ: `スケーラブルデプロイメント 1ポッド`
* Docker イメージ: `nginx`

|![Nginx新規ワークロードの画面.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/962e006e-03d9-3545-0be5-2d8edd3e5012.jpeg)|
|:-:|

**2. 「起動」をクリックします。**

一番最初のデプロイはイメージのPullがあるので少し時間がかかります。
無事Nginxが立ち上がれば、次のようにActiveと表示されます。

|![Nginx新規のワークロード一覧画面.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/a31747f9-efa3-4983-2f37-cb06330dee39.jpeg)|
|:-:|

### Nginxのポートを公開する

このままでは、単にCPUとメモリを消費するだけで何もできません。
差し当ってhttpポートを公開して、アクセスできるようにします。

**1.ワークロードを選択して、「編集」を選択します。**
**2.「ポートを追加」をクリックし、以下を入力します。**

* コンテナポートを公開: `80`
* プロトコル: `TCP`
* As a: `ノードポート(全てのノード上)`
* リッスンポート: `30000`

|![Nginxポート公開のワークロード編集画面.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/196795b2-137a-4cfc-6d7a-55525dfd8de3.jpeg)|
|:-:|


**3. 最後に「アップグレード」をクリックします。**


ワークロード一覧の画面では、一時的にNginxが2つ立ち上がって、少し待つと1つになります。
これはデフォルトの設定が「ローリング: 新しいポッドを起動後、古いポッドを停止」になっているためです。
いわゆる、ブルーグリーンデプロイというやつです。

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/a1782aa7-66e5-b70a-60e6-666993efeee0.png)|
|:-:|


`http://192.168.111.238:30000/` (192.168.111.238はKubernetesのノードのIP)にアクセスすると、
Nginxの初期画面が表示されます。
Nginxはちゃんと稼働しているようです。

|![Nginxポート公開-初期画面.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/49fb2302-0580-3a3f-e18d-67dee1e1c76b.jpeg)|
|:-:|

### Config Mapでボリュームをマウントする

静的なhtmlを置いてそれをNginxで公開してみます。
コンテンツは、外部のボリュームにおいてそれをマウントするのがよいと思いますが、
コンテンツもKubernetesで管理することを想定してConfig Mapを使って、デプロイ時に静的なhtmlファイルを配置します。

**1.「リソース」ー「コンフィグマップ」を選択し、コンフィグマップを開きます**
**2.「コンフィグマップを追加」のページで以下を入力します**

* 名前: `nginx-indexhtml`
* キー: `index.html`
* 値: `<html><body>test</body></html>`

|!["Nginx静的コンテンツ-コンフィグマップ作成.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/253d9c3c-2f07-395c-97cc-93b67b421e29.jpeg)|
|:-:|

**3. 「保存」をクリックして完了します。**


**4. ワークロード一覧から、「mynginx」の編集を選択します**
**5.「ボリュームの追加」‐「Use a config map」を選択し、ボリュームを追加します**
**6. 以下を入力します**

* ボリューム名： `任意`
* デフォルトモード: `755`
* コンフィグマップ名: `nginx-indexhtml`
* items: `全てのキー`
* マウントポイント: `/usr/share/nginx/html/`
* 読み取り専用: `チェック`

|![Nginx静的コンテンツ-Nginxにボリューム追加](https://qiita-image-store.s3.amazonaws.com/0/217768/9bfa6fa5-9c20-2fae-fe42-6a606af50377.jpeg)|
|:-:|


**7.「アップグレード」をクリックし、反映されるまで少し待ちます**


もう一度、`http://192.168.111.238:30000/` にアクセスしてみます。
コンフィグマップで作成したindex.htmlが`/usr/share/nginx/html/`に配置され、表示されるはずです。

|![Nginx静的コンテンツ-testだけのWEBページ.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/c7b99eee-1725-fc0a-e36f-57ec582ca394.jpeg)|
|:-:|


### ロードバランサーを使ってみる

上の手順では、ノードポートで30000/tcpでNignxを立てましたが、
Kubernetesを使う場合は通常ロードバランサーを使って、
要求を適切なPodに振り分けます。
Rancher Serverにはデフォルトでロードバランサーが付いていますのでそれを使って、
ドメイン名を基に振り分けます。
なお、付属のロードバランサーの中身はIngress Nginx Controllerのようです。


**1.「ワークロード」―「ワークロード」を開きます**
**2.「mynginx」を選択して、「編集」を選択します**
**3. ポートマッピングを以下のように変更します**

* コンテナポートを公開: `80`
* プロトコル: `TCP`
* As a: `クラスターIP(内部のみ)`
* リッスンポート: `80`

|![NginxロードバランサーーNginxポート80に変更.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/796aca2a-2bc7-5b28-928e-b8c299885464.jpeg)|
|:-:|


**4. アップグレードをクリックします**

これで外部公開の30000ポートは閉じられ、内部向けの80ポートが公開されている状態になります。

**5.「ワークロード」―「ロードバランサー」を開きます**
**6.「イングレスを追加」をクリックします**
**7. 以下を入力します**

* 名前: `myingress`
* Specify a hostname to use: `www.example.com`
* パス: `/`
* ターゲット: `mynginx`
* ポート: `80`

|![NginxロードバランサーーIngress画面.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/84d2a264-a619-5edf-72b0-1504fc94f729.jpeg)|
|:-:|

**8.「保存」をクリックします**

これで、 `www.example.com/` に来た要求は`mynginx`の80/tcpに転送されます。

**9. 手元のPCのHostsを編集して「www.example.com」で「192.168.111.238(Kubernetes node ip)」に
アクセスするように設定します。DNSがあるならそちらに設定してもよいです。**

`http://www.example.com/` にアクセスします。

|![NginxロードバランサーーtestだけのWEBページ.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/ef95b678-c5e2-5a53-3adc-d2604bb07cf3.jpeg)|
|:-:|

`www.example.com`へのアクセスで正しくNignxに転送されました。


### ロードバランサーをhttpsに対応する

最近は、各種ブラウザのセキュリティが厳しくなり、httpsでないと警告が出るようになりました。
幸い、Let's Encryptといった無料のSSL証明書が使えますので、無料でhttps化が可能です。
事前に証明書が用意してある前提で、ロードバランサーに証明書を設定すればhttpsでアクセス可能になります。
なお、ホストの部分にはワイルドカードの指定(例:*.example.com)が可能なので、ワイルドカード証明書を作っておけばホスト毎の設定は不要で、便利です。

**1.「リソース」-「証明書」を開きます**
**2.「証明書を追加」をクリックします**
**3. 以下を入力します**

* 名前: `mycertificate`
* プライベートキー: `SSL証明書のプライベートキー`
* 証明書: `SSL証明書のCerファイル`

|![https化ー証明書画面.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/5e1379d1-8512-08b0-7c03-3ec9bd1a238c.jpeg)|
|:-:|


**4.「保存」をクリックします**

これで `mycertificate` の名前で証明書が登録されました。これをロードバランサーに設定します。

**5.「ワークロード」―「ロードバランサー」を開きます**
**6. Ingressを選択し、編集を開きます**
**7.「SSL/TLS証明書」を展開し、「証明書を追加」をクリックします**
**8. 以下を設定します**

* Choose a certificate: `選択`
* 証明書: `mycertificateを選択`
* ホスト: `*.example.com`

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/3c16fcb5-7828-8737-e17e-965d1c22b7fa.png)|
|:-:|



**9.「保存」をクリックします**

ワイルドカードで指定したので、 `www.example.com` を含めて、末尾が`.example.com`の場合に
今回登録した証明書が使われます。

`https://www.example.com/` にブラウザでアクセスすると、httpsでtestのページが表示されることがわかります。

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/4e8a350f-3a1f-9869-ca99-6964f67f6c57.png)|
|:-:|


### Nginxにリバースプロキシを設定する

ホスティングしたいWebサーバーが全てKubernetesクラスター内にあるならよいのですが、
特定のホスト名の場合は外部のWebサーバーを公開したい場合があります。
Kubernetesクラスターの前にリバースプロキシを置けばよいのですが、外に設定を持つと
管理が面倒なので、Kubernetesでリバースプロキシを作ります。
今回は、`https://192.168.0.1`のルーターのWeb画面のリバースプロキシを作ります。

**1.「リソース」－「コンフィグマップ」を開き、コンフィグマップを開きます**
**2. 「コンフィグマップを追加」をクリックし、以下を入力します**

* 名前: `nginx-reverseproxy-conf`
* キー(1つ目): `default.conf`
* 値(1つ目): 下記参照
* キー(2つ目): `reverseproxy.conf`
* 値(2つ目): 下記参照

default.conf

```
server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
```

reverseproxy.conf

```
server {
listen     80;
server_name  router.example.com;
location / {
    proxy_pass https://192.168.0.1/;
}

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}
```


|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/9fc44e12-25d4-21a1-b68e-62c87720e05b.png)|
|:-:|

**3.「保存」をクリックして完了します**


**4.「ワークロード」－「ワークロード」を開きます**
**5. 「mynginx」を選択して、「編集」を開きます**
**6.「ボリュームの追加」－「Use a config map」をクリックし、ボリュームを追加します**
**7.以下を入力します**

* ボリューム名： `任意`
* デフォルトモード: `755`
* コンフィグマップ名: `nginx-reverseproxy-conf`
* items: `全てのキー`
* マウントポイント: `/etc/nginx/conf.d/`
* 読み取り専用: `チェック`



|![リバースプロキシーNginx編集.jpg](https://qiita-image-store.s3.amazonaws.com/0/217768/30d6fb95-4920-4d37-f036-1476d564e344.jpeg)|
|:-:|

**8.「アップグレード」をクリックします**

**9. 「ワークロード」－「ロードバランサー」を開きます**
**10. Ingressを選択し、編集を開きます**
**11. 「ルールを追加」をクリックし、以下を設定します**

* Specify a hostname to use: `router.example.com`
* パス: `/`
* ターゲット: `mynginx`
* ポート: `80`


|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/907cdcfd-b511-42a4-56e2-acff3206fc2a.png)|
|:-:|


**14. 「保存」をクリックします**

**15. 手元のPCのHostsを編集して、「router.example.com」で「192.168.111.238(Kubernetes node ip)」にアクセスするように設定します。DNSがあるならそちらに設定してもよいです。**


`https://router.example.com/` にアクセスすると、Kubernetes外部のWebページが表示され、
リバースプロキシとして動作していることがわかります。
今回はルーターのWebページが表示されるはずです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/52dd4781-58cb-5193-7923-8db6a8c2f9a9.png)


このように、コンフィグマップにNginxの設定を持てば、Kubernetesだけでリバースプロキシが作れます。


### yamlを参照する

GUIだけでリバースプロキシの構築までできましたが、脱初心者に向けてyamlの勉強もしたいところです。
また、GUIだけでは設定のバックアップをどうするか、というところも気になります。
Rancher ServerではGUIで行った設定をyamlとして出力することができます。

**1.「ワークロード」－「ワークロード」を開く**
**2. 「mynginx」を選択し、「YAMLの参照/編集」を開きます**

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/fd0518dd-a1d7-9543-225c-03e00dfeba9c.png)|
|:-:|

GUIで設定したyamlを確認することができます。
また、yamlを基にサーバーに設定するには「YAMLをインポート」から行えます。


## Pritnulを使ってVPNサーバーを立てる

[Pritnul](https://pritunl.com/) というOpenVPNを使ったVPNサーバーがあります。
PritnulはDocker対応しているので、Kubernetesでホスティングしてみます。

この記事に docker-compose.yml がありますので、これを参考にさせてもらいます。
https://qiita.com/cha2maru/items/e6efb976cc1cb6eb7f7a

### NFSボリュームを用意する

PritunlはバックエンドにMongoDBを使っています。
DBのデータは永続化しておかないと、コンテナの再起動時に初期化されてしまいますので、
通常コンテナ外にデータを置きます。
ノードボリュームでもよいのですが、ノードが増えたときにも対応できるように外部のネットワークボリュームを用意します。

今回は気軽に使えるNFSボリュームを使用します。
事前にNFSサーバーで、NFSを公開しておきます。
今回は、「/kube-volume」 として公開しました。

**1. クラスターを選択し、「ストレージ」―「永続ボリューム」を選択します。**
**2. 「永続ボリュームの追加」をクリックし、次を入力します。**

* 名前: `myvolume`
* ボリュームプラグイン: `NFS共有`
* 容量: `10`
* プラグイン設定
    * パス: `/kube-volume`
    * サーバー: `192.168.111.239 (NFSサーバー)`
* カスタマイズ
    * アクセスモード: `単一ノード読み取り/書き込み、複数ノード読み取り専用、複数ノード読み取り/書き込み のすべてにチェック`

|![NFS-永続ボリュームの追加](https://qiita-image-store.s3.amazonaws.com/0/217768/43747917-8a07-8df4-77a7-cc8c723d82b2.png)|
|:-:|


**3. 「保存」をクリックします。**


**4. 「ワークロード」―「ボリューム」を開きます**
**5. 「ボリュームを追加」をクリックし、次を入力します**

* 名前: `myvolume`
* 永続ボリューム: `myvolume`
* カスタマイズ
    * アクセスモード: `単一ノード読み取り/書き込み、複数ノード読み取り専用、複数ノード読み取り/書き込み のすべてにチェック`

|![NFS-ボリュームの追加](https://qiita-image-store.s3.amazonaws.com/0/217768/b4886261-08b5-93fe-e4a3-d4928c6e144c.png)|
|:-:|


**6. 作成をクリックします**

これで外部のネットワークボリュームを使用する準備ができました。

### MongoDBを立てる

先ほど作った外部ネットワークボリュームにDBのデータを永続化するようにして、MongoDBを立てます。
後でPritunlから27017/tcpにアクセスされるため、ポートも公開しておきます。
この時のポート公開はKubernetesクラスター外には出ないので「クラスターIP(内部のみ)」です。

**1. 「ワークロード」―「ワークロード」を開きます**
**2. 「デプロイ」をクリックし、次の入力します**

* 名前: `vpn-mongo`
* ワークロードタイプ: `スケーラブルデプロイメント: 1ポッド`
* Docker イメージ: `mongo`
* ポートマッピング
    * コンテナポートを公開: `27017`
    * プロトコル: `TCP`
    * As a: `クラスターIP(内部のみ)`
    * リッスンポート: `コンテナポートと同様`

**3. 「ボリュームの追加」‐「既存の永続ボリューム(要求)を作成」を選択し、ボリュームを追加します**
**4. 以下を入力します**

* ボリューム名: `(任意)`
* 永続ボリューム要求: `myvolume`
* マウントポイント: `/data/db`
* Sub Path in Volume: `vpn-mongo/data/db`
* 読み取り専用: `OFF`

|![Mongo-デプロイ](https://qiita-image-store.s3.amazonaws.com/0/217768/c0bdcf69-67c9-5d9d-b322-8df8ce633a9e.png)|
|:-:|

**5. 「起動」をクリックします**

これでMongoDBを使う準備ができました。



### Pritunlを立てる

DBの用意ができましたので、Pritnulを立ち上げます。
Pritnulは管理ページとしてhttpsを使いますので443ポートを公開します。

ただし、Rancher ServerのIngressはhttpしか転送しないので、
httpsはロードバランサー経由ではアクセスできません。
また、443ポートはIngressが使っているため「ノードポート(全てのノード上)」も使えません。
(ポートNoを変えればOKですが)

先に作ったNginxをリバースプロキシとして、Pritnulのhttpsをhttpとして公開し、
Ingressはそこにアクセスを転送するようにします。


また、VPNの通信用ポートとして、30001/udpを使用します。
これは、後からPritunlの管理ページで設定します。
当然、IngressはUDPも転送できませんので、「ノードポート(全てのノード上)」として
30001/udpを公開します。


**1. 「ワークロード」―「ワークロード」を開きます**
**2. 「デプロイ」をクリックし、次を入力します**

* 名前: `vpn-pritnul`
* ワークロードタイプ:  `スケーラブルデプロイメント: 1ポッド`
* Docker イメージ: `jippi/pritunl`
* ポートマッピング
    * コンテナポートを公開: `443`
    * プロトコル: `TCP`
    * As a: `クラスターIP(内部のみ)`
    * リッスンポート: `443`
* ポートマッピング(2個目)
    * コンテナポートを公開: `30001`
    * プロトコル: `UDP`
    * As a: `ノードポート(全てのノード上)`
    * リッスンポート: `30001`



|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/b263db6d-71f9-4336-2797-98e605dd1b44.png)|
|:-:|


**3. 「環境変数」を展開してから、「環境変数を追加」をクリックし、次を入力します。**

* 変数:`PRITUNL_MONGODB_URI`
* 値: `mongodb://vpn-mongo:27017/pritunl`

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/a2b1fd38-6b9d-306a-3240-3bb510a52bf7.png)|
|:-:|


VPNサーバーは新しいネットワークを作るため、一般ユーザーの権限では動作しません。
そのため、コンテナに特権を与えます。
当然ですが、コンテナに特権を与えるのはセキュリティ上のリスクがありますので、
リスクを検討したうえで設定してください。

**4. 「詳細オプションを表示」をクリックし、「セキュリティ & ホスト設定」を展開して、以下を入力します**

* 特権モード: `はい`

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/bb6301b1-077a-41d8-46bc-9b999c0acbf0.png)|
|:-:|

**5.「デプロイ」をクリックして完了します**


リバースプロキシとIngressの設定を行います。
基本的に上と同じです。

**6. リソース‐コンフィグマップを開きます**
**7.「nginx-reverseproxy-conf」の編集を開き、「コンフィグマップ値の追加」をクリックし、以下を入力します**

* キー: `vpn-proxy.conf`
* 値: 下記参照

```
server {
listen     80;
server_name  vpn.example.com;
location / {
    proxy_pass https://vpn-pritnul/;
}

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}
```


|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/1772e15d-1a6f-700c-8a82-54cc2ef651d3.png)|
|:-:|

**8.「保存」をクリックし、完了します**

**9.「ワークロード」－「ロードバランサー」を開き、「myingress」の編集を開きます**
**10.「ルールを追加」をクリックし、次を入力します**

* Specify a hostname to use: `vpn.example.com`
* パス: `/`
* ターゲット: `mynginx`
* ポート: `80`

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/4738018f-66e8-fbb4-889c-fd8bb2d4b30f.png)|
|:-:|

**11.「保存」をクリックします**



**12. 手元のPCのHostsを編集して「vpn.example.com」で
　「192.168.111.238(Kubernetes node ip)」にアクセスするように設定します。
　DNSがあるならそちらに設定してもよいです**


`https://vpn.example.com/` にアクセスすると、次のようにPritunlの管理画面が表示されます。

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/2bb93844-b84a-7274-9f08-49f6c65293c7.png)|
|:-:|

Pritnulの設定や使い方は、他のサイトを参考にしてほしいですが、
ポイントとしては、上で設定したように通信用のポートを30001/udpにしてください。
Pritnulの設定例を軽く載せておきます。

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/4fab9507-7b8c-c93c-8046-6b16b76767c6.png)|
|:-:|

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/217768/acb5c315-d105-21f7-60d4-ff22058a9209.png)|
|:-:|

# まとめ

Ranchser ServerのGUIを使って、yamlやKubectlを使わずに
Nginxによるリバースプロキシ、PritnulによるVPNサーバーの構築を行いました。
深いところに手を出さない限りはGUIだけで完結できそうです。

無料でここまでのことができるRancher Serverに感謝したいです。