使用Dockerfile構(gòu)建Docker鏡像

目錄

  1. 前言
  2. Dockerfile的書寫規(guī)則及指令使用方法
  3. 創(chuàng)建Dockerfile请契,構(gòu)建運行環(huán)境
  4. 構(gòu)建鏡像
  5. Dockerfile參考示例
  6. Dockerfile最佳實踐

1. 前言

Dockfile是一種被Docker程序解釋的腳本睬捶,Dockerfile由一條一條的指令組成餐抢,每條指令對應Linux下面的一條命令美浦。Docker程序?qū)⑦@些Dockerfile指令翻譯真正的Linux命令失晴。Dockerfile有自己書寫格式和支持的命令臭杰,Docker程序解決這些命令間的依賴關系曹动,類似于Makefile。Docker程序?qū)⒆x取Dockerfile饰恕,根據(jù)指令生成定制的image挠羔。相比image這種黑盒子,Dockerfile這種顯而易見的腳本更容易被使用者接受埋嵌,它明確的表明image是怎么產(chǎn)生的破加。有了Dockerfile,當我們需要定制自己額外的需求時雹嗦,只需在Dockerfile上添加或者修改指令范舀,重新生成image即可,省去了敲命令的麻煩了罪。

2. Dockerfile的書寫規(guī)則及指令使用方法

Dockerfile的指令是忽略大小寫的锭环,建議使用大寫,使用#作為注釋泊藕,每一行只支持一條指令辅辩,每條指令可以攜帶多個參數(shù)。

Dockerfile的指令根據(jù)作用可以分為兩種娃圆,構(gòu)建指令和設置指令玫锋。構(gòu)建指令用于構(gòu)建image,其指定的操作不會在運行image的容器上執(zhí)行踊餐;設置指令用于設置image的屬性景醇,其指定的操作將在運行image的容器中執(zhí)行。

(1). FROM(指定基礎image)

構(gòu)建指令吝岭,必須指定且需要在Dockerfile其他指令的前面三痰。后續(xù)的指令都依賴于該指令指定的image吧寺。FROM指令指定的基礎image可以是官方遠程倉庫中的,也可以位于本地倉庫散劫。

該指令有兩種格式:

FROM <image>

指定基礎image為該image的最后修改的版本稚机。或者:

FROM <image>:<tag>

指定基礎image為該image的一個tag版本获搏。

(2). MAINTAINER(用來指定鏡像創(chuàng)建者信息)

構(gòu)建指令赖条,用于將image的制作者相關的信息寫入到image中。當我們對該image執(zhí)行docker inspect命令時常熙,輸出中有相應的字段記錄該信息纬乍。

指令格式:

MAINTAINER <name>

(3). RUN(安裝軟件用)

構(gòu)建指令,RUN可以運行任何被基礎image支持的命令裸卫。如基礎image選擇了ubuntu仿贬,那么軟件管理部分只能使用ubuntu的命令。

  • RUN命令將在當前image中執(zhí)行任意合法命令并提交執(zhí)行結(jié)果墓贿。命令執(zhí)行提交后茧泪,就會自動執(zhí)行Dockerfile中的下一個指令。
  • 層級 RUN 指令和生成提交是符合Docker核心理念的做法聋袋。它允許像版本控制那樣队伟,在任意一個點,對image 鏡像進行定制化構(gòu)建幽勒。
  • RUN 指令緩存不會在下個命令執(zhí)行時自動失效嗜侮。比如 RUN apt-get dist-upgrade -y 的緩存就可能被用于下一個指令. --no-cache 標志可以被用于強制取消緩存使用。

指令格式:

RUN <command> (the command is run in a shell - /bin/sh -c)
RUN ["executable", "param1", "param2" ... ] (exec form)

(4). CMD(設置container啟動時執(zhí)行的操作)

設置指令代嗤,用于container啟動時指定的操作棘钞。該操作可以是執(zhí)行自定義腳本缠借,也可以是執(zhí)行系統(tǒng)命令干毅。該指令只能在文件中存在一次,如果有多個泼返,則只執(zhí)行最后一條硝逢。

該指令有三種格式:

CMD ["executable","param1","param2"] (like an exec, this is the preferred form)
CMD command param1 param2 (as a shell)

