如何理解 Dockerfile 指令
- 结合 supervisor 的配置和 shell 命令去类比去理解,有很多相似的地方。
- 是 DSL,和最近做的 makefile 挺类似。它们都规定了一些语法,这些语法最终会按照解释器执行。然而这些语法又不完备,所以常常需要借助 shell 的语法。
注释
# this is comment
Dockerfile 语句换行
跟普通的 shell 程序一样换行.
注意,换行符不能和前面的字符有空格,/batch_test/requirement.txt\ 必须要联在一起。RUN "pip install --no-cache -r /batch_test/requirement.txt\
-f /Users/yutou/shouxin/sxProject/pysubway/pysubway/gitignore/batch_test/local_source\"
FROM
定义基础镜像,基础镜像应该选择官方的,未经过修改的镜像,这样的镜像体积小,别人使用你的 docekerfile 生成镜像也不会找不到。FROM centos:7
ENV
设置环境变量。环境变量就是 Linux 中 export 设置的那个环境变量。设置环境变量
举例,设置环境变量 PATH 时应该写成如下形式:ENV PATH="/opt/gtk/bin:${PATH}"
使用环境变量
${PATH}
ARG
ARG 指令用来定义外部传入参数。
如果定义了外部传入参数,在打包docker镜像时需要指定传入参数及其值。使用场景
1 个 Dockerfile 多个环境打包,可以使用ARG
,这样比起 ENV 没有写死,便于打包不同环境的镜像。Dockerfile 中定义
示例,程序运行时需要指定环境和配置文件:FROM alpine:latest
ENV projectName=guard_v2
ENV projectPort=8080
ENV containerBinary=/$projectName/$projectName
ARG env
ARG conf
RUN mkdir /$projectName
COPY $PWD/$projectName /$projectName
RUN chmod +X $containerBinary
EXPOSE ${projectPort}
RUN ["$containerBinary", "-env=$env", "-conf=$conf"]
build 时传入命令
ARG指令定义的参数,在docker build命令中以—build-arg a_name=a_value形式赋值。docker build . --build-arg env=local
RUN
RUN 只能在镜像中执行
比如这个错误实例中,-f /usr/local_source
中的目录是宿主机中的目录。
RUN 命令中出现的目录都是镜像中的目录,不是宿主机中的目录:RUN pip install --no-cache -r /batch_test/requirement.txt\
-f /usr/local_source
RUN 后可以加环境变量
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .
COPY
COPY 与 ADD
COPY $PWD/ /batch_test/
COPY 和 ADD 都是进行复制,ADD 在复制压缩包时还能自动解压。
COPY 移动文件夹时,
COPY ./sqlaudit /kylin/sqlaudit/
COPY ./sqlaudit /kylin
优雅 COPY
先切换目录,然后直接 copy 就OK了。
WORKDIR /
COPY . .
COPY —from
参考链接:https://docs.docker.com/develop/develop-images/multistage-build/
参考多级打包。
踩坑
- 镜像文件件必须以
/
结尾。
COPY $PWD/* /batch_test
, 抛出的异常:When using COPY with more than one source file, the destination must be a directory and end with a /.
COPY $PWD/* /batch_test/
- 宿主机目录后面不要加
*
。这样的做法会让$PWD/
下的一级子目录都不会在镜像中创建
参考链接,保持目录结构:https://codeday.me/bug/20170910/68286.html
COPY $PWD/* /batch_test/
WORKDIR
WORKDIr 相当于 shell 中的 cd
WORKDIR 相当于 cd,cd 到哪个目录,RUN 后面的命令就在哪里执行。这就是所谓的工作目录。最后一个 WORKDIR 指定的目录,也是 CMD 执行的目录。——毕竟 CMD 也是靠 sh 来执行的。
目录不存在会自动创建
WORKDIR 指定的目录如果不存在会自动创建,所以不必使用 RUN mkdir xx
来创建。
WORKDIR 可以被覆盖
可以在docker run命令
中用-w参数覆盖掉WORKDIR指令的设置,如:
# docker run -w / myimage1
上面的-w参数把容器的工作目录设置成了根目录,而根目录下没有test.txt文件。所以结果显示:test.txt: No such file or directory。
VOLUME
声明要挂载的目录,只是声明而已,并不是说在创建容器时真的会挂载
EXPORT
声明要暴露的端口,只是声明而已,并不是说在创建容器时真的会暴露。
ENTRYPOINT
ENTRYPOINT 与 CMD 的不同:
ENTRYPOINT 我认为最牛的地方在于,能够接收启动容器时的参数。
CMD
CMD ["/bin/bash","-c","supervisord -c ${SUPERVISORD_CONF}\nwhile true;do sleep 100;done\n"]
CMD的主要是为一个正运行的容器提供默认执行命令。如果存在多个CMD指令,那么只有最后一个会被执行。
如果在容器运行时指定了命令,则CMD指定的默认内容会被替代。
为 ENTRYPOINT 提供默认参数
CMD ["参数1", "参数2"]
CMD 调试技巧
把 CMD 执行的命令用 RUN 来执行,如果 build 镜像时能正常启动,说明 CMD 后面跟的命令是正确的。
例子
docker 内部署 supervisor 和 web app 的启动命令:
CMD ["/bin/bash","-c","supervisord -c ${SUPERVISORD_CONF}\nwhile true;do sleep 100;done\n"]
build 生成镜像
进入 dockerfile 所在的目录,执行:
.
代表当前目录,build 命令会打包当前的文件。-f
指定 Dockerfile 文件,默认名称为 Dockerfile.-t
, 镜像名称。--build-arg
, ARG 中传递的参数。- path, 如果在项目根目录下,写一个
.
。docker build -f <Dockerfile> -t <imageName>:<tag> <path>
踩坑
path 使用绝对路径
path 使用相对路径,直接执行docker build
时没有问题,但是将打包命令放到 shell 脚本时执行就容易出现问题。
使用绝对路径示例:docker login --username=${aliyun_registry_username} registry.cn-shanghai.aliyuncs.com --password ${aliyun_registry_password}
例子1 supplier
supplier 是 guard 2.0 中抽出的供应商服务。调试
打印变量
$变量名
, 使用RUN echo
打印 Dockerfile 中的变量是否符合预期。RUN echo $变量名