From Code to Cloud: Building CI/CD Pipelines for Containerized Apps
Last Updated on March 4, 2024 by Editorial Team
Author(s): Afaque Umer
Originally published on Towards AI.
From Code to Cloud: Building CI/CD Pipelines for Containerized Apps
Introduction U+1F516
Imagine yourself as a Data Scientist, leaning in over your keyboard, sculpting Python scripts that decode the mysteries hidden within your dataset. Your algorithms hum with anticipation, your visualizations shimmer with insight, and youβre teetering on the edge of something truly remarkable. But hold on a moment β How do you share this ingenious code with the world? How can you ensure that your data science wizardry effortlessly reaches its intended audience?
Ah, the wild world of data science and machine learning, where algorithms roam free, and models hold the keys to unlocking the mysteries of the universe. But in this jungle of ones and zeros, there lies a crucial tool β MLOps
, the superhero of streamlined development and deployment.
At the heart of MLOps lies the mighty Continuous Integration and Continuous Deployment (CI/CD)
pipelines – the secret ingredients that morph your data science endeavors from local experiments into global phenomena. They make sure your models are ready for action without you lifting a finger.
So, In this blog, weβll demystify CI/CD, explore its role in data science, and discover how it can elevate your projects to new heights. Weβll learn how to tame the beast of CI/CD for our projects, using Streamlit to navigate the frontend (think of it as our trusty GPS), GitHub Actions to automate like clockwork, and Docker Hub for containerized deployments (because who doesnβt love a good container?).
But wait, thereβs more! Weβll even hitch a ride on Render, our free-of-charge hosting platform straight from the clouds. Itβs like getting a first-class ticket to the data science galaxy without breaking the bank U+1F4B8.
Here is an overview of the blogβs structure, outlining the specific sections that will provide a detailed breakdown of the process:
Setting up Streamlit Application
Dockerizing the Application
Set up GitHub Repository
Configure DockerHub
Deployment in Cloud
CI-CD Implementation
Step 1: Create Your Streamlit App U+1F525
Letβs embark on creating a straightforward Streamlit application; our goal is simplicity. Weβll kick things off by constructing a basic Quote of the Day
app leveraging the Forismatic API. Our initial focus will be on minimal functionality. Once weβve completed this initial build and hosted it, weβll move on to enhancing the layout in version 2. Then, weβll push our code to test the implementation of CI/CD. Hereβs the code for it U+1F447
Hereβs a preview of how the app will appear U+26A1
Now that we have the basic framework for our project, itβs time to initialize Git and set up a GitHub repository. But before diving into that, weβll need to dockerize our application to facilitate integration with the CI/CD pipeline. Letβs proceed to the next step.
Step 2: Dockerize Your App U+1F433
Since our app is fairly basic and doesnβt require many dependencies or volume considerations, our Dockerfile will be a breeze to set up. But hey, if youβre just dipping your toes into the Docker world, fear not! Iβve got you covered with a beginner-friendly article on Docker. Check it out for some handy tips and tricks!
Docker Essentials: A Beginnerβs Blueprint U+1F433
Upgrade your deployment skills with the Art of Containerization
pub.towardsai.net
This Dockerfile sets up a Python environment based on the Python 3.8 slim version, installs required dependencies from a requirements.txt file (here we have only one requirement streamlit), copies the project files into the container, and specifies the command to run the streamlit app.
Step 3: Commit, Push & Actions U+2699οΈ
Alright, itβs time to take the next step and push our code to a GitHub repository. To do this, Iβll create a new repository on GitHub and push our code to the main branch. Once thatβs done, Iβll set up an Actions file within the repository. This Actions file will essentially serve as our CI/CD pipeline. Whenever we push changes to the main branch, it will automatically trigger a series of actions. But before thatβ¦.
What is CI / CD?
Itβs a symphony that harmonizes development, testing, and deployment. Letβs break it down:
Continuous Integration (CI):
Imagine a backstage crew meticulously rehearsing your act. Thatβs CI. Whenever you push code to your repository (say, on GitHub), CI tools kick into action. They build your Python scripts, run tests, and ensure everything plays nicely together. If your code hits a sour note (bugs or errors), CI alerts you early, sparing you embarrassment during the grand performance. In a nutshell:
- Triggered on every push to the repository.
- Build your Docker image using a Dockerfile.
- Pushes the image to Docker Hub.
Continuous Deployment (CD):
Now, picture the curtains rising, the spotlight on you. Thatβs a CD. The CD takes your polished Python code and transforms it into a Docker image β a portable, self-contained package. Think of it as your data science show in a magical container. Next, CD whisks your Docker image to the cloud (weβll use Render as our stage). Your app is live, accessible via a URL, and ready for its audience. The workflow is like:
- Triggered after successful CI.
- Deploy the Docker image to your production environment (here Render, can be GCP, AWS, AZURE instance).
- Executes any necessary setup (e.g. pulling the latest image, starting containers).
Okay, now navigate to the Actions
tab in your GitHub repository. Here, youβll discover a variety of pre-designed templates tailored to different project requirements. For our specific needs, weβll opt for the Docker image template and tailor it accordingly. Itβs important to note the structure of Docker image naming convention, which typically follows the format: username/image-name:tag
. Here, the username
refers to your Docker Hub username, image-name
is the name of your image, and tag
is an optional version identifier for the image.
In our case, letβs name our image quotedaily
and assign it the version v1
(though this can be anything you prefer, serving as a tag for the image. It ensures that each time we build images on this branch, the new image will replace the previous one in the centralized repository). Hereβs a preview of our actions file:
The above configuration triggers on pushes to the main branch and pull requests targeting the main branch. It consists of a single job named build
(CI Pipeline)
that runs on an Ubuntu latest environment. Within the build
job, the steps include checking out the code, building a Docker image tagged as ${{ secrets.DOCKER_USERNAME }}/quotedaily:v1
, logging in to Docker Hub using secrets, and pushing the Docker image to Docker Hub.
However, once we build and commit this, the Actions file will run and fail because we havenβt configured the necessary environment variables in the repository secrets.
Additionally, we havenβt set up the repository in Docker Hub for this purpose. Therefore, letβs proceed to create the Docker Hub repository and configure the secrets in the next step.
Step 4: Set up Docker Hub and GitHub Secrets U+1F510
Alright, this step is quite straightforward. Youβll need to log in to Docker Hub and create a repository with the same image name as defined in the configuration file above. Letβs proceed by signing in and creating the repository.
Now that weβve created the repository on Docker Hub, itβs currently empty. To enable GitHub to push the Docker image to this repository, weβll need to store our Docker Hub account credentials securely in the GitHub repository secrets. This will allow GitHub to log in to Docker Hub and push the image weβve created to the repository. Letβs proceed by adding the credentials to the repository secrets.
Now that weβve configured all the secrets, itβs time to run the actions file. You can trigger the actions file by committing something to the main branch, or if there was a previous failed run, you can manually retry it from the Actions
tab.
Voila! All jobs, including the build and push steps, ran successfully. But did it really happen? Letβs verify by checking the Docker Hub repository.
Oh yeah, our latest image is right here. Alright, weβre almost there, the CI pipeline is complete.
Now, we just need a place to host our container for the end game. We have a range of options depending on requirements and scaling needs. For this demo, Iβm opting for a free hosting service, and Iβll be using Render
, an awesome cloud hosting service provider that supports Docker Hub. Letβs set that up in the next step.
Step 5: Deploy to Cloud Hosting U+2601οΈ
Here weβll utilize Render for hosting our application. Weβll start by creating a web service to host our Docker image. A crucial consideration is network mapping, our image will run a Streamlit app, which typically operates on port 8501 (In render I guess it does automatically though). Weβll define this port in the service settings. Since weβre using a public repository from Docker Hub, no credentials are required here. However, for private repositories, setting up a username and token for Docker Hub is necessary.
Step 1: Sign Up and select the Web Service
Step 2: Select the Image from Docker Hub that you want to Deploy
Step 3: Some more inputs U+1F911β¦.
Step 4: Deploy
and we are all done letβs hit the URL where the app is hosted:
And thatβs it! Itβs as easy as it gets. Now, take a look at the URL where itβs hosted, right below the image name. It may take a while, but once itβs ready, we can access our app directly from that URL. So, weβve successfully deployed and hosted our app end-to-end. But wait, weβve done this manually. What if we make changes in the main branch? Will the hosted app reflect these changes? Unfortunately, no. To update the hosted app, weβd need to manually deploy it again by selecting Manual Deploy
and choosing the latest reference. Alternatively, Render provides an API webhook that, when triggered, performs the update process in the background. We can integrate this into our GitHub Actions under the CD pipeline. Once the CI pipeline is complete, weβll run the deployment pipeline, fulfilling our destiny seamlessly.
Step 6: Building CD Pipeline U+27B0
Now, this step is quite similar to the previous one. We can locate the deploy hook URL in the settings of the Render web service. Next, weβll need to add this URL as another secret within GitHub Actions. Additionally, weβll create another job named deploy
that runs after our build
job completes. Adding secrets follows the same process as before. So, letβs edit the actions file accordingly. Hereβs the updated actions file U+26A1
Along with that, letβs make some modifications to the Streamlit code. This way, when the actions run again, weβll be able to determine whether our entire pipeline has worked successfully or not.
So once we are done with the commits and push the action will now have two job as pipeline U+1F447
How beautiful it looks! And now that our pipeline has run successfully, itβs time to check the ultimate prize. Letβs hit that URL and see if the app has truly been updated or if it was all just our fantasies.
Oh, how splendid! Here we are β our fully operational end-to-end CI/CD pipeline, meticulously crafted and thoroughly tested. And with that, itβs time to bid farewell.
Now, we have the power to code, commit, and serve β all in one plate. Alrighty, fellas, this has been a fun ride. But keep in mind, our journey doesnβt end here! This is just the beginning, akin to laying down the foundation. We can expand our setup by incorporating test cases, setting up monitoring pipelines, and more. Think of it as a set of Lego blocks, ready for you to assemble into magnificent structures. Thereβs endless potential waiting to be unlocked, so let your creativity flourish and build something remarkable!
Here is the link for the repo for reference:
GitHub – afaqueumer/quotedaily
Contribute to afaqueumer/quotedaily development by creating an account on GitHub.
github.com
I hope you enjoyed this article! You can follow me Afaque Umer for more such articles.
I will try to bring up more Machine learning/Data science concepts and will try to break down fancy-sounding terms and concepts into simpler ones.
Thanks for reading U+1F64F Keep learning U+1F9E0 Keep Sharing U+1F91D Stay Awesome U+1F918
Join thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming aΒ sponsor.
Published via Towards AI