在Linux环境下编译好Go源文件以后我尝试将最后的可执行文件复制到Docker镜像alpine中。
这是一个最简单的Go Web代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
var r = gin.Default()

r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, "pong")
})

r.GET("/produce", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
"goods": "apple",
})
})

if err := r.Run(":3000"); err != nil {
panic("start error")
}
}

以及对应的Dockerfile

1
2
3
4
5
6
FROM alpine

WORKDIR /app
COPY web /app/web

CMD ["/app/web"]

在最后运行容器时始终出现了file not found的警告,容器一直启动失败,我尝试通过exec进入到容器内部查看文件,发现文件确实拷贝到了正确的位置,但是我在容器中无法使用./web之类的方式启动。

那看来是可执行文件本身的问题,很快发现默认情况下Go编译处的可执行文件是需要动态链接,而alpine是一个相当轻量的Linux,其本身并不包括动态链接所需要的文件,所以我们要使用静态链接

找到问题之后我们只要静态编译即可

1
$ CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' .

最后再次重新构建发现问题果然解决