當Dockerfile指定了ENTRYPOINT,那么使用下面的格式:

CMD ["param1","param2"] (as default parameters to ENTRYPOINT)

ENTRYPOINT指定的是一個可執(zhí)行的腳本或者程序的路徑绅喉,該指定的腳本或者程序?qū)詐aram1和param2作為參數(shù)執(zhí)行渠鸽。所以如果CMD指令使用上面的形式,那么Dockerfile中必須要有配套的ENTRYPOINT柴罐。

(5). ENTRYPOINT(設置container啟動時執(zhí)行的操作)

設置指令徽缚,指定容器啟動時執(zhí)行的命令,可以多次設置革屠,但是只有最后一個有效凿试。

兩種格式:

ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)
ENTRYPOINT command param1 param2 (as a shell)

該指令的使用分為兩種情況排宰,一種是獨自使用,另一種和CMD指令配合使用那婉。

當獨自使用時板甘,如果你還使用了CMD命令且CMD是一個完整的可執(zhí)行的命令,那么CMD指令和ENTRYPOINT會互相覆蓋只有最后一個CMD或者ENTRYPOINT有效详炬。

# CMD指令將不會被執(zhí)行盐类,只有ENTRYPOINT指令被執(zhí)行  
CMD echo “Hello, World!”  
ENTRYPOINT ls -l  

另一種用法和CMD指令配合使用來指定ENTRYPOINT的默認參數(shù),這時CMD指令不是一個完整的可執(zhí)行命令呛谜,僅僅是參數(shù)部分在跳;ENTRYPOINT指令只能使用JSON方式指定執(zhí)行命令,而不能指定參數(shù)隐岛。

FROM ubuntu  
CMD ["-l"]  
ENTRYPOINT ["/usr/bin/ls"]  

(6). USER(設置container容器的用戶)

設置指令硬毕,設置啟動容器的用戶,默認是root用戶礼仗。

# 指定memcached的運行用戶  
ENTRYPOINT ["memcached"]  
USER daemon  
或  
ENTRYPOINT ["memcached", "-u", "daemon"]  

(7). EXPOSE(指定容器需要映射到宿主機器的端口)

設置指令吐咳,該指令會將容器中的端口映射成宿主機器中的某個端口。當你需要訪問容器的時候元践,可以不是用容器的IP地址而是使用宿主機器的IP地址和映射后的端口韭脊。要完成整個操作需要兩個步驟,首先在Dockerfile使用EXPOSE設置需要映射的容器端口单旁,然后在運行容器的時候指定-p選項加上EXPOSE設置的端口沪羔,這樣EXPOSE設置的端口號會被隨機映射成宿主機器中的一個端口號。也可以指定需要映射到宿主機器的那個端口象浑,這時要確保宿主機器上的端口號沒有被使用蔫饰。EXPOSE指令可以一次設置多個端口號,相應的運行容器的時候愉豺,可以配套的多次使用-p選項篓吁。

指令格式:

EXPOSE <port> [<port>...]

# 映射一個端口  
EXPOSE port1  
# 相應的運行容器使用的命令  
docker run -p port1 image  
  
# 映射多個端口  
EXPOSE port1 port2 port3  
# 相應的運行容器使用的命令  
docker run -p port1 -p port2 -p port3 image  
# 還可以指定需要映射到宿主機器上的某個端口號  
docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image  

端口映射是docker比較重要的一個功能,原因在于我們每次運行容器的時候容器的IP地址不能指定而是在橋接網(wǎng)卡的地址范圍內(nèi)隨機生成的蚪拦。宿主機器的IP地址是固定的杖剪,我們可以將容器的端口的映射到宿主機器上的一個端口,免去每次訪問容器中的某個服務時都要查看容器的IP的地址驰贷。對于一個運行的容器盛嘿,可以使用docker port加上容器中需要映射的端口和容器的ID來查看該端口號在宿主機器上的映射端口。

(8). ENV(用于設置環(huán)境變量)

  • ENV指令可以用于為docker容器設置環(huán)境變量
  • ENV設置的環(huán)境變量括袒,可以使用docker inspect命令來查看次兆。同時還可以使用docker run --env <key>=<value>來修改環(huán)境變量。

格式:

ENV <key> <value>

