Monday, December 4, 2017

Azure Container Instance (4): Integrating with Logic App


Azure Logic Apps are very useful tools to automate workflows and business processes. Azure Container Instances have been integrated with Logic Apps, and you have more flexibility to integrate systems and services for your organization with the integration.

This blog is going to show you how to utilize Azure Container Instances with Logic App. A container group is created when there is a new RSS feed and it would to uploaded to Azure file storage automatically. The high-level logic app workflow looks like:


Let’s monitor the RSS feed at http://feeds.reuters.com/reuters/topNews, and the workflow will be trigger when a new feed is available. The trigger looks like:


And then let’s create an action to create container group. Firstly, we set the subscription Id, resource group, container group name, and location:


 And then we define a container inside the container group. The following is an example:


Finally, we have more settings for the container group, as shown below:


An Azure file share is mounted as a volume in the container.  When a new RSS feed is available, its title will be echoed and appended into the file feed.txt of the mounted volume. We can read all titles of the feeds via Azure portal.

In your scenarios you may do more interesting works with containers, such analyzing the news, getting statistical information like word frequency, or sending you an email if the news is about a company you are interested in. You are free to do whatever you want as long as you define the container.

Friday, December 1, 2017

Azure Container Instance (3): Introducing ACI gitRepo Volume

A new type of volume named gitRepo volume was supported in Azure Container Instance since version 2017-12-01-preview.

What is gitRepo volume?

A gitRepo volume mounts an empty directory and clones a git repository into it for your container group to use.

When to use gitRepo volume?

The gitRepo is very useful when we are using GitHub as the source version control tool and we’d like to have containers to work on the source code, such as build and deploy automatically.

How to use gitRepo volume?

Firstly, a gitRepo object is added into the volumes array of the container group, and then a volume mount is added into the volumeMounts of a container. The name of the volume mount should match the name of the volume.

The following is an example container group definition in JSON:

{
  "properties": {
    "containers": [
      {
        "name": "demo1",
        "properties": {
          "command": [
            "bin/bash",
            "-c",
            "cp -R /mnt/gitrepos /mnt/azurefile && while sleep 50000; do echo sleep; done"
          ],
          "image": "nginx",
          "ports": [
            {
              "port": 80
            }
          ],
          "resources": {
            "requests": {
              "cpu": 1,
              "memoryInGb": 1.5
            }
          },
          "volumeMounts": [
            {
              "name": "gitrepo",
              "mountPath": "/mnt/gitrepos",
              "readOnly": false
            },
            {
              "name": "azurefile",
              "mountPath": "/mnt/azurefile",
              "readOnly": false
            }
          ]
        }
      }
    ],
    "volumes": [
      {
        "name": "gitrepo",
        "gitRepo": {
          "repository": "https://github.com/Azure-Samples/aci-helloworld.git"
        }
      },
      {
        "name": "azurefile",
        "azureFile": {
          "shareName": "<YourAzureFileShare>",
          "storageAccountName": "<YourAzureStorageAccountName>",
          "storageAccountKey": "<YouAzureStorageAccountKey>"
        }
      }
    ],
    "osType": "Linux",
    "ipAddress": {
      "ports": [
        {
          "protocol": "TCP",
          "port": 80
        }
      ],
      "type": "Public"
    }
  },
  "location": "westus"
}

In the JSON definition above, the source code files in GitHub reprository https://github.com/Azure-Samples/aci-helloworld are cloned to the path “/mnt/gitrepos”. Since we copy the directory “/mnt/gitrepos” to “/mnt/azurefile”, which is the mounted path of Azure file share. You may find all source code in the GitHub are uploaded to your Azure file storage if you check on your Azure portal.

The sample above just uploads source code in GitHub to Azure file storage. In your scenario you may do anything on the GitHub source code as you like, such as building and deploying code automatically.

Besides property “repository”, a gitRepo object can also have two properties: One is “directory”, which is target directory name. It must not contain or start with '..'.  If '.' is supplied, the volume directory will be the git repository.  Otherwise, if specified the volume will contain the git repository in the subdirectory with the given name. The other is “revision”, which is the commit hash for the specified revision.

Azure Container Instance (2): Introducing ACI Secret Volumes

A new type of volume named secret volume was supported in Azure Container Instance since version 2017-12-01-preview.

What is secret volume?

A secret volume is used to pass sensitive information, such as passwords and certificates, to container groups. You can store secrets and mount them as files for use by containers.

How to use secret volume?

First a secret object is added into the volumes array of the container group, and then the volume mount is added into the volumeMounts of a container. The name of the volume mount should match the name of the volume.

