Givepo
Blog

Cloud và DevOps: Hướng dẫn thực tế về Docker, CI/CD và triển khai đáng tin cậy

Từ một Dockerfile sẵn sàng cho production đến pipeline tự động và phát hành không gián đoạn: những phương pháp DevOps giúp các đội nhỏ phát hành nhiều lần mỗi ngày mà không làm hỏng hệ thống.

Đội ngũ Givepo
5 phút đọc
Illustration of a cloud above a CI/CD pipeline with build, test and scan steps passed and deploy in progress, next to a stack of containersCloud & DevOps

Viết code chỉ là một nửa của việc phát hành phần mềm. Nửa còn lại là build, kiểm thử, đưa lên server và giữ cho nó vận hành, lý tưởng nhất là nhiều lần mỗi tuần mà không phải thức khuya xử lý sự cố. DevOps là tập hợp các phương pháp biến điều đó thành thường lệ, còn container, pipeline CI/CD và hạ tầng cloud là những công cụ giúp nó khả thi.

DevOps thực sự là gì

DevOps không phải là một chức danh hay một công cụ. Đó là ý tưởng rằng những người xây dựng phần mềm và những người vận hành nó cùng chịu trách nhiệm cho cả hai, được hỗ trợ bởi tự động hóa ở mức cao. Chương trình nghiên cứu DORA tóm tắt hiệu quả phát hành bằng bốn chỉ số:

  • Tần suất triển khai: bạn phát hành lên production thường xuyên đến mức nào.
  • Thời gian từ thay đổi đến production: một commit mất bao lâu để lên production.
  • Tỷ lệ thay đổi thất bại: bao nhiêu lần phát hành gây ra lỗi cần khắc phục.
  • Thời gian khôi phục dịch vụ: bạn phục hồi nhanh đến đâu khi một lần phát hành thất bại.

Các đội hiệu quả cao đạt điểm tốt ở cả bốn chỉ số cùng lúc. Hóa ra phát hành những thay đổi nhỏ thường xuyên vừa nhanh hơn vừa an toàn hơn so với phát hành những gói lớn hiếm hoi.

Container với Docker

Một container image đóng gói ứng dụng của bạn cùng môi trường chạy, thư viện hệ thống và cấu hình mặc định chính xác. Một container là một phiên bản đang chạy của image đó. Vì image giống hệt nhau trên laptop, trong CI và trên production, vấn đề "máy tôi chạy được mà" không còn nữa.

Build nhiều giai đoạn giữ image production nhỏ gọn và an toàn: dependency được cài và ứng dụng được biên dịch ở các giai đoạn tạm thời, chỉ kết quả đầu ra được sao chép vào một image chạy tối giản. Đây là ví dụ cho một ứng dụng Next.js build với output: 'standalone':

Dockerfile
# syntax=docker/dockerfile:1
FROM node:24-alpine AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile

FROM node:24-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN corepack enable && pnpm build

FROM node:24-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
# Never run the application as root
RUN addgroup -S app && adduser -S app -G app
COPY --from=build --chown=app:app /app/.next/standalone ./
COPY --from=build --chown=app:app /app/.next/static ./.next/static
COPY --from=build --chown=app:app /app/public ./public
USER app
EXPOSE 3000
CMD ["node", "server.js"]

Những phương pháp tốt với container nên áp dụng ngay từ đầu:

  • Thêm file .dockerignore để node_modules, .git và các bí mật cục bộ không bao giờ lọt vào build context.
  • Cố định phiên bản base image và build lại định kỳ để nhận các bản vá bảo mật.
  • Chạy một tiến trình cho mỗi container và ghi log ra standard output để nền tảng thu thập.
  • Truyền cấu hình qua biến môi trường, và giữ bí mật hoàn toàn bên ngoài image.
  • Lưu dữ liệu trong volume hoặc dịch vụ được quản lý, không bao giờ bên trong container, vì container có thể bị thay thế bất cứ lúc nào.

