Docker通过对于在Dockerfile中的一系列指令的顺序解析实现自动的image的构建。
通过使用build命令,根据Dockerfile的描述来构建镜像。
只支持Docker自己定义的一套指令,不支持自定义
大小写不敏感,但是建议全部使用大写
根据Dockerfile的内容顺序执行
FROM指令
FROM {base镜像}
必须放在DOckerfile的第一行,表示从哪个baseimage开始构建
MAINTAINER
MAINTAINER: xxx
可选的,用来标识image作者的地方
RUN
每一个RUN指令都会是在一个新的container里面运行,并提交为一个image作为下一个RUN的base
一个Dockerfile中可以包含多个RUN,按定义顺序执行
RUN支持两种运行方式:
RUN <cmd> 这个会当作/bin/sh -c “cmd” 运行
RUN [“executable”,“arg1”,。。],Docker把他当作json的顺序来解析,因此必须使用双引号,而且executable需要是完整路径
RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN command1 的执行仅仅是当前进程,一个内存上的变化而已,其结果不会造成任何文件。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。而如果需要将两条命令或者多条命令联合起来执行需要加上&&。如:cd /usr/local/src && wget xxxxxxx
ADD & COPY
当在源代码构建的方式下,可以通过ADD和COPY的方式,把host上的文件或者目录复制到image中
ADD和COPY的源必须在context路径下
当src为网络URL的情况下,ADD指令可以把它下载到dest的指定位置,这个在任何build的方式下都可以work
ADD相对COPY还有一个多的功能,能够进行自动解压压缩包
ENV
ENV key value
用来设置环境变量,后续的RUN可以使用它所创建的环境变量
当创建基于该镜像的container的时候,会自动拥有设置的环境变量
CMD
CMD的作用是作为执行container时候的默认行为(容器默认的启动命令)
当运行container的时候声明了command,则不再用image中的CMD默认所定义的命令
一个Dockerfile中只能有一个有效的CMD,当定义多个CMD的时候,只有最后一个才会起作用
CMD定义的三种方式:
CMD <cmd> 这个会当作/bin/sh -c "cmd"来执行
CMD ["executable","arg1",....]
CMD ["arg1","arg2"],这个时候CMD作为ENTRYPOINT的参数
示例1 :以最常用的tomcat为示例
1 2 3 4 | FROM tomcat:latest ENV TZ=Asia /Shanghai RUN rm /usr/local/tomcat/webapps -rf COPY . /webapps/ /usr/local/tomcat/webapps/ |
示例解释:
基础镜像为 tomcat:latest ,基础镜像如果本地存在,则使用本地的镜像,如果不存在,则自动会从官方镜像仓库拉取镜像,查 看镜像:docker images
ENV 设置时区,亚洲 / 上海
RUN 运行命令把 tomcat 自身 webapps 目录下的内容清除
COPY 把当前目录中的 webapps 目录拷贝到镜像中,生成我们自己需要的新的镜像。
这里有几个需要注意的地方
rm /usr/local/tomcat/webapps -rf 和 rm /usr/local/tomcat/webapps/* -rf 的区别
rm /usr/local/tomcat/webapps -rf 表示删除整个webapps目录,也就是webapps目录都没有了
rm /usr/local/tomcat/webapps/* -rf 表示删除webapps目录下的东西,也就是webapps目录还在,但是里的东西没有了。
程序的war包或者前端包放在什么地方?
这里需要结合上面的rm 语句的写法来决定。如果上面写的是rm /usr/local/tomcat/webapps -rf ,也就是容器里没有了webapps,那么我们COPY或ADD程序包的时候,会使用
COPY ./webapps/ /usr/local/tomcat/webapps/ 这样的指令,给容器里再COPY进去一个webapps,这种情况的程序包当然就放在当前目录的webapps目录下。
如果是使用的 COPY ./webapps/ /usr/local/tomcat/webapps/* -rf 这样的指令,那么可以直接把war包或者前端包放到Dockerfile的同级目录。也即是这样:
1 2 3 4 5 | FROM tomcat:latest ENV TZ=Asia /Shanghai RUN rm /usr/local/tomcat/webapps/ * -rf COPY *.war /usr/local/tomcat/webapps/ COPY build /usr/local/tomcat/webapps/ |
示例2:初始的tomcat镜像不够我们使用,我们需要下载一些东西,下载一些插件。
1 2 3 4 | FROM tomcat:latest ENV TZ=Asia /Shanghai RUN rm /usr/local/tomcat/webapps -rf && apt-get update && apt-get install -y ffmpeg && apt-get clean COPY . /webapps/ /usr/local/tomcat/webapps/ |
示例解释:
本示例多了一步下载程序的步骤,可以通过 && 使用一条 RUN 命令完成(RUN指令里也有解释)。这里是下载了 ffmpeg 插件。
需要注意的是,不同的初始镜像,镜像的发布版本不一样,也即发布版本不一定是 centos 版的镜像。这里的 tomcat 就是使用 debain 镜像制作而成,那么下载东西得参考 debain 的下载包的方法,具体debain,ubuntu怎么下载包可以网上百度。
如何分辨到底是 centos 发布版本,还是 debain ,或者是 ubuntu ?可以查看镜像官方文档或者运行一个初始镜像
docker run -it tomcat:latest bash 运行一个基础镜像
cat /etc/debian_version 是 debian 系统,则 /etc/ 目录下有此文件,可以查看 debian 版本
如果是 centos 系统,则有 cat /etc/redhat-release , ubuntu 也有自己相应的标识。
示例3:添加CMD指令,作为启动程序的指令
上面的tomcat镜像,由于在初始镜像中就已经做了CMD启动指令,这里我换成基础平台的镜像举例。(tomcat镜像你也可以自己再写一条CMD,会覆盖掉基础镜像的启动指令)
1 2 3 4 5 6 7 | [root@localhost app] # cat Dockerfile FROM microsoft /dotnet :2.2-aspnetcore-runtime RUN ln -s /lib/x86_64-linux-gnu/libdl-2 .24.so /lib/x86_64-linux-gnu/libdl .so RUN apt-get update && apt-get install -y net-tools procps lsof sysstat libfontconfig1 libgdiplus && ln -s libgdiplus.so gdiplus.dll #ENV LANG C.UTF-8 COPY . /JF-ISBM /etc/JF-ISBM CMD [ "sh" , "-c" , "cd /etc/JF-ISBM/ ;dotnet /etc/JF-ISBM/JF-ISBM2.0WEBAPI.dll" ] |
示例解释:基础镜像为微软镜像仓库的dotnet2.2镜像
RUN 下载基础平台需要的依赖包
COPY 把当前目录的基础平台程序拷贝到镜像中
CMD 设置基础平台的启动命令。
需要注意的是: 在设置程序启动命令的时候,需要前台运行,不能后台运行,如tomcat如果设置为 startup.sh 方式启动,则属于放入后台启动,容器运行后会自动退出。解决方式,可以使用 catalina.sh 方式启动,或者在 startup.sh 启动后面增加一句,tail -f /usr/local/tomcat/logs/catalina.out ,让容器前台有持续输出。
docker build -t IMAGENAME:TAG .
docker-compose是一种容器管理方式,我们在生产环境中启动一个容器,除了会使用-p 参数映射容器端口,还会使用很多参数,比如-v 映射目录,--restart 指定容器重启方式等,这样就会造成一条启动命名会非常的长,使用起来也会很不方便。
除此之外,直接使用docker run命令也只能一次管理一个容器。docker-compose是一种非常方便的docker容器单机编排脚本。
docker-compose的运行方式依托于docker-compose.yml文件,是一种yaml语言风格的key-value文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | version: "3" #docker-compose版本,根据docker-compose版本决定,如果版本不对,在运行时会报错提示应该使用的版本 services: #定义服务 jf-isgct-web: # 服务名,自定义,这里定义的第一个服务名为jf-isgct-web build: . /web #build,指定Dockerfile的位置,需要构建镜像时开启这个参数 restart: always # restart,容器重启策略 image: jf-isgct-web:v2-20190901 #运行容器的镜像名称,如果是拉取或者需要上传到私有镜像仓库的镜像,得按照后边部署文档中添加私有镜像仓库前缀。如果前面添加了build参数,则这里也是新构建的镜像名称,故再每次更新重新构建镜像时,需要修改版本号以区分新旧镜像,方便回滚,回滚时只需修改为旧镜像版本。 privileged: true #容器特权模式 container_name: jf-isgct-web #指定容器名 # mem_limit: 1g #内存限制 # cpus: 1 #cpu限制 ports: #容器暴露端口,冒号前为宿主机端口,冒号后为容器内服务端口 - 6199:6190 environment: #环境变量,可以添加多组,以-开头 - TZ=Asia /Shanghai links: #关联容器,如果有需要关联的容器,可以添加此参数,如果没有,可不添加 - jf-isgct:backend depends_on: #依托容器,即该参数下的容器启动后才会启动本服务容器,根据需求是否添加 - jf-isgct # volumes: #容器目录映射,冒号前为映射到宿主机的目录,可以为相对路径,冒号后为容器里需要映射出来的目录 # - ./logs:/usr/local/tomcat/logs command : "sh -c 'cd /front-end;npm run start'" #类似Dockerfile中的CMD,添加容器中服务启动命令,一个服务只能出现一条command,并且也是需要前台启动 jf-isgct: #第二个服务,可以在一个docker-compose.yml中写多个服务,也可以单独一个 # build: ./backend image: 1.xxx.xxx.xxx /zhxy/jf-isgct :v2.0-20180830 restart: always container_name: jf-isgct # mem_limit: 1g #内存限制 # # cpus: 1.0 ports: - 12216:8080 volumes: - . /config .txt: /usr/share/JFConfig/config .txt - . /logs : /usr/local/tomcat/logs - /etc/localtime : /etc/localtime :ro command : "sh -c '/usr/local/tomcat/bin/startup.sh; tail -f /usr/local/tomcat/logs/catalina.out'" |
docker-compose 命令使用:
docker-compose up -d 运行容器
docker-compose down 关闭容器
docker-compose up -d --build 构建新镜像,并用新镜像运行一个容器
docker-compose build 只构建新镜像
docker-compose restart 重启容器
需要注意的是,运行docker-compose命令需要在docker-compose.yml存放的目录中。
我们构建镜像可能会存在更新的情况。这里介绍两种方式更新镜像。
这种方式的初始镜像为官方镜像,即FROM 的镜像为官方镜像,比如tomcat:latest ,node:10.16 , microsoft/dotnet:2.2-aspnetcore-runtime 等都是官方的基础镜像。我所有做的公司业务镜像都是以这种方式构建。这里以基础平台的dotnet 镜像为例。
1 2 3 4 5 6 | FROM microsoft /dotnet :2.2-aspnetcore-runtime RUN ln -s /lib/x86_64-linux-gnu/libdl-2 .24.so /lib/x86_64-linux-gnu/libdl .so RUN apt-get update && apt-get install -y net-tools procps lsof sysstat libfontconfig1 libgdiplus && ln -s libgdiplus.so gdiplus.dll #ENV LANG C.UTF-8 COPY . /JF-ISBM /etc/JF-ISBM CMD [ "sh" , "-c" , "cd /etc/JF-ISBM/ ;dotnet /etc/JF-ISBM/JF-ISBM2.0WEBAPI.dll" ] |
Dockerfile详解:
这里的初始镜像为微软官方下载的 microsoft/dotnet:2.2-aspnetcore-runtime
两条RUN命令为基础镜像所需要的依赖包和一些工具。
COPY命令为把和Dockerfile同级目录的基础平台程序JF-ISBM目录拷贝到镜像中
CMD dotnet启动基础平台
我这里Dockerfile和JF-ISBM放置的目录为: /mdata/jf-isbm/app ;mdata标准化部署目录,jf-isbm,基础产品目录,app,程序放置目录,如果是tomcat的程序,按照Dockerfile的内容,可能会在app目录下存在webapps目录,具体根据不同的Dockerfile确定,上文已经解释过。
如果需要更新程序,那么只需要把旧的基础包替换成新的基础包,然后再重新运行构建镜像的命令。
在重新构建镜像之前,需要修改docker-compose.yml文件中image字段的版本号。这样的好处也是显而易见的,如果新的镜像不适合上线运行,那么你只需要重新修改docker-compose.yml文件中image字段的版本号为老版本号,重新运行容器即可。
正常情况来讲,如果有程序更新,我这边会做好新的镜像然后重新推送到镜像仓库,你们直接拉取新的镜像即可。但如果遇到特殊情况,镜像仓库的镜像还未更新,那么就需要在部署环境中制作镜像更新了。
由于部署环境中已经存在我们从镜像仓库拉取的老版本的镜像,那么我们可以由此镜像作为FROM的基础镜像,来更新我们的镜像。
如果我们是直接从仓库拉取镜像,我们的部署目录jf-isbm下可能没有app目录,也没有Dockerfile文件,那么需要我们手动创建一个,按照规范标准来部署。
在jf-isbm下创建一个app目录,专门存放程序包,并在app目录下创建一个Dockerfile。
1 2 3 | FROM 1.xxx.xxx.xxx /zhxy/jf-isbm :v2.0-20190830 COPY . /JF-ISBM /etc/JF-ISBM CMD [ "sh" , "-c" , "cd /etc/JF-ISBM/ ;dotnet /etc/JF-ISBM/JF-ISBM2.0WEBAPI.dll" ] |
Dockerfile详解:
这里的基础镜像就是我们已经使用的需要更新的旧镜像了。因为这个镜像已经包含了我们需要的插件,需要的工具,故这里也不需要我们再重新下载,直接把程序包做一个替换,COPY会覆盖原有的JF-ISBM。
写完Dockerfile,上传我们新的包并解压,名字要跟Dockerfile里的名字保持一致。之后,我们需要修改一下docker-compose.yml文件。
第一处修改,取消掉build行的注释,因为需要构建镜像,或者是自己在image行的上面的同级别处(也即前面的空格一样多)添加一个build: ./app 。这里注意,冒号后面有空格,app为docker-compose.yml同级下存放程序和Dockerfile的目录,如果你的目录不叫app,请改成你自己的名字。
第二处修改,更改image字段的版本号。
修改完之后,我们就可以docker-compose down 和docker-compose up -d --build了。
1 上传的文件解压后注意中文乱码问题,具体的解决方法在《解决基础平台程序包乱码问题》
2 注意修改版本号,一定记得,修改好处多多
3 docker-compose可能由于版本不同,在version指定的版本可能会出现不能使用的情况,这里在运行的时候会有报错提示,提示你该使用的版本,如下:会提示你用2.2或者3.3
1 2 3 | [root@localhost jf-isbm] # docker-compose build ERROR: Version in "./docker-compose.yml" is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a supported version (e.g "2.2" or "3.3" ) and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1. For more on the Compose file format versions, see https: //docs .docker.com /compose/compose-file/ |
4 这里只是举例了两个镜像构建和更新,其他的镜像构建类似,参照即可
5 公司私有镜像仓库地址http://1.xxx.xxx.xxx
首先设置私有镜像仓库可信任:
vi /etc/docker/daemon.json
{"registry-mirrors": ["http://f1361db2.m.daocloud.io"],
"insecure-registries": ["1.xxx.xxx.xxx"]
}
systemctl restart docker
centos 登陆方式:docker login -u xxx -p xxxx 1.xxx.xxx.xxx
docker pull 1.xxx.xxx.xxx/datacenter/jf-beais:v1.0-20190516 拉取镜像
docker push 1.xxx.xxx.xxx/datacenter/jf-beais:v1.0-20190516 推送镜像
镜像的名需要有私有仓库地址标识
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。