「Virtual Kubelet」を使って、Azure Kubernetes Service (AKS)とAzure Container Instances (ACI)を連係する

# はじめに

去年から今年にかけて、Azureの「Azure Container Instances (ACI)」、AWSの「Fargate」、GCPの「Serverless containers」などのサーバーレスコンテナプラットフォームが次々に発表/リリースされました。

かつ、各社のマネージドKubernetesサービス(AKS、EKS、GKE)とこれらのサーバーレスコンテナプラットフォームを連係するソリューションも提供が予定されています。

* AKS： マイクロソフトがOSSとして「[Virtual Kubelet](https://github.com/virtual-kubelet/virtual-kubelet)」を公開
* EKS： EKSにおけるFargateのサポートを2018年に開始する予定であると[公表](https://aws.amazon.com/jp/fargate/)
* GKE： Serverless containersの発表と同時に「GKE serverless add-on」を[発表](https://cloudplatform.googleblog.com/2018/07/bringing-the-best-of-serverless-to-you.html)

これらのうち、現時点で実際に触ってみることができるのは「Virtual Kubelet」です。

6月に一度試してみて、Azureのユーザーコミュニティ「[JAZUG熊本 (くまあず)](https://jazug.connpass.com/event/88033/)」で紹介させて頂いたのですが、その後、いくつか変更点があったようなので、その点を含めて再度試してみました。


# Virtual Kubeletとは

もともと、ACIをAKSの仮想ノードとして利用できるようにするOSSとして、マイクロソフトが「ACI Connector for Kubernetes (aci-connector-k8s)」を公開していました。
これを、AKSのみでなく他のマネージドKubernetesサービスにも対応できるPluggableなOSSとして発展させたものが「Virtual Kubelet」です。
https://github.com/virtual-kubelet/virtual-kubelet

Virtual Kubeletを用いてAKSとACIがどのように連係して動作するのか、イメージを掴みたい方は、よろしければ「JAZUG熊本 (くまあず)」での私の発表スライドをご覧になって下さい。(手抜き)
[SlideShare: AKSとACIを組み合わせて使ってみた](https://www.slideshare.net/HideakiAoyagi/aks-aci)

(スライドの3～6枚目で **ざっくりと** 説明しています)
<img src="https://qiita-image-store.s3.amazonaws.com/0/273982/8f565f71-7a79-0eb0-e7af-5d7be37f1e52.png" width="320">
<img src="https://qiita-image-store.s3.amazonaws.com/0/273982/9a9d471a-0d3d-1f53-1e2e-f3d6257ba142.png" width="320">
<img src="https://qiita-image-store.s3.amazonaws.com/0/273982/333cac8a-d413-dede-663a-0fefb14601ea.png" width="320">
<img src="https://qiita-image-store.s3.amazonaws.com/0/273982/876f6257-9de3-67c9-4404-c493ed84fcd5.png" width="320">


# Virtual Kubelet導入手順

「Virtual Kubelet ACI provider」のドキュメント
https://github.com/virtual-kubelet/virtual-kubelet/tree/master/providers/azure
に記載されている手順に従って導入します。

ただし、内容が一部古い部分があるようですので、その点を解説しながら進めて行きます。


## 前提

* Microsoft Azureのアカウントを持っていること

は当然として、手元のPCに下記のツールがインストールされている必要があります。

* Azure CLI
* Kubernetes CLI (kubectl)
* Helm CLI

Helmは、Virtual Kubeletの設定コマンド( `az aks install-connector` )の内部で使われます。

なお、[Azure Cloud Shell](https://azure.microsoft.com/ja-jp/features/cloud-shell/)であれば上記のツールは全てインストール済みですので楽チン(死語)です。

参考：私が試した時のバージョン
* Azure CLI ： 2.0.44
* Kubernetes CLI： 1.11.0
* Helm CLI： 2.9.1


## 1. AKSクラスタの作成

AKSクラスタはGUI(Azure Portal)でも作成できますが、ここではAzure CLIでの作成手順を示します。

### (1) リソースグループを作成する

AKS自体は既に日本(東日本リージョン)で利用可能ですが、ACIがまだ日本に来ていないため、今回は「米国西部(westus)」リージョンを使用することにします。

```shell
$ az group create -n myResourceGroup -l westus
```

### (2) AKSクラスタを作成する

最低限、指定が必須なパラメータは「リソースグループ」「クラスタ名」です。

```shell
$ az aks create -g myResourceGroup -n myAksCluster
```

ワーカーノードのスペックについて、パラメータ省略時のデフォルトは以下のようになります。
* VMサイズ( `--node-vm-size` / `-s` )： Standard_DS1_v2
* ノード数( `--node-count` / `-c` )： 3

費用を節約したい場合はVMサイズをより小さいものにしたりノード数を「1」とかにしても問題ありませんが、余りにも低スペックのVMを指定すると(Standard_A0など)コマンドがエラーを返します。

#### 【ワンポイント】 AKSクラスタ作成時の「RBAC有効/無効」の指定について

Azure CLIの **バージョン2.0.40** (2018/7/3リリース) 以降、`az aks create` コマンドでAKSクラスタを作成する際にデフォルトで「RBAC (ロールベースのアクセス制御)」が有効化されるようになりました。
(RBACを無効にしたい場合は明示的に `--disable-rbac` を指定する必要あり)

RBACが有効/無効のどちらであるのかは、後の手順に影響してきます。
どちらでAKSクラスタが作成されるのかを意識しておきましょう。

### (3) kubectlの設定を行い、AKSクラスタへ接続する

AKSクラスタが作成されたら、kubectlからAKSクラスタへ接続するために `~/.kube/config` ファイルを記述します。
手で書いてもよいですが、AKSの場合はコマンド一発で必要な情報をconfigに取り込んでくれるので楽チ・・・便利です。

```shell
$ az aks get-credentials -g myResourceGroup -n myAksCluster
Merged "myAksCluster" as current context in /home/user/.kube/config
```

設定が終わったら、ASKクラスタへ接続できることを確認しましょう。

```shell
$ kubectl config get-contexts
CURRENT   NAME           CLUSTER        AUTHINFO                                   NAMESPACE
*         myAksCluster   myAksCluster   clusterUser_myResourceGroup_myAksCluster
```

```shell
$ kubectl get nodes -o wide
NAME                       STATUS    ROLES     AGE       VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
aks-nodepool1-38988403-0   Ready     agent     6m        v1.9.9    10.240.0.4    <none>        Ubuntu 16.04.5 LTS   4.15.0-1018-azure   docker://1.13.1
aks-nodepool1-38988403-1   Ready     agent     6m        v1.9.9    10.240.0.6    <none>        Ubuntu 16.04.5 LTS   4.15.0-1018-azure   docker://1.13.1
aks-nodepool1-38988403-2   Ready     agent     6m        v1.9.9    10.240.0.5    <none>        Ubuntu 16.04.5 LTS   4.15.0-1018-azure   docker://1.13.1
```


## 2. Helmの設定

### (1) AKSクラスタを「RBAC無効」で作成した場合

この場合は、単純に `helm init` コマンドを実行するだけです。

```shell
$ helm init
Creating /home/user/.helm
Creating /home/user/.helm/repository
Creating /home/user/.helm/repository/cache
Creating /home/user/.helm/repository/local
Creating /home/user/.helm/plugins
Creating /home/user/.helm/starters
Creating /home/user/.helm/cache/archive
Creating /home/user/.helm/repository/repositories.yaml
Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com
Adding local repo with URL: http://127.0.0.1:8879/charts
$HELM_HOME has been configured at /home/user/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!
```

### (2) AKSクラスタを「RBAC有効」で作成した場合

この場合は、Helmのドキュメントにある通り、追加の手順が必要です。
https://github.com/helm/helm/blob/master/docs/rbac.md

まず、以下のKubernetesマニフェストファイルを作成します。

```yaml:rbac-config.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
```

マニフェストからServiceAccount(およびClusterRoleBinding)リソースを作成します。

```shell
$ kubectl apply -f rbac-config.yaml
serviceaccount/tiller created
clusterrolebinding.rbac.authorization.k8s.io/tiller created
```

作成したServiceAccountを指定してHelmの初期化を行います。

```shell
$ helm init --service-account tiller
Creating /home/user/.helm
Creating /home/user/.helm/repository
Creating /home/user/.helm/repository/cache
Creating /home/user/.helm/repository/local
Creating /home/user/.helm/plugins
Creating /home/user/.helm/starters
Creating /home/user/.helm/cache/archive
Creating /home/user/.helm/repository/repositories.yaml
Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com
Adding local repo with URL: http://127.0.0.1:8879/charts
$HELM_HOME has been configured at /home/user/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!
```


## 3. Virtual Kubeletのインストール

Virtual Kubeletのインストールは `az aks install-connector` コマンドで行います。
ここでも最低限指定が必須なパラメータは「リソースグループ」「クラスタ名」のみです。

```shell
$ az aks install-connector -g myResourceGroup -n myAksCluster
```

その他の主なパラメータは、以下の通りです。

<dl>
<dt><code>--connector-name</code>
<dd>ACI Connectorの名前を指定します。<br>
以前は省略不可でしたが、現在では省略可能となっており、省略時にはデフォルトで「aci-connector」という名前が付けられます。
</dl>

<dl>
<dt><code>--os-type</code>
<dd>使用するACIのOSタイプを「Linux」「Windows」「Both」から選択して指定します。(Bothの場合は両方が選択される)<br>
省略時のデフォルトは「Linux」です。
</dl>

<dl>
<dt><code>--aci-resource-group</code>
<dd>ACIのデプロイ先リソースグループを指定します。<br>
デフォルトでは、AKSクラスタ作成時に自動的に作成される「MC_～」で始まるリソースグループが指定されます。<br>
ドキュメントには「Azure CLIの<strong>バグ</strong>のため、このパラメータは明示的に指定する必要がある(省略できない)」とありますが、現在ではこのバグは解消されているようです。
</dl>

`az aks install-connector` コマンドの実行結果は以下のようになります。

```shell
$ az aks install-connector -g myResourceGroup -n myAksCluster
Merged "myAksCluster" as current context in /tmp/tmp4yibmvpa
Deploying the ACI connector for 'Linux' using Helm
NAME:   aci-connector-linux-westus
LAST DEPLOYED: Thu Aug 16 12:44:12 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Secret
NAME                                                TYPE    DATA  AGE
aci-connector-linux-westus-virtual-kubelet-for-aks  Opaque  3     1s

==> v1/ServiceAccount
NAME                                                SECRETS  AGE
aci-connector-linux-westus-virtual-kubelet-for-aks  1        1s

==> v1beta1/ClusterRoleBinding
NAME                                                AGE
aci-connector-linux-westus-virtual-kubelet-for-aks  1s

==> v1beta1/Deployment
NAME                                                DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
aci-connector-linux-westus-virtual-kubelet-for-aks  1        1        1           0          1s

==> v1/Pod(related)
NAME                                                             READY  STATUS             RESTARTS  AGE
aci-connector-linux-westus-virtual-kubelet-for-aks-7f6589dhzmht  0/1    ContainerCreating  0         1s


NOTES:
The virtual kubelet is getting deployed on your cluster.

To verify that virtual kubelet has started, run:

  kubectl --namespace=default get pods -l "app=aci-connector-linux-westus-virtual-kubelet-for-aks"

Note:
TLS key pair not provided for VK HTTP listener. A key pair was generated for you. This generated key pair is not suitable for production use.
user@Azure:~/aks-virtualkubelet$
```

### 【ワンポイント】 az aks install-connectorコマンドでエラーとなってしまった場合

「2. Helmの設定」において、AKSクラスタでRBACが有効であるのにもかかわらず `helm init` (オプション無し)で初期化してしまった場合、`az aks install-connector` コマンドの実行時に以下のようなエラーとなってしまいます。

```shell
Error: release myconnector-linux-westus failed: namespaces "default" is forbidden: User "system:serviceaccount:kube-system:default" cannot get namespaces in the namespace "default"
```

こうなってしまった場合は、一度 `helm reset --force` コマンドでHelm環境をリセットした後、「(2) AKSクラスタを「RBAC有効」で作成した場合」からやり直しましょう。


## 4. インストール後の確認

さて、ここまででVirtual Kubeletの導入は終わりです。
ノードの一覧を確認してみましょう。

```shell
$ kubectl get nodes -o wide
NAME                                         STATUS    ROLES     AGE       VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
aks-nodepool1-38988403-0                     Ready     agent     13m       v1.9.9    10.240.0.4    <none>        Ubuntu 16.04.5 LTS   4.15.0-1018-azure   docker://1.13.1
aks-nodepool1-38988403-1                     Ready     agent     13m       v1.9.9    10.240.0.6    <none>        Ubuntu 16.04.5 LTS   4.15.0-1018-azure   docker://1.13.1
aks-nodepool1-38988403-2                     Ready     agent     13m       v1.9.9    10.240.0.5    <none>        Ubuntu 16.04.5 LTS   4.15.0-1018-azure   docker://1.13.1
virtual-kubelet-aci-connector-linux-westus   Ready     agent     45s       v1.8.3    10.244.2.3    <none>        <unknown>            <unknown>           <unknown>
```

既にある3つの物理ノード(aks-nodepool1-～)に加えて、4番目のノード(仮想ノード)として「virtual-kubelet-aci-connector-linux-westus」が作成されたことが分かります。

ついでに、デプロイされたACI Connector/Virtual Kubeletの実体を確認してみましょう。

```shell
$ kubectl get all -o wide
NAME                                                                  READY     STATUS    RESTARTS   AGE       IP           NODE
pod/aci-connector-linux-westus-virtual-kubelet-for-aks-7f6589dhzmht   1/1       Running   0          1m        10.244.2.3   aks-nodepool1-38988403-2

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE       SELECTOR
service/kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   14m       <none>

NAME                                                                       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINERS               IMAGES                             SELECTOR
deployment.extensions/aci-connector-linux-westus-virtual-kubelet-for-aks   1         1         1            1           1m        aci-connector-linux-westus-virtual-kubelet-for-aks   microsoft/virtual-kubelet:latest   app=aci-connector-linux-westus-virtual-kubelet-for-aks

NAME                                                                                  DESIRED   CURRENT   READY     AGE       CONTAINERS           IMAGES                             SELECTOR
replicaset.extensions/aci-connector-linux-westus-virtual-kubelet-for-aks-7f6589df64   1         1         1         1m        aci-connector-linux-westus-virtual-kubelet-for-aks   microsoft/virtual-kubelet:latest   app=aci-connector-linux-westus-virtual-kubelet-for-aks,pod-template-hash=3921458920

NAME                                                                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINERS         IMAGES                             SELECTOR
deployment.apps/aci-connector-linux-westus-virtual-kubelet-for-aks   1         1         1            1           1m        aci-connector-linux-westus-virtual-kubelet-for-aks   microsoft/virtual-kubelet:latest   app=aci-connector-linux-westus-virtual-kubelet-for-aks

NAME                                                                            DESIRED   CURRENT   READY     AGE       CONTAINERS     IMAGES                             SELECTOR
replicaset.apps/aci-connector-linux-westus-virtual-kubelet-for-aks-7f6589df64   1         1         1         1m        aci-connector-linux-westus-virtual-kubelet-for-aks   microsoft/virtual-kubelet:latest   app=aci-connector-linux-westus-virtual-kubelet-for-aks,pod-template-hash=3921458920
```

「default」ネームスペースにデプロイされていますし(kube-systemとかの方がいいと思うのですが・・・)、レプリカ数は「1」となっています。
このあたりはHelmのチャートを書き換えれば変更できそうではありますが、Virtual Kubelet自体が「プレビュー中 (本番環境には推奨しない)」となっているため、正式リリースまでには見直されるのかもしれません。


# 動作確認

作成したVirtual Kubelet環境にポッドをデプロイして、動作を確認してみます。

ドキュメントにある「virtual-kubelet-test.yaml」をそのまま実行してもよいのですが、どうせなら複数個のポッドをデプロイした時にACIがどのように展開されるのかを見てみましょう。


## マニフェストの記述方法

レプリカ数「3」のポッドをデプロイするDeploymentを記述し、LoadBalancerサービスで振り分けられるようにします。

```yaml:aci-helloworld.yaml
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: aci-helloworld
spec:
  replicas: 3
  selector:
    matchLabels:
      app: aci-helloworld
  template:
    metadata:
      labels:
        app: aci-helloworld
    spec:
      containers:
      - name: aci-helloworld
        image: microsoft/aci-helloworld
        ports:
        - containerPort: 80
      nodeSelector:
        kubernetes.io/hostname: virtual-kubelet-aci-connector-linux-westus
      tolerations:
      - key: azure.com/aci
        effect: NoSchedule
---
apiVersion: v1
kind: Service
metadata:
  name: aci-helloworld-lb
spec:
  type: LoadBalancer
  selector:
    app: aci-helloworld
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
```

Virtual Kubeletを使って仮想ノード(ACI)上にポッドをデプロイする際のポイントは、以下の記述です。

```yaml
nodeSelector:
  kubernetes.io/hostname: virtual-kubelet-aci-connector-linux-westus
tolerations:
- key: azure.com/aci
  effect: NoSchedule
```

Virtual Kubeletでは、「kube-proxy」等のシステム上重要なポッドあるいはVirtual Kubelet自身のポッドが意図せず仮想ノードで実行されることを避けるため、「Taints」が設定されています。
(Taintsについての詳細は[Kubernetes公式ドキュメント](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)を参照して下さい)

意図して仮想ノード上へポッドを配置したい場合は、「nodeSelector:」および「tolerations:」を上記のように記述する必要があります。
それぞれの記述の意味は以下の通りです。

<dl>
<dt>「nodeSelector:」
<dd>ポッドの配置先を特定のホスト名を持つノードに限定します。<br>
物理ノードへ配置させないための指定とも言えます。<br>
仮想ノードのホスト名は <code>kubectl get nodes</code> で確認できますが、デフォルトに従って手順を進めた場合は「virtual-kubelet-aci-connector-linux-westus」となっているはずです。
</dl>

<dl>
<dt>「tolerations:」
<dd>前述の通り、仮想ノードには「Taints」が指定されているため、「Taints」の指定を無視して強制的にポッドを配置させるための設定です。
</dl>

### 【ワンポイント】 「tolerations:」の記述方法について

ドキュメントでは「tolerations:」を次のように記述するよう書かれています。

```yaml
tolerations:
- key: virtual-kubelet.io/provider
  value: azure
  effect: NoSchedule
```

より汎用的な記述方法にした、ということのようですが、現時点で「virtual-kubelet-for-aks」にはまだ反映されていないようです。
実際、仮想ノードのTaintsを確認してみると以下のようになっています。

```shell
$ kubectl describe node/virtual-kubelet-aci-connector-linux-westus
Name:   virtual-kubelet-aci-connector-linux-westus
(中略)
Taints: azure.com/aci:NoSchedule
(後略)
```

現時点では古い記述方法「key: azure.com/aci」にしておきましょう。(近々変更されるものと思われます)


## ポッドのデプロイ

それでは、ポッド(およびサービス)をデプロイします。

```shell
$ kubectl apply -f aci-helloworld.yaml
deployment.apps/aci-helloworld created
service/aci-helloworld-lb created
```

ポッドが以下のように配置・実行されていれば成功です。
NODE欄が「virtual-kubelet-aci-connector-linux-westus」となっているのが確認できます。

```shell
$ kubectl get pods -o wide
NAME                                                              READY     STATUS    RESTARTS   AGE       IP              NODE
aci-connector-linux-westus-virtual-kubelet-for-aks-7f6589dhzmht   1/1       Running   0          7m        10.244.2.3      aks-nodepool1-38988403-2
aci-helloworld-674f5554bd-57z7g                                   1/1       Running   0          2m        40.78.0.207     virtual-kubelet-aci-connector-linux-westus
aci-helloworld-674f5554bd-jkw2z                                   1/1       Running   0          2m        104.42.184.78   virtual-kubelet-aci-connector-linux-westus
aci-helloworld-674f5554bd-nbn2r                                   1/1       Running   0          2m        40.78.61.148    virtual-kubelet-aci-connector-linux-westus
```

もし、ポッドのSTATUSがいつまで経っても「Pending」となっている場合は、「nodeSelector:」および「tolerations:」の設定が間違っている可能性が大です。(行き場の無いポッドが「待ち」状態に陥っている)
マニフェストの記述内容を見直してみて下さい。

Virtual Kubeletと直接関係しませんが、LoadBalancerサービスの方は以下のようになっていればOKです。
EXTERNAL-IPが取得されるまで結構時間がかかる場合があるので、気長に待ちましょう。

```shell
$ kubectl get services -o wide
NAME                TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE       SELECTOR
aci-helloworld-lb   LoadBalancer   10.0.33.249   104.210.56.69   80:32172/TCP   3m        app=aci-helloworld
kubernetes          ClusterIP      10.0.0.1      <none>          443/TCP        20m       <none>
```

ここまで出来たら、LoadBalancerサービスの「EXTERNAL-IP」欄に表示されているIPアドレスに対して、Webブラウザで接続してみます。
![helloworld](https://qiita-image-store.s3.amazonaws.com/0/273982/fc93e333-b525-bb21-640a-01116fc6b943.png)
(以前のキャプチャなのでIPアドレスが違いますが気にしないで下さい)


## ACIはどのようになっているか？

`az aks install-connector` コマンドの `--aci-resource-group` パラメータの項目で説明した通り、AKSクラスタ作成時に自動的に作成されるリソースグループ「MC_～」内にACIのリソースが作成されます。
![aci-resources](https://qiita-image-store.s3.amazonaws.com/0/273982/984c0a40-2937-973a-8ae4-d5edd7461742.png)
1つのポッドにつき1つのACIリソースが作成されていることが確認できます。
リソース名は、Kubernetesの「ネームスペース名」＋「ポッド名」が付与されていることが分かります。

CLIでも確認してみましょう。

```shell
$ az container list -g MC_myResourceGroup_myAksCluster_westus -o table
Name                                     ResourceGroup                           ProvisioningState    Image                     IP:ports          CPU/Memory       OsType    Location
---------------------------------------  --------------------------------------  -------------------  ------------------------  ----------------  ---------------  --------  ----------
default-aci-helloworld-674f5554bd-57z7g  MC_myResourceGroup_myAksCluster_westus  Succeeded            microsoft/aci-helloworld  40.78.0.207:80    1.0 core/1.5 gb  Linux     westus
default-aci-helloworld-674f5554bd-jkw2z  MC_myResourceGroup_myAksCluster_westus  Succeeded            microsoft/aci-helloworld  104.42.184.78:80  1.0 core/1.5 gb  Linux     westus
default-aci-helloworld-674f5554bd-nbn2r  MC_myResourceGroup_myAksCluster_westus  Succeeded            microsoft/aci-helloworld  40.78.61.148:80   1.0 core/1.5 gb  Linux     westus
```

IPアドレスがグローバル(パブリック)であることが確認できます。
そうです、**パブリックIPアドレス** なのです。ですので、ACIのIPアドレスを直接指定してもアクセスできてしまいます。
これをプライベートIPアドレスにすることができるのかどうか・・・については、すみません、調べきれていません。
(まあ、ACIはもともと単体で外部から利用できるコンテナサービスであるため、仕方ないのかもしれません)

また、CPU/メモリのスペックも確認できます。
このあたりを指定したい場合は、マニフェストに明示的に記述しましょう。


# おわりに

Kubernetesとサーバーレスコンテナプラットフォームの連係(融合？)として期待できるVirtual Kubeletですが、現在はプレビュー段階ということもあり「Azure CLI一発では導入できない(Helmの初期化等が必要)」「仕様がちょくちょく変わっていく」といった点が見受けられます。

ただ、AKSリリース時のUI(Azure Portal/Azure CLI)の完成度などを考えると、Virtual Kubeletも本番リリースまでにはもっとシンプル・スマートな手順になっていることを期待しています。