Cho môi trường phát triển và các triển khai nhỏ, Docker Compose mô tả nhiều container và cách chúng kết nối trong một file duy nhất:

YAML
services:
  app:
    build: .
    ports:
      - '3000:3000'
    environment:
      DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/app
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: app
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U app']
      interval: 5s
      retries: 10

volumes:
  db-data:

Pipeline CI/CD

Continuous integration (CI) nghĩa là mọi lần push đều được build và kiểm thử tự động, để vấn đề lộ ra trong vài phút thay vì vài ngày trước khi phát hành. Continuous delivery (CD) mở rộng điều đó: mọi thay đổi vượt qua pipeline đều được đóng gói sẵn sàng triển khai, và với continuous deployment nó được đưa lên production tự động.

Một pipeline cơ bản vững chắc trên GitHub Actions cài dependency, kiểm tra kiểu, chạy test và build cho mọi pull request và mọi lần push lên main:

YAML
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: pnpm/action-setup@v4
        with:
          version: 10
      - uses: actions/setup-node@v5
        with:
          node-version: 24
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm typecheck
      - run: pnpm test
      - run: pnpm build

Từ đó, hãy thêm các bước cho những vấn đề đội của bạn hay gặp phải: quét lỗ hổng dependency và container image, test end-to-end trên môi trường preview, và một job triển khai chỉ chạy trên main sau khi mọi thứ đều xanh. Giữ pipeline nhanh. Pipeline mười phút sẽ được chạy; pipeline bốn mươi phút sẽ bị bỏ qua.

Chiến lược triển khai

Cách bạn phát hành quan trọng không kém những gì bạn phát hành. Mục tiêu là không gián đoạn và có một đường lui nhanh, đơn giản khi có sự cố:

  • Rolling update: thay thế từng nhóm nhỏ instance. Đơn giản và là mặc định trên hầu hết nền tảng, nhưng phiên bản cũ và mới chạy song song trong một khoảng thời gian.
  • Blue-green: chạy phiên bản mới cạnh phiên bản cũ, kiểm thử nó, rồi chuyển toàn bộ lưu lượng sang cùng lúc. Rollback chỉ là chuyển ngược lại.
  • Canary: chuyển một phần nhỏ lưu lượng, chẳng hạn 5%, sang phiên bản mới, theo dõi tỷ lệ lỗi và độ trễ, rồi tăng dần.
  • Feature flag: triển khai code ở trạng thái tắt và bật nó cho những người dùng được chọn sau. Điều này tách triển khai khỏi phát hành.

Thay đổi cơ sở dữ liệu cũng cần cẩn trọng như vậy. Dùng mẫu expand and contract: trước hết thêm cột hoặc bảng mới theo cách tương thích ngược, triển khai code dùng chúng, và chỉ xóa cấu trúc cũ ở một lần phát hành sau. Nhờ vậy phiên bản trước của ứng dụng vẫn hoạt động trong lúc triển khai và khi rollback.

Hạ tầng cloud, nói một cách đơn giản

Các nhà cung cấp cloud có một dải lựa chọn từ máy ảo thuần túy (IaaS), qua các nền tảng được quản lý và dịch vụ container (PaaS), đến hàm serverless nơi bạn chỉ cung cấp code. Càng đi xa, bạn càng ít phải tự quản lý và càng ít quyền kiểm soát. Với hầu hết các đội, điểm cân bằng là dịch vụ được quản lý cho những phần khó (cơ sở dữ liệu, hàng đợi, object storage, bộ cân bằng tải) và container cho ứng dụng.

Hãy định nghĩa hạ tầng đó dưới dạng code với các công cụ như Terraform, OpenTofu hoặc Pulumi. Khi đó server, mạng và DNS của bạn nằm trong hệ thống quản lý phiên bản, được review như code và có thể tạo lại trong vài phút, kể cả một môi trường staging thực sự giống production.

