golang编译与go程序部署

Go程序编译

1. 交叉编译(Cross compiler)

交叉编译是在一个平台上生成另一个平台上的可执行代码。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行

对于交叉编译我们简单的理解是在当前平台上编译出其他平台可以执行的文件

交叉编译给我们带来的好处是我们一次编写的代码经过交叉编译之后可以在多个平台上执行

我们在 Windows 编写Go程序可以编译成在 Mac OS 或者 Linux 上的运行程序 (良好的可移植性)

2. 交叉编译设置

重点参数说明 :

GOOS : 目标操作系统

GOARCH : 目标操作系统的架构

1.1 Windows 平台
# 目标平台 Mac
SET GOOS=darwin 
SET GOARCH=amd64
# 执行编译
go build main.go
# 目标平台 Linux
SET GOOS=linux
SET GOARCH=amd64
go build main.go
1.2 Linux 平台
# 目标平台 Mac
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
# 目标平台 Windows
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
1.3 Mac 平台
# 目标平台 Linux
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
# 目标平台 windows
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

tips1 :

交叉编译是不支持CGO的(Go代码中存在C代码是编译不过的) , 所以需要将 CGO_ENABLED 设置为0 (禁用CGO)

需要支持CGO 就要将 CGO_ENABLED 设置为1

tips2 :

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

$ go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/386
darwin/amd64
darwin/arm
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/s390x
nacl/386
nacl/amd64p32
nacl/arm
netbsd/386
netbsd/amd64
netbsd/arm
openbsd/386
openbsd/amd64
openbsd/arm
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
windows/386
windows/amd64
windows/arm

3. 编译简单示例 :

Windows 平台编译 Linux 运行程序

G:\app_project\GoProject>set GOOS=linux

G:\app_project\GoProject>go env
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\captain\AppData\Local\go-build
set GOEXE=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=linux
set GOPATH=E:\Go
set GOPROXY=https://goproxy.cn
set GORACE=
set GOROOT=C:\GO
set GOTMPDIR=
set GOTOOLDIR=C:\GO\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=0
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-fPIC -m64 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\captain\AppData\Local\Temp\go-build187358654=/tmp/go-build -gno-record-gcc-switches

G:\app_project\GoProject\>go build main.go

将生成的可执行文件main 上传到 Linux服务器上

# 进入main所在位置
# 给main程序可执行权限
chmod +x main
# 执行
./main

Go程序部署

1. 容器部署

容器部署是现在比较流行的部署方式,容器部署的前提是服务器上安装了Docker

基础步骤:

  1. 编译程序
  2. 编写Dockerfile
  3. 通过Dockerfile 编译成docker镜像
  4. 通过新建的镜像运行一个Golang程序容器
# 将Golang程序编译成对应平台的可执行文件 (-o 指定名称)
GOOS=linux GOARCH=amd64 go build -o MyApp main.go
# 如果是windows平台生成可执行文件
SET GOOS=linux
SET GOARCH=amd64
go build -o MyApp main.go
# 新建 Dockerfile (linux平台执行) 
touch Dockerfile
# 要是windows 平台就新建一个文件文件名就是Dockerfile(没有文件后缀)

1.1 编写Dockerfile (简单示例文件)
# 镜像是基于alpine:3.8
FROM loads/alpine:3.8
# LABLE 给镜像添加元数据
# MAINTAINER 维护者信息
LABEL maintainer="demo@163.com"
# ENV 指定环境变量
# 设置固定的项目路径
ENV WORKDIR /var/wwwroot/BossAdmin
# ADD <src> <dest>  复制指定的 <src> 到容器中的 <dest>
# MyApp是Go代码生成的可执行文件
ADD ./MyApp   $WORKDIR/main
# RUN 指令将在当前镜像基础上执行指定命令
# 添加应用可执行文件,并设置执行权限
RUN chmod +x $WORKDIR/main
# 添加静态文件、配置文件、模板文件 (根据自己的项目实际情况配置)
ADD public    $WORKDIR/public
ADD configs   $WORKDIR/configs
ADD templates  $WORKDIR/templates
# EXPOSE docker容器暴露的端口
EXPOSE 8080
# 指定工作目录
WORKDIR $WORKDIR
# CMD 指定启动容器时执行的命令
CMD ./main
1.2 通过新建的Dockerfile创建镜像

命令 docker build 创建镜像

命令格式 docker build [选项] 路径

参数 -t 来指定镜像的标签

看一下当前文件结构

