
Continuous integration and Continuous delivery (CI/CD) is now becoming the norm in developing software applications. This popularity of CI/CD is because adopting CI/CD pipeline allows software projects to release more often without compromising quality. In addition, with the rising popularity of Kubernetes in orchestrating containers in a microservice architecture, the CI/CD pipeline usually involves steps related to deploying the apps to the Kubernetes cluster. Implementing the CI/CD pipeline, which consists in communicating to the Kubernetes cluster, is not a trivial task since there are multiple components in the Kubernetes cluster that you need to configure to work well with the CI tool.
This article will teach you how to implement the CI/CD workflows using GitHub actions with Vultr Kubernetes Engine.
GitHub action is a CI/CD tool created by GitHub, similar to Jenkins or GitLab CI, allowing you to deliver your app to a specific environment automatically. GitHub has many actions created by communities or organizations, so you can easily connect your existing technology stack with GitHub without the need to build your integrators.
Vultr Kubernetes Engine (VKE) is a Vultr-managed Kubernetes cluster. Managing and maintaining system resources for deploying the Kubernetes cluster takes time due to the complexity of Kubernetes. Moreover, to scale the Kubernetes cluster so your application can handle more user workload, you need to add more Kubernetes nodes. Adding nodes to the Kubernetes cluster is a costly initial investment for the software team. A product like Vultr Kubernetes Engine is the solution to these problems.
With Vultr Kubernetes Engine, you can quickly scale up and down the Kubernetes cluster the way you want. You also use the pay-as-you-go pricing method, so you only need to pay for what you use, not investing a lot of money to create multi-node Kubernetes clusters to deploy your app.
To understand how CI/CD workflow works and how to build the workflow to deploy your app to the Kubernetes cluster, let's create a completed CI/CD workflow for a movie management app. The steps for implementing the CI/CD workflow would be like below:
The movie management app is an API service. It will allow users to sign up and sign in to the app. Then from the access token the users got after signing in, they can add, update, read, and delete their movies through the app.
The movie management app stores data using MySQL database. Self-managing a MySQL database is complicated, and it takes time to maintain it. Let's use a Vultr MySQL database, then.
Create the Vultr MySQL database.
From the Vultr products page, click the "+" button to choose the resources you want to create. Then select "Add managed databases" to add a database. Choose the "MySQL" option and the server configuration and region for the MySQL database. Below is the minimum MySQL server configuration option that would satisfy the article scenario.
Then click the "Deploy" button and wait a few minutes for the database to be created. Vultr automatically created the admin account and default database for you.
Create a movie management database and new user in the Vultr MySQL database.
From the "Users & Databases" tab on the Vultr MySQL page:
Get the database connection info.
From the overview page of the created Vultr MySQL database, you can see the connection details for your database. The example values for this article are as below:
Create tables in the movie management database
For the movie management app to work, you must create two tables: user_info and movie. Access the movie management database from your machine using the command line below:
Show the list of current databases by executing the below command:
You should see the "movie_management" database in the result:
Use the "movie_management" database by running the following code:
Create a new user_info table by executing the following sql code:
Create a new movie table with the following sql code:
Now that you have finished creating the Vultr MySQL database for storing movie management app data. Let's move on to create a Vultr Kubernetes Engine.
Add a new Vultr Kubernetes Engine cluster.
From the Vultr Product page, click "+" button and choose "Add Kubernetes". The example values for the Vultr Kubernetes Engine in this article are:
Click "Deploy Now" and wait a few minutes for Vultr finishes creating a new Vultr Kubernetes Engine. Once the VKE is ready to use, click the "Download Configuration" button to download the Kubernetes configuration file. The example file for Kubernetes configuration is: "vke-d77dc163-b45d-436a-ab4b-e75b921581fa.yaml".
Connect to Vultr Kubernetes Engine.
Open your terminal in the VKE configuration file's directory, then execute the following command to create an environment variable for KUBECONFIG.
Using kubectl to get node information:
You should be able to see similar output as below:
You have now finished adding a new Vultr Kubernetes Engine. Let's move on to implementing the movie management app.
You will implement the movie management app using FastAPI and Python. Let's create a new directory to store the application code.
Install the needed dependencies to implement the app.
Create a requirements.txt file that stores all the dependencies you need to implement the app.
Copy the following content into the requirements.txt file:
Create a new Python virtual environment to isolate your machine's movie management app dependencies with other Python projects.
Activate the virtual environment using:
Install all the required dependencies from requirements.txt file using the following:
Create app_utils.py file.
The app_utils.py file is for implementing utility functions. When authorizing the user credential, you will define the functions for encoding and decoding access tokens.
Create app_utils.py and open it using the following:
Add the following content to it:
Create crud.py file.
The crud.py file defines methods that allow the app to interact with the MySQL database to create, edit, retrieve, and delete data.
Create and open crud.py by running:
Copy the following content to crud.py file:
Create database.py file.
The database.py file defines the configuration values to connect to the MySQL database. Create and open database.py file using the following:
Copy the following content to database.py file:
Create models.py file.
The models.py file is for creating classes that correspond to the MySQL database tables so that you can interact with the movie management database tables.
Create and open models.py file:
Copy the following content to models.py file:
Create schemas.py file.
The schemas.py file defines Python classes so that you can conveniently interact with the request and response body of the APIs the app will create.
Create and open schemas.py file using the following:
Copy the following content to schemas.py file:
Create main.py file.
The main.py is the entry point of the application. You will create the application APIs inside this file.
Create and open main.py file:
Copy the following content to it:
Create a Dockerfile file.
A Dockerfile file defines steps for building a Docker image for the movie management app. You will work with the Docker image later when implementing the CI/CD workflow.
Create and open Dockerfile by running:
Copy the following content to Dockerfile:
Now that you finished implementing the movie management app. Let's move on to see how to run the app in the local environment and try to interact with the functionalities that the app provides.
From the current terminal, run the following commands to define environment variables for the app to connect with the MySQL database:
Run the following command to bring up the app:
You should see the app is up and running with the output below:
Open a new terminal, then try to create a new user using curl:
You should see the output showing a new user has been created.
Authenticate the user to get the access token so that you can add a new movie later.
The output should look like as:
Let's add a new movie using the access token above for authentication.
The output should look similar to the below:
You have finished implementing the movie management app in the local environment. Let's move on to how to write the application's unit test.
Create and open a new file named test_unit.py:
Copy the following content to the test_unit.py file:
Here you have a test that checks whether the app can decode the encoded token correctly. To run the test from your terminal, execute the following command:
You should see the result as passed.
FastAPI provides easy support for implementing integration tests using the TestClient.
Copy the following content to the file.
Here you check whether the response status code of the authentication API is 200 if you provide the correct user credentials.
Let's run the test using pytest. Note that the app needs to connect with the actual database since you run the integration test. You need to define the environment variables before running the test.
You should see the result as "pass". Now you successfully implemented the unit test and integration test for the app. Let's move on to create a cluster role in the Vultr Kubernetes Engine to set up the integration between GitHub actions and VKE.
From the folder where you have saved the VKE configuration file, create a file named clusterrole.yaml.
Please copy the following content to it.
Run the following command to create a cluster role:
You should see a message that Kubernetes created a new cluster role.
From the terminal, run the following command to create a new service account named github-actions-kubernetes-vultr.
You should see that Kubernetes has created a new service account named github-actions-kubernetes-vultr. Then you create a ClusterRoleBinding to bind the continuous-deployment role to github-actions-kubernetes-vultr:
Run the following command to see details of the service account information:
You should see a similar output below:
After having the service account with role biding for accessing the Kubernetes cluster, you need to create a secret for the service account. You will later use this secret in the GitHub workflow definition to allow GitHub action to set the Kubernetes context to deploy to Kubernetes. Create a new file named secret-service-account.yaml to store the definition for the secret.
Copy the following content to the file:
Run the following command to create a secret for the service-account:
Get the yaml output of the secret you have just created above:
The output should look similar as below:
Create a new GitHub action secret named KUBERNETES_SECRET in the GitHub actions secret page, and copy the above content from yaml output to the secret. You will use this KUBERNETES_SECRET later in the GitHub workflow file.
Go to your GitHub developer settings page, then create a new GitHub token that has the permission to "read:packages", so that Kubernetes can pull the image from the GitHub container registry. Container registry later on. After having the GitHub token created, you create a secret using the command below:
The output should show Kubernetes has successfully created a new secret named github-container-registry. You will use this secret in the Kubernetes deployment yaml file later.
The movie management application requires environment variables for DB_HOST, DB_NAME, DB_USERNAME, DB_PASSWORD, DB_PORT to run. You need to create a secret file for defining these environment variables so that the Kubernetes deployment process will use these secret values later on when creating the Kubernetes pod. You need to encode each environment value using base64 encode method first. For example, below is the command to encode "example" value using base64:
You should see the similar result as:
Then create a new file named secret-as-environment-variable.yaml.
Copy the following content and replace the values of secrets with values of your secrets in base64 encoded format.
Then run the following command to create the secret:
You should see the message showing Kubernetes has created the secret named mysecret.
You have successfully prepared the secrets, cluster role, and service account for Kubernetes to interact with GitHub actions. Let's create a GitHub action workflow. Go to your local project, and create a folder named .github. Inside .github folder, create a folder named workflows.
Inside the workflows folder, you create a workflow definition file named movie-management-vultr.yaml.
Copy the following content to it.
The GitHub action will trigger this workflow if you push new code to the repository. Inside this workflow, you have the secrets as DB_HOST, DB_NAME, DB_USERNAME, DB_PASSWORD, DB_PORT. You use these secrets when running the test before deploying it to Kubernetes. Create five more new secrets with the actual value of the movie-management database.
You also have another secret for GH_TOKEN. You need the GitHub token to push the new container image to the GitHub container registry. You must create another GitHub token with permission for repo, write:packages. Then add a new action secret named GH_TOKEN, and put the value of the GitHub token you created in it.
You already created the secret for KUBERNETES_SECRET in the step "Create a secret for the service account to store GitHub token, " so please ignore it.
Let's create a deployment file to deploy the app to Kubernetes. Go to your local project, then create a folder named kubernetes.
Inside the kubernetes folder, create a file named deployment.yaml.
Copy the following content to it. Remember to replace the container image ghcr.io/cuongld2/vultr-cicd-githubactions:latest with your actual value.
Create a new GitHub repository, and then you push your local project to that GitHub repository in the main branch. The workflow should automatically run with successful results for all stages: test, build, and deploy.
After the GitHub workflows is finished, open the terminal in your local machine to get the Kubernetes pod.
You should see similar output as:
The application is now up and running in Kubernetes. Let's try to interact with the app from the local environment. To do that, you need to forward the app's port inside the Kubernetes cluster to the local port using the below command. Note that you need to replace the pod name with your actual one.
You should see the similar output as below:
Let's use the authenticate API of your app to authenticate the user to see whether the deployed app is working.
You should see similar output as:
The app is working as fine. You have finally completed implementing the CI/CD pipeline triggered to deploy the app to the Vultr Kubernetes cluster.
Through the article, you have learned about how CI/CD pipeline works and have hands-on practice deploying your application to the Vultr Kubernetes cluster with the help of GitHub actions. To learn more about deploying CI/CD pipeline to Kubernetes cluster with different examples, check out other interesting Vultr articles.
0 Comments
Be the first to comment and share your perspective with the community.