Skip to content

Commit 347802b

Browse files
Refactor Django on GCP learning path content for clarity and consistency
1 parent d99d028 commit 347802b

10 files changed

Lines changed: 126 additions & 81 deletions

File tree

content/learning-paths/servers-and-cloud-computing/django-on-gcp/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Deploy Django on Google Cloud C4A (Arm-based Axion VMs)
2+
title: Deploy Django on Arm-based Google Cloud C4A
33

44
minutes_to_complete: 60
55

content/learning-paths/servers-and-cloud-computing/django-on-gcp/background.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Get started with Django on Google Axion C4A (Arm Neoverse V2)
2+
title: Get started with Django on Google Axion C4A
33

44
weight: 2
55

content/learning-paths/servers-and-cloud-computing/django-on-gcp/baseline.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ weight: 6
66
layout: learningpathall
77
---
88

9-
## Verify Django is working on your Arm-based VM
9+
## Verify Django installation
1010

1111
In this section, you'll confirm that Django is installed correctly and can serve web requests on your Google Cloud C4A VM. You'll create a Django project, run the development server, and access it from your browser.
1212

content/learning-paths/servers-and-cloud-computing/django-on-gcp/benchmarking.md

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ This section guides you through benchmarking your Django web application using G
1414

1515
To begin, if your Django development server is still running, stop it using `Ctrl + C`.
1616

17+
Install ApacheBench to measure your application's performance under load.
18+
19+
```bash
20+
sudo zypper install -y apache2-utils
21+
```
22+
23+
Verify the installation:
24+
25+
```bash
26+
ab -V
27+
```
28+
29+
You should see the ApacheBench version information displayed.
30+
31+
1732
ApacheBench (`ab`) is a command-line tool that simulates multiple HTTP requests to measure web server performance. Install it using the following:
1833

1934
```bash
@@ -22,7 +37,7 @@ sudo zypper install -y apache2-utils
2237

2338
### Verify installation
2439

25-
Confirm ApacheBench is correctly installed and available:
40+
Confirm ApacheBench is correctly installed and available.
2641

2742
```bash
2843
ab -V
@@ -34,19 +49,19 @@ The output displays the ApacheBench version.
3449

3550
Before benchmarking your Django application, you need to install Gunicorn, a production-grade WSGI HTTP server. Gunicorn provides better performance characteristics than Django's development server and more accurately represents real-world deployment scenarios.
3651

37-
### Install both Django and Gunicorn using pip:
52+
### Install both Django and Gunicorn using pip
3853

3954
```bash
4055
python3 -m pip install django gunicorn
4156
```
4257

43-
This installs Django and Gunicorn. Gunicorn is a high-performance WSGI HTTP server that handles multiple concurrent requests efficiently. Unlike Django's built-in development server, Gunicorn is designed for production workloads and provides the multi-worker architecture needed for accurate performance testing.
58+
This installs Django and Gunicorn. Gunicorn is a production-grade WSGI HTTP server that handles multiple requests at the same time. Unlike Django's built-in development server, Gunicorn uses multiple workers to process requests efficiently, which gives you more accurate performance measurements.
4459

4560
## Run Django with Gunicorn
4661

47-
Your Django application runs with Gunicorn inside GKE. Gunicorn is deployed inside your Kubernetes Pods and exposed through a Kubernetes Service and LoadBalancer. The benchmark is executed against the external IP of the GKE service.
62+
Your Django application runs with Gunicorn inside GKE. The Gunicorn server is deployed inside your Kubernetes Pods and exposed through a Kubernetes Service and LoadBalancer. You run the benchmark against the external IP of the GKE service.
4863

49-
{{% notice note %}}Ensure your GKE cluster and LoadBalancer are properly configured. If you haven't set up the cluster yet, refer to the previous sections for GKE deployment and service configuration. {{% /notice %}}
64+
{{% notice Note %}}Ensure your GKE cluster and LoadBalancer are properly configured. If you haven't set up the cluster yet, refer to the previous sections for GKE deployment and service configuration.{{% /notice %}}
5065

