Dockerfile是docker构建镜像的基础,也是docker区别于其他容器的重要特征,正是有了Dockerfile,docker的自动化和可移植性才成为可能。不论是开发还是运维,学会编写Dockerfile几乎是必备的。
1.Dockerfile语法
Dockerfile中每行都以一个关键字为行首,如果一行内容过长,使用“\”换行。
2.关键字
- FROM:Dockerfile的第一行,指定从哪个基础镜像开始构建。
FROM centos
FROM java:8
FROM python:3.6.5
如果当前要构建的镜像本身就是一个基础镜像
FROM scratch
- LABEL:描述镜像信息(镜像生成后,可以使用docker inspect查看镜像信息)。
LABEL key="value"
LABEL maintainer="author <xxx@yyy.com>"
LABEL version="1.2"
- ENV:设置环境变量。
ENV TEST 1
-
RUN:构建镜像时执行shell命令,多条命令之间使用用
&&
连接,还可以使用\
换行。
RUN apt-get -y update
RUN apt-get -y install nginx
- ADD:将外部文件拷贝到镜像里,src可以为url
ADD http://nicescale.com/ /data/nicescale.tgz
- COPY:将编译机本地文件拷贝到镜像文件系统中(与ADD类似,不能使用URL)。
COPY /tmp/nicescale.tgz /data/nicescale.tgz
- WORKDIR:设置工作目录
WORKDIR /var/www
- USER:设置用户
USER nginx
- VOLUME:设置容器与宿主机数据共享及数据持久化
也可以在创建容器时使用-v选项 docker run -v <host_dir>:<container_dir> IMAGE
(指定宿主机映射目录) 或docker run -v <host_dir>:<container_dir> IMAGE
(使用默认的映射目录/var/lib/docker/volumes/<container_id>)达到同样效果
VOLUME ['/data']
- EXPOSE:指定监听的端口。
EXPOSE 80 443
- ENTRYPOINT:指定容器启动时执行的命令(Dockerfile中仅最后一条ENTRYPOINT有效)。
# exec方式
ENTRYPOINT ['/bin/bash', 'echo','hello world']
# shell方式
ENTRYPOINT echo "hello world"
docker run
命令后如果跟了内容,会作为ENTRYPOINT
指定的命令的参数,如:
ENTRYPOINT ["/bin/ls"]
如果用以下命令创建并启动容器
docker run <image> -l
那么ENTRYPOINT中指定的命令最终会与-l
参数一起运行
/bin/ls -l
-
CMD:指定容器启动时执行的命令(Dockerfile中仅最后一条CMD有效,并且
docker run
指定的命令会替代CMD指定的命令)。
CMD ["/bin/bash","echo","service started..."]
CMD echo "service started..."
当CMD与ENTRYPOINT同时使用时,CMD后的内容会作为ENTRYPOINT后命令的默认参数,如果docker run后又附带了内容,则附带内容会替换CMD后的内容,作为参数ENTRYPOINT后命令的参数。这样CMD与ENTRYPOINT同时使用,能够构建一个既有默认参数又支持参数传入的镜像。
3.创建镜像
通过当前目录下的Dockerfile文件构建镜像
docker build -t IMAGE:VERSION .
通过指定目录下的Dockerfile文件构建镜像
docker build -t IMAGE:VERSION /app/
4.镜像维护
使用Dockerfile文件维护镜像相对比较容易,只需要修改Dockerfile的部分内容,通过docker build重新构建即可。另外还可以通过“-t”选项指定一个新版本,在新旧两个版本间快速切换。
5.Dockerfile实例
5.1 官方镜像hello-world
# 从零开始构建基础镜像
FROM scratch
# 复制可执行文件到docker虚拟机根目录
COPY hello /
# 启动后运行可执行文件
CMD ["/hello"]
5.2 以centos为基础镜像,创建一个新的镜像,用echo输出字符串
Dockerfile文件内容如下
FROM centos
CMD echo "hello docker $(date)"
创建镜像
$ docker build -t test .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> e934aafc2206
Step 2/2 : CMD echo "hello docker $(date)"
---> Running in 9ad050c6be7b
Removing intermediate container 9ad050c6be7b
---> 4b412e803011
Successfully built 4b412e803011
Successfully tagged test:latest
通过镜像创建容器并启动(不指定启动时运行的命令)
$ docker run test --name test1
hello docker Thu May 17 05:09:22 UTC 2018
通过镜像创建容器并启动(指定启动时运行的命令),此时CMD中指定的命令不会执行
# 指定启动时以交互模式在终端运行bash
$ docker run --name test2 -it test /bin/bash
[root@9d4414207eeb /]#
# 指定启动时pwd命令
$ docker run test2 pwd
/
5.3 打包SpringBoot镜像
Dockerfile
FROM openjdk:8-jre
ADD crs-core-0.0.1-SNAPSHOT.jar /opt/jar/crs-core.jar
EXPOSE 8080
CMD ["java","-jar","/opt/jar/crs-core.jar"]
打包镜像过程如下
$ sudo docker build -t crs-core:0.0.1 .
Sending build context to Docker daemon 41.98MB
Step 1/4 : FROM openjdk:8-jre
---> dd20fb277e3c
Step 2/4 : ADD crs-core-0.0.1-SNAPSHOT.jar /opt/jar/crs-core.jar
---> Using cache
---> 021003891a14
Step 3/4 : EXPOSE 8080
---> Using cache
---> b6f8e3d010dd
Step 4/4 : CMD ["java","-jar","/opt/jar/crs-core.jar"]
---> Running in 5b6fb9d78093
Removing intermediate container 5b6fb9d78093
---> 6d9938a0f6be
Successfully built 6d9938a0f6be
Successfully tagged crs-core:0.0.1
查看镜像
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
crs-core 0.0.1 6d9938a0f6be 47 seconds ago 485MB
openjdk 8-jre dd20fb277e3c 2 weeks ago 443MB
启动容器
$ sudo docker run --name crs-core -p 9090:8080 -d crs-core:0.0.1
52dc83fe7542f1958e509bdd905a91f0ac967fe6dd094486c6c13028bc782c4a
[clinflash@localhost crs-docker]$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
52dc83fe7542 crs-core:0.0.1 "java -jar /opt/jar/…" 6 seconds ago Up 5 seconds 0.0.0.0:9090->8080/tcp crs-core
5.4 更多实例
To be continued...