Blog Chia SẻBlog Chia Sẻ

CI/CD với Jenkins và Docker

0

Mục tiêu là “Xây dựng hệ thống CI/CD sử dụng Jenkins multibranch pipeline and docker cho Laravel project”.

Mô hình chúng ta sẽ thực hiện

CICD Jenkins Docker

Chúng ta thực hiện các bước build 03 branches cho Laravel project  như sau:

  • Feature branch: Khi Developers commit code lên nhánh này thì Jenkins thực hiện các stage: check smc, cài đặt
    thư viện, chạy test trực tiếp trên Jenkins.

  • Develop branch: Khi accepted code vào develop branch, thì thực hiện các stage check scm, cài đặt thư viện,
    chạy test và đồng bộ code sang test server, sau đó thực hiện chạy ứng dụng trên môi trường test với docker
    containers

  • Master branch: Khi yêu cầu merge từ develop to master branch được accept, thì thực hiện các stage check
    scm, cài đặt thư viện, chạy test và đồng bộ code sang prod server, sau đó thực hiện chạy ứng dụng trên
    môi trường product với docker containers. Ở bước này, nếu có điều kiện chúng ta thực hiện thêm stage
    “integration test”

Yêu cầu trước khi thực hiện cấu hình:

  • Máy chủ Jenkins, cài đặt các PHP7 modules cho Testing
  • Máy chủ SCM (GitLab), kết nối webhook với Jenkins

  • Test Server: Cài đặt docker, docker-compose

  • Prod Server: Cài đặt docker, docker-compose

1. Tạo thư mục chứa project (code)

Thư mục project gồm: source code, Jenkinsfile, docker-compose.yml

Khi đó cấu trúc thư mục được xây dựng như sau

cicd jenkins docker directory tree

Nội dung trong cấu trúc thư mục như sau:

1.1 Jenkinsfile

Tệp tin Jenkinsfile được viết bằng scripted pipeline có nội dung sau:

        node {
            currentBuild.result = "SUCCESS"
            try {
                stage('Checkout'){
                    checkout scm
                }

                stage("Composer Update") {
                // Run composer update
                    sh 'cd src && composer update'
                }

                stage("PHPUnit") {
                    // Run PHPUnit
                    sh 'cd src && ./vendor/bin/phpunit'
                }
                // Deploy to each branch
                switch (env.BRANCH_NAME) {
                    case "master":
                        stage("Build Docker"){
                            sh 'rsync -avzhP --delete --exclude=.git/ --exclude=Jenkinsifle $WORKSPACE/ root@192.168.1.111:/root/docker/'
                            //build docker & mount source to /var/www/html
                            sh 'ssh root@192.168.1.111 "cd /root/docker/ && bash docker-compose.sh"'
                            //push image to private dockerhub
                            //....
                        }
                        break
                    case "develop":
                        stage("Build Docker"){
                            sh 'rsync -avzhP --delete --exclude=.git/ --exclude=Jenkinsifle $WORKSPACE/ root@192.168.1.112:/root/docker/'
                            //build docker & mount source to /var/www/html
                            sh 'ssh root@192.168.1.112 "cd /root/docker/ && bash docker-compose.sh"'
                        }
                        break
                    default:
                // No deployments for other branches
                        break
                }
            }
            catch (err) {
                    currentBuild.result = "FAILURE"
                        mail body: "project build error is here: ${env.BUILD_URL}" ,
                        from: 'info@vnsys.wordpress.com',
                        replyTo: 'info@vnsys.wordpress.com',
                        subject: 'project build failed',
                        to: 'keepwalking86@vnsys.wordpress.com'
                    throw err
                }    
        }
    

Trong script này, chúng ta sử dụng biến “currentBuild.result” để xác định kết quả trạng thái build là
“SUCCESS” hay “FAILURE”

