Dockerfile和docker-compose应用

2023-06-07,,

Dockerfile 介绍

Docker通过对于在Dockerfile中的一系列指令的顺序解析实现自动的image的构建。

通过使用build命令,根据Dockerfile的描述来构建镜像。

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的参数

Dockerfile示例

示例1 :以最常用的tomcat为示例

1234 FROM tomcat:latestENV TZ=Asia/ShanghaiRUN rm /usr/local/tomcat/webapps -rfCOPY ./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的同级目录。也即是这样:

12345 FROM tomcat:latestENV TZ=Asia/ShanghaiRUN rm /usr/local/tomcat/webapps/* -rfCOPY *.war /usr/local/tomcat/webapps/COPY build  /usr/local/tomcat/webapps/

   

示例2:初始的tomcat镜像不够我们使用,我们需要下载一些东西,下载一些插件。

1234 FROM tomcat:latestENV TZ=Asia/ShanghaiRUN rm /usr/local/tomcat/webapps -rf && apt-get update && apt-get install -y ffmpeg && apt-get cleanCOPY ./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,会覆盖掉基础镜像的启动指令)

1234567 [root@localhost app]# cat DockerfileFROM microsoft/dotnet:2.2-aspnetcore-runtimeRUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.soRUN apt-get update  && apt-get install -y net-tools  procps lsof  sysstat libfontconfig1 libgdiplus && ln-s libgdiplus.so gdiplus.dll#ENV LANG C.UTF-8COPY  ./JF-ISBM /etc/JF-ISBMCMD ["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构建镜像

    docker build -t  IMAGENAME:TAG  .    

Docker-compose介绍

docker-compose是一种容器管理方式,我们在生产环境中启动一个容器,除了会使用-p 参数映射容器端口,还会使用很多参数,比如-v 映射目录,--restart 指定容器重启方式等,这样就会造成一条启动命名会非常的长,使用起来也会很不方便。

除此之外,直接使用docker run命令也只能一次管理一个容器。docker-compose是一种非常方便的docker容器单机编排脚本。

docker-compose的运行方式依托于docker-compose.yml文件,是一种yaml语言风格的key-value文件。

123456789101112131415161718192021222324252627282930313233343536 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存放的目录中。

docker镜像更新

我们构建镜像可能会存在更新的情况。这里介绍两种方式更新镜像。

直接使用官方初始镜像构建的镜像更新

这种方式的初始镜像为官方镜像,即FROM 的镜像为官方镜像,比如tomcat:latest    ,node:10.16  , microsoft/dotnet:2.2-aspnetcore-runtime 等都是官方的基础镜像。我所有做的公司业务镜像都是以这种方式构建。这里以基础平台的dotnet 镜像为例。

123456 FROM microsoft/dotnet:2.2-aspnetcore-runtimeRUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.soRUN apt-get update  && apt-get install -y net-tools  procps lsof  sysstat libfontconfig1 libgdiplus && ln-s libgdiplus.so gdiplus.dll#ENV LANG C.UTF-8COPY  ./JF-ISBM /etc/JF-ISBMCMD ["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。

123 FROM 1.xxx.xxx.xxx/zhxy/jf-isbm:v2.0-20190830COPY  ./JF-ISBM /etc/JF-ISBMCMD ["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

123 [root@localhost jf-isbm]# docker-compose buildERROR: Version in "./docker-compose.yml" is unsupported. You might be seeing this error because you're using the wrong Compose fileversion. 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 fileto 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  推送镜像

镜像的名需要有私有仓库地址标识


《Dockerfile和docker-compose应用.doc》

下载本文的Word格式文档,以方便收藏与打印。