• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Dockerizing and Orchestrating Legacy Python Systems on Modern Google Cloud Infrastructure

Dockerizing and Orchestrating Legacy Python Systems on Modern Google Cloud Infrastructure

Containerizing the Legacy Python Application

The first critical step in modernizing a legacy Python application for cloud deployment is to containerize it. This involves creating a Dockerfile that encapsulates the application’s dependencies, runtime environment, and startup commands. For a typical Python web application, this often means installing system-level packages, Python dependencies via pip, and defining the entry point for the application server.

Consider a hypothetical legacy Flask application with a requirements.txt file and a simple WSGI entry point (e.g., app.py). The Dockerfile might look like this:

# Use an official Python runtime as a parent image
FROM python:3.8-slim

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container at /app
COPY requirements.txt /app/

# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# Copy the current directory contents into the container at /app
COPY . /app/

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

This Dockerfile:

  • Starts with a slim Python 3.8 base image for a smaller footprint.
  • Sets the working directory to /app.
  • Copies and installs dependencies from requirements.txt.
  • Copies the application code into the container.
  • Exposes port 80, assuming the application will listen on this port.
  • Sets a default environment variable (though this might be overridden later).
  • Specifies the command to run the application using Python.

For production deployments, it’s highly recommended to use a production-ready WSGI server like Gunicorn or uWSGI instead of the development server implied by python app.py. If using Gunicorn, the CMD instruction would change:

# ... (previous lines) ...

# Run Gunicorn to serve the Flask app
# Assuming 'app' is the Flask application instance in 'app.py'
CMD ["gunicorn", "--bind", "0.0.0.0:80", "app:app"]

After creating the Dockerfile, build the image:

docker build -t my-legacy-app:v1.0 .

And test it locally:

docker run -p 8080:80 my-legacy-app:v1.0

This will run the container and map host port 8080 to container port 80. You can then access your application at http://localhost:8080.

Pushing to Google Container Registry (GCR)

Once the Docker image is built and tested, it needs to be pushed to a container registry accessible by Google Cloud. Google Container Registry (GCR) is the standard choice. First, authenticate Docker with GCR:

gcloud auth configure-docker

Next, tag the local image with the GCR repository path. Replace [PROJECT-ID] with your Google Cloud project ID and [REGION] with your desired GCR region (e.g., us.gcr.io, eu.gcr.io, asia.gcr.io).

docker tag my-legacy-app:v1.0 [REGION]/[PROJECT-ID]/my-legacy-app:v1.0

Finally, push the tagged image to GCR:

docker push [REGION]/[PROJECT-ID]/my-legacy-app:v1.0

Orchestration with Google Kubernetes Engine (GKE)

For robust orchestration, scaling, and management, Google Kubernetes Engine (GKE) is the ideal platform. We’ll define Kubernetes manifests (YAML files) to deploy our containerized application.

Deployment Manifest

A Kubernetes Deployment manages stateless applications. It ensures that a specified number of pod replicas are running at any given time. Create a deployment.yaml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-legacy-app-deployment
  labels:
    app: my-legacy-app
spec:
  replicas: 3 # Start with 3 replicas
  selector:
    matchLabels:
      app: my-legacy-app
  template:
    metadata:
      labels:
        app: my-legacy-app
    spec:
      containers:
      - name: my-legacy-app
        image: [REGION]/[PROJECT-ID]/my-legacy-app:v1.0 # Replace with your GCR image path
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health # Assuming a /health endpoint exists
            port: 80
          initialDelaySeconds: 15
          periodSeconds: 20
        readinessProbe:
          httpGet:
            path: /health # Assuming a /health endpoint exists
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10