Sử dụng try/catch block. Trong đó chúng ta sử dụng “try” block để định nghĩa 4 stage đơn giản sau:

  • Checkout: sẽ kiểm tra source code từ GitLab và pull project từ gitlab có địa chỉ http://gitlab.example.local/dungnv/laravel-docker-compose.git
  • Composer_Update: sẽ thực hiện lệnh “composer update”
  • PHPUnit: Sẽ thực hiện lệnh phpunit cho để test source code. Tùy thuộc vào nhu cầu và điều kiện
    chúng ta sẽ thực hiện chi tiết và nhiều hơn các bước test. Trong bài viết này, chúng ta chỉ sử dụng PHPUnit
    cho test đơn giản
  • Build Docker: Sẽ thực hiện đồng bộ code sang server (test/prod), tùy thuộc vào điều
    kiện kiểm tra. Nếu source code trên develop branch, khi đó nó sẽ đồng bộ sang test server và sau đó chạy
    script docker-composer.sh để thực hiện build docker
    images và chạy các container. Nếu source code trên master branch, khi đó code sẽ được đồng bộ sang
    production server và chạy docker-composer.sh để
    thực hiện build docker images và chạy các container. Đối với các nhánh khác thì chỉ thực hiện 3 bước đầu
    tiên.
  • Khối “catch” được sử dụng khi biến “ currentBuild.result” xác định kết quả trạng thái build
    FAILURE”, khi đó nó thực hiện gửi thông báo build lỗi qua mail

1.2 ./docker Directory

Thư mục ./docker chứa thông tin cấu hình để build các image: nginx và php-fpm

  • Nội dung tệp Dockerfile cho nginx docker image
        FROM nginx:latest

        MAINTAINER KeepWalking86

        ADD ./default.conf /etc/nginx/conf.d/
        RUN mkdir -p /var/www/example/
        #ADD ./src /var/www/example/public/
        RUN chown -R nginx:nginx /var/www/example

        #Install net tools
        RUN apt-get update
        RUN apt-get install net-tools lsof -y

        #Change nginx uid & gid
        RUN usermod -u 1000 nginx && groupmod -g 1000 nginx

        ##Clearing the apt-get caches
        RUN apt-get clean

        ## Expose ports
        EXPOSE 80
    
  • Ngoài ra ta sẽ add tệp cấu hình default nginx cho site (ví dụ example.local)
        server {
                listen 80;
                listen [::]:80 ipv6only=on;

            # Log files for Debugging
                access_log /var/log/nginx/laravel-access.log;
                error_log /var/log/nginx/laravel-error.log;

            # Webroot Directory for Laravel project
                root /var/www/example/public;
                index index.php index.html index.htm;

                # Your Domain Name
                server_name example.local;
                location ~* \.(jpg|jpeg|gif|css|png|js|ico|txt|srt|swf|zip|rar|html|htm|pdf)$ {
                        access_log        off;
                        log_not_found     off;
                        expires 30d; # caching, expire after 30 days
                }

                location / {
                        try_files $uri $uri/ /index.php?$query_string;
                }

            # PHP-FPM Configuration Nginx
                location ~ \.php$ {
                        try_files $uri =404;
                        fastcgi_split_path_info ^(.+\.php)(/.+)$;
                        #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
                        fastcgi_index index.php;
                        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                        include fastcgi_params;
                        fastcgi_pass php-fpm:9000;
                }
        }
        
  • Nội dung tệp tin Dockerfile cho php-fpm docker image
        FROM php:7.2-fpm

        RUN apt-get update
        RUN apt-get install libxml2-dev unzip libmcrypt-dev zlib1g-dev -y
        #Using docker-php-ext-install to install php modules
        RUN docker-php-ext-install pdo_mysql mysqli mbstring xml opcache zip

        EXPOSE 9000
        CMD ["php-fpm", "-F"]
    

1.3 Tệp Compose (docker-compose.yml)

