Skip to content

Release 1.0.0

Release 1.0.0 #1

name: CD Prod Pipeline
on:
pull_request:
types: [closed]
branches:
- main
jobs:
setup-env-job:
if: ${{ github.repository != 'Azure/llmops-project-template' }} &&
github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'release/')
runs-on: ubuntu-latest
environment: prod
outputs:
AZURE_APP_SERVICE_NAME: ${{ steps.config-env.outputs.AZURE_APP_SERVICE_NAME }}
AZURE_APP_SERVICE_PLAN_NAME: ${{ steps.config-env.outputs.AZURE_APP_SERVICE_PLAN_NAME }}
AZURE_CONTAINER_REGISTRY_NAME: ${{ steps.config-env.outputs.AZURE_CONTAINER_REGISTRY_NAME }}
AZURE_CONTAINER_REPOSITORY_NAME: ${{ steps.config-env.outputs.AZURE_CONTAINER_REPOSITORY_NAME }}
AZURE_LOCATION: ${{ steps.config-env.outputs.AZURE_LOCATION }}
AZURE_RESOURCE_GROUP: ${{ steps.config-env.outputs.AZURE_RESOURCE_GROUP }}
AZUREAI_RESOURCE_GROUP: ${{ steps.config-env.outputs.AZURE_RESOURCE_GROUP }}
AZURE_SUBSCRIPTION_ID: ${{ steps.config-env.outputs.AZURE_SUBSCRIPTION_ID }}
steps:
- uses: actions/checkout@v4
- name: Provision prod environment
uses: ./.github/actions/config-env
id: config-env
with:
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
MANUAL_PROVISIONING: ${{ vars.MANUAL_PROVISIONING }}
AZURE_DEPLOY_APP_SERVICE: true
env:
AZUREAI_PROJECT_NAME: ${{ vars.AZUREAI_PROJECT_NAME }}
AZURE_APP_SERVICE_NAME: ${{ vars.AZURE_APP_SERVICE_NAME }}
AZURE_APP_SERVICE_PLAN_NAME: ${{ vars.AZURE_APP_SERVICE_PLAN_NAME }}
AZURE_CONTAINER_REGISTRY_NAME: ${{ vars.AZURE_CONTAINER_REGISTRY_NAME }}
AZURE_CONTAINER_REPOSITORY_NAME: ${{ vars.AZURE_CONTAINER_REPOSITORY_NAME }}
AZURE_OPENAI_API_VERSION: ${{ vars.AZURE_OPENAI_API_VERSION }}
AZURE_OPENAI_CHAT_DEPLOYMENT: ${{ vars.AZURE_OPENAI_CHAT_DEPLOYMENT }}
AZURE_OPENAI_EMBEDDING_DEPLOYMENT: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT }}
AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_MODEL }}
AZURE_OPENAI_ENDPOINT: ${{ vars.AZURE_OPENAI_ENDPOINT }}
AZURE_OPENAI_NAME: ${{ vars.AZURE_OPENAI_NAME }}
AZURE_RESOURCE_GROUP: ${{ vars.AZURE_RESOURCE_GROUP }}
AZUREAI_RESOURCE_GROUP: ${{ vars.AZURE_RESOURCE_GROUP }}
AZURE_SEARCH_ENDPOINT: ${{ vars.AZURE_SEARCH_ENDPOINT }}
LOAD_AZURE_SEARCH_SAMPLE_DATA: ${{ vars.LOAD_AZURE_SEARCH_SAMPLE_DATA }}
AZURE_SEARCH_NAME: ${{ vars.AZURE_SEARCH_NAME }}
PROMPTFLOW_SERVING_ENGINE: ${{ vars.PROMPTFLOW_SERVING_ENGINE }}
PROMPTFLOW_WORKER_NUM: ${{ vars.PROMPTFLOW_WORKER_NUM }}
AZURE_PRINCIPAL_ID: ${{ vars.AZURE_PRINCIPAL_ID }}
AZUREAI_HUB_NAME: ${{ vars.AZUREAI_HUB_NAME }}
AZURE_APP_INSIGHTS_NAME: ${{ vars.AZURE_APP_INSIGHTS_NAME }}
AZURE_KEY_VAULT_NAME: ${{ vars.AZURE_KEY_VAULT_NAME }}
AZURE_LOG_ANALYTICS_NAME: ${{ vars.AZURE_LOG_ANALYTICS_NAME }}
AZURE_STORAGE_ACCOUNT_NAME: ${{ vars.AZURE_STORAGE_ACCOUNT_NAME }}
integration-testing:
if: ${{ github.repository != 'Azure/llmops-project-template' }}
runs-on: ubuntu-latest
environment: prod
needs: [setup-env-job]
steps:
- name: Integration Tests
run: |
echo "Run PROD Integration Tests"
get-source-acr-and-repository:
needs: [setup-env-job, integration-testing]
runs-on: ubuntu-latest
environment: qa
env:
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
AZURE_DEV_COLLECT_TELEMETRY: no
outputs:
SOURCE_REGISTRY: ${{ steps.get-vars.outputs.SOURCE_REGISTRY }}
steps:
- uses: actions/checkout@v4
- name: Install Azure Developer CLI
uses: Azure/[email protected]
- name: azd Login
shell: bash
run: |
info=$(echo $AZURE_CREDENTIALS | jq -r '.')
echo "::add-mask::$(echo $info | jq -r '.clientSecret')"
azd auth login \
--client-id "$(echo $info | jq -r '.clientId')" \
--client-secret "$(echo $info | jq -r '.clientSecret')" \
--tenant-id "$(echo $info | jq -r '.tenantId')"
- name: Get source repo vars
id: get-vars
shell: bash
run: |
echo "AZURE_SUBSCRIPTION_ID=$AZURE_SUBSCRIPTION_ID"
echo "AZURE_LOCATION=$AZURE_LOCATION"
echo "azd init -e $AZURE_ENV_NAME -l $AZURE_LOCATION -s $AZURE_SUBSCRIPTION_ID"
azd init -e $AZURE_ENV_NAME -l $AZURE_LOCATION -s $AZURE_SUBSCRIPTION_ID
# Run azd env refresh and capture last deployment outputs
echo "πŸ”Ά | Run azd env refresh and capture outputs"
azd env refresh -e "$AZURE_ENV_NAME"
echo "πŸ”Ά | Get $AZURE_ENV_NAME environment variables"
# Get environment variable from the last deployment
AZURE_CONTAINER_REGISTRY_NAME=$(azd env get-values -e $AZURE_ENV_NAME | grep AZURE_CONTAINER_REGISTRY_NAME | cut -d'=' -f2 | tr -d '"' || true)
echo "SOURCE_REGISTRY=$AZURE_CONTAINER_REGISTRY_NAME" >> "$GITHUB_OUTPUT"
echo "SOURCE_REGISTRY=$AZURE_CONTAINER_REGISTRY_NAME"
import-image:
runs-on: ubuntu-latest
needs: [setup-env-job, get-source-acr-and-repository]
environment: prod
env:
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
SOURCE_REGISTRY: ${{ needs.get-source-acr-and-repository.outputs.SOURCE_REGISTRY }}
AZURE_CONTAINER_REGISTRY_NAME: ${{ needs.setup-env-job.outputs.AZURE_CONTAINER_REGISTRY_NAME }}
AZURE_CONTAINER_REPOSITORY_NAME: ${{ needs.setup-env-job.outputs.AZURE_CONTAINER_REPOSITORY_NAME }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Azure CLI
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Import image
run: |
# release branch version
release_commit_sha="${{ github.event.pull_request.head.sha }}"
release_branch_name="${{ github.event.pull_request.head.ref }}"
release_version=$(echo $release_branch_name | sed 's/release\///')
source_image_tag="${release_version}-rc-${release_commit_sha}"
# current (merged) commit sha
commit_sha="${{ github.sha }}"
image_tag="${release_version}-${commit_sha}"
if az acr repository show-tags -n $SOURCE_REGISTRY --repository $AZURE_CONTAINER_REPOSITORY_NAME --query "contains(@, '${source_image_tag}')" | grep -q true; then
echo "βœ… | Image ${source_image_tag} exists in QA ACR."
az acr import -n $AZURE_CONTAINER_REGISTRY_NAME --source $SOURCE_REGISTRY.azurecr.io/$AZURE_CONTAINER_REPOSITORY_NAME:$source_image_tag --image $AZURE_CONTAINER_REPOSITORY_NAME:$image_tag --force
# in case ACR is in another subscription:
# az acr import -n myregistry --source sourcerepository:sourcetag -t targetrepository:targettag -r /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sourceResourceGroup/providers/Microsoft.ContainerRegistry/registries/sourceRegistry
else
echo "❌ | Image ${source_image_tag} does not exist in QA ACR. You need to create a hotfix branch for the fix if you want to add changes outside the release."
exit 1
fi
deploy-flow:
runs-on: ubuntu-latest
needs: [setup-env-job, import-image]
environment: prod
env:
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
AZURE_DEV_COLLECT_TELEMETRY: no
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Azure CLI
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Set az account
uses: azure/CLI@v2
with:
inlineScript: |
az account set --subscription $AZURE_SUBSCRIPTION_ID
- name: Deploy Flow
env:
AZURE_APP_SERVICE_NAME: ${{needs.setup-env-job.outputs.AZURE_APP_SERVICE_NAME}}
AZURE_APP_SERVICE_PLAN_NAME: ${{needs.setup-env-job.outputs.AZURE_APP_SERVICE_PLAN_NAME}}
AZURE_CONTAINER_REGISTRY_NAME: ${{needs.setup-env-job.outputs.AZURE_CONTAINER_REGISTRY_NAME}}
AZURE_CONTAINER_REPOSITORY_NAME: ${{needs.setup-env-job.outputs.AZURE_CONTAINER_REPOSITORY_NAME}}
AZURE_RESOURCE_GROUP: ${{needs.setup-env-job.outputs.AZURE_RESOURCE_GROUP}}
AZURE_SUBSCRIPTION_ID: ${{needs.setup-env-job.outputs.AZURE_SUBSCRIPTION_ID}}
shell: bash
run: |
# Deploy Flow
echo "πŸ”Ά | Deploying to Azure"
release_branch_name="${{ github.event.pull_request.head.ref }}"
release_version=$(echo $release_branch_name | sed 's/release\///')
commit_sha="${{ github.sha }}"
full_image_tag="${AZURE_CONTAINER_REPOSITORY_NAME}:${release_version}-${commit_sha}"
name="${AZURE_APP_SERVICE_NAME}"
service_plan_name="${AZURE_APP_SERVICE_PLAN_NAME}"
subscription="${AZURE_SUBSCRIPTION_ID}"
resource_group="${AZURE_RESOURCE_GROUP}"
registry_name="${AZURE_CONTAINER_REGISTRY_NAME}"
full_registry_name="${registry_name}.azurecr.io"
acr_image_tag=$full_registry_name/$full_image_tag
echo "Full Image Tag: $full_image_tag"
echo "ACR Image Tag: $acr_image_tag"
echo "App Service Name: $name"
echo "Service Plan Name: $service_plan_name"
echo "Subscription ID: $subscription"
echo "Resource Group: $resource_group"
echo "Registry Name: $registry_name"
echo "Full Registry Name: $full_registry_name"
function append_to_command {
command=$1
if [ -n "$subscription" ]; then
command="$command --subscription $subscription"
fi
if $verbose; then
command="$command --debug"
fi
echo "$command"
}
echo "πŸ”Ά | Trying to login to $registry_name..."
az acr login -n "$registry_name"
# Check if the container image exists
echo "πŸ”Ά | Checking if ${acr_image_tag} exists..."
set +e
image_exists=$(az acr repository show --name $registry_name --image ${acr_image_tag} --query "name" -o tsv > /dev/null 2>&1 && echo true || echo false)
set -e
if [ -z "$image_exists" ]; then
echo "❌ | $acr_image_tag does not exist"
exit 1
else
echo "βœ… | $acr_image_tag exists"
fi
# Check if the app exists
echo "πŸ”Ά | Checking if the app exists..."
app_exists=$(az webapp show --name $name --resource-group $resource_group --query "name" -o tsv)
if [ -z "$app_exists" ]; then
# Create app
echo "πŸ”Ά | Creating $name app..."
command="az webapp create --name $name -p $service_plan_name --deployment-container-image-name $acr_image_tag --startup-file 'bash start.sh' -g $resource_group"
command=$(append_to_command "$command")
echo "$command"
eval "$command"
else
# Update app
echo "πŸ”Ά | Updating $name app..."
command="az webapp config container set --name $name --resource-group $resource_group --container-image-name $acr_image_tag"
command=$(append_to_command "$command")
echo "$command"
eval "$command"
fi
# Set Registry and ACR credentials
echo "πŸ”Ά | Setting ACR credentials in $registry_name registry..."
az acr update -n $registry_name --admin-enabled true
acr_username=$(az acr credential show --name $registry_name --query username --output tsv)
acr_password=$(az acr credential show --name $registry_name --query passwords[0].value --output tsv)
az webapp config container set --name $name --resource-group $resource_group --container-registry-user $acr_username --container-registry-password $acr_password
# Config environment variables
echo "πŸ”Ά | Config app $name env variables ..."
# Port default to 8080 corresponding to the DockerFile
command="az webapp config appsettings set -g $resource_group --name $name --settings USER_AGENT=promptflow-appservice WEBSITES_PORT=8080"
command=$(append_to_command "$command")
echo "$command"
eval "$command"
# Restarting app
echo "πŸ”Ά | Restarting app ...$name"
az webapp restart --name $name --resource-group $resource_group
echo "πŸ”— Please go to https://portal.azure.com/ to config environment variables of $name app at (Settings>Configuration) or (Settings>Environment variables)"
echo "Reach deployment logs at (Deployment>Deployment Central) and app logs at (Monitoring>Log stream)"
echo "πŸ”— Reach advanced deployment tools at https://$name.scm.azurewebsites.net/"
echo "πŸ”— Reach more details about app service at https://learn.microsoft.com/en-us/azure/app-service/"
- name: GitHub Summary Step
if: ${{ success() }}
run: |
echo "Deployment completed successfully! :rocket:" >> $GITHUB_STEP_SUMMARY
deep_link=https://portal.azure.com/#@/resource/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/rg-$AZURE_ENV_NAME/overview
echo "πŸ”— [View Resources Deployed Here]($deep_link)" >> $GITHUB_STEP_SUMMARY
smoke-tests:
needs: [setup-env-job, deploy-flow]
runs-on: ubuntu-latest
environment: prod
env:
AZURE_APP_SERVICE_NAME: ${{needs.setup-env-job.outputs.AZURE_APP_SERVICE_NAME}}
steps:
- name: Smoke Tests
run: |
curl https://${AZURE_APP_SERVICE_NAME}.azurewebsites.net/score --data '{"question":"What is the size of the moon?", "chat_history":[]}' -X POST -H "Content-Type: application/json"