Attempting to add CI/CD automation
Some checks failed
Build and deploy Main Bridgeman Accessible website to QA/Stagging (private Kubernetes cluster) / build (push) Failing after 19s
Build and deploy Main Bridgeman Accessible website to QA/Stagging (private Kubernetes cluster) / deploy (push) Has been skipped

This commit is contained in:
Alan Bridgeman 2025-06-10 10:54:11 -05:00
parent beb5368e28
commit 8d35d69efa
2 changed files with 239 additions and 2 deletions

View file

@ -0,0 +1,237 @@
# +=========================================================================================================================+
# | QA/Stagging CI/CD workflow |
# | |
# | Our QA/Stagging environment is hosted on servers in our office using a combination of: |
# | - Kubernetes (10 Ubuntu 24.04 VM nodes, hosted within a Proxmox VE cluster of 2 servers, a Dell R730xd and a Dell R730) |
# | - Nginx Proxy Manager as a reverse proxy |
# | - Pi-hole for DHCP |
# | - Bind for custom DNS |
# | On a cluster wide level: |
# | - Rook/Ceph |
# | - MetalLb |
# | - Nginx Ingress Controller |
# | - PosgreSQL Operator (CloudNativePG) |
# | - Custom PostgreSQL Database Operation (https://github.com/AlanBridgeman/postgres-controller) |
# | - MongoDB Community Operator |
# | On a namespace level: |
# | - Redis |
# | - Hasshicorp Vault |
# | - Mongo containers |
# | |
# | It's worth noting we largely use Helm to deploy resources into the cluster. |
# +=========================================================================================================================+
name: Build and deploy Main Bridgeman Accessible website to QA/Stagging (private Kubernetes cluster)
on:
push:
branches:
- stagging
# I'm leaving this here because I've tried to add and then had to remove this several times
# In particular, the problem is conditions are OR'd NOT AND'd
# This means controls via branch commit rules combined with this workflow achieve a better result than having this here
#tags:
# - 'v[0-9]+.[0-9]+.[0-9]+' # Matches any semantic versioning tag (e.g. v1.0.0, v2.1.3, etc.)
workflow_dispatch:
permissions:
contents: write # Allows the workflow to push changes to the repository (e.g. for tagging)
jobs:
# Run tests (particularly unit tests) on the codebase
# This mostly relies on the `yarn test` command
#test:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
#
# - name: Set up Node.js version
# uses: actions/setup-node@v3
# with:
# # Take from [Repo README](https://github.com/actions/setup-node#readme)
# #
# # > Version Spec of the version to use in SemVer notation.
# # > It also admits such aliases as lts/*, latest, nightly and canary builds
# # > Examples: 12.x, 10.15.1, >=10.15.0, lts/Hydrogen, 16-nightly, latest, node
# node-version: '18.x'
#
# # Take from [Repo README](https://github.com/actions/setup-node#readme)
# #
# # > Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file,
# # > and set up auth to read in from env.NODE_AUTH_TOKEN.
# # > Default: ''
# registry-url: 'https://npm.pkg.bridgemanaccessible.ca'
#
# # Take from [Repo README](https://github.com/actions/setup-node#readme)
# #
# # > Optional scope for authenticating against scoped registries.
# # > Will fall back to the repository owner when using the GitHub Packages registry (https://npm.pkg.github.com/).
# scope: '@BridgemanAccessible'
#
# - name: yarn install and test
# env:
# NODE_AUTH_TOKEN: ${{ secrets.PRIVATE_NPM_TOKEN }}
# run: |
# yarn install
# yarn test
# Builds the codebase (builds the image)
build:
runs-on: self-hosted
outputs:
build_and_deploy: ${{ steps.version_check.outputs.build_and_deploy }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare Environment Variables
run: |
echo "Harbor Username: ${{ secrets.HARBOR_USERNAME }}"
echo "HARBOR_USERNAME=${{ secrets.HARBOR_USERNAME }}" >> $GITHUB_ENV
echo "Harbor Password: ${{ secrets.HARBOR_PASSWORD }}"
echo "HARBOR_PASSWORD=${{ secrets.HARBOR_PASSWORD }}" >> $GITHUB_ENV
# Check if this is a "significant" commit that should trigger a build and deploy
# This is done by checking if the latest git tag matches the version in the `package.json` file
- name: Version Check
id: version_check
run: |
echo 'Harbor Username: ${{ env.HARBOR_USERNAME }}'
# Get the latest version from the `package.json` file
# This should be updated if a new build and deploy is desired
LATEST_VERSION=$(jq -r '.version' package.json)
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
# Get the latest Git tag from the repository
LATEST_TAG=$(git describe --tags --abbrev=0)
echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
# If the git tag and the version ARE the same, this is a commit that SHOULD NOT trigger a build and deploy
# Inversely, if the git tag and the version are NOT the same, this is a commit that SHOULD trigger a build and deploy
if [[ "$LATEST_TAG" == "v$LATEST_VERSION" ]]; then
echo "Latest tag matches the version in package.json, SHOULD NOT build and deploy"
echo "build_and_deploy=false" >> $GITHUB_OUTPUT
else
echo "Latest tag does not match the version in package.json, SHOULD build and deploy"
echo "build_and_deploy=true" >> $GITHUB_OUTPUT
fi
# Because a build and deploy is desired, we want to check if a new tag already exists or if we need to create one as part of the workflow
# This is commented out because the approach here makes sense but the logic doesn't fully because we already know the git tag and the version don't match
#- name: Tag Check
# id: tag_check
# if: steps.version_check.outputs.build_and_deploy == 'true'
# run: |
# # Check if a matching image build already exists
# MATCHING_IMAGE=$(docker image ls $(jq -r '.name' package.json) | grep ${{ env.LATEST_TAG }} || echo "Image not found")
#
# # If a matching image exists, set the `create_tag` output to true (so that a new tag is created)
# if [[ "$MATCHING_IMAGE" == "Image not found" ]]; then
# echo "No matching image found, No new tag required"
# echo "create_tag=false" >> $GITHUB_OUTPUT
# else
# echo "Matching image found, new tag required"
# echo "create_tag=true" >> $GITHUB_OUTPUT
# fi
# Conditional step to create a new Git tag
# This is required because when we go to build and deploy the image we rely on the latest git tag
# We do it this way so that ONLY situations where the git tag and the last built image are mal-aligned do we create a new tag
- name: Add Git Tag (if needed)
if: steps.version_check.outputs.build_and_deploy == 'true'
#if: steps.version_check.outputs.build_and_deploy && steps.tag_check.outputs.create_tag == 'true'
run: |
# Increment the version's patch number (within the `package.json` file)
#jq '.version |= (. | split(".") | [.[0], .[1], (.[2] | tonumber + 1 | tostring)] | join("."))' package.json > temp.json && mv temp.json package.json
# Update remote URL to use the GITHUB_TOKEN for authentication
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@git.bridgemanaccessible.ca/${{ github.repository }}.git
# Setup git user details for committing the version change and tag
git config user.name "Forgjo Actions"
git config user.email "actions@git.bridgemanaccessible.ca"
# Commit the version change to the `package.json` file
#git add package.json
#git commit -m "[Github Actions] Update version to $(jq -r '.version' package.json)"
# Push the changes to the repository
#git push origin HEAD:stagging
# Create a new tag with the updated version number
git tag -a "v${{ env.LATEST_VERSION }}" -m "Version ${{ env.LATEST_VERSION }}"
# Push the new tag to the repository
git push --tags
# Run the build script found on self-hosted runner
- name: Run Build Image Script
if: steps.version_check.outputs.build_and_deploy == 'true'
run: |
IMAGE_NAME=ba-website
echo "Repository Path: $GITHUB_WORKSPACE"
echo "Name for Image: $IMAGE_NAME"
# Not necessarily needed but keeping track of the current directory (so that we can return to it is just a good practice)
CURR_DIR="$PWD"
# Change into the repository directory
cd "$GITHUB_WORKSPACE"
IMAGE_TAG=$(git describe --tags --abbrev=0) # Use the most recent tag as the image tag
IMAGE_FULL_NAME="containers.bridgemanaccessible.ca/k8s/${IMAGE_NAME}:${IMAGE_TAG}"
echo "🔹 Building and pushing image..."
docker build -t ${IMAGE_FULL_NAME} .
docker login -u $HARBOR_USERNAME -p $HARBOR_PASSWORD containers.bridgemanaccessible.ca
docker push ${IMAGE_FULL_NAME}
cd "$CURR_DIR"
echo "✅ Build successful!"
deploy:
runs-on: self-hosted
needs: build
if: needs.build.outputs.build_and_deploy == 'true'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get the latest tag
id: get_latest_tag
run: |
LATEST_TAG=$(git describe --tags --abbrev=0)
echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
echo "IMAGE_VERSION=${LATEST_TAG#v}" >> $GITHUB_ENV
#- name: Prepare Environment Variables
# run: |
# echo "HARBOR_USERNAME=${{ secrets.HARBOR_USERNAME }}" >> $GITHUB_ENV
# echo "HARBOR_PASSWORD=${{ secrets.HARBOR_PASSWORD }}" >> $GITHUB_ENV
- name: Run Deploy Kubernetes Script
run: |
IMAGE_VERSION="${{ env.IMAGE_VERSION }}"
NAMESPACE="ba-website"
DEPLOYMENT_NAME="website"
CONTAINER_NAME="website"
IMAGE_NAME="ba-website"
echo "Image Version: $IMAGE_VERSION"
echo "Namespace: $NAMESPACE"
echo "Deployment Name: $DEPLOYMENT_NAME"
echo "Container Name: $CONTAINER_NAME"
echo "Image Name: $IMAGE_NAME"
update-k8s-deployment-image \
--image-version $IMAGE_VERSION \
--namespace $NAMESPACE \
--deployment-name $DEPLOYMENT_NAME \
--container-name $CONTAINER_NAME \
--image-name "containers.bridgemanaccessible.ca/k8s/$IMAGE_NAME"