Docker scratch 无法正常运行golang二进制程序的问题

使用Docker构建容器能够极大的降低运维成本,提高部署效率,同时非常方便对服务的平行扩展。然而在构建容器镜像过程中的,存在着一个难以避免的问题,就是如果使用常见的发行版本作为程序运行的基础环境,那么即使一个服务本身的运行文件非常小,最终构建的镜像也可能会有会在运行环境的镜像的基础上变得更大,动不动就是数百M的体积。

以最常用于微服务开发的golang为例,golang的二进制程序可以一次开发跨平台编译,到处运行,因此其本身的程序自洽性其实非常完善,也很少会依赖复杂的外部环境,因此常用的发行版本镜像硕大的体积其实很没必要。因此,alpine成为了一个非常好的选择。最终alpine也不负众望,将最终的镜像体积减小到了10M+左右,已经压缩了非常大的空间了,结果还算理想。

 

然而,能不能更小呢?

 

docker自带的scratch镜像给了我一个思路:没有任何镜像会比空镜像更小。那使用scratch制作出来的镜像也必然是最小的。那么scratch是不是一个好的选择呢?scratch镜像是docker自带的空镜像,我也曾见过数篇文章推荐使用其作为golang的运行镜像,然而,在最终实践的时候,遇到的bug却会让人倍感疑惑。

 

# 1. 使用官方的golang镜像构建运行的容器

golang程序非常简单:

 

package main

import "fmt"

func main(){

    fmt.Println("你好,世界!")

}

 

Dockerfile也不难:

 

FROM harbor.corp.sdo.com/library/golang:alpine as build

MAINTAINER fanxiaoqiang <fan_xq@live.com>

 

ADD . /data/

 

WORKDIR /data/

 

RUN export GO111MODULE=on

RUN export GOSUMDB=off

RUN unset GOPATH

RUN go env -w GOPROXY=https://goproxy.cn

 

RUN go build -o server helloworld.go

 

# deploy-image

 

FROM scratch

#FROM alpine

 

COPY --from=build /data/server /data/server

#COPY --from=build /data/entrypoint.sh /data/entrypoint.sh

WORKDIR /data/

 

EXPOSE 9090

 

CMD ["/data/server"]

 

构建,运行!

 

docker build -t hello .

&& docker run

-p 9090:9090

hello


容器成功的输出了helloword,最终的镜像大小只有2.068MB,效果非常理想。然后scratch是否真的能够满足golang容器化的所有需求呢?下面我们继续看。

 

# 2. 使用scratch构建稍复杂的golang的运行容器

 

这一次我们构建一个golang实现的http服务器。在开始之前,首先强调一下scratch是一个空镜像,意味这Docker内部不存在任何环境和依赖库。机智的读者可能已经想到我想说什么,接下来开始进行实验。

 

golang程序:

 

package main

 

import (

    "log"

    "net/http"

    "os"

    "os/signal"

    "time"

)

 

func main() {

    server := http.Server{

        Addr:        ":9090",

        ReadTimeout: 10 * time.Second,

    }

    //log.Println("start running")

    log.Println("start running")

 

    server.ListenAndServe()

    //合建chan

    c := make(chan os.Signal)

    //监听指定信号 ctrl+c kill

    signal.Notify(c, os.Interrupt, os.Kill)

    //阻塞直到有信号传入

    //阻塞直至有信号传入

    s := <-c

    log.Println("exit!", s)

}

 

Docker文件第一节相同,这里就不放了。

现在让我们尝试 运行,

docker build -t hello .

&& docker run

-p 9090:9090

hello

构建镜像的过程依旧轻松愉快:

Building image...

Preparing build context archive...

[==================================================>]9/9 files

Done

 

Sending build context to Docker daemon...

[==================================================>] 2.859kB

Done

 

Step 1/14 : FROM harbor.corp.sdo.com/library/golang:alpine as build

 ---> dda4232b2bd5

Step 2/14 : MAINTAINER fanxiaoqiang <fan_xq@live.com>

 ---> Using cache

 ---> 546d5bcb606b

Step 3/14 : ADD . /data/

 ---> d6bcfc3f9976

Step 4/14 : WORKDIR /data/

 ---> Running in 4a8f0fa4c9c4

Removing intermediate container 4a8f0fa4c9c4

 ---> 6f6092bc91a8

Step 5/14 : RUN export GO111MODULE=on

 ---> Running in 44a83bb9c9a9

Removing intermediate container 44a83bb9c9a9

 ---> ea199d64e9d9

Step 6/14 : RUN export GOSUMDB=off

 ---> Running in df368787ddd7

Removing intermediate container df368787ddd7

 ---> c338c09c4980

Step 7/14 : RUN unset GOPATH

 ---> Running in c6016dd29cd8

Removing intermediate container c6016dd29cd8

 ---> 8f7004cb8ed5

Step 8/14 : RUN go env -w GOPROXY=https://goproxy.cn

 ---> Running in 237a89c7a644

Removing intermediate container 237a89c7a644

 ---> 5b5b9b8efb43

Step 9/14 : RUN go build -o server http_server.go

 ---> Running in 27a5afb6b775

Removing intermediate container 27a5afb6b775

 ---> 8e0771380586

 

Step 10/14 : FROM scratch

 --->

Step 11/14 : COPY --from=build /data/server /data/server

 ---> 76dc69f34774

Step 12/14 : WORKDIR /data/

 ---> Running in 8550a1a7b8ee

Removing intermediate container 8550a1a7b8ee

 ---> 269d3ee7bb29

Step 13/14 : EXPOSE 9090

 ---> Running in 2a3f21f67f90

Removing intermediate container 2a3f21f67f90

 ---> 79640d9e743a

Step 14/14 : CMD ["/data/server"]

 ---> Running in 39581ed1d208

Removing intermediate container 39581ed1d208

 ---> e30b2238a606

 

Successfully built e30b2238a606

Successfully tagged hello:latest

Existing container found: 8b31d39f149117566da56be2796418089c47509018857427559600f1ba7c7982, removing...

Creating container...

Container Id: 20d38a265fe3496b5a4b6c3742740c6c517b7d449250ab0be246688973212079

Container name: '/vibrant_hodgkin'

Attaching to container '/vibrant_hodgkin'...

Starting container '/vibrant_hodgkin'

'<unknown> Dockerfile: Dockerfile' has been deployed successfully.

 

然而查看容器的日志输出:

standard_init_linux.go:211: exec user process caused "no such file or directory"

 

???

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzswx.html