亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 服務器 > Web服務器 > 正文

編寫最佳的Dockerfile的方法

2024-09-01 13:51:59
字體:
來源:轉載
供稿:網友

Dockerfile的語法非常簡單,然而如何加快鏡像構建速度,如何減少Docker鏡像的大小卻不是那么直觀,需要積累實踐經驗。這篇博客可以幫助你快速掌握編寫Dockerfile的技巧。

為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用于學習。

我已經使用Docker有一段時間了,其中編寫Dockerfile是非常重要的一部分工作。在這篇博客中,我打算分享一些建議,幫助大家編寫更好的Dockerfile。

目標:

  1. 更快的構建速度
  2. 更小的Docker鏡像大小
  3. 更少的Docker鏡像層
  4. 充分利用鏡像緩存
  5. 增加Dockerfile可讀性
  6. 讓Docker容器使用起來更簡單

總結

  1. 編寫.dockerignore文件
  2. 容器只運行單個應用
  3. 將多個RUN指令合并為一個
  4. 基礎鏡像的標簽不要用latest
  5. 每個RUN指令后刪除多余文件
  6. 選擇合適的基礎鏡像(alpine版本最好)
  7. 設置WORKDIR和CMD
  8. 使用ENTRYPOINT (可選)
  9. 在entrypoint腳本中使用exec
  10. COPY與ADD優先使用前者
  11. 合理調整COPY與RUN的順序
  12. 設置默認的環境變量,映射端口和數據卷
  13. 使用LABEL設置鏡像元數據
  14. 添加HEALTHCHECK

示例

示例Dockerfile犯了幾乎所有的錯(當然我是故意的)。接下來,我會一步步優化它。假設我們需要使用Docker運行一個Node.js應用,下面就是它的Dockerfile(CMD指令太復雜了,所以我簡化了,它是錯誤的,僅供參考)。

FROM ubuntuADD . /appRUN apt-get update RUN apt-get upgrade -y RUN apt-get install -y nodejs ssh mysql RUN cd /app && npm install# this should start three processes, mysql and ssh# in the background and node app in foreground# isn't it beautifully terrible? <3CMD mysql & sshd & npm start 

構建鏡像:

docker build -t wtf .

1. 編寫.dockerignore文件

構建鏡像時,Docker需要先準備context ,將所有需要的文件收集到進程中。默認的context包含Dockerfile目錄中的所有文件,但是實際上,我們并不需要.git目錄,node_modules目錄等內容。 .dockerignore 的作用和語法類似于 .gitignore,可以忽略一些不需要的文件,這樣可以有效加快鏡像構建時間,同時減少Docker鏡像的大小。示例如下:

.git/node_modules/  

2. 容器只運行單個應用

從技術角度講,你可以在Docker容器中運行多個進程。你可以將數據庫,前端,后端,ssh,supervisor都運行在同一個Docker容器中。但是,這會讓你非常痛苦:

非常長的構建時間(修改前端之后,整個后端也需要重新構建)
非常大的鏡像大小
多個應用的日志難以處理(不能直接使用stdout,否則多個應用的日志會混合到一起)
橫向擴展時非常浪費資源(不同的應用需要運行的容器數并不相同)
僵尸進程問題 - 你需要選擇合適的init進程
因此,我建議大家為每個應用構建單獨的Docker鏡像,然后使用 Docker Compose 運行多個Docker容器。

現在,我從Dockerfile中刪除一些不需要的安裝包,另外,SSH可以用docker exec替代。示例如下:

FROM ubuntuADD . /appRUN apt-get update RUN apt-get upgrade -y# we should remove ssh and mysql, and use# separate container for database RUN apt-get install -y nodejs # ssh mysql RUN cd /app && npm installCMD npm start 

3. 將多個RUN指令合并為一個

Docker鏡像是分層的,下面這些知識點非常重要:

Dockerfile中的每個指令都會創建一個新的鏡像層。
鏡像層將被緩存和復用
當Dockerfile的指令修改了,復制的文件變化了,或者構建鏡像時指定的變量不同了,對應的鏡像層緩存就會失效
某一層的鏡像緩存失效之后,它之后的鏡像層緩存都會失效
鏡像層是不可變的,如果我們再某一層中添加一個文件,然后在下一層中刪除它,則鏡像中依然會包含該文件(只是這個文件在Docker容器中不可見了)。
Docker鏡像類似于洋蔥。它們都有很多層。為了修改內層,則需要將外面的層都刪掉。記住這一點的話,其他內容就很好理解了。

現在,我們將所有的RUN指令合并為一個。同時把apt-get upgrade刪除,因為它會使得鏡像構建非常不確定(我們只需要依賴基礎鏡像的更新就好了)

FROM ubuntuADD . /appRUN apt-get update /   && apt-get install -y nodejs /  && cd /app /  && npm installCMD npm start 

記住一點,我們只能將變化頻率一樣的指令合并在一起。將node.js安裝與npm模塊安裝放在一起的話,則每次修改源代碼,都需要重新安裝node.js,這顯然不合適。因此,正確的寫法是這樣的:

FROM ubuntuRUN apt-get update && apt-get install -y nodejs ADD . /app RUN cd /app && npm installCMD npm start 

4. 基礎鏡像的標簽不要用latest
當鏡像沒有指定標簽時,將默認使用latest 標簽。因此, FROM ubuntu 指令等同于FROM ubuntu:latest。當時,當鏡像更新時,latest標簽會指向不同的鏡像,這時構建鏡像有可能失敗。如果你的確需要使用最新版的基礎鏡像,可以使用latest標簽,否則的話,最好指定確定的鏡像標簽。

示例Dockerfile應該使用16.04作為標簽。

FROM ubuntu:16.04 # it's that easy!RUN apt-get update && apt-get install -y nodejs ADD . /app RUN cd /app && npm installCMD npm start 

5. 每個RUN指令后刪除多余文件
假設我們更新了apt-get源,下載,解壓并安裝了一些軟件包,它們都保存在/var/lib/apt/lists/目錄中。但是,運行應用時Docker鏡像中并不需要這些文件。我們最好將它們刪除,因為它會使Docker鏡像變大。

示例Dockerfile中,我們可以刪除/var/lib/apt/lists/目錄中的文件(它們是由apt-get update生成的)。

FROM ubuntu:16.04RUN apt-get update /   && apt-get install -y nodejs /  # added lines  && rm -rf /var/lib/apt/lists/*ADD . /app RUN cd /app && npm installCMD npm start 

6. 選擇合適的基礎鏡像(alpine版本最好)

在示例中,我們選擇了ubuntu作為基礎鏡像。但是我們只需要運行node程序,有必要使用一個通用的基礎鏡像嗎?node鏡像應該是更好的選擇。

FROM nodeADD . /app # we don't need to install node # anymore and use apt-getRUN cd /app && npm installCMD npm start 

更好的選擇是alpine版本的node鏡像。alpine是一個極小化的Linux發行版,只有4MB,這讓它非常適合作為基礎鏡像。

FROM node:7-alpineADD . /app RUN cd /app && npm installCMD npm start 

apk是Alpine的包管理工具。它與apt-get有些不同,但是非常容易上手。另外,它還有一些非常有用的特性,比如no-cache和 --virtual選項,它們都可以幫助我們減少鏡像的大小。

7. 設置WORKDIR和 CMD

WORKDIR指令可以設置默認目錄,也就是運行RUN / CMD / ENTRYPOINT指令的地方。

CMD指令可以設置容器創建是執行的默認命令。另外,你應該講命令寫在一個數組中,數組中每個元素為命令的每個單詞(參考官方文檔)。

FROM node:7-alpineWORKDIR /app ADD . /app RUN npm installCMD ["npm", "start"] 

8. 使用ENTRYPOINT (可選)

ENTRYPOINT指令并不是必須的,因為它會增加復雜度。ENTRYPOINT是一個腳本,它會默認執行,并且將指定的命令錯誤其參數。它通常用于構建可執行的Docker鏡像。entrypoint.sh如下:

#!/usr/bin/env sh# $0 is a script name, # $1, $2, $3 etc are passed arguments# $1 is our commandCMD=$1case "$CMD" in  "dev" )  npm install  export NODE_ENV=development  exec npm run dev  ;; "start" )  # we can modify files here, using ENV variables passed in   # "docker create" command. It can't be done during build process.  echo "db: $DATABASE_ADDRESS" >> /app/config.yml  export NODE_ENV=production  exec npm start  ;;  * )  # Run custom command. Thanks to this line we can still use   # "docker run our_image /bin/bash" and it will work  exec $CMD ${@:2}  ;;esac 

示例Dockerfile:

FROM node:7-alpineWORKDIR /app ADD . /app RUN npm installENTRYPOINT ["./entrypoint.sh"] CMD ["start"] 

可以使用如下命令運行該鏡像:

# 運行開發版本docker run our-app dev # 運行生產版本docker run our-app start # 運行bashdocker run -it our-app /bin/bash

