使用Github Action自动化打包构建部署Go程序

使用Github Action自动化打包构建部署Go程序

July 3, 2024

Dockerfile #

首先在项目根目录创建Dockerfile文件,以下是一个样例:

# 使用官方的 Golang 镜像创建构建产物。
FROM golang:1.21.6 AS builder

RUN mkdir /app
# 将本地代码复制到容器镜像中。
WORKDIR /app
COPY . .

# 在容器内构建命令。
RUN go mod download && \
    CGO_ENABLED=0 GOOS=linux go build -o dbdemo .

# 使用一个新的阶段创建一个最小的镜像。
FROM alpine:3.20
COPY ./conf /conf
COPY --from=builder /app/dbdemo /usr/local/bin/dbdemo
# 更新文件权限以确保它是可执行的。
RUN chmod +x /usr/local/bin/dbdemo
# 设置容器的默认端口
EXPOSE 3000

# 设置容器的默认命令。
CMD ["/usr/local/bin/dbdemo"]

[!NOTE]

如果有静态文件,需要在二次创建时复制进去

说明:

dbdemo:我的镜像的名字,需要修改成你自己的

EXPOSE 3000:容器的端口号,改成你的服务端端口号

Github Action #

在根目录创建.github/workflows/xxx.yml,yml的名字自己取,以下是一个样例:

name: CI	#名字随意

on:
  push:
    branches:
      - main # 触发工作流的分支

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Build Docker image	#打包镜像
        run: |
          docker build -t username/dbdemo:${{ github.sha }} .
          docker tag username/dbdemo:${{ github.sha }} username/dbdemo:latest          

      - name: Login to Docker Hub	#登录Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKER_HUB_USERNAME }}
          password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

      - name: Push Docker image to Docker Hub	#推送到Docker Hub
        run: |
          docker push username/dbdemo:latest
          docker push username/dbdemo:${{ github.sha }}          

      - name: Deploy to server	#部署到服务器
        uses: appleboy/ssh-action@v0.1.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USERNAME }}
          password: ${{ secrets.SERVER_PASSWORD }}
          port: ${{ secrets.SERVER_PORT }}
          script: |
            docker pull username/dbdemo:${{ github.sha }}
            docker stop dbdemo || true  
            docker rm dbdemo || true   
            docker run -d --name dbdemo -p 3000:3000 username/dbdemo:${{ github.sha }}            

说明:

username:你的Docker Hub用户名,没有账户的可以去注册一个Docker Hub账户

dbdemo:这是我的镜像名,改成你自己的

appleboy/ssh-action@v0.1.3:用于ssh连接服务器,可选,支持多种验证方式,我这里选择的用户名密码,你也可以选择sshkey等方式,参考官方文档

secrets.xxx:需要在Github仓库创建对应的secret,例如secrets.DOCKER_HUB_USERNAME就需要创建一个名为DOCKER_HUB_USERNAME的secret

Ngnix #

我们可以通过Ngnix进行反代,简化api接口的链接

我这里使用的OpenResty,可以理解为Ngnix的Plus版本

location /api {
    proxy_pass http://127.0.0.1:3000; 
    proxy_set_header Host $host; 
    proxy_set_header X-Real-IP $remote_addr; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header REMOTE-HOST $remote_addr; 
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection "upgrade"; 
    proxy_set_header X-Forwarded-Proto $scheme; 
    proxy_http_version 1.1; 
    add_header X-Cache $upstream_cache_status; 
    add_header Strict-Transport-Security "max-age=31536000"; 
    add_header Cache-Control no-cache; 
}

反代可以简单地理解为将请求链接进行替换,举个例子:

前台请求的是ip/xxx/api,ngnix会将其转化为127.0.0.1:3000/api

这样我们的服务器就只需要开放443和80端口,而不需要开放3000端口

Cors #

我们还需要注意跨域的问题,关于什么是跨域,可以参考跨域资源共享 CORS 详解

我们可以在前端/Nginx/后端任何一个地方配置跨域,注意不要重复配置

我这里选择在后端进行配置,Golang中只需要加入Cors中间件即可:

func Cors() gin.HandlerFunc {
	return cors.New(cors.Config{
		//AllowOrigins:  []string{"*"},
		AllowAllOrigins: true,
		AllowMethods:    []string{"PUT", "PATCH", "GET", "POST", "DELETE", "OPTIONS"},
		AllowHeaders:    []string{"Origin", "Content-Type"},
		ExposeHeaders:   []string{"Content-Length", "Authorization"},
		MaxAge:          12 * time.Hour,
	})
}

AllowOrigins可以设置允许的来源,*表示任意来源

AllowAllOrigins的值设置为true表示允许任何来源

Tips #

在写Golang程序的时候,注意不要将服务端地址写成localhost:3000,不然会导致外部无法访问,Nginx也无法进行代理

应当写成0.0.0.0:3000或者:3000,表示允许任意ip访问