Dockerfile Dockerfile是一个文本文件,其中包含了构建Docker镜像需要执行的命令序列。使用dockerbuild命令从Dockerfile中读取指令来构建镜像。上下文 构建镜像时,该过程的第一件事是将Dockerfile文件所在目录下的所有内容发送给Docker守护进程。所以大多数情况下,最好创建一个新的目录,在其中保存Dockerfile,以及构建镜像所需的其它文件。Dockerfile文件所在目录也被称为构建上下文(context)。 使用FROM指令指定一个基础镜像,后续指令将在此镜像基础上运行:FROMubuntu:14。04 在Dockerfile中可以指定一个用户,后续的RUN,CMD以及ENTRYPOINT指令都会使用该用户身份去执行,该用户必须已存在。USERsoundhearer 除了指定用户之外,还可以使用WORKDIR指定当前工作目录(CWD),RUN,CMD,COPY,ADD指令将在指定的工作目录中执行。WORKDIR RUN指令用于执行命令,该指令有两种形式:RUN,在shell中执行命令command,一般默认的shell为binsh。RUN〔executable,param1,param2,。。。〕,运行可执行程序executable,可以指定程序需要的命令行参数。 例如我们执行更新命令:RUNaptgetupdate CMD的使用方式跟RUN类似,不过在一个Dockerfile文件中只能有一个CMD指令,如果有多个,则只有最后一个会生效。该指令指定了启动容器时要执行的命令,例如:CMDechohellosoundhearer 可以在dockerrun时指定命令来覆盖默认的CMD命令,比如dockerrunimageechohelloshiyanlou。 CMD指令还有一种特殊用法。在Dockerfile中,如果使用ENTRYPOINT指令指定了入口命令,则CMD指令的内容会作为ENTRYPOINT指令的参数:CMD〔param1,param2〕 ENTRYPOINT指令会覆盖CMD指令作为容器运行时的默认指令,并且该指令不会被dockerrun时指定的指令覆盖,如下示例:FROMubuntu:latestENTRYPOINT〔ls,a〕CMD〔l〕 上述文件构建出来的镜像,使用dockerrunimage等同于dockerrunimagelsal。使用dockerrunimageis等同于dockerrunimagelsais。即CMD指令的值会被当作ENTRYPOINT指令的参数附加到ENTRYPOINT指令的后面,只有CMD指令可以被覆盖。COPY和ADD COPY和ADD都用于将构建上下文中的文件,目录等复制到镜像中。使用方式如下:ADDsrc。。。destADD〔SRC,。。。dest〕COPYsrc。。。destCOPY〔src,。。。dest〕 可以指定多个,但是其路径不能超出构建上下文范围,即必须在Dockerfile同级或子目录中。 不需要预先存在,不存在时会自动创建,如果使用相对路径,则为相对于工作目录的路径。 COPY和ADD的不同之处在于,ADD可以添加远程文件,并且可以是gzip或tar等格式的压缩文件,添加时会自动进行解压。ENV ENV指令用于设置环境变量:ENVkeyvalueENVkeyvaluekeyvalue。。。VOLUME VOLUME指令指定要创建的挂载路径,在容器运行时,将为每个挂载路径创建一个匿名卷并挂载上去:VOLUMEdata1data2 上述指令将会在容器运行时,创建两个匿名卷,并分别挂载到容器中的data1和data2路径。EXPOSE EXPOSE用来暴露容器运行时会监听的端口,它只是一种声明,让外部能够知道容器内部的服务端口。可以在运行容器时通过p选项来绑定容器监听端口到宿主机端口,这些监听端口不一定需要通过EXPOSE暴露。当使用P(大写)选项时会自动绑定所有暴露出来的端口。EXPOSEport从Dockerfile创建镜像 学习了上面这些常见的Dockerfile指令之后,可以使用这些指令来构建一个镜像。如下所示,构建一个提供ssh服务的镜像:cdDockerSerDockerfilecentossshviDockerfile生成的新镜像以centos镜像为基础FROMcentos指定作者信息MAINTAINERsoundhearer安装opensshserverRUNyumyinstallopensshserverRUNmkdirvarrunsshdRUNsshkeygentrsafetcsshsshhostrsakeyRUNsshkeygentdsafetcsshsshhostdsakey指定root密码RUNbinechoroot:123456chpasswdRUNbinsedis。session。required。pamloginuid。so。sessionoptionalpamloginuid。sogetcpam。dsshdRUNbinechoeLANGenUS。UTF8etcdefaultlocalEXPOSE22CMDusrsbinsshdD 构建镜像〔rootVM017centosdockerfile〕dockerbuildt5588centosssh:v1。0。0。SendingbuildcontexttoDockerdaemon14。85kBStep111:FROMcentos470671670cacStep211:MAINTAINERsoundhearerRunningind5705e869a7eRemovingintermediatecontainerd5705e869a7e76f3b6fa1597Step311:RUNyumyinstallopensshserverRunningindcd4af79f6c1 查看镜像〔rootVM017centosdockerfile〕dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZE5588centossshv1。0。0c16cedf7052c2minutesago278MB 启动容器〔rootVM017centosdockerfile〕dockerrunitdp10022:22nametestcentos15588centosssh:v1。0。0ae638dff422529144e0066a98611a96ea51cd1469aa8007a503ed8b53ab62d22〔rootVM017centosdockerfile〕 查看已经启动的容器〔rootVM017centosdockerfile〕dockerpsCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMESae638dff42255588centosssh:v1。0。0binshcusrsb51secondsagoUp50seconds0。0。0。0:1002222tcptestcentos1 测试远程登录〔rootVM017centosdockerfile〕sshp10022127。0。0。1root127。0。0。1spassword:〔rootae638dff4225〕DockerComposeCompose Compose是运行由多个容器组成的Docker应用的工具,使用Compose可以一次启动一组有关联的服务,每个服务由来自同一镜像的单个或多个容器组成。Service 在复杂应用中,应用一般由多个服务(service)组成,例如一个网站后台通常包含Web服务、数据库服务、缓存服务、消息队列服务等。使用步骤 使用Compose的步骤如下:定义和构建组成应用的各个服务的镜像,主要是编写各个服务的Dockerfile文件定义应用服务描述文件,主要是编写dockercompose。yml文件启动应用 关于dockercompose。yml文件的详细格式可以参考官方文档。 目前有三种版本的Compose文件格式:version1:最早的版本使用传统格式,将在未来弃用version2:现在使用最多的文件格式version3:最新版本,旨在使得Compose和已被集成到DockerEngine中的swarmmode互相兼容。安装 下载dockercomposeLinuxx8664 下载成功后,为了方便使用,可以将其添加到PATH路径下sudomvdockercomposeLinuxx8664usrlocalbindockercompossudochmodxusrlocalbindockercompose 执行完成后,就能够在终端下直接使用dockercompose命令了:〔rootVM017centosdockerfile〕dockercomposehelpDefineandrunmulticontainerapplicationswithDocker。Usage:dockercompose〔f。。。〕〔options〕〔COMMAND〕〔ARGS。。。〕dockercomposehhelp实例 接下来我们将创建一个Web应用,该应用包含两个容器:web容器:提供web服务,该服务需要连接后端的redis服务redis容器:提供redis服务 项目目录结构如下:appwebweb。pyrequirements。txtDockerfiledockercompose。yml 首先编辑appwebweb。py文件,写入下面的内容:fromflaskimportFlaskfromredisimportRedisappFlask(name)redisRedis(hostredis,port6379)app。route()defhello():redis。incr(number)returnHelloDocker!sredis。get(number)ifnamemain:app。run(host0。0。0。0,port80,debugTrue) 上述代码创建了一个简单的Web应用。该应用会连接redis服务,在访问页面时,自动将变量number加1。 编辑appwebrequirements。txt文件,输入如下内容:flask0。10redis2。10。3 requirements。txt文件存放了Web应用依赖的第三方库包的名称和版本信息。 编辑appwebDockerfile文件,添加如下内容FROMpython:2。7COPY。webWORKDIRwebRUNpipinstallrrequirements。txtCMDpythonweb。py 上述Dockerfile定义了Web应用镜像,该镜像基于python:2。7基础镜像,在其基础上安装了应用依赖的库包,并通过CMD指令指定了应用的启动命令。 编辑appdockercompose。yml文件:services:redis:image:redis:3。2web:build:context:homeshiyanlouappwebdependson:redisports:8001:80tcpvolumes:homeshiyanlouappweb:web:rwversion:3。0 该dockercompose。yml文件定义了两个服务,分别为web和redis服务,并且配置了web服务的端口映射和挂载目录。dependson定义了依赖关系,被依赖的服会先启动。 进入app目录,执行dockercomposeup命令来启动应用:〔rootVM017centosapp〕dockercomposeupBuildingwebStep15:FROMpython:2。7fbc983cb5352Step25:COPY。web10bdacc94674Step35:WORKDIRwebRunningin7ff982241c92Removingintermediatecontainer7ff982241c920a37af3e9713Step45:RUNpipinstallrrequirements。txtRunningin9832ab0165d1DEPRECATION:Python2。7reachedtheendofitslifeonJanuary1st,2020。PleaseupgradeyourPythonasPython2。7isnolongermaintained。AfutureversionofpipwilldropsupportforPython2。7。MoredetailsaboutPython2supportinpip,canbefoundathttps:pip。pypa。ioenlatestdevelopmentreleaseprocesspython2supportCollectingflask0。10DownloadingFlask0。10。tar。gz(544kB)Collectingredis2。10。3Downloadingredis2。10。3。tar。gz(86kB)CollectingWerkzeug0。7DownloadingWerkzeug1。0。0py2。py3noneany。whl(298kB)CollectingJinja22。4DownloadingJinja22。11。1py2。py3noneany。whl(126kB)Collectingitsdangerous0。21Downloadingitsdangerous1。1。0py2。py3noneany。whl(16kB)CollectingMarkupSafe0。23DownloadingMarkupSafe1。1。1cp27cp27mumanylinux1x8664。whl(24kB)Buildingwheelsforcollectedpackages:flask,redisBuildingwheelforflask(setup。py):startedBuildingwheelforflask(setup。py):finishedwithstatusdoneCreatedwheelforflask:filenameFlask0。10py2noneany。whlsize115528sha256967ce1269d455054b3713a87985eeceda84b437ff0c2d0ba8855bb813daf9c10Storedindirectory:root。cachepipwheels75152cb14930624e0a52fdd754537b216da52d96b79dd5d14966abb7Buildingwheelforredis(setup。py):startedBuildingwheelforredis(setup。py):finishedwithstatusdoneCreatedwheelforredis:filenameredis2。10。3py2noneany。whlsize50695sha2569741ffb0196e0dc9d1818811a48f206aff9c53699dfe822e1b0f9591f72db9e8Storedindirectory:root。cachepipwheels12ce011aba4866d936f9a08aeb59a573b188c17daea0da2537c68deaSuccessfullybuiltflaskredisInstallingcollectedpackages:Werkzeug,MarkupSafe,Jinja2,itsdangerous,flask,redisSuccessfullyinstalledJinja22。11。1MarkupSafe1。1。1Werkzeug1。0。0flask0。10itsdangerous1。1。0redis2。10。3Removingintermediatecontainer9832ab0165d1f12bc5dc1aacStep55:CMDpythonweb。pyRunninginaec73ed63ab6Removingintermediatecontaineraec73ed63ab6228792f96283Successfullybuilt228792f96283Successfullytaggedappweb:latestWARNING:Imageforservicewebwasbuiltbecauseitdidnotalreadyexist。TorebuildthisimageyoumustusedockercomposebuildCreatingappredis1。。。doneCreatingappredis1。。。Creatingappweb1。。。doneAttachingtoappredis1,appweb1redis11:C14Mar13:54:22。030Warning:noconfigfilespecified,usingthedefaultconfig。Inordertospecifyaconfigfileuseredisserverpathtoredis。confredis1。redis1。。redis1。。。。Redis3。2。12(000000000)64bitredis1。。。。,。redis1(,。,)Runninginstandalonemoderedis1。。。。。。。。。。Port:6379redis1。。。PID:1redis1。。。。。redis1。。。。。。redis1。。。。http:redis。ioredis1。。。。。。redis1。。。。。。redis1。。。。redis1。。。。。。redis1。。。。redis1。。redis1。。redis1redis11:M14Mar13:54:22。033WARNING:TheTCPbacklogsettingof511cannotbeenforcedbecauseprocsysnetcoresomaxconnissettothelowervalueof128。redis11:M14Mar13:54:22。033Serverstarted,Redisversion3。2。12redis11:M14Mar13:54:22。033WARNINGovercommitmemoryissetto0!Backgroundsavemayfailunderlowmemorycondition。Tofixthisissueaddvm。overcommitmemory1toetcsysctl。confandthenrebootorrunthecommandsysctlvm。overcommitmemory1forthistotakeeffect。redis11:M14Mar13:54:22。033WARNINGyouhaveTransparentHugePages(THP)supportenabledinyourkernel。ThiswillcreatelatencyandmemoryusageissueswithRedis。Tofixthisissuerunthecommandechoneversyskernelmmtransparenthugepageenabledasroot,andaddittoyouretcrc。localinordertoretainthesettingafterareboot。RedismustberestartedafterTHPisdisabled。redis11:M14Mar13:54:22。033Theserverisnowreadytoacceptconnectionsonport6379web1Runningonhttp:0。0。0。0:80(PressCTRLCtoquit)web1Restartingwithstatweb1Debuggerisactive!web1DebuggerPIN:764159950web1116。30。196。114〔14Mar202013:58:04〕GETHTTP1。1200web1116。30。196。114〔14Mar202013:58:05〕GETfavicon。icoHTTP1。1404web1Detectedchangeinwebweb。py,reloadingweb1Restartingwithstatweb1Debuggerisactive!web1DebuggerPIN:764159950 启动成功后,就可以打开网址127。0。0。1:8001来访问Web应用了。 另外一些命令:后台运行应用:dockercomposeupd查看容器dockercomposeps查看镜像dockercomposeimages停止并删除应用,相关容器也会一并删除dockercomposedown