1 Dockerfile介紹
Dockfile是一種被Docker程序解釋的腳本柬采,Dockerfile由一條一條的指令組成欢唾,每條指令對應(yīng)Linux下面的一條命令。Docker程序?qū)⑦@些Dockerfile指令翻譯真正的Linux命令警没。Dockerfile有自己書寫格式和支持的命令匈辱,Docker程序解決這些命令間的依賴關(guān)系,類似于Makefile杀迹。Docker程序?qū)⒆x取Dockerfile,根據(jù)指令生成定制的image押搪。相比image這種黑盒子树酪,Dockerfile這種顯而易見的腳本更容易被使用者接受,它明確的表明image是怎么產(chǎn)生的大州。有了Dockerfile续语,當(dāng)我們需要定制自己額外的需求時,只需在Dockerfile上添加或者修改指令厦画,重新生成image即可疮茄,省去了敲命令的麻煩。
2 Dockerfile語法介紹
Dockerfile的注釋以“#”開始根暑,每一行都是一個指令
一般情況下力试,Dockerfile由4部分組成:
- 基礎(chǔ)鏡像信息(Base Image)
- 維護(hù)者信息(maintainer)
- 鏡像操作指令(Commands to update the base image)
- 容器啟動指令(Commands when creating a new container)
必須說明的是,如果使用Dockerfile來構(gòu)建鏡像排嫌,需要確定
- Dockerfile的第一條有效信息必須是基礎(chǔ)鏡像信息
- 維護(hù)者信息緊隨其后
- 鏡像操作指令則在維護(hù)者信息之后
- 最后是鏡像啟動指令
2.1 Dockerfile 指令
Dockerfile的指令一般采用的格式,其中INSTRUCTION是Dockerfile的關(guān)鍵字,包括FROM, MAINTAINER, RUN等腺逛,下面進(jìn)行詳細(xì)介紹
INSTRUCTION arguments
2.1.1 FROM
Dockerfile的第一條必須是FROM指令唤冈,用來指定要制作的鏡像繼承自哪個鏡像,格式如下
FROM <image>
FROM <image>:<tag>
例如需要構(gòu)建一個采用mongodb的數(shù)據(jù)庫鏡像颇象,用以下指令
FROM mongo:3.2
2.1.2 MAINTAINER
用來指定維護(hù)者信息伍伤,格式為
MAINTAINER <name>
例如我自己的維護(hù)者信息
MAINTAINER xixy10@foxmail.com
2.1.3 RUN
該指令用于執(zhí)行shell命令,當(dāng)解析Dockerfile時遣钳,遇到RUN指令扰魂,Docker會將該指令翻譯為如下,其中xxxxxx為RUN后面的shell命令
/bin/sh -c "XXXXXX"
格式為
RUN <command>
RUN <"executable","param1","param2"...>
例如需要安裝相關(guān)軟件及創(chuàng)建文件夾
RUN mkdir /Code
RUN pip install -r requirements.txt
2.1.4 EXPOSE
該指令將容器中的端口號暴露出來耍贾,也可以通過"docker run -p" 命令實現(xiàn)和服務(wù)器端口的映射
格式為
EXPOSE <PORT>[<PORT>...]
例如容器中部署了web應(yīng)用阅爽,需要將8080端口和80端口暴露出來
EXPOSE 80 8080
2.1.5 EXPOSE
該指令指定啟動容器時執(zhí)行的命令,每個Dockerfile只能有一條CMD指令荐开,如果指定了多條付翁,只有最后一條會被執(zhí)行。
如果用戶啟動容器時指定了運行的命令晃听,則會覆蓋CMD指定的命令
格式為
CMD ["executable","param1","param2"] #使用exec執(zhí)行百侧,推薦方式
CMD command param1 param2 #在/bin/sh中執(zhí)行砰识,提供給需要交互的應(yīng)用
CMD [“param1”,"param2"] #提供給ENTRYPOINT的默認(rèn)參數(shù)
例如啟動容器時要求啟動服務(wù)器
CMD python app.py
2.1.6 ENTRYPOINT
設(shè)置指令,指定容器啟動時執(zhí)行的命令佣渴,可以多次設(shè)置辫狼,但是只有最后一個有效
格式如下所示
ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)
ENTRYPOINT command param1 param2 (as a shell)
該指令的使用分為兩種情況,一種是獨自使用辛润,另一種和CMD指令配合使用膨处。
當(dāng)獨自使用時,如果你還使用了CMD命令且CMD是一個完整的可執(zhí)行的命令砂竖,那么CMD指令和ENTRYPOINT會互相覆蓋只有最后一個CMD或者ENTRYPOINT有效真椿。
# CMD指令將不會被執(zhí)行,只有ENTRYPOINT指令被執(zhí)行
CMD echo “Hello, World!”
ENTRYPOINT ls -l
另一種用法和CMD指令配合使用來指定ENTRYPOINT的默認(rèn)參數(shù)乎澄,這時CMD指令不是一個完整的可執(zhí)行命令突硝,僅僅是參數(shù)部分;ENTRYPOINT指令只能使用JSON方式指定執(zhí)行命令置济,而不能指定參數(shù)解恰。
FROM ubuntu
CMD ["-l"]
ENTRYPOINT ["/usr/bin/ls"]
2.1.7 VOLUME
創(chuàng)建一個可以從本地主機(jī)或者其他容器掛載的掛載點(目錄),一般用來存放數(shù)據(jù)庫或者需要永久保存的數(shù)據(jù)浙于,該目錄可以被容器本身使用护盈,也可以共享給其他容器使用。我們知道容器使用的是AUFS路媚,這種文件系統(tǒng)不能持久化數(shù)據(jù)黄琼,當(dāng)容器關(guān)閉后,所有的更改都會丟失整慎。當(dāng)容器中的應(yīng)用有持久化數(shù)據(jù)的需求時可以在Dockerfile中使用該指令脏款。
如果和host共享目錄,Dockerfile中必須創(chuàng)建一個掛載點裤园,然后在啟動容器的時候撤师,通過以下指令來進(jìn)行掛載
docker run -v $HOSTPATH:$CONTAINERPATH
格式如下所示
VOLUME ["<mountpoint>"]
例如
FROM base
VOLUME ["/tmp/data"]
運行通過該Dockerfile生成image的容器,/tmp/data目錄中的數(shù)據(jù)在容器關(guān)閉后拧揽,里面的數(shù)據(jù)還存在剃盾。例如另一個容器也有持久化數(shù)據(jù)的需求,且想使用上面容器共享的/tmp/data目錄淤袜,那么可以運行下面的命令啟動一個容器
docker run -t -i -rm -volumes-from container1 image2 bash
container1為第一個容器的ID痒谴,image2為第二個容器運行image的名字
2.1.8 ENV
該指令指定一個環(huán)境變量,會被后續(xù)RUN指令使用铡羡,并在容器運行時保持积蔚,格式為
ENV <key> <value>
container啟動后,可以通過docker inspect查看這個環(huán)境變量烦周,也可以通過在docker run --env key=value時設(shè)置或修改環(huán)境變量尽爆。
假如你安裝了JAVA程序怎顾,需要設(shè)置JAVA_HOME,那么可以在Dockerfile中這樣寫
ENV JAVA_HOME /path/to/java/dirent
2.1.9 ADD指令
該指令將復(fù)制指定的到容器中的漱贱,其中可以是
- Dockerfile所在目錄的一個相對路徑
- 一個URL
- 可以是一個tar文件(會自動解壓為目錄)
指令為
ADD <src> <dest>
所有拷貝到container中的文件和文件夾權(quán)限為0755槐雾,uid和gid為0;
- 如果是一個目錄幅狮,那么會將該目錄下的所有文件添加到container中募强,不包括目錄;
- 如果文件是可識別的壓縮格式彪笼,則docker會幫忙解壓縮(注意壓縮格式)钻注;
- 如果是文件且中不使用斜杠結(jié)束,則會將視為文件配猫,的內(nèi)容會寫入;
- 如果是文件且中使用斜杠結(jié)束杏死,則會將文件拷貝到目錄下
2.1.10 WORKDIR
設(shè)置指令泵肄,可以多次切換(相當(dāng)于cd命令),對RUN,CMD,ENTRYPOINT生效
格式為
WORKDIR /path/to/workdir
例如
WORKDIR /p1 WORKDIR p2 RUN vim a.txt
2.2 docker build
root@ubuntu:~# docker build --help
Usage: docker build [OPTIONS] PATH | URL | -
Build a new image from the source code at PATH
-c, --cpu-shares=0 CPU shares (relative weight)
--cpuset-cpus= CPUs in which to allow execution (0-3, 0,1)
-f, --file= Name of the Dockerfile (Default is 'PATH/Dockerfile')
--force-rm=false Always remove intermediate containers
--help=false Print usage
-m, --memory= Memory limit
--memory-swap= Total memory (memory + swap), '-1' to disable swap
--no-cache=false Do not use cache when building the image
--pull=false Always attempt to pull a newer version of the image
-q, --quiet=false Suppress the verbose output generated by the containers
--rm=true Remove intermediate containers after a successful build
-t, --tag= Repository name (and optionally a tag) for the image
3 示例
我將以前的一個項目的后端用Docker進(jìn)行發(fā)布淑翼,采用兩個容器腐巢,一個用來跑Service,一個專門用來作為數(shù)據(jù)庫(mongodb)玄括,兩個服務(wù)器之間有交互冯丙,Service容器會對Database容器進(jìn)行增刪改查操作
3.1 Database容器
直接拉取mongo服務(wù)器
docker pull mongo:3.2
等待下載完成后,我們就可以在本地鏡像列表里查到REPOSITORY為mongo,標(biāo)簽為3.2的鏡像遭京。
然后運行容器
docker run -p 27017:27017 -v $PWD/db:/data/db -d mongo:3.2
命令說明:
-p 27017:27017 :將容器的27017 端口映射到主機(jī)的27017 端口
-v $PWD/db:/data/db :將主機(jī)中當(dāng)前目錄下的db掛載到容器的/data/db胃惜,作為mongo數(shù)據(jù)存儲目錄
3.2 Service容器
Service容器需要運行Flask應(yīng)用,Dockerfile如下所示
FROM python:2.7
MAINTAINER xixy10 "xixy10@foxmail.com"
RUN /bin/echo 'root:123456' |chpasswd
RUN useradd xixy
RUN /bin/echo 'xixy:123456' |chpasswd
RUN mkdir /Code
WORKDIR /Code
ADD . /Code/
RUN pip install -r requirements.txt
WORKDIR ./TOP/util
RUN python question_lib_generator.py
WORKDIR ../
EXPOSE 5000
CMD python test.py
然后build產(chǎn)生鏡像
docker build -t xixy/tpo:1.0 .
運行容器
docker run -it -p 5000:5000 xixy/tpo:1.0
然后即可訪問哪雕,API正常運行船殉,運行過程中Service容器會對Database容器進(jìn)行增刪改查,容器間通信會令寫一篇