Deploy a Kubernetes Service on Azure with IP address that is in a different resource group to the cluster

When a service is deployed to Kubernetes we often need to specify a static IP address. This means that if the service gets recreated it retains the same IP. By default when you deploy a service in Kubernetes on Azure that static IP address must reside in the same resource group as the cluster nodes. This causes a couple of potential problems:

  • If you delete an Azure Kubernetes Service cluster then the cluster resource group (starts MC_) gets deleted and can lose the IP address in the resource group.
  • If need to reassign the IP address to a different cluster then you need to move it to the new MC_ resource group.
  • Many customers want to manage resources such as IP addresses in a dedicated resource group

In Kubernetes 1.10 we have a new feature that resolves these issues. A service annotation can be defined that specifies the resource group that the IP addresse reside in:

    // ServiceAnnotationLoadBalancerResourceGroup is the annotation used on the service
    // to specify the resource group of load balancer objects that are not in the same resource group as the cluster.

    ServiceAnnotationLoadBalancerResourceGroup = ""

In the following example I have specified the above annotation, and also a LoadBalancerIP. As I want to inject environment variables in the YAML prior to deployment I’ve used $IP_RG and $PUBLIC_IP. Along with the service is a vanilla deployment of nginx.

kind: Service
apiVersion: v1
  name: my-service
  annotations: $IP_RG
    app: my-app
  - protocol: TCP
    port: 80
    targetPort: 80
  loadBalancerIP: $PUBLIC_IP
  type: LoadBalancer


apiVersion: apps/v1
kind: Deployment
  name: my-app
    app: my-app
  replicas: 3
      app: my-app
        app: my-app
      - name: nginx
        image: nginx
        - containerPort: 80

The first step is to ensure we have a cluster running a Kubernetes cluster greater than version 1.10:


az group create -n $CLUSTER_RG -l westeurope

az aks create -g $CLUSTER_RG -n cluster1 --kubernetes-version 1.10.3

Once we have a cluster we need to create a resource group for the IP addresses:

export IP_RG="MyIPRG"
az group create -n $IP_RG -l westeurope

To enable Kubernetes to attach the IP to a load balancer the Azure Service Principal used by the cluster must be granted "Network Contributor" rights to the resource group:

CLIENT_ID=$(az aks show -n cluster1 -g $CLUSTER_RG --query servicePrincipalProfile.clientId | sed 's/"//g')
az role assignment create --role "Network Contributor" --assignee $CLIENT_ID --resource-group $IP_RG

Create an Public IP address and retrieve the IP:

az network public-ip create -g $IP_RG -n service-ip --dns-name demo-service-ip  --allocation-method Static

export PUBLIC_IP=$(az  network public-ip show -n service-ip -g $IP_RG --query ipAddress | sed 's/"//g')

Retrieve the cluster credentials and deploy the service:

az aks get-credentials -g $CLUSTER_RG -n cluster1

envsubst < service-ip-in-rg.yaml | kubectl apply -f -

We can check the status of the service with:

kubectl describe service my-service

After a few minutes we can see that the load balancer is created and IP address assigned to the service:

Name:                     my-service
Namespace:                default
Labels:                   <none>
Annotations:    {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"":"MyIPRG"},"name":"my-ser...
Selector:                 app=my-app
Type:                     LoadBalancer
IP:                       13.73.182.XX
LoadBalancer Ingress:     13.73.182.XX
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30512/TCP
Endpoints:      ,,
Session Affinity:         None
External Traffic Policy:  Cluster
  Type     Reason                      Age              From                Message
  ----     ------                      ----             ----                -------
  Warning  CreatingLoadBalancerFailed  6m (x3 over 7m)  service-controller  Error creating load balancer (will retry): failed to ensure load balancer for service default/my-service: network.PublicIPAddressesClient#List: Failure responding to
request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="AuthorizationFailed" Message="The client 'XXX' with object id 'XXX' does
not have authorization to perform action 'Microsoft.Network/publicIPAddresses/read' over scope '/subscriptions/XXX/resourceGroups/MyIPRG/providers/Microsoft.Network'."
  Normal   EnsuringLoadBalancer        6m (x4 over 7m)  service-controller  Ensuring load balancer
  Normal   EnsuredLoadBalancer         4m               service-controller  Ensured load balancer

We can now verify access to nginx using our newly created IP:


<!DOCTYPE html>
<title>Welcome to nginx!</title>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
<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=""></a>.<br/>
Commercial support is available at
<a href=""></a>.</p>

<p><em>Thank you for using nginx.</em></p>

1 Comment

  1. Sunil

    The external IP shows still pending while i list the services. How to do this in a custom cluster setup using few virtual machines in azure. Not AKS PAAS service. The machine not getting any public ips


Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.