docker部署go程序实现极小镜像占用

1.交叉编译

通常我们编写代码会在linux的环境中,一般开发环境就是win里面装个linux虚拟机,有的时候在虚机里安装相关IDE,这就使得本来资源有限的虚机进一步压缩,go恰好可以交叉编译,这为编码带来了极大的好处。
根据go的编译逻辑,我们在编译前更改go env后可实现win平台build linux平台运行的程序。
通过cmd或者powershell或者其他终端查看go env,然后调整env: GOOS,具体来说如以下命令:

# 1.windows平台
$ go env | grep GOOS
set GOOS=windows

# win -> linux
$ go env -w GOOS=linux

# 查看GOOS,确认env生效
$ go env| grep GOOS
set GOOS=linux

# 查看arch,确认是否需要更改,通常都是amd64,通常较少是arm架构的
$ go env | grep GOARCH
set GOARCH=amd64

# 2.linux平台,如果需要在linux上编译win上运行的exe可执行文件,参考更改,GOOS: linux -> windows

2.镜像准备

参考文章:golang 打包到docker运行,最小镜像,考虑go编译后的就是一个可执行文件,我们可以将二进制运用和配置打到容器里面,就不用在容器里也要求配置go的运行环境,那种考虑的是在build镜像时,在Dockerfile中go build出来,那样的话,镜像大小在G级别了,换种思路,在apline中打入二进制应用加配置,镜像大小会小很多,是不是在20M级别呢。

确认好运行后编辑Dockerfile:

# cat Dockerfile
# 表示依赖 alpine 最新版
FROM alpine:latest

ENV VERSION 1.0

# 在容器根目录 创建一个 apps 目录
WORKDIR /apps

# 挂载容器目录
# VOLUME ["/apps/conf"]

# 拷贝当前目录下 go_docker_demo1 可以执行文件
COPY main /apps/golang_app

# 拷贝配置文件到容器中
# COPY conf/config.toml /apps/conf/config.toml

# 设置时区为上海
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone

# 设置编码
ENV LANG C.UTF-8

# 暴露端口
EXPOSE 8090

# 运行golang程序的命令
ENTRYPOINT ["/apps/golang_app"]

构建镜像:

docker build -t go-apline:v1.0 .

# 查看镜像
docker images
REPOSITORY         TAG       IMAGE ID       CREATED        SIZE
go-apline          v1.0      5a81dd4bb076   16 hours ago   18.9MB
alpine             latest    b2aa39c304c2   4 weeks ago    7.05MB

# 可以看到构建后的容器也仅在20M内了,确实很省空间了

注:相关源码

pwd
# /root/ngx-go-web/apline

ls
---
.:
conf  Dockerfile  go.mod  go.sum  main  main.go

./conf:
config.toml
---
# mai为win平台编译后的linux下可运行的二进制应用,go build即可,cp到linux上时,由于win上的权限问题,需要通过chomod调整,chmod 777 main

main.go

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"log"
	"strconv"
	"strings"
)

func main()  {
	r := gin.Default()
	r.Any("/", any)

	appAddrPort := strings.Join([]string{":", strconv.Itoa(conf.Port)}, "")
	r.Run(appAddrPort)
}

func any(c *gin.Context)  {
	message := strings.Join([]string{"Hello", conf.AppName, conf.Description}, " ")
	c.JSON(200, gin.H{
		"message": message,
	})
}

type AppConfig struct {
	AppName string `json:"appName"`
	Port int `json:"port"`
	Description string `json:"description"`
}

var conf AppConfig

func init()  {
	log.Println("loading config ...")
	viper.SetConfigName("config")
	viper.SetConfigType("toml")
	viper.AddConfigPath("./conf")

	if err := viper.ReadInConfig(); err != nil {
		log.Println(err)
	}
	if err := viper.Unmarshal(&conf); err != nil {
		log.Println(err)
	}
	log.Println("loading config completed.")
}

config.toml

appName = "go docker demo1"
port = 8090
description = "这是一个go-gin demo"

go.mod

module go-crossBuild

go 1.19

require (
	github.com/gin-gonic/gin v1.9.0
	github.com/spf13/viper v1.15.0
)

3.部署

go运行容器的镜像也准备好了,接下来直接运行容器:

docker run -d --name my-go-gin \ 
  -p 8090:8090 \  # 映射端口出来,通过host:hostPort即可访问
  -v /root/ngx-go-web/apline/conf/config.toml:/apps/conf/config.toml \ # 挂载配置
  -v /etc/localtime:/etc/localtime:ro  \ # 调整时间
  go-apline:v1.0

docker ps | grep my-go
# 11dc135c63e2   go-apline:v1.0          "/apps/golang_app"       16 hours ago   Up 16 hours   0.0.0.0:8090->8090/tcp, :::8090->8090/tcp       my-go-gin

接下来看看测试效果。

改下配置,再看看效果:

cat config.toml
---
appName = "go docker demo22222222222222222222222222222"
port = 8090
description = "这是一个go-gin demo"
---

重启docker:docker restart my-go-gin
再看看效果:

说明确实起作用了,更改配置的appname后,也看到更改了。

posted on 2023-03-16 18:34  进击的davis  阅读(361)  评论(0)    收藏  举报

导航