設置了后锹锰,后續(xù)的RUN命令都可以使用芥炭,container啟動后狈邑,可以通過docker inspect查看這個環(huán)境變量,也可以通過在docker run --env key=value時設置或修改環(huán)境變量蚤认。

假如你安裝了JAVA程序米苹,需要設置JAVA_HOME,那么可以在Dockerfile中這樣寫:

ENV JAVA_HOME /path/to/java/dirent

(9). ADD(從src復制文件到container的dest路徑)

構(gòu)建指令砰琢,所有拷貝到container中的文件和文件夾權(quán)限為0755蘸嘶,uid和gid為0;如果是一個目錄陪汽,那么會將該目錄下的所有文件添加到container中训唱,不包括目錄;如果文件是可識別的壓縮格式挚冤,則docker會幫忙解壓縮(注意壓縮格式)况增;如果<src>是文件且<dest>中不使用斜杠結(jié)束,則會將<dest>視為文件训挡,<src>的內(nèi)容會寫入<dest>澳骤;如果<src>是文件且<dest>中使用斜杠結(jié)束,則會<src>文件拷貝到<dest>目錄下澜薄。

格式:

ADD <src> <dest>

  • <src> 是相對被構(gòu)建的源目錄的相對路徑为肮,可以是文件或目錄的路徑,也可以是一個遠程的文件url;
  • <dest> 是container中的絕對路徑

(10). VOLUME (指定掛載點)

創(chuàng)建一個可以從本地主機或其他容器掛載的掛載點肤京,一般用來存放數(shù)據(jù)庫和需要保持的數(shù)據(jù)等颊艳。

Volume設置指令,使容器中的一個目錄具有持久化存儲數(shù)據(jù)的功能忘分,該目錄可以被容器本身使用棋枕,也可以共享給其他容器使用。我們知道容器使用的是AUFS妒峦,這種文件系統(tǒng)不能持久化數(shù)據(jù)重斑,當容器關閉后,所有的更改都會丟失舟山。當容器中的應用有持久化數(shù)據(jù)的需求時可以在Dockerfile中使用該指令绸狐。

格式:

VOLUME ["<mountpoint>"]

例如:

FROM base  
VOLUME ["/tmp/data"] 

運行通過該Dockerfile生成image的容器卤恳,/tmp/data目錄中的數(shù)據(jù)在容器關閉后累盗,里面的數(shù)據(jù)還存在。例如另一個容器也有持久化數(shù)據(jù)的需求突琳,且想使用上面容器共享的/tmp/data目錄若债,那么可以運行下面的命令啟動一個容器:

docker run -t -i -rm -volumes-from container1 image2 bash 

說明:container1為第一個容器的ID,image2為第二個容器運行image的名字拆融。

(11). WORKDIR(切換目錄)

設置指令蠢琳,可以多次切換(相當于cd命令)啊终,對RUN,CMD,ENTRYPOINT生效。

格式:

WORKDIR /path/to/workdir

示例:

# 在 /p1/p2 下執(zhí)行 vim a.txt  
WORKDIR /p1 
WORKDIR p2 
RUN vim a.txt  

(12). ONBUILD(在子鏡像中執(zhí)行)

ONBUILD 指定的命令在構(gòu)建鏡像時并不執(zhí)行傲须,而是在它的子鏡像中執(zhí)行蓝牲。

格式:

ONBUILD <Dockerfile關鍵字>

(13). COPY(復制本地主機的src文件為container的dest)

復制本地主機的src文件(為Dockerfile所在目錄的相對路徑、文件或目錄 )到container的dest泰讽。目標路徑不存在時例衍,會自動創(chuàng)建。

格式:

COPY <src> <dest>

當使用本地目錄為源目錄時已卸,推薦使用COPY

(14). ARG(設置構(gòu)建鏡像時變量)

ARG指令在Docker1.9版本才加入的新指令佛玄,ARG 定義的變量只在建立 image 時有效,建立完成后變量就失效消失

格式:

ARG <key>=<value>

(15). LABEL(定義標簽)

定義一個 image 標簽 Owner累澡,并賦值梦抢,其值為變量 Name 的值。

格式:

LABEL Owner=$Name

3. 創(chuàng)建Dockerfile愧哟,構(gòu)建運行環(huán)境

