Streamlining Flask App Deployment on GKE with Cloud SQL and a Secure Sidecar Proxy

Sarthak Kesarwani
Google Cloud - Community
9 min readJan 5, 2024

In the dynamic world of cloud-native application development, deploying a Flask web application to Google Kubernetes Engine (GKE) can be both a thrilling journey and a complex endeavor. This step-by-step guide is your compass, leading you through the intricate process of deploying a Flask app on GKE while harnessing the power of Google Cloud SQL and a Sidecar Proxy.

As we embark on this adventure, you’ll discover how to seamlessly containerize your Flask application, wield Google Kubernetes Engine for orchestration, and establish a robust database foundation using Google Cloud SQL. Along the way, we’ll unveil the magic of a Sidecar Proxy, enhancing the security and performance of our deployment.

Whether you’re a seasoned cloud engineer or a curious developer exploring new horizons, this guide will equip you with the knowledge and tools to confidently navigate the cloud-native landscape. By the end of this journey, you’ll have a Flask application soaring in the cloud, backed by the resilience of GKE and the reliability of Cloud SQL, all with the added magic of a Sidecar Proxy.

Let’s set sail on this exciting voyage and transform your Flask app into a cloud-native masterpiece!

Architecture Diagram

Before moving forward let us see what the prerequisites and which are steps we are going to follow:-

Prerequisites:-

  1. Google Cloud Platform (GCP) Account: You’ll need access to a GCP account. If you don’t have one, you can create a free trial account, which includes a $300 credit to get started.
  2. Docker: Have Docker installed on your local machine. Docker will be essential for containerizing your Flask application.
  3. Python and Flask: Familiarity with Python and Flask is assumed. Ensure you have Python installed, and consider setting up a virtual environment for your Flask project.
  4. Basic Kubernetes Knowledge: Basic knowledge of Kubernetes concepts will be helpful. You can get started with the Kubernetes Basics guide.
  5. Sidecar Proxy Understanding: Familiarize yourself with the concept of a Sidecar Proxy, as we’ll be using it to enhance the security and performance of our deployment.

With these prerequisites in place, you’ll be well-prepared to follow along with our step-by-step guide to deploying your Flask application to GKE with Cloud SQL and a Sidecar Proxy. Let’s embark on this exciting journey!

Steps:-

Develop Flask Application

Create a Docker Image for Flask App

Create a Private Cloud SQL instance

Setup Google Kubernetes Engine

Connecting GKE and Cloud SQL using sidecar proxy

Testing

Step1:- Develop Flask Application

1.1:- In the following article, I will be using a Flask application that Parwiz Forogh developed. I have made some changes to the application code to suit our requirements. You can either develop your application or proceed with the one I will be using.

Step2:- Create a Docker Image for the Flask App

Docker is a powerful tool for containerizing applications, making it easy to package your Flask application and its dependencies into a portable image. In this guide, we’ll walk through the steps to create a Docker image for your Flask application.

Before we can create a Docker image, ensure that you have the following:

  1. Your Flask application code.
  2. A requirements.txt file listing your application's dependencies.

2.1:- Create a Dockerfile

A Dockerfile is a script used to build a Docker image. Create a file named Dockerfile in the root directory of your Flask application, and add the following contents:

# Use the official Python image as the base image
FROM python:3.10-slim

