GitHub Actions — Makes ‘One Click To Deploy’ Feasible For ML CI/CD Pipeline

How to create a CICD Pipeline for Machine Learning Applications with GitHub Actions

Ritheesh Baradwaj Yellenki
Towards Data Science

--

Designed using Canva

What if I told you “You can automate the process of building, testing, delivering, or deploying your Machine Learning models into production”?

The world’s most popular hosted repository service, GitHub is providing an integrated way to design and develop our workflows by automating the tasks through GitHub Actions. With Actions, the events that take place in our GitHub repository like pushes, pull requests, releases, etc. are used as triggers to kick-off the workflows. These workflows are coded in YAML format.

Workflows are nothing but the steps we follow while bringing an application into production which includes unit testing, integration testing, building artifacts, sanity check, and deploying. In this article, I am going to introduce you to GitHub Actions and show you how to build your workflow to deploy a Machine Learning Application.

Let’s Get Started!!

Background

GitHub repository (Photo by Author)

Create a repository on GitHub, if you don’t have an account I recommend you to create one. Every repository on GitHub now supports GitHub Actions features.

GitHub Actions (Photo by Author)

Click on “Actions”. If we already have any files in our repository, GitHub will recommend some predefined workflows. Here we will create our workflow. Click on “set up a workflow yourself”.

Our First Action (Photo by Author)

As I mentioned earlier, GitHub workflows are coded in YAML format, here we define the jobs, steps, and the pipeline. Before getting started let’s have a glimpse of the attributes we use in the YAML file. Below is a simple template to print “Hello, World!!”

Sample Workflow

The basic attributes we use in any workflow are:

  • name — The name of your workflow (optional)
  • on — GitHub event that triggers the flow. It can be repository events (push, pull requests, release) or webhooks, branch creation, issues, or members joining the repository.
  • jobs — Workflows must have at least one job. Each job must have an identifier, it’s like a name for the task we perform say “build”, “test” etc.
  • runs-on — The type of machine needed to run the job. These environments are called Runners. Some of them are windows server 2019, ubuntu 18.04, macOS Catalina 10.15, etc.
  • steps — a list of all the commands or actions. Each step runs its process.
  • uses — identifies an action to use, defines the location of that action. An action can be uploading and downloading artifacts or checkout or configure any cloud account. You can find various actions at GitHub MarketPlace, with categories including Continuous Integration, Deployment, Project management, Testing, Security, etc. I really suggest you to explore various actions, also we can publish our custom actions on the Marketplace.
  • run — runs the command in the virtual environment shell.
  • name — an optional name identifier for the step.

After configuring your workflow with the steps and jobs as per your wish, commit the pipeline — YAML file. The workflow will start running now. Now that we know the terminology of GitHub Actions, let’s start building the workflow for a Machine Learning Application.

Sample ML Application (Photo by Author)

I have developed a machine learning application that will predict the profit of a startup by taking some inputs from the user.

Firstly, I trained the model with the required dataset, tested it, and validated it. Then I created a Flask server that serves the requests from users. I pushed the project directory to GitHub. The GitHub repository should look something like this:

GitHub repository (Photo by Author)

I want to create a workflow with the following four stages. You can also define your workflow accordingly.

  1. Linting
  2. Build a Docker Image and push to Google’s Container Registry.
  3. Testing — Download the Docker image from Container Registry and Test it.
  4. Deploy the Docker image on Cloud Run.
Pipeline (Photo by Author)

Linting Stage

To reduce errors and improvise the overall quality of your code, Linting is necessary. If lint tools are used effectively, it helps fasten your development by reducing the costs of finding the errors. In this stage, we are doing unit testing and checking the code style.

Now we will create the workflow, as shown above, and we will do it step by step.

Lint Stage (Photo by Author)