Dockerfile文件

# 指定基于的基礎鏡像
FROM ubuntu:13.10  

# 維護者信息
MAINTAINER zhangjiayang "zhangjiayang@sczq.com.cn"  
  
# 鏡像的指令操作
# 獲取APT更新的資源列表
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe"> /etc/apt/sources.list
# 更新軟件
RUN apt-get update  
  
# Install curl  
RUN apt-get -y install curl  
  
# Install JDK 7  
RUN cd /tmp &&  curl -L 'http://download.oracle.com/otn-pub/java/jdk/7u65-b17/jdk-7u65-linux-x64.tar.gz' -H 'Cookie: oraclelicense=accept-securebackup-cookie; gpw_e24=Dockerfile' | tar -xz  
RUN mkdir -p /usr/lib/jvm  
RUN mv /tmp/jdk1.7.0_65/ /usr/lib/jvm/java-7-oracle/  
  
# Set Oracle JDK 7 as default Java  
RUN update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-7-oracle/bin/java 300     
RUN update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-7-oracle/bin/javac 300     

# 設置系統(tǒng)環(huán)境
ENV JAVA_HOME /usr/lib/jvm/java-7-oracle/  
  
# Install tomcat7  
RUN cd /tmp && curl -L 'http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.8/bin/apache-tomcat-7.0.8.tar.gz' | tar -xz  
RUN mv /tmp/apache-tomcat-7.0.8/ /opt/tomcat7/  
  
ENV CATALINA_HOME /opt/tomcat7  
ENV PATH $PATH:$CATALINA_HOME/bin  

# 復件tomcat7.sh到容器中的目錄 
ADD tomcat7.sh /etc/init.d/tomcat7  
RUN chmod 755 /etc/init.d/tomcat7  
  
# Expose ports.  指定暴露的端口
EXPOSE 8080  
  
# Define default command.  
ENTRYPOINT service tomcat7 start && tail -f /opt/tomcat7/logs/catalina.out

tomcat7.sh命令文件

export JAVA_HOME=/usr/lib/jvm/java-7-oracle/  
export TOMCAT_HOME=/opt/tomcat7  
  
case $1 in  
start)  
  sh $TOMCAT_HOME/bin/startup.sh  
;;  
stop)  
  sh $TOMCAT_HOME/bin/shutdown.sh  
;;  
restart)  
  sh $TOMCAT_HOME/bin/shutdown.sh  
  sh $TOMCAT_HOME/bin/startup.sh  
;;  
esac  
exit 0  

4. 構(gòu)建鏡像

根據(jù)配置完的dockerfile構(gòu)建Docker鏡像奥吩,并啟動docker容器。

docker build -t wechat-tomcat.  
docker run -d -p 8090:8080 wechat-tomcat 

默認情況下蕊梧,tomcat會占用8080端口圈驼,所以在啟動container的時候,指定了 -p 8090:8080望几,映射到宿主機端口就是8090绩脆。

5. Dockerfile參考示例

示例1:構(gòu)建Wordpress + nginx運行環(huán)境

# 指定基于的基礎鏡像
FROM ubuntu:14.04

# 維護者信息
MAINTAINER Eugene Ware <eugene@noblesamurai.com>

# Keep upstart from complaining
RUN dpkg-divert --local --rename --add /sbin/initctl
RUN ln -sf /bin/true /sbin/initctl

# Let the conatiner know that there is no tty
ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update
RUN apt-get -y upgrade

# Basic Requirements
RUN apt-get -y install mysql-server mysql-client nginx php5-fpm php5-mysql php-apc pwgen python-setuptools curl git unzip

# Wordpress Requirements
RUN apt-get -y install php5-curl php5-gd php5-intl php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-ming php5-ps php5-pspell php5-recode php5-sqlite php5-tidy php5-xmlrpc php5-xsl

# mysql config, 配置MySQL運行參數(shù)
RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf

# nginx config橄抹, 配置Nginx運行參數(shù)
RUN sed -i -e"s/keepalive_timeout\s*65/keepalive_timeout 2/" /etc/nginx/nginx.conf
RUN sed -i -e"s/keepalive_timeout 2/keepalive_timeout 2;\n\tclient_max_body_size 100m/" /etc/nginx/nginx.conf
RUN echo "daemon off;" >> /etc/nginx/nginx.conf

