前言
在Docker中创建镜像最常用的方式,就是使用Dockerfile。Dockerfile是一个Docker镜像的描述文件,我们可以理解成火箭发射的A、B、C、D…的步骤。Dockerfile其内部包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
组成部分
问题
从Docker-Hub上拖下来的Nginx镜像,原本的配置文件可能不符合我们的期望,就要求我们更改配置文件。
第一种是容器启动后绕过文件系统,以docker exec
进入容器内部,去修改,再reload,太过繁琐。
另一种做法是提前将它的配置文件存储到宿主机目录中,在宿主机上进行编辑,之后在容器启动时指定宿主机配置文件目录,覆盖他原有的配置文件,容器启动后,加载宿主机上的配置,可以让他生效。但是,容器启动后,发现配置可能不对,需要修改配置,还是需要reload。
制作镜像
基于容器:先启动起来,使用 docker exec进入容器内部,交互式的修改,修改完后他就会跑到读写层,覆盖下层配置,可以保存为新镜像。这个缺点等于是写死了,多次做变更很麻烦。还比如日常、预发、线上环境不同,需要制作3种不同的镜像,多次变更,头都大了,凭记忆出现精神错乱!!!
基于Dockerfile:构建Docker镜像的指令。一个纯文本文件,里面包含了一些指令而已。
Dockerfile
注意事项:
Dockerfile首字母必须大写,且需要一个专有目录存放Dockerfile。
Dockerfile文件中引用到的文件必须与Dockerfiler同目录或子目录,不能是专有目录的父目录或其他目录。
Dockerfile支持在下层做一个文本隐藏文件,隐藏不需要的文件,dockeringore。可在其中写需要隐藏的文件路径,在docker打包生成镜像时不会被打包进去。
通过 docker build 基于Dockerfile来制作镜像,打好标签。Dockerfile 中 shell命令是底层镜像支持才会运行。
Environment Replacement
${variable:-world}:变量如果为空,就替换为world指定的字符串。
${variable:+world}:变量如果有值,就显示world指定的字符串。
Dockerfile Instructions
FROM
使用名字引用镜像可能会拉取到恶意的同名基础镜像,使用 @哈希码,则可以保证该镜像的准确性。
1 | mkdir img1 |
MAINTANIER(deprecated)
当下使用 LABLE 标签来替换,他拥有各种K/V信息,作者只是其中的一项,所以它有了更宽泛的含义。
LABEL:为镜像指定元数据
Docker1.7 兼容:推荐使用LABEL
COPY
1 | #Description: test image |
Docker build
1 | docker build --help |
1 | # 容器运行时可以输入一些命令查看信息,查看完成后容器退出就被删除 |
如何复制目录呢?
1 | cd img1 |
将yum.repos.d/ 目录下的所有文件打包放在 镜像 /etc/yum.repos.d/文件夹下
Dockerfile中,惜字如金,每一条指令,都会构成一个新的镜像层,两条指令合成一条,就合成,层越多,联合挂载,效率越差。
1 | vim Dockerfile |
1 | docker build -t tinyhttpd:v0.1-2 ./ |
1 | docker run --name tinyweb1 --rm tinyhttpd:v0.1-2 ls /etc/yum.repos.d/ |
ADD
1 |
|
1 | # 展示会展开的tar包,tar包下载到build的工作目录,即Dockerfile所在目录 |
1 | docker build -t tinyhttpd:v0.1-4 ./ |
WORKDIR
1 | !vim |
VOLUME
1 | VOLUME /data/mysql/ |
1 | docker build -t tinyhttpd:v0.1-5 ./ |
或者让容器起来前先睡一会,inspect检查下
1 | docker run --name tinyweb1 --rm tinyhttpd:v0.1-5 sleep 60 |
EXPOSE
1 | # 待暴露默认端口,并没有真正暴露,容器运行时 -P 才会暴露 |
1 | docker build -t tinyhttpd:v0.1-6 ./ |
1 | # 没有结果,容器中指定暴露了,但是却没有暴露,上面怎么可以访问呢?同一个桥上,容器本身就可以被宿主机访问,如果其他容器也启动到同一个桥上,也可以互相通信 |
外部网页可以访问 192.168.121.100:32768
ENV
1 | # doc_root 也可小写 \ 代表换行 |
1 | docker build -t tinyhttpd:v0.1-7 ./ |
镜像构建和启动容器是两个不同的阶段,上面变量替换是发生在build过程中,那run过程中是否可以呢?当然可以
1 | # 输出环境变量信息 |
build时 Nginx定义为 1.18.0,run时 Nginx重新赋值为其他版本,
1 | # -e K=V 替换带Dockerfile中的环境变量 |
1 | docker run --name tinyweb1 --rm -P -e WEB_SERVER="nginx-1.15.1" tinyhttpd:v0.1-7 ls /usr/local/src |
这里还是 1.18.0,Dockerfile 在 build 过程中已经生效了,即使后台做了更改,也只是名称改变,不会改变名称下面的事实内容。
Dockerfile—->docker build —>docker run —> running container
这两个阶段 docker build 与 docker run 都可以运行shell命令。
RUN
运行Dockerfile中的命令
1 | # 手动展开,前提示 FROM 的基础镜像环境中有tar命令 |
1 | docker build -t tinyhttpd:v0.1-9 ./ |
1 | # RUN命令可以运行多次,建议多个有关的COMMAND 写到一起 |
CMD