精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

編寫Dockerfiles的優秀實踐

開發 前端
本文檔介紹了構建高效鏡像的優秀實踐和方法。Docker通過從Dockerfile(按順序包含構建給定鏡像所需的所有命令的文本文件)讀取命令來自動構建鏡像。Dockerfile遵循特定的格式和一組命令,您可以在Dockerfile reference中找到這些命令。

本文檔介紹了構建高效鏡像的優秀實踐和方法。

[[276943]]

Docker通過從Dockerfile(按順序包含構建給定鏡像所需的所有命令的文本文件)讀取命令來自動構建鏡像。Dockerfile遵循特定的格式和一組命令,您可以在Dockerfile reference中找到這些命令。

Docker鏡像由只讀層組成,每個只讀層表示Dockerfile指令。這些層被堆疊起來,每一層都是前一層變化的增量。考慮一下這個Dockerfile: 

  1. FROM ubuntu:18.04 
  2. COPY . /app 
  3. RUN make /app 
  4. CMD python /app/app.py 

每一個指令會創建一個層:

  • FROM從docker image ubuntu:18.04 創建層 。
  • COPY從Docker 客戶端添加文件到當前目錄。
  • RUN使用make 命令構建應用。
  • CMD指定在容器里運行的命令。

當您運行一個鏡像并生成一個容器時,您將在底層之上添加一個新的可寫層("容器層")。對正在運行的容器所做的所有更改,例如寫入新文件、修改現有文件和刪除文件,都被寫入這個可寫容器層。

通用概覽和建議

創建臨時容器

Dockerfile定義的鏡像應該生成盡可能"短暫"的容器。所謂"臨時性",是指容器可以停止和銷毀,然后用絕對最小的設置和配置重新構建和替換。

理解構建上下文

當您發出docker構建命令時,當前工作目錄稱為構建上下文。默認情況下, Dockerfile在當前目錄,但是您可以使用file標志(-f)指定一個不同的位置。無論Dockerfile實際位于何處,當前目錄中文件和目錄的所有遞歸內容都作為構建上下文發送到Docker守護進程。

構建上下文:

為構建上下文創建一個目錄并將cd放入其中。將"hello"寫入一個名為hello的文本文件中,并創建一個運行cat的Dockerfile。從構建上下文中構建鏡像(.): 

  1. mkdir myproject && cd myproject 
  2. echo "hello" > hello 
  3. echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > Dockerfile 
  4. docker build -t helloapp:v1 . 

將Dockerfile和hello移到單獨的目錄中,并構建鏡像的第二個版本(不依賴于上一個構建的緩存)。使用-f指向Dockerfile并指定構建上下文的目錄: 

  1. mkdir -p dockerfiles context 
  2. mv Dockerfile dockerfiles && mv hello context 
  3. docker build --no-cache -t helloapp:v2 -f dockerfiles/Dockerfile context 

無意中包含了構建鏡像所不需要的文件,會導致構建上下文和鏡像大小變大。這可以增加構建鏡像的時間、拖放鏡像的時間和容器運行時大小。要查看構建上下文的大小,請在構建Dockerfile時查看類似這樣的消息: 

  1. Sending build context to Docker daemon 187.8MB 

通過stdin使用Dockerfile 管道

Docker能夠通過使用本地或遠程構建上下文通過stdin管道傳輸Dockerfile來構建鏡像。通過stdin管道傳輸Dockerfile對于執行一次性構建非常有用,不需要將Dockerfile寫入磁盤,或者在生成Dockerfile的情況下,不應該在生成后保存Dockerfile。

為了方便起見,本節中的示例使用here文檔【http://tldp.org/LDP/abs/html/here-docs.html】,但是可以使用在stdin上提供Dockerfile的任何方法。

例如: 下面的命令是等價的: 

  1. echo -e 'FROM busybox\nRUN echo "hello world"' | docker build - 
  2. docker build -<<EOF 
  3. FROM busybox 
  4. RUN echo "hello world" 
  5. EOF 

您可以用您喜歡的方法或者最適合您用例的方法來替代這些例子。

使用STDIN中的DOCKERFILE構建鏡像,而不發送構建上下文

使用此語法可以從stdin中用Dockerfile構建映像,而不需要發送額外的文件作為構建上下文。連字符(-)占據路徑的位置,指示Docker從stdin而不是目錄中讀取構建上下文(其中只包含Dockerfile): 

  1. docker build [OPTIONS] – 

下面的示例使用通過stdin傳遞的Dockerfile構建一個鏡像。沒有文件作為構建上下文發送到守護進程。 

  1. docker build -t myimage:latest -<<EOF 
  2. FROM busybox 
  3. RUN echo "hello world" 
  4. EOF 

在Dockerfile不需要將文件復制到鏡像中的情況下,省略構建上下文是非常有用的,并且可以提高構建速度,因為沒有文件被發送到守護進程。

注意:如果使用這種語法,嘗試構建使用COPY或ADD的Dockerfile將會失敗。下面的例子說明了這一點: 

  1. create a directory to work in 
  2. mkdir example 
  3. cd example 
  4. create an example file 
  5. touch somefile.txt 
  6. docker build -t myimage:latest -<<EOF 
  7. FROM busybox 
  8. COPY somefile.txt . 
  9. RUN cat /somefile.txt 
  10. EOF 
  11. # observe that the build fails 
  12. ... 
  13. Step 2/3 : COPY somefile.txt . 
  14. COPY failed: stat /var/lib/docker/tmp/docker-builder249218248/somefile.txt: no such file or directory 

