The Azure Container App team released a new command to simplify the deployment process. With az containerapp up, you can deploy your workload to Azure Container Apps (ACA) with one command. This article demonstrates how to use az containerapp up and how you can tailor its behavior to meet your requirements.



What does az containerapp up actually do?

You can think of az containerapp up as a meta-command that will spin up all necessary resources to take your application source and run it in ACA. Under the covers, it does the following

  • Create a new Resource Group in Azure
  • Create a new Azure Container Registry (ACR)
  • Create a new Azure Log Analytics Workspace (LAW)
  • Create a new Azure Container App Environment
  • It builds a container image using your local Dockerfile (It does not build on your local machine - it uses ACR Container Builds hoods - that means there is no need to have Docker installed locally)
  • It deploys your application to ACA
  • If your Dockerfile exposes a port (EXPOSE <PORT>), it will enable the ingress and route requests to that particular port

It sounds like a perfect command to speed up your inner loop performance! So, let’s give it a spin!

Install the containerapp extension for Azure CLI

We have to install the latest (0.3.2) version of the containerapp extension for Azure CLI:

az extension add --name containerapp --upgrade 

Once installation (or upgrade) has finished, you should verify the existence of az containerapp up by executing az containerapp -h | grep up:

az containerapp -h | grep up 

  up      : Create or update a container app as well as any associated resources (ACR,
          resource group, container apps environment, Github Actions, etc.).

Awesome, now we’re good to go. For demonstration purposes, let’s take a simple NGINX web server:

# make a new directory
mkdir sample && cd sample

# make a simple Dockerfile
echo << EOF > Dockerfile
FROM nginx:alpine
EXPOSE 80
EOF

All-in-one deployment to Azure Container Apps

First, let’s be naive and invoke az containerapp up:

# invoke az containerapp up
az containerapp up -n up-sample --source .

Command group 'containerapp' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Adding external ingress port 80 based on dockerfile expose.
Using resource group 'rg-aca-up-sample'
Using ContainerAppEnvironment 'env-jwuickydofm34' in resource group rg-aca-up-sample
Creating Azure Container Registry ca1951440480acr in resource group rg-aca-up-sample
2022/04/29 06:41:22 Downloading source code...
2022/04/29 06:41:23 Finished downloading source code
2022/04/29 06:41:23 Using acb_vol_f60ec473-6d12-4d0b-9fbe-ae578137dd75 as the home volume
2022/04/29 06:41:23 Setting up Docker configuration...
2022/04/29 06:41:24 Successfully set up Docker configuration
2022/04/29 06:41:24 Logging in to registry: ca1951440480acr.azurecr.io
2022/04/29 06:41:25 Successfully logged into ca1951440480acr.azurecr.io
2022/04/29 06:41:25 Executing step ID: build. Timeout(sec): 28800, Working directory: '', Network: ''
2022/04/29 06:41:25 Scanning for dependencies...
2022/04/29 06:41:25 Successfully scanned dependencies
2022/04/29 06:41:25 Launching container with name: build
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM nginx:alpine
alpine: Pulling from library/nginx
df9b9388f04a: Already exists
5867cba5fcbd: Pulling fs layer
4b639e65cb3b: Pulling fs layer
061ed9e2b976: Pulling fs layer
bc19f3e8eeb1: Pulling fs layer
4071be97c256: Pulling fs layer
bc19f3e8eeb1: Waiting
4071be97c256: Waiting
4b639e65cb3b: Verifying Checksum
4b639e65cb3b: Download complete
061ed9e2b976: Verifying Checksum
061ed9e2b976: Download complete
4071be97c256: Verifying Checksum
4071be97c256: Download complete
bc19f3e8eeb1: Verifying Checksum
bc19f3e8eeb1: Download complete
5867cba5fcbd: Verifying Checksum
5867cba5fcbd: Download complete
5867cba5fcbd: Pull complete
4b639e65cb3b: Pull complete
061ed9e2b976: Pull complete
bc19f3e8eeb1: Pull complete
4071be97c256: Pull complete
Digest: sha256:5a0df7fb7c8c03e4158ae9974bfbd6a15da2bdfdeded4fb694367ec812325d31
Status: Downloaded newer image for nginx:alpine
 ---> 51696c87e77e
Step 2/2 : EXPOSE 80
 ---> Running in d2aad6fe0b5d
Removing intermediate container d2aad6fe0b5d
 ---> b825bc0bd477