In this stage, we need to define the environment (Ubuntu in my case), check out the repository in that environment, and install all the dependencies or requirements required for the model to run. Also, I used Pylint and flake8 for checking the code base against coding style (PEP8), programming errors, and to check cyclomatic complexity.

Build Docker Image

Now that we have tested our code against certain coding styles, let’s build a Docker Image. Create a Dockerfile as shown below

Dockerfile (Photo by Author)

We build a docker image for the application using a Dockerfile. This artifact (docker image) needs to be stored somewhere, where all the different versions of our application are present. This will ensure that you are delivering your software in successive versions continuously. We have various tools to store artifacts few of which are — JFrog Artifactory, Amazon ECR, DockerHub, Google’s Container Registry.

Build a Docker image (Photo by Author)

Now, I am going to push the docker image to Google’s Container Registry. So we need to set up the GCP environment which requires sensitive information like passwords and API keys. GitHub allows us to store secrets and we can access those secrets as variables.

${{ secrets.GCP_SERVICE_ACCT_KEY }}

To create a secret go to settings and select secrets.

Settings section (Photo by Author)

You will be redirected to the secrets section. Click on “New secret”. Give the secret a name and add value. Click on “Add secret”

Creating a Secret (Photo by Author)

I have updated all of the required secrets.

Secrets (Photo by Author)

Once the environment is set up, our job will start to build a docker image and upload it to Google’s container Registry (make sure you enable the API for the Container registry on the Google Cloud Platform).

Testing Stage

After executing the above stages, we will have a docker image at our service stored on the container registry. In this stage, we are going to download the image and run it against various test cases. In the real scenarios, we may use different versions of docker images and we specify the versions we want to release. So we download the image from the registry rather than use an image built from the previous stage.

Test Stage (Photo by Author)

Testing is required for the effective performance of software applications or products. Here we can test our Flask server by checking if it is returning 200 status code i.e., a proof of successful run. Also, as we can test and validate our machine learning model, calculate the accuracy and give a threshold level for accuracy and allow the job to continue to deploy the model only if the accuracy is greater than 95% (or any other threshold).

Deploy the Docker Image on Cloud Run

Once the testing stage is finished with all test cases passed, our next step is to deploy the artifact or docker image. For deploying the docker image, I have used Cloud Run.

Deployment Stage (Photo by Author)

That’s all! Soon after executing this stage, the application will be in production.

Results

Now we have seen the entire workflow, let’s start creating our action. You can copy the workflow file from here.

Create the workflow (Photo by Author)

Click on Start commit and give a commit message. Commit the file. Go to the Actions section. You can see that the workflow has started to execute.

Actions section (Photo by Author)

After running all jobs successfully, you will see the following output. We can check the console output for each stage and we can also check the logs for debugging.

Workflow Output (Photo by Author)

Now if we go to the Container Registry, we can view the artifacts that got pushed.

Docker images on Container Registry (Photo by Author)

Go to Cloud Run under COMPUTE Section on GCP Navigation Menu. A service with the given name is created. The machine learning model is in production. You can access the service through the endpoint now!

The endpoint on Cloud Run Console (Photo b Author)

The final application (in my case) looks something like this:

Final StartUp Application (Photo by Author)

This workflow will get triggered every time you push the changes to code. This is a basic pipeline. You can build a pipeline with various stages — Getting Data through API calls, Perform Feature Engineering, Model Training, Building or storing models (artifacts), Testing, and Deploying to production.

The full code can be found on GitHub here.

Conclusion

We have seen the process of setting up a workflow that automates the deployment of a Machine Learning Application using GitHub Actions. It enables us to create our actions and combine them to create a workflow for any software application.

I’ll be happy to hear suggestions if you have any. I will come back with another intriguing topic very soon. Till then, Stay Home, Stay Safe, and keep exploring!

If you would like to get in touch, connect with me on LinkedIn.

--

--

Machine Learning | DevOps. I am a technology lover. I love building new applications-starting from things that I have learned, which come across my daily life.