e Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。
基础的小linux系统。jdk;
一般而言,Dockerfile可以分为四部分
基础镜像信息 维护者信息 镜像操作指令 启动时执行指令
image.png

1.测试dockerfile

  1. # 这是我的Dockerfile
  2. FROM alpine
  3. #给镜像加个标签
  4. LABEL maintainer="yangchao @ dd" \
  5. abc=def
  6. #运行的指令,安装了软件,修改了文件,默认是用id=0 也就是root,这个基础系统的root用户
  7. #代表镜像构建过程中运行的命令。
  8. RUN echo 11111
  9. #镜像启动如果要运行很长命令才行,容器启动执行的命令
  10. ##1、准备一个sh文件,让镜像启动运行sh文件(大多镜像操作)
  11. ##2、直接在CMD的位置写即可
  12. CMD sleep 10;echo success
  13. //执行
  14. docker build -t myalpine:v1 -f Dockerfile1 .

image.png

2、FROM

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

3、LABEL

标注镜像的一些说明信息。

LABEL maintainer=”yangchao @ dd” \abc=def

  1. "Labels": {
  2. "abc": "def",
  3. "maintainer": "yangchao @ dd"
  4. }

4、RUN

RUN指令在当前镜像层顶部的新层执行任何命令,并提交结果,生成新的镜像层。
生成的提交映像将用于Dockerfile中的下一步。 分层运行RUN指令并生成提交符合Docker的核心概念,就像源代码控制一样。
exec形式可以避免破坏shell字符串,并使用不包含指定shell可执行文件的基本映像运行RUN命令。
可以使用SHELL命令更改shell形式的默认shell。 在shell形式中,您可以使用\(反斜杠)将一条RUN指令继续到下一行。

  1. #指定构建参数【构建时】
  2. ARG aaa=aaaa
  3. #指定环境变量【为RUN以及CMD指定环境变量的】
  4. ENV parm=11111
  5. RUN echo $msg 可以取到值
  6. RUN ["echo","$msg"] 不可以取到值
  7. # shell* 形式; bash -c "echo 11111"
  8. RUN echo $parm
  9. # exec 形式。$parm 默认拿不到ENV
  10. RUN ["echo","$aaa"]
  11. # 错误语法 RUN ["echo",'$parm']
  12. # 错误语法 RUN ["echo",$parm]
  13. # 错误语法。NOT FOUND(取不出环境变量【ENV】,ARG也是取不出)
  14. #RUN ["echo",'${aaa}']
  15. #RUN ["echo",${parm}]

RUN指令上下并没有上下文关系;

5、ARG 构建时有效

  1. #可以在任意位置定义,并在以后取值使用,
  2. #使用--build-arg version=3.13 改变;以我们传入的为准
  3. ARG version=3.13.4
  4. # 3.13
  5. FROM alpine:$version
  6. LABEL maintainer="leifengyang"
  7. ##测试构建期间生效
  8. RUN echo $app
  9. RUN echo $param
  10. # 定义以后的剩下环节(不包括运行时)能生效:取值$param;
  11. #可以在构建时进行变化,docker build
  12. # ARG不像ENV不能并排写
  13. ARG param=123456
  14. ARG msg="hello docker"
  15. #构建时期我们会运行的指令(根据Dockerfile创建一个镜像的整个过程时期)
  16. RUN echo 11111
  17. RUN echo $param
  18. RUN echo $msg
  19. #运行时期我们会运行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令)
  20. #(docker run/docker start)
  21. # CMD和ENTRYPOINT` 都是指定的运行时的指令
  22. CMD ["/bin/sh","-c","echo 1111;echo $param"]

6、ENV 可以在运行期修改

  1. #构建期+运行期都可以生效;但是只能在运行期进行修改
  2. #怎么修改:构建期修改和运行期修改
  3. #构建期不能改 ENV的值
  4. #运行期:docker run -e app=atguigu 就可以修改
  5. ENV app=itdachang

