mirror of
				https://github.com/yeasy/docker_practice.git
				synced 2025-10-31 02:03:11 +00:00 
			
		
		
		
	Add multistage builds #226
This commit is contained in:
		
							
								
								
									
										1
									
								
								image/demo/multistage-builds/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								image/demo/multistage-builds/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| app | ||||
							
								
								
									
										12
									
								
								image/demo/multistage-builds/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								image/demo/multistage-builds/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| FROM golang:1.9-alpine | ||||
| RUN apk --no-cache add git | ||||
| WORKDIR /go/src/github.com/go/helloworld/ | ||||
| RUN go get -d -v github.com/go-sql-driver/mysql | ||||
| COPY app.go . | ||||
| RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . | ||||
|  | ||||
| FROM alpine:latest | ||||
| RUN apk --no-cache add ca-certificates | ||||
| WORKDIR /root/ | ||||
| COPY --from=0 /go/src/github.com/go/helloworld/app . | ||||
| CMD ["./app"] | ||||
							
								
								
									
										10
									
								
								image/demo/multistage-builds/Dockerfile.build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								image/demo/multistage-builds/Dockerfile.build
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| FROM golang:1.9-alpine | ||||
|  | ||||
| RUN apk --no-cache add git | ||||
|  | ||||
| WORKDIR /go/src/github.com/go/helloworld | ||||
|  | ||||
| COPY app.go . | ||||
|  | ||||
| RUN go get -d -v github.com/go-sql-driver/mysql \ | ||||
|   && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . | ||||
							
								
								
									
										9
									
								
								image/demo/multistage-builds/Dockerfile.copy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								image/demo/multistage-builds/Dockerfile.copy
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| FROM alpine:latest | ||||
|  | ||||
| RUN apk --no-cache add ca-certificates | ||||
|  | ||||
| WORKDIR /root/ | ||||
|  | ||||
| COPY app . | ||||
|  | ||||
| CMD ["./app"] | ||||
							
								
								
									
										15
									
								
								image/demo/multistage-builds/Dockerfile.one
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								image/demo/multistage-builds/Dockerfile.one
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| FROM golang:1.9-alpine | ||||
|  | ||||
| RUN apk --no-cache add git ca-certificates | ||||
|  | ||||
| WORKDIR /go/src/github.com/go/helloworld/ | ||||
|  | ||||
| COPY app.go . | ||||
|  | ||||
| RUN go get -d -v github.com/go-sql-driver/mysql \ | ||||
|   && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ | ||||
|   && cp /go/src/github.com/go/helloworld/app /root | ||||
|  | ||||
| WORKDIR /root/ | ||||
|  | ||||
| CMD ["./app"] | ||||
							
								
								
									
										7
									
								
								image/demo/multistage-builds/app.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								image/demo/multistage-builds/app.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| package main | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| func main(){ | ||||
|     fmt.Printf("Hello World!"); | ||||
| } | ||||
							
								
								
									
										14
									
								
								image/demo/multistage-builds/build.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										14
									
								
								image/demo/multistage-builds/build.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| echo Building go/helloworld:build | ||||