# php-fpm config
RUN sed -i -e "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g" /etc/php5/fpm/php.ini
RUN sed -i -e "s/upload_max_filesize\s*=\s*2M/upload_max_filesize = 100M/g" /etc/php5/fpm/php.ini
RUN sed -i -e "s/post_max_size\s*=\s*8M/post_max_size = 100M/g" /etc/php5/fpm/php.ini
RUN sed -i -e "s/;daemonize\s*=\s*yes/daemonize = no/g" /etc/php5/fpm/php-fpm.conf
RUN sed -i -e "s/;catch_workers_output\s*=\s*yes/catch_workers_output = yes/g" /etc/php5/fpm/pool.d/www.conf
RUN find /etc/php5/cli/conf.d/ -name "*.ini" -exec sed -i -re 's/^(\s*)#(.*)/\1;\2/g' {} \;

# nginx site conf靴迫,將本地Nginx配置文件復制到容器中的目錄
ADD ./nginx-site.conf /etc/nginx/sites-available/default

# Supervisor Config
RUN /usr/bin/easy_install supervisor
RUN /usr/bin/easy_install supervisor-stdout
ADD ./supervisord.conf /etc/supervisord.conf

# Install Wordpress
ADD https://wordpress.org/latest.tar.gz /usr/share/nginx/latest.tar.gz
RUN cd /usr/share/nginx/ && tar xvf latest.tar.gz && rm latest.tar.gz
RUN mv /usr/share/nginx/html/5* /usr/share/nginx/wordpress
RUN rm -rf /usr/share/nginx/www
RUN mv /usr/share/nginx/wordpress /usr/share/nginx/www
RUN chown -R www-data:www-data /usr/share/nginx/www

# Wordpress Initialization and Startup Script
ADD ./start.sh /start.sh
RUN chmod 755 /start.sh

# private expose
EXPOSE 3306
EXPOSE 80

# volume for mysql database and wordpress install
VOLUME ["/var/lib/mysql", "/usr/share/nginx/www"]

# 容器啟動時執(zhí)行命令
CMD ["/bin/bash", "/start.sh"]

示例2:構(gòu)建Ruby on Rails環(huán)境

# 指定基礎鏡像
FROM fcat/ubuntu-universe:12.04

# development tools
RUN apt-get -qy install git vim tmux

# ruby 1.9.3 and build dependencies
RUN apt-get -qy install ruby1.9.1 ruby1.9.1-dev build-essential libpq-dev libv8-dev libsqlite3-dev

# bundler
RUN gem install bundler

# create a "rails" user
# the Rails application will live in the /rails directory
RUN adduser --disabled-password --home=/rails --gecos "" rails

# copy the Rails app
# we assume we have cloned the "docrails" repository locally
#  and it is clean; see the "prepare" script
ADD docrails/guides/code/getting_started /rails

# Make sure we have rights on the rails folder
RUN chown rails -R /rails

# copy and execute the setup script
# this will run bundler, setup the database, etc.
ADD scripts/setup /setup
RUN su rails -c /setup

# copy the start script
ADD scripts/start /start

EXPOSE 3000

# 創(chuàng)建用戶
USER rails

# 設置容器啟動命令
CMD /start

示例3: 構(gòu)建Nginx運行環(huán)境

# 指定基礎鏡像
FROM sameersbn/ubuntu:14.04.20161014

# 維護者信息
MAINTAINER sameer@damagehead.com

# 設置環(huán)境
ENV RTMP_VERSION=1.1.10 \
    NPS_VERSION=1.11.33.4 \
    LIBAV_VERSION=11.8 \
    NGINX_VERSION=1.10.1 \
    NGINX_USER=www-data \
    NGINX_SITECONF_DIR=/etc/nginx/sites-enabled \
    NGINX_LOG_DIR=/var/log/nginx \
    NGINX_TEMP_DIR=/var/lib/nginx \
    NGINX_SETUP_DIR=/var/cache/nginx

# 設置構(gòu)建時變量,鏡像建立完成后就失效
ARG BUILD_LIBAV=false
ARG WITH_DEBUG=false
ARG WITH_PAGESPEED=true
ARG WITH_RTMP=true

