目錄
- 前言
- Dockerfile的書寫規(guī)則及指令使用方法
- 創(chuàng)建Dockerfile请契,構(gòu)建運行環(huán)境
- 構(gòu)建鏡像
- Dockerfile參考示例
- 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一致,并且盡量在末尾修改勋功。