../../_images/azure_aci.png

Azure Container Instances

Prerequisites

Azure Container Instances is a quick way to deploy your container into Docker host within Azure, without having to provision the underlying servers first (VM + OS).

  • Azure Subscription

  • Azure Service Principal Account

CLI tools

The az command line tool will be used to programmatically access your Azure subscription. To install the CLI tool, follow the link below and choose the correct operating sytem:

Obtain the latest ARM template

The ARM template establishes some default values and general configuration for the ESP deployment. You will leave this template intact and use the parameters file (created in the next step) to fill in your specific details and credentials. The latest ARM template is as follows:

@description('Name (default: l7esp-example)')
param containerName string = 'l7esp-example'

@description('Azure location to deploy containers (default: Azure Resource Group location)')
param azureLocation string = resourceGroup().location

@description('L7|ESP software license (optional; JSON string)')
param appLicense string = ''

@description('L7|ESP admin password (required; initial password)')
param appPassword string = 'changeme'

@description('L7|ESP web UI port (default: 8002)')
param appPortHTTP int = 8002

@description('Container Image (e.g. acme/l7esp:3.0.0)')
param containerImage string = ''

@description('Container CPU cores (default: 2 vCPU)')
param containerCPU int = 2

@description('Container Memory (default: 6GB RAM)')
param containerMemory int = 6

@description('Container Restart Policy (default: Never)')
@allowed([
  'Always'
  'Never'
  'OnFailure'
])
param containerRestartPolicy string = 'Never'

@description('Container Registry URL (default: docker.io)')
param registryURL string = ''

@description('Container Registry Username (e.g. Docker Hub user)')
param registryUsername string = ''

@description('Container Registry Password (e.g. Docker Hub app password)')
param registryPassword string = ''

resource container_instance 'Microsoft.ContainerInstance/containerGroups@2021-09-01' = {
  name: containerName
  location: azureLocation
  properties: {
    containers: [
      {
        name: containerName
        properties: {
          image: containerImage
          ports: [
            {
              port: appPortHTTP
              protocol: 'TCP'
            }
          ]
          environmentVariables: [
            {
              secureValue: appPassword
              name: 'L7ESP_PASSWORD'
            }
            {
              secureValue: appLicense
              name: 'L7ESP_LICENSE'
            }
          ]
          resources: {
            requests: {
              cpu: containerCPU
              memoryInGB: containerMemory
            }
          }
        }
      }
    ]
    osType: 'Linux'
    restartPolicy: containerRestartPolicy
    ipAddress: {
      type: 'Public'
      ports: [
        {
          port: appPortHTTP
          protocol: 'TCP'
        }
      ]
    }
    imageRegistryCredentials: [
      {
        password: registryPassword
        server: registryURL
        username: registryUsername
      }
    ]
  }
}

output containerIPv4Address string = container_instance.properties.ipAddress.ip
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.6.18.56646",
      "templateHash": "17739852969827724894"
    }
  },
  "parameters": {
    "containerName": {
      "type": "string",
      "defaultValue": "l7esp-example",
      "metadata": {
        "description": "Name (default: l7esp-example)"
      }
    },
    "azureLocation": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Azure location to deploy containers (default: Azure Resource Group location)"
      }
    },
    "appLicense": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "L7|ESP software license (optional; JSON string)"
      }
    },
    "appPassword": {
      "type": "string",
      "defaultValue": "changeme",
      "metadata": {
        "description": "L7|ESP admin password (required; initial password)"
      }
    },
    "appPortHTTP": {
      "type": "int",
      "defaultValue": 8002,
      "metadata": {
        "description": "L7|ESP web UI port (default: 8002)"
      }
    },
    "containerImage": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Container Image (e.g. acme/l7esp:3.0.0)"
      }
    },
    "containerCPU": {
      "type": "int",
      "defaultValue": 2,
      "metadata": {
        "description": "Container CPU cores (default: 2 vCPU)"
      }
    },
    "containerMemory": {
      "type": "int",
      "defaultValue": 6,
      "metadata": {
        "description": "Container Memory (default: 6GB RAM)"
      }
    },
    "containerRestartPolicy": {
      "type": "string",
      "defaultValue": "Never",
      "allowedValues": [
        "Always",
        "Never",
        "OnFailure"
      ],
      "metadata": {
        "description": "Container Restart Policy (default: Never)"
      }
    },
    "registryURL": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Container Registry URL (default: docker.io)"
      }
    },
    "registryUsername": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Container Registry Username (e.g. Docker Hub user)"
      }
    },
    "registryPassword": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Container Registry Password (e.g. Docker Hub app password)"
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.ContainerInstance/containerGroups",
      "apiVersion": "2021-09-01",
      "name": "[parameters('containerName')]",
      "location": "[parameters('azureLocation')]",
      "properties": {
        "containers": [
          {
            "name": "[parameters('containerName')]",
            "properties": {
              "image": "[parameters('containerImage')]",
              "ports": [
                {
                  "port": "[parameters('appPortHTTP')]",
                  "protocol": "TCP"
                }
              ],
              "environmentVariables": [
                {
                  "secureValue": "[parameters('appPassword')]",
                  "name": "L7ESP_PASSWORD"
                },
                {
                  "secureValue": "[parameters('appLicense')]",
                  "name": "L7ESP_LICENSE"
                }
              ],
              "resources": {
                "requests": {
                  "cpu": "[parameters('containerCPU')]",
                  "memoryInGB": "[parameters('containerMemory')]"
                }
              }
            }
          }
        ],
        "osType": "Linux",
        "restartPolicy": "[parameters('containerRestartPolicy')]",
        "ipAddress": {
          "type": "Public",
          "ports": [
            {
              "port": "[parameters('appPortHTTP')]",
              "protocol": "TCP"
            }
          ]
        },
        "imageRegistryCredentials": [
          {
            "password": "[parameters('registryPassword')]",
            "server": "[parameters('registryURL')]",
            "username": "[parameters('registryUsername')]"
          }
        ]
      }
    }
  ],
  "outputs": {
    "containerIPv4Address": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups', parameters('containerName'))).ipAddress.ip]"
    }
  }
}

