Skip to content

HARRY-30 — GĐ16 — AWS nền tảng cho Backend: EC2, S3, IAM, RDS, Lambda, CloudWatch, VPC

GĐ16 — AWS nền tảng cho Backend: EC2, S3, IAM, RDS, Lambda, CloudWatch, VPC ​

Study note cho FE engineer chuyển sang Backend. Mục tiêu là đọc được sơ đồ AWS nhỏ, triển khai một API có database và upload an toàn, rồi biết tìm lỗi và dọn tài nguyên lab.


1. AWS nhìn từ một backend engineer ​

AWS có hàng trăm dịch vụ. Giai đoạn này chỉ học bảy khối thường gặp để bạn hiểu app nằm ở đâu, dữ liệu đi qua đâu, quyền được cấp thế nào và lỗi được quan sát ra sao. Đây là nền tảng để đọc job description và tiếp tục học theo dự án; nó không bảo đảm việc làm và không phải mọi production system đều chỉ cần bảy dịch vụ.

Dịch vụVai tròCâu hỏi backend cần trả lời
EC2Máy ảo chạy ứng dụngProcess chạy bằng user nào, mở port nào, restart và cập nhật OS ra sao?
S3Lưu object/fileBucket và object key là gì, ai được upload/download, file lớn đi đường nào?
IAMDanh tính và quyền AWSPrincipal nào được gọi action nào trên resource nào?
RDSDatabase quan hệ được quản lýDB nằm trong subnet nào, app được kết nối ra sao, backup và pool do ai lo?
LambdaChạy code theo event hoặc requestTrigger nào gọi handler, retry có thể lặp thế nào, execution role có quyền gì?
CloudWatchLogs, metrics và alarmsKhi app lỗi, log nào giúp tìm nguyên nhân và alarm nào báo sớm?
VPCMạng riêng của resource AWSTraffic được route qua đâu, resource nào public, rule nào cho phép kết nối?

Thứ tự học: VPC → IAM → EC2 → RDS và S3 → Lambda → CloudWatch. Thứ tự này bắt đầu từ ranh giới mạng và quyền truy cập, sau đó mới đặt app và data vào đó.

Trước khi tạo tài nguyên ​

  1. Bảo vệ root user, bật MFA, và không dùng root cho thao tác hằng ngày.
  2. Chọn một Region gần nơi bạn học hoặc người dùng thử nghiệm. Hầu hết resource phải được tạo cùng Region để kết nối thuận tiện.
  3. Tạo AWS Budget hoặc billing alert trước khi mở EC2, RDS, NAT Gateway hay địa chỉ IP tĩnh. Free tier và ưu đãi có thể thay đổi theo tài khoản và thời điểm.
  4. Dùng AWS Console hoặc profile đăng nhập tạm thời cho người học. Không dán access key vào source, Docker image, chat, hay lệnh terminal được lưu lịch sử.
  5. Tạo lab nhỏ, ghi lại tên resource, và xoá tài nguyên sau buổi học. Dừng EC2 không tự xoá RDS, disk snapshot, log, hoặc địa chỉ IP có phí.

2. VPC — vẽ mạng trước khi deploy ​

Định nghĩa. VPC là mạng ảo tách biệt trong một AWS Region. Bạn chọn dải IP (CIDR), chia subnet theo Availability Zone, gắn route table, gateway và security controls. VPC không tự làm app private hay public; route, địa chỉ IP và firewall rules cùng quyết định khả năng truy cập.

Các khối cần nhận diện ​

KhốiLàm gìMental model
VPC CIDRCấp dải địa chỉ private cho mạngVí dụ 10.20.0.0/16 là không gian IP của lab
SubnetChia dải VPC theo AZ và mục đíchSubnet public thường có route tới Internet Gateway; subnet private không có route trực tiếp đó
Route tableChọn next hop theo địa chỉ đích0.0.0.0/0 → IGW cho đường IPv4 tới Internet Gateway
Internet Gateway (IGW)Kết nối VPC với InternetCó route tới IGW vẫn cần địa chỉ public và security rule phù hợp
Security Group (SG)Allowlist traffic ở resource như EC2/RDSMở port 5432 chỉ từ SG của app, thay vì từ mọi IP
Network ACL (NACL)Lọc traffic ở subnetCó thể dùng thêm, nhưng lab thường bắt đầu bằng route table + SG

