go项目想运行在docker中,需要先制作镜像。主要有两种方式!

1.在 https://hub.docker.com/ 中 搜索 golang ,Dockerfile 中 依赖 golang 镜像 (大概100M左右)


​这种方式 如下,是在容器里,将 golang 程序编译的。所以需要依赖 golang sdk 进行编译

FROM golang:alpine
WORKDIR $GOPATH/src/gin_docker
ADD . ./
ENV GO111MODULE=on
ENV GOPROXY="https://goproxy.io"
RUN go build -o gin_docker .
EXPOSE 8080
ENTRYPOINT  ["./gin_docker"]

这种方式,我不太喜欢,打包的镜像文件太大了 。 最少也是100M,也浪费了golang 的交叉编译的功能

2.在本地使用交叉编译,将go程序编译成 Linux 可以执行文件,然后只需要依赖一个非常小的操作系统就可以了。如: alpine 只有 3M 左右的大小。再加上go可执行文件的大小。也就是十几MB

​下面我们使用第2种方式,将go程序使用docker运行。

随便编写一个 go 程序,如下

package main

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

//项目配置
type AppConfig struct {
	AppName     string
	Port        int
	Description string
}

var conf AppConfig

// 初始化配置文件
func init() {
	viper.SetConfigName("config")
	viper.SetConfigType("toml")
	viper.AddConfigPath("/etc/appname/") // 查找配置文件所在路径
	viper.AddConfigPath("$HOME/.appname") // 多次调用AddConfigPath,可以添加多个搜索路径
	viper.AddConfigPath(".") // 还可以在工作目录中搜索配置文件
	viper.AddConfigPath("./conf") // 还可以在工作目录中搜索配置文件
	if err := viper.ReadInConfig(); err != nil {
		fmt.Printf("read config failed: %v \r", err)
	}
	if err := viper.Unmarshal(&conf); err != nil {
		fmt.Println(err)
	}
}

// 使用 gin 创建一个 http 服务
func main() {
	r := gin.Default()
	r.Any("/", func(c *gin.Context) {
		message := strings.Join([]string{"Hello", conf.AppName, conf.Description}, " ")
		c.JSON(200, gin.H{
			"message": message,
		})
	})
	appPort := strings.Join([]string{":", strconv.Itoa(conf.Port)}, "")
	r.Run(appPort)
}

config.toml 配置文件,如下

appName = "go docker demo1"
port = 8089
description = "这是一个非常牛逼的app"
​我这边是使用了  goreleaser 插件,
goreleaser --rm-dist --snapshot
 

当然也可以手动去交叉编译

SET CGO_ENABLED=0

# 设置 操作系统的类型
SET GOOS=linux

# 设置 cpu 架构
SET GOARCH=amd64

go build

切记一定要先把项目编译了,然后才能 构建 docker 镜像

编写 Dockerfile

# 表示依赖 alpine 最新版
FROM alpine:latest
MAINTAINER Wang Chen Chen<932560435@qq.com>
ENV VERSION 1.0

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

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

# 拷贝当前目录下 go_docker_demo1 可以执行文件
COPY dist/go_docker_demo1_linux_amd64/go_docker_demo1 /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 8089

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


需要注意 这条命令 ! 如果你是用手动编译的方式,那么可执行文件就在当前目录下

# goreleaser 插件编译的方式
COPY dist/go_docker_demo1_linux_amd64/go_docker_demo1 /apps/golang_app 


# 手动编译的方式
COPY go_docker_demo1 /apps/golang_app 

拷贝当前项目下编译好的可执行文件,到容器中的 apps 目录下,并且修改名称为 “golang_app”

前置条件就已经ok了!

构建docker镜像
docker build -t go_docker_demo1:v1.1 .

我们构建的镜像大小只有 17MB 真的很小


启动 构建的镜像

docker run -d --name my-go_docker_demo1 -p 8089:8089 go_docker_demo1:v1.1

浏览器 打开  http://localhost:8089/
​带挂载目录的启动,意思:将当前操作系统的目录 
D盘 go_docker_demo1/conf 挂在到容器中 /apps/conf 目录。
这样 conf/config.toml 的配置文件,就可以在宿主机中修改了。
容器重启后,就会加载新的配置文件。目的是为了解决,有时候无需要重新构建项目,
只需要修改配置文件 的情况!


Windows docker 容器的挂载方式

docker run -d --name my-go_docker_demo1 -p 8089:8089 -v /d/go_docker_demo1/conf:/apps/conf go_docker_demo1:v1.1

Linux docker 容器的挂载方式,任意选一个都可以

docker run -d --name my-go_docker_demo1 -p 8089:8089 -v /home/go_docker_demo1/conf:/apps/conf go_docker_demo1:v1.1

docker run -d --name my-go_docker_demo1 -p 8089:8089 -v $PWD/conf:/apps/conf go_docker_demo1:v1.1

确保宿主机中有配置文件,否则程序读不到配置文件,就没法启动了

Windows  d:\go_docker_demo1\conf\config.toml 

Linux  /home/go_docker_demo1/conf/config.toml 

我只是修改了,d:\go_docker_demo1\conf\config.toml 中的文件,然后重启容器后,就重新加载配置文件; 这种方式更灵活一些!