美文网首页
一文让你完全弄懂Go语言打包和部署!

一文让你完全弄懂Go语言打包和部署!

作者: 左诗右码 | 来源:发表于2024-05-07 23:48 被阅读0次

Go 打包和部署

打包相关命令

命令 含义
go run 编译并马上运行 go 程序(只接收 main 包下的文件作为参数)
go build 编译指定的源文件、软件包及其依赖项,但它不会运行编译后的二进制文件。(如果想要指定所生成的二进制文件为其他名称,则可以通过 -o 参数进行调整)
go install 编译并安装源文件、软件包到 $GOBIN 目录下。 可以执行 go install -x 查看它的编译过程。文件名称为 Go modules 的项目名,而不是目录名
参数 含义
-x 打印编译过程中的所有执行命令,执行生成的二进制文件,比如:go run -x main.gogo build -x
-n 打印编译过程中的所有执行命令,不执行生成的二进制文件
-a 强制重新编译所有涉及的依赖,简单来说,就是不利用缓存或已编译好的部分文件,直接所有包都是最新的代码重新编译和关联
-o 指定生成的二进制文件名称
-p 指定编译过程中可以并发运行程序的数量,默认值为可用的 CPU 数量(Go 语言默认是支持并发编译的)
-work 打印临时工作目录的完整路径,在退出时不删除该目录
-race 启用数据竞争检测,目前仅支持 Linux/amd64、FreeBSD/amd64、Darwin/amd64 和 Windows/amd64 平台
-installsuffix 在软件包安装的目录中增加后缀标识,以保持输出与默认版本分开

跨平台交叉编译

Go 语言支持跨平台交叉编译,也就是说我们可以在 Windows 或 Mac 平台下编写代码,最后将代码编译成能够在 Linux amd64 服务器上运行的程序。

根目录使用以下指令可以静态编译 Linux 平台 amd64 架构的可执行文件:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o <application-name>

# 比如
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o <application-name> .

Windows 依次执行以下四个命令:

SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build -o <application-name>
参数名 含义
CGO_ENABLED 设置是否在 Go 代码中调用 C 代码。0 为关闭,采用纯静态编译。可通过执行 go env 进行查看
GOOS 目标操作系统,如 Linux 、Darwin、Windows
GOARCH 目标操作系统的架构,若不设置,则默认值为程序运行环境的目标计算架构一致
GOHOSTOS 用于标识程序运行环境的目标操作系统
GOHOSTARCH 用于标识程序运行环境的目标计算架构

可以通过如下命令查看 Go 支持 OS 和平台列表

go tool dist list
系统 GOOS GOARCH
Windows 32位 windows 386
Windows 64位 windows amd64
OS X 32位 darwin 386
OS X 64位 darwin amd64
Linux 32位 linux 386
Linux 64位 linux amd64

第三方打包工具

以下几个第三方打包工具可以将静态文件(JS、CSS、图片)或者模版文件等非 .go 文件打包到一个二进制文件中, Embed 标准库也可以,但是得使用 go 1.16 版本以后的版本才行。

将数据文件转换成 go 代码

go-bindata 库可以将数据文件转换为 Go 代码。例如:常见的配置文件、资源文件(如 swagger ui)
因此读取配置信息也可以通过 go-bindata/go-bindata 包提供的方式来读取。使用方式如下:

  1. 安装 go-bindata/go-bindata
go get -u github.com/go-bindata/go-bindata/...
  1. 将配置文件生成 go 代码
# 执行这条命令后,会将 `configs/config.yaml` 文件打包,并通过 `-o` 参数选择指定的路径输出到 `configs/config.go` 文件中
# 再通过 `-pkg` 选项指定生成的包名为 `configs`
go-bindata -o configs/config.go -pkg-configs configs/config.yaml
  1. 读取文件中的配置信息
data, err := configs.Asset("configs/config.yaml")

if err == nil {
    fmt.Println(string(data))
}

编译缓存


# 查看编译缓存所在的目录
go env GOCACHE

# 清理编译缓存
go clean -cache

# 查看程序编译的时间
time go build

