1.1 Dockerfile简介
什么是Dockerfile
Dockerfile就是制作docker镜像的脚本,将我们在上面学到的docker镜像,使用自动化的方式实现出来。
注意事项:
- 文件名首字母大写
- 存储Dockerfile的目录, 尽量是空目录
- 制作的镜像功能尽量单一
- 制作步骤要尽可能精简
dockerfile的组成
dockerfile中的注释使用: #
- 基础镜像信息
- 要制作的新的镜像, 基于那个镜像来制作的
- 通过 docker images 查看
- 维护者信息
- 这个dockerfile是谁写的
- 镜像操作指令
- 基于原始进行进行的操作
- 容器启动指令
- 基于第三步得到了新镜像
- 新的镜像启动之后, 在容器中默认执行的指令
Dockerfile使用命令:
#构建镜像命令格式:
docker build -t [镜像名]:[版本号][Dockerfile所在目录]
#构建样例:
docker build -t nginx:v0.2 /opt/dockerfile/nginx/
#参数详解:
-t 指定构建后的镜像信息,
/opt/dockerfile/nginx/ 则代表Dockerfile存放位置,如果是当前目录,则用 .(点)表示
1.2 Dockerfile快速入门
接下来我们快速的使用Dockerfile来基于ubuntu创建一个定制化的镜像:nginx。
#创建Dockerfile专用目录
:~$ mkdir ./docker/images/nginx -p
:~$ cd docker/images/nginx/
#创建Dockerfile文件
:~/docker/images/nginx$ vim Dockerfile
dockerfile内容
# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER panda kstwoak47@163.com
# 执行命令
RUN mkdir hello
RUN mkdir world
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt-get update
RUN apt-get install nginx -y
# 对外端口
EXPOSE 80
进行构建操作
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.1 .
#查看新生成镜像
:~/docker/images/nginx$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-nginx v0.1 a853de1b8be4 9 seconds ago 208MB
nginx latest e548f1a579cf 6 days ago 109MB
ubuntu latest 0458a4468cbc 4 weeks ago 112MB
#查看构建历史
:~/docker/images/nginx$ docker history a853de1b8be4
IMAGE CREATED CREATED BY SIZE COMMENT
#镜像 创建时间 依赖命令 大小 评论
a853de1b8be4 41 seconds ago /bin/sh -c #(nop) EXPOSE 80 0B
925825b680fd 42 seconds ago /bin/sh -c apt-get install nginx -y 56.5MB
4c57d6c99603 About a minute ago /bin/sh -c apt-get update 40MB
b6d030a0d123 About a minute ago /bin/sh -c sed -i's/security.ubuntu.com/mir… 2.77kB
3357bf8069ca About a minute ago /bin/sh -c sed -i's/archive.ubuntu.com/mirr… 2.77kB
7bfb90c1e20d About a minute ago /bin/sh -c mkdir world 0B
972d6ab76d01 About a minute ago /bin/sh -c mkdir hello 0B
a76394bfad01 About a minute ago /bin/sh -c #(nop) MAINTAINER panda kstwoak4… 0B
#注意:
因为容器没有启动命令,所以肯定访问不了
优化刚刚的Dockerfile文件
# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER panda kstwoak47@163.com
# 执行命令
RUN mkdir hello && mkdir world
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && \sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt-get update && apt-get install nginx -y
# 对外端口
EXPOSE 80
运行修改好的Dockerfile进行构建
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.2 .
:~/docker/images/nginx$ docker history ubuntu-nginx:v0.2
IMAGE CREATED CREATED BY SIZE COMMENT
eaba9bd1c4ac 3 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B
ed08d6e29eb1 3 minutes ago /bin/sh -c apt-get update && apt-get install… 96.5MB
eef6238ec5bd 6 minutes ago /bin/sh -c sed -i 's/archive.ubuntu.com/mirr… 2.77kB
58f755a1b29c 6 minutes ago /bin/sh -c mkdir hello && mkdir world 0B
a76394bfad01 25 minutes ago /bin/sh -c #(nop) MAINTAINER panda kstwoak4… 0B
#对比两个镜像的大小
:~/docker/images/nginx$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-nginx v0.2 eaba9bd1c4ac 7 seconds ago 208MB
ubuntu-nginx v0.1 a853de1b8be4 21 minutes ago 208MB
#深度对比连个镜像的大小
:~/docker/images/nginx$ docker inspect a853de1b8be4
"Size": 208237435,
"VirtualSize": 208237435,
:~/docker/images/nginx$ docker inspect eaba9bd1c4ac
"Size": 208234662,
"VirtualSize": 208234662,
Dockerfile构建过程:
从基础镜像1运行一个容器A
遇到一条Dockerfile指令,都对容器A做一次修改操作
执行完毕一条命令,提交生成一个新镜像2
再基于新的镜像2运行一个容器B
遇到一条Dockerfile指令,都对容器B做一次修改操作
执行完毕一条命令,提交生成一个新镜像3
…
**构建过程镜像介绍
构建过程中,创建了很多镜像,这些中间镜像,我们可以直接使用来启动容器,通过查看容器效果,从侧面能看到我们每次构建的效果。提供了镜像调试的能力
1.3 基础指令详解
FROM
FROM
#格式:
FROM <image>
FROM <image>:<tag>
#解释:
#FROM 是 Dockerfile 里的第一条而且只能是除了首行注释之外的第一条指令
#可以有多个FROM语句,来创建多个image
#FROM 后面是有效的镜像名称,如果该镜像没有在你的本地仓库,那么就会从远程仓库Pull取,如果远程也没有,就报错失败
#下面所有的 系统可执行指令 在 FROM 的镜像中执行。
MAINTAINER
MAINTAINER
#格式:
MAINTAINER <name>
#解释:
#指定该dockerfile文件的维护者信息。类似我们在docker commit 时候使用-a参数指定的信息
RUN
RUN
#格式:
RUN <command> (shell模式)
RUN["executable", "param1", "param2"] (exec 模式)
#解释:
#表示当前镜像构建时候运行的命令,如果有确认输入的话,一定要在命令中添加 -y
#如果命令较长,那么可以在命令结尾使用 \ 来换行
#生产中,推荐使用上面数组的格式
#注释:
#shell模式:类似于 /bin/bash -c command
#举例: RUN echo hello
#exec模式:类似于 RUN["/bin/bash", "-c", "command"]
#举例: RUN["echo", "hello"]
EXPOSE
EXPOSE
#格式:
EXPOSE <port> [<port>...]
#解释:
设置Docker容器对外暴露的端口号,Docker为了安全,不会自动对外打开端口,如果需要外部提供访问,
还需要启动容器时增加-p或者-P参数对容器的端口进行分配。
# docker run -itd -p 8888:80
EXPOSE 80
1.4 运行时指令详解
CMD
CMD
#格式:
CMD ["executable","param1","param2"] (exec 模式)推荐
CMD command param1 param2 (shell模式)
CMD ["param1","param2"] 提供给ENTRYPOINT的默认参数;
#解释:
#CMD指定容器启动时默认执行的命令
#每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行
#如果你在启动容器的时候使用docker run 指定的运行命令,那么会覆盖CMD命令。
#举例: CMD ["/usr/sbin/nginx","-g","daemon off;"]
"/usr/sbin/nginx" nginx命令
"-g" 设置配置文件外的全局指令
"daemon off;" 后台守护程序开启方式 关闭
#CMD指令实践:
#修改Dockerfile文件内容:
#在上一个Dockerfile文件内容基础上,末尾增加下面一句话:
CMD ["/usr/sbin/nginx","-g","daemon off;"]
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.3 .
#根据镜像创建容器,创建时候,不添加执行命令
:~/docker/images/nginx$ docker run --name nginx-1 -itd ubuntu-nginx:v0.3
#根据镜像创建容器,创建时候,添加执行命令/bin/bash
:~/docker/images/nginx$ docker run --name nginx-2 -itd ubuntu-nginx:v0.3 /bin/bash
docker ps
#发现两个容器的命令行是不一样的
itcast@itcast-virtual-machine:~/docker/images/nginx$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED NAMES
921d00c3689f ubuntu-nginx:v0.3 "/bin/bash" 5 seconds ago nginx-2
e6c39be8e696 ubuntu-nginx:v0.3 "/usr/sbin/nginx -g …" 14 seconds ago nginx-1
ENTRYPOINT
ENTRYPOINT
#格式:
ENTRYPOINT ["executable", "param1","param2"] (exec 模式)
ENTRYPOINT command param1 param2 (shell 模式)
#解释:
#和CMD 类似都是配置容器启动后执行的命令,并且不会被docker run 提供的参数覆盖。
#每个Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。
#生产中我们可以同时使用ENTRYPOINT 和CMD,
#想要在docker run 时被覆盖,可以使用"docker run --entrypoint"
#ENTRYPOINT指令实践:
#修改Dockerfile文件内容:
#在上一个Dockerfile 文件内容基础上,修改末尾的CMD 为ENTRYPOINT:
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.4 .
#根据镜像创建容器,创建时候,不添加执行命令
:~/docker/images/nginx$ docker run --name nginx-3 -itd ubuntu-nginx:v0.4
#根据镜像创建容器,创建时候,添加执行命令/bin/bash
:~/docker/images/nginx$ docker run --name nginx-4 -itd ubuntu-nginx:v0.4 /bin/bash
#查看ENTRYPOINT是否被覆盖
:~/docker/images/nginx$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED NAMES
e7a2f0d0924e ubuntu-nginx:v0.4 "/usr/sbin/nginx -g …" 59 seconds ago nginx-4
c92b2505e28e ubuntu-nginx:v0.4 "/usr/sbin/nginx -g …" About a minute ago nginx-3
#根据镜像创建容器,创建时候,使用--entrypoint参数,添加执行命令/bin/bash
docker run --entrypoint "/bin/bash" --name nginx-5 -itd ubuntu-nginx:v0.4
#查看ENTRYPOINT是否被覆盖
:~/docker/images/nginx$ docker ps
CONTAINER ID IMAGE COMMAND CREATED NAMES
6c54726b2d96 ubuntu-nginx:v0.4 "/bin/bash" 3 seconds ago nginx-5
CMD ENTRYPOINT 综合使用实践
#修改Dockerfile文件内容:
# 在上一个Dockerfile文件内容基础上,修改末尾的ENTRYPOINT
:~/docker/images/nginx$ vim Dockerfile
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-g"]
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.5 .
#根据镜像创建容器,创建时候,不添加执行命令
:~/docker/images/nginx$ docker run --name nginx-6 -d ubuntu-nginx:v0.5
#查看效果
:~/docker/images/nginx$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED NAMES
e28875d281eb ubuntu-nginx:v0.5 "/usr/sbin/nginx -g" 9 seconds ago nginx-6
#根据镜像创建容器,创建时候,不添加执行命令,覆盖cmd的参数 -g "daemon off;"
:~/docker/images/nginx$ docker run --name nginx-7 -d ubuntu-nginx:v0.5 -g "daemon off;"
#查看效果
itcast@itcast-virtual-machine:~/docker/images/nginx$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED NAMES
e5addad86ef5 ubuntu-nginx:v0.5 "/usr/sbin/nginx -g …" 5 seconds ago nginx-7
#注释:
#任何docker run设置的命令参数或者CMD指令的命令,都将作为ENTRYPOINT 指令的命令参数,追加到ENTRYPOINT指令之后
1.5 文件编辑指令详解
ADD
#ADD
#格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
#解释:
# 将宿主机文件拷贝到容器目录中
# 如果宿主机文件是可识别的压缩包, 会进行解压缩 -> tar
ADD 宿主机文件 容器目录/文件
# ADD ["宿主机文件", "容器目录"]
- 宿主机文件一般放到Dockerfile对应的目录中
- 容器目录, 有可能存在, 有可能不存在
- 存在: 直接拷贝到容器目录
- 不存在: 先在容器中创建一个, 再拷贝
ADD ["a.txt", "/home/go/a.txt"]
- 第二个参数如果指定的是一个文件名
- 这个文件存在: 直接覆盖
- 不存在: 直接拷贝
#ADD实践:
#拷贝普通文件
:~/docker/images/nginx$ vim Dockerfile
#Dockerfile文件内容
# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER panda kstwoak47@163.com
# 执行命令
ADD ["sources.list","/etc/apt/sources.list"]
RUN apt-get clean
RUN apt-get update
RUN apt-get install nginx -y
# 对外端口
EXPOSE 80
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.6 .
#根据镜像创建容器,创建时候,不添加执行命令进入容器查看效果
docker run --name nginx-8 -it ubuntu-nginx:v0.6
#拷贝压缩文件
tar zcvf this.tar.gz ./*
#Dockerfile文件内容
...
# 执行命令
...
# 增加文件
ADD ["linshi.tar.gz","/nihao/"]
...
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.7 .
#根据镜像创建容器,创建时候,不添加执行命令进入容器查看效果
docker run --name nginx-9 -it ubuntu-nginx:v0.7
:~/docker/images/nginx$ docker run --name nginx-9 -it ubuntu-nginx:v0.7
COPY
#COPY
#格式:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
#解释:
#COPY 指令和ADD 指令功能和使用方式类似。只是COPY 指令不会做自动解压工作。
#单纯复制文件场景,Docker 推荐使用COPY
#COPY实践
#修改Dockerfile文件内容:
# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER panda kstwoak47@163.com
# 执行命令
ADD ["sources.list","/etc/apt/sources.list"]
RUN apt-get clean
RUN apt-get update
RUN apt-get install nginx -y
COPY ["index.html","/var/www/html/"]
# 对外端口
EXPOSE 80
#运行时默认命令
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
index.html 文件内容:
<h1>hello world </h1>
<h1>hello docker </h1>
<h1>hello nginx</h1>
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.8 .
#根据镜像创建容器,创建时候,不添加执行命令
:~/docker/images/nginx$ docker run --name nginx-10 -itd ubuntu-nginx:v0.8
#查看nginx-10信息
:~/docker/images/nginx$docker inspect nginx-10
#浏览器访问nginx查看效果
VOLUME
#VOLUME
#格式:
VOLUME ["/data"]
#解释:
#VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点
#通过VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。
#举例:
VOLUME ["/var/lib/tomcat7/webapps/"]
VOLUME实践
#VOLUME实践
#修改Dockerfile文件内容:
#将COPY替换成为VOLUME
:~/docker/images/nginx$vim Dockerfile
VOLUME ["/helloworld/"]
...
#构建镜像
:~/docker/images/nginx$docker build -t ubuntu-nginx:v0.9 .
#创建数据卷容器
:~/docker/images/nginx$docker run -itd --name nginx-11 ubuntu-nginx:v0.9
#查看镜像信息
:~/docker/images/nginx$docker inspect nginx-11
#验证操作
:~/docker/images/nginx$docker run -itd --name vc-nginx-1 --volumes-from nginx-11 nginx
:~/docker/images/nginx$docker run -itd --name vc-nginx-2 --volumes-from nginx-11 nginx
#进入容器1
:~/docker/images/nginx$docker exec -it vc-nginx-1 /bin/bash
:/# echo 'nihao itcast' > helloworld/nihao.txt
#进入容器2
:~/docker/images/nginx$ docker exec -it vc-nginx-2 /bin/bash
:/# cat helloworld/nihao.txt
1.6 环境指令详解
ENV
#ENV
#格式:
ENV <key> <value> (一次设置一个环节变量)
ENV <key>=<value> ... (一次设置一个或多个环节变量)
ENV HELLO 12345
ENV HELLO=12345
ENV HELLO=12345 WORLD=12345 NIHAO=12345
#解释:
#设置环境变量,可以在RUN 之前使用,然后RUN 命令时调用,容器启动时这些环境变量都会被指定
ENV实践
#ENV实践:
#命令行创建ENV的容器
:~$ docker run -e NIHAO="helloworld" -itd --name ubuntu-111 ubuntu /bin/bash
#进入容器ubuntu-111
:~$ docker exec -it ubuntu-111 /bin/bash
:/# echo $NIHAO
#修改Dockerfile文件内容:
#在上一个Dockerfile 文件内容基础上,在RUN 下面增加一个ENV
ENV NIHAO=helloworld
...
#构建镜像
docker build -t ubuntu-nginx:v0.10 .
#根据镜像创建容器,创建时候,不添加执行命令
docker run --name nginx-12 -itd ubuntu-nginx:v0.10
docker exec -it nginx-12 /bin/bash
echo $NIHAO
WORKDIR
#WORKDIR
#格式:
WORKDIR /path/to/workdir (shell 模式)
#解释:
#切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。相当于cd
#可以多次切换(相当于cd 命令),
#也可以使用多个WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如
#举例:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
#则最终路径为/a/b/c
WORKDIR实践
#WORKDIR实践:
#修改Dockerfile文件内容:
# 在上一个Dockerfile 文件内容基础上,在RUN 下面增加一个WORKDIR
WORKDIR /nihao/itcast/
RUN ["touch","itcast1.txt"]
WORKDIR /nihao
RUN ["touch","itcast2.txt"]
WORKDIR itcast
RUN ["touch","itcast3.txt"]
...
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.11 .
#根据镜像创建容器,创建时候,不添加执行命令
docker run --name nginx-13 -itd ubuntu-nginx:v0.11
#进入镜像
docker exec -it nginx-13 /bin/bash
USER与ARG
#USER
#格式:
USER daemon
#解释:
#指定运行容器时的用户名和UID,后续的RUN 指令也会使用这里指定的用户。
#如果不输入任何信息,表示默认使用root 用户
#ARG
#格式:
ARG <name>[=<default value>]
#解释:
#ARG 指定了一个变量在docker build 的时候使用,可以使用--build-arg <varname>=<value>来指定参数的值,不过
#如果构建的时候不指定就会报错。
1.7 触发器指令详解
触发器指令
ONBUILD
#格式:
ONBUILD [command]
#解释:
#当一个镜像A被作为其他镜像B的基础镜像时,这个触发器才会被执行,
#新镜像B在构建的时候,会插入触发器中的指令。
#使用场景对于版本控制和方便传输,适用于其他用户。
# 原始镜像 -> 纯净版
-> 修改 ONBUILD ["echo", "hello,linux"]
# 基于原始镜像制作新镜像 -> 镜像A
-> 启动镜像A -> 不会输出hello, linux
# 基于镜像A制作了镜像B
-> 启动镜像B -> 会输出 hello, linux
触发器实践
#编辑Dockerfile
:~/docker/images/nginx$ vim Dockerfile
#内容如下:
# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER panda kstwoak47@163.com
# 执行命令
ADD ["sources.list","/etc/apt/sources.list"]
RUN apt-get clean
RUN apt-get update
RUN apt-get install nginx -y
#触发器
ONBUILD COPY ["index.html","/var/www/html/"]
# 对外端口
EXPOSE 80
#运行时默认命令
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.12 .
#根据镜像创建容器,
:~/docker/images/nginx$docker run -p 80 --name nginx-14 -itd ubuntu-nginx:v0.12
:~/docker/images/nginx$docker ps
#查看镜像信息
:~/docker/images/nginx$ docker inspect ubuntu-nginx:v0.12
#访问容器页面,是否被更改
:~/docker/images/nginx$ docker inspect nginx-14
#构建子镜像Dockerfile文件
FROM ubuntu-nginx:v0.12
MAINTAINER panda kstwoak47@163.com
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
#构建子镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.13 .
#根据镜像创建容器,
docker run -p 80 --name nginx-15 -itd ubuntu-nginx:v0.13
#查看镜像信息
:~/docker/images/nginx$ docker inspect ubuntu-nginx:v0.13
docker ps
#访问容器页面,是否被更改
1.8 Dockerfile构建缓存
我们第一次构建很慢,之后的构建都会很快,因为他们用到了构建的缓存。
#取消缓存:
docker build --no-cache -t [镜像名]:[镜像版本][Dockerfile位置]