使用STDIN中的DOCKERFILE從本地構建上下文構建

使用此語法可以使用本地文件系統上的文件構建映像,但要使用stdin中的Dockerfile。語法使用(-f或--file)選項指定要使用的Dockerfile,使用連字符(-)作為文件名,指示Docker從stdin中讀取Dockerfile: 

  1. docker build [OPTIONS] -f- PATH 

下面這個例子我們用當前目錄作為構建上下文,并且構建鏡像用到的Dockerfile是通過stdin傳進去的。例子在這里【http://tldp.org/LDP/abs/html/here-docs.html】 

  1. create a directory to work in 
  2. mkdir example 
  3. cd example 
  4. create an example file 
  5. touch somefile.txt 
  6. # build an image using the current directory as context, and a Dockerfile passed through stdin 
  7. docker build -t myimage:latest -f- . <<EOF 
  8. FROM busybox 
  9. COPY somefile.txt . 
  10. RUN cat /somefile.txt 
  11. EOF 

使用STDIN中的DOCKERFILE從遠程構建上下文構建

使用此語法,使用來自遠程git存儲庫的文件(使用來自stdin的Dockerfile)構建一個鏡像。語法使用(-f或--file)選項指定要使用的Dockerfile,使用連字符(-)作為文件名,指示Docker從stdin中讀取Dockerfile: 

  1. docker build [OPTIONS] -f- PATH 

當您希望從不包含Dockerfile的存儲庫構建鏡像,或者希望使用自定義Dockerfile構建鏡像,而不需要維護存儲庫的分支時,這種語法非常有用。

下面的示例使用來自stdin的Dockerfile構建一個鏡像,并添加hello.c文件從git 倉里庫【https://github.com/docker-library/hello-world】 

  1. docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF 
  2. FROM busybox 
  3. COPY hello.c . 
  4. EOF 
  5. Note: 

當使用遠程Git存儲庫作為構建上下文構建鏡像時,Docker在本地 執行存儲庫的Git clone,并將這些文件作為構建上下文發送給守護進程。該特性要求git安裝在運行docker構建命令的主機上。

使用.dockerignore忽略不需要的文件

要排除與構建不相關的文件(不需要調整資源庫),請使用.dockerignore文件。該文件支持類似于.gitignore文件的排除模式。 更多信息請查看【https://docs.docker.com/engine/reference/builder/#dockerignore-file】

使用多級構建

多階段構建允許您大幅度減小最終映像的大小,而不必費力地減少中間層和文件的數量。

因為鏡像是在構建過程的最后階段構建的,所以可以通過利用構建緩存最小化鏡像層。【https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache】

例如,如果您的構建包含多個層,您可以將它們排序從更改頻率較低的層(以確保構建緩存可重用)到更改頻率較高的層:

  • 安裝構建應用程序所需的工具
  • 安裝或者更改依賴的庫
  • 生成應用

