OKE（Container Engine for Kubernetes）on Virtual Nodeを試してみる

# はじめに
OKE（Container Engine for Kubernetes）のクラスタにサーバーレスのVirtual Nodeがリリースされましたので、試してみます。

https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengworkingwithvirtualnodes.htm#contengspecifyingvirtualnodes

# IAMポリシーの設定
マニュアルの通りにIAMポリシーを設定します。

https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengvirtualnodes-Required_IAM_Policies.htm

特にルートコンパートメントにポリシーを設定しないと、クラスタは作成できますが、Podが起動できない状態になります。

# クラスタの作成
OKEのコンソールからクラスタを作成します。
ノードタイプの項目で「仮想」を選択します。「管理対象」は従来からあるコンピュートインスタンスをWorker Nodeとして使用します。

ノード数は1にしておきます。

![NoName_2023-3-26_13-25-44_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/4cd466ba-3aba-6b13-aab7-96a1de3e1208.png)

# クラスタの確認
プロビジョニングされたクラスタを確認します。

```
$ kubectl get node
NAME         STATUS   ROLES    AGE   VERSION
10.0.10.73   Ready    <none>   43h   v1.25.4-0.2.129-230309195324
```

詳細を確認します。

```
$ kubectl describe nodes 10.0.10.73
Name:               10.0.10.73
Roles:              <none>
Labels:             beta.kubernetes.io/os=linux
                    failure-domain.beta.kubernetes.io/zone=CA-TORONTO-1-AD-1
                    kubernetes.io/os=linux
                    name=cluster1-20230324
                    node.kubernetes.io/exclude-from-external-load-balancers=true
                    oci.oraclecloud.com/fault-domain=FAULT-DOMAIN-3
                    topology.kubernetes.io/zone=CA-TORONTO-1-AD-1
Annotations:        node.alpha.kubernetes.io/ttl: 0
                    oci.oraclecloud.com/virtual-node-pool-id:
                      ocid1.virtualnodepool.oc1.ca-toronto-1.amaaaaaassl65iqab4x345nos56orv4msst6es6i4rp2trg45fdnncymrlqq
                    virtual-kubelet.io/last-applied-node-status:
                      {"capacity":{"cpu":"2k","memory":"8000Gi","pods":"500"},"allocatable":{"cpu":"2k","memory":"8000Gi","pods":"500"},"phase":"Running","condi...
                    virtual-kubelet.io/last-applied-object-meta:
                      {"name":"10.0.10.73","uid":"8bcb349d-e99a-48c6-b55c-a185232d221a","creationTimestamp":null,"labels":{"kubernetes.io/os":"linux","name":"cl...
CreationTimestamp:  Fri, 24 Mar 2023 08:43:16 +0000
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  10.0.10.73
  AcquireTime:     <unset>
  RenewTime:       Sun, 26 Mar 2023 04:27:16 +0000
Conditions:
  Type                 Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----                 ------  -----------------                 ------------------                ------                       -------
  Ready                True    Sun, 26 Mar 2023 04:27:08 +0000   Fri, 24 Mar 2023 08:43:16 +0000   KubeletReady                 Kubelet is ready
  OutOfDisk            False   Sun, 26 Mar 2023 04:27:08 +0000   Fri, 24 Mar 2023 08:43:16 +0000   KubeletHasSufficientDisk     kubelet has sufficient disk space available
  MemoryPressure       False   Sun, 26 Mar 2023 04:27:08 +0000   Fri, 24 Mar 2023 08:43:16 +0000   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure         False   Sun, 26 Mar 2023 04:27:08 +0000   Fri, 24 Mar 2023 08:43:16 +0000   KubeletHasNoDiskPressure     kubelet has no disk pressure
  NetworkUnavailable   False   Sun, 26 Mar 2023 04:27:08 +0000   Fri, 24 Mar 2023 08:43:16 +0000   RouteCreated                 RouteController created a route
Addresses:
  InternalIP:  10.0.10.73
Capacity:
  cpu:     2k
  memory:  8000Gi
  pods:    500
Allocatable:
  cpu:     2k
  memory:  8000Gi
  pods:    500
System Info:
  Machine ID:
  System UUID:
  Boot ID:
  Kernel Version:
  OS Image:
  Operating System:           Linux
  Architecture:               amd64
  Container Runtime Version:
  Kubelet Version:            v1.25.4-0.2.129-230309195324
  Kube-Proxy Version:
ProviderID:                   ocid1.virtualnode.oc1.ca-toronto-1.amaaaaaassl65iqadqmsl7wfv54ghnjzehciceq5lk5gdh3dkafwff54sfwa
Non-terminated Pods:          (5 in total)
  Namespace                   Name                                    CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                    ------------  ----------  ---------------  -------------  ---
  kube-system                 coredns-854ddf66ff-28n2l                100m (0%)     0 (0%)      70Mi (0%)        170Mi (0%)     43h
  kube-system                 csi-oci-node-28w5t                      30m (0%)      500m (0%)   70Mi (0%)        300Mi (0%)     43h
  kube-system                 kube-dns-autoscaler-7c97dc6dc4-wg7vg    20m (0%)      0 (0%)      10Mi (0%)        0 (0%)         43h
  kube-system                 kube-proxy-4tsjj                        0 (0%)        0 (0%)      0 (0%)           0 (0%)         43h
  kube-system                 kube-proxy-dq29j                        0 (0%)        0 (0%)      0 (0%)           0 (0%)         32h
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests    Limits
  --------           --------    ------
  cpu                150m (0%)   500m (0%)
  memory             150Mi (0%)  470Mi (0%)
  ephemeral-storage  0 (0%)      0 (0%)
Events:              <none>
```

