Dockerize Strapi CMS: Triển khai Headless CMS chuyên nghiệp với PostgreSQL và Docker Compose

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

Tại sao bạn nên Dockerize Strapi ngay hôm nay?

Strapi là một Headless CMS tuyệt vời, nhưng việc setup thủ công từng phiên bản Node.js hay PostgreSQL mỗi khi deploy là một cực hình. Mình từng mất cả buổi sáng chỉ để fix lỗi lệch version thư viện giữa máy local và server Ubuntu. Docker sinh ra để giải quyết triệt để nỗi lo “chạy máy em ngon mà”.

Kinh nghiệm thực tế cho thấy Strapi khá ngốn tài nguyên. Trên một con VPS 2GB RAM, nếu chạy không khéo, tiến trình build có thể làm treo cả hệ thống. Bằng cách sử dụng Multi-stage build, mình đã giảm dung lượng Image từ 1.2GB xuống còn khoảng 450MB. Điều này không chỉ giúp tiết kiệm băng thông mà còn đẩy nhanh tốc độ CI/CD lên gấp 3 lần.

Khởi tạo cấu trúc dự án chuẩn

Đầu tiên, hãy tạo một dự án Strapi mới. Mình luôn ưu tiên PostgreSQL cho các dự án thực tế vì khả năng chịu tải và tính toàn vẹn dữ liệu tốt hơn hẳn SQLite.

npx create-strapi-app@latest my-project --quickstart --no-run

Cấu trúc thư mục tối ưu sẽ trông như thế này:

.
├── strapi-app/
│   ├── Dockerfile
│   ├── .dockerignore
│   └── ... (source code)
├── docker-compose.yml
└── .env

Xây dựng Dockerfile tối ưu (Multi-stage build)

Trái tim của quy trình này nằm ở Dockerfile. Thay vì đóng gói tất cả công cụ build vào image cuối cùng, chúng ta sẽ chia làm hai giai đoạn: Build và Runtime. Kỹ thuật này giúp loại bỏ các dependencies dư thừa, giữ cho môi trường production luôn sạch và nhẹ.

Hãy tạo file Dockerfile trong thư mục strapi-app/:

# Stage 1: Build
FROM node:18-alpine as build
RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev vips-dev git
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

WORKDIR /opt/
COPY package.json package-lock.json ./
RUN npm install -g node-gyp
RUN npm config set fetch-retry-maxtimeout 600000 -g && npm install --only=production

WORKDIR /opt/app
COPY . .
RUN npm run build

# Stage 2: Runtime
FROM node:18-alpine
RUN apk add --no-cache vips-dev
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

WORKDIR /opt/
COPY --from=build /opt/node_modules ./node_modules
WORKDIR /opt/app
COPY --from=build /opt/app ./

EXPOSE 1337
CMD ["npm", "run", "start"]

Lưu ý quan trọng: Đừng quên file .dockerignore. Nếu bạn vô tình copy thư mục node_modules từ máy local vào container, các thư viện native như sharp sẽ bị lỗi kiến trúc hệ điều hành ngay lập tức.

Kết nối Strapi và PostgreSQL qua Docker Compose

Strapi có một “tật xấu” là thường xuyên crash nếu database chưa sẵn sàng khởi động xong. Để khắc phục, chúng ta sẽ sử dụng cơ chế healthcheck. Docker Compose sẽ đợi cho đến khi PostgreSQL thực sự sẵn sàng mới bắt đầu kích hoạt container Strapi.

Nội dung file docker-compose.yml ở thư mục gốc:

version: '3.8'

services:
  strapi-db:
    image: postgres:15-alpine
    container_name: strapi-db
    env_file: .env
    volumes:
      - strapi-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${DATABASE_USERNAME} -d $${DATABASE_NAME}"]
      interval: 10s
      timeout: 5s
      retries: 5

  strapi-app:
    container_name: strapi-app
    build: 
      context: ./strapi-app
    depends_on:
      strapi-db:
        condition: service_healthy
    env_file: .env
    ports:
      - "1337:1337"
    volumes:
      - ./strapi-app/uploads:/opt/app/public/uploads

volumes:
  strapi-data:

Mẹo thực chiến để vận hành ổn định

1. Bảo vệ dữ liệu người dùng

Mọi dữ liệu trong container sẽ biến mất khi bạn cập nhật image mới. Với Strapi, thư mục uploads chứa toàn bộ ảnh và tài liệu của bạn. Hãy luôn map thư mục này ra Volume ngoài như cách mình làm trong file Compose để tránh mất dữ liệu đáng tiếc.

2. Tối ưu RAM cho server yếu

Nếu bạn deploy lên các gói VPS giá rẻ (như DigitalOcean $6/mo hoặc Linode 1GB), hãy giới hạn RAM cho Node.js. Thêm biến môi trường NODE_OPTIONS=--max-old-space-size=1024 để tránh tình trạng Strapi chiếm dụng toàn bộ bộ nhớ và gây sập server.

3. Workflow cho môi trường Development

Khi code ở local, bạn cần tính năng hot-reload. Thay vì dùng Dockerfile cho production, hãy mount trực tiếp code vào container và chạy lệnh npm run develop. Việc này giúp bạn thấy thay đổi ngay lập tức mà không cần rebuild lại image mất thời gian.

Triển khai hệ thống

Mọi thứ đã sẵn sàng. Bây giờ bạn chỉ cần thực hiện một lệnh duy nhất để khởi động toàn bộ hệ thống:

docker-compose up -d --build

Chờ khoảng 2 phút để Docker tải image và build source code. Sau đó, hãy truy cập http://localhost:1337/admin để tạo tài khoản quản trị đầu tiên. Chúc mừng bạn, hệ thống CMS của bạn hiện đã nằm gọn trong một môi trường cô lập, an toàn và cực kỳ dễ scale.

Share: