dcokerfile 詳解

董雷發表於2021-11-25

dockerfile 詳細解釋

  • 本次內容是對上一篇文章的補充

部落格:docker製作自己的映象並上傳dockerhub

dockerfile 內容

FROM golang:alpine AS builder

LABEL stage=gobuilder

ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct

WORKDIR /build/zero

ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .
COPY service/hello/etc /app/etc
RUN go build -ldflags="-s -w" -o /app/hello service/hello/hello.go

FROM alpine

RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai

WORKDIR /app
COPY --from=builder /app/hello /app/hello
COPY --from=builder /app/etc /app/etc
CMD ["./hello", "-f", "etc/hello-api.yaml"]

dockerfile 詳解

#當我在/Users/myself/Golang/common_project/src/greet目錄下執行 docker build -t hello:v1 -f service/hello/Dockerfile . 命令
# -f service/hello/Dockerfile 代表的事dockerfile檔案的所在目錄,可以是任意目錄
# . 代表的是當前目錄的所有檔案,就是執行命令所在的目錄下的檔案,所以 greet目錄下 的所有檔案都會打包到  Docker引擎(服務端守護程式)
# 如果沒有 . ,那麼預設上下文路徑就是 Dockerfile 所在的位置。
#所以首先會把  greet目錄 打包到 守護程式,後面繼續執行以下程式碼


#FROM <image>
#FROM <image>:<tag>
#FROM <image>@<digest>
#tag或digest是可選的,如果不使用這兩個值時,會使用latest版本的基礎映象
#打包依賴階段使用golang:alpine作為基礎映象
FROM golang:alpine AS builder

#維護者資訊
MAINTAINER Dong Lei
MAINTAINER 2781897595@qq.com
MAINTAINER Dong Lei <2781897595@qq.com>

#LABEL:用於為映象新增後設資料
LABEL stage=gobuilder

#ENV:設定環境變數
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct

#WORKDIR:工作目錄,類似於cd命令,進入/build/zero這個目錄
WORKDIR /build/zero
#格式:
#    WORKDIR /path/to/workdir
#示例:
#    WORKDIR /a  (這時工作目錄為/a)
#    WORKDIR b  (這時工作目錄為/a/b)
#    WORKDIR c  (這時工作目錄為/a/b/c)
#注:
#  通過WORKDIR設定工作目錄後,Dockerfile中其後的命令RUNCMDENTRYPOINTADDCOPY等命令都會在該目錄下執行。在使用
#ADD:將本地檔案新增到容器中,tar型別檔案會自動解壓(網路壓縮資源不會被解壓),可以訪問網路資源,類似wget
# 因為複製的上下問目錄是 greet,所以  將專案目錄下的
# 把docekr守護程式下的 go.mod 拷貝到  /build/zero目錄下
ADD go.mod .
ADD go.sum .
RUN go mod download
#COPY:功能類似ADD,但是是不會自動解壓檔案,也不能訪問網路資源
# .是上下文路徑,是指 docker 在構建映象,有時候想要使用到本機的檔案(比如複製),docker build 命令得知這個路徑後,會將路徑下的所有內容打包。
#解析:由於 docker 的執行模式是 C/S。我們本機是 C,docker 引擎是 S。實際的構建過程是在 docker 引擎下完成的,所以這個時候無法用到我們本機的檔案。這就需要把我們本機的指定目錄下的檔案一起打包提供給 docker 引擎使用。
#如果未說明最後一個引數,那麼預設上下文路徑就是 Dockerfile 所在的位置。
#注意:上下文路徑下不要放無用的檔案,因為會一起打包傳送給 docker 引擎,如果檔案過多會造成過程緩慢
#COPY <源路徑>... <目標路徑>
#COPY <src>... <dest>
#dest: 指得是映象(image)中的路徑
#src: 指得是Dockerfile所在的context路徑
#那麼COPY的作用就是:將構建映象的電腦上的檔案或者資料夾拷貝到映象中去。
#我們知道,Dockerfile檔案往往是放在github上的某個工程裡,當我們checkout工程,然後執行 docker build 命令的時候,我們的電腦和作者的電腦肯定不一樣的,所以,明白了這一點,基於這樣最基本的常識,我們馬上就能明白什麼樣的src是正確的,什麼樣的src是錯誤的:

#正確:
#COPY ./package.json /app/
#COPY package.json /usr/src/app/
#錯誤:
#COPY ../package.json /app 因為上一層目錄大家都不一樣的
#或者 COPY /opt/xxxx /app 有可能連作業系統都不一樣,哪裡有什麼/opt這樣的目錄
#所以,Dockerfile中的COPY中的context(上下文)指得就是 Dockerfile 所在的工程中的目錄結構,離開了這個工程的其他目錄都是錯誤的。
#順便說一下:dest 是可以在映象中的任意位置的,這個無所謂,不用解釋大家都明白了吧。