Key elements:

  • replicas: 3: Specifies that we want 3 instances of our application running.
  • image: Points to the Docker image stored in GCR.
  • containerPort: 80: The port the application listens on inside the container.
  • resources: Defines CPU and memory requests and limits. This is crucial for GKE scheduling and preventing resource starvation.
  • livenessProbe and readinessProbe: Essential for Kubernetes to manage the health of your application. The liveness probe tells Kubernetes when to restart a container, and the readiness probe tells Kubernetes when a container is ready to serve traffic. You’ll need to implement a simple /health endpoint in your Flask app for these to work.

Service Manifest

A Kubernetes Service provides a stable IP address and DNS name for a set of pods, acting as a load balancer. Create a service.yaml file:

apiVersion: v1
kind: Service
metadata:
  name: my-legacy-app-service
spec:
  selector:
    app: my-legacy-app # Matches the labels on the pods managed by the Deployment
  ports:
    - protocol: TCP
      port: 80 # The port the Service will be available on within the cluster
      targetPort: 80 # The port on the pods to forward traffic to
  type: LoadBalancer # Exposes the service externally using a cloud provider's load balancer

The type: LoadBalancer will instruct GKE to provision a Google Cloud Load Balancer, giving your application an external IP address.

Applying the Manifests

Ensure you have a GKE cluster running. You can create one using the `gcloud` CLI:

gcloud container clusters create my-gke-cluster --num-nodes=3 --zone=us-central1-a

Once your cluster is ready, configure kubectl to connect to it:

gcloud container clusters get-credentials my-gke-cluster --zone=us-central1-a

Now, apply your Kubernetes manifests:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

You can check the status of your deployment and service:

kubectl get deployments
kubectl get pods
kubectl get services

The output of kubectl get services will show an external IP address assigned to your my-legacy-app-service, which is the entry point to your application.

Advanced Considerations and Next Steps

This setup provides a solid foundation. For production, consider these enhancements:

  • Configuration Management: Move sensitive information (database credentials, API keys) out of the Docker image and into Kubernetes Secrets. Use ConfigMaps for non-sensitive configuration.
  • Database Migrations: Implement a strategy for running database migrations. This can be done via a Kubernetes Job that runs before the application deployment or by integrating migration logic into the application’s startup sequence (with careful handling to avoid race conditions).
  • Logging and Monitoring: Integrate robust logging (e.g., Fluentd/Fluent Bit to GKE’s Cloud Logging) and monitoring (e.g., Prometheus/Grafana or Cloud Monitoring).
  • CI/CD Pipeline: Automate the build, push, and deploy process using Cloud Build, Jenkins, GitLab CI, or GitHub Actions. This pipeline should trigger on code commits, build the Docker image, push it to GCR, and then update the Kubernetes Deployment (e.g., using `kubectl set image` or Helm).
  • Ingress Controller: For more advanced routing, SSL termination, and path-based routing, deploy an Ingress controller (like Nginx Ingress or GKE’s built-in Ingress) and use Kubernetes Ingress resources instead of a Service of type LoadBalancer.
  • Resource Optimization: Continuously monitor resource utilization and adjust CPU/memory requests and limits in your Deployment manifest.
  • Autoscaling: Implement Horizontal Pod Autoscaler (HPA) to automatically scale the number of application replicas based on CPU or custom metrics.

By following these steps, you can effectively containerize and orchestrate legacy Python applications on Google Cloud, leveraging the scalability, resilience, and manageability of modern cloud-native infrastructure.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Disaster Recovery 101: Architecting Auto-Failovers for Redis and PHP Deployments on OVH
  • How We Audited a High-Traffic WooCommerce Enterprise Stack on Google Cloud and Mitigated Race conditions during high-concurrency payment processing
  • Disaster Recovery 101: Architecting Auto-Failovers for Elasticsearch and Magento 2 Deployments on DigitalOcean
  • An Auditor’s Checklist for Securing WordPress Backends on OVH
  • Step-by-Step: Diagnosing Perl script high CPU throttling due to unoptimized regular expressions on AWS Servers

Copyright © 2026 · Vinay Vengala