Crear un volumen persistente con Azure Files y Private Enpoint para AKS dinámicamente

Ayer te mostré un escenario donde el resultado final era la posibilidad de utilizar Azure Files para tus volúmenes persistentes en AKS utilizando Private Link para su acceso. En ese artículo vimos el paso a paso de todos los recursos que necesitas crear para llegar a tu objetivo. Hoy quiero mostrarte cómo la versión 1.5 del CSI driver puede hacer todo este trabajo por ti y generar de forma dinámica todo lo que necesita para llegar al mismo punto.

Creación del clúster y asignación de permisos

Si leíste el artículo anterior, habrás comprobado que tuve que crear un montón de recursos (que en un entorno real podría ser reutilizar existentes), para hacer uso de una cuenta existente de Azure Storage con acceso a través de Private Link. Esto conllevaba crear la VNET, la cuenta de almacenamiento, el private endpoint, la zona DNS privada, para registrar la IP y el nombre asociado a la cuenta, y la relación entre la VNET y la zona DNS. Un montón de trabajo y piezas que debes saber cómo relacionar entre sí. Para este ejemplo vamos a crear simplemente el clúster de Kubernetes de la siguiente forma:

#Variables
RESOURCE_GROUP="AKS-DynamicStorage"
AKS_NAME="aks-dynamicstore"
LOCATION="northeurope"

#Create Resource Group
az group create --name $RESOURCE_GROUP --location $LOCATION

#Create AKS cluster
az aks create \
    --resource-group $RESOURCE_GROUP \
    --name $AKS_NAME \
    --generate-ssh-keys \
    --node-count 3 \
    --zones 1 2 3

Y vamos a asignar permisos a la managed identity, creada de manera automática, de Contributor:

#Get AKS node resource group name
AKS_RESOURCE_GROUP=$(az aks show --resource-group $RESOURCE_GROUP --name $AKS_NAME --query nodeResourceGroup --output tsv)

#Get AKS node resource group id
AKS_RESOURCE_GROUP_ID=$(az group show --name $AKS_RESOURCE_GROUP --query id --output tsv)

#Get Managed identity id
MANAGED_IDENTITY_ID=$(az aks show --name ${AKS_NAME} -g $RESOURCE_GROUP --query identityProfile.kubeletidentity.clientId --output tsv)

# Give Contributor permissions to the managed identity of the cluster
az role assignment create --assignee $MANAGED_IDENTITY_ID --role contributor --scope $AKS_RESOURCE_GROUP_ID

Instalar el CSI driver

El siguiente paso que necesitamos es instalar el driver CSI, de la misma forma que lo hicimos en el artículo anterior:

# Install CSI Driver
curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/v1.5.0/deploy/install-driver.sh | bash -s v1.5.0 --
k get pod -A

Nota: también hay un modo en preview para hacer todos estos pasos, añadiendo la opción –aks-custom-headers EnableAzureDiskFileCSIDriver=true durante la creación del clúster, que te ahorraría la instalación y la asignación de permisos, pero todavía está en preview:

az aks create \
    --resource-group $RESOURCE_GROUP \
    --name $AKS_NAME \
    --generate-ssh-keys \
    --node-count 3 \
    --zones 1 2 3 \
    --aks-custom-headers EnableAzureDiskFileCSIDriver=true

Crear una StorageClass para el aprovisionamiento dinámico

Ahora bien, a parte de los permisos asignados a la managed identity, lo que cambia en este caso es la configuración de la StorageClass:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: azurefile-csi
provisioner: file.csi.azure.com
allowVolumeExpansion: true
parameters:
  networkEndpointType: privateEndpoint
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
  - dir_mode=0777
  - file_mode=0777
  - uid=0
  - gid=0
  - mfsymlinks
  - cache=strict  
  - nosharesock  
  - actimeo=30

En este caso, en comparación con el anterior, lo único que añado es la opción networkEndpointType: privateEndpoint y, al no tener ninguna cuenta de almacenamiento existente, obvio el resto de parámetros que si asigné en el modo estático (accountName, resourceGroup, server). Con este parámetro es más que suficiente para que el propio driver sea el que se encargue de crear todo lo que tuvimos que hacer nosotros de manera «manual».

Desplegar aplicación de ejemplo

Para demostrar que eso funciona igual de bien que en el caso anterior, voy a utilizar el mismo ejemplo ubicado en k8s. El proceso tardará unos segundos más en completarse, ya que en esta ocasión tiene que crear todos los recursos que nosotros le proporcionamos de antemano la vez anterior, salvo que esta vez están ubicados en el grupo de recursos del AKS. Una vez finalice, el resultado será parecido al siguiente:

Recursos para Azure Files y Private Link en AKS creados dinamicamente

Si accedes a tu nueva cuenta de almacenamiento y subes la página de ejemplo apache-content/index.php verás que los pods responden sin problemas.

El código de ejemplo lo tienes en el mismo repo de GitHub, en el branch without-storage.

¡Saludos!