9. 在entrypoint腳本中使用exec
在前文的entrypoint腳本中,我使用了exec命令運行node應用。不使用exec的話,我們則不能順利地關閉容器,因為SIGTERM信號會被bash腳本進程吞沒。exec命令啟動的進程可以取代腳本進程,因此所有的信號都會正常工作。

10. COPY與ADD優先使用前者
COPY指令非常簡單,僅用于將文件拷貝到鏡像中。ADD相對來講復雜一些,可以用于下載遠程文件以及解壓壓縮包(參考官方文檔)。

FROM node:7-alpineWORKDIR /appCOPY . /app RUN npm installENTRYPOINT ["./entrypoint.sh"] CMD ["start"] 

11. 合理調整COPY與RUN的順序
我們應該把變化最少的部分放在Dockerfile的前面,這樣可以充分利用鏡像緩存。

示例中,源代碼會經常變化,則每次構建鏡像時都需要重新安裝NPM模塊,這顯然不是我們希望看到的。因此我們可以先拷貝package.json,然后安裝NPM模塊,最后才拷貝其余的源代碼。這樣的話,即使源代碼變化,也不需要重新安裝NPM模塊。

FROM node:7-alpineWORKDIR /appCOPY package.json /app RUN npm install COPY . /appENTRYPOINT ["./entrypoint.sh"] CMD ["start"] 

12. 設置默認的環境變量,映射端口和數據卷

運行Docker容器時很可能需要一些環境變量。在Dockerfile設置默認的環境變量是一種很好的方式。另外,我們應該在Dockerfile中設置映射端口和數據卷。示例如下:

FROM node:7-alpineENV PROJECT_DIR=/appWORKDIR $PROJECT_DIRCOPY package.json $PROJECT_DIR RUN npm install COPY . $PROJECT_DIRENV MEDIA_DIR=/media /   NODE_ENV=production /  APP_PORT=3000VOLUME $MEDIA_DIR EXPOSE $APP_PORTENTRYPOINT ["./entrypoint.sh"] CMD ["start"] 

ENV指令指定的環境變量在容器中可以使用。如果你只是需要指定構建鏡像時的變量,你可以使用ARG指令。

13. 使用LABEL設置鏡像元數據
使用LABEL指令,可以為鏡像設置元數據,例如鏡像創建者或者鏡像說明。舊版的Dockerfile語法使用MAINTAINER指令指定鏡像創建者,但是它已經被棄用了。有時,一些外部程序需要用到鏡像的元數據,例如nvidia-docker需要用到com.nvidia.volumes.needed。示例如下:

FROM node:7-alpine LABEL maintainer "jakub.skalecki@example.com" ...

14. 添加HEALTHCHECK
運行容器時,可以指定--restart always選項。這樣的話,容器崩潰時,Docker守護進程(docker daemon)會重啟容器。對于需要長時間運行的容器,這個選項非常有用。但是,如果容器的確在運行,但是不可(陷入死循環,配置錯誤)用怎么辦?使用HEALTHCHECK指令可以讓Docker周期性的檢查容器的健康狀況。我們只需要指定一個命令,如果一切正常的話返回0,否則返回1。對HEALTHCHECK感興趣的話,可以參考這篇博客。示例如下:

FROM node:7-alpine LABEL maintainer "jakub.skalecki@example.com"ENV PROJECT_DIR=/app WORKDIR $PROJECT_DIRCOPY package.json $PROJECT_DIR RUN npm install COPY . $PROJECT_DIRENV MEDIA_DIR=/media /   NODE_ENV=production /  APP_PORT=3000VOLUME $MEDIA_DIR EXPOSE $APP_PORT HEALTHCHECK CMD curl --fail http://localhost:$APP_PORT || exit 1ENTRYPOINT ["./entrypoint.sh"] CMD ["start"] 

當請求失敗時,curl --fail 命令返回非0狀態。

原文: How to write excellent Dockerfiles