5166
## Run the benchmark
5267

@@ -56,9 +71,16 @@ Use ApacheBench to test your Django server with simulated traffic:
5671
ab -n 5000 -c 100 http://<external_IP_of_the_GKE_service>/healthz/
5772
```
5873

59-
This sends 5000 requests using 100 concurrent connections to your Django REST endpoint exposed through the GKE LoadBalancer. After a few minutes, press CTRL-C to stop the benchmark.
74+
This command sends 5000 requests with 100 concurrent connections to your Django REST endpoint.
75+
76+
Parameters explained:
77+
- `-n 5000`: total number of requests to send
78+
- `-c 100`: number of concurrent requests
79+
- `http://<external_IP_of_the_GKE_service>/healthz/`: your Django health check endpoint
80+
81+
Replace `<external_IP_of_the_GKE_service>` with your actual GKE LoadBalancer IP address.
6082

61-
The output is similar to:
83+
The benchmark runs for a few seconds and displays results similar to:
6284

6385
```output
6486
Server Software: gunicorn
@@ -103,24 +125,32 @@ The ApacheBench output provides key performance metrics for evaluating your Djan
103125

104126
### Request handling metrics
105127

106-
- Concurrency Level: number of simultaneous requests the benchmark sent (100 in this test)
107-
- Complete Requests: total successful requests processed (5000 in this test)
108-
- Failed Requests: number of errors or timeouts (0, indicating stable production-grade performance)
128+
Your benchmark captures three foundational indicators of request handling capacity:
129+
130+
- Concurrency Level: simultaneous requests sent during the benchmark (100)
131+
- Complete Requests: total successful requests processed (5000)
132+
- Failed Requests: errors or timeouts encountered (0, indicating stable performance)
109133

110134
### Performance metrics
111135

136+
Your Django application's performance under load is measured by three critical metrics:
137+
112138
- Requests per Second: how many requests your server handles per second; higher values indicate better throughput (14,001.88 req/sec)
113139
- Time per Request (mean): average time to complete a single request (7.142 ms)
114140
- Time per Request (across concurrent): average latency when factoring in concurrent processing (0.071 ms), showing excellent parallel execution on Axion Arm cores
115141

116142
### Data transfer metrics
117143

144+
The benchmark captures how efficiently your application transfers data across the network stack:
145+
118146
- Total Transferred: all data sent and received, including HTTP headers (1,650,000 bytes)
119147
- HTML Transferred: actual response payload size (75,000 bytes)
120148
- Transfer Rate: network throughput in KB/sec (4512.32 KB/sec), indicating efficient networking through GKE LoadBalancer
121149

122150
### Timing breakdown
123151

152+
The timing breakdown section provides detailed insight into how your application spends time processing each request:
153+
124154
- Time Taken for Tests: total benchmark duration (0.357 seconds)
125155
- Connection Times: shows minimum, mean, median, and maximum times for connecting, processing, and waiting
126156

@@ -134,33 +164,46 @@ Results from the run on the `Axion (C4A) Arm64 GKE nodes`:
134164

135165
| **Parameter** | **Description** | **Value** |
136166
|--------------|------------------|-----------|
137-
| **Server Software** | Web server used for serving Django | gunicorn |
138-
| **Server Hostname** | External LoadBalancer IP | 34.132.110.81 |
139-
| **Server Port** | Port number for benchmark | 80 |
140-
| **Document Path** | Endpoint used for testing | /healthz/ |
141-
| **Document Length** | Size of each response | 15 bytes |
142-
| **Concurrency Level** | Number of concurrent requests | 100 |
143-
| **Time Taken for Tests** | Total time to complete all requests | 0.357 seconds |
144-
| **Complete Requests** | Total number of successful requests | 5000 |
145-
| **Failed Requests** | Number of failed requests | 0 |
146-
| **Total Transferred** | Total bytes transferred (including headers) | 1,650,000 bytes |
147-
| **HTML Transferred** | Total response body bytes | 75,000 bytes |
148-
| **Requests per Second (mean)** | Throughput - higher is better | **14,001.88 req/sec** |
149-
| **Time per Request (mean)** | Average time for each request | **7.142 ms** |
150-
| **Time per Request (across all concurrent requests)** | Average latency considering concurrency | **0.071 ms** |
151-
| **Transfer Rate** | Network throughput rate | **4512.32 KB/sec** |
167+
| **Server Software** | web server used for serving Django | gunicorn |
168+
| **Server Hostname** | external LoadBalancer IP | 34.132.110.81 |
169+
| **Server Port** | port number for benchmark | 80 |
170+
| **Document Path** | endpoint used for testing | /healthz/ |
171+
| **Document Length** | size of each response | 15 bytes |
172+
| **Concurrency Level** | number of concurrent requests | 100 |
173+
| **Time Taken for Tests** | total time to complete all requests | 0.357 seconds |
174+
| **Complete Requests** | total number of successful requests | 5000 |
175+
| **Failed Requests** | number of failed requests | 0 |
176+
| **Total Transferred** | total bytes transferred (including headers) | 1,650,000 bytes |
177+
| **HTML Transferred** | total response body bytes | 75,000 bytes |
178+
| **Requests per Second (mean)** | throughput - higher is better | **14,001.88 req/sec** |
179+
| **Time per Request (mean)** | average time for each request | **7.142 ms** |
180+
| **Time per Request (across all concurrent requests)** | average latency considering concurrency | **0.071 ms** |
181+
| **Transfer Rate** | network throughput rate | **4512.32 KB/sec** |
152182
| **p50 (Median Latency)** | 50% of requests completed within | **6 ms** |
153183
| **p90 Latency** | 90% of requests completed within | **11 ms** |
154184
| **p95 Latency** | 95% of requests completed within | **11 ms** |
155185
| **p99 Latency** | 99% of requests completed within | **28 ms** |
156-
| **Max Latency** | Longest request observed | **34 ms** |
186+
| **Max Latency** | longest request observed | **34 ms** |
157187

158188
## Key performance insights
159189

160190
The benchmark results demonstrate the strength of running Django on Google Axion (Arm64) GKE:
161191

162-
- Extreme Throughput: The cluster sustained 14,000+ requests per second through a public LoadBalancer → GKE → Gunicorn → Django → Cloud SQL → Redis stack.
163-
- Ultra-Low p95 Latency: Even at 100 concurrent users, 95% of all requests completed within 11 ms.
164-
- Production Stability: Zero failed requests confirms the platform is resilient under heavy parallel load.
165-
- Efficient Networking: Over 4.4 MB/sec of data transfer through the GKE LoadBalancer shows Arm-based networking is highly optimized.
166-
- Cloud-native Scalability: These results validate that Axion Arm64 nodes are well-suited for high-performance, horizontally scalable REST APIs in production.
192+
- Extreme Throughput: the cluster sustained 14,000+ requests per second through a public LoadBalancer → GKE → Gunicorn → Django → Cloud SQL → Redis stack.
193+
- Ultra-Low p95 Latency: even at 100 concurrent users, 95% of all requests completed within 11 ms.
194+
- Production Stability: zero failed requests confirms the platform is resilient under heavy parallel load.
195+
- Efficient Networking: over 4.4 MB/sec of data transfer through the GKE LoadBalancer shows Arm-based networking is highly optimized.
196+
- Cloud-native Scalability: these results validate that Axion Arm64 nodes are well-suited for high-performance, horizontally scalable REST APIs in production.
197+
198+
## What you've accomplished and what's next
199+
200+
In this section, you:
201+
- Installed and configured ApacheBench for load testing
202+
- Deployed Gunicorn as a production-grade WSGI server for Django
203+
- Executed a comprehensive benchmark against your GKE-hosted Django application
204+
- Analyzed performance metrics showing 14,000+ requests per second with sub-millisecond concurrent latency
205+
- Validated that Google Axion (Arm64) GKE delivers production-ready performance for Django workloads
206+
207+
Your Django application is now proven to handle high-concurrency traffic efficiently on Arm-based infrastructure. You've established a performance baseline that demonstrates the scalability and reliability of running Django on Google Cloud's Axion processors with GKE, Cloud SQL, and Redis.
208+
209+
You're ready to optimize further, scale your deployment, or integrate additional services into your cloud-native Django architecture.

content/learning-paths/servers-and-cloud-computing/django-on-gcp/containerization-and-deploy.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ layout: learningpathall
88

99
## Containerize and deploy Django on Axion GKE
1010

11-
This guide converts your Django REST API into a production-grade Arm64 container and deploys it on Axion-powered GKE.
11+
This section shows you how to package your Django REST API into a production-ready container and deploy it on GKE running Axion Arm64 processors.
12+
13+
## Create a Docker image
1214

13-
### Create Docker image
1415
This step packages your Django API and all its dependencies into a portable container image that can run on any Axion Arm64 node.
1516

1617
Create a file called `requirements.txt` and insert the following:
@@ -35,7 +36,7 @@ CMD ["gunicorn","django_api.wsgi:application","--bind","0.0.0.0:8000","--workers
3536

3637
This Dockerfile defines how to build your Django container for production deployment.
3738

38-
### Build and push the image
39+
## Build and push the image
3940

4041
Build the image on an Arm machine and push it to Artifact Registry, ensuring Kubernetes pulls an Arm-native image.
4142

@@ -55,7 +56,7 @@ docker push us-central1-docker.pkg.dev/PROJECT_ID/django-arm/api:1.0
5556

5657
The image is now stored in Artifact Registry and ready for deployment.
5758

58-
### Deploy to GKE
59+
## Deploy to GKE
5960

6061
Kubernetes Deployments define how many containers run and where. The nodeSelector forces pods onto Axion ARM64 nodes.
6162

@@ -115,7 +116,8 @@ django-api-XXXXXX 1/1 Running 0 3h52m 10.0.1.9 gke-django-a
115116

116117
The Django API is running as replicated containers on Axion Arm64 nodes.
117118

118-
### Create a Kubernetes service (LoadBalancer)
119+
## Create a Kubernetes service (LoadBalancer)
120+
119121
A Service exposes your pods to the internet using **Google Cloud’s managed load balancer**.
120122

121123
Create `k8s/service.yaml`:
@@ -140,7 +142,7 @@ Apply the service configuration:
140142
kubectl apply -f k8s/service.yaml
141143
```
142144