Ví dụ CIDR cho lab: VPC 10.20.0.0/16; subnet app 10.20.1.0/24; hai subnet DB 10.20.11.0/24 và 10.20.12.0/24 đặt ở hai AZ. RDS DB subnet group thường trải qua nhiều AZ để hỗ trợ cấu hình sẵn sàng cao.

text
Internet
   │ HTTPS (lab có thể giới hạn theo IP cá nhân)
   ▼
VPC 10.20.0.0/16
├─ Public subnet 10.20.1.0/24: EC2 Node API
└─ Private subnets 10.20.11.0/24, 10.20.12.0/24: RDS PostgreSQL

Security Group của EC2: inbound chỉ port cần thiết
Security Group của RDS: inbound TCP 5432, source = Security Group của EC2

Cách suy luận đường kết nối EC2 → RDS:

  1. EC2 và RDS có private IP trong cùng VPC, vì vậy VPC local route cho phép tìm đường nội bộ.
  2. Security Group của RDS phải cho phép TCP 5432 từ Security Group gắn với EC2.
  3. Security Group của EC2 phải cho phép outbound tới RDS; rule mặc định thường cho outbound, nhưng cần kiểm tra nếu đã siết rule.
  4. RDS vẫn không cần public IP. Không mở 5432 tới 0.0.0.0/0.

Pitfall. Gắn EC2 vào “public subnet” không tự động cho người ngoài truy cập được. Route tới IGW, public IPv4/EIP và SG inbound đều phải đúng. Ngược lại, bỏ public access của RDS không cản app trong VPC kết nối qua private IP.

Nếu app chuyển vào private subnet để không nhận kết nối Internet trực tiếp, nó vẫn cần một đường outbound để gọi API AWS hoặc tải image/package. Có thể thiết kế VPC endpoint phù hợp (ví dụ S3 Gateway Endpoint cho traffic tới S3) hoặc egress qua NAT; cân nhắc chi phí và không thêm NAT chỉ theo thói quen.

Làm thử. Mở VPC Resource Map, tìm VPC, subnet và route table. Tự trả lời: subnet nào có route tới IGW? SG nào cho phép port 443? SG DB nhận traffic từ CIDR rộng hay từ SG của app? AWS giải thích VPC, route tables và Security Groups.


3. IAM — quyền tối thiểu cho người và workload ​

Định nghĩa. IAM quản lý principal (người dùng, role hoặc dịch vụ), policy và quyền truy cập AWS. IAM không thay thế đăng nhập user của ứng dụng: user của SaaS là danh tính trong hệ thống của bạn; IAM role là danh tính để app gọi API AWS.

Role gồm hai câu hỏi khác nhau ​

  • Trust policy: ai hoặc dịch vụ nào được assume role? Ví dụ EC2 hoặc Lambda.
  • Permissions policy: sau khi assume role, principal được gọi action nào trên resource nào?
  • Least privilege: chỉ cấp đúng action và resource cần dùng. Tránh policy Action: "*" hoặc Resource: "*" trong workload.
  • Temporary credentials: EC2/Lambda nhận credentials tạm qua role. AWS SDK tự tìm credentials từ môi trường chạy; không cần copy access key vào .env.

Ví dụ permissions policy cho API chỉ được upload object vào prefix raw/ của một bucket:

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject"],
      "Resource": "arn:aws:s3:::backend-guide-lab/raw/*"
    }
  ]
}

Policy này không cho phép liệt kê bucket, đọc object, xoá object, hoặc ghi vào prefix khác. Nếu API cần GetObject, thêm riêng action và resource tương ứng sau khi có use case.

Một trust policy đơn giản cho EC2 có dạng:

