- vừa được xem lúc

Triển khai tự động ứng dụng trên VPS với GitOps bằng Docker, Portainer và Github Action

0 0 2

Người đăng: Khôi Nguyễn Đức Anh

Theo Viblo Asia

Ở bài viết trước, mình đã hướng dẫn các bạn cách cài đặt và cấu hình Portainer để quản lý docker image và container trên VPS. Hôm nay, mình sẽ tiếp tục ví dụ cách deploy trang web thông qua Portainer, cũng như cách để trang web này tự động deploy lại khi có commit thay đổi nhé (CI/CD ở mức cơ bản nhất)

Chuẩn bị ứng dụng

Để mình hoạ cho bài viết hôm nay, mình sẽ ví dụ bằng 1 trang web Hello world đơn giản viết bằng Sring Boot. Tất nhiên các bạn có thể sử dụng bất cứ ngôn ngữ và công nghệ nào các bạn yêu thích (NodeJS, Laravel, ...) miễn là các bạn có thể build được docker image cho nó.

Bạn nào biết cách khởi tạo ứng dụng và build docker image cho ứng dụng spring boot rồi thì có thể bỏ qua phần này nhé.

Đầu tiên chúng ta cần khởi tạo ứng dụng Spring Boot mới tại đây: Spring Initializr

Các options mình chọn giống như hình:

img.png

Tiến hành khởi tạo và tải project về bằng cách nhấn vào nút Generate

Sau khi giải nén project, ta được cấu trúc thư mục như sau:

img_1.png

Ta tiến hành tạo class controler cho trang chủ trong package com.example.demo

package com.example.demo; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
package com.example.demo; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
public class HomeController { @RequestMapping("/") public String home(final Model model) { model.addAttribute("message", "hello"); return "index"; } } 

Tiếp theo tạo view bằng cách tạo file index.html trong thư mục \src\main\resources\templates như sau:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head> <meta charset="UTF-8"> <title>Spring Boot Hello world</title>
</head>
<body>
<h1>Hello world</h1>
<p th:text="'message: ' + ${message} + '!'"/>
</body>
</html>

Chạy thử ứng dụng bằng lệnh sau:

./gradle bootRun # hoặc 'gradle bootRun' nếu sử dụng Windows

Mở http://localhost:8080 ta được kết quả như sau:

img_2.png

Nếu mọi thứ đã ổn, hãy tiến hành tạo repository trên github của bạn và push code lên nhé.

Như vậy đã xong phần chuẩn bị ứng dụng, tiếp theo chúng ta hãy đến với cách sử dụng Github Action để tự động thực hiện build và push docker image lên registry của github

Sử dụng Github Action để tự động build docker image và push lên kho lưu trữ Github Packages (ghcr.io)

GitHub Actions là 1 nền tảng miễn phí do GitHub cung cấp để giúp chúng ta tự động hoá quá trình CI/CD, cho phép người dùng định nghĩa các workflow tự động hoá các hoạt động trong phát triển phần mềm. Mỗi workflow trong GitHub Actions là một tập hợp các hành động (actions) được định nghĩa trong file YAML ( syntax thì các bạn có thể đọc ở đây)

Để sử dụng được Github Action, đầu tiên bạn cần tạo Personal Access Token cho tài khoản của bạn (nếu chưa có). Chi tiết cách tạo các bạn có thể xem hướng dẫn từ chính chủ Github ở đây

Để workflow có thể push docker image vào Github Packages chúng ta cần cấp quyền write cho nó. Truy cập vào trang Settings của repository của bạn, chọn ActionGeneral

img_3.png

Kéo xuống mục Workflow permissions, chọn vào option Read and write permissions, sau đó nhấn Save

img_4.png

Bây giờ, ta tiến hành định nghĩa 1 workflow mới bằng cách tạo file .github/workflows/main.yml. Nội dung như sau:

