Advanced CI/CD Patterns
Introduction
This guide continues Build & Deploy Actions and it is specifically tailored for teams who have more specific pipeline needs.
This article is currently a stub but will be regularly updated with new patterns and workflows as the automation requirements of our customers and users continue to evolve.
JFrog ML Configuration-as-Code
In a GitOps workflow, all configurations for builds and deployments are version-controlled and stored within your Git repository. This approach allows you to apply versioning, peer review, and automated testing to your infrastructure, just like you do with your code.
For that principle, let's consider the following JFrog ML model directory example:
qwak_model/
├── main/
│ ├── __init__.py # Required for exporting model from main
│ ├── model.py # Qwak model definition
│ ├── conda.yml # Conda environment file
├── configuration/
├── build_conf.yml # Build configuration
├── deployment_conf.yml # Deployment configuration
Within the configuration
directory, you have the option to centralize your JFrog ML Build and Deploy settings. By doing so, you can reference these configurations in both the build-action
and deploy-action
. This approach offers an advantage over embedding configurations directly in your GitHub workflow files, as it allows for easier management and version control.
Build Configuration
For instance, your build_conf.yml
might be structured as follows:
buildProperties:
modelId: "credit_risk_with_feature_store"
modelUri:
uri: "."
mainDir: "main"
tagsList:
- "build-with-conf-file"
environmentName: ""
gpuCompatible: false
buildEnv:
docker:
envVarsList: []
paramsList: []
assumedIamRoleArn: ""
pythonEnv:
conda:
condaFile: "conda.yml"
remote:
isRemote: false
resources:
instance: "small"
This would be the equivalent of running the following JFrog ML CLI command:
qwak models build --model-id credit_risk_with_feature_store \
--tags "build-with-conf-file" \
--instance "small" \
.
Of course the build configuration file can store more complex build configs, however, the primary advantage of this approach is the decoupling of JFrog ML configurations from your GitHub workflow files. This separation allows you to modify JFrog ML settings without altering the workflow code, thereby simplifying maintenance and enhancing version control.
Deploy Configuration
As opposed to a Build config, the deployment configuration is dependent on the deployment type; that being realtime
, batch
and streaming
.
Let's consider the following realtime
example:
resources:
instance_size: "small"
pods: 2 # number of pods per instance
realtime:
timeout: 6000 # REST endpoint timeout in ms
variation_name: "default"
audiences: # define the audiences for this deployment
- id: audience_1
routes:
- variation_name: default
weight: 100 # 100% of the live traffic goes to the default endpoint
shadow: false
- variation_name: shadow
weight: 20 # replicate 20% of the live traffic to a shadow endpoint
shadow: true
fallback_variation: shadow
In this deployment configuration we defined a realtime deployment with 2 Audiences, a default
one which should serve all the production traffic and a Shadow Variation that replicates 20% of the live requests to a shadow endpoint for testing purposes.
As opposed to the build configuration example, this deployment config file can only be called by a
qwak models deploy
command, but cannot be substituted by one as it contains the Audience configuration.
In the next section you'll learn how to leverage these 2 configuration files in a real Github Workflow example.
Build and Deploy Shadow Variations on Pull-Request
In this workflow, you will learn how to leverage the build_config.yml
and deploy_config.yml
configuration files defined earlier in a real-life Github workflow scenario.
This GitHub Actions workflow automates the process of building and deploying a JFrog ML model whenever a pull request is made against the main
branch. The workflow consists of two main jobs: build
and deploy
.
name: Build and Deploy JFrog ML Model as a Shadow Variation on PR
on:
pull_request:
types: [opened, reopened, synchronize]
branches:
- 'main' # replace with your `main` or `master` branch
paths-ignore:
- "*.md" # Ignore modifications to Readme files
workflow_dispatch: # Enables manual trigger
jobs:
build:
runs-on: ubuntu-latest # change with your required instance for example [ubuntu-latest]
outputs:
build_id: ${{ env.build-id }}
build_status: ${{ env.build-status }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build Qwak Model
id: qwak-build
uses: qwak-ai/build-action@v1
with:
qwak-api-key: ${{ secrets.QWAK_API_KEY }}
model-id: ${{ vars.QWAK_MODEL_ID }} # stored as a Repository variable
tags: ${{ github.head_ref }} # tag the build with the branch name
from-file: 'configuration/build_conf.yml'
# other config inputs as needed
# [Optional] Additional step to notify e.g. Slack
# [Optional] Additional step to post Qwak Build link on the Pull Request page
deploy:
if: needs.build.outputs.build_status == 'SUCCESSFUL' # Only call deploy on successful builds
runs-on: ubuntu-latest
needs: build
steps:
# Deploy model to a shadow/canary endpoint
- name: Deploy Qwak Build
uses: qwak-ai/deploy-action@v1
with:
qwak-api-key: ${{ secrets.QWAK_API_KEY }}
deploy-type: 'realtime' # Replace with the deployment type you need
model-id: ${{ vars.QWAK_MODEL_ID }} # Using the repository variable for model ID
build-id: ${{ needs.build.outputs.build_id }} # Using the build ID from the previous job
param-list: | # This will enforce the `shadow` variation over the default from the config file
variation-name=shadow,from-file=configuration/deploy_conf.yaml
# [Optional] Additional step to post the Qwak deployment URL on the Pull Request page.
# [Optional] Additional step to notify with the deployment status and details on Slack.
# [Optional] Additional job/separate workflow to run integration tests on the live model endpoint
Trigger Conditions
The workflow is triggered on pull request events such as opening, reopening, or synchronizing.
It focuses on changes made to the main branch and ignores any modifications to Markdown files (.md).
Manual triggering is also enabled through workflow_dispatch.
Build Job
- Checkout Code: Checks out the repository code.
- Build JFrog ML Model: Initiates the JFrog ML model build process using JFrog ML
build-action
. The build is tagged with the branch name and uses thebuild_conf.yml
configuration file for additional build settings.
Build Tagging
In this example we are tagging the Qwak Builds with the
Git branch
to make it easier to find the latest successful build when merging the code to themain
ormaster
branch.Alternative tagging can be the
PR Title
with${{ github.event.pull_request.title }}
.
Deploy Job
- Conditional Execution: This job runs only if the build job is successful.
- Deploy JFrog ML Build: Deploys the successfully built JFrog ML model to a realtime shadow/canary endpoint as defined in the
deploy_conf.yml
file.
Deployment Type
If your use case requires
batch
orstreaming
deployments, instead of the Shadow Variation you can use a test or staging Qwak Environment for the test deployment.
Troubleshooting
Validating Configuration Files
The easiest way to create JFrog ML build
and deploy
configuration files is to start from the JFrog ML CLI command using the --out-conf
flag as follows:
qwak models build --model-id <your-model-id> --out-conf
qwak models deploy realtime --model-id <your-model-id> --out-conf
Starting from these commands output you can strip down to a configuration that's reflecting your needs without redundancy.
Updated 18 days ago
Feel free to check out the rest of the Automations docs from this section.