はじめに
この記事ではAzure Kubernetes Service(以下、AKS)で、Azure Container Instance(以下、ACI)を利用して仮想ノードを構築する方法を解説します。
想定読者
- Kubernetesを利用したことがある方
- Azureが好きな方
AKSでのワーカーノード
Kubernetesにおけるワーカーノードとは、クラスタにデプロイしたアプリケーション(Podなど)を実行する場所です。
AKSでのワーカーノードを構成する方法として、Virtual Machine Scale Set(以下、VMSS)を利用する方法、ACIを利用する方法が挙げられます。
VMSSによってワーカーノードを構成する場合、展開される各Virtual Machine(以下、VM)にkubelet
やコンテナランタイム(containerd
)が搭載されます。
このワーカーノードはVMと同様にあらかじめVMのサイズを決定し、それに沿ったキャパシティのもとアプリケーションを実行できます。
ACIを利用してワーカーノードを構成する場合、kubelet
の代わりにOSSのVirtual Kubeletを利用してACIを仮想的なノードとして構成します。物理的なサーバを持たないことから、これを仮想ノードと呼びます。
VMSSによるワーカーノードと比較すると、以下の利点があります。
-
ノードの空きリソースに関係なく、リクエストのバースト時に素早くアプリケーションをスケールアウトできる
VMSSによるワーカーノードの場合、VMの空きリソースがある場合は素早くスケールアウトできますが、空きリソースがない場合にはノード自体をスケールアウト(VMを新しく起動)する必要があります。
ACIによるワーカーノードの場合は、ノードの空きリソースに関係なく、VMノードを起動するよりも素早くスケールアウトできます。 -
OS層のメンテナンスが必要ない
OS層がマネージドなACIを利用することで管理負荷を下げることができます。
ただし、仮想ノードのアドオン自体のバージョンアップは必要です。
ACIを使った仮想ノード
前述の通り、ACIはVirtual Kubeletをもとに実装されています。ここではそのアーキテクチャと、仮想ノードを利用するうえでの注意点について説明します。
アーキテクチャ
Virtual Kubeletを説明する前に、KubernetesにおけるKubeletについて簡単に説明します。
Kubeletの役割はノード上で実行されるPodを管理・操作することです。Kubernetesクラスタを構成する各ノード上で実行されるエージェントとして動作します。Kubeletが動作するノードは物理サーバ・仮想サーバを問いません。Kubernetesのapiserverからの入力を受け取り、受け取ったマニフェストのPodSpec
をもとにノード上のPodを監視し、PodSpec
通りの動作を続けるよう管理します。
Kubeletを実装したものの1つがVirtual Kubeletで、Kubernetes外のAPIと接続することを目的につくられています。
このVirtual Kubeletと接続するAPIとして、ACIなどのコンテナプラットフォームを選択することで、Kubernetesのノードをサーバレスに構成することができます。
画像はこちらから引用
仮想ノードを利用するうえでの注意点
仮想ノードを利用するうえでの注意点(制約)もあるので、ここで代表的なものを紹介します。
AKSではCoreDNS
やmetrics-server
のPodを常に起動させておくシステムノードプールが必要になります。
システムノードプールはノード数を0にできないため、AKSを構成するワーカーノードをすべて仮想ノードにすることはできません。
仮想ノードを利用すると、実際にはACIをVNETに配置することになるため、ACIのVNET上での制約事項がそのまま適用されます。
- Azure Container Registry(以下、ACR)からのサービスプリンシパルを利用したイメージのプルができない
仮想ノード上ではサービスプリンシパル(マネージドID含む)を利用してACRに対して認証することができません。仮想ノードでACRにホストされたイメージを利用したい場合、Kubernetes Secretを利用する必要があります。
- Init Containerが利用できない
Init Containerを利用するワークロードを仮想ノード上で実現できません。VMノードで実行するか、Init Containerを必要としないアプリケーションアーキテクチャを採用する必要があります。
- Kubenetを利用できない
Azure CNIネットワークを利用したAKSクラスタを構築する必要があります。
- DaemonSetのPodは仮想ノードにデプロイされない
DaemonSetのPodがデプロイされるのはVMノードのみです。
その他制約事項はこちらを参照ください。
ACIを利用して仮想ノードを構築する
ここからは公式ドキュメントにならって、AKSに仮想ノードを構築してアプリケーションをホストする手順を解説していきます。
Azure Cloud Shell
この記事では、Azure Cloud Shell(Bash)からAzure CLIを利用します。
Azure CLIからACIを利用するため、以下のコマンドを実行します。
az provider register --namespace Microsoft.ContainerInstance
次のコマンドによりACIのリソースプロバイダが登録されていることを確認します。
az provider list --query "[?contains(namespace,'Microsoft.ContainerInstance')]" -o table
RegistrationState
がRegistered
になっていることが確認できればOKです。
AKSの構築
AKSをリンクを参考に構築します。
-
ネットワークの種類はAzure CNIを選択してください。
AKSへの接続情報取得
以下コマンドを実行し、AKSへの接続情報を取得します。
az aks get-credentials --resource-group <リソースグループ名> --name <AKSクラスタ名>
kubectl config get-contexts
を実行したときに作成したAKSクラスターが選択されていればOKです。
マネージドIDの有効化とロールの割り当て
AKSクラスターでマネージドIDを有効化します。
az aks update -g <リソースグループ名> -n <AKSクラスタ名> --enable-managed-identity
az aks show -g <リソースグループ名> -n <AKSクラスタ名> --query "servicePrincipalProfile"
を実行したとき、"clientId": "msi"
が確認できればOKです。
次に有効化したマネージドIDに対して、ロールを割り当てます。
仮想ノードでは、AKSクラスターが利用しているVNETに対してACIをデプロイする必要があるため、そのデプロイに必要なロールを割り当てます。
なお、AKSのVNET名はAzureポータルから確認してください。
# マネージドIDのオブジェクトID取得
principalId=$(az aks show -g <リソースグループ名> -n <AKSクラスタ名> --query "identity.principalId" -o tsv)
# ノードのリソースグループ取得
nodeRg=$(az aks show -g <リソースグループ名> -n <AKSクラスタ名> --query "nodeResourceGroup" -o tsv)
# VNETのオブジェクトIDの取得
vnetId=$(az network vnet show --resource-group $nodeRg --name <AKSのVNET名> --query id -o tsv)
# マネージドIDへVNETへのアクセス許可を割り当て
az role assignment create --assignee $principalId --scope $vnetId --role Contributor
仮想ノード用のサブネットの作成
仮想ノードで利用するACIをデプロイするためのサブネットを作成します。
サブネットのCIDRは、作成されたVNETに合わせて調整してください。
az network vnet subnet create \
--resource-group $nodeRg \
--vnet-name <AKSのVNET名> \
--name <仮想ノード用サブネット名> \
--address-prefixes 10.241.0.0/16
仮想ノードアドオンを有効化
いよいよ仮想ノード用のアドオンを有効化します。
以下コマンドを実行してください。
az aks enable-addons \
--resource-group <リソースグループ名> \
--name <AKSクラスタ名> \
--addons virtual-node \
--subnet-name <仮想ノード用のサブネット名>
有効化後、kubectl get pods --namespace kube-system
を実行したときにaci-connector-linux
で始まるPodがデプロイされていればOKです。
仮想ノードにアプリケーションをデプロイ
仮想ノードにアプリケーションをデプロイするため、以下のマニフェスト(virtual-node.yaml
)を作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: aci-helloworld
spec:
replicas: 1
selector:
matchLabels:
app: aci-helloworld
template:
metadata:
labels:
app: aci-helloworld
spec:
containers:
- name: aci-helloworld
image: mcr.microsoft.com/azuredocs/aci-helloworld
ports:
- containerPort: 80
nodeSelector:
kubernetes.io/role: agent
beta.kubernetes.io/os: linux
type: virtual-kubelet
tolerations:
- key: virtual-kubelet.io/provider
operator: Exists
- key: azure.com/aci
effect: NoSchedule
ポイントはnodeSelector
とtolerations
です。
nodeSelector
はPodが利用するノードを特定のノードに限定するためのもので、ここではvirtual-kubelet
が指定されていることがわかります。VMノードにはPodを配置せず、仮想ノードにのみ配置するよう定義されています。
次にtolerations
を説明する前に、Taint
について説明します。
Taint
とはノード上で実行するPodを制限するためのものです。仮想ノードで重要なPod(kube-proxy
など)が配置されるのを避けるため、Taint
が設定されています。
tolerations
はこのTaint
による制約の影響を受けなくすることができるものです。上記マニフェストでは仮想ノードに設定されたTaint
の影響を避けることができます。
kubectl apply -f virtual-node.yaml
でデプロイします。
動作確認
kubectl get pods -o wide
を実行すると、aci-helloworld
のPodがvirtual-node-aci-linux
のノードで実行されていることが確認できます。これは仮想ノードであり、コンテナランタイムはACIになります。
実際にAzureポータルからACIのメニューを開くと、マニフェストで定義したコンテナが実行されていることが確認できます。
次に実際にアプリケーションが動作しているか確認します。
AKSクラスターに次のコマンドを実行して、仮想ノード上のアプリケーションに対してcurl
でアクセスしてみます。
まずはubuntuベースのコンテナをクラスタ内に展開します。
kubectl run -it --rm testvk --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11
コンテナ内でcurl
をインストールします。
apt-get update && apt-get install -y curl
実際にcurl
により、仮想ノード上のアプリケーションにアクセスします。
IPアドレスは、kubectl get pods
により得られるアドレスを指定してください。
curl -L http://<仮想ノード上のPodのIPアドレス>
<html>
<head>
<title>Welcome to Azure Container Instances!</title>
</head>
...
htmlの出力が得られているため、正常にアプリケーションが実行されていることが確認できました。
おわりに
この記事ではACIを利用して、AKSで仮想ノードを構成する方法を解説しました。
まだまだ制約事項が多く利用場所を選ぶ技術なので、実際のワークロードにそって導入を検討してください。