name: CI/CD
'on': push: branches: - main
jobs: build: runs-on: ubuntu-latest timeout-minutes: 40 steps: - name: Checkout uses: actions/checkout@v2 - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: temurin java-version: 17 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Cache Gradle packages uses: actions/cache@v2 with: path: ~/.gradle/caches key: '${{ runner.os }}-gradle-${{ hashFiles(''**/*.gradle'') }}' restore-keys: '${{ runner.os }}-gradle' - name: Build Image run: | ./gradlew clean bootBuildImage --imageName=app:latest - name: Login to GitHub Container Registry uses: docker/login-action@v2 with: registry: ghcr.io username: '${{ github.actor }}' password: '${{ secrets.GITHUB_TOKEN }}' - name: Push image to GitHub Container Registry run: | docker tag app:latest ghcr.io/${{ github.actor }}/${{ github.repository }}:latest docker push ghcr.io/${{ github.actor }}/${{ github.repository }}:latest

Sau đó tiến hành commit và push lên branch main của bạn.

Truy cập vào mục Actions trong repository, ta thấy workflow đã được kích hoạt và chạy:

img_5.png

Các bạn có thể nhấn vào workflow đó để xem log quá trình chạy. Việc của bạn hiện giờ là chỉ cần chờ vài phút cho đến khi workflow chạy hoàn tất

img_6.png

Quay lại trang chính của Repository, ta thấy đã tạo được image như hình

img_7.png

Tiến hành deploy docker image lên Portainer trên VPS

Theo đúng quy trình GitOps được mô tả trên trang chủ của Portainer, thì chúng ta cần tạo thêm config-repo, sau đó cấu hình Portainer liên kết với repo này. Tuy nhiên, trong bài viết này, để cho đơn giản thì mình sử dụng chung 1 repository với source code luôn nhé

Chúng ta sẽ triển khai bằng cách sử dụng tính năng Stack của Portainer. Stack sử dụng cú pháp docker compose nên chúng ta cần tạo file docker-compose.yml ngay trong thư mục gốc của project sau đó tiến hành commit push file này lên

version: '3.8'
services: app: image: ghcr.io/ndanhkhoi/spring-demo # Thay bằng image của bạn theo đã buikd ở bước trên ports: - "8080:8080"

Các bạn lưu ý nhớ thay tên image đã build ở bước trên vào sau ghcr.io/ nhé. Tên image trong workflow mình đã cấu hình là repository name luôn, nên cú pháp sẽ là ghcr.io/<username>/<repository>, ví dụ của mình là ndanhkhoi/spring-demo

TIP: Khi commit, các bạn thêm [skip ci] vào trước message, ví dụ [skip ci] add docker-compose.yml để bỏ qua quá trình chạy workflow vì thêm file docker-compose.yml này không ảnh hưởng đến code nên chung ta không cần build lại image

Tiến hành thêm Github Registry vào Portainer của bạn, truy cập Portainer, vào menu Registries, nhấn nút Add registry

img_8.png

Chọn Custom registry, nhập vào các thông tin sau:

  • Name: ghcr.io
  • Registry URL: ghcr.io
  • Bật tuỳ chọn Authentication
  • Username: username github của bạn
  • Password: Personal access token của bạn (nhớ là không phải mật khẩu github nha)

img_9.png

Nhấn Add registry

Tiếp theo, chúng ta tiến hành thêm stack và deploy ứng dụng. Truy cập menu Stack, sau đó nhấn chọn Add stack

img_10.png

Chọn sang Use a git repository, nhập các thông tin cần thiết

  • Tên stack (tuỳ ý)
  • Bật tuỳ chọn authentication
  • Username và Personal Access Token của bạn
  • Repository URL
  • Các thông tin Repository referenceCompose path để mặc định
  • Bật tuỳ chọn GitOps updates
  • Mục Mechanism các bạn chọn sang Webhook, sau đó nhấn Copy link. Các bạn dán link này ra đâu đó để lưu lại sử dụng cho bước sau nhé

img_11.png

  • Sau đó nhấn Deploy stack và chờ vài phút để Portainer tiến hành pull image về và deploy

Sau khi có thông báo deploy thành công, các bạn tiến hành truy cập:

http://<IP_ADDRESS>:8080

img_12.png

Tadaaaa! Ứng dụng spring boot của bạn đã được deploy thành công trên VPS

Cấu hình tự động deploy lại khi có commit thay đổi (GitOps updates)

Truy cập repository của bạn, tiến hành tạo secrets mới. Vào SettingsSecrets and variablesActionsNew repository secret

img_13.png

  • Mục name nhập: PORTAINER_STACK_WEBHOOK
  • Mục secret nhập URL ở bước trên các bạn đã Copy khi tạo Stack

img_14.png

Điều chỉnh workflow gọi webhook sau khi build và push xong image, file .github/workflows/main.yml sau khi chỉnh sửa:

name: CI/CD
'on': push: branches: - main
jobs: build: runs-on: ubuntu-latest timeout-minutes: 40 steps: - name: Checkout uses: actions/checkout@v2 - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: temurin java-version: 17 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Cache Gradle packages uses: actions/cache@v2 with: path: ~/.gradle/caches key: '${{ runner.os }}-gradle-${{ hashFiles(''**/*.gradle'') }}' restore-keys: '${{ runner.os }}-gradle' - name: Build Image run: | ./gradlew clean bootBuildImage --imageName=app:latest - name: Login to GitHub Container Registry uses: docker/login-action@v2 with: registry: ghcr.io username: '${{ github.actor }}' password: '${{ secrets.GITHUB_TOKEN }}' - name: Push image to GitHub Container Registry run: | docker tag app:latest ghcr.io/${{ github.repository }}:latest docker push ghcr.io/${{ github.repository }}:latest - name: Send portainer webhook run: | curl --insecure --connect-timeout 60 -X POST ${{ secrets.PORTAINER_STACK_WEBHOOK }}

Thử chỉnh sửa file \src\main\resources\templatesindex.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head> <meta charset="UTF-8"> <title>Spring Boot Hello world</title>
</head>
<body>
<h1>Hello world</h1>
<p th:text="'message: ' + ${message} + '!'"/>
<p> CI/CD demo
</p>
</body>
</html>

Sau đó tiến hành commit, đợi và kiểm tra workflow chạy xong. Tiến hành F5 và kiểm tra lại trang web chúng ta vừa deploy:

img_15.png

Đã xuất hiện dòng chữ CI/CD demo chúng ta vừa thêm vào vùa nảy ^^

Vậy là xong, từ nay, khi có cần chỉnh sửa gì trang web, bạn chỉ việc commit thay đổi lên github mà không cần phải làm thêm bất cứ thao tác nào cả, website của bạn sẽ được tự động cập nhật các thay đổi sau ít phút. Ngon lành cành đào rồi 🤣

Tổng kết

Cảm ơn các bạn đã đọc đến dòng này, đây toàn bộ đều là những gì mình đã tự mài mò được khi phát triển một trang web cá nhân của mình. Bài viết hôm nay hơi dài, do có nhiều nội dung, mình đã cố gắng viết ngắn gọn và đơn giản nhất có thể. Những gì mình chia sẻ ở bài viết này là ở mức độ cơ bản, minh hoạ cho quá trình CI/CD dựa vào Github Action và Portainer, các bạn có thể dựa vào từng bước mình đã liệt kê trong bài để tìm hểu và nghiên cứu sâu hơn nếu có hứng thú nhé.

See you next time !

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 376

- vừa được xem lúc

Phần 1: Giới thiệu về Kubernetes

Kubernetes là gì. Trang chủ: https://kubernetes.io/. Ai cần Kubernetes.

0 0 80

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 1- Lịch sử)

1. Vì sao nên sử dụng. . .

0 0 90

- vừa được xem lúc

Docker - những kiến thức cơ bản phần 1

Giới thiệu. Nếu bạn đang làm ở một công ty công nghệ thông tin, chắc rằng bạn đã được nghe nói về Docker.

0 0 65

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 2 - Dockerfile)

1. Mở đầu.

0 0 54

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 3: Docker-compose)

1. Mở đầu. . .

0 0 106