7、ENV的坑 —持久化问题

  1. # env的坑
  2. FROM alpine
  3. # ARG msg=hello
  4. # # ENV肯定能引用ARG
  5. # ENV name=${msg}
  6. # RUN echo ${name}
  7. # RUN echo ${msg}
  8. # ENV只能运行期改掉
  9. ENV msg1=hello
  10. ENV msg2=$msg1
  11. # 以上构建期间就已经确定好值了;ENV持久化问题。
  12. RUN echo ${msg1}
  13. RUN echo ${msg2}
  14. # msg1=msg2没问题;如果我运行期修改了msg1=66666的值,请求msg1;msg2输出什么
  15. # 结果输出: 6666 hello; 传值不是传引用???原因:
  16. # docker build的时候,env环境的信息会固化,直接在镜像配置里面就已经写死,msg1=hello,msg2=hello。
  17. # -e 真的只能修改当前env本身
  18. # 为什么运行期间能用ENV定义的所有值,一定是ENV存在某个地方
  19. #
  20. CMD ["/bin/sh","-c","echo ${msg1};echo ${msg2};"]

ENV 的早就已经配置好了, 不能改变引用环节
image.png

8、ADD

同COPY用法,不过ADD拥有自动下载远程文件和解压的功能。

  1. #把上下文Context指定的内容添加到镜像中,如果是压缩包,自动解压,
  2. # 把当前内容复制到这个 alpine小系统里面
  3. # 如果是远程文件,自动下载;不会解压
  4. # 如果是压缩包,自动解压;
  5. ADD https://download.redis.io/releases/redis-6.2.1.tar.gz /dest/
  6. #本地linux系统的内容文件添加进去 【宿主机 镜像内】
  7. # docker build -t demo:test -f Dockerfile 【.:上下文的文件路径】 : .代表上下文环境;代表Dockerfile所在的当前目录
  8. #自动解压
  9. # 压缩包位置:/root/dockerfiles
  10. ADD *.tar.gz /app/ #自动解压
  11. # RUN ls -l

9、 COPY

—chown功能仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用
COPY指令从 src 复制新文件或目录,并将它们添加到容器的文件系统中,路径为 dest 。
可以指定多个 src 资源,但是文件和目录的路径将被解释为相对于构建上下文的源。

  1. FROM alpine
  2. # 开用户
  3. #RUN adduser -u 1000 -g 1000
  4. # 以后的所有命令会用 abc:abc 来执行。有可能没有执行权限
  5. # 容器中的ROOT虽然不是linux宿主机的真实root,但是可以改掉这个镜像的所有
  6. USER 1000:1000
  7. # 把复制来的文件给用户所有权
  8. COPY --chown=1000:1000 *.txt /a.txt
  9. RUN ls -l /
  10. #不是root不能写
  11. RUN echo 2222 >> a.txt

10、WORKDIR

WORKDIR指令为Dockerfile中跟随它的所有 RUN,CMD,ENTRYPOINT,COPY,ADD 指令设置工作目 录。
如果WORKDIR不存在,即使以后的Dockerfile指令中未使用它也将被创建。
WORKDIR指令可在Dockerfile中多次使用。 如果提供了相对路径,则它将相对于上一个WORKDIR指 令的路径

  1. FROM alpine
  2. #此时未指定workdir 为系统根目录 /
  3. RUN pwd && ls -l
  4. # 为以下所有的命令运行指定了基础目录 /app/
  5. WORKDIR /app
  6. # 可以为进入容器指定一个默认目录 exec -it 进入工作目录 /app/abc
  7. WORKDIR /abc
  8. # /app/abc 多个WORKDIR可以嵌套
  9. RUN pwd && ls -l
  10. #复制到当前目录下
  11. COPY *.txt ./
  12. RUN pwd && ls -l
  13. CMD ping baidu.com
  14. ##比如我们的nginx镜像可以做成这样
  15. #WORKDIR /usr/share/nginx/html

11、VOLUME

