Hoang Nguyen
09 April 2025
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)
2.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# =====================================================
2# GIAI ĐOẠN BUILD (BUILD STAGE)
3# =====================================================
4# Sử dụng Node.js 20 với Alpine Linux làm base image
5# Alpine Linux được chọn vì nhẹ và bảo mật tốt
6FROM node:20-alpine AS builder
7
8# Thiết lập thư mục làm việc trong container
9WORKDIR /app
10
11# Cài đặt các công cụ cần thiết để build
12# python3: Cần cho một số package native
13# make và g++: Cần cho việc biên dịch các dependencies C++
14RUN apk add --no-cache python3 make g++
15
16# Kích hoạt corepack để quản lý yarn
17# Corepack là công cụ quản lý package manager của Node.js
18RUN corepack enable
19
20# Copy các file quản lý dependencies
21# Chỉ copy những file này trước để tận dụng cache layer của Docker
22COPY package*.json yarn.lock ./
23
24# Cài đặt tất cả dependencies với cache
25# --mount=type=cache: Sử dụng BuildKit để cache node_modules
26# --frozen-lockfile: Đảm bảo versions khớp với yarn.lock
27# --prefer-offline: Ưu tiên dùng cache thay vì tải lại
28RUN 29 \
30 yarn install --frozen-lockfile --prefer-offline
31
32# Copy toàn bộ source code vào container
33# .dockerignore sẽ loại bỏ các file không cần thiết
34COPY . .
35
36# Build ứng dụng cho production
37RUN yarn build:prod
38
39# =====================================================
40# GIAI ĐOẠN PRODUCTION (PRODUCTION STAGE)
41# =====================================================
42# Tạo image mới cho production, giảm kích thước
43FROM node:20-alpine AS production
44
45# Thiết lập thư mục làm việc
46WORKDIR /app
47
48# Copy các file quản lý dependencies
49COPY package*.json yarn.lock ./
50
51# Kích hoạt corepack cho yarn
52RUN corepack enable
53
54# Cài đặt chỉ dependencies cho production
55# Không cài đặt devDependencies để giảm kích thước
56RUN 57 \
58 yarn install --frozen-lockfile --production --prefer-offline
59
60# Copy các file đã build từ stage trước
61# Chỉ copy những gì cần thiết cho production
62COPY /app/dist ./dist
63COPY /app/public ./public
64COPY /app/.env.production ./.env
65
66# Thiết lập biến môi trường
67# NODE_ENV=production: Chạy ở chế độ production
68# PORT=5005: Port mà ứng dụng sẽ lắng nghe
69ENV NODE_ENV=production \
70 PORT=5005
71
72# Khai báo port sẽ được sử dụng
73EXPOSE 5005
74
75# Tạo user không có quyền root để tăng bảo mật
76# addgroup: Tạo group mới
77# adduser: Tạo user mới và thêm vào group
78RUN addgroup -S appgroup && adduser -S appuser -G appgroup
79USER appuser
80
81# Lệnh khởi động ứng dụng
82# Sử dụng CMD thay vì ENTRYPOINT để có thể override khi cần
83CMD ["yarn", "start:prod"]
Tạo file .github/workflows/docker-build.yml:
1# Tên của workflow, sẽ hiển thị trong tab Actions của GitHub
2name: Build and Push Docker Image
3
4# Xác định khi nào workflow này sẽ được trigger
5on:
6 push:
7 branches: ['master'] # Chạy khi có push vào nhánh master
8 pull_request:
9 branches: ['master'] # Chạy khi có pull request vào nhánh master
10
11# Định nghĩa các biến môi trường dùng trong workflow
12env:
13 # Địa chỉ registry để push Docker image
14 REGISTRY: ghcr.io
15 # Tên image sẽ được tạo, sử dụng tên repository
16 IMAGE_NAME: ${{ github.repository }}
17
18# Định nghĩa các jobs sẽ được thực thi
19jobs:
20 build-and-push:
21 # Chọn hệ điều hành để chạy job
22 runs-on: ubuntu-latest
23
24 # Cấp quyền cần thiết cho job
25 permissions:
26 contents: read # Quyền đọc code từ repository
27 packages: write # Quyền ghi vào GitHub Packages (để push image)
28
29 # Các bước thực hiện trong job
30 steps:
31 # Bước 1: Check out code từ repository
32 - name: Checkout repository
33 uses: actions/checkout@v4
34
35 # Bước 2: Tạo file .env.production từ GitHub secrets
36 - name: Create .env.production file
37 run: |
38 echo "${{ secrets.ENV_PRODUCTION }}" > .env.production
39
40 # Bước 3: Cài đặt Docker Buildx
41 # 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
42 - name: Set up Docker Buildx
43 uses: docker/setup-buildx-action@v3
44
45 # Bước 4: Đăng nhập vào GitHub Container Registry
46 # Sử dụng GITHUB_TOKEN tự động được GitHub cung cấp
47 - name: Log in to the Container registry
48 uses: docker/login-action@v3
49 with:
50 registry: ${{ env.REGISTRY }}
51 username: ${{ github.actor }}
52 password: ${{ secrets.ACCESS_TOKEN }}
53
54 # Bước 5: Trích xuất metadata cho Docker image
55 # Tạo các tags và labels phù hợp dựa trên context của GitHub
56 - name: Extract metadata (tags, labels) for Docker
57 id: meta
58 uses: docker/metadata-action@v5
59 with:
60 images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
61 # Cấu hình các loại tags sẽ được tạo:
62 tags: |
63 type=ref,event=branch # Tag theo tên nhánh
64 type=ref,event=pr # Tag cho pull request
65 type=semver,pattern={{version}} # Tag theo version (vd: v1.0.0)
66 type=semver,pattern={{major}}.{{minor}} # Tag theo major.minor (vd: v1.0)
67 type=sha,format=long # Tag theo SHA của commit
68
69 # Bước 6: Build và push Docker image
70 - name: Build and push Docker image
71 uses: docker/build-push-action@v5
72 with:
73 context: . # Thư mục chứa Dockerfile
74 push: true # Push image sau khi build
75 tags: ${{ steps.meta.outputs.tags }} # Sử dụng tags đã tạo ở bước trước
76 labels: ${{ steps.meta.outputs.labels }} # Sử dụng labels đã tạo ở bước trước
77 # Sử dụng cache để tối ưu quá trình build
78 cache-from: type=gha # Lấy cache từ GitHub Actions
79 cache-to: type=gha,mode=max # Lưu cache lại cho các lần build sau
Vào GitHub > Settings > Secrets and Variables > Actions > Add secrets:
Tên secret | Giá trị |
ACCESS_TOKEN | Personal Access Token có quyền write:packages |
ENV_PRODUCTION | Nội dung file .env.production |