Dockerfile多階段構建

多階段構建
之前的做法:
    在Docker17.05版本之前,構建Docker鏡像,通常採用兩種方式:
    1.全部放入一個Dockerfile
    一種方式是將所有的構建過程全都包含在一個Dockerfile中,包括項目及其依賴庫的編譯、測試、打包流程,這裏會帶來的一些問題:
        鏡像層次多,鏡像體積較大,部署時間變長
        源代碼存在泄漏的風險
        例如,編寫app.go文件,輸出Hello World!
		
package main
import "fmt"
func main(){
    fmt.Printf("Hello World!");
}

        編寫Dockerfile.one文件
		
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"]


        構建上面的鏡像
        docker build -t go/helloworld:1 -f Dockerfile.one .

        構建完之後查下 docker image ls
        輸出:
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
go/helloworld       1                   abdac4fc2d71        18 seconds ago      260MB

       啓動 docker run abdac4fc2d71 ,輸出 Hello World! ,說明沒問題。
	   
	2.第二種方式就是分散到多個Dockerfile 
        事先在一個Dockerfile將項目及其依賴庫編譯測試打包好後,再將其拷貝到運行環境中,這種方式需要編寫兩個Dockerfile和一些編譯腳本才能將其兩個階段自動整合起來,這種方式雖然可以很好的規避第一種方式存在的風險,但明顯部署過程複雜。
        例子:		
		

app.go文件
--------------------------
package main
import "fmt"
func main(){
    fmt.Printf("Hello World!");
}
		
		
Dockerfile.build 文件
--------------------------
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 文件
--------------------------
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY app .
CMD ["./app"]


build.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
54
/


然後執行build.sh 這個腳本
加個執行權限 chmod +x build.sh
./build.sh

PS:如果是windows環境下創建的build.sh這個文件的話,直接放到linux上會有問題,報錯會是說XXX文件路徑不存在,我的這個就是,最簡答的處理方法就是 用vim打開build.sh這個文件,然後執行:set fileformat=unix  然後再 wq 保存退出就行了。

看下鏡像 docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
go/helloworld       2                   411821efb026        4 minutes ago       7.97MB
go/helloworld       build               e43c3b88e2c2        4 minutes ago       258MB
go/helloworld       1                   abdac4fc2d71        2 hours ago         260MB
ubuntu              18.04               775349758637        4 weeks ago         64.2MB
alpine              latest              965ea09ff2eb        5 weeks ago         5.55MB
hello-world         latest              fce289e99eb9        11 months ago       1.84kB
golang              1.9-alpine          b0260be938c6        15 months ago       240MB

最上面的那個就是了,可以跑下試試:docker run 411821efb026 可以輸出Hello World!





上面就是兩種之前的創建鏡像的方式,接下來的筆記是關於 多階段構建的 Docker v17.05之後開始支持多階段構建(multistage builds)
    
	
Dockerfile 文件
FROM golang:1.9-alpine as builder
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 a
pp .
FROM alpine:latest as prod
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/go/helloworld/app .
CMD ["./app"]

開始構建 docker build -t go/helloworld:3 .
跑下試試:docker run 0186e09ebd69 可以跑出來Hello World!

對比下體積看看 docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
go/helloworld       3                   0186e09ebd69        36 seconds ago      7.97MB
go/helloworld       2                   411821efb026        55 minutes ago      7.97MB
go/helloworld       build               e43c3b88e2c2        55 minutes ago      258MB
go/helloworld       1                   abdac4fc2d71        3 hours ago         260MB

TAG爲3的這個鏡像非常小。


只構建某一階段的鏡像
使用  as  來爲某一階段命名,例如 FROM golang:1.9-alpine as builder
如當只想構建  builder  階段的鏡像時,增加  --target=builder  參數即可
docker build --target builder -t username/imagename:tag .

構建時從其他鏡像複製文件 使用  COPY --from=0
例子:
COPY --from=0 /go/src/github.com/go/helloworld/app .
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章