Skip to content

Instantly share code, notes, and snippets.

@greyhoundforty
Last active May 28, 2024 17:08
Show Gist options
  • Save greyhoundforty/e9582f98415c37755848736e8f0f44df to your computer and use it in GitHub Desktop.
Save greyhoundforty/e9582f98415c37755848736e8f0f44df to your computer and use it in GitHub Desktop.
Code Engine and Github CLI

Overview

Terminal commands for setting up a Code Engine webhook and example application repository

Overview of workflow

Pre-reqs:

Export Variables

Set these variables first as they are used by the next round that we need to set:

export RESOURCE_GROUP=""
export GITHUB_USERNAME=""
export IBMCLOUD_REGION=""
export IBMCLOUD_API_KEY=""

Next we generate a random secret for our webhook, set our ICR endpoint, and set some project related prefixes so its easier to keep track of what is deployed:

export WEBHOOK_SECRET=$(uuidgen | tr '[:upper:]' '[:lower:]')
export PROJECT_PREFIX=$(cat /dev/urandom | LC_ALL=C tr -dc 'a-z' | fold -w 4 | head -n 1)
export ICR_NAMESPACE="${PROJECT_PREFIX}-icr-ns"
export ICR_IMAGE="${PROJECT_PREFIX}-simpleflask"
export ICR_ENDPOINT="${IBMCLOUD_REGION%%-*}.icr.io"

Login to the IBM Cloud CLI and install or update plugins

If you already have the plugins installed you may be prompted to reinstall or update the plugins.

ibmcloud login --apikey "${IBMCLOUD_API_KEY}" -r "${IBMCLOUD_REGION}" -g "${RESOURCE_GROUP}"
ibmcloud plugin install code-engine container-registry

Login to the IBM Cloud container registry

The cr login command will use the already selected region. We then add a namespace and create a new variable for the ICR endpoint.

slight rant: This is one of the few ic plugins that does not support --output json and it is maddening.

ibmcloud cr region-set "${ICR_ENDPOINT}"
ibmcloud cr login
ibmcloud cr namespace-add "${ICR_NAMESPACE}"

Create Code Engine Project and Secrets

With the region and resource group targeted we can move on to creating the following resources:

  • Code Engine Project
  • Code Engine Registry secret to pull images from ICR
  • Code Engine Generic secret for our Function
ibmcloud ce project create --name "${PROJECT_PREFIX}-ce-proj"

ibmcloud ce secret create --name "${PROJECT_PREFIX}-icr-secret" --format registry --username iamapikey --password "${IBMCLOUD_API_KEY}" --email "iamuser@example.com" --server "private.${ICR_ENDPOINT}"

ibmcloud ce secret create --name "${PROJECT_PREFIX}-function-secret" --format generic --from-literal CE_APP="${PROJECT_PREFIX}-app" --from-literal WEBHOOK_SECRET="${WEBHOOK_SECRET}" --from-literal IBMCLOUD_API_KEY="${IBMCLOUD_API_KEY}" --from-literal ICR_NAMESPACE="${ICR_NAMESPACE}" --from-literal ICR_IMAGE="${ICR_IMAGE}"

Create a Github repository from an existing template repo

We also set the gh cli to use the newly cloned repo as the default. This ensures our variables and secrets are attached to the correct repoistory

gh repo create --clone "${PROJECT_PREFIX}-ce-app" --public --template cloud-design-dev/simple-flask-ce-app && cd "${PROJECT_PREFIX}-ce-app"

gh repo set-default

gh workflow enable build-push-icr.yaml

gh variable set REGISTRY_NAMESPACE --body "${ICR_NAMESPACE}"

gh variable set REGISTRY_IMAGE --body "${ICR_IMAGE}"

gh variable set REGISTRY_ENDPOINT --body "${ICR_ENDPOINT}"

gh secret set REGISTRY_PASSWORD --body "${IBMCLOUD_API_KEY}"

gh workflow run build-push-icr.yaml --ref main

Check status of build and push

JOB_ID=$(gh run list --workflow=build-push-icr.yaml -L 1 --json databaseId --jq '.[].databaseId')

gh run view "${JOB_ID}"

Create Code Engine App and Function

If the Github action completes we can move on to creating our Code Engine application and our Webhook reciever function. First up lets create our web application, it will take a few moments to deploy and configure the frontend ingress for our application:

ibmcloud ce app create --name "${PROJECT_PREFIX}-app" --registry-secret "${PROJECT_PREFIX}-icr-secret" --image "private.${ICR_ENDPOINT}/${ICR_NAMESPACE}/${ICR_IMAGE}:latest" --port "8080" 

After a few minutes you should see output similar to this:

ibmcloud ce app create --name "${PROJECT_PREFIX}-app" --registry-secret "${PROJECT_PREFIX}-icr-secret" --image "private.${ICR_ENDPOINT}/${ICR_NAMESPACE}/${ICR_IMAGE}:latest" --port "8080"
Creating application 'btbx-app'...
The Route is still working to reflect the latest desired specification.
Configuration 'btbx-app' is waiting for a Revision to become ready.
Ingress has not yet been reconciled.
Waiting for load balancer to be ready.
Run 'ibmcloud ce application get -n btbx-app' to check the application status.
OK

https://btbx-app.1hijp0rx5e1d.us-east.codeengine.appdomain.cloud

Now we can move on to deploying our webhook function in Code Engine:

ibmcloud ce function create --name "${PROJECT_PREFIX}-fn" --env-from-secret "${PROJECT_PREFIX}-function-secret" --runtime python-3.11 --build-source https://github.com/cloud-design-dev/gh-webhook-function.git 

Code Engine will pull out source code and build a container for our function and expose a Public endpoint. By default Code Engine will use its own pregenerated namespace to store the code bundle that is built for the function.

ibmcloud ce function create --name "${PROJECT_PREFIX}-fn" --env-from-secret "${PROJECT_PREFIX}-function-secret" --runtime python-3.11 --build-source https://github.com/cloud-design-dev/gh-webhook-function.git
Preparing function 'btbx-fn' for build push...
Creating function 'btbx-fn'...
Submitting build run 'btbx-fn-run-240528-105521517'...
Creating image 'private.de.icr.io/ce--6c272-1hijp0rx5e1d/function-btbx-fn:240528-1555-o9q6y'...
Waiting for build run to complete...
Build run status: 'pending'
Build run status: 'running'
Build run completed successfully.
Run 'ibmcloud ce buildrun get -n btbx-fn-run-240528-105521517' to check the build run status.
Waiting for function 'btbx-fn' to become ready...
Function 'btbx-fn' is ready.
OK
Run 'ibmcloud ce function get -n btbx-fn' to see more details.

https://btbx-fn.1hijp0rx5e1d.us-east.codeengine.appdomain.cloud

Add Function webhook to Github repository

The last step is to add our newly created webhook to the Github repository

WEBHOOK_URL=$(ibmcloud ce fn get --name "${PROJECT_PREFIX}-fn" --output json | jq -r '.endpoint')
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" "/repos/${GITHUB_USERNAME}/${PROJECT_PREFIX}-ce-app/hooks" -f "name=web" -F "active=true" -f "events[]=workflow_run" -f "config[url]=${WEBHOOK_URL}" -f "config[content_type]=json" -f "config[insecure_ssl]=0" -f "config[secret]=${WEBHOOK_SECRET}"

Test by pushing simple update

In our cloned directory we can run the folling to kick off the Github Action > Webhook > Code Engine flow:

echo -e "\nThis is a test at $(date)" | tee -a README.md
git add . 
git commit -m "Testing app update process"
git push
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment