CI/CD

Cấu hình CI/CD với Github

CI/CD là gì?

Có rất nhiều khái niệm cả chính thống và cả tà đạo về CI/CD nhưng theo mình thì CI/CD hiểu đơn giản nhất là CI (Continuous Integration) và CD (Continuous Delivery) tức là quá trình tích và triển khai hợp nhanh và liên tục.

Về mặt khái niệm là vậy nhưng về mặt triển khai thì CI/CD là quá trình tự động thực hiện các quá trình build, test, release, deploy khi có các trigger như commit/merge code lên một branch định sẵn hoặc có thể là tự động chạy theo một lịch cố định.

Bạn có thể xem qua bài viết của mình về Tổng quan về CI/CD pipelines để tìm hiểu thêm về CI/CD nhé!

Đây là một mô hình mà công ty minh đã apply cho một dự án:

  • Khi hoàn thành một feature thì teamlead tạo merge request rồi merge vào bran develop, đúng 5h chiều hàng ngày hệ thống sẽ tự động build, test, quét sonar…. và deploy lên develop eviroment (quá trình này là CD), không trtigger merger code để deploy với branch này vì code được merge vào đây liên tục nếu trigger merger code sẽ dẫn đến việc build liên tục, làm chậm hệ thống.
  • Với branch prepro thì sẽ được trigger mỗi lần có sự thay đổi về code sẽ tự động thực hiện các bước như với branch develop.
  • Với branch master thì có hơi khách một chúc, Git cũng sẽ tự động trigger và tiến hành các bước build, run unit test, quét sonar…. nhưng không tiến hành deploy (quá trình này chỉ là CI) lên server mà chỉ được deploy khi có confirm từ một người có quyền hoặc deploy bằng tay để đảm bảo quá trình delevery sản phẩm không xảy ra lỗi và đúng với thời gian khách hàng mong muốn.

Giới thiệu về GitHub Actions

Github actions được sinh ra để hỗ trợ việc tự động hóa các tác vụ trong vòng đời của một phần mềm. Git actions hoạt động theo hướng sự kiện, nghĩa là nó sẽ thực hiện một loạt commands đã được định nghĩa sẵn khi có một sự kiện được xảy ra. Ví dụ như, bạn có thể cấu hình để mỗi khi có người tạo một mergers request lên một repository nào đó hệ thống sẽ tự động run commands để run các unit test case của bạn.

Mô hình mô tả cách một git actions có thể tiến hành một công việc bất kì (như trong ví dụ trên là run các unit test case có sẵn). Một sự kiện sẽ tự động kích hoạt workflow đã được định nghĩa sẵn trong một job. Mỗi job sử dụng steps control để kiểm soát acttions. Actions là comands thực hiện một hành động cụ thể nào đó (run các unit test case)

Xem thêm: Sử dụng Git hiệu quả

Các thành phần của một Github Actions

Dưới đây là danh sách nhiều thành phần của GitHub Acttions hoạt động cùng nhau để chạy công việc. Bạn có thể thấy các thành phần này tương tác với nhau như thế nào.

Workflows là một tập các hành động mà bạn thêm và reponsitory của mình để định nghĩa các hành động. các jobs trong workflows có thể được thực thi theo lịch hoặc dựa vào một trigger nào đó. Workflows có thể được định nghĩa để build, test, release, deplpy…. một dự án trên Github. Một workflows được định nghĩa bằng file yml.

Events là một trigger đặc biệt để workflow bắt đầu. ví dụ như, bạn có thể cấu hình để workflow bắt đầu khi có một người nó đó push code hoặc tạo merger request lên branch develop. Bạn có thể sử dụng repository dispatch webhook để trigger một workflow khi một sự kiện bên ngoài xảy ra (Đọc cho vui chứ đoạn này cũng không dùng mấy 😉 ). Các bạn có thể xem danh sách các events có thể dùng để trigger một workflow ở đây.

Jobs là tập hợp các bước thược hiện một công việc của một runner. Mặc định thì các jobs trong một workflow được chạy song song. Bạn cũng có thể cấu hình để các jobs chạy một các tuần tự. Ví dụ trong một workflow có thể có jobs là build, run test case. Nhưng nếu build fails thì test case sẽ không được run.

Steps là một tác vụ độc lập nó có thể là một command trong một jobs. Mỗi steps có thể là một action hoặc một command để thực hiện một hành động nào đó. Mỗi step trong một job thực thi trong cùng một runner, có thể share data từ steps này với step khác.

