docker -f dockerfile1 -t 镜像名:tag .-f指定dockerfile 文件. 当前目录
其中镜像名可以是name1/name2:tag 注意容易写成路径形式/name1/name2:tag 会报错
docker build 的时候可以明显看出层结构,dockerfile 中的每一个命令就是一层
语法
FROM
定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
FROM <image> [AS <name>]FROM <image>[:<tag>] [AS <name>]FROM <image>[@<digest>] [AS <name>]
没有指定tag 就代表使用latest的版本
FROM scratch
如果以 scratch 为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
RUN
用于执行后面跟着的命令行命令。有以下俩种格式:
1.RUN <命令行命令> 等同于,在终端操作的 shell 命令
2.RUN ["可执行文件", "参数1", "参数2"]
eg:
RUN [“./test.php”, “dev”, “offline”] 等价于 RUN ./test.php dev offline
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大,任何无关的东西都应该清理掉。不需要的中间文件
FROM centosRUN yum -y install wgetRUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"RUN tar -xvf redis.tar.gz
可简化为以下格式,用&& 连接,同时可以删除掉没有用的 redis.tar.gz:
FROM centosRUN yum -y install wget \&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \&& tar -xvf redis.tar.gz&& rm redis.tar.gz
apt-get remove 会删除软件包而保留软件的配置文件apt-get purge 会同时清除软件包和软件的配置文件
COPY
COPY <src> <dest>
WORKDIR /appCOPY nickdir .
注意: 只复制目录下面的内容,而不复制目录本身,如果需要复制目录本身需要指定这个目录的名称
WORKDIR /appCOPY nickdir ./nickdir
ADD
ADD <src> <dest>
特殊作用1:解压压缩文件并把它们添加到镜像中
WORKDIR /appADD nickdir.tar.gz .
特殊作用2:从 url 拷贝文件到镜像中
下面的两段代码来自 docker 官方文档
ADD http://example.com/big.tar.xz /usr/src/things/RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/thingsRUN make -C /usr/src/things all
在 docker 官方文档的最佳实践中却强烈建议不要这么用!!docker 官方建议我们当需要从远程复制文件时,最好使用 curl 或 wget 命令来代替 ADD 命令。原因是,当使用 ADD 命令时,会创建更多的镜像层,当然镜像的 size 也会更大
如果使用下面的命令,不仅镜像的层数减少,而且镜像中也不包含 big.tar.xz 文件:
RUN mkdir -p /usr/src/things \&& curl -SL http://example.com/big.tar.xz \| tar -xJC /usr/src/things \&& make -C /usr/src/things all
CMD
如果用户启动容器run时指定了运行的命令,则会覆盖掉CMD指定的命令,出现多次,只有最后一个有效。
CMD <command> param1 param2 #shell 模式CMD ["executable","param1","param2"] #exec模式CMD ["param1","param2"] # 作为ENTRYPOINT指令的默认参数
当 ENTRYPOINT 与 CMD 同时给出时,CMD 中的内容会作为 ENTRYPOINT 定义命令的参数,最终执行容器启动的还是 ENTRYPOINT 中给出的命令。
ENTRYPOINT
ENTRYPOINT的指令不会被docker run 运行的命令项所覆盖。如果需要覆盖ENTRYPOINT的指令,需要使用docker run —entrypoint
ENTRYPOINT <command> param1 param2 #shell 模式ENTRYPOINT ["executable","param1","param2"] #exec模式
ENV
设置容器的环境变量,ENV 通过-e 设置 docker run 传参。
EVN <key> <value> #只能设置一个EVN <key>=<value>#允许一次设置多个
eg:
FROM alpineENV animals="turtle, monkey, goose"
docker run -it -e animals="mouse,rat,kangaroo" image
ARG
ARG指令用于docker build设置构建参数,类似于ENV。和ENV不同的是,ARG设置的是构建时的环境变量,在容器运行时是不会存在这些变量的。创建一个Dockerfile文件 内容如下
eg:
FROM alpineARG runmode=PROENV env=$runmodeCMD echo $env
执行dockerfile创建镜像baxiang/alpine
ARG 通过 --build-arg接收docker build 时传入的参数
$ docker build -t baxiang/alpine --build-arg runmode=dev ./
创建容器,获取当前的环境变量参数
$ docker run -it baxiang/alpine sh/ # echo $envdev
VOLUME
容器内目录/tmp 和 /usr/tmp,匿名挂载映射到宿主机
FROM java:8VOLUME /tmp /usr/tmpCOPY /target/springbootdemo.jar app.jarRUN bash -c 'touch /app.jar'EXPOSE 10001ENTRYPOINT ["java","-jar","/app.jar"]
Source是宿主机目录,Destination是容器内目录
$ docker inspect add8a379065c"Mounts": [{"Type": "volume","Name": "3c18486ccfe419156ef62d346d29f6668ec34a236497c47f7e7907e95c310d0e","Source": "/var/lib/docker/volumes/3c18486ccfe419156ef62d346d29f6668ec34a236497c47f7e7907e95c310d0e/_data","Destination": "/tmp","Driver": "local","Mode": "","RW": true,"Propagation": ""},{"Type": "volume","Name": "c5b6e1e0f6db6e70f15d836caa9663173e4bd8e23db1817146c31348d931a43b","Source": "/var/lib/docker/volumes/c5b6e1e0f6db6e70f15d836caa9663173e4bd8e23db1817146c31348d931a43b/_data","Destination": "/usr/tmp","Driver": "local","Mode": "","RW": true,"Propagation": ""}]
运行时可以覆盖这个挂载设置。执行:-v mydata:/data,就使用了本地 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。
docker run --name ubuntu2 -v ~/mytmp:/tmp dengxiaotian/ubuntu
"Mounts": [{"Type": "bind","Source": "/home/dengxiaotian/mytmp","Destination": "/tmp","Mode": "","RW": true,"Propagation": "rprivate"}],
EXPOSE
EXPOSE <端口1> [<端口2>...]
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P时,会自动随机映射 EXPOSE 的端口。
eg:
# 暴露多个端口;EXPOSE port1 port2 port3# 如果想代理EXPOSE端口, 相应的运行容器使用的命令;# 宿主端口随机$ docker run -p port1 -p port2 -p port3 image# 还可以指定需要映射到宿主机器上的某个端口号;# 指定宿主主机端口$ docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image
-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而EXPOSE仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。例如,如果你想在宿主机上访问对应port1端口的服务 时,需要使用命令docker run -p 宿主机端口:port1 image将端口进行映射。EXPOSE只是起到了声明作用,不是说我写了80端口,这个容器就只能使用80了,如果你想5000端口也可以向外暴露,也可以使用命令:docker run -p 宿主机端口:5000 imageWORKDIR
为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录,如果当前目录不存在会自动创建 ```bash FROM ubuntu:18.04 WORKDIR /eventrisk
COPY ./conf/ ./conf/ COPY ./resources/ ./resources/ COPY eventrisk .
CMD [“./eventrisk”]
<a name="VL4Px"></a>## USER```bashFROM jenkinsci/blueocean:latestUSER root
指定运行容器时的用户名或UID,后续的RUN、CMD、ENTRYPOINT也会使用指定用户
LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
eg:
LABEL org.opencontainers.image.authors="runoob"# 用/实现换行LABEL description="This text illustrates \that label-values can span multiple lines."
HEALTHCHECK
FROM nginx:latestCOPY test.txt /test.txtHEALTHCHECK --interval=5s --timeout=3s CMD cat /test.txt || exit 1
rm test.txt

可以用 docker inspect 来查看unhealth 的原因
ONBUILD
tips:
docker push 发布到dockerhub 或者阿里云
点击tag跳转到Dockerfile

