国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何編寫最佳的Dockerfile

Sike / 2354人閱讀

摘要:將安裝與模塊安裝放在一起的話,則每次修改源代碼,都需要重新安裝,這顯然不合適。使用設(shè)置鏡像元數(shù)據(jù)使用指令,可以為鏡像設(shè)置元數(shù)據(jù),例如鏡像創(chuàng)建者或者鏡像說明。自從年雙十一正式上線,累計(jì)處理了億錯(cuò)誤事件,付費(fèi)客戶有金山軟件百姓網(wǎng)等眾多品牌企業(yè)。

譯者按: Dockerfile 的語法非常簡單,然而如何加快鏡像構(gòu)建速度,如何減少 Docker 鏡像的大小卻不是那么直觀,需要積累實(shí)踐經(jīng)驗(yàn)。這篇博客可以幫助你快速掌握編寫 Dockerfile 的技巧。

原文: How to write excellent Dockerfiles

譯者: Fundebug

本文采用意譯,版權(quán)歸原作者所有

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

目標(biāo):

更快的構(gòu)建速度

更小的 Docker 鏡像大小

更少的 Docker 鏡像層

充分利用鏡像緩存

增加 Dockerfile 可讀性

讓 Docker 容器使用起來更簡單

總結(jié)

編寫.dockerignore 文件

容器只運(yùn)行單個(gè)應(yīng)用

將多個(gè) RUN 指令合并為一個(gè)

基礎(chǔ)鏡像的標(biāo)簽不要用 latest

每個(gè) RUN 指令后刪除多余文件

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

設(shè)置 WORKDIR 和 CMD

使用 ENTRYPOINT (可選)

在 entrypoint 腳本中使用 exec

COPY 與 ADD 優(yōu)先使用前者

合理調(diào)整 COPY 與 RUN 的順序

設(shè)置默認(rèn)的環(huán)境變量,映射端口和數(shù)據(jù)卷

使用 LABEL 設(shè)置鏡像元數(shù)據(jù)

添加 HEALTHCHECK

示例

示例 Dockerfile 犯了幾乎所有的錯(cuò)(當(dāng)然我是故意的)。接下來,我會(huì)一步步優(yōu)化它。假設(shè)我們需要使用 Docker 運(yùn)行一個(gè) Node.js 應(yīng)用,下面就是它的 Dockerfile(CMD 指令太復(fù)雜了,所以我簡化了,它是錯(cuò)誤的,僅供參考)。

FROM ubuntu

ADD . /app

RUN 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? <3
CMD mysql & sshd & npm start

構(gòu)建鏡像:

docker build -t wtf .
1. 編寫.dockerignore 文件

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

.git/
node_modules/
2. 容器只運(yùn)行單個(gè)應(yīng)用

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

非常長的構(gòu)建時(shí)間(修改前端之后,整個(gè)后端也需要重新構(gòu)建)

非常大的鏡像大小

多個(gè)應(yīng)用的日志難以處理(不能直接使用 stdout,否則多個(gè)應(yīng)用的日志會(huì)混合到一起)

橫向擴(kuò)展時(shí)非常浪費(fèi)資源(不同的應(yīng)用需要運(yùn)行的容器數(shù)并不相同)

僵尸進(jìn)程問題 - 你需要選擇合適的 init 進(jìn)程

因此,我建議大家為每個(gè)應(yīng)用構(gòu)建多帶帶的 Docker 鏡像,然后使用 Docker Compose 運(yùn)行多個(gè) Docker 容器。

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

FROM ubuntu

ADD . /app

RUN 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 install

CMD npm start
3. 將多個(gè) RUN 指令合并為一個(gè)

Docker 鏡像是分層的,下面這些知識(shí)點(diǎn)非常重要:

Dockerfile 中的每個(gè)指令都會(huì)創(chuàng)建一個(gè)新的鏡像層。

鏡像層將被緩存和復(fù)用