#COPY 指令將從構建上下文目錄中 <源路徑> 的檔案/目錄複製到新的一層的映象內的 <目標路徑> 位置。
#對於 COPYADD 命令來說,如果要把本地的檔案拷貝到映象中,那麼本地的檔案必須是在上下文目錄中的檔案。其實這一點很好解釋,因為在執行 build 命令時,docker 客戶端會把上下文中的所有檔案傳送給 docker daemon。考慮 docker 客戶端和 docker daemon 不在同一臺機器上的情況,build 命令只能從上下文中獲取檔案。如果我們在 Dockerfile 的 COPYADD 命令中引用了上下文中沒有的檔案,就會收到類似下面的錯誤:
#. 便是當前目錄
# 如果在 Dockerfile 中這麼寫:
# COPY ./package.json /app/
# 這並不是要複製執行 docker build 命令所在的目錄下的 package.json,也不是複製 Dockerfile 所在目錄下的 package.json,而是複製 上下文(context) 目錄下的 package.json。
# 因此,COPY 這類指令中的原始檔的路徑都是相對路徑。這也是初學者經常會問的為什麼 COPY ../package.json /app 或者 COPY /opt/xxxx /app 無法工作的原因,因為這些路徑已經超出了上下文的範圍,Docker 引擎無法獲得這些位置的檔案。如果真的需要那些檔案,應該將它們複製到上下文目錄中去。
#理解構建上下文對於映象構建是很重要的,避免犯一些不應該的錯誤。比如有些初學者在發現 COPY /opt/xxxx /app 不工作後,於是乾脆將 Dockerfile 放到了硬碟根目錄去構建,結果發現 docker build執行後,在傳送一個幾十 GB 的東西,極為緩慢而且很容易構建失敗。那是因為這種做法是在讓 docker build 打包整個硬碟,這顯然是使用錯誤。


# 把docekr守護程式下的所有檔案 複製到 /build/zero 目錄下,相當於  zero 就是 greet一樣
COPY . .
#把service/hello/etc 這個資料夾 複製到 容器中 /app/etc
# 因為我是在greet 這個專案下執行的 打包命令  docker build -t hello:v1 -f service/hello/Dockerfile .
# 所以上下文就是 greet,相當於把 greet整個 拷貝到守護程式,所以
COPY service/hello/etc /app/etc
# 指定編譯完成後的檔名,可以不設定使用預設的,最後一步要執行該檔名,因為service/hello/hello.go裡面是mian函式編譯到 /app/hello
RUN go build -ldflags="-s -w" -o /app/hello service/hello/hello.go

#通過上面的copy和RUN go 使 /app/etc 和 /app/hello 兩個資料生成 ,/app/hello是編譯後的檔案,而不是資料夾

# 執行階段指定scratch作為基礎映象
FROM alpine

#RUN用於在映象容器中執行命令,其有以下兩種命令執行方式:
#RUN指令建立的中間映象會被快取,並會在下次構建中使用。如果不想使用這些快取映象,可以在構建時指定--no-cache引數,如:docker build --no-cache
RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai

# 進去app 目錄
WORKDIR /app
#COPY --from=builder將上一層映象複製制定目錄複製到當前工作目錄   上一階 通過COPYRUN go 生成的  /app/hello  複製到 /app/hello
COPY --from=builder /app/hello /app/hello
COPY --from=builder /app/etc /app/etc

# 執行結果如下
#/ # ls
#app    bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
#/ # cd app
#/app # ls
#etc    hello
#/app #

#CMD:構建容器後呼叫,也就是在容器啟動時才進行呼叫。
#CMD不同於RUNCMD用於指定在容器啟動時所要執行的命令,而RUN用於指定映象構建時所要執行的命令。
CMD ["./hello", "-f", "etc/hello-api.yaml"]

案例1

dockerfile 檔案

FROM golang:alpine AS builder

LABEL stage=gobuilder

ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct

WORKDIR /build/zero
# 把docekr守護程式下的 go.mod 拷貝到  /build/zero目錄下
ADD go.mod .

啟動容器

luwei@luweideMacBook-Pro-2 greet % docker build -t hello:v4 -f service/hello/Dockerfile .
[+] Building 81.4s (9/9) FINISHED                                                                                                                                                                         
 => [internal] load build definition from Dockerfile                                                                                                                                                 0.1s
 => => transferring dockerfile: 6.13kB                                                                                                                                                               0.0s
 => [internal] load .dockerignore                                                                                                                                                                    0.1s
 => => transferring context: 2B                                                                                                                                                                      0.0s
 => [internal] load metadata for docker.io/library/golang:alpine                                                                                                                                    80.4s
 => [auth] library/golang:pull token for registry-1.docker.io                                                                                                                                        0.0s
 => [internal] load build context                                                                                                                                                                    0.1s
 => => transferring context: 27B                                                                                                                                                                     0.0s
 => [1/3] FROM docker.io/library/golang:alpine@sha256:55da409cc0fe11df63a7d6962fbefd1321fedc305d9969da636876893e289e2d                                                                               0.0s
 => CACHED [2/3] WORKDIR /build/zero                                                                                                                                                                 0.0s
 => CACHED [3/3] ADD go.mod .                                                                                                                                                                        0.0s
 => exporting to image                                                                                                                                                                               0.1s
 => => exporting layers                                                                                                                                                                              0.0s
 => => writing image sha256:b1298754a175d735d9e8d767e025c0b4ccf8ee1f65b78bd6af8a091b4f36a1b5                                                                                                         0.0s
 => => naming to docker.io/library/hello:v4                                                                                                                                                          0.0s