json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "ec2.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}

Trong Console: tạo role cho EC2 → gắn permissions policy → gắn role vào instance. Với Lambda, tạo role có trust cho lambda.amazonaws.com, rồi chỉ thêm quyền S3/CloudWatch function cần.

Pitfall. Tạo IAM user rồi lưu access key trong EC2 là cách dễ rò rỉ và khó rotate. Với workload AWS, ưu tiên role. Khi gặp AccessDenied, đọc cả identity policy, resource policy, trust policy và policy boundary; một policy allow không xoá được explicit deny.

Làm thử. Tạo role chỉ có s3:PutObject vào prefix raw/. Từ API, upload thử vào raw/ thành công, rồi thử ghi vào processed/ hoặc bucket khác và xác nhận bị từ chối. Bài này chứng minh policy đang giới hạn quyền thật.

Tài liệu chính thức: IAM là gì và best practices.


4. EC2 — máy ảo chạy Node API ​

Định nghĩa. EC2 instance là virtual server. Bạn chọn image/AMI, loại máy, disk, network và quyền; sau đó bạn chịu trách nhiệm OS, runtime, process, cập nhật và log agent. Đây là cách nhìn hạ tầng rõ nhất, nhưng cũng tự quản nhiều nhất. Với container production, phần trước đã giới thiệu ECS Fargate như một lựa chọn managed hơn.

Tạo một EC2 lab ​

  1. Chọn Region và VPC. Chọn Linux AMI được hỗ trợ, loại instance nhỏ phù hợp với lab và một disk vừa đủ.
  2. Gắn Security Group. Nếu dùng SSH, chỉ cho TCP 22 từ IP của bạn (x.x.x.x/32), không mở cho toàn Internet. Có thể dùng Systems Manager Session Manager thay SSH; cách đó cần instance role và agent/đường kết nối tương ứng.
  3. Gắn IAM role khi tạo instance, ví dụ role có quyền ghi vào prefix S3 ở phần IAM.
  4. Chọn subnet. Lab công khai cần route, public IP và inbound rule; DB không đặt trong subnet này.
  5. Kết nối vào máy, cài runtime hoặc Docker, deploy image đã build từ CI.
  6. Mở đúng port ứng dụng, kiểm tra /health, log và restart sau khi process lỗi.

Ví dụ lệnh chạy image đã được đẩy tới registry. Thay image/tag và port theo app; secret lấy từ secret store/runtime configuration, không viết vào lệnh hoặc image:

bash
docker run --detach \
  --name backend-api \
  --restart unless-stopped \
  --publish 3000:3000 \
  --env NODE_ENV=production \
  --env PORT=3000 \
  registry.example/backend-api:1.0.0

App trong container phải listen trên 0.0.0.0:3000, không chỉ 127.0.0.1, nếu muốn nhận traffic đi qua Docker port mapping.

Tự chịu trách nhiệm: OS patching, disk đầy, process restart, deploy/rollback, security updates và thu thập log. EC2 không tự thay bạn thành PaaS.

Pitfall. Public IP có thể đổi sau khi instance dừng/start; dùng DNS hoặc load balancer khi cần endpoint ổn định. docker run --restart chỉ khởi động lại process/container, không thay health check hay rollout an toàn. Kiểm tra phí cho instance, disk, snapshot và public IPv4; xoá lab khi xong.


5. RDS — PostgreSQL được quản lý ​

Định nghĩa. RDS giúp tạo, vận hành và backup database quan hệ mà không phải tự cài OS/database lên EC2. AWS lo một phần patching, backup, phần cứng và khả năng failover; bạn vẫn lo schema, migration, query, connection pool, authorization trong DB và khôi phục dữ liệu theo yêu cầu sản phẩm.

