Giới Thiệu: Bài Toán Kinh Tế Khi Deploy Nextjs Wagtail Google Cloud Run
Khi triển khai các dự án cá nhân, sản phẩm thử nghiệm (MVP) hoặc website doanh nghiệp nhỏ, việc phải chi trả từ **$5 đến $20/tháng** cho một chiếc VPS Linux (ngay cả khi trang web chỉ có vài trăm lượt truy cập mỗi ngày) là một sự lãng phí tài nguyên không cần thiết.
Nhiều lập trình viên đã tìm đến các nền tảng PaaS như Vercel hay Render. Tuy nhiên, Vercel rất đắt đỏ khi bạn sử dụng nhiều băng thông video/hình ảnh, còn Render thì lại có giới hạn độ trễ và số phút build khá khắt khe đối với tài khoản miễn phí.
Giải pháp tối ưu nhất cho bài toán này chính là kiến trúc **Serverless Container trên Google Cloud Run**. Bằng cách kết hợp **Next.js App Router (Frontend SSR)** và **Wagtail CMS (Backend Django Python)** được container hóa bài bản, hệ thống của bạn hoàn toàn có thể phục vụ hàng chục ngàn lượt truy cập mỗi tháng với mức hóa đơn gửi về từ Google Cloud luôn ở con số **0 VNĐ**.
1. Mô Hình Kiến Trúc Deploy Nextjs Wagtail Google Cloud Run "Tam Giác Vàng 0đ"
Để toàn bộ cụm ứng dụng vận hành trơn tru mà không phát sinh chi phí ẩn, chúng ta sẽ bóc tách hệ thống thành 3 trụ cột tài nguyên Serverless độc lập:
mermaid
2. Đóng Gói Wagtail Headless CMS Với Docker Multi-Stage & GCS Storage
Wagtail là hệ quản trị nội dung (CMS) xây dựng trên nền Django (Python) có tốc độ xử lý nhanh, bảo mật cao và hỗ trợ API Headless cực kỳ mạnh mẽ.
2.1. Cấu Hình Wagtail CMS Dạng Headless API
Trong file `settings/base.py` của dự án Wagtail, bạn kích hoạt module API v2:
INSTALLED_APPS = [
# ...
'wagtail.api.v2',
'rest_framework',
]
# Thêm cấu hình router cho API
from wagtail.api.v2.views import PagesAPIViewSet
from wagtail.api.v2.router import WagtailAPIRouter
api_router = WagtailAPIRouter('wagtailapi')
api_router.register_endpoint('pages', PagesAPIViewSet)2.2. Kết Nối Google Cloud Storage Cho Upload Hình Ảnh
Vì container trên Cloud Run là dạng tạm thời (Stateless - dữ liệu bị xóa khi container tắt), toàn bộ ảnh upload trên Wagtail CMS phải được lưu trữ trực tiếp lên Google Cloud Storage qua thư viện `django-storages`:
pip install django-storages[google] google-cloud-storageThêm cấu hình vào file `settings/production.py`:
import os
GS_BUCKET_NAME = os.getenv("GS_BUCKET_NAME", "my-wagtail-media-bucket")
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
GS_DEFAULT_ACL = "publicRead"2.3. Tạo File Dockerfile Multi-Stage Cho Wagtail Python
Để giảm dung lượng Docker image của Wagtail từ ~800MB xuống chỉ còn **~140MB** (giúp container khởi động tức thì trên Cloud Run), chúng ta sử dụng kỹ thuật Multi-stage build:
# Stage 1: Build dependencies
FROM python:3.12-slim AS builder
WORKDIR /app
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
RUN apt-get update && apt-get install -y --no-cache-dir build-essential libpq-dev
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: Runner siêu nhẹ chạy Production
FROM python:3.12-slim AS runner
WORKDIR /app
ENV PATH=/root/.local/bin:$PATH \
PYTHONUNBUFFERED=1
RUN apt-get update && apt-get install -y --no-install-recommends libpq5 && rm -rf /var/lib/apt/lists/*
COPY --from=builder /root/.local /root/.local
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "--threads", "4", "mysite.wsgi:application"]Đóng Gói & Tối Ưu Frontend Next.js App Router (SSR)
Frontend Next.js sẽ giao tiếp với Wagtail qua REST API để lấy dữ liệu trang và thực hiện Render giao diện trên Server (SSR).
3.1. Cấu Hình Tính Năng `output: 'standalone'` Trong Next.js
Mở file `next.config.ts` (hoặc `next.config.js`) và bật chế độ standalone:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
images: {
remotePatterns: [
{
protocol: "https",
hostname: "storage.googleapis.com",
},
],
},
};
export default nextConfig;3.2. Viết File Dockerfile Multi-Stage Tinh Gọn Cho Next.js
# Stage 1: Dependencies
FROM node:20-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Stage 2: Builder
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
RUN npm run build
# Stage 3: Runner
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
PORT=8080 \
HOSTNAME="0.0.0.0"
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 8080
CMD ["node", "server.js"]4. Các Bước Thực Hành Deploy Nextjs Wagtail Google Cloud Run Trực Tiếp
Bây giờ chúng ta sẽ tiến hành biên dịch Docker Image và thực hiện **deploy Nextjs Wagtail Google Cloud Run** trực tiếp từ dòng lệnh Terminal.
4.1. Khởi Tạo Dự Án Google Cloud & Bật Các API Cần Thiết
Mở Terminal máy tính của bạn và đăng nhập vào tài khoản Google Cloud:
gcloud auth login
gcloud config set project MY_GCP_PROJECT_ID
gcloud services enable run.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com4.2. Tạo Repository Trên Artifact Registry & Push Docker Images
gcloud artifacts repositories create web-apps \
--repository-format=docker \
--location=asia-east1 \
--description="Docker repo cho Nextjs va Wagtail"
gcloud auth configure-docker asia-east1-docker.pkg.devTiến hành build và push image Wagtail Backend:
gcloud builds submit ./backend --tag asia-east1-docker.pkg.dev/MY_GCP_PROJECT_ID/web-apps/wagtail-backend:v1
gcloud builds submit ./frontend --tag asia-east1-docker.pkg.dev/MY_GCP_PROJECT_ID/web-apps/nextjs-frontend:v14.3. Deploy Service Wagtail CMS Lên Cloud Run (`--min-instances 0`)
Đây là câu lệnh quyết định việc **đưa chi phí duy trì về $0.00** nhờ tham số `--min-instances 0`:
gcloud run deploy wagtail-cms \
--image asia-east1-docker.pkg.dev/MY_GCP_PROJECT_ID/web-apps/wagtail-backend:v1 \
--region asia-east1 \
--platform managed \
--allow-unauthenticated \
--min-instances 0 \
--max-instances 3 \
--memory 512Mi \
--cpu 1 \
--port 8080 \
--set-env-vars DATABASE_URL="postgresql://user:[email protected]/neondb?sslmode=require",GS_BUCKET_NAME="my-wagtail-media-bucket",SECRET_KEY="your-secret-key"Sau khi lệnh chạy xong, Google Cloud Run sẽ trả về một URL công khai cho backend (ví dụ: `https://wagtail-cms-xyz-de.a.run.app`).
4.4. Deploy Service Next.js SSR Lên Cloud Run
Tiếp tục triển khai service Frontend Next.js và truyền URL backend vừa tạo vào biến môi trường:
gcloud run deploy nextjs-frontend \
--image asia-east1-docker.pkg.dev/MY_GCP_PROJECT_ID/web-apps/nextjs-frontend:v1 \
--region asia-east1 \
--platform managed \
--allow-unauthenticated \
--min-instances 0 \
--max-instances 5 \
--memory 256Mi \
--cpu 1 \
--port 8080 \
--set-env-vars NEXT_PUBLIC_WAGTAIL_API_URL="https://wagtail-cms-xyz-de.a.run.app"5. Tối Ưu Hiệu Năng Cold Start & Cấu Hình Cloudflare CDN
5.1. Xử Lý Hiện Tượng Cold Start Khi `--min-instances 0`
Khi đặt `--min-instances 0`, nếu trong vòng 15 phút không có ai truy cập, Google Cloud Run sẽ tắt hoàn toàn các container. Người dùng đầu tiên truy cập sau thời gian nhàn rỗi sẽ gặp hiện tượng **Cold Start** (mất khoảng 1.2 – 2 giây để container khởi động lại).
**Giải pháp triệt tiêu Cold Start bằng Cloudflare Edge Cache:**
1. Thêm tên miền cá nhân của bạn vào Cloudflare (Miễn phí).
2. Tạo bản ghi CNAME trỏ về domain mặc định của Cloud Run (`nextjs-frontend-xyz-de.a.run.app`).
3. Cấu hình **Page Rules / Cache Rules** trên Cloudflare cho các đường dẫn tĩnh:
- Match: `example.com/static/*` hoặc các trang bài viết blog.
- Cache Level: `Cache Everything`.
- Edge Cache TTL: `7 days`.
Khi đó, **95% các yêu cầu từ người dùng sẽ được phản hồi trực tiếp từ mạng lưới Edge CDN của Cloudflare** với thời gian phản hồi TTFB siêu tốc **<50ms**, mà không cần kích hoạt container Cloud Run ở phía sau!
curl -w "TTFB: %{time_starttransfer}s\n" -o /dev/null -s https://example.com6. Bảng Checklist Tối Ưu Chi Phí 0đ Trên Google Cloud Run
Hãy rà soát danh mục dưới đây để đảm bảo tài khoản Google Cloud của bạn không bao giờ phát sinh chi phí phát sinh ngoài ý muốn:
| STT | Hạng Mục Cấu Hình | Thông Số Tối Ưu Miễn Phí | Trạng Thái |
|---|---|---|---|
| 1 | Cloud Run Min Instances | --min-instances 0 (Scale về 0 khi không có lưu lượng) |
[x] Đã cấu hình |
| 2 | Cloud Run Memory limit | Frontend: 256Mi / Backend: 512Mi |
[x] Đã giới hạn |
| 3 | Database Tier | Neon Serverless Postgres Free Tier (Compute Auto-suspend) | [x] Kết nối an toàn |
| 4 | Media Bucket | Google Cloud Storage Standard (< 5GB) | [x] Đã cấu hình GCS |
| 5 | Container Concurrency | --concurrency 80 (Một container xử lý 80 request đồng thời) |
[x] Tối ưu RAM |
| 6 | Edge Cache | Cloudflare Free Plan CNAME Proxied | [x] Đã bật CDN |
Câu Hỏi Thường Gặp (FAQ)
Google Cloud Run cung cấp cho bạn **2.000.000 requests** và **360.000 GB-giây RAM** hoàn toàn miễn phí mỗi tháng. Với một website tin tức, blog hoặc landing page có khoảng **30.000 – 50.000 lượt xem/tháng** (kết hợp lưu cache qua Cloudflare), lượng tài nguyên tiêu thụ thực tế chỉ chiếm khoảng **15% – 20%** hạn ngạch miễn phí. Bạn hoàn toàn yên tâm hệ thống sẽ chạy bền bỉ với chi phí $0.