Những điều cốt yếu về quản lý và bảo mật server

  • Đặc quyền tối thiểu: mỗi người, mỗi dịch vụ và mỗi job CI chỉ có những quyền nó cần.
  • Bí mật thuộc về trình quản lý bí mật hoặc phần cài đặt được mã hóa của nền tảng, không bao giờ nằm trong repository hay image.
  • Vá lỗi hệ điều hành, base image và dependency theo lịch, tự động hóa ở những chỗ có thể.
  • Mạng riêng: giữ cơ sở dữ liệu tránh xa internet công cộng, chỉ để lộ bộ cân bằng tải.
  • HTTPS ở mọi nơi, với chứng chỉ được gia hạn tự động.
  • Bản sao lưu chỉ có giá trị khi đã khôi phục thử: tự động hóa, mã hóa, lưu ở một nơi khác và thường xuyên thử khôi phục.
  • Giám sát và cảnh báo về tính sẵn sàng, tỷ lệ lỗi và độ trễ, có lịch trực và runbook viết sẵn cho các sự cố thường gặp.

Những điểm chính

  • Container giúp các bản build có thể tái lập. Dùng build nhiều giai đoạn, base image nhỏ và người dùng không phải root.
  • Tự động hóa con đường đến production: mọi thay đổi đều được build, kiểm thử và quét theo cùng một cách.
  • Phát hành thay đổi nhỏ thường xuyên, và dùng blue-green, canary hoặc feature flag để giảm rủi ro khi phát hành.
  • Quản lý hạ tầng dưới dạng code, dùng dịch vụ được quản lý cho các phần có trạng thái, và tập khôi phục bản sao lưu.

Kết luận

DevOps mang lại sự bình tĩnh chứ không chỉ tốc độ. Khi các bản build có thể tái lập, pipeline phát hiện vấn đề sớm và mọi lần phát hành đều có thể rollback trong một phút, việc triển khai không còn là sự kiện mà trở thành thường lệ. Hãy bắt đầu với một Dockerfile và một pipeline CI chạy các bài test của bạn, rồi tự động hóa từng bước thủ công một.

Đọc thêm

  • #CI/CD
  • #Cloud
  • #DevOps
  • #Docker
Tác giả
Đội ngũ Givepo

Givepo là công ty IT chuyên xây dựng website, ứng dụng di động và phần mềm theo yêu cầu, giúp doanh nghiệp của bạn phát triển vượt bậc.

Chia sẻ bài viết

Tư vấn miễn phí 30 phút

Trao đổi với đội ngũ của chúng tôi về ý tưởng, phạm vi và ngân sách của bạn.

Đặt lịch tư vấn

Bài viết khác

Blog
AI & Học máy
·7 phút đọc

AI và Machine Learning trong thực tế: Mang lại giá trị kinh doanh ở đâu

Gạt bỏ những lời quảng cáo thổi phồng. Hiểu cách machine learning và AI tạo sinh thực sự hoạt động, chúng tạo ra giá trị đo lường được ở đâu, và cách triển khai dự án AI đầu tiên đến tay người dùng thay vì dừng lại ở bản demo.

Xem chi tiết
Phát triển web
·5 phút đọc

Phát triển web hiện đại với Next.js, React và TypeScript: Các phương pháp tốt nhất

Server Components, chiến lược render, dữ liệu an toàn kiểu và Core Web Vitals. Hướng dẫn thực tế để xây dựng ứng dụng web nhanh, dễ bảo trì với bộ công nghệ mà hầu hết các đội đang chọn.

Xem chi tiết
Backend & API
·6 phút đọc

Giải thích kiến trúc backend: REST API, microservices và cơ sở dữ liệu mở rộng được

Cách thiết kế REST API mà lập trình viên thích dùng, khi nào microservices đáng với chi phí, cách mô hình hóa cơ sở dữ liệu chịu được tải lớn, và những mẫu thiết kế giữ cho hệ thống backend nhanh và ổn định.

Xem chi tiết