細かく見ていくと、リソースの上限は以下のようになっています。kubeletのデフォルトかな？
AWSのFargateと比べると1ノードあたりのCPU/メモリが大きいですね。
PodもFargateは1ノード/1Podですが、Virtual Nodeは1ノード/複数Podのようです。

```
Allocatable:
  cpu:     2k
  memory:  8000Gi
  pods:    500
```

OSはおそらくOracle Linuxだと思いますが、`Linux`となっています。

```
  OS Image:
  Operating System:           Linux
```

Container Runtimeは不明です。

```
  Container Runtime Version:
```

kubelet version

```
  Kubelet Version:            v1.25.4-0.2.129-230309195324
```

## Nodeのスケール
Nodeをスケールさせてみます。
ノードプールのコンソールから`スケール`→`ノード数`3に増やします。

![NoName_2023-3-26_14-1-13_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/22443ea1-4a2b-d3c5-d96e-20dd7d897a38.png)

しばらく待って確認します。

```
$ kubectl get node
NAME          STATUS   ROLES    AGE   VERSION
10.0.10.204   Ready    <none>   72s   v1.25.4-0.2.129-230309195324
10.0.10.231   Ready    <none>   81s   v1.25.4-0.2.129-230309195324
10.0.10.73    Ready    <none>   44h   v1.25.4-0.2.129-230309195324
```

## hostPath
hostPathでコンテナからVirtual Nodeのrootディレクトリをマウントしてみます。

```hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hostpath
spec:
  containers:
  - image: nginx
    name: hostpath
    volumeMounts:
    - mountPath: /test
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      path: /
      type: Directory
```

```
$ kubectl apply -f hostpath.yaml
pod/hostpath created
$ kubectl get pod
NAME       READY   STATUS    RESTARTS   AGE
hostpath   0/1     Waiting   0          28s
```

```
$ kubectl describe pod hostpath
Name:             hostpath
Namespace:        default
・・・
Events:
  Type     Reason                 Age   From                Message
  ----     ------                 ----  ----                -------
  Normal   Scheduled              45s   default-scheduler   Successfully assigned default/hostpath to 10.0.10.73
  Normal   ProviderCreateSuccess  45s   10.0.10.73/kubelet  Create pod in provider successfully
  Warning  Failed                 45s   10.0.10.73/kubelet  Error creating pod: [unsupported Volume: test-volume]
```
hostPathはサポートしてないですね。
サポートしているボリュームは、マニュアルでは以下となっています。

- emptyDir
- ConfigMap
- Secret
- 次のタイプのProjectedVolume
    - ServiceAccount
    - ConfigMap
    - Secret

# Pod
## デフォルトのPod