當(dāng) Dockerfile 的指令修改了,復(fù)制的文件變化了,或者構(gòu)建鏡像時(shí)指定的變量不同了,對(duì)應(yīng)的鏡像層緩存就會(huì)失效

某一層的鏡像緩存失效之后,它之后的鏡像層緩存都會(huì)失效

鏡像層是不可變的,如果我們?cè)倌骋粚又刑砑右粋€(gè)文件,然后在下一層中刪除它,則鏡像中依然會(huì)包含該文件(只是這個(gè)文件在 Docker 容器中不可見了)。

Docker 鏡像類似于洋蔥。它們都有很多層。為了修改內(nèi)層,則需要將外面的層都刪掉。記住這一點(diǎn)的話,其他內(nèi)容就很好理解了。

現(xiàn)在,我們將所有的RUN指令合并為一個(gè)。同時(shí)把apt-get upgrade刪除,因?yàn)樗鼤?huì)使得鏡像構(gòu)建非常不確定(我們只需要依賴基礎(chǔ)鏡像的更新就好了)

FROM ubuntu

ADD . /app

RUN apt-get update 
    && apt-get install -y nodejs 
    && cd /app 
    && npm install

CMD npm start

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

FROM ubuntu

RUN apt-get update && apt-get install -y nodejs
ADD . /app
RUN cd /app && npm install

CMD npm start
4. 基礎(chǔ)鏡像的標(biāo)簽不要用 latest

當(dāng)鏡像沒有指定標(biāo)簽時(shí),將默認(rèn)使用latest 標(biāo)簽。因此, FROM ubuntu 指令等同于FROM ubuntu:latest。當(dāng)時(shí),當(dāng)鏡像更新時(shí),latest 標(biāo)簽會(huì)指向不同的鏡像,這時(shí)構(gòu)建鏡像有可能失敗。如果你的確需要使用最新版的基礎(chǔ)鏡像,可以使用 latest 標(biāo)簽,否則的話,最好指定確定的鏡像標(biāo)簽。

示例 Dockerfile 應(yīng)該使用16.04作為標(biāo)簽。

FROM ubuntu:16.04  # it"s that easy!

RUN apt-get update && apt-get install -y nodejs
ADD . /app
RUN cd /app && npm install

CMD npm start
5. 每個(gè) RUN 指令后刪除多余文件

假設(shè)我們更新了 apt-get 源,下載,解壓并安裝了一些軟件包,它們都保存在/var/lib/apt/lists/目錄中。但是,運(yùn)行應(yīng)用時(shí) Docker 鏡像中并不需要這些文件。我們最好將它們刪除,因?yàn)樗鼤?huì)使 Docker 鏡像變大。

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

FROM ubuntu:16.04