Actions là một command độc lập khi kết hợp lại tạo thành một steps để tạo ra jobs trong workflow. Actions là đơn vị nhỏ nhất của một workflow là thành phần trực tiếp thực hiện các tác vụ mong muốn.

Runners là một server được cài đặt sẵn GitHub Actions runner application. Bạn có thể sử dụng runner hosted bởi GitHub hoặc bạn có thể tự host cho mình để sử dụng. Một runner luôn sẵn sàng lắng nghe các jobs, run một job tại một thời điểm, report process, logs và trả kết quả về cho GitHub. Với GitHub-hosted runner mỗi job được runs trên một máy ảo hoàn tòan mới (Điều này có nghĩa là mỗi job bạn đều cần có bước setup môi trường từ đầu )

GitHub-hosted runner chạy trên Ubuntu Linux, Microsoft Windows và MacOS. Các bạn có thể đọc thêm thông tin ở “Virtual environments for GitHub-hosted runners.”. Nếu bạn muốn một hệ điều hành khác hoặc một cấu hình phần cứng cụ thể bạn có thể host một Github-hosted runner cho mình, xem thêm thông tin ở “Hosting your own runners.”.

Xem thêm: CI/CD – GitHub Actions và các kiến thức cơ bản

Tạo một workflow với Github actions.

Cách 1: tạo ra file yml sau đó push lên thư mục .github/workflows/ Với cách này đơn giản là chúng ta tạo ra một file yml trong thư mục .github/workflows/ rồi push lên git

Cách 2: tạo một workflow theo các mẫu có sẵn

Bước 1: Vào git responsitory của bạn chọp tab Action

Bước 2: Chọn “Setup this workflow” git sẽ chọn flow default hoặc chọn một mẫu có sẵn trong danh sách git sẽ tạo ra file workflows theo những mẫu có sẵn.

Bước 3: Update file yml theo ý muốn.

Cấu trúc thông thường của một Github actions

Đây là một file yml mình đang sử dụng để cấu hình một git action để tự động install, build và publish source vue native lên expo mỗi khi có một người push code lên branch develop.

1.Khai báo

name:  Develop to Expo Pro2

2. Sự kiện – Trigger

on:
  push:
    branches:
      - develop

3. Công việc – Jobs

publish:
    name: Install and publish
    runs-on: ubuntu-latest
  • Setup enviroment
teps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - uses: expo/expo-github-action@v5
        with:
          expo-version: 3.x
          expo-username: ${{ secrets.EXPO_CLI_USERNAME }}
          expo-password: ${{ secrets.EXPO_CLI_PASSWORD }}
  • Actions
