+2

Series Jenkins #7: Thực chiến – Triển khai tự động dự án Backend (Golang & Microservices)

Chào anh em! Trải qua 6 bài học, chúng ta đã đi từ những khái niệm mù mờ nhất cho đến việc nắm trong tay những vũ khí hạng nặng như Pipeline as Code, Webhook và Docker.

Nhưng lý thuyết mãi chỉ là lý thuyết nếu không được đặt vào một bài toán thực tế. Hôm nay, chúng ta sẽ bước vào trận đánh lớn: Thực chiến triển khai một dự án Backend.

Để sát với thực tế đi làm của các kỹ sư hiện nay, tôi sẽ không dùng một ví dụ "Hello World" nhàm chán. Chúng ta sẽ lấy bối cảnh là một Microservice xử lý giao dịch bán vé tự động (AFC - Automatic Fare Collection) được viết bằng Golang. Service này đòi hỏi tốc độ cao, xử lý đồng thời tốt và trong tương lai có thể cần giao tiếp với Message Broker (như Kafka/RabbitMQ) hoặc lưu trữ log phân tán (như Vitess).

Hãy xem cách bác quản gia Jenkins xử lý bài toán này gọn gàng như thế nào nhé!

1. Chuẩn bị "vũ khí": Multi-stage Dockerfile cho Golang

Một trong những sai lầm lớn nhất của người mới khi đóng gói Golang là ôm cả bộ cài Go (hàng trăm MB) lên server Production. Trong khi đó, Golang là ngôn ngữ biên dịch (compiled language), nó biên dịch ra một file thực thi (binary) duy nhất, chạy độc lập mà không cần bộ cài Go.

Do đó, kỹ thuật chuẩn ở đây là dùng Multi-stage Build (Build nhiều giai đoạn) .

Anh em tạo một Dockerfile trong source code với nội dung sau:

# Giai đoạn 1: Build (Người thợ xây)
FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Biên dịch ra file chạy tên là 'afc-service'
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o afc-service .

# Giai đoạn 2: Production (Ngôi nhà hoàn thiện)
# Dùng Alpine siêu nhẹ (chỉ khoảng 5MB)
FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# Chỉ copy đúng file thực thi từ giai đoạn 1 sang
COPY --from=builder /app/afc-service .
EXPOSE 8080
CMD ["./afc-service"]

Nhờ cách này, Docker Image cuối cùng của anh em sẽ siêu nhẹ (thường chỉ loanh quanh 10-20MB thay vì gần 1GB), giúp tốc độ pull image và deploy trên Jenkins nhanh như chớp.

2. Thiết kế Jenkinsfile Thực chiến

Khác với ví dụ ở Bài 6, khi làm thực tế, anh em hiếm khi build và chạy trực tiếp trên cùng một server chứa Jenkins. Chu trình chuẩn phải là: Build Image -> Đẩy lên một kho chứa (Docker Hub hoặc Private Registry) -> Server Production kéo Image đó về để chạy.

Dưới đây là Jenkinsfile tiêu chuẩn cho luồng chạy này:

pipeline {
    agent any
    
    environment {
        // Tên image trên Docker Hub (thay bằng username của bạn)
        IMAGE_NAME = "myusername/afc-transaction-service"
        IMAGE_TAG = "v${env.BUILD_NUMBER}"
        // ID của Credentials chứa mật khẩu Docker Hub đã lưu trong Jenkins
        DOCKER_CREDS = "docker-hub-credentials" 
    }

    stages {
        stage('1. Kéo Code & Phân tích') {
            steps {
                echo "Đang kéo mã nguồn từ nhánh main..."
                git branch: 'main', url: 'https://github.com/Ten-Cua-Ban/afc-golang-service.git'
            }
        }
        
        stage('2. Build Docker Image') {
            steps {
                echo "Áp dụng Multi-stage build cho Golang..."
                sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} -t ${IMAGE_NAME}:latest ."
            }
        }
        
        stage('3. Push Image lên Registry') {
            steps {
                echo "Đăng nhập và đẩy Image lên Docker Hub..."
                withCredentials([usernamePassword(credentialsId: DOCKER_CREDS, usernameVariable: 'USER', passwordVariable: 'PASS')]) {
                    sh "echo \$PASS | docker login -u \$USER --password-stdin"
                    sh "docker push ${IMAGE_NAME}:${IMAGE_TAG}"
                    sh "docker push ${IMAGE_NAME}:latest"
                }
            }
        }
        
        stage('4. Deploy lên Server Production') {
            steps {
                echo "Triển khai service..."
                // Trong thực tế, đoạn này thường gọi SSH sang Server Production
                // Ở đây ta mô phỏng việc update container bằng Docker Compose
                sh """
                    docker-compose pull
                    docker-compose up -d --no-deps backend-afc
                """
            }
        }
    }
    
    post {
        success {
            echo "Tuyệt vời! Bản cập nhật ${IMAGE_TAG} đã lên sóng thành công!"
            // Có thể cấu hình gửi tin nhắn về Slack/Telegram ở đây
        }
        failure {
            echo "Opps! Quá trình CI/CD thất bại. Hãy kiểm tra lại log."
        }
    }
}

3. Phân tích những điểm "đắt giá" trong Pipeline

Nhìn vào đoạn code trên, anh em sẽ thấy tư duy của một kỹ sư hệ thống:

  • Quản lý thông tin nhạy cảm (Credentials): Ở bước 3, chúng ta không bao giờ viết "toạc" mật khẩu Docker Hub vào file code. Thay vào đó, ta lưu nó trong Jenkins Credentials, và dùng block withCredentials để gọi ra. Jenkins sẽ tự động mã hóa nó thành các dấu *** trên log để bảo mật.
  • Block post {}: Đây là tính năng cực hay của Declarative Pipeline. Nó giúp Jenkins tự động thực hiện các hành động "hậu kỳ" tùy theo kết quả (Thành công hay Thất bại), ví dụ như gửi thông báo lỗi thẳng vào group chat của team vận hành.

Triển khai không gián đoạn (Khái niệm cơ bản): Ở bước 4, việc đẩy image lên Registry và kéo về chạy qua docker-compose giúp quy trình rõ ràng, rành mạch. Nếu sau này hệ thống phình to, kết hợp thêm Kafka hay Redis, anh em chỉ cần khai báo vào file docker-compose.yml trên server, Jenkins sẽ lo việc gọi lệnh update trơn tru.

Tổng kết Bài 7

Vậy là anh em đã tự tay thiết kế được một quy trình CI/CD hoàn chỉnh, giải quyết được bài toán thực tế của một dự án Backend Golang hiệu năng cao. Từ khoảnh khắc gõ git push, mọi thao tác kiểm tra, đóng gói siêu nhẹ, đẩy lên kho chứa và cập nhật server đều được bác quản gia Jenkins lo liệu trong chưa đầy 1 phút. Cảm giác nhìn tiến trình chạy xanh mướt thực sự rất "đã" đúng không?

Tuy nhiên, trong quá trình làm việc, chắc chắn anh em sẽ phải thao tác với các biến môi trường như mật khẩu Database, API Keys, hay Cert SSL. Nếu để lộ những thông tin này ra ngoài thì hậu quả khôn lường.

Ở bài học cuối cùng, Bài 8: Bảo mật, Quản lý Secret và Best Practices cho người đi làm, chúng ta sẽ thắt chặt lại toàn bộ hệ thống để đảm bảo dây chuyền tự động hóa của anh em không chỉ nhanh, mà còn an toàn tuyệt đối. Hẹn gặp lại anh em ở trạm cuối!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí