Azure Function App CI/CD — Selenium, Docker, ACR & Azure Pipelines

Swapnil Jindal
5 min readOct 4, 2023

--

Learn how to deploy the Azure Function App built using the Python V2 programming model automating web parsing using Selenium to Azure Using Docker, ACRs & Azure Pipelines

This is in continuation of our previous tutorial where we successfully created the function app in Python and ran it locally to parse the data from Amazon.

Problem Statement

Azure Function App doesn’t allow Chrome and Selenium WebDrivers to be installed and used directly. Therefore, we will build a Docker image from the base Azure Function image, and pre-package it with our code, Google Chrome executable, and the Selenium Web Driver.

Updating Dockerfile

Open the Dockerfile and update it with the following code

# Select the base image to build on top of
FROM mcr.microsoft.com/azure-functions/python:4-python3.10

# Install essential packages
RUN apt-get update \
&& apt-get install -y \
build-essential \
cmake \
git \
wget \
unzip \
unixodbc-dev \
&& rm -rf /var/lib/apt/lists/*

# Install a specific version of Chrome - v114.0.5735.198-1 in this case.
RUN CHROME_VERSION=114.0.5735.198-1 && \
wget --no-check-certificate https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_VERSION}_amd64.deb && \
dpkg -i google-chrome-stable_${CHROME_VERSION}_amd64.deb; apt update; apt install -y -f; apt install -y xvfb;

# Install specific verions of the Chrome driver corresponding to the chrome version installed above
RUN BROWSER_MAJOR=$(google-chrome --version | sed 's/Google Chrome \([0-9]*\).*/\1/g') && \
wget https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${BROWSER_MAJOR} -O chrome_version && \
wget https://chromedriver.storage.googleapis.com/`cat chrome_version`/chromedriver_linux64.zip && \
unzip chromedriver_linux64.zip && \
mv chromedriver /usr/local/bin/ && \
DRIVER_MAJOR=$(chromedriver --version | sed 's/ChromeDriver \([0-9]*\).*/\1/g') && \
echo "chrome version: $BROWSER_MAJOR" && \
echo "chromedriver version: $DRIVER_MAJOR" && \
if [ $BROWSER_MAJOR != $DRIVER_MAJOR ]; then echo "VERSION MISMATCH"; exit 1; fi

ENV PATH="/usr/local/bin/chromedriver:${PATH}"

# Copy python code to image
COPY . /home/site/wwwroot

# Install packages in requirements.txt
RUN cd /home/site/wwwroot && \
pip install -r requirements.txt
  1. We’re pulling the base image of Azure Functions that can run Python
  2. Installing v114.0.5735.198–1 of Google Chrome. You can search for the available versions of Google Chrome from here. At the time of writing this article, no Chrome driver was available for Google Chrome major version > 114. Therefore, I have selected 114 as the major version of Google Chrome to be installed.
  3. Installing Chrome Driver specific to this Google Chrome version
  4. Copying the code in the current directory to /home/site/wwwroot folder
  5. Installing the Python libraries as listed in requirements.txt

Creating Azure Container Registry (ACR)

Head over to https://portal.azure.com > Container registries and Create a new Container registry.

Go to Review + create and click Create

Go to the newly created resource > Access Keys, and click the checkbox “Admin User” to allow logging in through username & password.

Copy your ACR login server name, username, and password from here. We’ll use it in the next step.

Deploying to ACR using Shell Script

We’ll build the Dockerfile & deploy the built image to the container registry we created above.

#!/bin/bash
acr_id="acr_login_server"
image_name="az-fn-py" # could be any image name
docker login "$acr_id" -u "{{acr_username}}" -p "{{acr_password}}"
docker build --tag "$acr_id/$image_name" .
docker push "$acr_id/$image_name:latest" # you can use any tag name. I've used latest

Save this as build_docker.sh, and run this file from terminal

sh ./build_docker.sh

Wait for the process to complete. Once completed, head over to your ACR, and click Repositories. You’ll see your newly created az-fn-py repository over there.

Connecting to Azure Functions App

Again go to https://portal.azure.com > Function App and click Create.

Fill in the necessary details and choose Container Image as the deployment method.

Once created, head over to the Function App and open Deployment Center.

Select Azure Container Registry connection, and select the registry name, image, and tag as previously created. Also, switch ON the Continuous Deployment to deploy as soon as a new manifest for the same image:tag is available. Click Save.

Head over to the Deployment Logs in the Deployment Center to see the image being deployed.

Once the deployment is complete, go to the Overview section of the Function App and you’ll see the Function “SearchAmazonProducts” as available.

Try hitting the page {{FunctionAppBaseUrl}}/api/SearchAmazonProducts?search=toys&pages=1 and it should work.

CI/CD Using Azure Pipelines

Add a new file to your project named azure-pipelines.yml and add the following code

trigger:
- main

resources:
- repo: self

variables:
# Container registry service connection established during pipeline creation
dockerRegistryServiceConnection: "{{ServiceConnectionIdToDocker}}"
imageRepository: "az-fn-py"
containerRegistry: "mediumtutsacr.azurecr.io"
dockerfilePath: "$(Build.SourcesDirectory)/Dockerfile"
tag: "latest"

# Agent VM image name
vmImageName: "ubuntu-latest"

stages:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)

Where {{ServiceConnectionIdToDocker}} is the Service Connection you create by going to Azure Pipelines > Settings > Service Connections, and adding a new Docker Registry Service Connection.

Commit your code to a git repo, and connect the repo to a new Azure Pipeline.

When creating a new pipeline, make sure to select the “Existing Azure Pipeline YAML file” option and choose the .yml file we created in the previous step.

The pipeline would run whenever new code is pushed to the main branch, docker image is built with the latest tag and uploaded to the ACR repository. As soon as a new build is available, the Azure Functions App will pull it and deploy it for use.

That’s all, thanks!

--

--