# Install system dependencies
RUN apt-get update && \
apt-get install -y default-libmysqlclient-dev build-essential && \
apt-get clean && rm -rf /var/lib/apt/lists/*

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY requirements.txt .

# Install the Python dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy the rest of the application code into the container
COPY . .

# Expose port 5000 for the Gunicorn server
EXPOSE 5000

# Run the Flask app using Gunicorn
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

2.2:- Build the Docker Image

In the same directory as your Dockerfile, open a terminal and run the following command to build your Docker image:

docker build -t my-flask-app:v3 .

2.3:- Run the Docker Container

Once the image is built successfully, you can run a Docker container from it using the following command:

docker run -p 5000:5000 my-flask-app:v3

This command maps port 5000 (left one) on your local machine to port 5000 (right one) in the container. Adjust the ports as needed.

Your Flask application should now be accessible at http://localhost:5000 in your web browser.

That’s it! You’ve successfully created a Docker image for your Flask application. You can now deploy and distribute your application as a container.

Note:- To run this locally you need to install MySQL and also need to create a database and table as mentioned in step 3.5.

Containerized Flask app running on localhost:5000

2.4:- Export the image to the Docker Hub

Open a terminal and log in to your Docker Hub account using the docker login command:

docker login

Enter your DockerHub credentials and proceed to the next step.

Tag Your Docker Image: You must tag your local Docker image with the repository name on Docker Hub. Use the following command

docker tag my-flask-app:v3 your-dockerhub-username/your-repo-name:tag

Push the Docker Image to Docker Hub: Push your tagged image to Docker Hub using the docker push command:

docker push your-dockerhub-username/your-repo-name:tag
Verify the image on DockerHub

Step3:- Setup Private Cloud SQL Instance

It’s important to note that we are utilizing a Private Cloud SQL instance for our database. This choice enhances security by ensuring that the database is not exposed to the public internet. Instead, it’s accessible only from within the Google Cloud network, making it more resilient to potential security threats.

By combining the Cloud SQL Proxy as a sidecar container and a Private Cloud SQL instance, we’re prioritizing both security and ease of database access for our Flask application deployed in GKE. This setup ensures that our application can communicate with the database safely while running within the Google Cloud ecosystem.

3.1 Use Cloud Shell to enable Cloud SQL APIs:-

# Enable Cloud SQL API
gcloud services enable sql-component.googleapis.com

# Enable sqladmin API
gcloud services enable sqladmin.googleapis.com

3.2 Create the private MySQL instance. Click on Show Configuration Options.

Cloud SQL instance configuration

3.3 Under Connections fill in the details shown in the image below and Click Create Instance.

3.4 Create a service account with permission to access Cloud SQL by using the following commands on Cloud Shell.

gcloud iam service-accounts create sql-access

gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member "serviceAccount:sql-access@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role "roles/cloudsql.client"

gcloud iam service-accounts keys create credentials.json --iam-account=sql-access@YOUR_PROJECT_ID.iam.gserviceaccount.com

3.5 Create the database and table after connecting to the database. Use this doc to connect to a private SQL instance.

#after connecting to database, write the following commands on shell if
#you are using the application that I am using

create database flaskaws;

use flaskaws;

CREATE TABLE IF NOT EXISTS book (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
author VARCHAR(100) NOT NULL,
price FLOAT
);

Step4:- Setup Google Kubernetes Engine

Google Kubernetes Engine (GKE) is a powerful platform for deploying, managing, and scaling containerized applications. In this guide, we’ll walk you through the process of deploying a Flask application on GKE using Docker images from Docker Hub. We’ll create three essential Kubernetes manifest files: Deployment.yaml, Service.yaml, and ConfigMap.yaml.

In addition to the previous steps, we’ll also cover how to manage sensitive information using Kubernetes Secrets. These secrets can securely store data such as API keys, passwords, or confidential information. We will create a Secret.yaml file and integrate it into our GKE deployment.

Let's start with creating a GKE cluster

4.1:- Create a GKE cluster

#Run following commands in cloud shell

gcloud container clusters create-auto <your-cluster-name> \
--location=us-central1 \
--subnetwork=SUBNETWORK
--project=<Your=Project-ID>


gcloud container clusters get-credentials <your-cluster-name>
--region us-central1 --project <Your-Project-ID>

#Will be used to attach sql-access service account to cluster
kubectl create secret generic google-credentials\
--from-file=key.json=credentials.json

Note:- Make sure to have the GKE cluster and Cloud SQL in the same VPC network.

4.2:- Create Deployment.yaml

The Deployment.yaml file defines how your application will be deployed within the Kubernetes cluster. Create the file with the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: web
image: lexion6/flask-web-app:3.0
ports:
- containerPort: 5000
env:
- name: INSTANCE_HOST
valueFrom:
configMapKeyRef:
name: flask-app-config
key: INSTANCE_HOST
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: flask-app-config
key: DATABASE_PORT
- name: PORT
valueFrom:
configMapKeyRef:
name: flask-app-config
key: PORT
- name: DATABASE_NAME
valueFrom:
configMapKeyRef:
name: flask-app-config
key: DATABASE_NAME
- name: DATABASE_USERNAME
valueFrom:
secretKeyRef:
name: sql-credentials
key: username
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: sql-credentials
key: password
# [END cloudsql_secrets]
# Change <INSTANCE_CONNECTION_NAME> here to include your Google Cloud
# project, the region of your Cloud SQL instance and the name
# of your Cloud SQL instance. The format is
# $PROJECT:$REGION:$INSTANCE
# [START proxy_container]
- name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:latest
args:
- "-ip_address_types=PRIVATE"
command: ["/cloud_sql_proxy",
"-instances=<Your-instance-connection-name>=tcp:3306",
"-credential_file=/secrets/cloudsql/key.json"]
# [START cloudsql_security_context]
securityContext:
runAsUser: 2 # non-root user
allowPrivilegeEscalation: false
# [END cloudsql_security_context]
volumeMounts:
- name: cloudsql-instance-credentials
mountPath: /secrets/cloudsql
readOnly: true
# [END proxy_container]
# [START volumes]
volumes:
- name: cloudsql-instance-credentials
secret:
secretName: google-credentials
# [END volumes]
---

NOTE:- Make sure to replace the instance connection name in the Deployment.yaml file with your Cloud SQL instance connection name.

4.3:- Create Service. yaml

The Service.yaml file defines the Kubernetes Service that exposes your application using Load Balancer. Create the file with the following content:

apiVersion: "v1"
kind: "Service"
metadata:
name: "wordpress-service"
namespace: "default"
labels:
app: "wordpress"
spec:
ports:
- protocol: "TCP"
port: 80
targetPort: 5000
selector:
app: "wordpress"
type: "LoadBalancer"
loadBalancerIP: ""

4.4:- Create ConfigMap.yaml

The ConfigMap.yaml file is used to store your application's configuration data. Create the file with the following structure:

apiVersion: v1
kind: ConfigMap
metadata:
name: flask-app-config
data:
INSTANCE_HOST: "127.0.0.1"
DATABASE_PORT: "3306"
PORT: "5000"
DATABASE_NAME: "flaskaws"

4.5:- Create Secret. yaml

The Secret.yaml file allows you to define secrets that your application needs. Create the file with the following structure:

apiVersion: v1
kind: Secret
metadata:
name: sql-credentials
type: Opaque
data:
username: cm9vdA== #base64 encoded for "root"
password: cGFzc3dvcmQ= #base64 encoded for "password"

Make sure to replace <base64-encoded-username> and <base64-encoded-password> with the actual base64-encoded values of your database username and password.

4.6:- Deploy to GKE

Assuming you have configured the gcloud CLI and kubectl context for your GKE cluster, apply the configurations:

kubectl apply -f ConfigMap.yaml
kubectl apply -f Secrets.yaml
kubectl apply -f Deployment.yaml
kubectl apply -f Service.yaml

Step 5:- Connect GKE and Cloud SQL using sidecar proxy

Google recommends running the Cloud SQL Auth Proxy in a sidecar pattern (as an additional container sharing a pod with your application). They recommend this over running as a separate service for several reasons:

  • Prevents your SQL traffic from being exposed locally; the Cloud SQL Auth Proxy provides encryption on outgoing connections, but you need to limit exposure for incoming connections.
  • Prevents a single point of failure; each application’s access to your database is independent from the others, making it more resilient.
  • Limits access to the Cloud SQL Auth Proxy, allowing you to use IAM permissions per application rather than exposing the database to the entire cluster.
  • Allows you to scope resource requests more accurately; because the Cloud SQL Auth Proxy consumes resources linearly to usage, this pattern allows you to more accurately scope and request resources to match your applications as it scales.

Step 6:- Testing

Congratulations to all readers who have successfully followed the steps outlined in this blog post!

If you have any questions or need help with anything regarding the article or cloud in general, feel free to connect with me on LinkedIn.

I’d like to give a shoutout to my team at Guysinthecloud for all the support.

Thank You,
Sarthak Kesarwani

--

--