Chúng ta tạo tệp tin docker-compose.yml để định nghĩa
các service và kết hợp chúng với nhau để chạy ứng dụng. Tệp tin được định nghĩa gồm 03 service: db, php-fpm và
webapp

        version: "3"

        services:
            db:
            image: mariadb:latest
            volumes:
                - ./db:/var/lib/mysql/laravel
            restart: always
            environment:
                MYSQL_ROOT_PASSWORD: P@ssw0rd
                MYSQL_DATABASE: laravel
                MYSQL_USER: keepwalking
                MYSQL_PASSWORD: P@ssw0rd

            php-fpm:
            build: ./docker/php-fpm
            volumes:
                - ./src:/var/www/example/

            webapp:
            depends_on:
                - db
                - php-fpm
            build: ./docker/nginx
            ports:
                - 8081:80
            restart: always
            volumes:
                - ./src:/var/www/example/
    

1.4 Tệp bash script (docker-compose.sh)

Chúng ta tạo tệp tin docker-compose.sh cho phép chạy tự động để kiểm tra
điều kiện port, container và gọi tệp tin docker-compose.yml

        #!/bin/bash
        PORT="8081"

        #Check port exists
        netstat -nta |grep -i listen |grep $PORT &>/dev/null
        if [[ $? -eq 0 ]]; then
            echo "Port ${PORT} is existing. Please, use different ports for Nginx"
            exit 0;
        else
            echo "Creating docker containers for NGINX MARIADB PHP7.2"
            sleep 2
            docker-compose up -d
        fi
    

1.5 ./src directory

Cuối cùng là thư mục ./src mà chứa dữ liệu source code (ở đây sử dụng Laravel framework) để cho phép bind
sourcecode giữa docker host và container.

Source code chúng ta có thể download tại https://github.com/laravel/framework

3.2 Tạo repository trên GitLab

Chúng ta sẽ tạo repository trên GitLab với tên “laravel-docker-compose” khi đó đường dẫn repository là:
http://gitlab.example.local/dungnv/laravel-docker-compose.git

Thực hiện push project lên GitLab repository

Truy cập thư mục chứa project, thực hiện đẩy lên gitlab repository “multibranch_pipeline_docker”

git init
        git remote add origin http://gitlab.example.local/dungnv/laravel-docker-compose.git
        git add  .
        git commit -m "Add repo"
        git push origin master
    

Sau đó chúng ta thực hiện tạo thêm một branch “develop

3.3 Tạo Job (item) trên Jenkins

Thực hiện tạo Job (item) “multibranch_pipleline_docker” trên Jenkins

Tại thẻ Branch Sources → vào thông tin đường dẫn repo “http://gitlab.example.local/dungnv/laravel-docker-compose.git
→ Chọn Credentials

Tại thẻ Build Configuration → Sử dụng với tệp Jenkinsfile với đường dẫn gốc của repository.

→ nhấn Save để lưu lại Jenkins job.

laravel docker compose jenkins job

a. Kiểm tra build trên Jenkins

Truy cập giao diện web của Jenkins, khi đó nó scan ra được 2 branch: master và develop. Quá trình build cũng bắt
đầu được thực hiện

scan multibranch pipeline log

Chúng ta truy cập vào từng branch vào xem kết quả

Trên nhánh master

  • Xem chi tiết kết quả build qua console output

master console output

  • Xem kết quả build qua stage view

Trên nhánh develop

  • Xem kết quả build qua console output

develop console output

  • Xem kết quả build qua stage view

pipeline develop

b. Kiểm tra trên 02 Server (Test/Prod)

  • Trên Prod Server

docker containers on prod

  • Trên Test Server

docker containers on test server

Chúng ta thấy docker-compose đã tạo 03 containers ở mỗi Test/Prod server cho chạy ứng dụng Laravel.

Câu hỏi/câu trả lời này có giải quyết được sự cố của bạn không?

Đánh giá

Ý kiến ​​(không bắt buộc)

0Nó rất hữu ích cho mọi người.

Tìm kiếm

Xem các câu hỏi liên quan