En el mes de mayo se anunció, en public preview, la posibilidad de integrar los objetos de tipo Services con la creación de Private Links de Azure. Gracias a ello, ahora será más sencillo la creación de estos y no tendrás que buscar la IP del balanceador interno al que asociarlos, quedando además reflejado como parte de la configuración del manifiesto del servicio. En este artículo te cuento cómo probarlo.
Crear un clúster de prueba
Si todavía no lo tienes, puedes crear un clúster de prueba ejecutando los siguientes comandos:
# Variables
RESOURCE_GROUP="aks-private-link-service-resource"
AKS_NAME="aks-pls-demo"
LOCATION="northeurope"
AKS_VNET="aks-vnet"
AKS_SUBNET="aks-subnet"
PLS_SUBNET="pls-subnet"
# Create a resource group
az group create --name $RESOURCE_GROUP --location $LOCATION
# Create a vnet for the cluster
az network vnet create \
--resource-group $RESOURCE_GROUP \
--name $AKS_VNET \
--address-prefixes 10.0.0.0/8 \
--subnet-name $AKS_SUBNET \
--subnet-prefixes 10.240.0.0/24
# Create a subnet for the Private Links
az network vnet subnet create \
--resource-group $RESOURCE_GROUP \
--vnet-name $AKS_VNET \
--name $PLS_SUBNET \
--address-prefixes 10.241.0.0/24
# Assign permissions to the vnet
# Create a service principal and read in the application ID
SP=$(az ad sp create-for-rbac --output json)
SP_ID=$(echo $SP | jq -r .appId)
SP_PASSWORD=$(echo $SP | jq -r .password)
# Wait 15 seconds to make sure that service principal has propagated
echo "Waiting for service principal to propagate..."
sleep 15
# Get the virtual network resource ID
VNET_ID=$(az network vnet show --resource-group $RESOURCE_GROUP --name $AKS_VNET --query id -o tsv)
# Assign the service principal Contributor permissions to the virtual network resource
az role assignment create --assignee $SP_ID --scope $VNET_ID --role Contributor
# Get the virtual network subnet resource ID
SUBNET_ID=$(az network vnet subnet show --resource-group $RESOURCE_GROUP --vnet-name $AKS_VNET --name $AKS_SUBNET --query id -o tsv)
# Create an AKS cluster
az aks create \
--resource-group $RESOURCE_GROUP \
--name $AKS_NAME \
--node-count 1 \
--generate-ssh-keys \
--node-vm-size Standard_B4ms \
--vnet-subnet-id $SUBNET_ID \
--service-principal $SP_ID \
--client-secret $SP_PASSWORD \
--docker-bridge-address 172.17.0.1/16 \
--dns-service-ip 10.2.0.10 \
--service-cidr 10.2.0.0/24 \
--network-plugin azure
# Get the cluster credentials
az aks get-credentials \
--resource-group $RESOURCE_GROUP \
--name $AKS_NAME
Como ves, estoy creando la red virtual a parte y he añadido además una subnet específica para los private links que vaya generando, asociados a mis servicios.
Servicios integrados con Private Link
Una vez que tengas el clúster, para probar esta integración es tan sencillo como esto:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: my-private-link-service
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true" # Right now PLS must be used with internal LB
service.beta.kubernetes.io/azure-pls-create: "true"
service.beta.kubernetes.io/azure-pls-name: my-private-link-service
service.beta.kubernetes.io/azure-pls-ip-configuration-subnet: pls-subnet
service.beta.kubernetes.io/azure-pls-ip-configuration-ip-address-count: "1"
service.beta.kubernetes.io/azure-pls-ip-configuration-ip-address: 10.241.0.9 # Must be available in pls-subnet
# service.beta.kubernetes.io/azure-pls-fqdns: "fqdn1 fqdn2"
# service.beta.kubernetes.io/azure-pls-proxy-protocol: "false"
service.beta.kubernetes.io/azure-pls-visibility: "*"
# service.beta.kubernetes.io/azure-pls-auto-approval: "subId1"
spec:
type: LoadBalancer
selector:
app: web
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
Como ves, he creado un Deployment con la imagen de nginx, para tener algo a lo que consultar, y después he generado un Service del tipo LoadBalancer con un montón de anotaciones:
- En primer lugar, es necesario que el balanceador que se utilice sea de tipo internal.
- En este caso, queremos que con la creación de este servicio se cree el private link.
- Le decimos en qué subnet queremos que alojemos el private link (pls-subnet)
- Cuántas IP le asociamos
- Y la IP que queremos asociarla, la cual debe estar disponible dentro de la subnet, en este caso la 10.241.0.9.
- Hay otras anotaciones que puedes consultar aquí, que para este ejemplo no hacen falta.
El resto de especificaciones son las habituales en un Service.
Probar la comunicación con los servicios
Para comprobar que todo funciona correctamente, he creado una máquina virtual dentro de la misma red donde se encuentra el clúster:
# Create a VM in the same vnet as the cluster
az vm create \
--resource-group $RESOURCE_GROUP \
--name jumpbox-vm \
--image UbuntuLTS \
--admin-username azureuser \
--admin-password AzurePassword1234 \
--size Standard_B4ms \
--vnet-name $AKS_VNET \
--subnet $VM_SUBNET
# Get the VM public IP address
VM_IP=$(az vm list-ip-addresses --resource-group $RESOURCE_GROUP --name jumpbox-vm --query '[0].virtualMachine.network.publicIpAddresses[0].ipAddress' -o tsv)
# Connect to the vm via ssh
ssh azureuser@$VM_IP
Recupero la IP del balanceador generada para el Servicio:
k get svc my-private-link-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Y hago una llamada a esta IP, para acceder a través del puerto 80 al Servicio que a su vez está asociado al Private Link:
curl http://10.240.0.35 # This is the Azure Internal Load Balancer IP
Por cada nuevo servicio que crees el balanceador interno cogerá una nueva IP y la asociará al mismo:

De la misma forma que creará el private link correspondiente:
y estos se asociarán de manera automática al balanceador interno de nuestro clúster de Kubernetes.
¡Saludos!