143-
### Validate public access
145+
## Validate the service
144146

145147
```bash
146148
kubectl get svc django-api
@@ -153,7 +155,7 @@ django-api LoadBalancer 34.118.226.245 34.45.23.92 80:31700/TCP 3h57m
153155

154156
Wait until the `EXTERNAL-IP` field is populated before proceeding.
155157

156-
### Validate public access
158+
## Test the application
157159

158160
Open the following URL in browser:
159161

content/learning-paths/servers-and-cloud-computing/django-on-gcp/django_application.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ layout: learningpathall
88

99
## Django REST API with PostgreSQL and Redis
1010

11-
This guide walks you through building a production-ready Django REST API that connects to PostgreSQL for data and Redis for caching.
11+
In this section you'll build a Django REST API that uses PostgreSQL for database storage and Redis for caching. This matches how production applications are typically structured.
1212

13-
### Create Django project
13+
## Create a Django project
1414

1515
Set up a clean Python virtual environment and install all runtime dependencies required for Django, PostgreSQL, Redis, and production serving with Gunicorn.
1616

@@ -37,7 +37,7 @@ django-admin startapp api
3737

3838
The Django project structure is ready with all required libraries for database, cache, and API support.
3939

40-
### Enable Django apps
40+
## Enable Django apps
4141

4242
Enable the REST framework and API app by editing `django_api/settings.py`. Add 'rest_framework' and 'api' to INSTALLED_APPS, set DEBUG to False, and add '*' to ALLOWED_HOSTS:
4343

@@ -60,7 +60,7 @@ INSTALLED_APPS = [
6060

6161
Django is configured to run as an API server.
6262

63-
### Configure PostgreSQL and Redis
63+
## Configure PostgreSQL and Redis
6464

6565
This step connects Django to external managed services instead of local SQLite. This mirrors how real production systems operate.
6666

@@ -96,7 +96,8 @@ Edit the above addition and set `REDIS_IP` to the actual IP address that you sav
9696

9797
The application is configured to use PostgreSQL and Redis.
9898

99-
### Migrate the database
99+
## Migrate the database
100+
100101
Django creates tables, metadata, and user models inside PostgreSQL.
101102

102103
```bash
@@ -106,7 +107,7 @@ python manage.py createsuperuser
106107

