一丘逸、Dockerfile簡介
Dockerfile 是一個文本文件,其內(nèi)包含了一條條的 指令(Instruction)花墩,每一條指令構(gòu)建一層复斥,因此每一條指令的內(nèi)容营密,就是描述該層應(yīng)當(dāng)如何構(gòu)建。
Dockerfile分為四部分:
- FROM:基礎(chǔ)鏡像信息
- MAINTAINER:維護(hù)者信息
- RUN目锭、COPY评汰、ADD、EXPOSE等:鏡像操作指令
- CMD痢虹、ENTRYPOINT:容器啟動時執(zhí)行指令被去。
例如:
FROM python:3.6
MAINTAINER cbbing <cbbing@163.com>
COPY pip.conf requirements.txt /root/.pip/
#設(shè)置時區(qū)
ENV TZ=Asia/Shanghai
ENV PYTHONPATH=/usr/src/app
RUN mkdir -p /usr/src/app \
&& pip install -r /root/.pip/requirements.txt \
&& apt-get update \
&& apt-get install -y supervisor \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
WORKDIR /usr/src/app
CMD ["python"]
Dockerfile指令
指令的一般格式為 INSTRUCTION arguments,指令包括 FROM奖唯、MAINTAINER惨缆、RUN 等。
1. FROM
格式為 FROM <image>或FROM <image>:<tag>丰捷。
第一條指令必須為 FROM 指令坯墨。并且,如果在同一個Dockerfile中創(chuàng)建多個鏡像時瓢阴,可以使用多個 FROM 指令(每個鏡像一次)畅蹂。
2. MAINTAINER
格式為 MAINTAINER <name>健无,指定維護(hù)者信息荣恐。
3. RUN
格式為 RUN <command> 或 RUN ["executable", "param1", "param2"]。
前者將在 shell 終端中運(yùn)行命令累贤,即 /bin/sh -c叠穆;后者則使用 exec 執(zhí)行。指定使用其它終端可以通過第二種方式實(shí)現(xiàn)臼膏,例如 RUN ["/bin/bash", "-c", "echo hello"]硼被。
每條 RUN 指令將在當(dāng)前鏡像基礎(chǔ)上執(zhí)行指定命令,并提交為新的鏡像渗磅。當(dāng)命令較長時可以使用 \ 來換行嚷硫。
4. CMD
支持三種格式
CMD ["executable","param1","param2"] 使用 exec 執(zhí)行检访,推薦方式;
CMD command param1 param2 在 /bin/sh 中執(zhí)行仔掸,提供給需要交互的應(yīng)用脆贵;
CMD ["param1","param2"] 提供給 ENTRYPOINT 的默認(rèn)參數(shù);
指定啟動容器時執(zhí)行的命令起暮,每個 Dockerfile 只能有一條 CMD 命令卖氨。如果指定了多條命令,只有最后一條會被執(zhí)行负懦。
如果用戶啟動容器時候指定了運(yùn)行的命令筒捺,則會覆蓋掉 CMD 指定的命令。
5. EXPOSE
格式為 EXPOSE <port> [<port>...]纸厉。
告訴 Docker 服務(wù)端容器暴露的端口號系吭,供互聯(lián)系統(tǒng)使用。在啟動容器時需要通過 -P残腌,Docker 主機(jī)會自動分配一個端口轉(zhuǎn)發(fā)到指定的端口村斟。
6. ENV
格式為 ENV <key> <value>。 指定一個環(huán)境變量抛猫,會被后續(xù) RUN 指令使用蟆盹,并在容器運(yùn)行時保持。
例如
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
ENV TZ=Asia/Shanghai
ENV PYTHONPATH=/usr/src/app
7. ADD
格式為 ADD <src> <dest>闺金。
該命令將復(fù)制指定的 <src> 到容器中的 <dest>逾滥。 其中 <src> 可以是Dockerfile所在目錄的一個相對路徑;也可以是一個 URL败匹;還可以是一個 tar 文件(自動解壓為目錄)寨昙。
8. COPY
格式為 COPY <src> <dest>。
復(fù)制本地主機(jī)的 <src>(為 Dockerfile 所在目錄的相對路徑)到容器中的 <dest>掀亩。
當(dāng)使用本地目錄為源目錄時舔哪,推薦使用 COPY。
9. ENTRYPOINT
兩種格式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2(shell中執(zhí)行)槽棍。
配置容器啟動后執(zhí)行的命令捉蚤,并且不可被 docker run 提供的參數(shù)覆蓋。
每個 Dockerfile 中只能有一個 ENTRYPOINT炼七,當(dāng)指定多個時缆巧,只有最后一個起效。
10. VOLUME
格式為 VOLUME ["/data"]豌拙。
創(chuàng)建一個可以從本地主機(jī)或其他容器掛載的掛載點(diǎn)陕悬,一般用來存放數(shù)據(jù)庫和需要保持的數(shù)據(jù)等。
11. USER
格式為 USER daemon按傅。
指定運(yùn)行容器時的用戶名或 UID捉超,后續(xù)的 RUN 也會使用指定用戶胧卤。
當(dāng)服務(wù)不需要管理員權(quán)限時,可以通過該命令指定運(yùn)行用戶拼岳。并且可以在之前創(chuàng)建所需要的用戶灌侣,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres。要臨時獲取管理員權(quán)限可以使用 gosu裂问,而不推薦 sudo侧啼。
12. WORKDIR
格式為 WORKDIR /path/to/workdir。
為后續(xù)的 RUN堪簿、CMD痊乾、ENTRYPOINT 指令配置工作目錄。
可以使用多個 WORKDIR 指令椭更,后續(xù)命令如果參數(shù)是相對路徑哪审,則會基于之前命令指定的路徑。例如
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
則最終路徑為 /a/b/c虑瀑。
13. ONBUILD
格式為 ONBUILD [INSTRUCTION]湿滓。
配置當(dāng)所創(chuàng)建的鏡像作為其它新創(chuàng)建鏡像的基礎(chǔ)鏡像時,所執(zhí)行的操作指令舌狗。
ONBUILD指令,實(shí)際上就是相當(dāng)于創(chuàng)建一個模板鏡像叽奥,后續(xù)可以根據(jù)該模板鏡像創(chuàng)建特定的子鏡像
例如,Dockerfile 使用如下的內(nèi)容創(chuàng)建了鏡像 image-A痛侍。
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
image-A的構(gòu)建過程中不執(zhí)行這兩條命令朝氓,但在FROM image-A的子鏡像中會執(zhí)行這兩條命令。
二主届、構(gòu)建鏡像
docker build -t mynginx:v2019 .
注意不要少了最后面的“.”
三赵哲、Dockerfile編寫建議
- 通過 Docker 多階段構(gòu)建將多個層壓縮為一個
在構(gòu)建 Docker 容器時,應(yīng)該盡量想辦法獲得體積更小的鏡像君丁,因?yàn)閭鬏敽筒渴痼w積較小的鏡像速度更快枫夺。
從 Docker 1.10 開始,COPY绘闷、ADD 和 RUN 語句會向鏡像中添加新層橡庞。層會占用空間,你擁有的層越多簸喂,最終的鏡像就越大毙死。Git 存儲庫在這方面也是類似的燎潮,存儲庫的大小隨著層數(shù)的增加而增加喻鳄,因?yàn)?Git 必須保存提交之間的所有變更。 - 將不經(jīng)常改動的命令确封,比如python的reqirements.txt 依賴包除呵,單獨(dú)拎出來放在項(xiàng)目代碼的前面再菊。因?yàn)橐蕾嚢唤?jīng)常變動,每次生成鏡像時颜曾,只需將后面的項(xiàng)目代碼copy到鏡像即可纠拔。
# 方案一:
FROM python:3.6
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN pip install -r /usr/src/app/requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
CMD python /usr/src/app/manage.py runserver 0.0.0.0:8000
# 方案二:
FROM python:3.6
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/
RUN pip install -r /usr/src/app/requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
COPY . /usr/src/app
CMD python /usr/src/app/manage.py runserver 0.0.0.0:8000
方案二比方案一好,為什么泛豪?因?yàn)榉桨敢恢械膔equirements.txt實(shí)際項(xiàng)目中是很少變動稠诲,但是因?yàn)?usr/src/app的項(xiàng)目代碼是經(jīng)常變動,導(dǎo)致每次打包都得根據(jù)equirements.txt安裝依賴包诡曙。而方案二先把requirements.txt 拷貝進(jìn)來臀叙,如果requirements.txt 沒改動,docker會用到之前緩存的价卤,加快打包速度劝萤。
實(shí)際運(yùn)行幾次打包過程,會發(fā)現(xiàn)速度的差異是比較明顯的慎璧。
四床嫌、實(shí)踐
公司現(xiàn)在的所有項(xiàng)目均以容器封裝,幾十個容器運(yùn)行在十來臺主機(jī)中胸私,現(xiàn)在正在將服務(wù)器整合到kubernetes集群中厌处,可以說一切皆容器,一切皆Docker岁疼。
1. Django項(xiàng)目的Dockerfile
Django項(xiàng)目打包成Docker鏡像是比較簡單嘱蛋,主要是安裝python依賴包,然后就是manage.py啟動服務(wù)五续。
Dockerfile 位于Django項(xiàng)目的根目錄洒敏,目錄結(jié)構(gòu)如下:
├── requirements.txt
├── Dockerfile
├── api
│ ├── __init__.py
│ ├── urls.py
│ ├── wsgi.py
│ └── settings.py
Dockerfile文件:
FROM python:3.6
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/
RUN pip install -r /usr/src/app/requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
COPY . /usr/src/app
CMD python /usr/src/app/manage.py runserver 0.0.0.0:8000
2. SpringMVC項(xiàng)目的Dockerfile
項(xiàng)目運(yùn)行在tomcat中。
先生成war文件疙驾,轉(zhuǎn)成tar.gz文件凶伙, 通過ADD命令解壓到鏡像中。接下來就是配置文件的替換它碎,最后運(yùn)行tomact服務(wù)函荣。
# Version 0.1
# 基礎(chǔ)鏡像
FROM cbbing/tomcat
RUN rm -rf $CATALINA_HOME/webapps/ROOT
ADD ROOT.tar.gz $CATALINA_HOME/webapps/
# 配置文件替換
COPY conf/server.xml $CATALINA_HOME/conf/
COPY conf/tomcat-users.xml $CATALINA_HOME/conf/
COPY conf/jdbc.properties $CATALINA_HOME/webapps/ROOT/WEB-INF/classes/properties/
CMD ["catalina.sh", "run"]
mvn.sh: 生成ROOT.tar.gz的腳本如下:
cd ../myweb
mvn clean
mvn install -DskipTests
cd ..
mkdir ./ROOT
cp ./myweb/target/myweb.war ./ROOT
cd ROOT
jar xvf myweb.war
rm myweb.war
cd ..
tar czf ROOT.tar.gz ./ROOT
rm -rf ROOT/
3. Vue.js項(xiàng)目的Dockerfile
步驟如下:
- 下載package.json中定義的依賴
- npm build生成編譯后的文件到dist
- 基礎(chǔ)鏡像為nginx,從nginx代理靜態(tài)文件
FROM nginx:1.15
MAINTAINER cbbing <cbbing@163.com>
ENV LANG C.UTF-8
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezone
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY dist /usr/share/nginx/html
make.sh:制作腳本如下
#!/usr/bin/env bash
echo "npm install"
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install
echo "npm build"
npm run build
image_tag=`date +%Y%m%d` #_%H%M
echo "當(dāng)前時間:$image_tag"
docker build -t cbbing/web_p:v${image_tag} .
4. Scrapy項(xiàng)目的Dockerfile
scrapy項(xiàng)目和Django項(xiàng)目的差別在于啟動的方式不同扳肛,這里涉及到一些配置文件傻挂。
FROM python:3.6
#設(shè)置時區(qū)
ENV TZ=Asia/Shanghai
ENV PYTHONPATH=/usr/src/app
RUN mkdir -p /usr/src/app \
&& pip install -r /root/.pip/requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ \
&& apt-get update \
&& apt-get install -y supervisor \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
WORKDIR /usr/src/app
COPY . /usr/src/app
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN mkdir -p /var/log/supervisor
COPY scrapyd.conf /usr/local/lib/python3.6/site-packages/scrapyd/default_scrapyd.conf
CMD ["/usr/bin/supervisord"]
其中用到的配置文件:
- supervisord.conf
[inet_http_server]
port=9020
username=admin
password=1234
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log;
pidfile=/var/log/supervisord.pid;
childlogdir=/var/log/supervisor
[program:scrapyd]
command=scrapyd
loglevel=info
redirect_stderr=true
stdout_events_enabled=true
[program:scrapyd-deploy]
command=bash supervisor-scrapyd-deploy.sh
startsecs = 35
loglevel=info
[program:simple_http]
command=/bin/bash supervisor-http-egg.sh
autorestart=true
startsecs=10
loglevel=info
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
- scrapyd.conf
[scrapyd]
eggs_dir = eggs
logs_dir = logs
items_dir =
jobs_to_keep = 20
dbs_dir = dbs
max_proc = 0
max_proc_per_cpu = 4
finished_to_keep = 100
poll_interval = 5.0
bind_address = 0.0.0.0
http_port = 6800
debug = off
runner = scrapyd.runner
application = scrapyd.app.application
launcher = scrapyd.launcher.Launcher
webroot = scrapyd.website.Root
[services]
schedule.json = scrapyd.webservice.Schedule
cancel.json = scrapyd.webservice.Cancel
addversion.json = scrapyd.webservice.AddVersion
listprojects.json = scrapyd.webservice.ListProjects
listversions.json = scrapyd.webservice.ListVersions
listspiders.json = scrapyd.webservice.ListSpiders
delproject.json = scrapyd.webservice.DeleteProject
delversion.json = scrapyd.webservice.DeleteVersion
listjobs.json = scrapyd.webservice.ListJobs
daemonstatus.json = scrapyd.webservice.DaemonStatus