使用Github Actions + Docker 部署Spring Boot應用

語言: CN / TW / HK

當前,如果我們手動部署Spring Boot應用,一般都是在本地打成jar包,然後在通過ftp上傳到伺服器,再重啟應用。這樣部署實在太過麻煩,如果能把程式碼直接提交到程式碼庫,自動跑測試,測試通過去部署應用,也就是持續整合,這樣就能省太多的時間去創造更好的產品。

當前的持續整合服務主要有:最早支援Github專案的Travis CI,騰訊的Coding和大名鼎鼎的Jenkins。

Github Actions是Github提供的持續整合和持續部署服務。

1. Github Actions

建立workflow檔案

Github Actions顧名思義,肯定是先選擇你的Github專案,並且找到Actions功能,如圖:

在這個頁面,我們可以看到官方建議的工作流,還有部署到不同平臺和不同語言的非常多的模板供我們選擇,這裡我們先看官方預設的配置,其他的再熟悉了流程之後可以慢慢研究。

2021-09-24-1G1Bks

當我們點選了建立工作流後,會在當前倉庫.github/workflows目錄下建立一個yml格式的檔案,這個就是我們工作流的配置檔案,在這裡我們可以定義觸發規則,編譯階段,部署階段等每一步需要做的事情。

2021-09-24-Shldap

在這個配置檔案中的基本欄位:

  1. name: workflow的名稱

  2. on:觸發規則。比如push,pr等特定事件或者定時執行或發生外部的事件時執行,比如建立分支等,更多可以參考觸發工作流程的事件

  3. jobs.*.runs-on:指定job執行的虛擬機器環境,比如ubuntu-latest。

  4. jobs.*.steps:指定每個job的執行步驟,比如指定jdk版本,編譯打包等階段。

  5. jobs.*.steps.run:該步驟執行的命令或者 action。

    每個 step 可以依次執行一個或多個命令(action),比如 mvn package和ssh-deploy。

Github Marketplace中提供了非常非常多的Actions,比如ssh,ftp等,可以非常方便的直接拿來使用。

注意,一個倉庫可以有多個workflow檔案,命名隨意,GitHub 只要發現.github/workflows目錄裡面有.yml檔案,就會自動執行該檔案。

環境變數

在Github專案裡找到Settings中的Secrets,並點選建立金鑰,如圖所示:

2021-09-24-jOfqf1

GitHub 設定適用於工作流程執行中每個步驟的預設環境變數,環境變數區分大小寫,在操作或步驟中執行的命令可以建立、讀取和修改環境變數。

建立自定義Runner

在上文的配置檔案中提到有jobs.*.runs-on欄位,是指官方提供的虛擬機器環境,也就是我們的job是在官方提供的伺服器上執行的,那麼能不能新增我們的伺服器呢,答案是肯定的。

我們可以將伺服器新增到單個倉庫中。如果要將自託管的執行器新增到使用者倉庫,您必須是倉庫所有者。對於組織倉庫,您必須是組織所有者或擁有該倉庫管理員的許可權。

在Github專案的主頁面上,點選Settings中的Actions。

2021-09-24-k2MRWP

在右上角點選新增自己託管的runner。

2021-09-24-z5K1S0

我們可以看到根據不同的作業系統都提供了對應的下載,配置和使用方法,根據步驟操作完就可以在列表上看到我們自定義的runner。

2. 使用Github Actions + Docker部署Spring Boot應用

建立workflow檔案

``` name: Deploy with docker

on:   push:     # 分支     branches: [ master ]   pull_request:     branches: [ master ]

jobs:   compile:     runs-on: ubuntu-latest     steps:       - uses: actions/[email protected]       - name: Set up JDK 11         uses: actions/[email protected]         with:           java-version: '11'           distribution: 'adopt'       # maven快取,不加的話每次都會去重新拉取,會影響速度          - name: Dependies Cache         uses: actions/[email protected]         with:           path: ~/.m2/repository           key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}           restore-keys: |             ${{ runner.os }}-maven-       # 編譯打包             - name: Build with Maven         run: mvn package -Dmaven.test.skip=true       # 登入Docker Hub         - name: Login to Docker Hub         uses: docker/[email protected]         with:           username: ${{ secrets.DOCKER_HUB_USERNAME }}           password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}       - name: Set up Docker Buildx         id: buildx         uses: docker/[email protected]       # build 映象並push到中央倉庫中         - name: Build and push         id: docker_build         uses: docker/[email protected]         with:           context: ./           file: ./Dockerfile           push: true           tags: ${{ secrets.DOCKER_HUB_USERNAME }}/imageName:latest       # push後,用ssh連線伺服器執行指令碼           - name: SSH         uses: fifsky/[email protected]         with:           command: |             sh start.sh           host: ${{ secrets.HOST }}           user: ${{ secrets.USER }}           key: ${{ secrets.PRIVATE_KEY}} ```