下面是一個構建golang應用的Dockerfile 文件: 

  1. FROM golang:1.11-alpine AS build 
  2. # Install tools required for project 
  3. # Run `docker build --no-cache .` to update dependencies 
  4. RUN apk add --no-cache git 
  5. RUN go get github.com/golang/dep/cmd/dep 
  6. # List project dependencies with Gopkg.toml and Gopkg.lock 
  7. # These layers are only re-built when Gopkg files are updated 
  8. COPY Gopkg.lock Gopkg.toml /go/src/project/ 
  9. WORKDIR /go/src/project/ 
  10. # Install library dependencies 
  11. RUN dep ensure -vendor-only 
  12. # Copy the entire project and build it 
  13. # This layer is rebuilt when a file changes in the project directory 
  14. COPY . /go/src/project/ 
  15. RUN go build -o /bin/project 
  16. # This results in a single layer image 
  17. FROM scratch 
  18. COPY --from=build /bin/project /bin/project 
  19. ENTRYPOINT ["/bin/project"
  20. CMD ["--help"

不安裝不必要的包

為了減少復雜、依賴、文件尺寸和構建時間,避免安裝額外的和不需要的包。一個高水準的Dockerfile必須要注意這些細節。

解耦

每個容器應該只有一個關注點。將應用程序解耦到多個容器可以更容易地水平伸縮和重用容器。例如,web應用程序棧可能由三個獨立的容器組成,每個容器都有自己獨特的鏡像,以解耦的方式管理web應用程序、數據庫和內存緩存。

限制每個容器只運行一個進程是一個很好的經驗法則。但是,這并不準確。因為很多應用都會有很多進程。比如,Celery就會有很多worker進程。Apache每個request就會有一個進程。容器自己也有init進程。

所以,用你的嚴謹和專業來保持容器盡可能的干凈和模塊化。如果容器彼此依賴,可以使用Docker容器網絡來確保這些容器能夠通信。

保存最小數量的層

在老一點的docker版本中,保持層數的最少是非常重要的,因為要保證性能。

為了減少這樣的限制,增加了一下的特性:

  • 只有指令RUN,COPY,ADD創建層。其他指令創建臨時中間鏡像,并且不增加構建的大小
  • 在可能的情況下,使用多階段構建,并且只將您需要的工件復制到最終鏡像中。這允許您在中間構建階段包含工具和調試信息,而不需要增加最終映像的大小。

命令行參數排序

只要方便,可以通過對多行參數進行字母數字排序來簡化后面的更改。這有助于避免包的重復,并使列表更容易更新。這也使得PRs更容易閱讀和審查。在反斜杠(\)之前添加空格也有幫助。

下面是一個參數排列的例子: 

  1. RUN apt-get update && apt-get install -y \ 
  2. bzr \ 
  3. cvs \ 
  4. git \ 
  5. mercurial \ 
  6. subversion 

利用構建緩存

在構建映像時,Docker逐步讀取 Dockerfile中的指令,并且按照順序執行。在檢查每條指令時,Docker會在緩存中查找可以重用的現有鏡像,而不是創建一個新的(重復的)鏡像。

如果,你就是不想用cache,可以使用—no-cache=true來關閉在執行docker build的時候。當然,如果你開啟了cacha,docker 在構建是找到緩存,如果沒有匹配到,就創建新的鏡像。 Docker遵循的基本規則如下:

  • 從緩存中已經存在的父鏡像開始,將下一條指令與從該基本鏡像派生的所有子鏡像進行比較,看看其中一條是否使用完全相同的指令構建。否則,緩存將無效
  • 在大多數情況下,只需將Dockerfile中的指令與其中一個子鏡像進行比較就足夠了。然而,某些指示需要更多的檢查和解釋。
  • 對于ADD和COPY指令,將檢查鏡像中文件的內容,并且檢查和校驗每個文件 。最后修改時間和最后訪問時間不會被校驗。在緩存查找期間,將校驗和與現有鏡像中的校驗和進行比較。如果文件中有任何更改,比如內容和元數據,那么緩存將無效。
  • 除了ADD和COPY命令外,緩存檢查不會查看容器中的文件來確定緩存匹配。例如,在處理RUN apt-get -y update命令時,不會檢查容器中更新的文件,以確定是否存在緩存命中。在這種情況下,僅使用命令字符串本身來查找匹配項。

一旦緩存失效,所有后續的Dockerfile命令都會生成新的鏡像,而緩存則不被使用。

Dockerfile 指令

這些建議旨在幫助您創建一個高效且可維護的Dockerfile。

FROM

只要可能,使用當前的官方鏡像作為你的鏡像的基礎鏡像。我們推薦Alpine鏡像【https://hub.docker.com/_/alpine/】,因為編寫這個鏡像是非常嚴格的,并且很小(目前小于5 MB),但仍然是一個完整的Linux發行版。

LABEL

您可以將標簽添加到鏡像中,以幫助按項目組織鏡像、記錄許可信息、幫助實現自動化或出于其他原因。對于每個標簽,用LABEL標記開始,用一個或者多個鍵值對 。下面的示例顯示了不同的可接受格式。解釋性注釋是內聯的。

必須引用帶空格的字符串,否則必須轉義空格。內部引號字符(")也必須轉義。

  1. Set one or more individual labels 
  2. LABEL com.example.version="0.0.1-beta" 
  3. LABEL vendor1="ACME Incorporated" 
  4. LABEL vendor2=ZENITH\ Incorporated 
  5. LABEL com.example.release-date="2015-02-12" 
  6. LABEL com.example.version.is-production="" 

一個鏡像可以有多個標簽。在Docker 1.10之前,建議將所有標簽合并到一個標簽指令中,以防止創建額外的層。這不再需要,但是仍然支持組合標簽。 

  1. Set multiple labels on one line 
  2. LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12" 

上面的這個例子還可以寫成下面這樣: 

  1. Set multiple labels at once, using line-continuation characters to break long lines 
  2. LABEL vendor=ACME\ Incorporated \ 
  3. com.example.is-beta= \ 
  4. com.example.is-production="" \ 
  5. com.example.version="0.0.1-beta" \ 
  6. com.example.release-date="2015-02-12" 
  7. RUN 

使用反斜杠(\) 來分隔獨立的命令行可以使RUN命令更有可讀性、易于維護。

APT-GET

Apt-get 命令是很多Docker經常使用的命令。因為,他是安裝各種包必須使用的命令。

避免運行apt-get升級和distl -upgrade,因為來自父鏡像的許多"基本"包無法在非特權容器中升級。如果父鏡像中包含的包過期了,請聯系它的維護人員。如果您知道有一個特定的包foo需要更新,那么使用apt-get install -y foo自動更新。

始終將RUN apt-get update與apt-get install組合在同一個RUN語句中。例如: 

  1. RUN apt-get update && apt-get install -y \ 
  2. package-bar \ 
  3. package-baz \ 
  4. package-foo 

在RUN語句中單獨使用apt-get update會導致緩存問題,隨后的apt-get安裝指令會失敗。例如,假設您有一個Dockerfile: 

  1. FROM ubuntu:18.04 
  2. RUN apt-get update 
  3. RUN apt-get install -y curl 

當構建完鏡像后,所有的層都已經被緩存了,假設之后你修改了apt-get install 增加了其他的包: 

  1. FROM ubuntu:18.04 
  2. RUN apt-get update 
  3. RUN apt-get install -y curl nginx 

Docker將初始指令和修改后的指令視為相同的,并重用前面步驟中的緩存。因此,apt-get更新不會執行,因為構建使用緩存的版本。由于apt-get更新沒有運行,您的構建可能會得到一個過時版本的curl和nginx包。

使用RUN apt-get update && apt-get install -y確保您的Dockerfile安裝最新的包版本,而無需進一步編碼或手動干預。這種技術稱為"緩存破壞"。還可以通過指定包版本來實現緩存崩潰。這就是所謂的版本固定,例如: 

  1. RUN apt-get update && apt-get install -y \ 
  2. package-bar \ 
  3. package-baz \ 
  4. package-foo=1.3.* 

版本固定強制構建以檢索特定版本,而不管緩存中的內容是什么。這種技術還可以減少由于所需包中的意外更改而導致的故障。

下面是一個格式良好的運行指令,演示了所有apt-get 的優秀實踐。 

  1. RUN apt-get update && apt-get install -y \ 
  2. aufs-tools \ 
  3. automake \ 
  4. build-essential \ 
  5. curl \ 
  6. dpkg-sig \ 
  7. libcap-dev \ 
  8. libsqlite3-dev \ 
  9. mercurial \ 
  10. reprepro \ 
  11. ruby1.9.1 \ 
  12. ruby1.9.1-dev \ 
  13. s3cmd=1.1.* \ 
  14. && rm -rf /var/lib/apt/lists/* 

s3cmd指定了一個新的版本。如果之前的鏡像安裝的是一個舊的版本。apt-get update 會導致緩存失效,從而安裝新的版本。

在這樣的條件下,當你清除apt緩存并且移除/var/lib/apt/lists 目錄,來減小文件尺寸。當RUN 聲明以apt-get update開始,在執行apt-get install的時候,緩存依然會被刷新。

注:

Debian和ubuntu的官方鏡像會自動運行apt-get clecn命令。所以不需要顯示調用。

使用管道

有些運行命令依賴于使用管道字符(|)將一個命令的輸出管道到另一個命令的能力,如下例所示: 

  1. RUN wget -O - https://some.site | wc -l > /number 

Docker使用/bin/sh -c解釋器執行這些命令,解釋器只計算管道中最后一個操作的退出代碼來確定是否成功。在上面的示例中,只要wc -l命令成功,即使wget命令失敗,這個構建步驟就會成功并生成一個新映像。

如果您希望命令在管道中的任何階段由于錯誤而失敗,請預先設置-o pipefail &&,以確保意外錯誤防止構建意外成功。例如: 

  1. RUN set -o pipefail && wget -O - https://some.site | wc -l > /number 

注:

不是所有的shell都支持 –o pipfail 選項

在基于debian的鏡像上使用dash shell的情況下,可以考慮使用exec形式的RUN顯式地選擇一個支持pipefail選項的shell。例如: 

  1. RUN ["/bin/bash""-c""set -o pipefail && wget -O - https://some.site | wc -l > /number"

CMD

CMD指令應該用于運行鏡像所包含的軟件,以及任何參數。CMD幾乎總是以CMD["executable"、"param1"、"param2"…]的形式使用。因此,如果鏡像是用于服務的,比如Apache和Rails,您將運行類似CMD ["apache2","-DFOREGROUND "]的東西。實際上,對于任何基于服務的鏡像,都推薦使用這種形式的指令。

在大多數其他情況下,應該為CMD提供一個交互式shell,如bash、python和perl。例如,CMD ["perl"、"-de0"], CMD ("python"),或CMD ("php","-a")。使用這種形式意味著,當您執行像docker run - python這樣的東西時,您將被放入一個可用的shell中,準備就緒。CMD應該很少與ENTRYPOINT一起以CMD ["param", "param"]的方式使用,除非您和您的預期用戶已經非常熟悉ENTRYPOINT的工作方式。

EXPOSE

EXPOSE指令指示容器監聽連接的端口。因此,您應該為您的應用程序使用公共的、傳統的端口。例如,包含Apache web服務器的鏡像使用 80端口,而包含MongoDB的映像將使用 27017 端口,以此類推。

對于外部訪問,用戶可以使用一個標志執行docker run,該標志指示如何將指定的端口映射到他們選擇的端口。對于容器鏈接,Docker為從接收容器返回到源容器的路徑提供了環境變量(即MYSQL_PORT_3306_TCP)。

ENV

為了使新軟件更容易運行,可以使用ENV更新容器安裝的軟件的PATH環境變量。例如,ENV PATH /usr/local/nginx/bin:$PATH確保CMD ["nginx"]正常工作。

ENV指令對于提供特定于您希望封裝的服務的所需環境變量也很有用,比如Postgres的PGDATA。

最后,ENV還可以用來設置常用的版本號,以便更容易維護版本,如下例所示: 

  1. ENV PG_MAJOR 9.3 
  2. ENV PG_VERSION 9.3.4 
  3. RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && … 
  4. ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH 

類似于在程序中使用常量變量(而不是硬編碼值),這種方法允許您更改單個ENV指令,從而自動地在容器中神奇地彈出軟件版本。

每個ENV行創建一個新的中間層,就像RUN命令一樣。這意味著,即使您在未來的層中取消了環境變量的設置,它仍然保留在這個層中,并且它的值可以被轉儲。您可以通過創建一個Dockerfile(如下所示)來測試它,然后構建它。 

  1. FROM alpine 
  2. ENV ADMIN_USER="mark" 
  3. RUN echo $ADMIN_USER > ./mark 
  4. RUN unset ADMIN_USER 
  5. $ docker run --rm test sh -c 'echo $ADMIN_USER' 
  6. mark 

為了防止這種情況發生,并真正取消對環境變量的設置,可以使用一個帶有shell命令的RUN命令,在一個單層中設置、使用和取消對變量的設置。你可以用;和& &。如果使用第二種方法,并且其中一個命令失敗,docker構建也會失敗。這通常是個好主意。使用\作為Linux Dockerfiles的行延續字符可以提高可讀性。您還可以將所有命令放入shell腳本中,并讓RUN命令運行該shell腳本。 

  1. FROM alpine 
  2. RUN export ADMIN_USER="mark" \ 
  3. && echo $ADMIN_USER > ./mark \ 
  4. && unset ADMIN_USER 
  5. CMD sh 
  6. docker run --rm test sh -c 'echo $ADMIN_USER' 

ADD 或者COPY

雖然ADD和COPY在功能上是相似的,但是一般來說,COPY是首選的。這是因為它比ADD更透明,COPY只支持將本地文件基本復制到容器中,而ADD的一些特性(比如只本地的tar提取和遠程URL支持)不是很有效。因此,ADD的最佳用途是將本地tar文件自動提取到映像中,如ADD rootfs.tar.xz / 。

如果有多個Dockerfile步驟使用與上下文不同的文件,請分別復制它們,而不是一次全部復制。這確保只有在特定需要的文件發生更改時,每個步驟的構建緩存才會失效(強制重新運行該步驟)。

例如: 

  1. COPY requirements.txt /tmp/ 
  2. RUN pip install --requirement /tmp/requirements.txt 
  3. COPY . /tmp/ 

將COPY . /tmp/放到RUN前面,會使緩存失效???

由于鏡像的大小很重要,因此強烈反對使用ADD從遠程url獲取包;您應該使用curl或wget來代替。這樣,你可以刪除你不再需要的文件后,他們已經被提取出來,你不需要添加另一層在您的鏡像。例如,你應該避免做以下事情: 

  1. ADD http://example.com/big.tar.xz /usr/src/things/ 
  2. RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things 
  3. RUN make -C /usr/src/things all 
  4. 我們用下面的命令取代: 
  5. RUN mkdir -p /usr/src/things \ 
  6. && curl -SL http://example.com/big.tar.xz \ 
  7. | tar -xJC /usr/src/things \ 
  8. && make -C /usr/src/things all 

如果不需要提取tar (文件、目錄)的話,應該始終使用COPY。

ENTRYPOINT

ENTRYPOINT的最佳用法是設置鏡像的主命令,允許像運行該命令一樣運行該鏡像(然后使用CMD作為默認標志)。

讓我們從命令行工具s3cmd的鏡像示例開始:

ENTRYPOINT ["s3cmd"]

CMD ["--help"]

現在,這個鏡像可以像這樣運行: 

  1. $ docker run s3cmd 

也可以傳參數執行: 

  1. $ docker run s3cmd ls s3://mybucket 

這很有用,因為鏡像的名字可以同時作為對二進制文件的引用,如上面的命令所示。

ENTRYPOINT指令也可以與helper腳本結合使用,允許它以類似于上面命令的方式運行,即使在啟動工具時可能需要不止一個步驟。

例如,Postgres官方鏡像使用以下腳本作為其入口點: 

  1. #!/bin/bash 
  2. set -e 
  3. if [ "$1" = 'postgres' ]; then 
  4. chown -R postgres "$PGDATA" 
  5. if [ -z "$(ls -A "$PGDATA")" ]; then 
  6. gosu postgres initdb 
  7. fi 
  8. exec gosu postgres "$@" 
  9. fi 
  10. exec "$@" 

注:

設置應用的PID為1,這樣,PG會結構linux的任何信號。

helper腳本被復制到容器中,并在容器開始時通過ENTRYPOINT運行: 

  1. COPY ./docker-entrypoint.sh / 
  2. ENTRYPOINT ["/docker-entrypoint.sh"
  3. CMD ["postgres"

這個腳本允許用戶以多種方式與Postgres交互。

它可以簡單地啟動Postgres: 

  1. $ docker run postgres 

或者,它可以用來運行Postgres并將參數傳遞給服務器: 

  1. $ docker run postgres postgres –help 

最后,它也可以用來啟動一個完全不同的工具,如Bash: 

  1. $ docker run --rm -it postgres bash 

VOLUME

卷指令應該用于公開由docker容器創建的任何數據庫存儲區域、配置存儲或文件/文件夾。強烈建議對鏡像的任何可變和或用戶可服務的部分使用VOLUME。

USER

如果服務可以在沒有特權的情況下運行,請使用USER將其更改為非root用戶。首先在Dockerfile中創建用戶和組,使用類似于RUN groupadd -r postgres && useradd——no-log-init -r -g postgres postgres的東西。

鏡像中的用戶和組被分配一個不確定的UID/GID,因為"下一個"UID/GID被分配,而不考慮鏡像的重建。因此,如果它是必須要使用的,您應該分配一個顯式的UID/GID。

由于Go archive/tar包在處理稀疏文件時存在一個未解決的bug,試圖在Docker容器中創建一個UID非常大的用戶可能會導致磁盤耗盡,因為容器層中的/var/log/faillog中填充了NULL(\0)字符。一個解決方案是將——no-log-init標志傳遞給useradd。Debian/Ubuntu adduser包裝器不支持這個標志。

避免安裝或使用sudo,因為它具有不可預知的TTY和信號轉發行為,可能會導致問題。如果您絕對需要類似于sudo的功能,比如將守護進程初始化為根進程,但以非根進程的形式運行它,那么可以考慮使用"gosu"。

最后,為了減少層次和復雜性,避免頻繁地來回切換用戶。

WORKER

為了清晰和可靠,您應該始終為您的WORKDIR使用絕對路徑。此外,您應該使用WORKDIR,而不是像RUN cd…&& do-something這樣的指令,這些指令很難閱讀、排除故障和維護。

ONBUILD

ONBUILD命令在當前Dockerfile構建完成后執行。ONBUILD在從當前鏡像派生的任何子鏡像中執行。將ONBUILD命令看作是父Dockerfile給子Dockerfile的一條指令。

Docker構建在子Dockerfile中的任何命令之前執行ONBUILD命令。

ONBUILD對于將從給定鏡像構建的鏡像非常有用。例如,您可以對一個語言堆棧鏡像使用ONBUILD,該鏡像可以在Dockerfile中構建用該語言編寫的任意用戶軟件,正如您可以在Ruby的ONBUILD變體中看到的那樣。

使用ONBUILD構建的鏡像應該有一個單獨的標記,例如:ruby:1.9-onbuild或ruby:2.0-onbuild。

在ONBUILD中添加或復制時要小心。如果新構建的上下文缺少正在添加的資源,則"onbuild"鏡像將災難性地失敗。如上面建議的那樣,添加一個單獨的標記,通過允許Dockerfile作者做出選擇,可以幫助緩解這種情況。

 

責任編輯:華軒 來源: 今日頭條
相關推薦

2023-07-04 15:56:08

DevOps開發測試

2020-06-01 09:40:06

開發ReactTypeScript

2022-08-19 09:01:59

ReactTS類型

2024-01-15 08:00:00

開發API文檔集成

2023-01-27 14:53:03

2021-12-04 23:10:02

Java代碼開發

2020-02-25 20:55:20

JavaScript開發 技巧

2023-04-14 08:10:59

asyncawait

2022-08-25 11:38:38

GolangDockerfile

2021-04-15 08:08:48

微前端Web開發

2019-11-27 10:55:36

云遷移云計算云平臺

2021-07-06 14:17:16

MLOps機器學習AI

2021-08-17 15:00:10

BEC攻擊網絡攻擊郵件安全

2020-03-09 14:10:48

代碼開發工具

2022-12-21 08:20:01

2023-06-29 00:19:51

2022-03-11 18:30:39

DevOps軟件開發

2019-05-07 09:00:40

無服務器Lambda管理

2020-11-25 10:26:24

云計算云安全數據

2021-01-20 10:53:41

云計算云存儲云遷移
點贊
收藏

51CTO技術棧公眾號

制服丝袜亚洲色图| 中文字幕va一区二区三区| 国产做受69高潮| 好吊一区二区三区视频| 日韩大尺度黄色| 18欧美亚洲精品| 国产91视觉| 夜夜躁日日躁狠狠久久av| 国产精品毛片一区二区在线看| 日韩欧美一区二区三区在线| 青娱乐自拍偷拍| 色欧美激情视频在线| 高清久久久久久| 国产91在线播放| 我家有个日本女人| 色婷婷狠狠五月综合天色拍 | 国产一区二区三区蝌蚪| 韩剧1988在线观看免费完整版| 免费观看a级片| 亚洲成人黄色| 欧美日韩亚洲综合| 午夜精品久久久久久久无码| 国产黄网站在线观看| av在线一区二区三区| 国产精品一区久久久| 精品成人久久久| 一本到12不卡视频在线dvd| 日韩毛片在线看| 中文字幕1区2区| 精品无人乱码一区二区三区| 亚洲h在线观看| 一区二区高清视频| 国内精品一区视频| 91亚洲男人天堂| 爱情岛论坛亚洲入口| 最近中文字幕免费在线观看| 99在线|亚洲一区二区| 久久午夜a级毛片| 极品人妻videosss人妻| 久久99精品国产自在现线| 日韩一区二区影院| 天天干天天操天天做| 欧美成人影院| 黑人精品xxx一区| 免费毛片网站在线观看| 怡红院在线播放| 亚洲日本在线a| 国产精品亚洲天堂| 久操视频在线观看| 亚洲视频一区在线| 宅男一区二区三区| 国产原创在线观看| 亚洲欧美日韩系列| www.国产亚洲| 国内小视频在线看| 亚洲综合免费观看高清完整版| 麻豆一区二区三区在线观看| 麻豆视频在线| 亚洲精品国产一区二区三区四区在线| 最新av在线免费观看| 免费黄色电影在线观看| 亚洲欧美成人一区二区三区| 在线观看18视频网站| 中中文字幕av在线| 亚洲国产精品久久人人爱蜜臀| 精品无码一区二区三区爱欲| 成人福利电影| 欧美丝袜一区二区| 欧美一级黄色影院| 欧美亚洲黄色| 欧美成人一区二区三区在线观看| 91视频免费入口| av日韩精品| 亚洲精品第一页| 醉酒壮男gay强迫野外xx| 国精一区二区| 在线观看亚洲视频| 一级二级黄色片| 日韩精品欧美激情一区二区| 亚洲第一区第二区| 国产精品三级在线观看无码| 自拍亚洲一区| 在线电影中文日韩| а天堂中文在线资源| 91精品在线观看国产| 欧美精品一二区| 国产在线综合网| 日韩精品高清不卡| 成人久久18免费网站图片| 国产又粗又猛又爽又黄的视频一| 精品一区二区三区视频| 91中文字幕一区| 狠狠躁夜夜躁av无码中文幕| 99在线热播精品免费| 欧美精品123| 91porn在线观看| 亚洲三级在线观看| 久久这里只有精品8| 日韩激情电影| 欧美色电影在线| 亚洲精品一二三四| 麻豆成人入口| 在线观看日韩欧美| 久久久久成人精品无码| 久久高清免费观看| 国产在线视频欧美| 亚洲人成色777777精品音频| 国产精品无圣光一区二区| 777久久精品一区二区三区无码 | 国产精一区二区| 欧美精品一区二区蜜臀亚洲| 中文字幕在线观看的网站| 欧美日韩精品一区二区视频| 欧美肥臀大乳一区二区免费视频| 欧美日韩综合在线观看| 奇米影视一区二区三区小说| 91中文字精品一区二区| 青青九九免费视频在线| 日韩毛片视频在线看| 国产精品国三级国产av| 自拍网站在线观看| 欧美一卡2卡3卡4卡| 喷水视频在线观看| 国产精品久久久久久久久久10秀| 久久久综合免费视频| 人妻中文字幕一区二区三区| 成人午夜视频在线观看| 亚洲一区二区自拍偷拍| 亚洲v.com| 亚洲国产欧美一区二区三区同亚洲| av男人的天堂av| 亚洲午夜电影| 成人免费观看网址| 国产福利片在线| 欧美日韩国产一区在线| 下面一进一出好爽视频| 日本一本不卡| 青青在线视频一区二区三区| 亚洲大尺度视频| 中文字幕一区二区日韩精品绯色| 91国视频在线| 成人春色在线观看免费网站| 久久亚洲精品视频| 一二三区中文字幕| 国产欧美日韩在线| 99色精品视频| 精品精品国产三级a∨在线| 久久视频在线免费观看| 亚洲精品一区二区二区| 久久久久久99精品| 亚洲午夜精品久久久久久人妖| 一区二区三区日本视频| 色黄久久久久久| 亚洲高清视频免费观看| 久久影院视频免费| 国产免费黄色一级片| 日韩中文字幕视频网| 精品国模在线视频| 中文字幕制服诱惑| 欧美激情一区二区三区全黄| 污污视频网站免费观看| 老司机在线精品视频| 2019亚洲男人天堂| 香蕉视频黄色片| 同产精品九九九| 菠萝菠萝蜜网站| 999亚洲国产精| 国产精品福利视频| 岛国av免费在线观看| 亚洲精品一区二区三区在线观看| 国产亚洲精品久久777777| 精品午夜一区二区三区在线观看| 亚洲一二三区在线| 国产精品一区二区三区四区在线观看| 久久久成人精品视频| a级片在线播放| 一区二区三区蜜桃| 日本一区二区免费视频| 亚洲欧洲一级| 免费一区二区三区| 台湾天天综合人成在线| 北条麻妃99精品青青久久| 国产又大又粗又硬| 亚洲免费视频成人| 亚洲无人区码一码二码三码| 亚洲永久字幕| 视频一区二区三区免费观看| 婷婷激情一区| 俺也去精品视频在线观看| wwwav在线播放| 午夜精品久久久久影视| 黑人巨大精品欧美| 捆绑调教美女网站视频一区| 成人毛片100部免费看| 久久亚州av| 国产精品视频1区| 丁香高清在线观看完整电影视频| 日韩不卡在线观看| 久草热在线观看| 一区二区三区四区亚洲| 成人网站免费观看| 久久国产尿小便嘘嘘| 青草视频在线观看视频| 伊人春色之综合网| 91色精品视频在线| 超碰在线免费公开| 精品视频—区二区三区免费| 中文字幕在线观看第二页| 一级特黄大欧美久久久| 欧美老熟妇乱大交xxxxx| 韩日av一区二区| 香港三级韩国三级日本三级| 久久最新网址| www.久久久| 一级二级黄色片| 亚洲www啪成人一区二区| 色吧影院999| 国产麻豆精品一区| 色素色在线综合| 欧美交换国产一区内射| 久久天堂av综合合色蜜桃网| 岛国毛片在线播放| 久久久久国产精品一区二区| 男人草女人视频| 精品视频免费| 国产一区二区自拍| 色综合久久久| 国产91在线视频| 国产精品专区免费| 欧美激情女人20p| 日本在线免费播放| 亚洲欧美中文日韩在线| 高潮毛片7777777毛片| 欧美精品日韩一区| 国产精品一区无码| 都市激情亚洲色图| 国产亚洲精品久久久久久无几年桃 | 亚洲一级二级片| 91麻豆精品在线观看| 国产精品igao网网址不卡| 日韩国产欧美在线视频| 国产又黄又大又粗视频| 午夜亚洲伦理| 99在线精品免费视频| 国产精品大片免费观看| 日本a级片在线观看| 91欧美在线| 视频一区视频二区视频三区视频四区国产 | 精品久久av| 亚洲精品中文字幕有码专区| 亚洲欧美国产高清va在线播放| 欧美一区二区三区不卡| 国产精品久久久久久久久久久久久久久久久久 | 麻豆成人av在线| 日韩手机在线观看视频| 久久精品女人| 天天色综合天天色| 蜜桃免费网站一区二区三区| 黄色一级二级三级| 日韩国产欧美三级| 美女喷白浆视频| 日韩av一区二区在线影视| 欧美日韩一区二区在线免费观看| 久久字幕精品一区| 青青青国产在线视频| 久久一区欧美| 天天爱天天操天天干| 日产国产欧美视频一区精品| 亚洲最大综合网| 久久av资源站| 国产又黄又猛的视频| 国产成人免费在线观看| 天天躁日日躁狠狠躁免费麻豆| 成人精品一区二区三区中文字幕| 动漫av在线免费观看| a亚洲天堂av| 亚洲AV无码国产成人久久| 久久久99久久| 久草手机视频在线观看| 亚洲激情图片一区| 日韩久久久久久久久| 精品女厕一区二区三区| 99re这里只有精品在线| 色偷偷88欧美精品久久久| 人妻中文字幕一区二区三区| 欧美亚洲一区二区三区四区| 亚洲精品久久久久久久蜜桃| 欧美乱妇15p| 亚洲女同志亚洲女同女播放| 日韩毛片在线观看| 蜜桃视频网站在线观看| 欧美激情国产精品| 日本精品裸体写真集在线观看| 成人黄色大片在线免费观看| 澳门成人av| 日韩高清三级| 中文字幕人成人乱码| 人人干视频在线| 美女高潮久久久| 免费看黄色片的网站| 国产色爱av资源综合区| 全网免费在线播放视频入口 | 国内自拍视频在线播放| 欧美性一级生活| 香蕉国产在线视频| 久久精品99无色码中文字幕| 国产色播av在线| 成人国产精品日本在线| 日韩精品免费一区二区三区竹菊| 欧美精品一区二区三区四区五区| 欧美精品播放| 亚洲国产精品三区| 91网站在线观看视频| 97精品在线播放| 色av成人天堂桃色av| 91精品在线视频观看| 亚洲日本欧美中文幕| 在线观看操人| 国产精品老牛影院在线观看| jizz18欧美18| 伊人精品久久久久7777| 亚洲在线电影| 午夜男人的天堂| 亚洲免费在线看| 中文字幕乱码一区二区| 精品亚洲国产成av人片传媒| jizzjizz亚洲| 国产精品草莓在线免费观看 | 蜜桃av免费看| 亚洲国产婷婷综合在线精品| 精品乱子伦一区二区| 日韩在线视频中文字幕| 成人va天堂| 精品亚洲欧美日韩| 国产一在线精品一区在线观看| 91色国产在线| 国产欧美va欧美不卡在线| 你懂的国产视频| 精品第一国产综合精品aⅴ| 顶级网黄在线播放| 国产美女扒开尿口久久久| 啪啪国产精品| 怡红院av亚洲一区二区三区h| 国产福利一区二区三区视频在线 | 一级片视频免费观看| 久久亚洲精品小早川怜子| 日韩免费不卡视频| 日韩欧美国产一二三区| 性欧美videoshd高清| 91久久久在线| 色综合色综合| 天天视频天天爽| 国产精品色婷婷久久58| 亚洲成人av影片| 中文日韩电影网站| 成人在线网站| 亚洲精品美女久久7777777| 日韩精品福利网| 综合 欧美 亚洲日本| 在线不卡a资源高清| 久久久久久久久免费视频| 成人网中文字幕| 国产精品99久久久久久动医院| 国产精品久久a| 国产精品久久久久久久久晋中 | 欧美猛男超大videosgay| av播放在线| 91视频国产一区| 欧美在线不卡| 精人妻一区二区三区| 亚洲成人免费电影| 亚洲欧洲国产综合| 国产精品99蜜臀久久不卡二区| 国产亚洲电影| 九九热99视频| 中文字幕一区二区三区蜜月| 亚洲av综合色区无码一区爱av| 色中色综合影院手机版在线观看| 91蝌蚪精品视频| 老太脱裤让老头玩ⅹxxxx| 26uuu精品一区二区在线观看| 国产一级做a爰片在线看免费| 亚洲男人天堂2019| av免费在线一区| 香蕉视频在线网址| 成人免费福利片| 91porny九色| 欧美激情免费在线| 国产成人精品999在线观看| 在线观看岛国av| 亚洲福利视频一区| 国产系列在线观看| 成人在线激情视频| 在线日韩电影| 波多野结衣福利| 欧美成人一区二区三区片免费| 三级在线观看视频| 天堂v在线视频| 26uuu精品一区二区| 中国女人一级一次看片|