1. 语法
1.1. 语法要求
- 执行docker build的目录为镜像创建的工作目录,所有被Dockerfile引用的文件都必须在此目录或者其子目录中,不可超出工作目录的边界
- Dockerfile可以引用文件也可以引用目录,支持通配符,对于引用的目录中个别不需要的文件可以将路径写入.dockerignore文件中,该文件同样支持通配符
- 注释以 # 开头,类似于shell 脚本
- 非注释的非空行是指令行,指令不区分大小写,但是约定都是大写,一个指令是镜像的一个层,因此需要合理编排,尽可能减少层级
Dockerfile支持变量的引用,引用时与shell脚本一致: $var , ${var} , ${var:-default} , ${var:+word}
1.2. 指令
1.2.1. # escape
Syntax
# escape=\
# escape=`
Introduction
The default escape is \,usually used in RUN directive.But in windows image,file path delimiter is \,so the ` is better choice in create window image.
1.2.2. FROM
Syntax
FROM image[:tag] [AS name] FROM image[@digest] [AS name]
Introduction
Specify base image,default tag is :latest.You can speicify tag or digest.If local host doesn’t has the image,it will pull from repository.Digest is image hash.
1.2.3. MAINTAINER(deprecated)
Syntax
MAINTAINER strings
Introduction
Add author information to image.The directive is deprecated,the new choice is LABEL command.
1.2.4. LABEL
Syntax
LABEL key=vaule key=vaule ……
Introduction
Add label to image,such as author,version.In label,you can use a “\” to continue a single key-vaule to next line.
1.2.5. COPY
Syntax
COPY [--chown=user:group] src …… dest COPY [--chown=user:group] ["src","src",……,"dest"]
Introduction
Chown option only worked on Linux container.
COPY instruction copy files or directory based on docker-build workdir to container destination path.The src path support wildcards which will be done using Go’s filepath match rules,such as “hom* hom?.txt”. The dest is an absolute path,or a path ralative to WORKDIR.
- If src is a directory,the whole contents of the directory are copied,include filesystem and metadata.
- If src is a directory,the directory is not copied,just its contents.
- If dest is ending with “/“,it will be done an directory.Otherwise,it will be considered a regular file.
- If specify src by wildcards or sepcify multiple src,the dest must be direcotry.
- If dest doesn’t exits,it will be created.
- If filename contain blank charactre,the JSON array is better choice
1.2.6. ADD
Syntax
ADD [--chown=user:group] src …… dest ADD [--chown=user:group] ["src","src",……,"dest"]
Introduction
The ADD instruction is like COPY instruction.But the instruction has some features:
- ADD can sepcify local files or remote file URLs from src.
- If src is URL,the destination will be chmod to 600.
- If src is tar archive format(.tar,.tar.gz,.tar.bz2,.tar.xz),it will be unpacked on destination(like tar -xf src).
- If scr is URL tar archive format,it will not be unpacked on destination.
- If URL requires authentication,you must be download by wget or curl on COM instruction.
1.2.7. RUN
Syntax
RUN command RUN ["executable","param1","param2",…]
Introduction
RUN command is running when you create image by “docker build”.All commands must included in base image.
- “RUN command … “ is shell form,the command is run in a shell,whinc by defualt is “/bin/sh -c” on Linux or “cmd /s /c” on Windows.
The default shell for shell form can be changed by “SHELL” command.
- “RUN [“executable”,”param1”,”param2”,…]” is exec form,the command is run skep shell.
- In shell form you can use a “\” to continue a single RUN instruction onto next line.
- The exec form is parsed as a JSON array,so you must use double-quotes(“) rather than single-quotes(‘).
- In windows image, RUN [“c:\windows\system32\tasklist.exe”] is syntax error.The correct syntax for this example is:RUN [“c:\windows\system32\tasklist.exe”]]
1.2.8. CMD
Syntax
CMD command param1 param2 CMD ["executable","param1","param2"] CMD ["param1","param2"]
Introduction
The CMD directive used for define a default command when start a container.There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.
- Shell format:
The first format is shell format.Run command by shell,default is “/bin/sh -c”.
- Exec format:
The second format is exec format.It is preferred format.
The exec format skip shell to run command,so some enviroment or commands can’t run success.
The exec format is JSON array,that need use double-quotes(“).
- Entrypoint argument format
The third format is entrypoint argument format.
It define default arguments for ENTRYPOIN command.
1.2.9. ENTRYPOINT
Syntax
ENTRYPOINT command param1 param2 ENTRYPOINT ["executable","param1","param2"]
Introduction
ENTRYPOINT is container default command when container start.The exec-form and shell-form has differences:
No ENTRYPOINT | ENTRYPION e_cmd e_arg | ENTRYPOIN[“e_cmd”,”e_arg”] | |
---|---|---|---|
No CMD | Error | /bin/sh -c e_cmd e_arg | E_cmd e_arg |
CMD c_cmd c_arg | /bin/sh -c c_cmd c_arg | /bin/sh -c e_cmd e_arg | E_cmd e_arg /bin/sh -c c_cmd c_arg |
CMD [“c_cmd”,”c_arg”] | C_cmd c_arg | /bin/sh -c e_cmd e_arg | E_cmd e_arg c_cmd c_arg |
CMD [“c_arg”] | C_arg | /bin/sh -c e_cmd e_arg | E_cmd e_arg c_arg |
- When don’t specify ENTRYPOIN,CMD will be container default Cmd.
- When specify exec-form ENTRYPOINT,CMD will become arguments for ENTRYPOIN directive.
- When specify shell-form ENTRYPOIN,CMD will be ignore.In most time,use “exec commnad”.
- You can specify “—entrypoint string” overwrite ENTORYPIONT when run a container.
- The exec-from is better choice.
1.2.10. EXPOSE
Syntax
EXPOSE port[/protocol] ……
Introduction
Set default expose port and protocol when you run container with “-P” optinon,default protocol is TCP.
Use the “-p” option will publish and map one or more ports.Use the “-P” option will publish all exposed ports and map to high-order ports.
1.2.11. ENV
Syntax
ENV key value ENV key=vaule key=value …
Introduction
Defines variable key to the value.The vaule be in the environment for all subsequent instruction in docker build,even you can change them when create and run a container by options “—env key=value”.
When you need define multiple variables,you can use second format,and you also can use quotes include values.
1.2.12. HEALTHCHECK
Syntax
HEALTHCHECK [--interval=time --timeout=time --start-period=time --retries=number] CMD command HEALTHCHECK NONE
Introduction
Defines health check process to test container status.The first format is defined health check method.The second format is disable any healthcheck inherited from the base image.
Options:
- —interval: Sets time between tow check.Default 30s.
- —timeout: Defines timeout time,default is 30s.
- —start-period: Defines seconds after container start to run health check.Default 0s.
- —retries: Retry times.Default 3.
Status:
Syntax
VOLUME ["mounted_point","mounted_point",……] VOLUME mounted_point mounted_point
Introduction
Specify volume which will mounted by container-managed when container run.
Docker will copy file to volume when the files created before volumes declared.After valume declared,any build steps change the data within the volume will be discarded.
The volume can’t specify host dirctory.
1.2.14. USER
Syntax
USER user[:group] USER UID[:GID]
Introduction
The USER command set user name or UID and group name or GID to use when running the image and for any RUN,CMD,and ENTRYPOIN directive.
When the user doesn’t have a primary group when the image will be run with root group.
1.2.15. WORKDIR
Syntax
WORKDIR path
Introduction
Specify work directory in container for any RUN,CMD,ENTRYPOIN,ADD,COPY instructions.If the path dosen’t exist,it will be create.
1.2.16. ONBULID
Syntax
ONBUILD INSTRODUCTION
Introduction
Defines introduction when the image referer by others.In other word,if other people create use base image which sets ONBUILD command,it will execute the INSTRODUCTION when referer.
1.2.17. ARG
Syntax
ARG key[=default_value]
Introduction
Define variable that user can pass value by “—build-arg key=value” when docker build.It use default value when user doesn’t pass value and defines default in Dockerfile.
If you need specify image version,you can set “ARG VERSION” before FROM instruction,but the ARG instruction that before FROM will not be referer after FROM instruction,you must reset ARG instruction after FROM instruction.
1.2.18. SHELL
Syntax
SHELL ["executalbe","parameters"]
Introduction
Defins shell which overwrite default shell (“/bin/sh -c” or “cmd /S /C”).
1.2.19. STOPSINGLE
Syntax
STOPSIGNAL signal
Introduction
Defines signal when execute “docker container stop”,default is 15.
1.3. 多阶段构建
在学习go语言过程中,存在一个镜像制作的场景:
- 下载 golang 官方镜像,使用Dockerfile将go代码进行编译,编译结果为一个二进制文件
- 下载 业务容器基础镜像(比如centos),将编译好的二进制文件通过Dockerfile拷贝到业务容器基础镜像中
为了实现上述的需求,以前仅有两种方式:分两个Dockerfile进行镜像的制作,使用shell脚本将两个制作流程合并。在 Docker 17.05 之后,Dockerfile 支持多阶段构建镜像,方式如下:
FROM golang:1.13 as builder # 编译代码的基础镜像
WORKDIR /workspace
COPY ./ .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on GOPROXY=https://goproxy.cn go build -a -o test-project main.go
FROM centos:7
COPY --from=builder /workspace/test-project .
RUN chmod +x test-project
CMD ["/test-project"]
2. Examples
2.1. 常用的指令使用案例
2.1.1. LABEL & COPY
[root@centos-82 test-01]# cp -r /etc/yum.repos.d/ ./
[root@centos-82 test-01]# cp /etc/passwd ./
[root@centos-82 test-01]# head -100 Dockerfile .dockerignore
==> Dockerfile <==
# Test FROM directive
FROM busybox:latest
LABEL author="heyingsheng <hys_1992@outlook.com>" version="test-image-v1.0.1" baseimage="busybox:latest"
COPY yum.repos.d passwd /tmp/
==> .dockerignore <== ## 需要忽略的文件
yum.repos.d/CentOS-*
[root@centos-82 ~]# docker container run --name c1 --rm test-image:v1.0.2 ls /tmp/
docker-ce.repo
passwd
[root@centos-82 ~]# docker image inspect -f {{.ContainerConfig.Labels}} test-image:v1.0.2
map[author:heyingsheng <hys_1992@outlook.com> baseimage:busybox:latest version:test-image-v1.0.1]
2.1.2. ADD
[root@centos-82 test-01]# cat Dockerfile
# Test FROM directive
FROM busybox:latest
LABEL author="heyingsheng <hys_1992@outlook.com>" version="test-image-v1.0.1" baseimage="busybox:latest"
# URL 格式的文件不会解压,而直接 ADD 进去的本地 .tar[.xx] 格式文件会解压
ADD http://nginx.org/download/nginx-1.14.2.tar.gz /tmp/url_tar/
ADD nginx-1.14.2.tar.gz /tmp/local_tar/
[root@centos-82 test-01]# docker build -t test-image:v1.0.3 ./
[root@centos-82 ~]# docker container run —name c1 —rm test-image:v1.0.3 ls /tmp/url_tar /tmp/local_tar/
/tmp/local_tar/:
nginx-1.14.2
/tmp/url_tar:
nginx-1.14.2.tar.gz
2.1.3. VOLUME
[root@centos-82 test-01]# cat Dockerfile
# Test FROM directive
FROM busybox:latest
LABEL author="heyingsheng <hys_1992@outlook.com>" version="test-image-v1.0.1" baseimage="busybox:latest"
# COPY yum.repos.d passwd /tmp/
ADD nginx-1.14.2.tar.gz /tmp/local_tar/
## 只能指定容器中的挂载点,而不能指定宿主机上的目录
VOLUME /tmp/
ADD passwd yum.repos.d /tmp/
RUN mv /tmp/local_tar/nginx-1.14.2 /tmp/local_tar/nginx_src
[root@centos-82 test-01]# docker build -t test-image:v1.0.6 ./
[root@centos-82 ~]# docker container run —name c1 —rm test-image:v1.0.6 sh -c “ls /tmp/ /tmp/local_tar ;sleep 60 “
/tmp/:
docker-ce.repo
local_tar
passwd
/tmp/local_tar:
nginx-1.14.2
#### 此处最后的RUN并没有修改声明volume之前创建的文件
[root@centos-82 test-01]# docker container inspect -f {{.Mounts}} c1
[{volume fb376e4f9dd94ec8b4e8a2778bd15b405dda653f3773ca4cb53fd120170eb6f4 /var/lib/docker/volumes/fb376e4f9dd94ec8b4e8a2778bd15b405dda653f3773ca4cb53fd120170eb6f4/_data /tmp local true }]
2.1.4. EXPOSE
[root@centos-82 test-01]# cat Dockerfile
# Test FROM directive
FROM busybox:latest
LABEL author="heyingsheng <hys_1992@outlook.com>" version="test-image-v1.0.1" baseimage="busybox:latest"
COPY index.html /data/web/html/
EXPOSE 80/tcp
[root@centos-82 test-01]# docker build -t test-image:v1.0.8 ./
[root@centos-82 ~]# docker container run —name c1 —rm test-image:v1.0.8 /bin/httpd -f -h /data/web/html/
[root@centos-82 test-01]# docker container port c1 ## Default case doesn’t expose 80 prot.
[root@centos-82 ~]# docker container run —name c1 -P —rm test-image:v1.0.8 /bin/httpd -f -h /data/web/html/
[root@centos-82 test-01]# docker container port c1 ## When you specify “-P”,it will expose 80
80/tcp -> 0.0.0.0:32769
[root@centos-82 test-01]# curl 192.168.1.82:32769
<h1>Httpd Server</h1>
2.1.5. CMD
2.1.5.1. exec-form CMD
[root@centos-82 test-02]# vim Dockerfile
FROM busybox:latest AS baseimage
LABEL Author="heyingsheng <123@qq.com>"
ENV WEB_ROOT="/data/html/www"
RUN mkdir -p $WEB_ROOT && \
echo "Test index!" > $WEB_ROOT/index.html
# CMD ["/bin/httpd","-f","-h","$WEB_ROOT"] ## The exec format can't referer shell variable.
CMD ["/bin/httpd","-f","-h","/data/html/www"]
[root@centos-82 test-02]# docker build -t test-image:v2.0.2 ./
[root@centos-82 ~]# docker image inspect -f {{.Config.Cmd}} test-image:v2.0.2
[/bin/httpd -f -h /data/html/www]
[root@centos-82 ~]# docker run —name c2 —rm -d test-image:v2.0.2
[root@centos-82 ~]# docker container inspect -f {{.NetworkSettings.IPAddress}} c2
172.17.0.2
[root@centos-82 ~]# curl 172.17.0.2
Test index!
2.1.5.2. Shell-form CMD
[root@centos-82 test-02]# cat Dockerfile
FROM busybox:latest AS baseimage
LABEL Author="heyingsheng <123@qq.com>"
ENV WEB_ROOT="/data/html/www"
RUN mkdir -p $WEB_ROOT && \
echo "Test index!" > $WEB_ROOT/index.html
# CMD ["/bin/httpd","-f","-h","$WEB_ROOT"]
# CMD ["/bin/httpd","-f","-h","/data/html/www"]
CMD /bin/httpd -f -h /data/html/www
[root@centos-82 test-02]# docker build -t test-image:v2.0.3 ./
[root@centos-82 ~]# docker image inspect -f {{.Config.Cmd}} test-image:v2.0.3
[/bin/sh -c /bin/httpd -f -h /data/html/www]
[root@centos-82 ~]# docker container run —name c1 —rm -d test-image:v2.0.3
[root@centos-82 ~]# docker container inspect -f {{.NetworkSettings.IPAddress}} c1
172.17.0.2
[root@centos-82 ~]# curl 172.17.0.2 ## Upper success.
Test index!
[root@centos-82 ~]# docker container inspect -f {{.Config.Cmd}} c1 ## The container first process is /bin/sh.
[/bin/sh -c /bin/httpd -f -h /data/html/www]
[root@centos-82 ~]# docker container exec c1 ps ## The PID 1 process is replaced!
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f -h /data/html/www
2.1.6. ENTRYPOINT
2.1.6.1. exec-form ENTRYPOINT
[root@centos-82 test-02]# cat Dockerfile
FROM busybox:latest
LABEL Author="heyingsheng <123@qq.com>"
RUN mkdir -p /data/web/html && \
echo "Test index!" > /data/web/html/index.html
CMD ["-h","/data/web/html"]
ENTRYPOINT ["/bin/httpd","-f"]
[root@centos-82 test-02]# docker build -t test-image:v2.0.6 ./
[root@centos-82 ~]# docker container run —name c1 —rm -d test-image:v2.0.7
[root@centos-82 ~]# docker container exec c1 ps uax ## The CMD arguments will append to ENTRYPOINT.
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f -h /data/web/html
6 root 0:00 ps uax
2.1.6.2. shell-form ENTRYPOINT
[root@centos-82 test-02]# cat Dockerfile
FROM busybox:latest
LABEL Author="heyingsheng <123@qq.com>"
RUN mkdir -p /data/web/html && \
echo "Test index!" > /data/web/html/index.html
CMD ["-h","/data/web/html"]
# ENTRYPOINT ["/bin/httpd","-f"]
ENTRYPOINT /bin/httpd -f
[root@centos-82 test-02]# docker build -t test-image:v2.0.7 ./
[root@centos-82 ~]# docker container run —name c1 —rm -d test-image:v2.0.7
[root@centos-82 ~]# docker container exec c1 ps uax ## The CMD directive is ignored.
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f
6 root 0:00 ps uax
2.1.6.3. configuration & ENTRYPOINT
[root@centos-82 test-02]# cat Dockerfile
FROM centos:centos7
LABEL Author="heyingsheng <123@qq.com>"
ADD http://nginx.org/download/nginx-1.14.2.tar.gz /usr/local/src/
RUN yum install -y gcc gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel && \
useradd -M -s /sbin/nologin nginx && \
tar -xf /usr/local/src/nginx-1.14.2.tar.gz -C /usr/local/src/ && \
cd /usr/local/src/nginx-1.14.2 && \
./configure --user=nginx --group=nginx && \
make -j 4 && make install && \
mkdir -p /data/web/html/ && \
echo "Vhost Test!" > /data/web/html/index.html && \
yum clean all && \
cd / && \
rm -fr /var/cache/yum /usr/local/src/*
EXPOSE 80/tcp
ADD nginx_start.sh /bin/
ENV SERVER_NAME="www.heyang.com" \
PORT=8080
CMD ["/usr/local/nginx/sbin/nginx"]
ENTRYPOINT ["/bin/nginx_start.sh"]
[root@centos-82 test-02]# cat nginx_start.sh
#!/bin/sh
cat <<EOF >/usr/local/nginx/conf/nginx.conf
user nginx;
worker_processes 1;
events {
worker_connections 1024;
}
daemon off;
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen ${IP:-0.0.0.0}:${PORT:-80};
server_name ${SERVER_NAME:localhost};
location / {
root /data/web/html/;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
EOF
exec $@
[root@centos-82 ~]# docker container run —name c1 —rm —env PORT=8081 -d test-image:v2.0.11
[root@centos-82 ~]# docker container exec c1 ps uax
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 20548 1448 ? Ss 23:31 0:00 nginx: master process /usr/local/nginx/sbin/nginx
[root@centos-82 ~]# curl 172.17.0.2:8081
Vhost Test!