Thiết lập RDS cho API ​

  1. Chọn PostgreSQL version, instance class và storage phù hợp với lab.
  2. Chọn VPC và DB subnet group trong private subnets. Không bật public access cho DB.
  3. Tạo RDS Security Group, chỉ inbound TCP 5432 từ Security Group của EC2/API.
  4. Bật automated backups và đặt retention theo bài tập. Dùng Multi-AZ khi cần failover/high availability và chấp nhận chi phí tương ứng.
  5. Tạo user database quyền ứng dụng riêng; không dùng master user trong app.
  6. Lưu connection string trong secret store hoặc biến môi trường được inject an toàn. Không commit password.
  7. Dùng TLS khi app kết nối, pool connection, và chạy migration bằng pipeline có kiểm soát.

Từ máy app nằm trong VPC, psql có thể kết nối endpoint private của RDS:

bash
psql "host=mydb.abc123.ap-southeast-1.rds.amazonaws.com port=5432 dbname=app user=app_user sslmode=verify-full"

Lệnh sẽ hỏi password; không truyền password trực tiếp trong shell command. Để verify-full hoạt động, cấu hình CA certificate theo hướng dẫn TLS của database engine.

Multi-AZ không đồng nghĩa read replica. Standby Multi-AZ là cho high availability/failover và thường không nhận truy vấn đọc ứng dụng. Read replica phục vụ read workload riêng và có thể có replication lag. Chọn theo mục tiêu availability hay throughput đọc; đừng thêm replica để chữa query/index kém.

Pitfall. “RDS managed” không có nghĩa là không cần backup drill. Backup có thể tồn tại nhưng restore vẫn chậm hoặc app không biết đổi endpoint. Đo thử restore và xác nhận pool reconnect sau failover. RDS cũng không làm SQL query nhanh hơn tự động.

Tài liệu: RDS User Guide, RDS backups, read replicas.


6. S3 — object storage và upload trực tiếp ​

Mental model. S3 lưu object trong bucket. Mỗi object được định danh bởi bucket + key (ví dụ raw/user-123/uuid.pdf). “Folder” thường là prefix của key, không phải thư mục POSIX. Dùng S3 cho file/blob; metadata nghiệp vụ và quyền sở hữu vẫn nên được lưu trong database.

Bảo vệ bucket ​

  • Để bucket private và bật S3 Block Public Access.
  • Ghi theo key do server tạo, không dùng nguyên filename người dùng làm key.
  • Gán IAM quyền theo bucket/prefix cần thiết; tách input raw/ và output processed/.
  • Bật versioning nếu cần khôi phục overwrite; đặt lifecycle/retention để kiểm soát chi phí.
  • Không proxy file lớn qua Node nếu có thể cấp presigned URL có thời hạn ngắn.
  • Presigned URL là bearer token: ai có URL có thể dùng đúng action cho tới khi URL hết hạn; không ghi URL vào log.

Ví dụ Node.js/TypeScript: API cấp presigned PUT ​

Cài AWS SDK for JavaScript v3:

bash
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner

Backend đã xác thực user, lấy userId từ session/JWT đã verify, tự tạo key rồi ký URL. EC2 role hoặc profile local cấp credentials cho SDK:

ts
import { randomUUID } from 'node:crypto'
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const s3 = new S3Client({ region: process.env.AWS_REGION })

export async function createUploadUrl(userId: string) {
  const key = `raw/${userId}/${randomUUID()}.pdf`
  const command = new PutObjectCommand({
    Bucket: process.env.UPLOAD_BUCKET!,
    Key: key,
    ContentType: 'application/pdf',
  })

  const url = await getSignedUrl(s3, command, { expiresIn: 60 })
  return { url, key, method: 'PUT', contentType: 'application/pdf' as const }
}

Client upload đúng method và content type đã ký:

ts
await fetch(url, {
  method: 'PUT',
  headers: { 'Content-Type': 'application/pdf' },
  body: file,
})

URL thành công không chứng minh file an toàn hoặc thuộc user đó. Sau upload, backend cần xác minh object tồn tại, kiểm tra size/type bằng server-side checks, rồi mới đánh dấu file sẵn sàng. Xem quy trình đầy đủ tại GĐ12 — File upload.

