Release 1.0.0 #1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |