Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DEVOPS-263] Add ephemeral deployments workflow #61

Merged
merged 23 commits into from
Oct 9, 2023
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
40e0f2b
Add ephemeral deployments workflow
ebronson68 Oct 3, 2023
8c73a84
disable AzPsSession in destroy step
ebronson68 Oct 3, 2023
91315e8
Removed spaces around build arg option
ebronson68 Oct 4, 2023
c61d2c3
Fix build args GitHub action env setting
ebronson68 Oct 4, 2023
2beb769
Switch to Container Apps
ebronson68 Oct 5, 2023
fad70ee
switch to registry* inputs for container registry
ebronson68 Oct 5, 2023
4dbc1e6
Fix clusterResourceGroup default value
ebronson68 Oct 5, 2023
f8b1632
add docker build/push step back so that the buildargs get used
ebronson68 Oct 5, 2023
519df12
remove appSourcePath from deploy action to prevent building image whe…
ebronson68 Oct 5, 2023
168f2b0
Fix empty targetPort input
ebronson68 Oct 5, 2023
96085db
use cat + find in TARGET_PORT var
ebronson68 Oct 5, 2023
87af402
Fixing only first environment variable being set
ebronson68 Oct 5, 2023
14d509b
Add step to fix NEXT URL variables in container app
ebronson68 Oct 6, 2023
4061fd6
set environment url from hostname in later step
ebronson68 Oct 6, 2023
ba638ad
Add --yes option onto container delete cmd
ebronson68 Oct 9, 2023
6dd68cc
Add --yes option to acr repository delete cmd
ebronson68 Oct 9, 2023
a96f986
add githubPAT secret
ebronson68 Oct 9, 2023
c1b7999
Fix container app deletion cmd
ebronson68 Oct 9, 2023
99aed93
Resolve shellcheck SC2002 and SC2046 errors
ebronson68 Oct 9, 2023
ecea9f0
Fixing shellcheck SC2046 warning
ebronson68 Oct 9, 2023
db4d3df
Fixing SC2046 shellchecck warning
ebronson68 Oct 9, 2023
1d30efa
Resolving shellcheck SC2013 warning
ebronson68 Oct 9, 2023
bc9b30b
Merge branch 'main' into story/DEVOPS-263/ephemeral-deployments-workflow
ebronson68 Oct 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions .github/workflows/ephemeral-deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
name: Ephemeral Deployment

on:
workflow_call:
inputs:
environment:
required: true
type: string
description: "Deploy Environment. This is used to pull in and set the github environment. Can be development, staging, or production."
environmentKeyVault:
required: false
type: string
description: "AKS Key vault."
repositoryName:
required: false
type: string
description: "GitHub Repository Name."
default: "${{ github.event.repository.name }}"
clusterResourceGroup:
required: false
type: string
description: "Azure Resource Group."
default: "AMU_EphemeralDeployments_RG"
dockerFilePath:
required: false
type: string
description: "Relative path to Dockerfile."
default: "."
dockerImageName:
required: false
type: string
description: "Docker image name."
default: "${{ github.event.repository.name }}"
azureResourceLocation:
required: false
type: string
description: "Location of resources in Azure"
default: "centralus"
secrets:
azureCredentials:
required: true
registryHostName:
required: true
registryUserName:
required: true
registryPassword:
required: true
githubPAT:
required: true

env:
githubPrBranch: ${{ github.head_ref }}
githubPrTitle: ${{ github.event.pull_request.title }}
githubPrDescription: ${{ github.event.pull_request.body }}

jobs:
prepare:
name: Preparation Step
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'ephemeral-deployment' || github.event_name == 'pull_request' && github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'ephemeral-deployment') }}
runs-on: ubuntu-latest
steps:
- name: Retrieve Jira ticket ID
id: jira-ticket
run: |
PR_BRANCH=$(echo "${{ env.githubPrBranch }}" | grep -Eo "\b[A-Z][A-Z0-9_]+-[1-9][0-9]*")
PR_TITLE=$(echo "${{ env.githubPrTitle }}" | grep -Eo "\b[A-Z][A-Z0-9_]+-[1-9][0-9]*")
PR_DESC=$(echo "${{ env.githubPrDescription }}" | grep -Eo "\b[A-Z][A-Z0-9_]+-[1-9][0-9]*")