- run: npm install
      - run: expo publish --release-channel=pro2
      - uses: unsplash/comment-on-pr@master
        env:
          GITHUB_TOKEN: ${{ secrets.EXPO_CLI_GIT_TOKEN }}
        with:
          msg: App is ready for review, you can [see it here](https://expo.io/@bycedric/use-expo?release-channel=pro2.

Setup secrets key

Secrests key để làm gì? có một số thông tin bảo mật các bạn không muốn public cho mọi người (kể cả những member trong dự án) biết: access token, password….. vậy các bạn cần một cơ chế để public một key ra ngoài để run time có thể access vào value được lưu trong setting của git. chúng ta có thể sử dụng Secrets key

Tạo một secrets key

Bước 1: Chuyển đến tab setting

Bước 2: Chọn sheet Secrets: ở đây hiển thị danh sách các secrets key trong responsitory

Bước 3: Click “new repository secret” để tạo một secret key mới: nhập key và value

Bước 4: Xong thì add secret thôi nào

Có một đặt điểm là bạn không thể xem giá trị hiện tại của một secret key để tránh việc người khác có thể có được những thông tin bảo mật của bạn.

Xem thêm: Set up Kubernetes Cluster trên Microsofr Azure

Events trigger

Bạn có thể cấu hình cho workflows chạy khi có một sự kiện nào đó xảy ra trên GitHub, theo một lịch có sẵn hoặc cũng có thể là một sự kiện nào đó xảy ra ngoài GitHub.

Cấu hình cho một workflow events

Bạn có thể cấu hình cho một workflow run một hoặc một trong những events được thực hiện thông qua cú pháp on . Xem thêm cú pháp ở “Workflow syntax for GitHub Actions.“.

Syntax của một event trigger

on.<push | pull_request>.<branches | tags>

Ví dụ cấu hình trigger khi actions push, pull request và một branch.

# Triggered một workflow khi có push code lên một branch bất kì 
# của responsotiry
on: push

# Triggers một workflow có push code hoặc pull request
on: [push, pull_request]

Hoặc bạn cũng có thể sử dụng nhiều events với các cấu hình khác nhau.

on:
  # Trigger một workflow khi push or pull request,
  # nhưng chỉ trên main branch
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
  # Cũng trigger khi page_build, cũng như release created events
  page_build:
  release:
    types: # Cấu hình này không ảnh hưởng đến events page_build ở trên
      - created

on.<push | pull_request>.paths

Ví dụ cấu hình trigger khi actions push, pull request và bỏ qua khi chỉ có action folder docs.

on:
  push:
    paths-ignore:
    - 'docs/**'

hoặc chỉ trigger khi có action trên các file có đuôi js

on:
  push:
    paths:
    - '**.js'

Các bước xảy để một event có thể trigger một workflow run:

  1. Một event xảy ra trên reponsotory của bạn và kết quả trả về có một liên kết commit SHA và Git ref.
  2. Thư mục .github/workflows lưa trữ các yml file để định nghĩa các workflow. Github sẽ đọc những file đó để tham chiết tới commit SHA và Git ref. Các file yml có chứa các events mới được xem xét thực thi.
  3. Các workflow files có commit SHA và Git ref được triển khai, và một workflow mới sẽ chạy với các trigger khi các trigger trong file yml trùng với sự kiện đang trigger.

Trigger theo Scheduled

Để tạo một schedule chúng ta sử dụng cúp pháp schedule. Một Scheduled event cho phép trigger một workflow theo một lịch được định nghĩa sẵn. Một Scheduled có thể bị delay do hệ thống đang load.

Bạn có thể tạo một scheduled trigger chạy trên UTC time sử dụng POSIX cron syntax. Một workkflow đã được lên lịch sẽ thực thi trên source của commit mới nhất trên default hoặc base branch. Thời gian ngắn nhất để tạo ra một scheduled workflows tối thiểu là 5 phút.

Ví dụ trigger schedule đơn giản, thực hiện run workflows mỗi 15 phút:

on:
  schedule:
    - cron:  '*/15 * * * *' // thực hiện trigger mỗi 15 phút

Cú pháp Cron syntax có 5 fields được phân cách bằng một khoảng trắng, mỗi field đại diện cho một đơn vị thời gian.

┌───────────── phút (0 - 59)
│ ┌───────────── giờ (0 - 23)
│ │ ┌───────────── ngày trong tháng (1 - 31)
│ │ │ ┌───────────── tháng (1 - 12 or JAN-DEC)
│ │ │ │ ┌───────────── ngày trong tuần (0 - 6 or SUN-SAT)
│ │ │ │ │                                   
│ │ │ │ │
│ │ │ │ │
* * * * *

Bạn cũng có thể sử dụng các toán tử trong mỗi fields:

Toán tửMô tảVí dụ
*Tất cả các giá trị* * * * Chạy mỗi phút trong tất cả các ngày.
,Giá trị trong danh sách2,10 4,5 * * * chạy phút thứ 2, 10, 4, 5 trong mỗi giờ.
Khoảng giá trị0 4-6 * * * mỗi 0 phút giờ thức 4 đến 6 của ngày.
/Bước nhảy giá trị20/15 * * * * chạy mỗi 15 bắt đầu từ phút thức 20 (phút thứ 20, 35 và 50) mỗi giờ.

Ngoài ra còn một số cách khác để trigger một workflow nhưng mà mình chưa dùng nên cũng không giám chém, các bạn có thể tham khảo thêm ở đây

Các mẫu job cơ bản

Sau đây là một số mẫu Github action cơ bản mà các bạn có thể sử dụng để tạo một flow hoàn chỉnh, phụ thuộc vào yêu cầu của từng dự án khác nhau.

Ở đây mình chỉ liệt kê một số mẫu cơ bản có những trường hợp các bạn có thể áp cho dự án của mình. Các bạn có thể xem thêm ở đây, chọn ngôn ngữ của dự án và xem các mẫu có sẵn để có thể build một workflow trong nháy mắt.

Xem thêm: Setup Docker Hub và Github Workflow CI/CD pipelines

  • Cơ bản nhất là echo ra câu “Hello, world” thần thánh
jobs:
  # workflow này chứa một job tên là "build"
  build:
    # khai báo runner sẽ được chạy
    runs-on: ubuntu-latest

    # Các bước thể hiện một chuỗi các nhiệm vụ sẽ được thực hiện như một phần của công việc
    steps:
      # Kiểm tra kho lưu trữ của bạn dưới $ GITHUB_WORKSPACE, để công việc của bạn có thể truy cập nó
      - uses: actions/checkout@v2

      # Chạy một lệnh đơn bằng cách sử dụng trình bao của người chạy
      - name: Run a one-line script
        run: echo Hello, world!
  • build một ứng dụng Nodejs và push lên Azure Web App
env:
   # Khai báo một số biến để sử dụng
  AZURE_WEBAPP_NAME: your-app-name    # tên ứng dụng
  AZURE_WEBAPP_PACKAGE_PATH: '.'      # đường dẫn đến ứng dụng
  NODE_VERSION: '10.x'                # version sử dụng

jobs:
  build-and-deploy:
    name: Build and Deploy
    runs-on: ubuntu-latest
    environment: production
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ env.NODE_VERSION }}
      uses: actions/setup-node@v2
      with:
        node-version: ${{ env.NODE_VERSION }}
    - name: npm install, build, and test
      run: |
        # Build and test ứng dụng
        # deploy lên Azure Web App.
        npm install
        npm run build --if-present
        npm run test --if-present
    - name: 'Deploy to Azure WebApp'
      uses: azure/webapps-deploy@v2
      with:
        app-name: ${{ env.AZURE_WEBAPP_NAME }}
        publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
        package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
  • build and push một container image lên Amazon ECR
jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-2

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: my-ecr-repo
        IMAGE_TAG: ${{ github.sha }}
      run: |
        # Build một docker container
        # đẩy nó lên ECR để nó có thể được triển khai tới ECS.
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
    - name: Fill in the new image ID in the Amazon ECS task definition
      id: task-def
      uses: aws-actions/amazon-ecs-render-task-definition@v1
      with:
        task-definition: task-definition.json
        container-name: sample-app
        image: ${{ steps.build-image.outputs.image }}

    - name: Deploy Amazon ECS task definition
      uses: aws-actions/amazon-ecs-deploy-task-definition@v1
      with:
        task-definition: ${{ steps.task-def.outputs.task-definition }}
        service: sample-app-service
        cluster: default
        wait-for-service-stability: true
  • tải một Ruby version, cài đặt cái gói phụ thuộc và run tests với Rake
jobs:
  test:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        ruby-version: ['2.6', '2.7', '3.0']

    steps:
    - uses: actions/checkout@v2
    - name: Set up Ruby
    # Để tự động nhận các bản sửa lỗi và các phiên bản Ruby mới cho ruby/setup-ruby,
    # thay đổi thành (see https://github.com/ruby/setup-ruby#versioning):
    # sử dụng: ruby/setup-ruby@v1
      uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
      with:
        ruby-version: ${{ matrix.ruby-version }}
        bundler-cache: true # runs 'bundle install' and caches installed gems automatically
    - name: Run tests
      run: bundle exec rake
  • Building and testing .NET
jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        dotnet-version: ['3.0', '3.1.x', '5.0.x' ]

    steps:
      - uses: actions/checkout@v2
      - name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
        uses: actions/[email protected]
        with:
          dotnet-version: ${{ matrix.dotnet-version }}
      - name: Install dependencies
        run: dotnet restore
      - name: Build
        run: dotnet build --configuration Release --no-restore
      - name: Test
        run: dotnet test --no-restore --verbosity normal
  • Building and testing Python
jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [2.7, 3.5, 3.6, 3.7, 3.8]

    steps:
      - uses: actions/checkout@v2
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v2
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install flake8 pytest
          if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
      - name: Lint with flake8
        run: |
          # dừng quá trình build nếu có lỗi cú pháp Python hoặc tên không xác định
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          # exit-zero coi tất cả các lỗi là cảnh báo. Trình chỉnh sửa GitHub rộng 127 ký tự
          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
      - name: Test with pytest
        run: |
          pytest

Nguồn tham khảo:

Một số bài viết liên quan có thể bạn sẽ thích:

Mọi thắc mắc xin hãy liên hệ
Email: [email protected]

(Nguồn: KhanhVQ-Viblo)

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button