RUN apt-get update 
    && apt-get install -y nodejs 
    # added lines
    && rm -rf /var/lib/apt/lists/*

ADD . /app
RUN cd /app && npm install

CMD npm start
6. 選擇合適的基礎(chǔ)鏡像(alpine 版本最好)

在示例中,我們選擇了ubuntu作為基礎(chǔ)鏡像。但是我們只需要運(yùn)行 node 程序,有必要使用一個(gè)通用的基礎(chǔ)鏡像嗎?node鏡像應(yīng)該是更好的選擇。

FROM node

ADD . /app
# we don"t need to install node
# anymore and use apt-get
RUN cd /app && npm install

CMD npm start

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

FROM node:7-alpine

ADD . /app
RUN cd /app && npm install

CMD npm start

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

7. 設(shè)置 WORKDIR 和 CMD

WORKDIR指令可以設(shè)置默認(rèn)目錄,也就是運(yùn)行RUN / CMD / ENTRYPOINT指令的地方。

CMD指令可以設(shè)置容器創(chuàng)建是執(zhí)行的默認(rèn)命令。另外,你應(yīng)該講命令寫在一個(gè)數(shù)組中,數(shù)組中每個(gè)元素為命令的每個(gè)單詞(參考官方文檔)。

FROM node:7-alpine

WORKDIR /app
ADD . /app
RUN npm install

CMD ["npm", "start"]
8. 使用 ENTRYPOINT (可選)

ENTRYPOINT指令并不是必須的,因?yàn)樗鼤?huì)增加復(fù)雜度。ENTRYPOINT是一個(gè)腳本,它會(huì)默認(rèn)執(zhí)行,并且將指定的命令錯(cuò)誤其參數(shù)。它通常用于構(gòu)建可執(zhí)行的 Docker 鏡像。entrypoint.sh 如下:

#!/usr/bin/env sh
# $0 is a script name,
# $1, $2, $3 etc are passed arguments
# $1 is our command
CMD=$1

case "$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-alpine

WORKDIR /app
ADD . /app
RUN npm install

ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]

可以使用如下命令運(yùn)行該鏡像:

# 運(yùn)行開發(fā)版本
docker run our-app dev

# 運(yùn)行生產(chǎn)版本
docker run our-app start

# 運(yùn)行bash
docker run -it our-app /bin/bash
9. 在 entrypoint 腳本中使用 exec

在前文的 entrypoint 腳本中,我使用了exec命令運(yùn)行 node 應(yīng)用。不使用exec的話,我們則不能順利地關(guān)閉容器,因?yàn)?SIGTERM 信號(hào)會(huì)被 bash 腳本進(jìn)程吞沒。exec命令啟動(dòng)的進(jìn)程可以取代腳本進(jìn)程,因此所有的信號(hào)都會(huì)正常工作。

10. COPY 與 ADD 優(yōu)先使用前者

COPY指令非常簡單,僅用于將文件拷貝到鏡像中。ADD相對(duì)來講復(fù)雜一些,可以用于下載遠(yuǎn)程文件以及解壓壓縮包(參考官方文檔)。

FROM node:7-alpine

WORKDIR /app

COPY . /app
RUN npm install

ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
11. 合理調(diào)整 COPY 與 RUN 的順序

我們應(yīng)該把變化最少的部分放在 Dockerfile 的前面,這樣可以充分利用鏡像緩存。

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

FROM node:7-alpine

WORKDIR /app

COPY package.json /app
RUN npm install
COPY . /app

ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
12. 設(shè)置默認(rèn)的環(huán)境變量,映射端口和數(shù)據(jù)卷

運(yùn)行 Docker 容器時(shí)很可能需要一些環(huán)境變量。在 Dockerfile 設(shè)置默認(rèn)的環(huán)境變量是一種很好的方式。另外,我們應(yīng)該在 Dockerfile 中設(shè)置映射端口和數(shù)據(jù)卷。示例如下:

FROM node:7-alpine

ENV PROJECT_DIR=/app

WORKDIR $PROJECT_DIR

COPY package.json $PROJECT_DIR
RUN npm install
COPY . $PROJECT_DIR

ENV MEDIA_DIR=/media 
    NODE_ENV=production 
    APP_PORT=3000

VOLUME $MEDIA_DIR
EXPOSE $APP_PORT

ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]

ENV指令指定的環(huán)境變量在容器中可以使用。如果你只是需要指定構(gòu)建鏡像時(shí)的變量,你可以使用ARG指令。

13. 使用 LABEL 設(shè)置鏡像元數(shù)據(jù)

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

FROM node:7-alpine
LABEL maintainer "jakub.skalecki@example.com"
...
14. 添加 HEALTHCHECK

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

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

ENV PROJECT_DIR=/app
WORKDIR $PROJECT_DIR

COPY package.json $PROJECT_DIR
RUN npm install
COPY . $PROJECT_DIR

ENV MEDIA_DIR=/media 
    NODE_ENV=production 
    APP_PORT=3000

VOLUME $MEDIA_DIR
EXPOSE $APP_PORT
HEALTHCHECK CMD curl --fail http://localhost:$APP_PORT || exit 1

ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]

當(dāng)請(qǐng)求失敗時(shí),curl --fail 命令返回非 0 狀態(tài)。

關(guān)于Fundebug

Fundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應(yīng)用實(shí)時(shí)BUG監(jiān)控。 自從2016年雙十一正式上線,F(xiàn)undebug累計(jì)處理了10億+錯(cuò)誤事件,付費(fèi)客戶有Google、360、金山軟件、百姓網(wǎng)等眾多品牌企業(yè)。歡迎大家免費(fèi)試用!

版權(quán)聲明

轉(zhuǎn)載時(shí)請(qǐng)注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/05/15/write-excellent-dockerfile/

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/26932.html

相關(guān)文章

  • Windows Containers 大冒險(xiǎn): 優(yōu)化計(jì)劃(Dockerfile)

    摘要:最終疊加在一起成為新的鏡像。優(yōu)化的方法就是使用和換行符將多條語句合并成一條執(zhí)行。第一點(diǎn),所有指令在中需要大寫,從而和具體的操作命令區(qū)分開來。第二點(diǎn),對(duì)于過長的指令請(qǐng)合理使用換行符,從而增加的可閱讀性。 前言 有一定旅行經(jīng)驗(yàn)的朋友都知道,即使在出發(fā)前制定了詳細(xì)的出行計(jì)劃,也會(huì)在路途中因?yàn)楦魇礁鳂拥臓顩r而不得不重新修改計(jì)劃。這個(gè)狀況在我們編寫Dockerfile時(shí)一樣存在。花了30分鐘編寫...

    Enlightenment 評(píng)論0 收藏0
  • docker-compose 運(yùn)行 Flask 應(yīng)用最佳實(shí)踐

    摘要:現(xiàn)在有了之后,部署方式變了更加容易,不容易出現(xiàn)配置錯(cuò)誤,環(huán)境不一致問題。實(shí)際應(yīng)用中,經(jīng)常遇到多個(gè)容器相配合運(yùn)行一套應(yīng)用程序的情況。所以想要將應(yīng)用運(yùn)行在容器中,該容器必須將該應(yīng)用所有的環(huán)境依賴安裝好。 showImg(https://segmentfault.com/img/remote/1460000017081815); 背景 ??以前部署應(yīng)用,需要各種環(huán)境配置,各種shell操作...

    fasss 評(píng)論0 收藏0
  • docker-compose 運(yùn)行 Flask 應(yīng)用最佳實(shí)踐

    摘要:現(xiàn)在有了之后,部署方式變了更加容易,不容易出現(xiàn)配置錯(cuò)誤,環(huán)境不一致問題。實(shí)際應(yīng)用中,經(jīng)常遇到多個(gè)容器相配合運(yùn)行一套應(yīng)用程序的情況。所以想要將應(yīng)用運(yùn)行在容器中,該容器必須將該應(yīng)用所有的環(huán)境依賴安裝好。 showImg(https://segmentfault.com/img/remote/1460000017081815); 背景 ??以前部署應(yīng)用,需要各種環(huán)境配置,各種shell操作...

    sumory 評(píng)論0 收藏0
  • Dockerfile 與 Compose 環(huán)境搭建學(xué)習(xí)筆記(一)

    摘要:的主要作用是自己根據(jù)基礎(chǔ)鏡像,重新定制鏡像,而不是直接從官方倉庫拿現(xiàn)成的使用。以接下來要構(gòu)建的環(huán)境來說明下,下面我將要搭建一個(gè)的開發(fā)環(huán)境,需要進(jìn)行配合。它的主要作用是持久化數(shù)據(jù),避免容器銷毀后內(nèi)部數(shù)據(jù)丟失暴露到宿主機(jī)的端口。 以前一直使用 Vagrant 作為自己的開發(fā)環(huán)境,并且在上家公司也推行大家采用 Vagrant 作為開發(fā)環(huán)境,保障公司使用的是同一套開發(fā)環(huán)境。隨著docker的流...

    TZLLOG 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<