for var in ${PR_BRANCH} ${PR_TITLE} ${PR_DESC}; do JIRA_TICKET_ID=$(echo $var | grep -E ".") && break ; done
JIRA_TICKET_ID_LC=$(echo "${JIRA_TICKET_ID}" | tr '[:upper:]' '[:lower:]')

echo "jiraTicketIdLc=${JIRA_TICKET_ID_LC}" >> $GITHUB_OUTPUT
echo "jiraTicketId=${JIRA_TICKET_ID}" >> $GITHUB_OUTPUT

- name: Fix repository name
id: repository-name
run: |
REPOSITORY_NAME=$(echo "${{ inputs.repositoryName }}" | tr '[:upper:]' '[:lower:]' | tr "_" "-")

echo "repositoryName=${REPOSITORY_NAME}" >> $GITHUB_OUTPUT
outputs:
jiraTicketId: ${{ steps.jira-ticket.outputs.jiraTicketId }}
jiraTicketIdLc: ${{ steps.jira-ticket.outputs.jiraTicketIdLc }}
repositoryName: ${{ steps.repository-name.outputs.repositoryName }}

deploy:
name: Deploy Azure Container Instance
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'ephemeral-deployment' || github.event_name == 'pull_request' && github.event.action != 'closed' && github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'ephemeral-deployment') }}
needs: [prepare]
runs-on: ubuntu-latest
environment:
name: ${{ needs.prepare.outputs.jiraTicketId }}
url: ${{ steps.hostname.outputs.hostname }}
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Generate .env file from Azure Key Vaults
uses: Andrews-McMeel-Universal/get-envs@v1
with:
environment: ${{ inputs.environment }}
azurecredentials: ${{ secrets.azureCredentials }}
environmentKeyVault: ${{ inputs.environmentKeyVault }}

- name: Set environment variables
id: env-vars
shell: bash
run: |
ENVIRONMENT_VARIABLES=$(tr "\n" " " < .env)
TARGET_PORT=$(find . -iname "values.yaml" -exec grep "targetPort: " {} \; | awk -F ': ' '{print $2}' | uniq)

echo "targetPort=${TARGET_PORT}" >> $GITHUB_OUTPUT
echo "environmentVariables=${ENVIRONMENT_VARIABLES}" >> $GITHUB_OUTPUT

- name: Generate build args from Azure Key Vaults
shell: bash
run: |
ENVIRONMENT="${{ inputs.environment }}"
REPOSITORY_NAME="${{ inputs.repositoryName }}"
ENV_KEYVAULT_NAME="${{ inputs.environmentKeyVault }}"
BUILDARG_PREDICATE="--build-arg"

# Check if searching for key vaults by repository name or otherwise, if key vault name argument is given
if [ -z "${ENV_KEYVAULT_NAME}" ]; then
# Search for key vault using tags
KEYVAULT_NAME=$(az keyvault list --query "[?tags.\"repository-name\" == '${REPOSITORY_NAME}' && tags.environment == '${ENVIRONMENT}'].name" --output tsv)
else
KEYVAULT_NAME="${ENV_KEYVAULT_NAME}"
fi

# Get key vault object
KEYVAULT=$(az keyvault list --query "[?name == '${KEYVAULT_NAME}']" )

# Check if key vault exists
if ! echo "${KEYVAULT}" | grep -Eq "\w"; then
echo -e "${RED}Invalid value provided for 'KeyVaultName'. Please confirm a Key Vault exists under the name specified. Value provided: ${KEYVAULT_NAME}"
exit 1
fi
KEYVAULT_NAME="${KEYVAULT_NAME// /}"

# Set secrets list
SECRETS=$(az keyvault secret list --vault-name "${KEYVAULT_NAME}" --query "[?contentType == 'BuildArg Env' || contentType == 'BuildArg'].name" --output tsv)

