1,Dcockerfile是什么
docker推荐使用dockerfile的定义文件和docker build命令来构建镜像。dockerfile使用基本的基于DSL(面向领域语言)语法的指令来构建Docker镜像。另一种创建Docker镜像的方式是使用docker commit,不推荐使用。
2,dockerfile的基本组成
dockerfile有一系列指令和参数组成,每条指令都必须为大写,执行时按顺序从上到下执行,所以应该根据需要合理安排指令的顺序。
Dockerfile的基本组成及说明:
组成 | 说明 |
---|---|
基础镜像信息 | FROM |
维护者信息 | MAINTAINER |
镜像操作指令 | RUN、(COPY/ADD)、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME等 |
容器启动时执行指令 | CMD、ENTRYPOINT |
2.1 FROM
指定基础镜像,如:
FROM ubuntu:18.04
2.2 MAINTAINER
指定该镜像的作者及电子邮件等信息
MAINTAINER lisen "xxxxx@163.com"
2.3 RUN
在镜像内部执行的指令,如安装软件,配置基础环境等,可用\进行换行
RUN echo 'hello' > /usr/local/file.txt
也可以使用exec格式,RUN ["命令", "参数1","参数2"], 如:
RUN ["apt-get", "install", "-y", "ubuntu"]
2.4 COPY
将主机的文件复制到镜像中,如果目的目录不存在,docker会自动创建所需目录结构。注意:该命令只是单纯的复制,并不会做文件的提取解压工作。
COPY file.txt /usr/local
注意:需复制的文件或目录必须要放在Dockerfile文件的同级目录下。
2.5 ADD
将宿主机文件复制到镜像,该命令与COPY命令作用和用法是一样的,但ADD命令会对压缩文件做解压和提取操作(tar,gzip等)
2.6 EXPOSE
暴露镜像的端口供主机做端口映射,运行镜像时使用-P参数将镜像端口与宿主机随机端口或指定端口做映射。
示例:
EXPOSE 8080
可以通过docker port查看到端口的映射情况。
2.7 WORKDIR
WORKDIR指令用来在从镜像创建一个新容器时,在容器内部设置一个工作目录,ENTRYPOINT和/或CMD指定的程序会在这个目录下执行。
我们可以使用该指令为Dockerfile中后续的一系列指令设置工作目录,也可以为最终的容器设置工作目录。
示例:
WORKDIR /opt/webapp/db
RUN bundle install
WORKDIR /opt/webapp
ENTRYPOINT [ "rackup" ]
这里,我们将工作目录切换为/opt/webapp/db后运行了bundle install命令,之后又将工作目录设置为/opt/webapp,最后设置了ENTRYPOINT指令来启动rackup命令。
可以通过-w标志在运行时覆盖工作目录,如代码清单4-57所示。
代码清单4-57 覆盖工作目录
$ sudo docker run -ti -w /var/log ubuntu pwd
/var/log
该命令会将容器内的工作目录设置为/var/log。
2.8 ONBUILD
当一个包含ONBUILD命令的镜像被用作其他镜像的基本镜像时,ONBUILD指令将执行。
例如:base-image
FROM ubuntu
ONBUILD ADD . /var/www
......
当使用base-image作基础镜像创建imageA时,
FROM base-image
......
则base-image基础镜像的 ONBUILD指令会执行
2.9 USER
指定镜像以什么用户执行
USER user01
2.10 VOLUME
向基于镜像创建的容器添加卷。一个卷是可以存在于一个或者多个容器内的特定的目录,这个目录可以绕过联合文件系统,并提供如下共享数据或者对数据进行持久化的功能。
示例:
#使用VOLUME 指令向容器添加volume
VOLUME /data
#可以添加多个
VOLUME ["/data1","/data2"] #添加多个
注意:VOLUME指令不能挂载宿主机中指定的目录,这是为了保证Dockerfile的可移植性,因为不能保证所有的宿主机都有对应的目录。
2.11 CMD
CMD指令用于指定一个容器启动时要运行的命令,这有点儿类似于RUN指令,只是RUN指令是指定镜像被构建时要运行的命令,而CMD是指定容器被启动时要运行的命令。
例如:
$ sudo docker run -i -t jamtur01/static_web /bin/true
在Dockerfile中以下的CMD指令是等效的
CMD ["/bin/true"]
可以为要运行的命令指定参数,以下代码清单
CMD ["/bin/bash", "-l"]
这里我们将-l参数传递给了/bin/bash命令。
需要注意的是使用docker run命令可以覆盖CMD指令,如果我们在Dockerfile里指定了CMD指令,而同时在docker run命令行中也指定了要运行的命令,命令行中指定的命令会覆盖Dockerfile中的CMD指令。
2.12 ENTRYPOINT
ENTRYPOINT指令与CMD指令很相似,它们的区别在于ENTRYPOINT指令提供的命令不容易在启动容器时被覆盖,docker run命令行中指定的任何参数都会当作参数再次传给ENTRYPOINT命令。
ENTRYPOINT命令的一个示例:
ENTRYPOINT ["/usr/sbin/nginx"]
与CMD命令相似,ENTRYPOINT命令可以使用数组形式指定参数,如以下代码清单:
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
若我们构建镜像,并将ENTRYPOINT设置为ENTRYPOINT["/usr/sbin/nginx"],用docker build构建镜像,代码清单如下:
$ sudo docker build -t="jamtur01/static_web" .
然后用如下命令启动容器:
sudo docker run –t -i jamtur01/static_web -g "daemon off;"
则命令行参数-g "daemon off;"会传递给ENTRYPOINT指定的命令。在这里该命令为/usr/sbin/nginx -g "daemon off;"。该命令会以前台运行的方式启动Nginx守护进程,此时这个容器就会作为一台Web服务器来运行
3,dockerfile示例
该示例通过Dockerfile的方式构建一个安装了jdk的镜像。
3.1 准备
创建一个目录,在该目录中放入jdk,并创建一个Dockerfile文件。如图:
Dockerfile文件如下:
#0.vi Dockerfile进入编辑模式
#1.指定基础镜像,并且必须是第一条指令
FROM ubuntu:latest
#2.指明该镜像的作者和其电子邮件
MAINTAINER zs "zs@qq.com"
#3.在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录
WORKDIR /usr/local/java
#4.一个复制命令,把jdk安装文件复制到镜像中,语法:ADD <src>... <dest>,注意:jdk*.tar.gz使用的是相对路径
ADD jdk-8u151-linux-x64.tar.gz /usr/local/java/
#5.配置环境变量
ENV JAVA_HOME=/usr/local/java/jdk1.8.0_151
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH=$JAVA_HOME/bin:$PATH
#容器启动时需要执行的命令
#CMD ["java","-version"]
注:在构建镜像时基础镜像请使用指定版本,而不要使用latest
3.2 将该目录上传至linux
3.3 构建镜像
登录linux,进入dockerfilejdk目录,通过docker build 构建镜像
3.4 通过镜像运行容器
查看我们刚才创建的镜像
root@ubuntu:/home/lisen/dockerfilejdk# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jkd1.8-container latest f61711334bc6 13 seconds ago 449MB
通过镜像运行容器
root@ubuntu:/# docker run -it jkd1.8-container /bin/bash
root@ba5158079806:/usr/local/java#
4,建议
- 精简镜像用途:尽量让每个镜像的用途都比较集中单一,避免构造大而复杂、多功能的镜像
- 选用合适的基础镜像:容器的核心是应用,选择过大的父镜像(如Ubuntu系统镜像)会造成最终生成应用镜像的膝肿,推荐选用瘦身过的应用镜像或者较为小巧的系统镜像(alpine)