DOCKERNESTJSUBUNTUTECHNICAL

GitHub Container Registry (GHCR)

Hoàng Nguyễn

Hoàng Nguyễn

Thumbnail

Hướng dẫn này giúp bạn cấu hình Docker và thiết lập workflow CI/CD trên GitHub để:

  1. Build và push Docker image lên GitHub Container Registry (GHCR)
  1. Tự động SSH vào server và chạy script deploy.sh để làm mới container ( thật ra có thể dùng watchtower để watch thay vì như mình)

1. 🐳 Tạo Dockerfile cho NestJS

# =====================================================
# GIAI ĐOẠN BUILD (BUILD STAGE)
# =====================================================
# Sử dụng Node.js 20 với Alpine Linux làm base image
# Alpine Linux được chọn vì nhẹ và bảo mật tốt
FROM node:20-alpine AS builder

# Thiết lập thư mục làm việc trong container
WORKDIR /app

# Cài đặt các công cụ cần thiết để build
# python3: Cần cho một số package native
# make và g++: Cần cho việc biên dịch các dependencies C++
RUN apk add --no-cache python3 make g++

# Kích hoạt corepack để quản lý yarn
# Corepack là công cụ quản lý package manager của Node.js
RUN corepack enable

# Copy các file quản lý dependencies
# Chỉ copy những file này trước để tận dụng cache layer của Docker
COPY package*.json yarn.lock ./

# Cài đặt tất cả dependencies với cache
# --mount=type=cache: Sử dụng BuildKit để cache node_modules
# --frozen-lockfile: Đảm bảo versions khớp với yarn.lock
# --prefer-offline: Ưu tiên dùng cache thay vì tải lại
RUN --mount=type=cache,target=/root/.yarn/cache \
    --mount=type=cache,target=/root/.yarn/berry/cache \
    yarn install --frozen-lockfile --prefer-offline

# Copy toàn bộ source code vào container
# .dockerignore sẽ loại bỏ các file không cần thiết
COPY . .

# Build ứng dụng cho production
RUN yarn build:prod

# =====================================================
# GIAI ĐOẠN PRODUCTION (PRODUCTION STAGE)
# =====================================================
# Tạo image mới cho production, giảm kích thước
FROM node:20-alpine AS production

# Thiết lập thư mục làm việc
WORKDIR /app

# Copy các file quản lý dependencies
COPY package*.json yarn.lock ./

# Kích hoạt corepack cho yarn
RUN corepack enable

# Cài đặt chỉ dependencies cho production
# Không cài đặt devDependencies để giảm kích thước
RUN --mount=type=cache,target=/root/.yarn/cache \
    --mount=type=cache,target=/root/.yarn/berry/cache \
    yarn install --frozen-lockfile --production --prefer-offline

# Copy các file đã build từ stage trước
# Chỉ copy những gì cần thiết cho production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
COPY --from=builder /app/.env.production ./.env

# Thiết lập biến môi trường
# NODE_ENV=production: Chạy ở chế độ production
# PORT=5005: Port mà ứng dụng sẽ lắng nghe
ENV NODE_ENV=production \
    PORT=5005

# Khai báo port sẽ được sử dụng
EXPOSE 5005

# Tạo user không có quyền root để tăng bảo mật
# addgroup: Tạo group mới
# adduser: Tạo user mới và thêm vào group
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

# Lệnh khởi động ứng dụng
# Sử dụng CMD thay vì ENTRYPOINT để có thể override khi cần
CMD ["yarn", "start:prod"] 

2. ⚙️ Tạo GitHub Actions Workflow

Tạo file .github/workflows/docker-build.yml:

# Tên của workflow, sẽ hiển thị trong tab Actions của GitHub
name: Build and Push Docker Image

# Xác định khi nào workflow này sẽ được trigger
on:
  push:
    branches: ['master'] # Chạy khi có push vào nhánh master
  pull_request:
    branches: ['master'] # Chạy khi có pull request vào nhánh master

# Định nghĩa các biến môi trường dùng trong workflow
env:
  # Địa chỉ registry để push Docker image
  REGISTRY: ghcr.io
  # Tên image sẽ được tạo, sử dụng tên repository
  IMAGE_NAME: ${{ github.repository }}

# Định nghĩa các jobs sẽ được thực thi
jobs:
  build-and-push:
    # Chọn hệ điều hành để chạy job
    runs-on: ubuntu-latest

    # Cấp quyền cần thiết cho job
    permissions:
      contents: read # Quyền đọc code từ repository
      packages: write # Quyền ghi vào GitHub Packages (để push image)

    # Các bước thực hiện trong job
    steps:
      # Bước 1: Check out code từ repository
      - name: Checkout repository
        uses: actions/checkout@v4

      # Bước 2: Tạo file .env.production từ GitHub secrets
      - name: Create .env.production file
        run: |
          echo "${{ secrets.ENV_PRODUCTION }}" > .env.production

      # Bước 3: Cài đặt Docker Buildx
      # Buildx là plugin của Docker cho phép build đa nền tảng và có nhiều tính năng mở rộng
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      # Bước 4: Đăng nhập vào GitHub Container Registry
      # Sử dụng GITHUB_TOKEN tự động được GitHub cung cấp
      - name: Log in to the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.ACCESS_TOKEN }}

      # Bước 5: Trích xuất metadata cho Docker image
      # Tạo các tags và labels phù hợp dựa trên context của GitHub
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          # Cấu hình các loại tags sẽ được tạo:
          tags: |
            type=ref,event=branch     # Tag theo tên nhánh
            type=ref,event=pr         # Tag cho pull request
            type=semver,pattern={{version}}  # Tag theo version (vd: v1.0.0)
            type=semver,pattern={{major}}.{{minor}}  # Tag theo major.minor (vd: v1.0)
            type=sha,format=long      # Tag theo SHA của commit

      # Bước 6: Build và push Docker image
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: . # Thư mục chứa Dockerfile
          push: true # Push image sau khi build
          tags: ${{ steps.meta.outputs.tags }} # Sử dụng tags đã tạo ở bước trước
          labels: ${{ steps.meta.outputs.labels }} # Sử dụng labels đã tạo ở bước trước
          # Sử dụng cache để tối ưu quá trình build
          cache-from: type=gha # Lấy cache từ GitHub Actions
          cache-to: type=gha,mode=max # Lưu cache lại cho các lần build sau



3. 🔐 Cấu hình Secrets trong GitHub

Vào GitHub > Settings > Secrets and Variables > Actions > Add secrets:

Tên secretGiá trị
ACCESS_TOKENPersonal Access Token có quyền write:packages
ENV_PRODUCTIONNội dung file .env.production

Copyright © 2025 Hoang. All rights reserved.