Successfully built b825bc0bd477
Successfully tagged ca1951440480acr.azurecr.io/up-sample:20220429084120103489
2022/04/29 06:41:28 Successfully executed container: build
2022/04/29 06:41:28 Executing step ID: push. Timeout(sec): 3600, Working directory: '', Network: ''
2022/04/29 06:41:28 Pushing image: ca1951440480acr.azurecr.io/up-sample:20220429084120103489, attempt 1
The push refers to repository [ca1951440480acr.azurecr.io/up-sample]
b991c80c3ef2: Preparing
8df6b63c60d4: Preparing
d63b53686463: Preparing
c0b09410617a: Preparing
be9057e6dae4: Preparing
4fc242d58285: Preparing
4fc242d58285: Waiting
b991c80c3ef2: Pushed
c0b09410617a: Pushed
8df6b63c60d4: Pushed
d63b53686463: Pushed
4fc242d58285: Pushed
be9057e6dae4: Pushed
20220429084120103489: digest: sha256:533756ef41e69ee3a6a04e37fde4662725709ab192f6de61958700eca090af25 size: 1568
2022/04/29 06:41:37 Successfully pushed image: ca1951440480acr.azurecr.io/up-sample:20220429084120103489
2022/04/29 06:41:37 Step ID: build marked as successful (elapsed time in seconds: 2.885663)
2022/04/29 06:41:37 Populating digests for step ID: build...
2022/04/29 06:41:39 Successfully populated digests for step ID: build
2022/04/29 06:41:39 Step ID: push marked as successful (elapsed time in seconds: 9.534231)
2022/04/29 06:41:39 The following dependencies were found:
2022/04/29 06:41:39
- image:
  registry: ca1951440480acr.azurecr.io
  repository: up-sample
  tag: "20220429084120103489"
  digest: sha256:533756ef41e69ee3a6a04e37fde4662725709ab192f6de61958700eca090af25
 runtime-dependency:
  registry: registry.hub.docker.com
  repository: library/nginx
  tag: alpine
  digest: sha256:5a0df7fb7c8c03e4158ae9974bfbd6a15da2bdfdeded4fb694367ec812325d31
 git: {}


Run ID: ca1 was successful after 17s
Creating Containerapp up-sample in resource group rg-aca-up-sample
/ Running ..
Your container app up-sample has been created and deployed! Congrats!

Browse your container app at: http://up-sample.politecoast-4e06302b.northeurope.azurecontainerapps.io

Stream logs for your container with: az containerapp logs show -n up-sample -g rg-aca-up-sample

See full output using: az containerapp show -n up-sample -g rg-aca-up-sample

It took less than a minute to take my source code (obviously the most straightforward web server ever :D), spin everything up in the cloud, containerize it, and deploy it.

The logs also print the FQDN of the container app. When you hit the FQDN, you will see the NGINX welcome page.

NGINX running in Azure Container Apps in less than 2 minutes

That’s awesome!

However, we often need tailored behavior in this workflow. We want to reuse existing resources to optimize the cloud footprint and your cloud spending. That said, let’s see what we can do

Tailored Deployments (aka reusing existing dependencies)

When you look at the available flags and arguments that az containerapp up offers, you’ll immediately recognize that we can customize the workflow. We can select the desired Azure region using --location (or -l) (keep in mind that ACA is not available in all Azure Regions). We can deploy with az containerapp up to an existing resource group by providing the name of the desired resource group using --resource-group (or -g). Besides those basic customizations, we can also reuse existing cloud resources to optimize and integrate with existing cloud deployments.

How to use existing Azure Container Registry with az containerapp up

Reusing an existing ACR instance was the first thing that came into my mind when I saw az containerapp up.

Fortunately, the team thought of that too and provided us the --registry-server --registry-username and --registry-password arguments. We can use any existing ACR instance and authenticate using existing ACR credentials. (Quick side-note: Please do not enable the ACR Admin account for this. Consider using scopes and tokens to create tailored authentication and authorization). For example, let’s redeploy the previous sample using an existing ACR instance and authorize using a custom ACR token which is authorized to push new container images:

az containerapp up --name up-sample-2 --source . --registry-server thans.azurecr.io --registry-user thans --registry-password $ACR_TOKEN

# Snipped
Successfully tagged thans.azurecr.io/up-sample-2:20220429122633470453
# Snipped

I’ve removed the entire output from az containerapp up here. However, the important part is shown. We can see that the existing ACR instance is used to build and store the container image 🎉.

How to use existing Azure Log Analytics Workspace with az containerapp up

Typically, we want to have a single Azure Log Analytics Workspace (LAW) used by all cloud(-native) application resources. Sending all logs, metrics, and traces to a single LAW simplifies troubleshooting, querying, and visualizing KPIs of the overall application.

We can use --logs-workspace-id and --logs-workspace-key to have az containerapp up linking the Container App Environment to an existing Log Analytics Workspace.

How to deploy to an existing Container App Environment with az containerapp up

Container Apps are deployed to Container App Environments. Suppose your application consists of more than just a single container (which it will probably do). In that case, you can also instruct az containerapp up to deploy the application to an existing Container App Environment using the --environment argument. You can either provide the name or the unique Azure resource identifier and let the command deploy your container into the desired Container App Environment.

Further customizations

Consider browsing through all the arguments offered by az containerapp up to see how you can customize the deployment process to fit your needs. Batteries are included to configure other things like pulling the source code from GitHub instead of using a local source context.

My take on using az containerapp up for continuous deployment

Although az containerapp up looks like a great fit for automating all the things in Azure Container Apps - also when deploying using services like Azure DevOps or GitHub Actions - I would not recommend going that direction. I see az containerapp up as a great tool to improve the inner-loop performance. Developers can use it to quickly get their apps up and running for demonstration or testing purposes.

Everything that goes beyond that should use proper Infrastructure-as-Code (IAC) tooling like Project Bicep or Terraform (once Terraform supports Azure Container Apps)

What we have covered today

  • 👋🏻 Welcomed az containerapp up
  • ⬇️ Installed necessary Azure CLI extension
  • 🚀 Deployed a sample application to Azure Container Apps using az containerapp up
  • ⚙️ Learned and used customizations when deploying apps with az containerapp up

Recap

We need more commands like containerapp up. These improve the inner-loop performance and help developers to find proper cloud infrastructure/services for their needs.Being able to customize the az containerapp up behavior according to individual needs is excellent and will be the key to making it a success. That said, give it a spin. Take those three minutes and get something up and running in Azure Container Apps, today!