The following is an ARM template of a container group with a secret volume:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "containergroupname": {
      "type": "string",
      "metadata": {
        "description": "Name for the container group"
      }
    },
    "containername": {
      "type": "string",
      "metadata": {
        "description": "Name for the container"
      }
    },
    "volumename": {
      "type": "string",
      "metadata": {
        "description": "Name for the secret volume"
      }
    },
    "clientCertificate": {
      "metadata": {
        "description": "The base64 client certificate used to communicate with the master"
      },
      "type": "string"
    },
    "clientPrivateKey": {
      "metadata": {
        "description": "The base64 client private key used to communicate with the master"
      },
      "type": "securestring"
    },
    "port": {
      "type": "string",
      "metadata": {
        "description": "Port to open on the container and the public IP address."
      },
      "defaultValue": "80"
    },
    "cpuCores": {
      "type": "string",
      "metadata": {
        "description": "The number of CPU cores to allocate to the container."
      },
      "defaultValue": "1.0"
    },
    "memoryInGb": {
      "type": "string",
      "metadata": {
        "description": "The amount of memory to allocate to the container in gigabytes."
      },
      "defaultValue": "1.5"
    }
  },
  "variables": {},
  "resources": [
    {
      "name": "[parameters('containergroupname')]",
      "type": "Microsoft.ContainerInstance/containerGroups",
      "apiVersion": "2017-12-01-preview",
      "location": "[resourceGroup().location]",
      "dependsOn": [],
      "properties": {
        "containers": [
          {
            "name": "[parameters('containername')]",
            "properties": {
              "command": [
                "bin/bash",
                "-c",
                "cp /mnt/secrets/clientCertificate /mnt/azurefile && cp /mnt/secrets/clientPrivateKey /mnt/azurefile && while sleep 50000; do echo sleep; done"
              ],
              "image": "nginx",
              "ports": [
                {
                  "port": "[parameters('port')]"
                }
              ],
              "resources": {
                "requests": {
                  "cpu": "[parameters('cpuCores')]",
                  "memoryInGb": "[parameters('memoryInGb')]"
                }
              },
              "volumeMounts": [
                {
                  "name": "[parameters('volumename')]",
                  "mountPath": "/mnt/secrets",
                  "readOnly": false
                },
                {
                  "name": "azurefile",
                  "mountPath": "/mnt/azurefile",
                  "readOnly": false
                }
              ]
            }
          }
        ],
        "osType": "Linux",
        "ipAddress": {
          "type": "Public",
          "ports": [
            {
              "protocol": "tcp",
              "port": "[parameters('port')]"
            }
          ]
        },
        "volumes": [
          {
            "name": "[parameters('volumename')]",
            "secret": {
              "clientCertificate": "[parameters('clientCertificate')]",
              "clientPrivateKey": "[parameters('clientPrivateKey')]"
            }
          },
          {
            "name": "azurefile",
            "azureFile": {
              "shareName": "<YourAzureFileShare>",
              "storageAccountName": "<YourAzureStorageAccountName>",
              "storageAccountKey": "<YourAzureStorageAccountKey>"
            }
          }
        ]
      }
    }
  ],
  "outputs": {
    "containerIPv4Address": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups/', parameters('containergroupname'))).ipAddress.ip]"
    }
  }
}

And the parameters of template look like:

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "containergroupname": {
      "value": "GEN-UNIQUE"
    },
    "containername": {
      "value": "GEN-UNIQUE"
    },
    "volumename": {
      "value": "GEN-UNIQUE"
    },
    "clientCertificate": {
      "reference": {
        "keyVault": {
          "id": "GEN-KEYVAULT-RESOURCE-ID"
        },
        "secretName": "GEN-KEYVAULT-SSL-SECRET-NAME"
      }
    },
    "clientPrivateKey": {
      "reference": {
        "keyVault": {
          "id": "GEN-KEYVAULT-RESOURCE-ID"
        },
        "secretName": "GEN-KEYVAULT-SSL-SECRET-NAME"
      }
    }
  }
}

The secret in the sample above has two set of key-value pairs, one for client certificate and the other for client private key. The certificate and private key are originally in Azure key vault. The certificate is mounted as a file /mnt/secrets/clientCertificate in the container, and the private key is mounted as a file /mnt/secrets/clientPrivateKey.

In the sample, the two files for the certificate and key are copied to Azure file share, so we can see them in Azure portal. In the real development scenarios, we can do anything we like with the certificate and private key, such as setting SSL connections. 

AKS (1) - Five seconds latency when resolving DNS

We intermittently meet 5s latencies in an AKS clusters with CNI when it’s resolving DNS. This article is to summarize what we have learned...