FROM命令:repository为基础镜像(base image)的名称,tag为base image的标签,不指定就是latest。若是不指定registry,就从docker hub上拉取。html
FROM <registry><repository>[:<tag>]nginx
FROM <registry><repository>@<digest>c++
当从外部registry拉image时,image有可能被别人替换了,可是repository名字相同,因此不安全。digest是image的hash值,因此指定了digest就不会被别人替换掉了。web
MAINTAINER(不推荐使用,被LABLE替代了)命令:用于让dockerfile制做者提供本人的详细信息。docker
MAINTAINER能够出如今任何位置,但推荐放到FROM后面。shell
LABEL命令:用于指定元数据,好比做者,文件大小等。centos
COPY命令:复制宿主机里的文件或目录到:要build出的image的文件系统的某个目录里。安全
语法:bash
文件复制准则:微信
src必须是dockerfile里面的文件或目录,不能是其父目录中的文件或路径。
若是src是目录,则其内部文件或子目录都会被递归复制,但src目录自身不会被复制。
至关于:cp src/* /dest。
若是指定了多个src,或在src中使用了通配符,则dest必须是目录,且必须以/结尾。
若是dest事先不存在,它将会被自动建立,其父目录也会被一并建立。
好比COPY命令,若是目标目录相同,则最好只使用一次COPY。虽然使用屡次COPY也不出错误,可是会多出层,性能很差。
获取帮助信息:
# docker build --help Usage: docker build [OPTIONS] PATH | URL | - Build an image from a Dockerfile Options: --add-host list Add a custom host-to-IP mapping (host:ip) --build-arg list Set build-time variables --cache-from strings Images to consider as cache sources --cgroup-parent string Optional parent cgroup for the container --compress Compress the build context using gzip --cpu-period int Limit the CPU CFS (Completely Fair Scheduler) period --cpu-quota int Limit the CPU CFS (Completely Fair Scheduler) quota -c, --cpu-shares int CPU shares (relative weight) --cpuset-cpus string CPUs in which to allow execution (0-3, 0,1) --cpuset-mems string MEMs in which to allow execution (0-3, 0,1) --disable-content-trust Skip image verification (default true) -f, --file string Name of the Dockerfile (Default is 'PATH/Dockerfile') --force-rm Always remove intermediate containers --iidfile string Write the image ID to the file --isolation string Container isolation technology --label list Set metadata for an image -m, --memory bytes Memory limit --memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap --network string Set the networking mode for the RUN instructions during build (default "default") --no-cache Do not use cache when building the image --pull Always attempt to pull a newer version of the image -q, --quiet Suppress the build output and print image ID on success --rm Remove intermediate containers after a successful build (default true) --security-opt strings Security options --shm-size bytes Size of /dev/shm -t, --tag list Name and optionally a tag in the 'name:tag' format --target string Set the target build stage to build. --ulimit ulimit Ulimit options (default [])
dockerfile 例子1:拷贝一个文件。
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" COPY index.html /data/html/
build一下上面的dockerfile 试试,使用-t
,来指定image的名字和tag,发现build成功了。
# docker build -t tinyhttpd:v0.01 ./ Sending build context to Docker daemon 3.072kB Step 1/4 : FROM busybox:latest ---> b534869c81f0 Step 2/4 : MAINTAINER "magedu <mage@magedu.com>" ---> Using cache ---> 5c5a1c47716c Step 3/4 : LABEL maintainer="magedu <mage@magedu.com>" ---> Using cache ---> 88b87ddfdb22 Step 4/4 : COPY index.html /data/html/ ---> Using cache ---> 59b7dd6c3eb8 Successfully built 59b7dd6c3eb8 Successfully tagged tinyhttpd:v0.01
启动这个image,看看里面有没有/data/html/index.html
# sudo docker run --name b1 --rm tinyhttpd:v0.01 cat /data/html/index.html <h1>http server</h1>
dockerfile 例子2:拷贝一个目录。
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" COPY index.html /data/html/ COPY yum.repos.d /etc/yum.repos.d/
执行build:
docker build -t tinyhttpd:v0.02 ./ Sending build context to Docker daemon 30.21kB Step 1/5 : FROM busybox:latest ---> b534869c81f0 Step 2/5 : MAINTAINER "magedu <mage@magedu.com>" ---> Using cache ---> 5c5a1c47716c Step 3/5 : LABEL maintainer="magedu <mage@magedu.com>" ---> Using cache ---> 88b87ddfdb22 Step 4/5 : COPY index.html /data/html/ ---> Using cache ---> 59b7dd6c3eb8 Step 5/5 : COPY yum.repos.d /etc/yum.repos.d/ ---> 99d306a25cc7 Successfully built 99d306a25cc7 Successfully tagged tinyhttpd:v0.02
验证:
docker run --name b1 -it --rm tinyhttpd:v0.02 ls /etc/yum.repos.d/ CentOS-Base.repo CentOS-Sources.repo CentOS-Base.repo_20191129 CentOS-Vault.repo CentOS-CR.repo CentOS-fasttrack.repo CentOS-Debuginfo.repo docker-ce.repo CentOS-Media.repo
ADD命令:相似COPY,比COPY多了支持压缩类文件的自动解压和从URL下载
语法:
ADD准则:
tar -x
;然而经过URL下载的压缩文件不会自动展开。例子1:使用URL
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" COPY index.html /data/html/ COPY yum.repos.d /etc/yum.repos.d/ ADD http://nginx.org/download/nginx-1.2.9.tar.gz /usr/local/src
确认结果:
# docker run --name b1 --rm tinyhttpd:v0.03 ls /usr/local/src/ nginx-1.2.9.tar.gz
例子2:使用本地压缩文件
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" COPY index.html /data/html/ COPY yum.repos.d /etc/yum.repos.d/ #ADD http://nginx.org/download/nginx-1.2.9.tar.gz /usr/local/src/ ADD nginx-1.2.9.tar.gz /usr/local/src/
确认结果:
# docker run --name b1 --rm tinyhttpd:v0.03 ls /usr/local/src/nginx-1.2.9 CHANGES CHANGES.ru LICENSE README auto conf configure contrib html man src
WORKDIR命令:用于dockerfile中全部RUN,CMD,ENTRYPOINT,COPY和ADD指定设定的工做目录。
WORKDIR能够出现屡次,这些命名去上面去找离它最近的WORKDIR做为相对路径的起始。
语法:
例子:
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" COPY index.html /data/html/ COPY yum.repos.d /etc/yum.repos.d/ #ADD http://nginx.org/download/nginx-1.2.9.tar.gz /usr/local/src/ WORKDIR /usr/local/ ADD nginx-1.2.9.tar.gz ./src1/
确认结果:
sudo docker run --name b1 --rm tinyhttpd:v0.03 ls /usr/local/src1/nginx-1.2.9 [sudo] password for ys: CHANGES CHANGES.ru LICENSE README auto conf configure contrib html man src
VOLUME:和run -v相似,但只能指定image里的某个目录,而不能指定宿主机的目录。
语法:
注意:若是image挂载点目录下有文件,则启动容器后,会把挂载点下的文件拷贝到宿主机。
例子:
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" COPY index.html /data/html/ COPY yum.repos.d /etc/yum.repos.d/ #ADD http://nginx.org/download/nginx-1.2.9.tar.gz /usr/local/src/ WORKDIR /usr/local/ ADD nginx-1.2.9.tar.gz ./src/ VOLUME /usr/local/src
确认结果:因为image的/usr/local/src目录下有nginx-1.2.9,因此nginx-1.2.9会被拷贝到宿主机。
# docker run --name b1 -it --rm tinyhttpd:v0.03 # ls /var/lib/docker/volumes/1240925e87efaa5d9ed375b268a6d804c29013c04792f9a0dde9e135aa7e9f9e/_data/ nginx-1.2.9
EXPOSE:和-p选项类型,指定容器要暴漏给外部的端口,但不能指定宿主机的端口,由于在做dockerfile的时候,没法肯定此image运行在什么宿主机上。也就没法知道宿主机上哪些端口可使用。因此是随机去找宿主机里可使用的端口。
注意:即便使用了EXPOSE命令,但若是RUN时不加-P
选项的话,端口也不会被暴露出去的。
语法:EXPOSE <port>[/protocol] <port>[/protocol]
例子:
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" COPY index.html /data/html/ COPY yum.repos.d /etc/yum.repos.d/ #ADD http://nginx.org/download/nginx-1.2.9.tar.gz /usr/local/src/ WORKDIR /usr/local/ ADD nginx-1.2.9.tar.gz ./src/ VOLUME /usr/local/src EXPOSE 80
确认结果:
启动时先不指定-P
,用docker port查看,发现没有端口。
# docker run --name b1 --rm tinyhttpd:v0.03 /bin/httpd -f -h /data/html/ # docker port b1
启动时先指定-P
,用docker port查看,发现有端口。
# docker run --name b1 --rm -P tinyhttpd:v0.03 /bin/httpd -f -h /data/html/ # docker port b1 80/tcp -> 0.0.0.0:32768
EXPOSE的做用是:默认想暴露的端口,在启动的时候,可使用-p
去覆盖EXPOSE指定的端口。
ENV:在容器的系统了定义环境变量,ENV,ADD,COPY等指令可使用。
语法:
例子:${DOC_ROOT:-/data/html/}的用法是,if(DOC_ROOT 没有值) {DOC_ROOT=/data/html/}
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" ENV DOC_ROOT=/data/html/ \ WEB_SERVER_PACKAGE="/nginx-1.2.9" COPY index.html ${DOC_ROOT:-/data/html/} COPY yum.repos.d /etc/yum.repos.d/ #ADD http://nginx.org/download/nginx-1.2.9.tar.gz /usr/local/src/ WORKDIR /usr/local/ ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/ VOLUME /usr/local/src EXPOSE 80
延申,在docker run的时候也可使用-e
选项设置环境变量。
在run的时候,经过-e,能够改变dockerfile里指定环境变量的值。
dockerfile里定义的是nginx-1.2.9,可是-e指定的nginx-1.2.3,因此WEB_SERVER_PACKAGE=/nginx-1.2.3。
# docker run --name b1 --rm -e WEB_SERVER_PACKAGE=/nginx-1.2.3 tinyhttpd:v0.03 printenv PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=7a242517b02e WEB_SERVER_PACKAGE=/nginx-1.2.3
可是,/usr/local/src里的目录仍是nginx-1.2.9。由于在build的时点,image里放的就已是nginx-1.2.9了,因此你在-e里,改变的只是环境变量的值而已。
# docker run --name b1 --rm -e WEB_SERVER_PACKAGE=/nginx-1.2.3 tinyhttpd:v0.03 ls /usr/local/src nginx-1.2.9
RUN:在build执行过程当中,执行基础镜像里能够执行的任何shell命令。若是是多个命令是有关联的话,最好写到一块儿。
语法:
例子:咱们指定ADD里的src若是是压缩文件的话,不会自动解压缩,因此咱们RUN一个tar命令去解压缩它。
FROM busybox:latest MAINTAINER "magedu <mage@magedu.com>" LABEL maintainer="magedu <mage@magedu.com>" ENV DOC_ROOT=/data/html/ \ WEB_SERVER_PACKAGE="nginx-1.2.9" COPY index.html ${DOC_ROOT:-/data/html/} COPY yum.repos.d /etc/yum.repos.d/ ADD http://nginx.org/download/${WEB_SERVER_PACKAGE}.tar.gz /usr/local/src/ RUN cd /usr/local/src && \ tar xf ${WEB_SERVER_PACKAGE}.tar.gz
RUN用途举例:先找个基础的centos镜像,而后装一个nginx,通常都是下载源代码编译安装,不是使用yum install。理由是yum会产生多余的文件。
FROM centos RUN yum -y install epel-release && \ yum makecache && \ yum install nginx
CMD:在docker build时不被运行,而是在docker run时运行。好比nginx镜像启动的时候,那么CMD确定是启动nginx的命令。因此CMD即便给了多个,只有最后一个生效。
语法:
CMD <command>
command一般是shell命令,并且是以/bin/sh -c来运行此命令,所以,是经过shell启动的,因此可使用shell的特性,并且启动结束后,shell进程会自动推出,让此进程代替shell进程。因此它pid是1。
CMD ["executable1","arg1","executable2","arg1"]
executable是目录名加上可执行程序名,好比/bin/ls。它不是经过/bin/sh -c来运行,是由内核直接启动,因为不是由shell启动,因此shell里的通配符,管道,重定向等特性,所有不能用。若是想用shell特性,能够这么使用:CMD ["/bin/bash","-c","executable","arg"].
RUN的第一种和第二种用法和CMD的第一种和第二种用法同样。
CMD ["arg1","arg2"]
配合ENTRYPOINT命令使用。
例子:
FROM busybox LABEL maintainer="mageedu <mage@magedu.com>" app="httpd" ENV WEB_ROOT="/data/web/html/" RUN mkdir -p ${WEB_ROOT} && \ echo '<h1>Busybox httpd.</h1>' > ${WEB_ROOT}/index.html CMD /bin/httpd -f -h ${WEB_ROOT}
确认结果:用inspect确认,确实是用/bin/sh -c来启动的。
"Cmd": [ "/bin/sh", "-c", "/bin/httpd -f -h ${WEB_ROOT}" ],
pid也是1
docker exec -it b1 /bin/sh / # ps PID USER TIME COMMAND 1 root 0:00 /bin/httpd -f -h /data/web/html/ 6 root 0:00 /bin/sh 11 root 0:00 ps # printenv HOSTNAME=e877c51f7dab WEB_ROOT=/data/web/html/
ENTRYPOINT:
相似CMD指令,用于为容器指定默认运行程序。
与CMD不一样的是,不会被docker run指定的参数覆盖(也有覆盖的办法),并且docker run指定的参数,会自动加到ENTRYPOINT命令的后面,至关于ENTRYPOINT命令的参数了。
run时使用--entrypoint string选项,能够强制替换ENTRYPOINT命令。
若是docker run时没有指定参数,则使用上面CMD的第三种格式定义的参数,做为ENTRYPOINT的参数。
若是docker run时指定了参数,CMD的第三种格式也指定了参数,ENTRYPOINT使用的是docker run时指定的参数,忽略CMD的第三种格式指定的参数。
dockerfile文件种也能够出现多个ENTRYPOINT,但只有最后一个生效。
语法:
例子:在build时建立nginx的配置文件,并且在run的时候,还能够经过-e参数传递环境变量,修改监听的端口号等信息。
FROM nginx:alpine LABEL maintainer="MageEdu <mage@magedu.com>" ENV NGX_DOC_ROOT="/data/web/html/" ADD entrypoint.sh /bin/ ADD index.html ${NGX_DOC_ROOT} CMD ["/usr/sbin/nginx", "-g", "daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"]
ENTRYPOINT命令执行的是一个本身定义的shell命令文件,内容以下。
首先用cat命令建立了一个nginx的配置文件,还使用了环境变量。
而后,调用exec系统函数,参数是CMD定义的命令:["/usr/sbin/nginx", "-g", "daemon off;"]。exec函数的做用是:启动ngxin进程,并终止当前进程(/bin/sh进程),让nginx进程取代当前的shell进程,因此nginx进程的pid是1。
"$@":shell的所有参数,也就是/usr/sbin/nginx", "-g", "daemon off;
entrypoint.sh:
#!/bin/sh cat > /etc/nginx/conf.d/www.conf << EOF server { server_name $HOSTNAME; listen ${IP:-0.0.0.0}:${PORT:-80}; root ${NGX_DOC_ROOT:-/usr/share/nginx/html}; } EOF exec "$@"
当run的时候,执行ENTRYPOINT命令,参数是CMD里定义的。
确认结果:经过-e把监听端口设置成了8080;nginx的pid是1;www.conf也被建立了。在宿主机器上执行【curl -H "Host: a6b94dae9be4" 192.0.0.2:8080】,也输出了index.html的结果。
# docker run --name b1 --rm -d -e "PORT=8080" mynignx:002 # docker exec -it b1 /bin/sh / # netstat -tnl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN # cat /etc/nginx/conf.d/www.conf server { server_name a6b94dae9be4; listen 0.0.0.0:8080; root /data/web/html/; } / # ps PID USER TIME COMMAND 1 root 0:00 nginx: master process /usr/sbin/nginx -g daemon off; 8 nginx 0:00 nginx: worker process # cat /data/web/html/index.html <h1>nginx hello</h1> $ curl -H "Host: a6b94dae9be4" 192.0.0.2:8080 <h1>nginx hello</h1>
试验一下,在run时,指定参数:/usr/sbin/nginx daemon off(故意不加-g),去覆盖CMD。由于缺乏了-g,因此容器启动失败,说明了,确实覆盖CMD里定义的命令。
# docker run --name b1 --rm -d -e "PORT=8080" mynignx:002 /usr/sbin/nginx daemon off 4c88e021408c143ec45e70611c42bd715831cb9c75d6f4a00d307a7a6b53af5c [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
试验一下,使用--entrypoint "/bin/sh",覆盖ENTRYPOINT。
覆盖成功了,1号进程是/bin/sh进程;www.conf文件没有被建立;nginx进程没有被启动。
# docker run --name b1 --rm -it -e "PORT=8080" --entrypoint "/bin/sh" mynignx:002 / # ls bin dev home media opt root sbin sys usr data etc lib mnt proc run srv tmp var / # ps PID USER TIME COMMAND 1 root 0:00 /bin/sh 7 root 0:00 ps / # ls /etc/nginx/conf.d/ default.conf
ENTRYPOINT用法的最佳实践:build以前事先建立好配置文件,build时,注入到image了。就能达到动态建立各类服务的配置文件,从而解决了只是由于配置文件的不一样,而不得不建立多个image的问题。
USER
使用USER的背景,不指定USER的时候,进程的全部者都是root,好比下面的nginx。当不但愿是root的时候,使用此命令。
/ # ps PID USER TIME COMMAND 1 root 0:00 nginx: master process nginx -g daemon off;
docker run,CMD,ENTRYPOINT执行的时候,所使用的用户名或者UID
默认状况下是root
语法:USER <UID> | <UserName>
UID或者UserName必须是在image里存在的,必须存在于/etc/passwd中。
HEALTHCHECK:
按期查看容器里运行的进程是否还在工做状态。docker本身会自动检查容器里的进程是否还活着,若是死了或者不在前台运行的时候,docker会自动杀死这个容器。但这是不够的,有的容器即便活着,但不能提供服务了,那也至关于死了,因此要本身定义一个命令去检查容器里运行的进程,是否还在工做。
语法:
例子:健康检查结果是正常的。
FROM nginx:alpine LABEL maintainer="MageEdu <mage@magedu.com>" ENV NGX_DOC_ROOT="/data/web/html/" ADD entrypoint.sh /bin/ ADD index.html ${NGX_DOC_ROOT} HEALTHCHECK --interval=3s --timeout=3s \ CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/ CMD ["/usr/sbin/nginx", "-g", "daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"]
结果确认:
# docker run --name b1 --rm mynginx:v001 127.0.0.1 - - [08/Dec/2019:13:54:18 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2019:13:54:21 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2019:13:54:25 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
例子:健康检查结果是不正常的。发现不正常后,直接【kill 1】。容器启动后,立刻就被杀死了。
FROM nginx:alpine LABEL maintainer="MageEdu <mage@magedu.com>" ENV NGX_DOC_ROOT="/data/web/html/" ADD entrypoint.sh /bin/ ADD index.html ${NGX_DOC_ROOT} HEALTHCHECK --interval=1s --timeout=1s --retries=1 \ CMD wget -O - -q http://${IP:-0.0.0.0}:10080/ || kill 1 CMD ["/usr/sbin/nginx", "-g", "daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"]
SHELL:指定用哪一个shell去运行RUN,CMD,ENTRYPOINT的命令,默认是/bin/sh -c。
STOPSIGNAL:【docker stop 容器名】默认是个PID为1的进程发送15号信号。STOPSIGNAL能够指定别的信号。
ARG:
在build时,经过【--build-arg】传入到dockerfile里面的变量
dockerfile里能够有多个ARG
语法: ARG <name>[=<default value>]
能够在dockerfile里定有ARG的默认值
ARG version=1.14
例子:
FROM nginx:alpine ARG author="MageEdu <mage@magedu.com>" LABEL maintainer=${author}
确认结果:build时,没有使用--build-arg
# docker build -t mynginx:v002 ./ # docker image inspect mynginx:v002 "Labels": { "maintainer": "MageEdu <mage@magedu.com>" },
确认结果:build时,使用--build-arg
# docker build --build-arg author="abc <asd@sd.com>" -t mynginx:v002 ./ # docker image inspect mynginx:v002 "Labels": { "maintainer": "abc <asd@sd.com>" },
ONBUILD