# 復制本地文件到容器目錄中
COPY setup/ ${NGINX_SETUP_DIR}/
RUN bash ${NGINX_SETUP_DIR}/install.sh

# 復制本地配置文件到容器目錄中
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /sbin/entrypoint.sh

# 運行指令
RUN chmod 755 /sbin/entrypoint.sh

# 允許指定的端口
EXPOSE 80/tcp 443/tcp 1935/tcp

# 指定網(wǎng)站目錄掛載點
VOLUME ["${NGINX_SITECONF_DIR}"]

ENTRYPOINT ["/sbin/entrypoint.sh"]
CMD ["/usr/sbin/nginx"]

示例4:構(gòu)建Postgres鏡像

# 指定基礎鏡像
FROM sameersbn/ubuntu:14.04.20161014

# 維護者信息
MAINTAINER sameer@damagehead.com

# 設置環(huán)境變量
ENV PG_APP_HOME="/etc/docker-postgresql"\
    PG_VERSION=9.5 \
    PG_USER=postgres \
    PG_HOME=/var/lib/postgresql \
    PG_RUNDIR=/run/postgresql \
    PG_LOGDIR=/var/log/postgresql \
    PG_CERTDIR=/etc/postgresql/certs

ENV PG_BINDIR=/usr/lib/postgresql/${PG_VERSION}/bin \
    PG_DATADIR=${PG_HOME}/${PG_VERSION}/main