压缩编译后的二进制文件

如非必要情况,不建议压缩

  • 方式一:去掉 DWARF 调试信息和符号表信息
go build -ldflags="-w -s"
参数名 含义 副作用
-w 去除 DWARF 调试信息 会导致异常 panic 抛出时,调用堆栈信息没有文件名、行号信息
-s 去除符号表信息 无法使用 gdb 调试
  • 方式二:使用 upxupx 教程 工具对可执行文件进行压缩

编译信息写入(使用 ldflags 设置编译信息)

go version 信息注入

  • 先在 main.go 文件中写入代码

var (
    buildTime    string // 二进制文件编译时间
    buildVersion string // 二进制文件编译版本
    goVersion    string // 打包二进制文件时的 go 版本信息
    gitCommitID  string // 二进制文件编译时的 git 提交版本号
)

func main() {

    args := os.Args
    if len(args) == 2 && (args[1] == "--version" || args[1] == "-v") {
        fmt.Printf("Build Time: %s \n", buildTime)
        fmt.Printf("Build Version: %s \n", buildVersion)
        fmt.Printf("Build Go Version: %s \n", goVersion)
        fmt.Printf("Build Git Commit Hash ID: %s \n", gitCommitID)
        return
    }

}

  • 编译代码时执行如下命令
go build -o app-service -ldflags \
"-X main.buildTime=`date +%Y-%m-%d,%H:%M:%S` -X main.buildVersion=1.0.0 -X 'main.goVersion=$(go version)' -X main.gitCommitID=`git rev-parse HEAD`"

在上述命令中,通过 -ldflags 命令的 -X 参数可以在链接时将信息写入变量中,其格式为:package_name.variable_name=value

  • 查看编译后的二进制文件和版本信息
./app-service -version

# output is:
# Build Time: 2022-03-27,13:50:26
# Build Version: 1.0.0
# Build Go Version: go version go1.16.3 darwin/amd64
# Build Git Commit Hash ID: b3473e9cc98148f5c94b53c1cada7de133143462

部署

关于守护进程

  • nohup —— linux 系统内置,直接使用 nohup ./<executable-file> & 即可
  • systemctl —— linux 系统内置,需要配置 systemctl 管理配置文件
  • supervisor
  • go-supervisor —— Go 语言实现但 supervisor,好处是不需要安装 Python 环境

1. 使用 supervisor 部署:

# 假设关闭一个监听端口为 3000 的服务
kill -9 $(lsof -ti:3000)

创建 supervisor 相关配置信息

vim /etc/supervisor/conf.d/alex-blog.conf

# 程序名称,stop start 等管理时使用
[program:alex-blog]
# 进入该目录运行命令,确保了和项目相关的一些配置文件可以得到加载,比如 .env 文件
directory=/data/www/blog
# 以绝对路径的方式执行 alex-blog 二进制文件
command=/data/www/blog/alex-blog
# 重启时发送的信号,确保端口正常关闭
stopsignal=TERM
# 是否自启动
autostart=true
# 是否自动重启
autorestart=true
# 执行程序的用户
user=www-data
# 输出日志位置
stdout_logfile=/data/log/supervisor/blog/stdout.log
# 错误输出日志
stderr_logfile=/data/log/supervisor/blog/stderr.log

重载 Supervisor 配置文件

# 重载 supervisor 配置文件
supervisorctl reload

# 查看程序名称为 alex-blog 的程序状态
# 如果直接执行 `supervisorctl status` 命令的话,则是查看所有任务的状态
supervisorctl status alex-blog

# 关闭所有任务
supervisorctl shutdown

# 启动任务
supervisorctl start <程序名>

# 关闭任务
supervisorctl stop <程序名>

2. 使用 docker 部署:

编译后的二进制文件放在 docker 中运行

先要在宿主机中项目根目录下进行编译

# 交叉编译生成 Linux 平台的可执行文件
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o hello-world

编写 Dockerfile 文件

# 基础镜像
FROM alpine:3.12
# 或者使用 Scratch 镜像
# FROM scratch

