Triển khai liên tục với Jenkins Pipeline

Gần đây, tôi được yêu cầu chuyển sang sử dụng Jenkins Pipeline để triển khai dự án, đồng thời có thể thay đổi cấu hình triển khai trực tiếp trên Jenkins. Do các dự án khác sử dụng Pipeline khác biệt nhiều so với dự án của chúng tôi (Jenkins chạy trên Docker, quá trình build không thực hiện trên máy Jenkins mà trên máy phát triển), sau một thời gian thử nghiệm, tôi đã đạt được một phiên bản khả thi.

Kiến trúc tổng quan

  1. Developer push code lên repository.
  2. Push code kích hoạt Jenkins job.
  3. Jenkins thực thi script từ xa trên máy build.
  4. Máy build pull source, build và đóng gói.
  5. Chuyển package và Dockerfile tới máy tạo image.
  6. Tạo Docker image.
  7. Push image lên registry.
  8. Triển khai container.

Trong thiết lập này, chức năng build được tích hợp vào máy phát triển, do đó cần cấu hình máy phát triển và máy Jenkins.

1. Chọn registry cho image

Có thể sử dụng registry miễn phí như Docker Hub, Alibaba Cloud, hoặc tự xây dựng registry riêng với Harbor. Ở đây tôi chọn Alibaba Cloud (registry.cn-beijing.aliyuncs.com).

2. Chuẩn bị máy build (builder server)

2.1 Cài đặt Docker

Tham khảo hướng dẫn cài đặt Docker trên CentOS 7.

2.2 Cài đặt Git

sudo yum install -y git

2.3 Cài đặt .NET Core

Tham khảo tài liệu chính thức của Microsoft.

2.4 Tạo SSH key

Sử dụng git qua SSH, cần tạo key pair trên máy build:

sudo ssh-keygen -t rsa

Mặc định lưu tại /root/.ssh/id_rsa. Sao chép nội dung public key (/root/.ssh/id_rsa.pub) vào Git account.

2.5 Clone source code

sudo mkdir -p /opt/src
cd /opt/src
sudo git clone -b dev <git-repo-url>

3. Cấu hình Jenkins server

3.1 Cài đặt Jenkins (chạy trên Docker)

Tham khảo hướng dẫn cài đặt Jenkins.

3.2 Tạo SSH key trên Jenkins server

sudo ssh-keygen -t rsa
cd /root/.ssh
sudo cp id_rsa.pub id_rsa.pub.jenkins

3.3 Thiết lập kết nối SSH không cần mật khẩu từ Jenkins tới máy build

Trên máy build:

sudo mkdir -p /root/.ssh
sudo touch /root/.ssh/authorized_keys

Sao chép file id_rsa.pub.jenkins từ Jenkins vào thư mục /root của máy build, sau đó thêm vào authorized_keys:

cat /root/id_rsa.pub.jenkins >> /root/.ssh/authorized_keys

3.4 Thêm credential trong Jenkins

Vào "Manage Jenkins" → "Manage Credentials" → "Global" → "Add Credentials". Chọn loại "SSH Username with private key", nhập ID, Username, và dán nội dung private key (từ Jenkins server).

3.5 Tạo Pipeline job

Tạo job mới, chọn "Pipeline", và nhập script Jenkinsfile sau:

pipeline {
    agent any

    stages {
        stage('1. Prepare & Upload scripts') {
            steps {
                script {
                    sh '''
                    tee ./gitpull.sh <<-'EOF'
#!/bin/bash
cd /opt/src/abc
sudo git checkout dev
sudo git pull
EOF

                    tee ./build.sh <<-'EOF'
#!/bin/bash
src="/opt/src/abc"
pub="/opt/publish/abc"
sudo rm -rf "$pub/published"
sudo mkdir -p "$pub/published"
cd "$src"
sudo dotnet publish -o "$pub/published"
EOF

                    tee ./image_build.sh <<-'EOF'
#!/bin/bash
src="/opt/src/abc"
pub="/opt/publish/abc"
sudo cp "$src/Server/Dockerfile" "$pub"
cd "$pub"
sudo docker build --rm -t registry.cn-beijing.aliyuncs.com/abc/abc:latest .
sudo docker push registry.cn-beijing.aliyuncs.com/abc/abc:latest
EOF

                    tee ./deploy_stack.sh <<-'EOF'
#!/bin/bash
cd /opt/docker/compose/abc
sudo docker stack rm abc-stack
sudo docker stack deploy -c abc-stack.yml abc-stack
EOF

                    tee ./abc-stack.yml <<-'EOF'
version: '3.7'
services:
  abc:
    image: registry.cn-beijing.aliyuncs.com/abc/abc:latest
    environment:
      - TZ=Asia/Shanghai
      - ASPNETCORE_ENVIRONMENT=Production
    deploy:
      replicas: 1
      restart_policy:
        condition: any
      resources:
        limits:
          cpus: "2"
          memory: 2048M
      update_config:
        parallelism: 1
        delay: 5s
        max_failure_ratio: 0.1
        order: start-first
    ports:
      - 35000:5000
    networks:
      - swarm-net
networks:
  swarm-net:
    external: true
EOF
                    '''
                }

                withCredentials([sshUserPrivateKey(credentialsId: 'mykey', keyFileVariable: 'kf', passphraseVariable: '', usernameVariable: 'usr')]) {
                    sh "scp -o StrictHostKeyChecking=no -i ${kf} *.sh ${usr}@192.168.1.1:/opt/jenkinsfiles/"
                    sh "scp -o StrictHostKeyChecking=no -i ${kf} abc-stack.yml ${usr}@192.168.1.1:/opt/docker/compose/abc/"
                }
            }
        }

        stage('2. Pull source') {
            steps {
                withCredentials([sshUserPrivateKey(credentialsId: 'mykey', keyFileVariable: 'kf', passphraseVariable: '', usernameVariable: 'usr')]) {
                    sh "ssh -o StrictHostKeyChecking=no -i ${kf} ${usr}@192.168.1.1 'cd /opt/jenkinsfiles; sh ./gitpull.sh'"
                }
            }
        }

        stage('3. Build source') {
            steps {
                withCredentials([sshUserPrivateKey(credentialsId: 'mykey', keyFileVariable: 'kf', passphraseVariable: '', usernameVariable: 'usr')]) {
                    sh "ssh -o StrictHostKeyChecking=no -i ${kf} ${usr}@192.168.1.1 'cd /opt/jenkinsfiles; sh ./build.sh'"
                }
            }
        }

        stage('4. Build image') {
            steps {
                withCredentials([sshUserPrivateKey(credentialsId: 'mykey', keyFileVariable: 'kf', passphraseVariable: '', usernameVariable: 'usr')]) {
                    sh "ssh -o StrictHostKeyChecking=no -i ${kf} ${usr}@192.168.1.1 'cd /opt/jenkinsfiles; sh ./image_build.sh'"
                }
            }
        }

        stage('5. Deploy stack') {
            steps {
                withCredentials([sshUserPrivateKey(credentialsId: 'mykey', keyFileVariable: 'kf', passphraseVariable: '', usernameVariable: 'usr')]) {
                    sh "ssh -o StrictHostKeyChecking=no -i ${kf} ${usr}@192.168.1.1 'cd /opt/jenkinsfiles; sh ./deploy_stack.sh'"
                }
            }
        }
    }
}

3.6 Chạy job

Vào job vừa tạo, nhấn "Build Now" để thực thi.

Thẻ: Jenkins pipeline docker CI/CD .net core

Đăng vào ngày 22 tháng 8 lúc 03:45