GKEで出来る限り安くアプリを外部公開する

# はじめに

結論としては Service を `type:LoadBalancer` にしたり、`ingress` を利用するとロードバランサーが作成されて課金が発生するので `NodePort` を使うというだけです
ただし、service の type 指定によって GCP のどんなリソースが作られるのか、またその料金体系がどうなっているか調査した時の内容を残しておきます
またこれはあくまで記事作成時点の料金体系の話ということに注意してください

## NodePort による外部公開の仕方

### 1. Service の type を NodePort にして作成する

   ```yaml
   apiVersion: v1
   kind: Service
   metadata:
     name: sample
   spec:
     ports:
       - name: http
         port: 80
         targetPort: 5000
         nodePort: 30000
     selector:
       app: sample
     type: NodePort
   ```

   この時に、`spec.ports.nodePort`は 30000-32767 の範囲で指定します。
   指定しない場合はこの範囲で勝手に割り振られます。

### 2. クラスタの Node に関して 30000-32767 のポートへのアクセスを許可する  
   デフォルトでは Node への 30000-32767 へのアクセスは許可されていないので、その通信を許可するファイアウォールルールを以下のコマンドで作成する必要がある

   ```sh
   gcloud compute firewall-rules create $RULENAME --allow tcp:30000-32767 --target-tags=$GKE_NODE_TAG
   ```

   環境変数の部分は各自好きなルール名と実際の GKE の Node に付与されているタグを指定してください  
    自身でタグを設定していない場合は以下の手順でデフォルトで作られているはずのタグを確認できる

   1. GCP メニューから Kubernetes Engine を選択
   2. クラスタを選択
   3. ノードプールから Node を選ぶ
   4. メタデータのネットワークタグに記述されている内容を確認する

### 3. Node の ExternalIP に対して 30000 番ポートでアクセスすることで service を紐付けたアプリにアクセスできる  
   Node に付与されている ExternalIP は以下のコマンドで確認できる

   ```sh
   kubectl describe node |grep ExternalIP
   ```

## Ingress または type:LoadBalancer で作成した場合の課金について

各リソースを作った時に GCP 上で作成されるリソースとその料金体系について確認する

### 1. `ingress` と `type:LoadBalancer` の service を作る
   画像は以下の手順で GKE クラスタ内の service と ingress を確認したもの
　　
   1. GCP メニューから ｢Kubernetes Engine｣ を選択
   2. ｢Services と Ingress｣ を選択
   ![ingress1_loadbalancer2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501970/3f370679-9ec7-3fb5-4a9b-b0064fd654df.png)


   チェックをしている部分で外部公開用のエンドポイントを持っているものが 3 つで、`type:LoadBalancer`のリソースが 2 つで`ingress`が 1 つあることが確認できる

### 2. ロードバランサーが作成されているのか確かめる
   画像は以下の手順でGCPプロジェクト内で作られている LB を確認したもの

   1. GCP メニューから ｢ネットワークサービス｣ を選択
   2. ｢負荷分散｣ を選択
　　![lb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501970/c3d0376d-67d6-7bd7-8c32-e82f8c5772d1.png) 


   `type:LoadBalancer`のリソース 2 つ分の TCP の LB と`ingress`リソース 1 つ分の HTTP の LB が作られていることが確認できる
   挙動としては以下のドキュメントに書かれている通り

   - [Service とは(LoadBalancer タイプの Service)](https://cloud.google.com/kubernetes-engine/docs/concepts/service#services_of_type_loadbalancer)
   - [HTTP(S) 負荷分散用 GKE Ingress](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress)

   よって以下のドキュメントの内容に従って課金が発生することがわかる  
   [ネットワークの料金(負荷分散と転送ルール)](https://cloud.google.com/compute/network-pricing?hl=ja#lb)

### 3. 料金を確かめる

   画像は以下の手順で特定の 1 日の使用日に発生した支払いを確認したもの

   1. GCP メニューから ｢お支払い｣ を選択
   2. ｢レポート｣ を選択
   3. 期間を使用日にして特定の日付を選択
   4. グループ条件を SKU にする
　　![charge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501970/2d06117f-240b-a998-1009-e3f5a9a9e2b3.png)

   以下のロードバランサーの費用が一番高くかかっている
　　* `HTTP Load Balancing: Global Forwarding Rule Minimum Service Charge`
　　* `Network Load Balancing: Forwarding Rule Minimum Service Charge in Americas`
   L7LB と L4LB で作成されている数が違うはずなのに料金が同じな理由は、最初の 5 つの転送ルールまでかかる費用が同じだから

## 補足

Preemptible VM で Node を作っている場合は、ExternalIPが変わることに注意する必要がある
以下のドキュメントで示されている様に静的IPアドレスを予約して固定して使ってもいいが、クラスタを削除する等で予約して使っていないIPがあると課金されてしまう点にも注意が必要
[静的外部 IP アドレスの予約](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address?hl=ja)
[全ての料金(外部 IP アドレス料金)](https://cloud.google.com/compute/all-pricing?hl=ja&_ga=2.81142098.-414697353.1566860495#ipaddress)

## 終わりに

GCP の無料トライアルの期間が終了に近づいてきて、\$300 分の無料クレジットが余っていたため今まで節約していなかった料金について調べて削れるところを削った時の内容です
ただ istio の導入を考えていて `istio-ingressgateway` を NodePort でやりくりするのは難しそうなので、結局外部公開用の LB を作ることになりそう