You can use either the JSON or the Bicep version of the file, but Bicep is a bit easier to read and edit, and it’s the Azure-native format. We’ll assume you saved the file in your current directory as arm_template.bison.

Create a parameters file with your specific customization

Save this file as parameters.json in your current directory.

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appLicense": {
      "value": ""
    },
    "appPassword": {
      "value": ""
    },
    "containerImage": {
      "value": ""
    },
    "appPortHTTP": {
      "value": 8002
    },
    "containerCPU": {
      "value": 2
    },
    "registryUsername": {
      "value": ""
    },
    "registryPassword": {
      "value": ""
    },
    "registryURL": {
      "value": ""
    },
    "containerMemory": {
      "value": 6
    }
  }
}

Edit this file to set important values for your instance:

  • containerName : This name will identify your container in Azure. For this example we will use ‘acme’. (default: l7esp-example)

  • appPassword : The admin password on the ESP instance that you are deploying (required; initial password)

  • appLicense : The text of the entire JSON object representing the ESP license key. The object should be wrapped in single quotes. (required; JSON string)

  • containerImage: The docker image that your deployed container will be based on. Example: docker.io/acme/l7esp:3.0.0

  • registryURL : The hostname of the Docker registry where your image is hosted. The default is ‘docker.io’ for Docker Hub, but may be located somewhere in Azure like ‘examplecompany.azurecr.io’ (default: docker.io)

  • registryUsername : The login name for the container registry (required)

  • registryPassword : The password for the container registry user (required)

Optional parameters that you may want to change, depending on your specific deployment:

  • containerCPU : Container CPU cores (default: 2 vCPU)

  • containerMemory : Container Memory (default: 6GB RAM)

  • containerRestartPolicy - Container Restart Policy (default: Never)

  • azureLocation - Azure location to deploy containers (default: Azure Resource Group location)

Login to Azure

$ az login

This command will open a web browser, where you can authenticate to Azure using the credentials for a user with the ability to perform deployments. This brief command should be sufficient for most cases, but if you are using a Service Principal or Tenant, your command may look like this:

$ az login \
      --service-principal \
      --username <service-principal-id> \
      --password <service-principal-password> \
      --tenant <tenant-id>

Deploy a new Resource Group

You may already have a Resource Group created for this deployment, but if not, create one now: az group create --name example-resource-group --location "Central US"

Run ARM template pipeline to create AKS

Now run the deployment command:

$ az deployment group create --resource-group example-resource-group --template-file ./arm_template.bicep --parameters deployment.json --verbose

If you are updating an existing deployment, you may want to add the flag --rollback-on-error to this command. However, this flag will cause a new deployment to fail.

Validate Resource Creation

After about 3 minutes, the command will complete and you should see the new container running in the Azure portal.

Navigate to Container Instances and verify that the L7|ESP container instance was created and that it ends up in the Running state:

../../_images/acicontainergroup.png

ESP will not be available until the build process has completed (about 15 minutes). You can observe the resource usage on the Container Instances detail page. When the memory and CPU usage graphs stabilize and level off with a solid line, you will be able to access the application via the public IP address displayed in the Azure Portal – http://<public IP address>:8002