# Loop through secrets and add them to .env
if echo "${SECRETS}" | grep -Eq "\w"; then
while IFS= read -r SECRET; do
# Convert to upper case snake case and remove quotes
SECRET_NAME=$(echo "${SECRET}" | tr '[:upper:][:lower:]' '[:lower:][:upper:]' | tr "-" "_" | tr -d '"')

# Get secret value and set it to the secret name
SECRET_VALUE=$(az keyvault secret show --vault-name "${KEYVAULT_NAME}" -n "${SECRET}" --query "value" --output tsv)

# Add secret to file
BUILDARGS="${BUILDARGS} ${BUILDARG_PREDICATE} ${SECRET_NAME}=${SECRET_VALUE}"
done < <(echo "${SECRETS[*]}")
fi
echo "buildArguments=${BUILDARGS}" >> $GITHUB_ENV

- name: Login to Azure Container Registry
uses: Azure/docker-login@v1
with:
login-server: ${{ secrets.registryHostName }}
username: ${{ secrets.registryUserName }}
password: ${{ secrets.registryPassword }}

- name: Build & Push Docker Image
id: docker
run: |
docker build ${{ inputs.dockerFilePath }} ${{ env.buildArguments }} -t "${{ secrets.registryHostName }}/${{ inputs.dockerImageName }}:${{ needs.prepare.outputs.jiraTicketId }}"
docker push -a "${{ secrets.registryHostName }}/${{ inputs.dockerImageName }}"

- name: Deploy Azure Container App
uses: azure/container-apps-deploy-action@v1
with:
registryUrl: ${{ secrets.registryHostName }}
registryUsername: ${{ secrets.registryUserName }}
registryPassword: ${{ secrets.registryPassword }}
imageToDeploy: ${{ secrets.registryHostName }}/${{ inputs.dockerImageName }}:${{ needs.prepare.outputs.jiraTicketId }}
containerAppName: ${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }}
resourceGroup: ${{ inputs.clusterResourceGroup }}
targetPort: ${{ steps.env-vars.outputs.targetPort }}
location: ${{ inputs.azureResourceLocation }}
environmentVariables: ${{ steps.env-vars.outputs.environmentVariables }}
ingress: external
disableTelemetry: true

- name: Get Container App Hostname
id: hostname
run: |
HOSTNAME=$(az containerapp list --query "[?name == '${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }}'].properties.configuration.ingress.fqdn" -o tsv)
echo "hostname=https://${HOSTNAME}" >> $GITHUB_OUTPUT

- name: Update Next URL variables
if: contains(steps.env-vars.outputs.environmentVariables, 'BASE_URL')
run: |
REPOSITORY_NAME=$(echo "${{ github.event.repository.name }}" | awk -F '_' '{print $1}' | tr -d "-")
HOSTNAME="${{ steps.hostname.outputs.hostname }}"
URL_VARS=""
while IFS= read -r line; do
var=$(echo "$line" | awk -F '=' '{print $1}' | sed "s|$|=${HOSTNAME}|g")
URL_VARS+="$var "
done < <(grep -E "localhost|${REPOSITORY_NAME}.com" .env)

az containerapp update -n "${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }}" -g "${{ inputs.clusterResourceGroup }}" --set-env-vars "${URL_VARS}"

destroy:
name: Destroy Azure Container Instance
if: ${{ github.event_name == 'pull_request' && github.event.action == 'closed' }}
needs: [prepare]
runs-on: ubuntu-latest
steps:
- name: Login via Az module
uses: azure/login@v1
with:
creds: "${{ secrets.azureCredentials }}"

- name: Delete Azure Resources
run: |
az containerapp delete --resource-group ${{ inputs.clusterResourceGroup }} --name ${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }} --yes
az acr repository delete -n ${{ secrets.registryHostName }} --image ${{ inputs.dockerImageName }}:${{ needs.prepare.outputs.jiraTicketId }} --yes

- name: Delete deployment environment
uses: strumwolf/delete-deployment-environment@v2
with:
token: ${{ secrets.githubPAT }}
environment: ${{ needs.prepare.outputs.jiraTicketId }}
ref: ${{ github.ref_name }}
Loading