目录
一、FROM 语法
二、label语法
三、run语法
四、workdir 语法
五、add 和copy 语法
六、ENV语法
七、volume 和expose 语法
八、run、cmd 和entrypoint


一、FROM 语法
scratch -- 从头开始
尽量来使用官方提供的image
FROM 指定基础镜像,最好挑一些apline,slim之类的基础小镜像. scratch镜像是一个空镜像,常用于多阶段构建 如何确定我需要什么要的基础镜像? Java应用当然是java基础镜像(SpringBoot应用)或者Tomcat基础镜像(War应用) JS模块化应用一般用nodejs基础镜像 其他各种语言用自己的服务器或者基础环境镜像,如python、golang、java、php等


编辑
二、label语法
meta信息,类似于代码的注释。


LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
三、run语法
没run一次image上会有新的一层。因此有必要使用&&合并执行,避免layer 过多看起来很混乱。


编辑
四、workdir 语法
使用workdir不要使用run cd来替代
workdir尽量使用绝对路径。增强dockerfile的可移植性。


编辑
五、add 和copy 语法
区别:add 还具有解压缩的功能,例如add test.tat.gz / 会直接将test.tar.gz解压出来
下面以reids源代码为例进行演示
Dockerfile如下
FROM alpine
ADD ./redis-7.0.8.tar.gz /redis/
RUN ls -l
RUN cd /redis && ls -l
结果

workdir 和add的结合
添加远程文件/目录使用curl 或者 wget


编辑
copy文件夹时候的坑
https://www.jianshu.com/p/9b7da9aacd8a
六、ENV语法
定义常量,增加可维护性,和shell中定义变量一个意思。


编辑
七、volume 和expose 语法
八、run、cmd 和entrypoint


编辑


例子:
shell 格式的docker file build的image
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# more Dockerfile
FROM centos
ENV name Docker
ENTRYPOINT echo "hello $name"
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker build -t ninesun0318/centos-entrypoint-shell .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM centos
---> 0d120b6ccaa8
Step 2/3 : ENV name Docker
---> Running in 00b2f71e6d9f
Removing intermediate container 00b2f71e6d9f
---> 4be9a34323b3
Step 3/3 : ENTRYPOINT echo "hello $name"
---> Running in cfc67b613f7a
Removing intermediate container cfc67b613f7a
---> 865aaaacd1ee
Successfully built 865aaaacd1ee
Successfully tagged ninesun0318/centos-entrypoint-shell:latest
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ninesun0318/centos-entrypoint-shell latest 865aaaacd1ee 17 seconds ago 215MB
centos latest 0d120b6ccaa8 2 months ago 215MB
hello-world latest bf756fb1ae65 10 months ago 13.3kB
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker run 865aaaacd1ee
hello Docker

很完美这个dockerfile没有问题。
exec格式的docker file build的image
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# more Dockerfile
FROM centos
ENV name Docker
ENTRYPOINT ["/bin/echo", "hello $name"]
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker build -t ninesun0318/centos-entrypoint-exec .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM centos
---> 0d120b6ccaa8
Step 2/3 : ENV name Docker
---> Using cache
---> 4be9a34323b3
Step 3/3 : ENTRYPOINT ["/bin/echo", "hello $name"]
---> Running in 61c84954936b
Removing intermediate container 61c84954936b
---> 2292313abbf0
Successfully built 2292313abbf0
Successfully tagged ninesun0318/centos-entrypoint-exec:latest
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]#
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]#
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ninesun0318/centos-entrypoint-exec latest 2292313abbf0 5 seconds ago 215MB
ninesun0318/centos-entrypoint-shell latest 865aaaacd1ee 8 minutes ago 215MB
centos latest 0d120b6ccaa8 2 months ago 215MB
hello-world latest bf756fb1ae65 10 months ago 13.3kB
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker run ninesun0318/centos-entrypoint-exec
hello $name
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]#

奇怪exec 并没有把name 这个ENV打印出来。为何?
只有shell 中才会执行name才会被解释为变量,exec 就是简单的执行。
如何修改呢?
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# more Dockerfile
FROM centos
ENV name Docker
ENTRYPOINT ["/bin/bash","-c","echo hello $name"]
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]#