Pitfall. Tin Content-Type do browser gửi là không đủ; kiểm tra magic bytes ở pipeline xử lý. Không cấp presigned URL cho key tùy ý từ request body, nếu không user có thể ghi đè file của user khác.

Tài liệu: S3 là gì, block public access, ví dụ SDK v3.


7. Lambda — xử lý event không quản server ​

Định nghĩa. Lambda chạy handler khi được gọi bằng event hoặc request. Bạn không tự quản OS/instance; đổi lại function có runtime, quyền, memory, concurrency và timeout cần cấu hình. Function nên stateless: mỗi invocation không được giả định sẽ dùng lại cùng một process hay local file.

Dùng S3 event để xử lý file ​

Luồng đơn giản: user upload vào raw/ → S3 ObjectCreated notification → Lambda đọc metadata/đẩy job → ghi kết quả vào processed/. Khi cấu hình trigger, S3 cần permission gọi Lambda. Dùng filter prefix raw/; tránh để function output vào đúng prefix kích hoạt nó.

Ví dụ handler Node.js đọc danh sách object từ event và ghi structured log:

js
export const handler = async (event) => {
  const files = (event.Records ?? []).map((record) => ({
    bucket: record.s3.bucket.name,
    key: decodeURIComponent(record.s3.object.key.replace(/\+/g, ' ')),
    eTag: record.s3.object.eTag,
  }))

  for (const file of files) {
    console.log(JSON.stringify({ level: 'info', event: 'upload.received', ...file }))
    // Thực tế: kiểm tra DB theo idempotency key trước khi xử lý tiếp.
  }

  return { received: files.length }
}

S3 event có thể được gửi lại; handler có side effect phải idempotent. Tạo unique job key từ bucket + object key + version ID (nếu bật versioning) hoặc một định danh nghiệp vụ khác. Ghi kết quả vào prefix processed/, không upload file mới vào raw/ trong cùng trigger.

Khi nào Lambda hợp? ​

  • Resize/validate file sau upload, gửi notification, consumer nhỏ, webhook nhẹ, tác vụ event-driven.
  • Không cần chạy server liên tục; workload tự tăng/giảm theo invocation.
  • Một invocation có timeout tối đa 900 giây (15 phút). Lambda hỗ trợ response streaming qua những đường invoke nhất định; kiểm tra giới hạn API, Region, memory, timeout và chi phí trước khi chọn cho LLM streaming.
  • Job dài, cần giữ process/connections ổn định, hoặc chạy liên tục thường phù hợp container/VM hơn. Không lưu state bền trong memory hoặc /tmp.

Pitfall. Lambda gọi RDS từ VPC có thể cần ENI/network configuration, subnet capacity, SG rule và connection pooling phù hợp; “gắn vào VPC” không tự làm RDS public. Với tải burst lớn, mỗi execution environment có thể mở connection; giới hạn pool để không làm cạn connection DB.

Tài liệu: cách Lambda hoạt động, S3 trigger tutorial, timeout, response streaming.


8. CloudWatch — log, metric, alarm ​

CloudWatch có ba góc nhìn chính:

  • Logs: sự kiện có timestamp từ Lambda, app, agent hoặc AWS service. Lambda có thể ghi log vào CloudWatch Logs khi execution role có quyền; log file của EC2 không tự xuất hiện nếu bạn chưa cấu hình CloudWatch Agent hoặc logging pipeline.
  • Metrics: số theo thời gian như EC2 CPU, RDS DatabaseConnections, Lambda Errors/Duration/Throttles.
  • Alarms/Dashboards: theo dõi ngưỡng hoặc trạng thái và gửi cảnh báo/thực hiện action đã cấu hình.

Log JSON giúp tìm request xuyên qua API và worker:

ts
console.log(JSON.stringify({
  level: 'error',
  event: 'db.query_failed',
  requestId,
  route: '/documents/:id',
  errorCode: 'ECONNRESET',
}))

