docker使用小记3-dockerfile自定义镜像

最近公司项目需要使用docker进行项目部署,现记录下这段时间的学习内容,本章主要记录dockerfile来自定义镜像。当然我们还可以用commit通过容器来自定义镜像,但是我这次基本都是用dockerfile来生成镜像,commit等以后有用到再作记录。

一、dockerfile命令

FROM 指定基础镜像,放在第一行,其格式为:

1 #语法:
2 FROM <image> 
3 FROM <image>:<tag>
4 FROM <image>:<digest>

 

若想构建一个最小的镜像,不想基于其他任何镜像时。可直接

1 FROM scratch

 

MAINTAINER指令允许你设置生成这个镜像的作者。

1 MAINTAINER lzq <xxx@xx.com>

 

也可以使用LABEL设置镜像相关信息

1 LABEL author="作者:xxx"
2 LABEL version="版本:v0.1"
3 LABEL desc="说明:test"

要查看时,可以使用docker inspect 镜像名或id 进行查看

 

ENV 设置环境变量,如java_home等。

1 ENV <key> <value>
2 ENV <key>=<value> ...

 

VOLUME 定义匿名卷,在我们运行容器时,有些数据是需要被持久化保存的,比如mysql容器中的数据,tomcat容器中的logs日志等,但是一般来说容器内的数据会随着容器的删除而消失,就算是用相同镜像再去生成容器,运行时产生的数据也不会存在。所以当我们需要对某些数据进行持久化时,可以在生成容器时加上【-v 卷名或主机目录:容器目录 】的参数来对容器某个或多个目录进行挂载,这样的话就算之后容器被删除,其被挂载的目录数据仍会存在于主机之中,而且挂载之后对卷或主机目录的修改会同步到容器对应目录中,反之亦然。而如果挂载的主机卷或者目录一开始就存在数据,则无论容器对应目录内有无数据,都会被隐藏,显示的是挂载主机卷或目录存在的数据。一般来说-v参数如果没有指定卷名或者主机目录,只指定容器目录的话,那么docker会自动为容器生成一个匿名卷,这样的话效果跟在dockerfile中用VOLUME命令是一样的,但每次都靠执行run命令生成容器时去添加-v参数的话有时会遗漏。所以我们可以在dockerfile文件使用VOLUME命令先定义匿名卷,对需要持久化的目录进行挂载,这样的话如果生成容器时忘了使用-v参数去挂载容器重要目录,docker也会生成匿名卷将数据保存。而如果在run时使用-v参数对dockerfile中使用VOLUME挂载的目录进行定义时(如指定卷名或者主机目录),则docker不会生成匿名卷,而是根据当前指定的卷名或主机目录对容器目录进行挂载。

例如这是一份docekrfile文件:

 1 FROM centos:latest
 2 RUN groupadd -r redis && useradd  -r -g redis redis
 3 RUN yum -y update &&  yum -y install epel-release && yum -y install redis && yum -y install net-tools
 4  
 5 RUN mkdir -p /config && chown -R redis:redis /config
 6  
 7  
 8 VOLUME /share/data      #声明容器中/share/data为匿名卷
 9  
10  
11 EXPOSE 6379

那么使用该Dockerfile构建镜像的为

1 #docker build -t image-redis    //构建镜像image-redis
2 ......
3 #docker run -itd -name redis1 -v /data:/share/data image-redis    //运行一个容器并且将当前机器的/data目录绑定到容器的匿名卷中
4 .....
5 #docker run -itd  -name redis2 image-redis     //运行一个容器但是不绑定目录到容器的匿名卷,这时候在/var/lib/docker/volumes(不同版本目录不一样)中就会创建一个目录绑定匿名卷
6 .....

删除数据卷

数据卷 是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v 这个命令。

数据卷可能会占据很多空间,可以使用以下命令清理掉没有容器使用的数据卷
谨慎操作,这需要你确认现在暂时没有使用数据卷在以后也不会再使用,里面也没有有价值的数据。

1 docker volume prune

 

COPY 复制文件,主要就是构建镜像时,进行拷贝文件到镜像的指定路径下,格式为:

1 COPY <源路径>... <目标路径>
2 COPY ["<源路径1>",... "<目标路径>"]

 

ADD 更高级的复制文件,ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。比如<源路径>可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到<目标路径>去,而如果原路径是个压缩包的话,ADD会在复制完毕后在目标目录将文件进行解压。