kube-systemに起動しているPodを確認します。
```
$ kubectl get pod -n kube-system -o wide
NAME                                   READY   STATUS        RESTARTS   AGE     IP            NODE          NOMINATED NODE   READINESS GATES
coredns-854ddf66ff-28n2l               1/1     Running       0          44h     10.0.10.206   10.0.10.73    <none>           <none>
coredns-854ddf66ff-lgqv6               1/1     Running       0          9m23s   10.0.10.51    10.0.10.73    <none>           <none>
coredns-854ddf66ff-wzpg9               1/1     Running       0          9m23s   10.0.10.4     10.0.10.73    <none>           <none>
csi-oci-node-28w5t                     0/1     Pending       0          44h     <none>        10.0.10.73    <none>           <none>
csi-oci-node-hjghm                     0/1     Pending       0          9m24s   <none>        10.0.10.204   <none>           <none>
csi-oci-node-vcx4q                     0/1     Pending       0          9m33s   <none>        10.0.10.231   <none>           <none>
kube-dns-autoscaler-7c97dc6dc4-wg7vg   1/1     Running       0          44h     10.0.10.159   10.0.10.73    <none>           <none>
kube-proxy-dq29j                       0/1     Pending       0          32h     <none>        10.0.10.73    <none>           <none>
kube-proxy-tlj27                       0/1     Pending       0          9m33s   <none>        10.0.10.231   <none>           <none>
kube-proxy-z2h74                       0/1     Pending       0          9m24s   <none>        10.0.10.204   <none>           <none>
```
`csi-oci-node`と`kube-proxy`がPendingになっています。これはVirtual NodeはDaemonsetが未サポートだからのようです。

```
$ kubectl -n kube-system get daemonsets.apps
NAME                       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                                 AGE
csi-oci-node               3         3         0       3            0           <none>                                        44h
kube-proxy                 3         3         0       3            0           beta.kubernetes.io/os=linux                   32h
node-termination-handler   0         0         0       0            0           oci.oraclecloud.com/oke-is-preemptible=true   44h
nvidia-gpu-device-plugin   0         0         0       0            0           <none>                                        44h
proxymux-client            0         0         0       0            0           node.info.ds_proxymux_client=true             44h
vcn-native-ip-cni          0         0         0       0            0           <none>                                        44h
```

使えないなら、最初からデプロイしないでほしいですね。

## 作成、削除、ログイン
普通にPodを作成します。

```
$ k run nginx --image nginx
pod/nginx created
$ k get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          2m35s
```

ログインします。
```
$ kubectl exec -it nginx -- sh
$
```
ログインできずにプロンプトが返ってきました。-c でコンテナ名を指定してログインしてみましたが、同様でした。
マニュアルには、サポートしていないと書かれています。

ログは確認できます。

```
$ kubectl logs nginx
2023-03-26T05:17:48.370146022Z stdout F /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
2023-03-26T05:17:48.370166942Z stdout F /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
2023-03-26T05:17:48.371551298Z stdout F /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
2023-03-26T05:17:48.385396551Z stdout F 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
2023-03-26T05:17:48.396026804Z stdout F 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
2023-03-26T05:17:48.408288933Z stdout F /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
2023-03-26T05:17:48.436906488Z stdout F /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
2023-03-26T05:17:48.440753522Z stdout F /docker-entrypoint.sh: Configuration complete; ready for start up
2023-03-26T05:17:48.44171872Z stderr F 2023/03/26 05:17:48 [notice] 1#1: using the "epoll" event method
2023-03-26T05:17:48.441727187Z stderr F 2023/03/26 05:17:48 [notice] 1#1: nginx/1.23.3
2023-03-26T05:17:48.441730101Z stderr F 2023/03/26 05:17:48 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023-03-26T05:17:48.441731885Z stderr F 2023/03/26 05:17:48 [notice] 1#1: OS: Linux 5.4.17-2136.309.5.1.el8.container
2023-03-26T05:17:48.441733518Z stderr F 2023/03/26 05:17:48 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023-03-26T05:17:48.441800666Z stderr F 2023/03/26 05:17:48 [notice] 1#1: start worker processes
2023-03-26T05:17:48.442342478Z stderr F 2023/03/26 05:17:48 [notice] 1#1: start worker process 29
2023-03-26T05:17:48.44234881Z stderr F 2023/03/26 05:17:48 [notice] 1#1: start worker process 30
```

ただ、`kubectl logs -f` は使えず、-f オプションをつけてもつけてないと同じように表示されます。


削除します。
```
$ kubectl delete pod nginx
pod "nginx" deleted
```
Podの作成、削除は通常のKubernetesやOKEと比べて時間がかかる印象です。
また、EKS on FargateだとPodに合わせてNodeが増減しますが、OKE on Virtual NodeだとNode数は一定です。


# namespace
Namespaceを作成して、Podを作成します。

```
$ kubectl create ns red
namespace/red created
$ kubectl run nginx-red --image nginx -n red
pod/nginx-red created
$ k -n red get pod
NAME        READY   STATUS    RESTARTS   AGE
nginx-red   1/1     Running   0          73s
```

