Mục lục
- Mục tiêu bài học
- Render là gì và khi nào dùng
- Service types trên Render
- Chuẩn bị repo
- Tạo Web Service từ dashboard
- Build command và Start command
- Environment variables
- render.yaml — Infrastructure as Code
- Plan và pricing
- Database và Redis
- Persistent disk
- Logs, metrics và monitoring
- Auto-deploy và manual deploy
- Custom domain và HTTPS
- Ví dụ end-to-end — FastAPI inference app
- Common pitfalls
- Tóm tắt
- Bài tiếp theo
Mục tiêu bài học
Sau bài này bạn sẽ:
- ✅ Hiểu Render là gì, phù hợp với use case nào và giới hạn ở đâu
- ✅ Deploy được FastAPI app lên Render bằng Docker hoặc buildpacks
- ✅ Cấu hình environment variables và secret an toàn
- ✅ Khai báo toàn bộ infrastructure (Web Service + DB + Redis) bằng
render.yaml - ✅ Biết plan nào phù hợp với từng giai đoạn dự án
- ✅ Nhận biết và tránh các pitfall phổ biến khi deploy AI app
Render là gì và khi nào dùng
Render là PaaS (Platform-as-a-Service): bạn push code lên git, Render tự build image và chạy container. Bạn không cần cấu hình VM, firewall, load balancer hay certificate — Render lo phần đó.
So với AWS/GCP, Render đánh đổi sự linh hoạt để đổi lấy tốc độ triển khai. Đây là lựa chọn hợp lý khi:
- Cần đưa POC hoặc demo lên public URL nhanh.
- App đơn giản: FastAPI + Postgres + Redis, traffic không quá lớn.
- Team nhỏ, chưa có người chuyên về infra.
- Không muốn học AWS console hay GCP IAM.
Khi nào KHÔNG dùng Render
- Workload GPU liên tục: Render có GPU instance (T4/A10G/A100, ra mid-2024) nhưng số lượng hạn chế và giá không rẻ hơn AWS/GCP đáng kể. Nếu cần train hoặc inference nặng 24/7, xem xét các lựa chọn chuyên biệt.
- Traffic cao: trên ~10k req/s, Render có thể không đủ linh hoạt để scale ngang như Kubernetes.
- Data sovereignty / on-prem: Render chạy trên cloud (AWS và GCP infrastructure). Nếu luật yêu cầu data ở máy chủ trong nước, đây không phải lựa chọn đúng.
- Fine-grained network control: VPC peering, custom security group, private subnet — những thứ này Render không hỗ trợ đầy đủ.
Service types trên Render
Render cung cấp nhiều loại service; mỗi loại phục vụ một mục đích khác nhau:
| Service type | Dùng cho | Có public URL? |
|---|---|---|
| Web Service | API server, web app — nhận HTTP request | Có |
| Background Worker | Task worker, queue consumer — không nhận HTTP | Không |
| Static Site | Frontend build (React, Vue, Next.js static export) | Có |
| Cron Job | Lệnh chạy theo lịch (cron expression) | Không |
| Private Service | Service nội bộ, chỉ accessible từ service khác trong cùng account | Không |
| PostgreSQL | Managed Postgres | Không (chỉ connection string) |
| Redis | Managed Redis | Không (chỉ connection string) |
Trong bài này tập trung vào Web Service — loại phổ biến nhất khi deploy FastAPI. Background Worker và Cron Job dùng cấu hình tương tự, chỉ khác ở chỗ không có HTTP listener.
Chuẩn bị repo
Trước khi tạo service trên Render, repo cần đáp ứng một số điều kiện.
Cách 1: Dùng Dockerfile (khuyến nghị cho AI app)
Khi repo có Dockerfile, Render sẽ tự phát hiện và chạy docker build. Đây là cách được khuyến nghị vì bạn kiểm soát hoàn toàn environment — Python version, system packages (ví dụ libgomp cho PyTorch), và CUDA nếu cần.
# Dockerfile (ví dụ minimal FastAPI inference)
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Render truyền $PORT tại runtime — không hard-code 8000
CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port $PORT"]
Điểm quan trọng: app phải bind 0.0.0.0:$PORT. Render set env var PORT tại runtime với một giá trị port ngẫu nhiên. Hard-code 8000 sẽ khiến health check fail và service bị restart liên tục.
Cách 2: Buildpacks (Python native, không cần Dockerfile)
Nếu repo có requirements.txt, Render tự phát hiện Python và chạy buildpack:
- Build Command:
pip install -r requirements.txt - Start Command:
uvicorn main:app --host 0.0.0.0 --port $PORT
Buildpack phù hợp cho app nhẹ. Khi app cần system package ngoài Python (libsndfile cho audio, libGL cho OpenCV, hay bất kỳ C extension nào), dùng Dockerfile để cài thêm tường minh.
Cấu trúc repo tối thiểu
my-ai-app/
├── Dockerfile
├── requirements.txt
├── main.py # FastAPI app
├── .env.example # tên biến cần set, giá trị trống
└── render.yaml # tùy chọn, xem bước 8
File .env thật (chứa secret) phải có trong .gitignore, không commit lên repo.
Tạo Web Service từ dashboard
- Đăng ký tài khoản tại render.com (login bằng GitHub hoặc GitLab).
- Dashboard → nhấn New + → chọn Web Service.
- Chọn Connect a repository → authorize GitHub/GitLab nếu chưa. Chọn repo cần deploy.
- Render hiển thị form cấu hình:
| Trường | Ghi chú |
|---|---|
| Name | Tên service, xuất hiện trong subdomain: name.onrender.com |
| Region | Oregon (US West), Frankfurt, Singapore, Ohio... Chọn Singapore cho user ở VN để giảm latency |
| Branch | Branch git để theo dõi, thường là main |
| Runtime | Render auto-detect Docker nếu có Dockerfile. Hoặc chọn Python, Node, Ruby, etc. |
| Build Command | Bỏ trống nếu dùng Docker (Render tự docker build) |
| Start Command | Bỏ trống nếu dùng Docker (Render dùng CMD từ Dockerfile) |
| Instance Type | Chọn plan phù hợp (xem bước 9) |
Nhấn Create Web Service. Render bắt đầu clone repo, build image và deploy. Log build hiện trực tiếp trên dashboard.
URL sau deploy
Khi deploy thành công, Render cấp URL dạng https://<name>.onrender.com. HTTPS tự động, không cần cấu hình thêm.
Build command và Start command
Khi dùng Docker
Render tự chạy docker build . và docker run với CMD trong Dockerfile. Bỏ trống Build Command và Start Command trên dashboard.
Khi dùng buildpacks (không có Dockerfile)
Build Command: pip install -r requirements.txt
Start Command: uvicorn main:app --host 0.0.0.0 --port $PORT
Nếu dùng gunicorn thay vì uvicorn:
Start Command: gunicorn main:app -w 2 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:$PORT
Pre-deploy command
Render hỗ trợ trường Pre-Deploy Command — chạy sau khi build xong nhưng trước khi start. Dùng để chạy database migration:
Pre-Deploy Command: python -m alembic upgrade head
Nếu pre-deploy command fail, Render không triển khai build mới — giữ nguyên version cũ đang chạy. Đây là cơ chế an toàn để tránh deploy app với schema DB chưa migrate.
Environment variables
Trên dashboard của service, chọn tab Environment.
Thêm variable đơn lẻ
Nhấn Add Environment Variable, nhập key và value. Ví dụ:
OPENAI_API_KEY = sk-...
MODEL_NAME = gpt-4o-mini
LOG_LEVEL = info
Secret values được mã hóa sau khi lưu — Render không hiển thị lại giá trị. Bạn chỉ có thể ghi đè hoặc xóa.
Environment Group — chia sẻ biến giữa nhiều service
Nếu nhiều service dùng chung một tập biến (ví dụ API key cho cả Web Service và Background Worker), tạo một Environment Group:
- Dashboard → Environment Groups → New Environment Group.
- Đặt tên (ví dụ
ai-api-secrets), thêm các key/value. - Vào từng service → Environment → Link Environment Group.
Khi cập nhật giá trị trong group, các service link đến group sẽ nhận giá trị mới ở lần deploy tiếp theo.
DATABASE_URL tự inject
Khi tạo Postgres database trên Render và link với service, Render tự inject DATABASE_URL vào env của service. Không cần copy connection string thủ công.
render.yaml — Infrastructure as Code
render.yaml là file khai báo toàn bộ infrastructure của một project — Web Service, database, Redis, biến môi trường — dưới dạng code. Commit file này vào repo rồi dùng tính năng Blueprint để deploy toàn bộ stack với một click.
# render.yaml
services:
- type: web
name: ai-api
runtime: docker
repo: https://github.com/you/ai-app
branch: main
region: singapore
plan: starter
healthCheckPath: /health
envVars:
- key: OPENAI_API_KEY
sync: false # set thủ công trên dashboard, không sync từ file
- key: MODEL_NAME
value: gpt-4o-mini
- key: DATABASE_URL
fromDatabase:
name: my-pg
property: connectionString
- key: REDIS_URL
fromService:
name: my-redis
type: redis
property: connectionString
- type: worker
name: ai-worker
runtime: docker
repo: https://github.com/you/ai-app
branch: main
region: singapore
plan: starter
startCommand: python worker.py
envVars:
- key: OPENAI_API_KEY
sync: false
- key: DATABASE_URL
fromDatabase:
name: my-pg
property: connectionString
- type: redis
name: my-redis
plan: free
region: singapore
ipAllowList: [] # chỉ cho phép kết nối nội bộ (internal only)
databases:
- name: my-pg
plan: free
region: singapore
databaseName: appdb
user: appuser
Giải thích các trường quan trọng
sync: false: biến có giá trị nhạy cảm (API key) — không lưu trong file, set thủ công trên dashboard sau khi Blueprint tạo service.fromDatabase: Render tự resolve connection string của database tương ứng và inject vào env. Không cần copy tay.healthCheckPath: Render gọi endpoint này sau deploy để xác nhận app healthy. App phải trả về HTTP 200. Thiếu trường này → Render không biết app đã sẵn sàng chưa.ipAllowList: []: Redis chỉ cho phép kết nối từ service nội bộ trong cùng account, không expose ra internet.
Dùng Blueprint
Sau khi commit render.yaml vào repo:
- Render Dashboard → New + → Blueprint.
- Connect repo → Render đọc
render.yamlvà hiển thị preview toàn bộ service sẽ tạo. - Nhấn Apply → Render tạo tất cả service, database, Redis cùng lúc.
Blueprint giúp onboard thành viên mới hoặc tái tạo environment dễ dàng — tất cả cấu hình đã được version control.
Plan và pricing
Các con số dưới đây phản ánh thông tin tại thời điểm viết bài (mid-2025). Kiểm tra render.com/pricing để có số liệu mới nhất trước khi ra quyết định.
| Plan | Giá/tháng | RAM | CPU | Ghi chú |
|---|---|---|---|---|
| Free | $0 | 512 MB | 0.1 vCPU | Sleep sau 15 phút idle, quota 750h/month |
| Starter | ~$7 | 512 MB | 0.5 vCPU | Không sleep, chạy 24/7 |
| Standard | ~$25 | 2 GB | 1 vCPU | Đủ cho inference SLM nhẹ (DistilBERT, TinyLlama) |
| Pro | ~$85 | 4 GB | 2 vCPU | Persistent disk, đủ RAM cho nhiều model nhỏ |
| Pro Plus | ~$175 | 8 GB | 4 vCPU | Model lớn hơn, multi-worker |
| GPU (T4) | Pay-as-you-go | 16 GB VRAM | 4 vCPU + T4 | Inference GPU, ra mid-2024 |
Free tier — điểm cần lưu ý
- Sleep sau 15 phút idle: request đầu tiên sau khi service ngủ cần 10–30 giây để wake up. Không phù hợp cho production có user thật.
- 750h/month quota: đủ cho một service chạy liên tục (30 ngày × 24h = 720h). Nếu có nhiều service Free, quota chia sẻ.
- Postgres Free: tự động xóa sau 90 ngày nếu không upgrade. Backup data trước khi hết hạn.
Chọn plan theo giai đoạn
- POC / internal demo: Free tier, chấp nhận sleep.
- Demo public, user thật: Starter ($7) — không sleep, đủ cho API gọi OpenAI/Anthropic.
- App với model nhỏ on-device (DistilBERT, Sentence Transformers): Standard ($25) — 2GB RAM.
- App cần lưu model file (Whisper base, etc.): Pro trở lên — cần persistent disk.
Database và Redis
PostgreSQL
Tạo từ dashboard (New + → PostgreSQL) hoặc khai báo trong render.yaml. Render tự quản lý backup, upgrade, failover.
- Free plan: 1GB storage, expire sau 90 ngày.
- Starter plan (~$7/month): 1GB storage, không expire.
- Standard plan trở lên: nhiều RAM hơn cho query phức tạp, connection pooling.
Connection string có dạng:
postgresql://user:[email protected]/dbname
Render cung cấp cả Internal và External connection string:
- Internal URL: dùng trong code chạy trên Render — kết nối nhanh hơn, không qua internet.
- External URL: dùng từ máy local (ví dụ pgAdmin, psql để debug).
Redis
- Free plan: 25MB, không persist (data mất khi restart). Chỉ dùng cho cache tạm.
- Starter plan (~$10/month): 250MB, persist.
Sau khi tạo Redis service và link với Web Service, Render inject REDIS_URL vào env. Trong code Python:
import os
import redis
r = redis.from_url(os.environ["REDIS_URL"])
r.set("key", "value", ex=3600) # TTL 1h
Persistent disk
Mặc định, filesystem của Render container là ephemeral: data ghi vào sẽ mất khi service redeploy hoặc restart. Nếu cần lưu file qua các lần deploy (model weights, user uploads, cache), cần Persistent Disk.
Persistent Disk có sẵn từ Pro plan trở lên. Cấu hình trong render.yaml:
services:
- type: web
name: ai-api
runtime: docker
plan: pro
disk:
name: model-storage
mountPath: /data
sizeGB: 10
Trong code, đọc/ghi file dưới /data như filesystem thông thường:
import os
from pathlib import Path
MODEL_DIR = Path(os.getenv("MODEL_DIR", "/data/models"))
MODEL_DIR.mkdir(parents=True, exist_ok=True)
# Download model lần đầu, lần sau đọc từ disk
model_path = MODEL_DIR / "whisper-base.pt"
if not model_path.exists():
download_model(model_path)
Persistent Disk gắn với một service cụ thể — nếu scale lên nhiều instance, mỗi instance có disk riêng, không chia sẻ. Nếu cần shared storage giữa nhiều instance, phải dùng object storage ngoài (S3, GCS).
Logs, metrics và monitoring
Logs
Dashboard → service → tab Logs. Log hiển thị real-time, có thể filter theo level hoặc tìm kiếm chuỗi. Render giữ log trong 7 ngày (Free/Starter) hoặc lâu hơn tùy plan.
App ghi ra stdout/stderr như bình thường — Render tự capture:
import logging
import sys
logging.basicConfig(
stream=sys.stdout,
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
logger = logging.getLogger(__name__)
logger.info("Model loaded: %s", model_name)
Metrics
Dashboard → tab Metrics: CPU usage, RAM usage, request count, response time. Biểu đồ theo thời gian thực, đủ để phát hiện memory leak hoặc spike CPU trong inference.
Alerts
Render hỗ trợ alert qua email khi service crash hoặc health check fail liên tục. Cấu hình trong Settings → Notifications.
Tích hợp ngoài
Render hỗ trợ log drain: forward log đến Datadog, New Relic, Papertrail, Logtail qua HTTP endpoint. Cấu hình trong Dashboard → Log Streams.
Auto-deploy và manual deploy
Auto-deploy (mặc định bật)
Mỗi khi có commit mới trên branch đang track, Render tự trigger build và deploy. Luồng:
- Push code lên GitHub/GitLab.
- Render nhận webhook, clone repo, build image.
- Nếu build thành công và health check pass → swap sang version mới.
- Nếu build fail → version cũ tiếp tục chạy.
Tắt auto-deploy
Vào Settings → Auto-Deploy → tắt. Dùng khi bạn muốn kiểm soát thủ công thời điểm deploy (ví dụ chờ QA approve).
Manual deploy từ dashboard
Dashboard → service → nhấn Manual Deploy → chọn commit hoặc branch. Nếu build gần đây thất bại, nút Retry xuất hiện để chạy lại build đó.
Deploy via API
Render có REST API cho tự động hóa từ CI/CD pipeline:
curl -X POST \
"https://api.render.com/v1/services/${SERVICE_ID}/deploys" \
-H "Authorization: Bearer ${RENDER_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"clearCache": "do_not_clear"}'
Custom domain và HTTPS
Render cấp HTTPS tự động cho tất cả service (kể cả Free tier) qua subdomain .onrender.com. Để dùng domain riêng:
- Dashboard → service → tab Settings → Custom Domains.
- Nhập domain (ví dụ
api.yourdomain.com). - Render hiển thị DNS record cần thêm: thường là CNAME trỏ về
your-service.onrender.com. - Vào DNS provider (Cloudflare, Namecheap, GoDaddy, ...) thêm record.
- Sau khi DNS propagate (thường vài phút đến 1 giờ), Render tự cấp certificate Let's Encrypt và bật HTTPS.
Render tự gia hạn certificate — bạn không cần làm gì thêm.
Ví dụ end-to-end — FastAPI inference app
Dưới đây là ví dụ triển khai FastAPI app gọi OpenAI để inference, dùng Dockerfile, deploy lên Render.
Cấu trúc repo
ai-inference-api/
├── Dockerfile
├── requirements.txt
├── main.py
└── render.yaml
main.py
import os
from fastapi import FastAPI
from pydantic import BaseModel
from openai import AsyncOpenAI
app = FastAPI()
client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])
MODEL = os.getenv("MODEL_NAME", "gpt-4o-mini")
class ChatRequest(BaseModel):
message: str
class ChatResponse(BaseModel):
reply: str
@app.get("/health")
async def health():
return {"status": "ok"}
@app.post("/chat", response_model=ChatResponse)
async def chat(req: ChatRequest):
completion = await client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": req.message}],
)
return ChatResponse(reply=completion.choices[0].message.content)
requirements.txt
fastapi==0.115.0
uvicorn[standard]==0.30.6
openai==1.51.0
pydantic==2.9.2
Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port $PORT"]
render.yaml
services:
- type: web
name: ai-inference-api
runtime: docker
region: singapore
plan: starter
healthCheckPath: /health
envVars:
- key: OPENAI_API_KEY
sync: false
- key: MODEL_NAME
value: gpt-4o-mini
Quy trình deploy
- Push repo lên GitHub.
- Render Dashboard → New + → Blueprint → connect repo → Apply.
- Render tạo Web Service, đọc
render.yaml, bắt đầu build. - Sau khi tạo service: vào tab Environment → set giá trị cho
OPENAI_API_KEY. - Trigger manual deploy (hoặc push thêm commit để auto-deploy).
- Sau vài phút: service sẵn sàng tại
https://ai-inference-api-xxx.onrender.com.
Test nhanh
curl -X POST https://ai-inference-api-xxx.onrender.com/chat \
-H "Content-Type: application/json" \
-d '{"message": "Giải thích gradient descent trong 2 câu"}'
Common pitfalls
1. Hard-code port thay vì dùng $PORT
# SAI — port 8000 cố định, Render truyền port khác qua $PORT
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# ĐÚNG — đọc $PORT tại runtime
CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port $PORT"]
App hard-code port sẽ không nhận được request và Render liên tục restart container.
2. Free tier sleep gây user experience kém
Khi service Free sleep, request đầu tiên phải đợi container warm up (10–30 giây). Nếu app đã có người dùng thật, upgrade lên Starter ($7/month). Workaround tạm: cron job ping service mỗi 10 phút từ bên ngoài — nhưng cách này không đáng tin và vi phạm spirit của Free tier.
3. Build timeout vì cài PyTorch / Transformers
Render có giới hạn build time (mặc định 45 phút). pip install torch transformers có thể tốn 5–15 phút tùy plan. Nếu build thường xuyên timeout:
- Dùng multi-stage build (bài 34): stage builder cài dependency, stage final chỉ copy artifact.
- Dùng base image có sẵn PyTorch (
pytorch/pytorch:2.4.0-cuda12.1-cudnn8-runtime) để bỏ qua bước cài. - Pin version cụ thể trong
requirements.txt— tránh pip resolve lâu.
4. Không có health check endpoint
Nếu không khai báo healthCheckPath, Render không thể phân biệt container đang khởi động với container đã crash. Service có thể bị restart liên tục dù app đang chạy bình thường. Thêm endpoint GET /health trả về 200 là đủ.
5. Docker image quá lớn
Render có giới hạn image size (khoảng 8–10GB tùy plan). Image chứa full PyTorch + CUDA + Transformers rất dễ vượt ngưỡng này. Áp dụng multi-stage build (bài 34) để loại bỏ build tool và cache. Dùng --no-cache-dir khi pip install.
6. Free Postgres expire sau 90 ngày
Render tự xóa Postgres Free instance sau 90 ngày không upgrade. Nếu dùng cho dự án có data quan trọng, thiết lập backup định kỳ hoặc upgrade trước khi hết hạn. Render gửi email cảnh báo 30 ngày trước.
7. Region xa user gây latency cao
Render có region Singapore (gần VN nhất), Oregon (US West), Frankfurt, Ohio, Virginia. Với user ở Việt Nam, chọn Singapore. Latency từ Singapore đến HCM khoảng 20–40ms, so với Oregon ~200ms.
8. Filesystem ephemeral — mất file sau redeploy
File ghi vào container filesystem (ngoài persistent disk) sẽ mất khi deploy mới. Không lưu model, user upload, hay state quan trọng vào filesystem mặc định. Dùng persistent disk (Pro plan) hoặc object storage ngoài.
Tóm tắt
- ✅ Render phù hợp cho POC, demo, app nhỏ — không cần quản lý server hay infra phức tạp
- ✅ App phải bind
0.0.0.0:$PORT— Render setPORTtại runtime, không hard-code - ✅ Dùng Dockerfile để kiểm soát environment (Python version, system packages, CUDA)
- ✅
render.yamlkhai báo toàn bộ stack (Web Service + DB + Redis) dưới dạng code, deploy 1 click qua Blueprint - ✅ Secret qua Environment tab hoặc Environment Group — không hardcode trong YAML
- ✅ Free tier sleep sau 15 phút idle và Postgres expire sau 90 ngày — upgrade khi cần production-ready
- ✅ Persistent Disk (Pro plan) cho model weights, file cần survive qua redeploy
- ✅ Chọn Singapore region cho user ở Việt Nam
- ✅ Endpoint
/healthtrả 200 là bắt buộc để Render biết service đã sẵn sàng
