a purpose of this paper

Document how to automate the publishing of SpringBoot projects through Github Actions. The SpringBoot project is managed through Docker.

Two main steps required by Github Action

  1. Set up the Java environment and build the project via Maven
  2. Build a Docker image and push to a private registry
  3. Log in to the remote server, pull the image and restart the service

Three Set up the Java environment and build the project through Maven

Here we use JDK 11 and set up the maven cache to speed up the build time. Where -DskipTests=true means skip tests when building. You can delete this parameter if you need to test.

 - name: Set up JDK 11
  uses: actions/setup-java@v3
  with:
    java-version: '11'
    distribution: 'temurin'
    cache: maven

- name: Build with Maven
  run: mvn -B -DskipTests=true package --file pom.xml

4 Build a Docker image and push it to a private image repository

The main problem to be solved here is how to choose a Docker private image. The choices are as follows

name advantage shortcoming
Github Package Free, highly integrated with Github, easy to configure The cloud server in mainland my country is too slow to connect to Github
Docker Official Docker official, trustworthy, the connection speed of the mainland cloud server is OK Only supports one private image repository, more money is required
Coding.net The mainland cloud server has a fast connection speed and is free of charge. It has been accepted by Tencent, and the service should not be interrupted. Configuration is slightly complicated but acceptable

My final choice is Coding.net, but if the cloud server allows it, I'll choose Github Package.

4.1 Coding.net private mirror repository

4.1.1 Create a private image repository through Coding.net as follows:

  1. See the project for details, for example, select the project named docker-image
  2. Create a "product warehouse" in the project, select docker for the product type, then name it, set the permissions (can be default) and it's OK
Create an artifact Set product information
image.pngimage.png

4.1.2 Push and pull Docker images:

There are generally two ways: the command line or the CICD tool. However, you need to log in to an account with project operation permissions first.

Log in

Click the operation guide:
image.png

Get the login token:
image.png

 docker login \
-u random-user-name \
-p random-passworkd \
coding-username-docker.pkg.coding.net

Note here that although random username and password are generated, they are indeed valid for a long time, so they can be placed in the secrets of Gihub repo for Github Action to use.

push/pull image

Push:

 docker push \
coding-username-docker.pkg.coding.net/docker-image/test-service/<PACKAGE>:<VERSION>

Before pushing, make sure you already have this coding-username-docker.pkg.coding.net/docker-image/test-service/<PACKAGE>:<VERSION> this tag, if you don't have it, tag it.

 docker tag \
<LOCAL_IMAGE_TAG> coding-username-docker.pkg.coding.net/docker-image/test-service/<PACKAGE>:<VERSION>

Pull:

 docker pull \
coding-username-docker.pkg.coding.net/docker-image/test-service/<PACKAGE>:<VERSION>

4.1.3 Setting up Coding.net private mirror repository in Github Action

 # 登录
- name: Log in to the Coding docker registry
  uses: docker/login-action@v1
  with:
    registry: ${{ env.REGISTRY }} # REGISTRY 为 GHA 环境变量
    username: ${{ secrets.CODING_USER }} # coding.net 的 random-user-name,设置在 GHA 的 secrets 中
    password: ${{ secrets.CODING_TOKEN }} # coding.net 的 random-password

# 设置 image 名称
- name: Extract metadata (tags, labels) for Docker
  id: meta
  uses: docker/metadata-action@v3
  with:
    images: ${{ env.IMAGE_NAME_TOTAL_NAME }}

# 推送
- name: Build and push Docker image
  uses: docker/build-push-action@v2
  with:
    context: .
    push: true
    tags: ${{ steps.meta.outputs.tags }}
    labels: ${{ steps.meta.outputs.labels }}

Docker tags setting rules can refer to docker/metadata-action , the most basic rules are as follows

Event Ref Docker tags
push refs/heads/main main
push refs/heads/releases/v1 releases-v1
push tag refs/tags/v1.2.3 v1.2.3, latest

Note here that if it is Push Github tag , then two Docker tags (Perfect!) will be generated by default.

If we want to trigger GHA after push tag, we need to add it in workflow

 on:
  push:
    tags: # tags 更新时触发 workflow
      - 'v*'

4.2 Github Package Private Image Repository

First of all, Github Package is not necessarily a Docker image. You can go to the official website to learn more. Here we only introduce the use of Github package with Github's Container registry to create a private Docker image repository.

For the complete steps, please refer to Container registry . The process is similar to Coding.net: after login, push and pull.

4.2.1 Log in to Container registry

It is recommended to use GITHUB_TOKEN, set in Settings/Developer settings/Personal access tokens :

image.png

Remember to save the Token here, otherwise you won't be able to find it later.

After obtaining the Token, log in to the Contianer Registry

 $ export CR_PAT=YOUR_TOKEN # 存储 token 到变量 CR_PAT 中
$ echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
> Login Succeeded

4.2.2 Push/Pull mirroring

 # push
$ docker push ghcr.io/OWNER/IMAGE_NAME:TAG

# pull
docker pull ghcr.io/OWNER/IMAGE_NAME:TAG

4.2.3 Settings in GHA

You can directly use the github own variable, such as github.actor as the username. The overlapping parts with coding.net will not be repeated.

 - name: Log in to the Container registry
  uses: docker/login-action@v1
  with:
    registry: ${{ env.REGISTRY }} # 为 ghcr.io
    username: ${{ github.actor }} # 可以直接读取当前 Github 触发事件的用户
    password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
  id: meta
  uses: docker/metadata-action@v3
  with:
    images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # IMAGE_NAME 为 ${{ github.repository }}
    
- name: Build and push Docker image
  uses: docker/build-push-action@v2
  with:
    context: .
    push: true
    tags: ${{ steps.meta.outputs.tags }}
    labels: ${{ steps.meta.outputs.labels }}

5. Log in to the remote server, pull the image and restart the service

The appleboy/ssh-action is used here, which can directly configure the script that needs to be executed after logging in to the remote server in GHA workflow.

 - name: executing remote ssh commands using password
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.REMOTE_HOST }}
    username: ${{ secrets.REMOTE_USER }}
    # 通过 ssh key 登录
    key: ${{ secrets.REMOTE_ACCESS_TOKEN }}
    script: |
      docker login -u ${{ secrets.CODING_USER }} -p ${{ secrets.CODING_TOKEN }} ${{ env.REGISTRY }}
      docker pull ${{ env.IMAGE_TOTAL_NAME }}:${{ env.IMAGE_TAG }}
      docker stop ${{ env.CONTAINER_NAME }}
      docker rm ${{ env.CONTAINER_NAME }}
      docker run -d \
        --name ${{ env.CONTAINER_NAME }} \
        -p ${{ secrets.EXPOSED_PORT }}:${{ secrets.EXPOSED_PORT }} \
        --link ${{ secrets.DATABASE_CONTAINER_NAME }}:${{ secrets.DATABASE_CONTAINER_NAME }} \
        ${{ env.IMAGE_TOTAL_NAME }}:${{ env.IMAGE_TAG }}

A few things to note here:

  1. Use ssh key to log in to the remote server, mainly key not password ;
  2. It is recommended to copy all the key file contents to the clipboard directly through the command line tool, and then directly copy them to the secrets of the Github repo (if you copy manually, remember to put the comments as well):
 # mac 下操作
pbcopy < you_key_file
  1. Delete the old Docker container before restarting the service.

Six complete Github Actions YAML files

 name: GHA CI

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the main branch
  push:
    # branches: [ main ]
    tags: # tags 更新时触发 workflow
      - 'v*'
    # pull_request:
    # branches: [ main ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

env:
  IMAGE_TOTAL_NAME: ${{ secrets.CODING_REGISTRY }}/docker-image/${{ secrets.SERVICE_CONTAINER_NAME }}/${{ secrets.SERVICE_CONTAINER_NAME }}
  IMAGE_TAG: latest

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      # maven build
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'
          cache: maven
      - name: Build with Maven
        run: mvn -B -DskipTests=true package --file pom.xml

      # coding.net docker repo
      - name: Log in to the Coding docker registry
        uses: docker/login-action@v1
        with:
          registry: ${{ secrets.CODING_REGISTRY }}
          username: ${{ secrets.CODING_USER }}
          password: ${{ secrets.CODING_TOKEN }}
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v3
        with:
          images: ${{ env.IMAGE_TOTAL_NAME }}
      - name: Build and push Docker image
        uses: docker/build-push-action@v2
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      # pull new image and restart service
      - name: executing remote ssh commands using password
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_ACCESS_TOKEN }}
          script: |
            docker login -u ${{ secrets.CODING_USER }} -p ${{ secrets.CODING_TOKEN }} ${{ secrets.CODING_REGISTRY }}
            docker pull ${{ env.IMAGE_TOTAL_NAME }}:${{ env.IMAGE_TAG }}
            docker stop ${{ secrets.SERVICE_CONTAINER_NAME }}
            docker rm ${{ secrets.SERVICE_CONTAINER_NAME }}
            docker run -d \
              --name ${{ secrets.SERVICE_CONTAINER_NAME }} \
              -p ${{ secrets.EXPOSED_PORT }}:${{ secrets.EXPOSED_PORT }} \
              --link ${{ secrets.DATABASE_CONTAINER_NAME }}:${{ secrets.DATABASE_CONTAINER_NAME }} \
              ${{ env.IMAGE_TOTAL_NAME }}:${{ env.IMAGE_TAG }}

L小庸
871 声望592 粉丝

引用和评论

0 条评论