譯者: Fundebug


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品久久久久久久久久久不卡| 高清在线视频日韩欧美| 欧美一区二粉嫩精品国产一线天| 国产精品免费视频xxxx| 精品久久久一区二区| 色哟哟入口国产精品| 国产一区二区三区中文| 欧美野外猛男的大粗鳮| 久久人人爽人人爽人人片av高清| 成人国内精品久久久久一区| 国外色69视频在线观看| 中文字幕在线观看日韩| 国产精品永久在线| 92国产精品久久久久首页| 日韩亚洲成人av在线| 日本精品一区二区三区在线播放视频| 日韩一区在线视频| 国产精品久久久久久久av电影| 国产精品国语对白| 91在线国产电影| 日本一区二三区好的精华液| 亚洲精品国产福利| 91网站免费观看| 亚洲aaaaaa| 蜜臀久久99精品久久久久久宅男| 欧美成人高清视频| 综合欧美国产视频二区| 国自产精品手机在线观看视频| 亚洲免费精彩视频| 亚洲影院高清在线| 精品福利在线看| 亚洲国产欧美一区| 亚洲第一网站免费视频| 91av福利视频| 亚洲人成伊人成综合网久久久| 欧美日韩美女视频| 国产精品久久久久久久天堂| 国产精品日韩欧美大师| 亚洲最新视频在线| 欧美在线视频免费播放| 欧美国产日韩一区二区三区| 亚洲最新视频在线| 国产综合色香蕉精品| 精品日韩美女的视频高清| 亚洲欧美日韩精品久久| 色噜噜国产精品视频一区二区| 国产一区二区三区在线播放免费观看| 国产盗摄xxxx视频xxx69| 91久久嫩草影院一区二区| 欧美性少妇18aaaa视频| 久久男人av资源网站| 国产91在线播放| 国产精品夜间视频香蕉| 成人免费视频在线观看超级碰| 国产精品va在线| 色综合久久中文字幕综合网小说| 国产成人精品电影| 成人免费观看49www在线观看| 日韩在线免费av| 日韩欧美中文在线| 91精品国产高清自在线看超| 中文综合在线观看| 国产精品国产三级国产aⅴ浪潮| 欧美国产日本高清在线| 日韩中文字在线| 91精品国产色综合久久不卡98口| 按摩亚洲人久久| 亚洲国产精品视频在线观看| 亚洲精品国产成人| 中文字幕亚洲精品| 精品视频久久久| 色多多国产成人永久免费网站| 欧美激情视频播放| 亚洲综合最新在线| 国产一区二区在线免费视频| 国产成人精品免高潮费视频| 国产亚洲欧洲高清一区| 亚洲美女免费精品视频在线观看| 57pao国产精品一区| 在线观看日韩av| 久久91精品国产91久久久| 日韩在线观看视频免费| 亚洲午夜av久久乱码| 国产98色在线| 国产精品a久久久久久| 欧美精品做受xxx性少妇| 久久久国产一区二区三区| 欧美视频一区二区三区…| 国产成人在线视频| 97精品久久久中文字幕免费| 国产色综合天天综合网| 成人黄色短视频在线观看| 欧美一区二三区| 亚洲综合社区网| 亚洲欧美一区二区三区久久| 精品久久久久久久久久久| 国产精品小说在线| 国产69精品久久久久久| 精品毛片网大全| 欧美一级电影久久| 色777狠狠综合秋免鲁丝| 久久久精品视频在线观看| 少妇av一区二区三区| 91麻豆国产语对白在线观看| 色综合视频网站| 福利视频一区二区| 亚洲视频国产视频| 色综合久久久久久中文网| 亚洲精品久久久久久久久久久久久| 国内免费久久久久久久久久久| 久久97精品久久久久久久不卡| 欧美极品少妇xxxxⅹ裸体艺术| 亚洲色在线视频| 久久九九全国免费精品观看| 久久综合免费视频| 亚洲网址你懂得| 日韩人在线观看| 91久久精品视频| 精品国产拍在线观看| 国产成人一区二| 亚洲欧洲日本专区| 亚洲一区二区日本| 欧美影院久久久| 国产一级揄自揄精品视频| 成人午夜两性视频| 亚洲成人精品视频在线观看| 国产精品女主播| 国产mv久久久| 成人国产精品日本在线| 久久久亚洲国产天美传媒修理工| 亚洲国产精品网站| 国产拍精品一二三| 奇米影视亚洲狠狠色| 97精品在线观看| 91精品国产高清自在线看超| 超碰日本道色综合久久综合| 欧美另类极品videosbest最新版本| 亚洲国内精品视频| 欧美成人午夜激情视频| 日韩av不卡在线| 国产精品免费小视频| 亚洲自拍偷拍在线| 国产成人精品优优av| 中文字幕在线看视频国产欧美在线看完整| 亚洲精品成人免费| 亚洲成色777777在线观看影院| 欧美日产国产成人免费图片| www高清在线视频日韩欧美| 精品国产福利视频| 欧美在线欧美在线| 欧美电影院免费观看| 欧美精品成人91久久久久久久| 91网站在线免费观看| 精品五月天久久| 欧美激情女人20p| 久久精品国产69国产精品亚洲| 精品毛片三在线观看| 91精品国产精品| 九九热视频这里只有精品| 久久精品视频中文字幕| 国产成人精品视频| 国产精品久久久久久av福利| 欧美美最猛性xxxxxx| 日韩在线视频网站|