luwei@luweideMacBook-Pro-2 greet % 

檢視

luwei@luweideMacBook-Pro-2 greet % docker images
REPOSITORY         TAG        IMAGE ID       CREATED         SIZE
hello              v4         b1298754a175   42 hours ago    315MB

啟動容器

可以看到 go.mod被複制到容器 /build/zero 中

luwei@luweideMacBook-Pro-2 greet % docker run -t -i hello:v4          
/build/zero # ls
go.mod
/build/zero # cd go.mod
/bin/sh: cd: can't cd to go.mod: Not a directory

檔案目錄

為什麼需要 ADD go.sum . 因為其實 go.sun 是在根目錄下並不是 g.mod 目錄下

dcokerfile 詳解

dcokerfile 詳解

案例2

dockerfile 檔案

FROM golang:alpine AS builder

LABEL stage=gobuilder

ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct

WORKDIR /build/zero
# 把docekr守護程式下的所有檔案 複製到 /build/zero 目錄下,相當於  zero 就是 greet一樣
COPY . .

打包映象

docker build -t hello:v4 -f service/hello/Dockerfile .

luwei@luweideMacBook-Pro-2 greet % docker build -t hello:v4 -f service/hello/Dockerfile .
[+] Building 88.6s (9/9) FINISHED                                                                                                                                                                         
 => [internal] load build definition from Dockerfile                                                                                                                                                 0.1s
 => => transferring dockerfile: 6.13kB                                                                                                                                                               0.0s
 => [internal] load .dockerignore                                                                                                                                                                    0.0s
 => => transferring context: 2B                                                                                                                                                                      0.0s
 => [internal] load metadata for docker.io/library/golang:alpine                                                                                                                                    83.7s
 => [auth] library/golang:pull token for registry-1.docker.io                                                                                                                                        0.0s
 => [1/3] FROM docker.io/library/golang:alpine@sha256:55da409cc0fe11df63a7d6962fbefd1321fedc305d9969da636876893e289e2d                                                                               0.0s
 => [internal] load build context                                                                                                                                                                    2.9s
 => => transferring context: 145.68MB                                                                                                                                                                2.8s
 => CACHED [2/3] WORKDIR /build/zero                                                                                                                                                                 0.0s
 => [3/3] COPY . .                                                                                                                                                                                   0.5s
 => exporting to image                                                                                                                                                                               1.0s
 => => exporting layers                                                                                                                                                                              1.0s
 => => writing image sha256:2a71b6880ec710842cd090ffbf44ece12ab49829981aec3a424739c1f208f224                                                                                                         0.0s
 => => naming to docker.io/library/hello:v4                                                                                                                                                          0.0s
luwei@luweideMacBook-Pro-2 greet % 

檢視內容

內容和greet 內容一樣的

/build/zero # ls
Dockerfile    README.en.md  README.md     default.etcd  go.mod        go.sum        service

案例3

dockerfile 檔案

FROM golang:alpine AS builder

LABEL stage=gobuilder

ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct

WORKDIR /build/zero

# 這三個可以不放,前提是你已經把擴充套件已經同步過去了
#ADD go.mod .
#ADD go.sum .
#RUN go mod download

COPY . .
COPY service/hello/etc /app/etc
RUN go build -ldflags="-s -w" -o /app/hello service/hello/hello.go

FROM alpine

RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai

WORKDIR /app
COPY --from=builder /app/hello /app/hello
COPY --from=builder /app/etc /app/etc
CMD ["./hello", "-f", "etc/hello-api.yaml"]

啟動容器並進去

luwei@luweideMacBook-Pro-2 greet % docker run -t -i hello:v5 /bin/sh                     
/app # 
/app # ls
etc    hello
/app # 

請求測試

luwei@luweideMacBook-Pro-2 ~ % curl -i http://localhost:8889/from/you
HTTP/1.1 200 OK
Content-Type: application/json
X-Trace-Id: efd07feabdbedf9e3dd51e2eb6ddcb1b
Date: Thu, 25 Nov 2021 04:13:09 GMT
Content-Length: 14

{"message":""}%
luwei@luweideMacBook-Pro-2 ~ %
本作品採用《CC 協議》,轉載必須註明作者和本文連結
good good study day day up