追加設定なくできました。

# Deployment

Deploymentを作成します。
```
$ kubectl create deployment nginx-dep --image nginx --replicas 10
deployment.apps/nginx-dep created
```
3つのNodeにPodがデプロイされています。

```
$ k get pod -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
nginx-dep-5d749f9f67-48xrc   1/1     Running   0          34m   10.0.10.102   10.0.10.204   <none>           <none>
nginx-dep-5d749f9f67-4c5sq   1/1     Running   0          34m   10.0.10.132   10.0.10.73    <none>           <none>
nginx-dep-5d749f9f67-bxspw   1/1     Running   0          34m   10.0.10.191   10.0.10.204   <none>           <none>
nginx-dep-5d749f9f67-jls47   1/1     Running   0          25m   10.0.10.201   10.0.10.73    <none>           <none>
nginx-dep-5d749f9f67-k2z5b   1/1     Running   0          25m   10.0.10.177   10.0.10.231   <none>           <none>
nginx-dep-5d749f9f67-k9jn5   1/1     Running   0          34m   10.0.10.229   10.0.10.204   <none>           <none>
nginx-dep-5d749f9f67-krct4   1/1     Running   0          34m   10.0.10.50    10.0.10.204   <none>           <none>
nginx-dep-5d749f9f67-mvb25   1/1     Running   0          34m   10.0.10.115   10.0.10.73    <none>           <none>
nginx-dep-5d749f9f67-tvj2j   1/1     Running   0          34m   10.0.10.53    10.0.10.231   <none>           <none>
nginx-dep-5d749f9f67-xk52d   1/1     Running   0          34m   10.0.10.43    10.0.10.231   <none>           <none>
```


# LoadBalancer
上記のDeployment（のPod）に対してLoadBalancerを作成します。

```lb.yaml
apiVersion: v1
kind: Service
metadata:
  name: flex-nginx-lb
  labels:
    app: nginx-dep
  annotations:
    service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "50"
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx-dep
```

```
$ kubectl apply -f lb.yaml
service/flex-nginx-lb created
$ kubectl get svc
NAME            TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)             AGE
flex-nginx-lb   LoadBalancer   10.96.212.65   150.230.25.196   80:31096/TCP        100s
kubernetes      ClusterIP      10.96.0.1      <none>           443/TCP,12250/TCP   2d4h
```

しばらくするとLoadBalancerがデプロイされて、EXTERNAL-IPにIPアドレスが表示されますが、OCIのコンソールで確認すると、ヘルスチェックがクリティカルになっています。

![スクリーンショット 2023-03-26 220320.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/86d097e4-4eac-a22f-fced-62a50c76fabd.png)

マニュアルに以下の記載がありますので、セキュリティリストを設定します。

> ロード・バランシング:ロード・バランシングは、ワーカー・ノード間ではなくポッド間です(管理対象ノードの場合と同様)。仮想ノードを含むクラスタでは、ロード・バランサ・セキュリティ・リスト管理が有効になっていないため、常にセキュリティ・ルールを手動で構成する必要があります。

LoadBalancerがデプロイされているサブネットに、ノードがデプロイされているサブネットへの以下2つのポートのEgressルールを追加します。
- LoadBalancerのポート番号（ここでは31096）
- kube-proxyのポート番号（10256）

![スクリーンショット 2023-03-26 220904.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/4f6ae58d-381f-2fc3-f2ed-249df128a419.png)

同様にノードがデプロイされているサブネットに、LoadBalancerからのIngressルールを同様に追加します。

![Inkedスクリーンショット 2023-03-26 221110.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/6d239dab-5010-f479-eca6-77770dc1a354.jpeg)

Egress, Ingressルールを追加すると、LoadBalancerのヘルスチェックがOKになります。

![スクリーンショット 2023-03-26 221804.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/a2af4948-9356-f5fc-eec8-99b2cdabe46f.png)

LoadBalancerのEXTERNAL-IPに対して、外部から疎通を確認します。

```
$ curl 150.230.25.196
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>
```

# その他制限事項
制限事項、未サポート機能としてここに書かれています。

https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengcomparingvirtualwithmanagednodes_topic.htm

個人的に以下をサポートしてないのは気になりました。

- init container
- kubectl logの -f オプション
- Security Context
- Container.Resources.Requests
- kubectl exec
- daemonset
- PVC
- NetworkPolicy