[root@host5 MyApp]# ll
total 21552
drwxr-xr-x. 2 root root       46 May 12 03:22 configs
-rw-r--r--. 1 root root      854 May 12 05:46 Dockerfile
-rw-r--r--. 1 root root 22062544 May 12 03:22 MyApp
drwxr-xr-x. 2 root root        6 May 12 03:22 public
drwxr-xr-x. 2 root root        6 May 12 03:22 templates

构建镜像

[root@host5 MyApp]# docker build -t app1 .
Sending build context to Docker daemon  22.07MB
Step 1/11 : FROM loads/alpine:3.8
 ---> 20aa4fd1c5a8
Step 2/11 : LABEL maintainer="demo@163.com"
 ---> Running in da0bed8c5bb5
Removing intermediate container da0bed8c5bb5
 ---> 5a5500648739
Step 3/11 : ENV WORKDIR /var/wwwroot/BossAdmin
 ---> Running in 13156e7b009c
Removing intermediate container 13156e7b009c
 ---> bcde11586009
Step 4/11 : ADD ./MyApp   $WORKDIR/main
 ---> fb1a6391b87f
Step 5/11 : RUN chmod +x $WORKDIR/main
 ---> Running in 75d29f00223d
Removing intermediate container 75d29f00223d
 ---> 7e1cd9f4a222
Step 6/11 : ADD public    $WORKDIR/public
 ---> 56d02d9b71a1
Step 7/11 : ADD configs   $WORKDIR/configs
 ---> ec60ca235b75
Step 8/11 : ADD templates  $WORKDIR/templates
 ---> a0607eee6429
Step 9/11 : EXPOSE 8080
 ---> Running in fce1a3f02e70
Removing intermediate container fce1a3f02e70
 ---> 95cbaaae1b85
Step 10/11 : WORKDIR $WORKDIR
 ---> Running in f1b15db866e3
Removing intermediate container f1b15db866e3
 ---> ac7b91d386b3
Step 11/11 : CMD ./main
 ---> Running in 750d968533ba
Removing intermediate container 750d968533ba
 ---> 28da775342b1
Successfully built 28da775342b1
Successfully tagged app1:latest
[root@host5 MyApp]# docker images
REPOSITORY          TAG                       IMAGE ID            CREATED             SIZE
app1                latest                    28da775342b1        51 seconds ago      55MB
[root@host5 MyApp]# docker run -it app1 /bin/bash 
bash-4.4# ls -l
total 21548
drwxr-xr-x    2 root     root            46 May 13 09:54 configs
-rwxr-xr-x    1 root     root      22062544 May 12 15:22 main
drwxr-xr-x    2 root     root             6 May 13 09:54 public
drwxr-xr-x    2 root     root             6 May 13 09:54 templates

1.3 运行新镜像
[root@host5 MyApp]docker run --name myapp1 -p 8080:8080 app1

Tips : 构建好的镜像可以推送到(镜像仓库) 这样其他位置需要使用的时候可以拉取镜像

2. 独立部署

如下操作都是在 Linux 平台 (OS : Centos7)

独立部署一般是在Linux平台上部署Go程序 , 让Go程序在后台执行即可 (当前环境是 : CentOS7)

让Go程序后台执行的方式挺多的,简单罗列一下,具体使用也不麻烦.

2.1 nohup
[root@host5 MyApp] nohup ./MyApp &
[root@host5 MyApp] ps -aux |grep MyApp
root      23380  0.0  0.2 118908 10796 pts/0    Sl   06:52   0:00 ./MyApp
root      23390  0.0  0.0 112708   976 pts/1    S+   06:52   0:00 grep --color=auto MyApp

2.2 tmux
[root@host5 MyApp] yum install -y tmux # 如果没有安装就执行该命令
[root@host5 MyApp] tmux new -s MyApp #开启新的会话窗口
[root@host5 MyApp] ./MyApp # 运行Go程序
[root@host5 MyApp] tmux attach -t MyApp # 进入之前的会话
2.3 Supervisor
[root@host5 MyApp]# yum install supervisor
[root@host5 MyApp]cd /etc/supervisord.d
[root@host5 MyApp]vim app1.ini

app1.ini

[program:app1]
# 运行用户身份
user=root
# 执行的命令
command=/data/wwwwroot/BossAdmin/MyApp
# 日志输出
stdout_logfile=/data/wwwwlog/app1/app1-stdout.log
stderr_logfile=/data/wwwwlog/app1/app1-stderr.log
# supervisor启动的时候是否随着同时启动,默认True
autostart=true
# 当程序exit的时候是否重启
autorestart=true

supervisor 命令

