Docker multistage

#docker #docker_multistage

使用场景

在使用容器的搭建服务环境的时候,常常会因为安装过程中,产生的文件让容器变得非常臃肿,或者是在搭建编译环境编译代码后,我们只需要使用编译后的可执行文件,并不需要编译环境,以上情况,使用multistage的方式i就可以有效的给容器瘦身.

编写一个简单的应用

package main

import (
	"fmt"
	"log"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello from the webserver")
}

func main(){
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil))
}

编写Dockerfile

⚠️ WORKDIR WORKDIR 指定工作目录 - Docker —— 从入门到实践 使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

FROM golang:1.8

WORKDIR /go/src/app
COPY main.go .

RUN go build -o webserver .

CMD ["./webserver"]

生成Image

进入到Dockerfile所在文件夹后执行如下命令, -t 是给生成的image指定一个tag

$ docker build -t webserver .

运行容器

-p 指定host和容器之间的端口映射,访问host的8080端口就是访问容器中的8080端口

$ docker run  -p "8080:8080" webserver

查看当前Image的大小

$ docker images | grep webserver

会看到一个很简单的webserver居然有几百兆

如果把Dockerfile的基础镜像切换为alpine,可以做一些减少,不过还是有上百兆.

FROM golang:alpine

编写MultiStage Dockerfile

FROM golang:alpine AS builder # 第一阶段 搭建编译环境并编译可执行文件

WORKDIR /go/src/app
COPY main.go .

RUN go build -o webserver .

FROM alpine # 第二阶段 运行环境 
WORKDIR /app
COPY --from=builder /go/src/app/ /app/ # 将第一阶段编译生成的可执行文件和运行必要的其他文件 拷贝到第二阶段中

CMD ["./webserver"]

生成Image并测试,再查看Image大小

$ docker build -t webserver .
$ docker run  -p "8080:8080" webserver
$ docker images | grep webserver

⚠️ 编译环境最好喝运行环境是匹配的,就是说你不能在windows上编译出一个可执行文件,然后咋第二阶段用MacOS来运行.

如何确定哪些文件需要COPY到需要的阶段呢

关键的命令有两个