# 下載PostgreSQL
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
 && echo 'deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main' > /etc/apt/sources.list.d/pgdg.list \
 && apt-get update \
 && DEBIAN_FRONTEND=noninteractive apt-get install -y acl \
      postgresql-${PG_VERSION} postgresql-client-${PG_VERSION} postgresql-contrib-${PG_VERSION} \
 && ln -sf ${PG_DATADIR}/postgresql.conf /etc/postgresql/${PG_VERSION}/main/postgresql.conf \
 && ln -sf ${PG_DATADIR}/pg_hba.conf /etc/postgresql/${PG_VERSION}/main/pg_hba.conf \
 && ln -sf ${PG_DATADIR}/pg_ident.conf /etc/postgresql/${PG_VERSION}/main/pg_ident.conf \
 && rm -rf ${PG_HOME} \
 && rm -rf /var/lib/apt/lists/*

COPY runtime/ ${PG_APP_HOME}/
COPY entrypoint.sh /sbin/entrypoint.sh
RUN chmod 755 /sbin/entrypoint.sh

# 指定端口
EXPOSE 5432/tcp

# 指定數(shù)據(jù)掛載點
VOLUME ["${PG_HOME}", "${PG_RUNDIR}"]

# 切換目錄
WORKDIR ${PG_HOME}

# 設置容器啟動時執(zhí)行命令
ENTRYPOINT ["/sbin/entrypoint.sh"]

具體用例可以參考Github的Docker文件相應的示例楼誓。

6. Dockerfile最佳實踐

  • 使用.dockerignore文件

為了在docker build過程中更快上傳和更加高效玉锌,應該使用一個.dockerignore文件用來排除構(gòu)建鏡像時不需要的文件或目錄。例如,除非.git在構(gòu)建過程中需要用到疟羹,否則你應該將它添加到.dockerignore文件中主守,這樣可以節(jié)省很多時間。

  • 避免安裝不必要的軟件包

為了降低復雜性榄融、依賴性参淫、文件大小以及構(gòu)建時間,應該避免安裝額外的或不必要的包愧杯。例如涎才,不需要在一個數(shù)據(jù)庫鏡像中安裝一個文本編輯器。

  • 每個容器都跑一個進程

在大多數(shù)情況下力九,一個容器應該只單獨跑一個程序耍铜。解耦應用到多個容器使其更容易橫向擴展和重用邑闺。如果一個服務依賴另外一個服務,可以參考 Linking Containers Together棕兼。

  • 最小化層

我們知道每執(zhí)行一個指令陡舅,都會有一次鏡像的提交,鏡像是分層的結(jié)構(gòu)伴挚,對于 Dockerfile蹭沛,應該找到可讀性和最小化層之間的平衡。

  • 多行參數(shù)排序

如果可能章鲤,通過字母順序來排序摊灭,這樣可以避免安裝包的重復并且更容易更新列表,另外可讀性也會更強败徊,添加一個空行使用 \ 換行:

RUN apt-get update && apt-get install -y \
  bzr \
  cvs \
  git \
  mercurial \
  subversion
  • 創(chuàng)建緩存

鏡像構(gòu)建過程中會按照 Dockerfile 的順序依次執(zhí)行帚呼,每執(zhí)行一次指令 Docker 會尋找是否有存在的鏡像緩存可復用,如果沒有則創(chuàng)建新的鏡像皱蹦。如果不想使用緩存煤杀,則可以在docker build 時添加--no-cache=true選項。

從基礎鏡像開始就已經(jīng)在緩存中了沪哺,下一個指令會對比所有的子鏡像尋找是否執(zhí)行相同的指令沈自,如果沒有則緩存失效。在大多數(shù)情況下只對比 Dockerfile 指令和子鏡像就足夠了辜妓。ADD 和 COPY 指令除外枯途,執(zhí)行 ADD 和 COPY 時存放到鏡像的文件也是需要檢查的,完成一個文件的校驗之后再利用這個校驗在緩存中查找籍滴,如果檢測的文件改變則緩存失效酪夷。RUN apt-get -y update命令只檢查命令是否匹配,如果匹配就不會再執(zhí)行更新了孽惰。

為了有效地利用緩存晚岭,你需要保持你的Dockerfile一致,并且盡量在末尾修改勋功。

參考資料:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坦报,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子狂鞋,更是在濱河造成了極大的恐慌片择,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件要销,死亡現(xiàn)場離奇詭異构回,居然都是意外死亡,警方通過查閱死者的電腦和手機疏咐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門纤掸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浑塞,你說我怎么就攤上這事借跪。” “怎么了酌壕?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵掏愁,是天一觀的道長。 經(jīng)常有香客問我卵牍,道長果港,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任糊昙,我火速辦了婚禮辛掠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘释牺。我一直安慰自己萝衩,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布没咙。 她就那樣靜靜地躺著猩谊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祭刚。 梳的紋絲不亂的頭發(fā)上牌捷,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音涡驮,去河邊找鬼宜鸯。 笑死,一個胖子當著我的面吹牛遮怜,可吹牛的內(nèi)容都是我干的淋袖。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼锯梁,長吁一口氣:“原來是場噩夢啊……” “哼即碗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陌凳,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤剥懒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后合敦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體初橘,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了保檐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耕蝉。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖夜只,靈堂內(nèi)的尸體忽然破棺而出垒在,到底是詐尸還是另有隱情,我是刑警寧澤扔亥,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布场躯,位于F島的核電站,受9級特大地震影響旅挤,放射性物質(zhì)發(fā)生泄漏踢关。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一粘茄、第九天 我趴在偏房一處隱蔽的房頂上張望签舞。 院中可真熱鬧,春花似錦驹闰、人聲如沸瘪菌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽师妙。三九已至,卻和暖如春屹培,著一層夾襖步出監(jiān)牢的瞬間默穴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工褪秀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蓄诽,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓媒吗,卻偏偏與公主長得像仑氛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闸英,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載自 http://blog.opskumu.com/docker.html 一锯岖、Docker 簡介 Docke...
    極客圈閱讀 10,473評論 0 120
  • docker基本概念 1. Image Definition 鏡像 Image 就是一堆只讀層 read-only...
    慢清塵閱讀 8,725評論 1 21
  • Docker — 云時代的程序分發(fā)方式 要說最近一年云計算業(yè)界有什么大事件?Google Compute Engi...
    ahohoho閱讀 15,508評論 15 147
  • 0. 前言 docker是什么甫何?docker是用GO語言開發(fā)的應用容器引擎出吹,基于容器化,沙箱機制的應用部署技術(shù)辙喂〈防危可...
    sessionboy閱讀 3,838評論 2 49
  • 和朋友們分享關鍵詞的定向前鸠珠,先說說今天和朋友在討論關于SEO優(yōu)化的一些樂事吧。 朋友:“我肯定能讓百度收錄秋麸,我絕對...
    暮雨落花閱讀 1,357評論 3 3