# 维护者
MAINTAINER alex

# docker build 时执行命令
RUN mkdir -p /go-project/demo \
&& ln -sf /dev/stdout /go-project/demo/storage/service.log

# 工作目录
WORKDIR /go-project/demo

# 拷贝
COPY hello-world /go-project/demo/hello-world
# 或者直接将当前目录下所有的文件拷贝到容器中
# COPY . /go-project/demo

# 这里暴露端口与否都行
# EXPOSE 8501

# docker run 时执行的命令
ENTRYPOINT ["./hello-world"]

直接在 docker 容器中编译时,所需要编写的 Dockerfile 文件

# 直接使用 go 1.16 镜像
FROM golang:1.16-alpine AS build

WORKDIR /src/
COPY . /src/
# 交叉编译生成 Linux 平台的可执行文件
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /bin/hello-world

FROM scratch
COPY --from=build /bin/hello-world /bin/hello-world
ENTRYPOINT ["/bin/hello-world"]

构建镜像

docker build -t go-project:v1.0.0 .

运行容器

# 宿主机的 9501 端口映射到了容器的 8501 端口
# -d 用于该程序在后台运行
# -p 用于映射端口
docker run -d -p 9501:8501 go-project:v1.0.0

nginx 配置信息


upstream go-project {
    # go-project HTTP Server 的 IP 及 端口
    server 127.0.0.1:9501;
}

server
{
    listen 80;
    server_name goblog.com;
    
    access_log   /data/log/nginx/goblog/access.log;
    error_log    /data/log/nginx/goblog/error.log;
    
    location /static/ {
      alias /www/wwwroot/gitlab/go-project/public/uploads/; #静态资源路径
    }
    
    location / {
        # 将客户端的 Host 和 IP 信息一并转发到对应节点
        proxy_redirect             off;
        proxy_set_header           Host             $http_host;
        proxy_set_header           X-Real-IP        $remote_addr;
        proxy_set_header           X-Forwarded-For  $proxy_add_x_forwarded_for;
        
        # 转发Cookie,设置 SameSite
        proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
        
        # 执行代理访问真实服务器
        proxy_pass                 http://go-project;
    }
    
}

相关文章

  • GO打包部署脚本

    GO打包部署脚本 $ Linux 打包 build_linux.bat $ Windows exe 打包 bu...

  • Go | Go 语言打包静态文件以及如何与Gin一起使用Go-b

    Go | Go 语言打包静态文件以及如何与Gin一起使用Go-bindata 系列文章目录 第一章 Go 语言打包...

  • 树莓派内网穿透 Ngrok

    部署准备 go语言安装 树莓派和vps安装go的方式有所不同,树莓派下需要编译 树莓派安装go参考 http://...

  • go语言能做什么

    鉴于Go语言的特点和设计的初衷,Go语言作为服务器编程语言,很适合处理日志、数据打包、虚拟机处理、文件系统、分布式...

  • 使用maven build go项目放到Linux执行

    本地windows环境,直接maven打包go项目,并部署到linux执行。 maven构建文件

  • Beego打包部署到Linux

    Beego打包部署到Linux 打包 打开Terminal 定位到工程的 main.go 文件夹目录 使用命令 b...

  • Beego打包部署到Linux

    Beego打包部署到Linux 打包 打开Terminal 定位到工程的 main.go 文件夹目录 使用命令 b...

  • 换Make来构建你的Go语言项目吧

    看这篇文章之前,你是否打包Go语言开发的项目时,是直接在命令行输入: 在开发调试时是否是: 然后看到开源的Go语言...

  • Golang聚合

    教程 Go Web 编程Go语言圣经(中文版) Tips Golang 学习笔记——交叉编译 & 部署Golang...

  • 初识Go语言-1

    Go语言学习路径 初识Go语言 Go语言环境搭建与IDE安装 Go语言基础语法 Go语言数据类型 Go语言变量和常...

网友评论

      本文标题:一文让你完全弄懂Go语言打包和部署!

      本文链接:https://www.haomeiwen.com/subject/swydfjtx.html