107108
The PostgreSQL instance contains all Django system tables.
108109

109-
### Create a health API endpoint
110+
## Create a health API endpoint
110111

111112
A health endpoint allows Kubernetes and load balancers to verify if the service is running.
112113

@@ -134,7 +135,8 @@ urlpatterns = [
134135

135136
The health endpoint is configured.
136137

137-
### Validate locally
138+
## Validate locally
139+
138140
Before containerizing or deploying, validate that everything works end-to-end.
139141

140142
```bash

content/learning-paths/servers-and-cloud-computing/django-on-gcp/firewall_setup.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ For support on GCP setup, see the Learning Path [Getting started with Google Clo
1919

2020
Navigate to the Google Cloud Console and create a new firewall rule:
2121

22-
- Go to the **Google Cloud Console**
23-
- Select **VPC network** > **Firewall**
24-
- Select **Create firewall rule**
22+
- Go to the **Google Cloud Console**.
23+
- Select **VPC network** > **Firewall**.
24+
- Select **Create firewall rule**.
2525

2626
![Screenshot of the Google Cloud Console showing the Firewall section. The Create firewall rule button is prominently displayed at the top of the page#center](images/firewall-rule.png "Google Cloud Console Firewall page")
2727

content/learning-paths/servers-and-cloud-computing/django-on-gcp/installation.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ sudo zypper update -y
2020
sudo zypper install -y curl git tar gzip
2121
```
2222

23-
### Install Python 3.11
23+
## Install Python 3.11
2424

2525
Install Python 3.11:
2626

@@ -47,10 +47,6 @@ pip 22.3.1 from /usr/lib/python3.11/site-packages/pip (python 3.11)
4747

4848
The Google Cloud CLI is required to authenticate with GCP and allow your Django application VM to interact with Google Cloud services such as GKE, Cloud SQL, Artifact Registry, Memorystore, and to build, deploy, and operate the Django platform.
4949

50-
### Install Google Cloud SDK (gcloud)
51-
52-
The Google Cloud SDK is required to create and manage GKE clusters.
53-
5450
Download and extract the Google Cloud SDK:
5551

5652
```bash
@@ -70,7 +66,7 @@ After installation completes, exit and reconnect to apply the PATH changes:
7066
exit
7167
```
7268

73-
### Initialize gcloud
69+
## Initialize gcloud
7470

7571
Authenticate and configure the Google Cloud CLI:
7672

@@ -80,7 +76,7 @@ gcloud init
8076

8177
During initialization, select **Login with a new account**. You'll be prompted to authenticate using your browser and receive an auth code to copy back. Select the project you want to use and choose default settings when unsure.
8278

83-
### Verify authentication
79+
## Verify authentication
8480

8581
```bash
8682
gcloud auth list
@@ -144,4 +140,4 @@ In this section, you installed:
144140
- Python 3.11 with a virtual environment
145141
- Django and Gunicorn for web application development
146142

147-
Next, you'll verify Django is working by creating a basic project and running the development server.
143+
Next, you'll verify Django is working by creating a basic project and running the development server.

0 commit comments

Comments
 (0)