diff --git a/docker/docker file.md b/docker/docker file.md new file mode 100644 index 0000000..5589493 --- /dev/null +++ b/docker/docker file.md @@ -0,0 +1,207 @@ +# Dockerfile +Docker可以通过读取dockerfile中的指令自动构建image。 +## format +如下是dockerfile的格式: +```dockerfile +# Comment +INSTRUCTION arguments +``` +指令是不区分大小写的,但是习惯将其大写以区分INSTRUCTION和arguments。 +Dockerfile中的指令将会被按顺序执行,dockerfile必须以FROM指令开头。FROM指令制定了构建的Parent image。 +## parser directive +parser指令是可选的,并影响dockerfile后续的处理方式。parser指令并不会向build过程中添加layer,也不会展示为一个build过程。parser指令的格式如下所示: +```dockerfile +# directive=value +``` +一旦任何comment、空行或builder instruction被处理,docker将不再接受parser directive,即使后面有格式符合parser instruction的行也会被当作注释处理。故而parser instruction必须位于dockerfile的最顶端。 +parser directive是大小写不敏感的,但是推荐将其小写。约定也要求在任何parser directive后添加一个空白行。 +**如下格式是无效的:** +```dockerfile +# direc \ +tive=value +``` +**如下格式中parser指令连续出现了两次,也是无效的:** +```dockerfile +# directive=value1 +# directive=value2 + +FROM ImageName +``` +**由于之前已经有一条指令,如下parser指令将会被当作注释处理:** +```dockerfile +FROM ImageName +# directive=value +``` +**由于之前存在一条注释,故而parser指令也会被当作注释处理:** +```dockerfile +# About my dockerfile +# directive=value +FROM ImageName +``` +**不被识别的parser指令也会被当作注释处理,由于上一条parser指令不被识别被当作注释,故而第二条能被识别的parser指令也会被当作注释处理:** +```dockerfile +# unknowndirective=value +# knowndirective=value +``` +**非换行空白符允许在parser指令中出现,故而下列格式的parser instruction都是允许的:** +```dockerfile +#directive=value +# directive =value +# directive= value +# directive = value +# dIrEcTiVe=value +``` +dockerfile支持如下两条parser directive: +- syntax +- escape +### syntax +该特性仅当使用了BuildKit backend时可用,当使用classic builder backend时会被忽略。 +### escape +```dockerfile +# escape=\ (backslash) +``` +or +```dockerfile +# escape=` (backtick) +``` +escape指令用于设置dockerfile中的转义符。如果没有显式设置的情况下,默认情况下转义符为\\ +转义符在dockerfile中既用于对行内的字符进行转义,也用于对换行符进行转义,\后跟一个换行符可以将一行指令拆分为多行进行编写。 +## ENV +环境变量(dockerfile中以ENV开始的变量)可以在其他指令中作为变量被使用,由dockerfile进行解析。 +环境变量在dockerfile中通过$variable_name或${variable_name}的形式进行使用。 +${variable_name}支持一些标准的bash使用: +- ${variable:-word}:如果variable被设置,那么返回值为variable设置的值;如果variable没有被设置,那么返回值为word +- \${variable:+word}:如果variable被设置,那么返回word,否则返回空字符串 +可以通过\符号对$进行转义 +```dockerfile +FROM busybox +ENV FOO=/bar +WORKDIR ${FOO} # WORKDIR /bar +ADD . $FOO # ADD . /bar +COPY \$FOO /quux # COPY $FOO /quux +``` +在dockerfile中,如下命令都支持使用环境变量: +- ADD +- COPY +- ENV +- EXPOSE +- FROM +- LABEL +- STOPSIGNAL +- USER +- VOLUME +- WORKDIR +- ONBUILD (when combined with one of the supported instructions above) +在ENV中使用环境变量时,环境变量的值使用的是上一条ENV指令结束时的值: +```dockerfile +ENV abc=hello +ENV abc=bye def=$abc +ENV ghi=$abc +``` +其中def的值为hello,而ghi的值为bye。 +## .dockerignore file +当docker cli将context发送给docker daemon之前,其会先在context根目录查找文件名为.dockerignore的文件。如果该.dockerignore文件存在,docker cli将会删除context中符合pattern的文件。者可以避免务必要的发送大文件或敏感文件。 +docker cli将.dockerignore解释为用换行符分隔的一系列模式,**context的根目录既被当作工作目录,也被当作根目录**。 +> 在.dockerignore中,#开头的行将被看作注释。 + +.dockerignore的语法如下: +| rule | behave | +| :-: | :-: | +| # comment | 注释,忽略 | +| \*/temp\* | 排除了根目录的直接子目录中任何以temp开头的文件和目录,例如/somedir/temporary.txt或/somedir/temp | +| \*/\*/temp\* | 排除深度为2的子目录中任何以temp开头的文件或者目录,例如/somedir/subdir/temporary.txt is excluded | +| temp? | 排除根目录的子目录中名称为temp+任意字符的文件和目录 | +| \*\*/\*.go | **用于匹配任意层(包含0)的路径,此pattern会排除任何以.go结尾的文件 | + +当pattern以!开头时,代表不排除满足pattern的文件 +```.dockerignore +*.md +!README.md +``` +上述代表排除所有.md文件,但是不排除README.md +> 在.dockerignore文件中匹配的最后一条pattern将会决定该文件是否包含在context中 +```.dockerignore +*.md +!README*.md +README-secret.md +``` +上诉代表所有的.md文件都会被移除,但是满足README*.md格式的文件将会被保留,README-secret.md文件会被移除。 +> 如果想要在.dockerignore中指定哪些文件要被包含,而不是指定哪些文件被排除,可以使用如下形式 +```.dockerignore +* +!include-pattern... +``` +## FROM +FROM命令格式如下: +```dockerfile +FROM [--platform=] [AS ] +``` +or +```dockerfile +FROM [--platform=] [:] [AS ] +``` +or +```dockerfile +FROM [--platform=] [@] [AS ] +``` +FROM命令设置了一个初始build状态,并且为其他命令设置了一个初始的镜像。一个有效的dockerfile文件必须以FROM命令开始。 +- 在同一个dockerfile中,FROM命令可以出现多次,用于创建多个镜像或将其中一个build stage作为另一个的依赖。只需要在每条新的FROM语句之前记录上一个由commit输出的image id,每条新FROM语句都会清除之前语句创建的所有状态。 +- 可以为一个新的build stage指定一个名称,通过在FROM语句之后添加AS NAME,该名称可以在来连续的FROM语句或COPY --from=\中被使用。 +- tag或digest值也是可选的,如果忽略,那么会使用带lattest标签的值。 +如果FROM引用了一个多平台的镜像,那么--platform可以被使用,例如linux/amd64, linux/arm64, or windows/amd64.默认情况下,会使用build请求目标平台的值(--platform=$BUILDPLATFORM)。 +### ARG和FROM的交互 +FROM指令支持使用ARG定义的变量,例如: +```dockerfile +ARG CODE_VERSION=latest +FROM base:${CODE_VERSION} +CMD /code/run-app + +FROM extras:${CODE_VERSION} +CMD /code/run-extras +``` +位于FROM指令之前的的ARG指令是不被包含在build stage中的,故而无法被FROM之后的指令使用。如果想要使用在FROM之前声明的ARG变量的值,可以在build stage之内使用一个没有值的ARG指令,如下所示: +```dockerfile +ARG VERSION=latest +FROM busybox:$VERSION +# 再次声明VERSION,以此使用FROM之前的VERSION值 +ARG VERSION +RUN echo $VERSION > image_version +``` +## RUN +RUN命令具有两种格式: +- RUN \:shell格式,该命令默认是跑在shell中的,默认情况下是/bin/sh -c +- RUN ["executable", "param1", "param2"] +RUN指令将会在新的layer中执行任何command并且将结果提交,提交结果镜像将会作为dockerfile中下一步操作的镜像。 +在shell格式中,可以使用转义符来将RUN命令拓展到多行: +```dockerfile +RUN /bin/bash -c 'source $HOME/.bashrc && \ +echo $HOME' +# 其和如下形式命令等效 +RUN /bin/bash -c 'source $HOME/.bashrc && echo $HOME' +``` +如果想要使用其他的shell,可以使用如下形式: +```dockerfile +RUN ["/bin/bash", "-c", "echo hello"] +``` +RUN指令的缓存在下次build操作执行时并不会失效,在下次build操作时会被重用。RUN指令的缓存可以通过指定--no-cache选项被失效,使用示例如下:docker build --no-cache +## RUN --mount +RUN --amount允许创建一个文件系统挂载,build操作可以访问该文件系统。 +syntax: +```dockerfile +RUN --mount=[type=][,option=[,option=]...] +``` +### Mount Types +挂载类型如下: +- bind(default):绑定装载上下文目录(只读) +- cache:挂载一个临时目录到缓存目录,用于编译和包管理 +- secret:允许build container访问secure文件(例如私钥)而无需将私钥拷贝到image中 +- ssh:允许build container通过ssh agent访问ssh key +### RUN --mount=type=bind +该mount type允许将文件或者目录绑定到build container中,默认情况下一个bind-mount是只读的。 +| OPTION | DESCRIPTION | +| :-: | :-: | +| `target` | 挂载到的目录 | +| `source` | `from`中的source path | +| `from` | `source`根路径的build stage或image name,默认情况下为build context | +| `rw`,`readwrite` | 允许在mount后的文件系统执行写入操作,写入信息将会被丢弃 | +> RUN --mount=type=bind允许将context或镜像中的目录绑定到build container中,并且只有在该条RUN指令运行时,才可以访问挂载的目录。 \ No newline at end of file