|  | ||||
| docker build -t go/helloworld:build . -f Dockerfile.build | ||||
|  | ||||
| docker create --name extract go/helloworld:build | ||||
| docker cp extract:/go/src/github.com/go/helloworld/app ./app | ||||
| docker rm -f extract | ||||
|  | ||||
| echo Building go/helloworld:2 | ||||
|  | ||||
| docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy | ||||
| rm ./app | ||||
| @@ -1 +1,177 @@ | ||||
| ## 多阶段构建 | ||||
|  | ||||
| ### 之前的做法 | ||||
|  | ||||
| 在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式: | ||||
|  | ||||
| #### 全部放入一个 Dockerfile | ||||
|  | ||||
| 一种方式是将所有的构建过程编包含在一个 `Dockerfile` 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题: | ||||
|  | ||||
|   * `Dockerfile` 特别长,可维护性降低 | ||||
|  | ||||
|   * 镜像层次多,镜像体积较大,部署时间变长 | ||||
|  | ||||
|   * 源代码存在泄露的风险 | ||||
|  | ||||
| 例如 | ||||
|  | ||||
| 编写 `app.go` 文件,该程序输出 `Hello World!` | ||||
|  | ||||
| ```go | ||||
| package main   | ||||
|  | ||||
| import "fmt"   | ||||
|  | ||||
| func main(){   | ||||
|     fmt.Printf("Hello World!"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| 编写 `Dockerfile.one` 文件 | ||||
|  | ||||
| ```docker | ||||
| FROM golang:1.9-alpine | ||||
|  | ||||
| RUN apk --no-cache add git ca-certificates | ||||
|  | ||||
| WORKDIR /go/src/github.com/go/helloworld/ | ||||
|  | ||||
| COPY app.go . | ||||
|  | ||||
| RUN go get -d -v github.com/go-sql-driver/mysql \ | ||||
|   && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ | ||||
|   && cp /go/src/github.com/go/helloworld/app /root | ||||
|  | ||||
| WORKDIR /root/ | ||||
|  | ||||
| CMD ["./app"] | ||||
| ``` | ||||
|  | ||||
| 构建镜像 | ||||
|  | ||||
| ```bash | ||||
| $ docker build -t go/helloworld:1 -f Dockerfile.one . | ||||
| ``` | ||||
|  | ||||
| #### 分散到多个 Dockerfile | ||||
|  | ||||
| 另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。 | ||||
|  | ||||
| 例如 | ||||
|  | ||||
| 编写 `Dockerfile.build` 文件 | ||||
|  | ||||
| ```docker | ||||
| FROM golang:1.9-alpine | ||||
|  | ||||
| RUN apk --no-cache add git | ||||
|  | ||||
| WORKDIR /go/src/github.com/go/helloworld | ||||
|  | ||||
| COPY app.go . | ||||
|  | ||||
| RUN go get -d -v github.com/go-sql-driver/mysql \ | ||||
|   && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . | ||||
| ``` | ||||
|  | ||||
| 编写 `Dockerfile.copy` 文件 | ||||
|  | ||||
| ```docker | ||||
| FROM alpine:latest | ||||
|  | ||||
| RUN apk --no-cache add ca-certificates | ||||
|  | ||||
| WORKDIR /root/ | ||||
|  | ||||
| COPY app . | ||||
|  | ||||
| CMD ["./app"] | ||||
| ``` | ||||
|  | ||||
| 新建 `build.sh` | ||||
|  | ||||
| ```bash | ||||
| #!/bin/sh | ||||
| echo Building go/helloworld:build | ||||
|  | ||||
| docker build -t go/helloworld:build . -f Dockerfile.build | ||||
|  | ||||
| docker create --name extract go/helloworld:build | ||||
| docker cp extract:/go/src/github.com/go/helloworld/app ./app | ||||
| docker rm -f extract | ||||
|  | ||||
| echo Building go/helloworld:2 | ||||
|  | ||||
| docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy | ||||
| rm ./app | ||||
| ``` | ||||
|  | ||||
| 现在运行脚本即可构建镜像 | ||||
|  | ||||
| ```bash | ||||
| $ chmod +x build.sh | ||||
|  | ||||
| $ ./build.sh | ||||
| ``` | ||||
|  | ||||
| 对比两种方式生成的镜像大小 | ||||
|  | ||||
| ```bash | ||||
| $ docker images | ||||
|  | ||||
| REPOSITORY                                               TAG                    IMAGE ID            CREATED              SIZE | ||||
| go/helloworld                                            2                      f7cf3465432c        22 seconds ago       6.47MB | ||||
| go/helloworld                                            1                      f55d3e16affc        2 minutes ago        295MB | ||||
| ``` | ||||
|  | ||||
| ### 使用多阶段构建 | ||||
|  | ||||
| 为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`: | ||||
|  | ||||
| 例如 | ||||
|  | ||||
| 编写 `Dockerfile` 文件 | ||||
|  | ||||
| ```docker | ||||
| FROM golang:1.9-alpine | ||||
|  | ||||
| RUN apk --no-cache add git | ||||
|  | ||||
| WORKDIR /go/src/github.com/go/helloworld/ | ||||
|  | ||||
| RUN go get -d -v github.com/go-sql-driver/mysql | ||||
|  | ||||
| COPY app.go . | ||||
|  | ||||
| RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . | ||||
|  | ||||
| FROM alpine:latest | ||||
|  | ||||
| RUN apk --no-cache add ca-certificates | ||||
|  | ||||
| WORKDIR /root/ | ||||
|  | ||||
| COPY --from=0 /go/src/github.com/go/helloworld/app . | ||||
|  | ||||
| CMD ["./app"]   | ||||
| ``` | ||||
|  | ||||
| 构建镜像 | ||||
|  | ||||
| ```bash | ||||
| $ docker build -t go/helloworld:3 . | ||||
| ``` | ||||
|  | ||||
| 对比三个镜像大小 | ||||
|  | ||||
| ```bash | ||||
| $ docker images | ||||
|  | ||||
| REPOSITORY                                               TAG                    IMAGE ID            CREATED              SIZE | ||||
| go/helloworld                                            3                      d6911ed9c846        7 seconds ago        6.47MB | ||||
| go/helloworld                                            2                      f7cf3465432c        22 seconds ago       6.47MB | ||||
| go/helloworld                                            1                      f55d3e16affc        2 minutes ago        295MB | ||||
| ``` | ||||
|  | ||||
| 很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user