Day 7 - Deploying a Python Application to App Engine using Google Cloud Build (CI/CD)

Day 7 - Deploying a Python Application to App Engine using Google Cloud Build (CI/CD)

Nowadays, automating software delivery is important to ensure efficiency and faster time to market. Continuous Integration and Continuous Deployment (CI/CD) helps us streamline this automation process by automating code building, testing and deployment.
In this article, we’ll look into setting up a simple CI/CD pipeline for a simple Flask (Python) app using Google Cloud Build. This pipeline will automatically build, test, and deploy the application to Google App Engine.
The source code for this project can be found in this GitHub repo under the Day_7 folder.

Prerequisites

  1. Python 3.x

  2. Google Cloud Project with Cloud Build API and App Engine enabled

  3. gcloud CLI installed locally on your computer

Setting up:

  1. Create a Google Cloud Project and verify that Billing has enabled.

  2. Download, install and configure gcloud CLI on your computer (instructions)

  3. Create a folder you’ll be working in and create & activate a Python virtual environment we will use to install dependencies for our project:

      $ python -m venv venv
    
      # Activate the virtual environment
      $ venv\Scripts\activate # For Windows
    
      $ source venv/bin/activate # For MacOS/UNIX
    
  4. Create a requirements.txt file and add the following

     Flask==3.1.0
    
  5. Install the dependencies in your activated virtual environment

      (venv)$ pip install -r requirements.txt
    
  6. Create a file called main.py and paste the following code:

     from flask import Flask
    
     app = Flask(__name__)
    
     @app.route('/')
     def home():
         return 'Welcome to Jumanji!'
    
     if __name__ == '__main__':
         app.run(host='0.0.0.0', port=8080)
    

    Script explanation:

    The script above uses Flask, a web framework for building web applications.
    app = Flask(__name__) creates an instance of our Flask application. The __name__ argument refers to the name of the current Python module

    @app.route(“/”) defines the route for our root URL of our web app.
    The home() method is responsible for returning us the output when we visit the route defined above.

  7. Create a file called test_main.py and paste the following code:

     import unittest
     from main import app
    
     class AppTestCase(unittest.TestCase):
         def setUp(self):
             self.app = app.test_client()
             self.app.testing = True
    
         def test_home(self):
             response = self.app.get('/')
             self.assertEqual(response.data, b'Welcome to Jumanji!')
    
     if __name__ == '__main__':
         unittest.main()
    

    Script explanation:

    The script above imports and uses unittest, a testing framework that provides a set of tools for testing the bits of our Python code.
    The test will visit the route defined (‘/’) and check if the output would be equal to ‘Welcome to Jumanji!’. If the output is the same, the test passes, and fails if not.

  8. Create a file called cloudbuild.yaml and paste the following. Remember to replace <PROJECT_ID> with your Google Cloud Project ID:

     steps:
       # Install dependencies
       - name: 'python:3.10'
         entrypoint: 'bash'
         args:
           - '-c'
           - |
             pip install -r requirements.txt
             echo "Dependencies installed."
    
       # Run tests
       - name: 'python:3.10'
         entrypoint: 'bash'
         args:
           - '-c'
           - |
             python -m unittest test_main.py
             echo "All tests completed"
    
     images:
       - 'gcr.io/<PROJECT_ID>/Deploy-App-to-AppEngine-CloudBuild'
    

    The YAML file above contains the configurations needed for our app’s deployment to Google Cloud.

  9. Create a file called app.yaml. This is an important configuration file that’s used when deploying an application to Google App Engine. It defines key deployment settings, including the runtime environment, environment variables etc. Paste the following:

     runtime: python310
    
     handlers:
       - url: /.*
         script: auto
    
  10. Next, we’re going to create the .gcloudignore file. This file is used to specify files and directories that should be excluded from deployment when using gcloud commands. It functions similarly to .gitignore; but specifically for Google Cloud SDK to prevent unecessary or sensitive files from being uploaded to Google Cloud services.

    # This file specifies files that are *not* uploaded to Google Cloud
    # using gcloud. It follows the same syntax as .gitignore, with the addition of
    # "#!include" directives (which insert the entries of the given .gitignore-style
    # file at that point).
    #
    # For more information, run:
    #   $ gcloud topic gcloudignore
    #
    .gcloudignore
    # If you would like to upload your .git directory, .gitignore file or files
    # from your .gitignore file, remove the corresponding line
    # below:
    .git
    .gitignore
    
    # Python pycache:
    __pycache__/
    # Ignored by the build system
    /setup.cfg
    .venv/
    
  11. Run the project locally and visit http://127.0.0.1:8080 on your browser

     (venv)$ python main.py
    

    Results on the browser 👇

  12. Deploy the app

    In your terminal, run the following command:

$ gcloud app deploy

The output will request if you’d like to continue with the deployment, type Y and hit Enter

After the deployment is successful, your terminal’s output will look something like this

  1. Navigate to Cloud Build page on Google Cloud Console. Click on History on the left panel. Select the region you deployed your app and your build(s) will show up.

    Click on the Buiid number to see the Build details like logs, details and artifacts.

  2. Viewing our application
    Navigate to App Engine page on the Google Cloud Console. Click on Services on the left panel and you will see ‘default’ service listed there

Click on the ‘default’ name and a new tab will open on your browser with your deployed application

Congratulations! You’ve deployed your application to App Engine using Cloud Build (CI/CD)

Conclusion

Implementing CI/CD pipelines streamline the development workflow by automating build, test, and deployment processes. Our setup is even more seamless with the integration with Google App Engine, reducing manual intervention.