Deploying Python 3.12 on Cloud Run with Cloud SQL Private Service Connect Using Terraform
Introduction:
In this post, we will walk through the steps required to provision Cloud SQL Private Service Connect (PSC) using Terraform, build a Python 3.12 Flask application, and deploy it on Google Cloud Run. The application will securely connect to a Cloud SQL PostgreSQL instance using the Cloud SQL Python Connector.
For more detailed instructions on provisioning Cloud SQL with Private Service Connect using Terraform, refer to this post on LinkedIn.
Prerequisites:
Step 1: Set Up the Flask Application
We'll be creating a simple Flask app that connects to a Cloud SQL PostgreSQL instance. Below is the main.py file that contains our application logic.
main py
import os
from flask import Flask
from google.cloud.sql.connector import Connector
import logging
app = Flask(__name__)
# Setup logger
logger = logging.getLogger("test_cloudsql")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# Initialize the connector
logger.debug("Initializing Cloud SQL connector.")
connector = Connector()
def get_connection():
try:
logger.debug("Attempting to connect to Cloud SQL PostgreSQL instance.")
# Create a connection to the Cloud SQL PostgreSQL instance using PSC
conn = connector.connect(
"<PROJECT-ID>:<REGION>:psc-instance", # Cloud SQL instance name
"pg8000",
user="<user>",
password="<password>",
db="<my-database>",
ip_type="psc"
)
logger.info("Successfully connected to the Cloud SQL instance.")
return conn
except Exception as e:
logger.error(f"Failed to connect to the Cloud SQL instance: {str(e)}")
raise
# Example: Query the database
def query_db():
try:
conn = get_connection()
cursor = conn.cursor()
try:
logger.debug("Executing SQL query to fetch PostgreSQL version.")
cursor.execute("SELECT version();")
result = cursor.fetchone()
logger.info(f"Query successful, result: {result}")
except Exception as e:
logger.error(f"Error executing SQL query: {str(e)}")
raise
finally:
cursor.close()
logger.debug("Closed the database cursor.")
conn.close()
logger.debug("Closed the database connection.")
return result
except Exception as e:
logger.error(f"Error during database query: {str(e)}")
raise
@app.route("/")
def hello_world():
"""Example Hello World route."""
name = os.environ.get("NAME", "World")
logger.debug(f"Handling request for '/' route, NAME={name}")
return f"Hello {name}!"
@app.route("/db-version")
def db_version():
"""Route to query and return database version."""
try:
logger.debug("Handling request for '/db-version' route.")
version = query_db()
return f"Database version: {version[0]}"
except Exception as e:
logger.error(f"Error while handling '/db-version' request: {str(e)}")
return f"Error querying database: {str(e)}", 500
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
logger.debug(f"Starting Flask application on port {port}.")
app.run(debug=True, host="0.0.0.0", port=port)
This app connects to a Cloud SQL PostgreSQL instance using the Cloud SQL Python Connector via Private Service Connect.
Step 2: Write the Dockerfile
Now, create a Dockerfile to containerize the application.
Dockerfile:
# Use an official Python runtime as the base image
FROM python:3.12-slim
# Set the working directory in the container
WORKDIR /app
# Copy the requirements file into the container
COPY requirements.txt .
# Install the required packages
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application code
COPY main.py .
# Optionally, copy service account credentials if not using Workload Identity
# COPY your-service-account-key.json /app/service-account-key.json
# ENV GOOGLE_APPLICATION_CREDENTIALS=/app/service-account-key.json
# Set the environment variable for the Cloud SQL instance connection name
# ENV INSTANCE_CONNECTION_NAME="<PROJECT-ID>:<REGION>:psc-instance"
# Run the application
CMD ["python", "main.py"]
Step 3: Define the Required Python Packages
Create a requirements.txt file with the necessary dependencies:
requirements.txt:
Flask
gunicorn
Werkzeug
pg8000
cloud-sql-python-connector
Step 4: Build and Push the Docker Image
To build and push the Docker image to Google Artifact Registry, follow these commands:
docker build -t quickstart-python:1.0.1 .
docker tag quickstart-python:1.0.1 us-central1-docker.pkg.dev/MY_PROJECT_ID/my-repo/quickstart-python:1.0.1
docker push us-central1-docker.pkg.dev/MY_PROJECT_ID/my-repo/quickstart-python:1.0.1
Make sure to replace MY_PROJECT_ID with your project ID.
Step 5: Deploy to Cloud Run
Once the Docker image is pushed, deploy the containerized application to Google Cloud Run using the following command. Ensure that the Cloud SQL instance has a VPC connector for private communication.
领英推荐
gcloud run deploy python-cloudsql-run \
--image us-central1-docker.pkg.dev/<PROJECT-ID>/my-repo/quickstart-python:1.0.1 \
--region=us-central1 \
--allow-unauthenticated \
--service-account=cloudsql-service-account-id@<PROJECT-ID>.iam.gserviceaccount.com \
--vpc-connector private-cloud-sql
This command will:
Conclusion
In this post, we successfully set up a Python 3.12 application on Cloud Run, connecting securely to Cloud SQL PostgreSQL instances using Private Service Connect. We also covered the essential Terraform steps for provisioning the Cloud SQL instances, and demonstrated how to containerize and deploy the application to Cloud Run.
By utilizing tools like Terraform, Docker, and Cloud SQL Python Connector, you can easily build scalable and secure applications on Google Cloud.
TEST
Source Code
Here on?GitHub.
References