VPC Gen2対応のIKSでPrivateなクラスターを動かす Part.2

Part.1からの続きです。
[VPC Gen2対応のIKSでPrivateなクラスターを動かす Part.1](https://qiita.com/Ra1nmaker/items/fc5b0a12938949b562cd)

# 試してみたこと（サマリー）
Part.1の続きで、以下の項目に関して試してみました。
操作はPart.1の時点で用意していた、Bastion(踏み台)サーバー上で実施しました。

3. Private Endpoint Onlyな状態でアプリを公開する（Public/Private両方）


## 注意1: Privateに閉じたネットワークでのイメージの準備
今回はPrivate Endpoint Onlyな構成をとっており、IKSのWorker Nodeが所属するネットワークはインターネット接続はできません。(インターネット接続するためには、Public Gatewayを用意する必要があります。)

そのためアプリの公開に関して、DockerHubからコンテナ・イメージを持ってくる処理は今回行えません。

今回の構成のようにPrivate Networkに閉じた環境の場合、事前にICR(IBM Cloud Container Registry)に事前にイメージを保管しておき、そのイメージを使う方法が考えられます。

本記事では、イメージ「us.icr.io/\<NAMESAPCE名\>/nginx:alpine」を事前にICRに登録してあるものとして以下手順をまとめています。

## 注意2: 利用するドメインに関して
今回はIBM提供のドメインを使用します。「company.com」のようなカスタム・ドメインを利用したい場合、例えばIBM Cloud DNSサービスで、使用したいドメインをIBM提供のドメインに対しCNAMEで紐づける設定を行えば良い認識です。またそのうち試したいかなと。

# Step 4. アプリの公開（Public編）
IKS上にアプリをデプロイし、まずはインターネットにアプリを公開します。

デフォルトで、IKSに対しPublic側にVPC Load Balancerが構成されており、与えられたIngress Subdomainを利用する場合はすぐに利用することが可能です。

## Deployment, Serviceの作成
以下のDeployment作成用のリソース・ファイルを用意します。

<details><summary>deployment.yaml</summary><div>

```
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: my-nginx
  name: my-nginx
spec:
  replicas: 10
  selector:
    matchLabels:
      run: my-nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: my-nginx
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: "kubernetes.io/zone"
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            run: my-nginx
      - maxSkew: 1
        topologyKey: "kubernetes.io/hostname"
        whenUnsatisfiable: ScheduleAnyway
#        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            run: my-nginx
      containers:
      - image: us.icr.io/ra1nmaker/nginx:alpine
        name: my-nginx
        resources: {}
status: {}
```
</div></details>

このファイルを用いてDeploymentを作成し、サービスを公開します。

```
# Deploymentの作成
[root@ra1n-bastion1 ~]# kubectl apply -f deployment.yaml
deployment.apps/my-nginx created

# Podの状態確認
[root@ra1n-bastion1 ~]# kubectl get po -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP               NODE            NOMINATED NODE   READINESS GATES
my-nginx-5f96bcb545-2w4xs   1/1     Running   0          66s   172.31.253.195   192.168.130.5   <none>           <none>
my-nginx-5f96bcb545-5cp54   1/1     Running   0          66s   172.31.243.131   192.168.110.6   <none>           <none>
my-nginx-5f96bcb545-7xp5c   1/1     Running   0          66s   172.31.217.3     192.168.120.4   <none>           <none>
my-nginx-5f96bcb545-g9k5q   1/1     Running   0          66s   172.31.65.70     192.168.110.4   <none>           <none>
my-nginx-5f96bcb545-k99lj   1/1     Running   0          66s   172.31.148.205   192.168.110.5   <none>           <none>
my-nginx-5f96bcb545-qqjm5   1/1     Running   0          66s   172.31.154.131   192.168.130.4   <none>           <none>
my-nginx-5f96bcb545-t7zkr   1/1     Running   0          66s   172.31.123.131   192.168.120.6   <none>           <none>
my-nginx-5f96bcb545-ttssx   1/1     Running   0          66s   172.31.10.194    192.168.120.5   <none>           <none>
my-nginx-5f96bcb545-tzt9g   1/1     Running   0          66s   172.31.154.130   192.168.130.4   <none>           <none>
my-nginx-5f96bcb545-xwcf4   1/1     Running   0          66s   172.31.191.131   192.168.130.6   <none>           <none>

# サービスを公開
[root@ra1n-bastion1 ~]# kubectl expose deploy/my-nginx --port=8080 --target-port=80 --name my-svc
service/my-svc exposed
```

## アプリケーションの公開（Public）
Ingressを利用してPublic(インターネット)側にアプリケーションの公開を行います。本記事ではデフォルトで提供されるIngress Subdomainを利用したアプリケーションの公開を行います。

### 1. Ingress Subdomainの確認

以下のようにコマンドラインで確認するのが楽だと思います。
Ingress Subdomainや付属するSSL証明書がどのNamespace/Secret名で登録されているか確認できます。

```
[root@ra1n-bastion1 ~]# ibmcloud ks nlb-dns ls --cluster ra1n-cluster-1
OK
サブドメイン                                                                               ロード・バランサーのホスト名           SSL 証明書の状況   SSL 証明書の秘密名                                     秘密の名前空間
ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.us-south.containers.appdomain.cloud       76790e10-us-south.lb.appdomain.cloud   created     ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000   default
```

### 2. Ingressリソースの作成
以下のようにIngressのリソース・ファイルを作成します。

<details><summary>ing-pub.yaml</summary><div>

```
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
 name: demo-ingress
spec:
 tls:
 - hosts:
   - nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000.us-south.containers.appdomain.cloud
   secretName: ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000
 rules:
 - host: nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000.us-south.containers.appdomain.cloud
   http:
     paths:
     - path: /
       backend:
         serviceName: my-svc
         servicePort: 8080
```
</div></details>

ファイルの準備が完了したら、Ingressリソースを作成します

```
[root@ra1n-bastion1 ~]# kubectl apply -f ing-pub.yaml
ingress.networking.k8s.io/demo-ingress created

[root@ra1n-bastion1 ~]# kubectl get ing
NAME           HOSTS                                                                                      ADDRESS                                PORTS     AGE
demo-ingress   nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000.us-south.containers.appdomain.cloud   76790e10-us-south.lb.appdomain.cloud   80, 443   8s
```

### 3. アプリへのアクセス
完了したらcurlコマンドなどでアクセスします。ここではアプリケーションをPublicに公開しているので、インターネット経由でアクセスができます。

```
$ curl https://nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000.us-south.containers.appdomain.cloud
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

以上でPublic側にアプリケーションを公開することができました。

### 補足. VPC Gen2のIKSのアプリ公開の実装を調べてみる
VPC Gen2対応のIKSの場合、以下のようにL4のVPC Load BalancerがPublic側有効で作成されています。
Ingress SubdomainはLoad Banalcerに登録されているPublic IPで名前解決されるので、Public側からのアクセスの場合はこのLoad Balancerをまず経由します。

```
[root@ra1n-bastion1 ~]# ibmcloud is load-balancers
ユーザー XXXX@gmail.com としてアカウント XXXX の下でリソース・グループ prod と地域 us-south 内の世代 2 コンピュートの ロード・バランサー をリストしています...
ID                                          名前                                                         ホスト名                               パブリックです   パブリック IP                    プライベート IP               サブネット                               プロビジョン状況   作動状況   リソース・グループ
r006-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX4d22   kube-brs18a4d04f1bjdkdm1g-b16c81b658744ca7983d05f508c7a901  7679aaaa-us-south.lb.appdomain.cloud  yes           52.XXX.XXX.99,169.XXX.XXX.85      192.168.130.7,192.168.120.7   iks-subnet-3,iks-subnet-2,iks-subnet-1                            active             online     prod
```

IngressはL7で処理できますが、上記だとL4です。L7のALB(Application Load Balancer)機能は
IKSのPodとしてWorker Node上で稼働しているALBと組み合わせることで実現しています。

ALBとVPC Load Balancerとの紐付けは「ibmcloud ks albs」コマンドで確認できます。
(ロード・バランサーのホスト名で紐付けが確認できます。)

```
[root@ra1n-bastion1 ~]# ibmcloud ks albs --cluster ra1n-cluster-1
OK
ALB ID                                有効化   状況      タイプ    ロード・バランサーのホスト名           ゾーン       ビルド
public-crbrs18a4d04f1bjdkdm1g-alb1    true     enabled   public    7679aaaa-us-south.lb.appdomain.cloud   us-south-1   ingress:642/ingress-auth:413
public-crbrs18a4d04f1bjdkdm1g-alb2    true     enabled   public    7679aaaa-us-south.lb.appdomain.cloud   us-south-2   ingress:642/ingress-auth:413
public-crbrs18a4d04f1bjdkdm1g-alb3    true     enabled   public    7679aaaa-us-south.lb.appdomain.cloud   us-south-3   ingress:642/ingress-auth:413
```

## アプリケーションの公開（Private）
続いて、Privateに閉じたアプリケーションの公開を行います。
デフォルトでは、Private用のALBやIngress Subdomainが提供されていないので、作成します。

### 1. private ALBの有効化
以下のように、デフォルトでは「private-」のプリフィックスのALBは無効(disabled)です。

```
[root@ra1n-bastion1 ~]# ibmcloud ks albs --cluster ra1n-cluster-1
OK
ALB ID                                有効化   状況       タイプ    ロード・バランサーのホスト名           ゾーン       ビルド
private-crbrs18a4d04f1bjdkdm1g-alb1   false    disabled   private   -                                      us-south-1   ingress:/ingress-auth:
private-crbrs18a4d04f1bjdkdm1g-alb2   false    disabled   private   -                                      us-south-2   ingress:/ingress-auth:
private-crbrs18a4d04f1bjdkdm1g-alb3   false    disabled   private   -                                      us-south-3   ingress:/ingress-auth:
public-crbrs18a4d04f1bjdkdm1g-alb1    true     enabled    public    7679aaaa-us-south.lb.appdomain.cloud   us-south-1   ingress:642/ingress-auth:413
public-crbrs18a4d04f1bjdkdm1g-alb2    true     enabled    public    7679aaaa-us-south.lb.appdomain.cloud   us-south-2   ingress:642/ingress-auth:413
public-crbrs18a4d04f1bjdkdm1g-alb3    true     enabled    public    7679aaaa-us-south.lb.appdomain.cloud   us-south-3   ingress:642/ingress-auth:413
```

private側のALBを有効(enabled)にします。

```
[root@ra1n-bastion1 ~]# ibmcloud ks alb configure vpc-gen2 --alb-id private-crbrs18a4d04f1bjdkdm1g-alb1 --enable
ALB を構成中...
OK
[root@ra1n-bastion1 ~]# ibmcloud ks alb configure vpc-gen2 --alb-id private-crbrs18a4d04f1bjdkdm1g-alb2 --enable
ALB を構成中...
OK
[root@ra1n-bastion1 ~]# ibmcloud ks alb configure vpc-gen2 --alb-id private-crbrs18a4d04f1bjdkdm1g-alb3 --enable
ALB を構成中...
OK
```

しばらく待ってからALBの状態を確認します。

```
[root@ra1n-bastion1 ~]# ibmcloud ks albs --cluster ra1n-cluster-1
OK
ALB ID                                有効化   状況      タイプ    ロード・バランサーのホスト名           ゾーン       ビルド
private-crbrs18a4d04f1bjdkdm1g-alb1   true     enabled   private   deee1111-us-south.lb.appdomain.cloud   us-south-1   ingress:642/ingress-auth:413
private-crbrs18a4d04f1bjdkdm1g-alb2   true     enabled   private   deee1111-us-south.lb.appdomain.cloud   us-south-2   ingress:642/ingress-auth:413
private-crbrs18a4d04f1bjdkdm1g-alb3   true     enabled   private   deee1111-us-south.lb.appdomain.cloud   us-south-3   ingress:642/ingress-auth:413
public-crbrs18a4d04f1bjdkdm1g-alb1    true     enabled   public    7679aaaa-us-south.lb.appdomain.cloud   us-south-1   ingress:642/ingress-auth:413
public-crbrs18a4d04f1bjdkdm1g-alb2    true     enabled   public    7679aaaa-us-south.lb.appdomain.cloud   us-south-2   ingress:642/ingress-auth:413
public-crbrs18a4d04f1bjdkdm1g-alb3    true     enabled   public    7679aaaa-us-south.lb.appdomain.cloud   us-south-3   ingress:642/ingress-auth:413
```

この時点で、Private OnlyなVPC Load Balancerも作成されます。

```
[root@ra1n-bastion1 ~]# ibmcloud is load-balancers
ユーザー XXXX@gmail.com としてアカウント XXXX の下でリソース・グループ prod と地域 us-south 内の世代 2 コンピュートの ロード・バランサー をリストしています...
ID                                          名前                                                         ホスト名                               パブリックです   パブリック IP                 プライベート IP               サブネット                               プロビジョン状況   作動状況   リソース・グループ
r006-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX4d22   kube-brs18a4d04f1bjdkdm1g-b16c81b658744ca7983d05f508c7a901  7679aaaa-us-south.lb.appdomain.cloud  yes           52.XXX.XXX.99,169.XXX.XXX.85      192.168.130.7,192.168.120.7   iks-subnet-3,iks-subnet-2,iks-subnet-1  active             online     prod
r006-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX198e   kube-brs18a4d04f1bjdkdm1g-80a7c874535d42c49f017edbc8f45411   deee1111-us-south.lb.appdomain.cloud   no                                            192.168.130.8,192.168.120.8   iks-subnet-3,iks-subnet-2,iks-subnet-1  active             online     prod
```

> Hint & Tips
Public ALBは不要であれば同様の手順でdisabledにすれば、IngressでのPublic側からのアプリケーションの公開をさせないように設定できます


### 2. private側Ingress Subdomainの登録
次に、作成されたVPC Load Balancerに対し、使用するIngress Subdomainを作成します。
「--lb-host」は上記で確認したVPC Load Balancerのホスト名を指定します。

```
[root@ra1n-bastion1 ~]# ibmcloud ks nlb-dns create vpc-gen2 --cluster ra1n-cluster-1 --lb-host deee1111-us-south.lb.appdomain.cloud --type private
NLB DNS を作成中...
OK
```

こちらも実行してからしばらく時間がかかりますが、以下のコマンドで登録が完了したことが確認できます。
サブドメインのホスト部の末尾の４桁が「i」から始まるものがprivate, そうでないものはpublicのドメインを表しています。

```
[root@ra1n-bastion1 ~]# ibmcloud ks nlb-dns ls --cluster ra1n-cluster-1
OK
サブドメイン                                                                               ロード・バランサーのホスト名           SSL 証明書の状況   SSL 証明書の秘密名                                     秘密の名前空間
ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000.us-south.containers.appdomain.cloud   7679aaaa-us-south.lb.appdomain.cloud   created            ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-0000   default
ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud   deee1111-us-south.lb.appdomain.cloud   created            ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001   default
```

### 3. Ingressでの公開
Publicの場合と同様に、Ingressのリソース・ファイルを作成します。
annotationとして「ingress.bluemix.net/ALB-ID」を指定するのがポイントで、「;」区切りでprivate ALBのIDを指定するのがポイントです。

<details><summary>ing-pri.yaml</summary><div>

```
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
 name: demo-ingress-pri
 annotations:
  ingress.bluemix.net/ALB-ID: "private-crbrs18a4d04f1bjdkdm1g-alb1;private-crbrs18a4d04f1bjdkdm1g-alb2;private-crbrs18a4d04f1bjdkdm1g-alb3"
spec:
 tls:
 - hosts:
   - nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud
   secretName: ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001
 rules:
 - host: nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud
   http:
     paths:
     - path: /
       backend:
         serviceName: my-svc
         servicePort: 8080
```
</div></details>

ファイルを作成したら、Ingressリソースを作成します。

```
[root@ra1n-bastion1 ~]# kubectl apply -f ingress-pri.yaml
ingress.networking.k8s.io/demo-ingress-private created
```

### 4. アプリへのアクセス
では、実際にアクセスしてみましょう。
まずは、インターネット越しにアクセスできるかですが、今回はPrivateにのみ公開しているため、Public側からはアクセスできません。

```
$curl https://nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud/
curl: (7) Failed to connect to nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud port 443: Operation timed out
```

Private Addressに名前解決されているので、当然といえば当然ですね。

```
$nslookup nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud
Server:		8.8.8.8
Address:	8.8.8.8#53

Non-authoritative answer:
nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud	canonical name = deee1111-us-south.lb.appdomain.cloud.
Name:	deee1111-us-south.lb.appdomain.cloud
Address: 192.168.130.8
Name:	deee1111-us-south.lb.appdomain.cloud
Address: 192.168.120.8
```

一方で、Transit Gateway経由でIKSのVPCにアクセスが可能なBastion(踏み台)からはアクセスできます。

```
$curl https://nginx.ra1n-cluster-1-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-i001.us-south.containers.appdomain.cloud/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

以上で、Private側のみアプリケーションを公開することもできました。

# Part.2のまとめ
以上で、Private Endpoint OnlyなIKSクラスターでアプリケーションの公開までを実施することができました。
カスタム・ドメインでの公開はもう少しステップが必要ですが、そのうち補記したいと思います。