配置環境變數

2021-09-24-7xO49X

Docker Hub 專案配置

如果在Github Actions中使用Docker,可以參考官方文件。這裡介紹瞭如何建立Docker專案,建立流水線,優化流水線,推送映象版本等內容。

在示例專案中,主要使用到下面2個配置項:

  1. DOCKER_HUB_USERNAME:賬號的使用者名稱

  2. DOCKER_HUB_ACCESS_TOKEN:授權的Token,在使用者設定中建立Token。

    2021-09-24-droVZL

這裡除了使用Docker的方式外,也可以使用ftp的Actions上傳jar包到伺服器的指定目錄,然後直接通過jar -jar app.jar執行。

配置ssh金鑰對

ssh相關的配置項,主要是HOST,USER,私鑰PRIVATE_KEY,Host和使用者不必多說,看下私鑰是如何生成的:

[[email protected] ~]$ ssh-keygen  <== 建立金鑰對 Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): <== 按 Enter Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): <== 輸入金鑰鎖碼,或直接按 Enter 留空 Enter same passphrase again: <== 再輸入一遍金鑰鎖碼 Your identification has been saved in /root/.ssh/id_rsa. <== 私鑰 Your public key has been saved in /root/.ssh/id_rsa.pub. <== 公鑰 The key fingerprint is: 0f:d3:e7:1a:1c:bd:5c:03:f1:19:f1:22:df:9b:cc:08 [email protected]

建立好公鑰和私鑰之後,還需要把公鑰放在伺服器的authorized_keys中,這樣才能正確的連線上。

[[email protected] ~]$ cd .ssh [[email protected] .ssh]$ cat id_rsa.pub >> authorized_keys

為什麼需要ssh?

我們連線伺服器一般有2種方式,一種是通過密碼登入,但是密碼會被破解,非常不安全,那麼就可以用ssh登入。

ssh一般有一對公鑰和私鑰,連線的時候伺服器的步驟:

  1. 客戶端通過公鑰向伺服器發起請求。
  2. 伺服器會驗證客戶端傳送的公鑰是否在本地的公鑰列表中,如果不在就拒絕連線,如果在列表中,就會通過公鑰加密隨機字串,然後傳送給客戶端。
  3. 客戶端通過私鑰解密之後,傳送給伺服器,伺服器驗證解密後的字串是否匹配,如果匹配則連線成功。

create Dockerfile

既然使用Docker的方式,那麼首先就需要在專案根目錄下建立Dockerfile檔案,然後通過Dockerfile建立映象。

```

該映象需要依賴的基礎映象

FROM fabric8/java-alpine-openjdk11-jre

調整時區

RUN rm -f /etc/localtime \ && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone

將當前目錄下的jar包複製到docker容器的/目錄下

ADD target/app.jar /app/app.jar

指定docker容器啟動時執行jar包

ENTRYPOINT ["java", "-jar","app/app.jar"] ```

這裡基礎映象選擇了alpine版本,因為它的體積非常小,幾乎都可以忽略不計,另外還有Distroless或Busybox可以選擇。

除了這種已經集成了jdk的基礎映象,也可以在純淨的alpine映象上去安裝jdk,這樣的體積也會非常小,在推送映象和拉取映象上速度都會非常快。

更多參考:雲原生實驗室的Alpine vs Distroless vs Busybox

這樣,在我們提交程式碼到github的時候,流水線就會根據Dockerfile檔案建立映象,然後推送映象,在流水線配置中如下:

```

build 映象並push到中央倉庫中

- name: Build and push  id: docker_build   uses: docker/[email protected]   with:   context: ./   file: ./Dockerfile   push: true   tags: ${{ secrets.DOCKER_HUB_USERNAME }}/imageName:latest ```

pull image && restart container

通過上面的配置,我們已經可以成功的把映象推送到Docker Hub的中央倉庫中,那沒下一步就是需要我們去伺服器中拉取最新的映象,然後關閉之前的容器,基於最新的映象啟動新的容器。

```

push後,用ssh連線伺服器執行指令碼

- name: SSH   uses: fifsky/[email protected]   with:   command: |    sh start.sh   host: ${{ secrets.HOST }}   user: ${{ secrets.USER }}   key: ${{ secrets.PRIVATE_KEY}} ```

所以,我們通過ssh連線伺服器執行重啟的指令碼。

```

!/bin/bash

docker pull username/app:latest docker rm -f containerName||true&&docker run  --name=appName -d -p 8080:8080 username/app:latest docker image prune -af ```

到此為止,我們就可以實現持續整合,不用手動的去上傳jar包,然後執行各種命名。

3. 參考