This is a fully automated workflow for packaging and deploying a Machine Learning model. It includes Cloud infrastructure configuration with automation scripts and with Terraform, remote server provisioning with Ansible, and model packaging and deployment with Docker. It also includes a CI/CD pipeline for automatically packaging the model into a Docker container, pushing it to a GitHub Packages registry, and automatically deploying it on an AWS EC2 Webserver.
TABLE OF CONTENTS
- Operating System: all the commands and scripts run in this project are in Linux OS
- Terraform: Refer to the Terraform installation guide
- Ansible: Refer to the Ansible installation guide.
Also make sure you have openssh-server installed on your computer for Ansible to be able to SSH into the EC2 instance.
sudo apt install -y openssh-server
In order to be able to create and manage AWS resources you have to authenticate to your AWS account
-
AWS CLI installation: Refer to the AWS CLI installation guide
-
AWS authentication: Refer to the AWS Authentication with short-term credentials guide (this is the recommended authentication method)
Note: For conformity with this GitHub repository please choose "admin" as profile-name.
- Verify authentication: Once the authentication is complete, you can verify with the following command:
aws s3 ls --profile admin
Note: all of the actions performed in this repository are Free-Tier elligible
-
GitHub CLI installation: Refer to the GitHub installation guide
-
GitHub authentication: Refer to this GitHub authentication guide
In this repository, the whole workflow is fully automated, including the creation of the infrastructure, the provisioning of the remote server, and the building and deployment of the application running the model, all of which only needs 3 command: a terraform apply
, an ansible-playbook
and a git push
.
Note: to go in-depth on how every thing is set up, please check the next section Repository content in depth
To be able to enjoy the full potential of this repository and be able to run the GitHub Actions workflows (CI/CD pipeline), you need to fork the repository, this can be done in two mouse-clicks
And then
To be able to run the IaC scripts, you need to authenticate to AWS, and to be able to deploy the model using the CD you need authentication for the GitHub CLI. Please refer to the Authentication section.
Once you're authentication is done, you should be good to start!
The first thing to start with is to create our infrastructure, in particular this will run an AWS EC2 Instance (can be regarded as a Virtual Machine) with network and security configuration. (Refer to Content section for more in depth infromation)
To run the IaC with Terraform run the command:
make terraform-apply
In this step we will perform the necessary configurations to our EC2 Instance. In particular, we will run an update, we will install Docker and configure the GitHub Actions runner needed for the CD pipeline.
Run the following command so that Ansible can do all of this for us:
make ansible-all
you'll be prompted to enter your sudo password, since Ansible needs elevated privileges to run commands like update and install. Once this is done Ansible will fully configure the server for you.
Now that every thing is set, we can run our CI/CD pipline. What makes a CI/CD so powerfull is that it can be automatically triggered when we push changes to the repository (e.g. the application code has changed, new data has been introduced, etc.). To trigger a change let's run this simple echo command that will add text to a file:
echo "Time to Deploy" > trigger
Then all we need to do is push this change of state to our repository:
git add trigger
git commit -m "triggering our CI/CD pipeline"
git push -u origin main
In your GitHub repository go to "Actions"
You should see the workflow running
Don't hesitate to click on it and inspect the details!
Now everything is in place and anyone can browse to our webserver on port 8080 using the server's public IP address.
Run make ip
to retrieve the ip address of the server.
Run make curl
to curl the webserver for a prediction example.
Thanks to Terraform, destroying the infrastructure cannot be more easy.
make terraform-destroy
In this repository we offer two ways of running IaC, the first is using shell scripts, I would call this the rough way. The second is using Terraform, this is the easy yet better way of doing things.
Find the scripts under the automation/
directory.
automation/build_infra.sh
: builds the infrastructure on AWS
make auto-build
Check my medium article for a detailed step by step creation of the infrastructure on AWS.
automation/connect_to_instance.sh
: connects to the AWS EC2 instance previously created
make auto-connect
automation/set_node_address.sh
: adds the IP address of the EC2 instance to the list of hosts provisioned by ansible.automation/clean_infra.sh
: destroys the infrastructure previously created on AWS
make auto-clean
With Terraform things are way more easy and better organized, also we do not need to create any cleaning scripts as Terraform does that on our behalf: Terraform keeps track of the state of our infrastructure.
We create a Terraform module called ec2_instance
, that does all the network, security configuration and runs the EC2 instance.
Build the infrastructure:
make terraform-apply
Destroy the infrastructure:
make terraform-destroy
Ansible is a very powerfull tool, that automates provisioning, configuration management, orchestration and many other IT processes.
In this project we have two playbooks
- Instance configuration (see
ansible/playbooks/bootstrap.yml
andansible/playbooks/roles/docker
): runs an update on our instance, installs docker, and adds theubuntu
user to thedocker
group to be able to run Docker commands. (Requires elevated privileges)
make ansible-provision
- GitHub Actions runner configuration (see
ansible/playbooks/runner.yml
andansible/playbooks/roles/runner
): configures the self-hosted GitHub runner that runs the CD workflow.
make ansible-runner-config
We use Docker to containerize our Flask application, in order to easily deploy it on the AWS EC2 instance.
For this we use a simple Dockerfile located under the docker
subdirectory
- Build the image locally:
make docker-build
- Run the container locally:
make docker-run
- Stop the container:
make docker-stop
- Clean up:
make docker-clean
Note: You don't need to perform any of these actions when deploying the App on the Cloud, the CI/CD pipeline will take care of it.
We use GitHub Actions to automate the process of continuously building the application container and continuously deploying it on our Cloud Infrastructure.
The pipeline is defined in the file .github/workflows/main.yml
, it contains 2 separate jobs:
- the build job: Builds the docker image containing our Flask application, it then pushes it to the GitHub Packages registry.
- the deploy job: Pulls the Docker image from the GitHub Registry, and runs the container on our AWS EC2 instance.