使用dockerfile定制镜像及dockerfile指令解析
1.从零开始来创建一个新的镜像、
什么是 Dockerfile 文件?
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本
主要作用:
1、找一个镜像: centos
2、创建一个容器: docker run centos
3、进入容器: docker exec -it 容器 命令
4、操作: 各种应用配置
....
5、构造新镜像: docker commit
Dockerfile 使用准则
1、大: 首字母必须大写D
2、空: 尽量将Dockerfile放在空目录中。
3、单: 每个容器尽量只有一个功能。
4、少: 执行的命令越少越好。
Dockerfile 基础四指令:
基础镜像信息 从哪来?
维护者信息 我是谁?
镜像操作指令 怎么干?
容器启动时执行指令 嗨!!!
Dockerfile使用命令:
构建镜像命令格式:
docker build -t [镜像名]:[版本号] [Dockerfile所在目录]
构建样例:
docker build -t nginx:v0.2 /opt/dockerfile/nginx/
参数详解:
-t 指定构建后的镜像信息,
/opt/dockerfile/nginx/ 则代表Dockerfile存放位置,如果是当前目录,则用 .(点)表示
1.1编写Dockerfile文件、
$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile
$ cat Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
说明:
每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的
第一条FROM,指定使用哪个镜像源,基础镜像
FROM scratch (表示空白的镜像,是一个虚拟的概念,实际不存在)
RUN
指令是用来执行命令行命令的(两种格式)
shell 格式:RUN <命令>
exec 格式:RUN ["可执行文件", "参数1", "参数2"]
如:# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
最好不要写多个指令,每一个指令代表一层,则会创建了很多层镜像,如果需要写多个指令可以用连接符 && 连接起来,在同一层上面创建即可。
1.2 构建镜像
在 Dockerfile
文件所在目录执行:
$ docker build -t nginx:2.0 .
发现其执行了两步,查看镜像列表已经存在创建的镜像了
-t:指定要创建的镜像名
.:Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径
![](https://img2018.cnblogs.com/i-beta/1639063/201912/1639063-20191205005524408-640628487.png)
运行镜像:
[root@rbtnode1 mynginx]# docker run -d -p 82:80 nginx:2.0
查看 nginx,运行的页面如构建的shell脚本更改一致
1.3上下文路径
最后一个 . 是上下文路径,怎么理解呢?
是docker在构建镜像,不一定使用RUN指令完成的,有时候想要使用本机的文件(如复制COPY),docker build命令得知这个路径后,会将路径下的所有东西打包。docker是C/S模式,我们使用C,引擎是S。而build是是引擎完成的,则docker不能使用我们本机C的文件,所以需要制定目录下的文件打包给S使用。如果不说吗,则为Dockerfile所在的位置。
如果在Dockerfile中写:
COPY ./package.json /app/
这并不表示要复制docker build命令所在的目录下的package.json,也不是复制Dockerfile所在目录下的package.json,而是复制上下文目录下的package.json。
**COPY
这类指令中的源文件的路径都是相对路径。**
docker build -t nginx:2.0 .
中的这个 .
,实际上是在指定上下文的目录,docker build
命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。(输出的第一行就是其过程)
为了避免犯错:
-
应该会将
Dockerfile
置于一个空目录下,或者项目根目录下。
-
如果该目录下没有所需文件,那么应该把所需文件复制一份过来,去copy正常的Linux的路径如 ../../等是不会工作的。
-
不希望传有些东西给docker引擎,用.dockerignore文件(似.gitignore)剔除
为什么会误认为是指定Dockerfile路径呢?
-
因默认情况且不指定Dockerfile的话,会将上下文目录下的名为Dockerfile的文件名为Dockerfile
-
不必须命名为Dockerfile,可以用
-f ../Dockerfile.php
参数指定某个文件作为Dockerfile
。 -
当然,一般大家习惯性的会使用默认的文件名
Dockerfile
,以及会将其置于镜像构建上下文目录中
2.其它 docker build
的用法
2.1 直接用 Git repo 进行构建
-
docker build支持url构建
$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:11.1
指定默认的 master 分支,构建目录为 /11.1/,然后 Docker 就会自己去 git clone 这个项目、切换到指定分支、并进入到指定目录后开始构建。
2.2用给定的 tar 压缩包构建
$ docker build http://server/context.tar.gz
Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
2.3从标准输入中读取 Dockerfile 进行构建
docker build - < Dockerfile
cat Dockerfile | docker build -
如果标准输入传入的是文本文件,则将其视为 Dockerfile
,并开始构建。直接读取Dockerfile中的内容,没有上下文
2.4从标准输入中读取上下文压缩包进行构建
$ docker build - < context.tar.gz
3.Dockerfile 指令详解
3.1 COPY和ADD
COPY复制指令,将从构建上下文目录中 <源路径>
的文件/目录复制到新的一层的镜像内的 <目标路径>
位置。ADD是更高级的复制文件,两种格式两种(命令行,函数调动型):
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
如:COPY package.json /usr/src/app/
加入组的方式:COPY --chown=1 files* /mydir/
[--chown=<user>:<group>]**:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR
指令来指定。
使用COPY指令,各类元数据都会保留,git时很方便。
ADD源路径:
-
是一个url,docker引擎会去下载这个路径,自动设置权限为600,也可以加RUN调整权限。下载到的若是个压缩包,若解压则加一层RUN指令,也可以wget或curl下载,处理。
-
<源路径>
为一个tar
压缩文件的话,压缩格式为gzip
,bzip2
以及xz
的情况下,ADD
指令将会自动解压缩这个压缩文件到<目标路径>
去-
使用注意:
-
尽量多用COPY,只是复制没必要那么复杂,需要自动解压再用ADD
-
ADD会让镜像构建失效,从而镜像缓慢。
-
--chown=<user>:<group>
ADD --chown=55:mygroup files* /mydir/
修改用户及所属组
-
-
3.2 CMD和ENTRYPOINT
-
概念
CMD:指定默认的容器主进程的启动命令,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。多个CMD时仅最后一个生效。
ENTRYPOINT:类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序,存在多个 ENTRYPOINT 指令,仅最后一个生效。需要通过
docker run
的参数--entrypoint
来指定。 -
格式
CMD
指令的格式和 RUN
相似,CMD与ENTRYPOINT类似。也是两种格式(推荐exec):
-
shell
格式:CMD <命令>
-
exec
格式:CMD ["可执行文件", "参数1", "参数2"...]
-
参数列表格式:
CMD ["参数1", "参数2"...]
。在指定了ENTRYPOINT
指令后,用CMD
指定具体的参数。
-
使用规则
-
CMD
-
使用exec格式,其会被解析成接送数组,一定需要“”双引号。
-
使用shell格式,实际命令会被包装是 sh -c 执行。这样就需要环境变量,环境变量会被shell进行解析。容器中执行的命令需要在前台执行,类似于systemd后台命令无法执行,被迫容器退出,因为容器执行会解读为sh执行,这样sh就是这个命令的主进程。那么后台的命令结束则sh结束了就退出了,启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程结自然容器也退出了。除非CMD要求前台执行。
-
-
ENTRYPOINT
-
指定了
ENTRYPOINT
后,CMD
的含义就发生了改变,不再是直接的运行其命令,而是将CMD
的内容作为参数传给ENTRYPOINT
指令。<ENTRYPOINT> "<CMD>"。 -
可以让镜像变成像命令一样使用
-
启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。
-
-
3.3环境指令详情
1. 环境设置指令
ENV
格式:
ENV <key> <value>
ENV <key>=<value> ...
解释:
设置环境变量,可以在RUN之前使用,然后RUN命令时调用,容器启动时这些环境变量都会被指定
WORKDIR
格式:
WORKDIR /path/to/workdir (shell 模式)
解释:
切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。 相当于cd
可以多次切换(相当于cd命令),
也可以使用多个WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如
举例:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
则最终路径为 /a/b/c。
ENV实践
修改Dockerfile文件内容:
# 在上一个Dockerfile文件内容基础上,在RUN下面增加一个ENV
ENV NIHAO=helloworld
WORKDIR实践
修改Dockerfile文件内容:
# 在上一个Dockerfile文件内容基础上,在RUN下面增加一个WORKDIR
WORKDIR /nihao/itcast/
RUN ["touch","itcast.txt"]
Dockerfile**构建过程:**
-
从基础镜像1运行一个容器A
遇到一条Dockerfile指令,都对容器A做一次修改操作
执行完毕一条命令,提交生成一个新镜像2
再基于新的镜像2运行一个容器B
遇到一条Dockerfile指令,都对容器B做一次修改操作
执行完毕一条命令,提交生成一个新镜像3
...
-
构建过程镜像介绍**
构建过程中,创建了很多镜像,这些中间镜像,我们可以直接使用来启动容器,通过查看容器效果,从侧面能看到我们每次构建的效果。
提供了镜像调试的能力
我们可以通过docker history <镜像名> 来查看整个构建过程所产生的镜像
执行的步骤越多越好呢?还是越少越好?
-
构建缓存**
我们第一次构建很慢,之后的构建都会很快,因为他们用到了构建的缓存。
不适用构建缓存方法常见两种:
全部不同缓存:
docker build --no-cache -t [镜像名]:镜像版本
只要构建的缓存时间不变,那么就用缓存,如果时间一旦改变,就不用缓存了
样例:
# 构建一个基于ubuntu-base的docker定制镜像
# 基础镜像
FROM ubuntu-base
\ # 镜像作者
MAINTAINER 邮箱
\ # 创建构建刷新时间
ENV REFRESH_DATE 2019-12-06
# 执行命令
...
构建历史:
1. 查看构建过程查看
docker history
清理构建缓存:
docker system prune
docker system prune --volumes