1 ADD jdk-8u45-linux-x64.tar.gz /usr/local

 

EXPOSE 设置监听端口,为镜像设置监听端口,容器运行时会监听改端口,格式为:

1 EXPOSE <port> [<port>/<protocol>...]
2 EXPOSE 80
3 EXPOSE 80/udp

 

RUN 执行命令,在镜像的构建过程中执行特定的命令,并生成一个中间镜像。格式:

1 RUN <command>
2 或者
3 RUN ["executable", "param1", "param2"]

这也是很常用的一个功能了。
第一种后边直接跟shell命令

  • 在linux操作系统上默认 /bin/sh -c
  • 在windows操作系统上默认 cmd /S /C

第二种是类似于函数调用。

可将executable理解成为可执行文件,后面就是两个参数。

两种写法比对:

1 RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME
2 RUN ["/bin/bash", "-c", "echo hello"]

注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层.多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。

RUN书写时的换行符是\

 

CMD 启动时命令,功能为容器启动时要运行的命令,有三种写法:

1 1. CMD ["executable","param1","param2"]
2 2. CMD ["param1","param2"]
3 3. CMD command param1 param2

第三种比较好理解了,就时shell这种执行方式和写法,第一种和第二种其实都是可执行文件加上参数的形式:
举例说明两种写法:

1 CMD [ "sh", "-c", "echo $HOME" ]
2 CMD [ "echo", "$HOME" ]

补充细节:这里边包括参数的一定要用双引号,就是双引号",不能是单引号。千万不能写成单引号。原因是参数传递后,docker解析的是一个JSON array

 

ENTRYPOINT 启动默认命令,ENTRYPOINT 用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过 ENTRYPOINT 指定的程序都会被设置为默认程序。ENTRYPOINT 有以下两种形式:

1 ENTRYPOINT ["executable", "param1", "param2"]
2 ENTRYPOINT command param1 param2

ENTRYPOINT 与 CMD 非常类似,不同的是通过docker run执行的命令不会覆盖 ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINTDockerfile 中只允许有一个 ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT 指令。
docker run运行容器时指定的参数都会被传递给ENTRYPOINT,且会覆盖 CMD 命令指定的参数。如,执行docker run <image> -d时,-d 参数将被传递给入口点。
也可以通过docker run --entrypoint重写 ENTRYPOINT 入口点。

 

WORKDIR 指定工作目录,用于在容器内设置一个工作目录:

1 WORKDIR /opt/docker/workdir

通过WORKDIR设置工作目录后,Dockerfile 中其后的命令RUNCMDENTRYPOINTADDCOPY等命令都会在该目录下执行。

 

USER 指定当前用户,用于指定运行镜像所使用的用户:

1 USER lzq

使用USER指定用户后,Dockerfile 中其后的命令RUNCMDENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。

 

二、使用dockerfile构建自定义镜像

通过上面的命令我们可以编写一个dockerfile来自定义我们的镜像,现在我们来构建一个tomcat镜像,首先我们得准备jdk和tomcat,我们可以在dockerfile中去下载,但我这里已经下载了下来了

dockerfile当前目录:

dockerfile内容:

 

 

 该文件内容定义了:

1、使用了centos作为基础镜像

2、复制并解压了jdk,定义了JAVA环境变量

3、复制并解压了tomcat,定义了CATALINA_HOME

4、设置8080监听接口

5、定义tomcat的webapps目录为匿名卷

6、复制web文件夹中的文件到容器webapps目录中

7、设置tomcat的bin目录为工作目录

8、设置容器启动时默认启动tomcat

 

接下来我们用这个文件生成一个镜像:

1 docker build -t tomcat .

 

 这样就生成了一个自定义tomcat镜像,我们可以运行docker images查看

 

 可见tomcat镜像已经生成,接下来我们用该镜像生成一个容器:

1  docker run -itd -p 9000:8080 --name tomcat tomcat

 

 容器已经生成,我们可以输入docker ps 查看正在运行的容器:

 

 可见容器已经在运行,此时我们打开浏览器,输入ip:9000并回车,可以看到

 

 出现如上页面,说明我们容器中的tomcat也随着容器启动而启动了。

 

参考资料:https://blog.lqdev.cn/2018/08/04/docker/docker-five/

     https://blog.csdn.net/fangford/article/details/88873104

posted @ 2019-10-15 16:39  葱香排骨面  阅读(451)  评论(0编辑  收藏  举报