作用:把容器的某些文件夹映射到主机外部

  1. VOLUME ["/var/log/"] #可以是JSON数组
  2. VOLUME /var/log #可以直接写
  3. VOLUME /var/log /var/db #可以空格分割多个
  4. FROM alpine
  5. RUN mkdir /hello && mkdir /app
  6. RUN echo 1111 > /hello/a.txt
  7. RUN echo 222 > /app/b.txt
  8. #挂载 容器的指定文件夹,如果不存在就创建。
  9. #指定了 VOLUME ,即使启动容器没有指定 -v 参数,我们也会自动进行匿名卷挂载
  10. # 容器内的 /hello ,/app 文件夹,请你在使用镜像启动容器的时候,自动给宿主机上挂载
  11. # VOLUME挂载出去的东西,容器改变也不会最终commit的时候生效
  12. # -v 使用 VOLUME和-v挂载出去的目录(外面变,容器里面变)。但是
  13. # 所有改变也生效了,1)、但是 docker commit 提交当前容器的所有变化为镜像的时候,就会丢弃
  14. # 2)、VOLUME [ "/hello","/app" ] 容器以后自动挂载,在Dockerfile中对VOLUME的所有修改都不生效
  15. # 3)、挂载只有一点就是方便在外面修改,或者把外面的东西直接拿过来
  16. # 所以这个写在最后
  17. # JAVA 日志都要挂外面 /app/log
  18. # VOLUME ["/log"]
  19. VOLUME [ "/hello","/app" ]
  20. # VOLUME 指定的挂载目录
  21. # 这两句话没有生效 -->
  22. RUN echo 6666 >> /hello/a.txt
  23. RUN echo 8888 >> /app/b.txt
  24. RUN cd /hello && echo 88888 >>a.txt
  25. #
  26. CMD ping baidu.com

注意: 用 VOLUME 声明了卷,那么以后对于卷内容的修改会被丢弃,所以, 一定在volume声明之前修改内容

12、 EXPOSE

image.png
暴露 ,这个只是一个声明;给程序员看。docker也能看到
docker -d -P(随机分配端口)

13、CMD和ENTRYPOINT

  1. FROM alpine
  2. # ENTRYPOINT: 入口(真正的门)
  3. # ENTRYPOINT [ "ping" ]
  4. # 命令(进门的时候带口令)
  5. # 最终的用法: CMD是给ENTRYPOINT提供参数的
  6. #CMD可以被修改
  7. # CMD ping baidu.com
  8. # ENTRYPOINT + CMD = 容器的完整启动命令
  9. # 这是启动命令
  10. # ENTRYPOINT ping + CMD baidu.com = 错误
  11. #多个CMD只有最后一次生效
  12. # CMD ping baidu.com
  13. # ["echo","${param}"] 不是bash -c的方式,取不出环境变量性 【】
  14. # echo $param = ["/bin/sh","-c","多长的命令都写在这里 echo ${param}"]
  15. # ENTRYPOINT或者CMD作为唯一入口,只能写一个,最后一个生效
  16. # ENTRYPOINT ping atguigu.com
  17. # RUN,CMD,ENTRYPOINT
  18. # []: ["/bin/sh","-c"] = shell
  19. # shell:

image.png

  1. FROM alpine
  2. ENV url=baidu.com
  3. #CMD ["ping","baidu.com"]
  4. # CMD ["useradd","-u","1000","-g","2000"]
  5. # CMD ["ping","${url}"] 取不出变量
  6. # CMD ping ${url}
  7. # 官方都是建议使用 []方式
  8. # CMD ["/bin/sh","-c","ping ${url}"]
  9. # ENTRYPOINT ping baidu.com + CMD怎么写都没用,容器启动都是以ENTRYPOINT的完整命令为准
  10. # java -jar xxxx.jar --spring.profile=dev --server.port=8888
  11. # 这两个合在一起不能是错误的命令
  12. #官方推荐的写法,,变化的写CMD,而CMD是提供参数给ENTRYPOINT
  13. # docker run imageName cmd1 一旦传递了cmd1,CMD指定的所有参数都会被覆盖,
  14. # 自定义参数的情况下一定要传完
  15. CMD [ "5","baidu.com" ]
  16. #exec的写法 不变的写 ENTRYPOINT;未来他是容器启动的唯一入口, ping -c 5 baidu.com
  17. ENTRYPOINT [ "ping","-c" ]

14 、 多阶段构建

  1. # 多阶段构建
  2. # FROM alpine AS build
  3. # xxxxxx
  4. # FROM jre
  5. # COPY --from=build xxx xxx
  6. # ENTRYPOINT [ "executable" ]