重新build 然后run
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker build -t ninesun0318/centos-entrypoint-exec-new .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM centos
---> 0d120b6ccaa8
Step 2/3 : ENV name Docker
---> Using cache
---> 4be9a34323b3
Step 3/3 : ENTRYPOINT ["/bin/bash","-c","echo hello $name"]
---> Running in 5ee34add9195
Removing intermediate container 5ee34add9195
---> cf961663ddc1
Successfully built cf961663ddc1
Successfully tagged ninesun0318/centos-entrypoint-exec-new:latest
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# docker run ninesun0318/centos-entrypoint-exec-new
hello Docker
[root@iZ2vceej7yes1abpm7yec2Z dockerfile]# more Ddo
more: stat of Ddo failed: No such file or directory

这个问题得到了解决。


cmd推荐写法

Dockerfile 测试
CMD为ENTRYPOINT提供默认参数
FROM alpine
LABEL mantainer=ninesun
CMD ["testvm"]
CMD ["uuuidd"]
ENTRYPOINT ["echo"]
docker build -t demo:test -f Dockerfile3 .
docker run --rm --name test demo:test
uuuidd
# 指定其他命令
docker run --rm --name test demo:test 22222
22222


entrypoint推荐写法

例子说明:entrypoint 一定会被执行,cmd 会被覆盖。
Dockerfile列子
FROM alpine
LABEL mantainer=ninesun
CMD ["testvm"]
CMD ["uuuidd"]
ENTRYPOINT ["echo","hahhahah"]
# docker run指定参数 覆盖cmd,但是entrypoint一定被执行
docker run --rm --name test demo:test 222
hahhahah 222
# docker run 不覆盖cmd,但是entrypoint一定被执行
docker run --rm --name test demo:test
hahhahah uuuidd
CMD和ENTRYPOINT两者都可以作为容器的入口
Dockerfile中只能有一条CMD指令。 如果列出多个CMD,则只有最后一个CMD才会生效。
CMD的主要目的是为执行中的容器提供默认值。 这些默认值可以包含可执行文件,也可以省略可
执行文件,在这种情况下,您还必须指定ENTRYPOINT指令。
ARG和ENV的区别
ARG 是构建时变量
ENV是运行时变量
1、ARG
ARG指令定义了一个变量,用户可以在构建时使用--build-arg = 传递,docker build命令会将其传递给构建器。--build-arg 指定参数会覆盖Dockerfile 中指定的同名参数
如果用户指定了 未在Dockerfile中定义的构建参数 ,则构建会输出 警告 。
ARG只在构建期有效,运行期无效
不建议使用构建时变量来传递诸如github密钥,用户凭据等机密。因为构建时变量值使用docker
history是可见的。
ARG变量定义从Dockerfile中定义的行开始生效。
使用ENV指令定义的环境变量始终会覆盖同名的ARG指令。
2、ENV
在构建阶段中所有后续指令的环境中使用,并且在许多情况下也可以内联替换。
引号和反斜杠可用于在值中包含空格。
ENV 可以使用key value的写法,但是这种不建议使用了,后续版本可能会删除
ENV MY_MSG hello
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
#多行写法如下
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy

docker run --env 可以修改这些值
容器运行时ENV值可以生效
ENV在image阶段就会被解析并持久化(docker inspect image查看),参照下面示例
FROM alpine
ENV arg=1111111
ENV runcmd=$arg
RUN echo$runcmd
CMD echo$runcmd #ENV的固化问题: 改变arg,会不会改变 echo的值,会改变哪些值,如何修改这些值?
测试案例
FROM alpine
ARG arg1=22222
ENV arg2=1111111
ENV runcmd=$arg1
RUN echo$arg1$arg2$runcmd
CMD echo$arg1$arg2$runcmd
实战
java-springboot 镜像
# syntax=docker/dockerfile:1
FROM 10.50.10.185/qms/openjdk:8-jdk-alpine
LABEL maintainer="ninesun@126.com"
WORKDIR /opt/app
COPY target/*.jar ./
#Alpine Linux 下的包管理工具
#RUN apk add mysql-client
# 设定时区UTC -> CST
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone && touch EDA_ETL-0.0.51-SNAPSHOT.jar
ENV JAVA_OPTS=""
ENV PARAMS=""
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar EDA_ETL-0.0.51-SNAPSHOT.jar $PARAMS" ]
python 程序镜像
FROM submitty/python:3.7
COPY ./redis_key_mig /app
WORKDIR /app
RUN /bin/bash -c 'pwd;ls -l /app'
#RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip3 install redis==3.5.3
cmd ["python", "/app/redisMigrate.py"]