supervisorctl status            //查看所有进程的状态
supervisorctl stop app1         //停止app1
supervisorctl start app1        //启动app1
supervisorctl restart app1      //重启app1
supervisorctl update            //配置文件修改后使用该命令加载新的配置
supervisorctl reload            //重新启动配置中的所有程序
2.4 systemctl

我们很多服务可以使用 systemctl 来管理

[root@host5 system]# pwd
/etc/systemd/system
[root@host5 system]# vim app1.service 
# 如下是app1.service 的内容
[Unit]
# 单元描述
Description=MyApp

[Service]
Type=simple
# 程序执行的目录
WorkingDirectory=/data/wwwwroot/BossAdmin/
# 启动的脚本命令
ExecStart=/data/wwwwroot/BossAdmin/MyApp
# 重启条件
Restart=alway
# 几秒后重启
RestartSec=5

[Install]
 WantedBy=multi-user.target

通过systemctl 启动服务

[root@host5 system]# systemctl start app1 # 启动服务 
[root@host5 system]# systemctl restart app1 # 重启服务
[root@host5 system]# systemctl status app1 # 查看服务运行状态
[root@host5 system]# systemctl stop app1  # 停止服务
[root@host5 system]# systemctl enable app1 # 添加为开机启动项
[root@host5 system]# systemctl disable app1 # 从开机启动项中移除 

3. 代理部署

通常的做法是前置一个第三方的 web服务器 处理请求

那么我们通常是使用 nginx 作为 这个前置层

部署实例

Linux服务器 (Centos7)

IP : 192.168.30.26

将Go项目上传到Linux服务器的项目目录下

[root@host2 GoApp1]# pwd
/data/wwwroot/GoApp1
[root@host2 GoApp1]# yum install -y tree
[root@host2 GoApp1]# tree
.
├── GoApp
└── public
    ├── anni.wav
    └── go.jpg

1 directory, 3 files

编写 nginx 配置文件

更具场景配置文件会有不同

示例配置文件名 : GoApp.conf

server {
    # 监听的端口
    listen       18080;
    # 域名 
    server_name  _ ;
    # 访问日志
    access_log   /data/wwwlogs/GoApp1-access.log;
    # 错误日志
    error_log    /data/wwwlogs/GoApp1-error.log;
    
    # 静态文件交给nginx处理,这里是采用文件后缀来区分的
    location ~ .*\.(gif|jpg|jpeg|png|js|css|eot|ttf|woff|svg|otf)$ {
        access_log off;
        expires    1d;
        root       /data/wwwroot/GoApp1/public;
        try_files  $uri @go_dispose;
    }
 #  也可根据文件夹目录区分,指定目录的访问交给Nginx处理(将public目录交给nginx处理)
 #  location ^~ /public {
 #      access_log off;
 #      expires    1d;
 #      root       /data/wwwroot/GoApp1;
 #      try_files  $uri @go_dispose;
 #  }
 
    # 将其他程序交给后端Go处理
    location / {
        try_files $uri @go_dispose;
    }
    
    location @go_dispose {
        # Go程序处理的地址
        proxy_pass                 http://127.0.0.1:8080;
        proxy_redirect             off;
        proxy_set_header           Host             $host;
        proxy_set_header           X-Real-IP        $remote_addr;
        proxy_set_header           X-Forwarded-For  $proxy_add_x_forwarded_for;
    }
}

重启nginx

[root@host2 vhost]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@host2 vhost]# service nginx restart 

运行Go程序

[root@host2 GoApp1]# chmod +x GoApp 
[root@host2 GoApp1]# ./GoApp 
start http server and listen 8080

测试

后端Go程序处理

[root@host2 /]# curl -X POST -H "Content-type:application/json" -d '{"username":"admin","password":"123456","role":"edit"}' http://192.168.30.26:18080/auth
{"code":"200","message":"success","data":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJyb2xlIjoiZWRpdCIsImV4cCI6MTU4OTYyMDcxNywiaXNzIjoiY2FwdGFpbiIsInN1YiI6Imp3dCB0ZXN0In0.Ypqe9OP6yiIEqeo-Ub629kiEmYZVLnd8ZOh12R7BTns"}}

静态文件处理

直接在客户端浏览器中访问

http://192.168.30.26:18080/go.jpg

能浏览到图片

参考

- [1] golang交叉编译和条件编译的实际应用

- [2] tmux使用教程

- [3] Tmux 使用教程

- [4] Docker

- [5] Docker中文文档

- [6] Systemd 入门教程:命令篇

- [7] Nginx文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341