Không ghi access token, presigned URL, password, file contents hoặc PII không cần thiết. Đặt retention cho log group; nếu không chọn retention phù hợp, log có thể tồn tại lâu và phát sinh chi phí.

Ví dụ truy vấn CloudWatch Logs Insights để tìm lỗi mới nhất:

text
fields @timestamp, level, event, requestId, errorCode
| filter level = "error"
| sort @timestamp desc
| limit 20

Alarm lab có thể bắt Lambda Errors > 0 trong một khoảng thời gian hoặc RDS connections tiến gần giới hạn đã chọn. Một alarm cần threshold, evaluation periods và hành động thông báo; tạo alarm xong phải chủ động kích hoạt thử để xác nhận nó hoạt động.

Pitfall. “Có log” chưa phải monitoring. Khi sự cố xảy ra, cần biết metric nào tăng, log nào cùng request ID, ai nhận alarm, và dashboard mở ở đâu. Metrics và logs có pricing riêng; theo dõi ingestion, retention và query scan volume.

Tài liệu: CloudWatch, Logs Insights query, alarms.


9. Bài lab — nối cả bảy dịch vụ ​

Mục tiêu: API Node cho phép user upload file và lưu metadata trong PostgreSQL; Lambda nhận event S3; bạn tìm được log và alarm khi có lỗi.

  1. Vẽ VPC: chọn CIDR, một subnet cho app lab, hai private subnets cho DB subnet group. Đánh dấu route, IGW và SG rules.
  2. Tạo IAM roles: role EC2 chỉ được ký upload vào prefix raw/; role Lambda chỉ được đọc raw/, ghi processed/ và ghi log. Không tạo access key cho app.
  3. Tạo S3 bucket private: giữ Block Public Access, bật versioning nếu cần rollback, đặt lifecycle phù hợp lab.
  4. Tạo RDS PostgreSQL: private subnet, backup, user riêng; chỉ SG của EC2 được vào port 5432.
  5. Triển khai API lên EC2: Docker image immutable, health check, /health, structured log và giới hạn inbound. Với public demo, dùng load balancer + TLS như kiến thức ở GĐ15.
  6. Thêm endpoint upload: API xác thực user, tạo object key, ký presigned URL ngắn hạn; client PUT file thẳng lên S3; API xác minh object rồi ghi metadata vào RDS.
  7. Tạo Lambda trigger: chỉ prefix raw/; handler idempotent; không để output gọi lặp lại chính nó.
  8. Bật quan sát: tìm log theo request ID/key đã làm sạch, tạo alarm cho Lambda error hoặc lỗi app, kích hoạt thử alarm.
  9. Dọn lab: xóa DB/EC2 và resource liên quan sau khi kiểm tra backup cần giữ; kiểm tra bill/budget.

Done khi ​

  • [ ] Giải thích được request từ Internet tới EC2 và vì sao RDS không public.
  • [ ] Vẽ được đường EC2 → RDS và nêu SG rule cho port 5432.
  • [ ] API dùng EC2 role thay access key, và chỉ upload được vào S3 prefix được cấp.
  • [ ] Browser upload file qua presigned URL; server vẫn kiểm tra object sau upload.
  • [ ] S3 event kích hoạt Lambda; handler xử lý lặp an toàn và không tự tạo vòng lặp.
  • [ ] Tìm được lỗi bằng Logs Insights và chứng minh alarm đã kích hoạt.
  • [ ] Xoá tài nguyên lab và kiểm tra resource còn tồn tại.

Bước tiếp theo — Cloudflare, rồi Kubernetes ​

Khi bạn deploy được container và hiểu quyền, mạng, database, log cùng chi phí trên AWS, học GĐ17 — Cloudflare để so sánh runtime edge, bindings, object storage và queue. Sau đó học GĐ18 — Kubernetes về điều phối nhiều container; K8s không thay thế VPC, IAM, health check, connection pool hay graceful shutdown.

Học bằng cách build. Chứng minh, đừng tin.

Đồng bộ tiến độ

Đăng nhập trực tiếp để tiếp tục học trên desktop và PWA.