【云原生 | Docker篇】深入Dockerfile(四)(下)

简介: 【云原生 | Docker篇】深入Dockerfile(四)(下)

五、CMD和ENTRYPOINT



5.1、都可以作为容器启动入口


CMD 的三种写法:

  • CMD ["executable","param1","param2"] ( exec 方式, 首选方式)
  • CMD ["param1","param2"] (为ENTRYPOINT提供默认参数)
  • CMD command param1 param2 ( shell 形式)


ENTRYPOINT 的两种写法:


  • ENTRYPOINT ["executable", "param1", "param2"] ( exec 方式, 首选方式)
  • ENTRYPOINT command param1 param2 (shell 形式)


# 一个示例
FROM alpine
LABEL maintainer=leifengyang
CMD ["1111"]
CMD ["2222"]
ENTRYPOINT ["echo"]
# 构建出如上镜像后测试
docker run xxxx :效果 echo 1111


5.2、只能有一个CMD


  • Dockerfile中只能有一条CMD指令。 如果您列出多个CMD,则只有最后一个CMD才会生效。
  • CMD的主要目的是为执行中的容器提供默认值。 这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您还必须指定ENTRYPOINT指令。


5.3、CMD为ENTRYPOINT提供默认参数


  • 如果使用CMD为ENTRYPOINT指令提供默认参数,则CMD和ENTRYPOINT指令均应使用JSON数组格式指定。


5.4、组合最终效果


image.pngimage.png

5.5、docker run启动参数会覆盖CMD内容


# 一个示例
FROM alpine
LABEL maintainer=leifengyang
CMD ["1111"]
ENTRYPOINT ["echo"]
# 构建出如上镜像后测试
docker run xxxx :什么都不传则 echo 1111
docker run xxx arg1 :传入 arg1 则 echo arg1


六、ARG和ENV


6.1、ARG


  • ARG指令定义了一个变量,用户可以在构建时使用--build-arg = 传递,docker build命令会将其传递给构建器。
  • --build-arg 指定参数会覆盖Dockerfile 中指定的同名参数
  • 如果用户指定了 未在Dockerfile中定义的构建参数 ,则构建会输出 警告 。
  • ARG只在构建期有效,运行期无效
  • 不建议使用构建时变量来传递诸如github密钥,用户凭据等机密。因为构建时变量值使用docker history是可见的。
  • ARG变量定义从Dockerfile中定义的行开始生效。
  • 使用ENV指令定义的环境变量始终会覆盖同名的ARG指令。


6.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 的值,会改变哪些值,如何修改这些值 ?


6.3、综合测试示例


FROM alpine
ARG arg1=22222
ENV arg2=1111111
ENV runcmd=$arg1
RUN echo $arg1 $arg2 $runcmd
CMD echo $arg1 $arg2 $runcmd


七、ADD和COPY


7.1、COPY


COPY 的两种写法


COPY [--chown = <user>:<group>] <src>... <dest>
COPY [--chown = <user>:<group>] [ "<src>" ,... "<dest>" ]


--chown功能仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起


作用


  • COPY指令从 src 复制新文件或目录,并将它们添加到容器的文件系统中,路径为 dest 。
  • 可以指定多个 src 资源,但是文件和目录的路径将被解释为相对于构建上下文的源。
  • 每个 src 都可以包含通配符,并且匹配将使用Go的filepath.Match规则进行。


COPY hom* /mydir/ # 当前上下文,以 home 开始的所有资源
COPY hom?.txt /mydir/ # ? 匹配单个字符
COPY test.txt relativeDir/ # 目标路径如果设置为相对路径,则相对与 WORKDIR 开始


# 把 “test.txt” 添加到 <WORKDIR>/relativeDir/
COPY test.txt /absoluteDir/ # 也可以使用绝对路径,复制到容器指定位置
# 所有复制的新文件都是 uid(0)/gid(0) 的用户,可以使用 --chown 改变
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/


7.2、ADD


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


注意:


  • src 路径必须在构建的上下文中; 不能使用 ../something /something 这种方式,因为docker构建的第一步是将上下文目录(和子目录)发送到docker守护程序。
  • 如果 src 是URL,并且 dest 不以斜杠结尾,则从URL下载文件并将其复制到 dest 。
  • 如果 dest 以斜杠结尾,将自动推断出url的名字(保留最后一部分),保存到 dest
  • 如果 src 是目录,则将复制目录的整个内容,包括文件系统元数据。


八、WORKDIR和VOLUME



8.1、WORKDIR


WORKDIR指令为Dockerfile中跟随它的所有 RUN,CMD,ENTRYPOINT,COPY,ADD 指令设置工作目录。 如果WORKDIR不存在,即使以后的Dockerfile指令中未使用它也将被创建。


WORKDIR指令可在Dockerfile中多次使用。 如果提供了相对路径,则它将相对于上一个WORKDIR指令的路径。 例如:


WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# 结果 /a/b/c
也可以用到环境变量
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
# 结果 /path/$DIRNAME


8.2、VOLUME


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


写法:


VOLUME ["/var/log/"] # 可以是 JSON 数组
VOLUME /var/log # 可以直接写
VOLUME /var/log /var/db # 可以空格分割多个


注意:


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


九、USER



写法:


USER <user>[:<group>]
USER <UID>[:<GID>]


USER 指令设置运行映像时要使用的用户名(或 UID )以及可选的用户组(或 GID ),以及 Dockerfile中USER 后面所有 RUN , CMD 和 ENTRYPOINT 指令。


十、EXPOSE



EXPOSE指令通知Docker容器在运行时在指定的网络端口上进行侦听。 可以指定端口是侦听TCP还是UDP,如果未指定协议,则默认值为TCP。


EXPOSE指令实际上不会发布端口。 它充当构建映像的人员和运行容器的人员之间的一种文档,即有关打算发布哪些端口的信息。 要在运行容器时实际发布端口,请在docker run上使用-p标志发布并映射一个或多个端口,或使用-P标志发布所有公开的端口并将其映射到高阶端口。


EXPOSE <port> [<port>/<protocol>...]
EXPOSE [80,443]
EXPOSE 80/tcp
EXPOSE 80/udp


十一、multi-stage builds


多阶段构建


11.1、使用


https://docs.docker.com/develop/develop-images/multistage-build/

解决:如何让一个镜像变得更小 ; 多阶段构建的典型示例


### 我们如何打包一个 Java 镜像
FROM maven
WORKDIR /app
COPY . .
RUN mvn clean package
COPY /app/target/*.jar /app/app.jar
ENTRYPOINT java -jar app.jar
## 这样的镜像有多大?
## 我们最小做到多大?


11.2、生产示例


#  以下所有前提 保证 Dockerfile 和项目在同一个文件夹
# 第一阶段:环境构建 ; 用这个也可以
FROM maven:3.5.0-jdk-8-alpine AS builder
WORKDIR /app
ADD ./ /app
RUN mvn clean package -Dmaven.test.skip=true
# 第二阶段,最小运行时环境,只需要 jre ;第二阶段并不会有第一阶段哪些没用的层
#  基础镜像没有 jmap ; jdk springboot-actutor ( jdk )
FROM openjdk:8-jre-alpine
LABEL maintainer="lanson"
# 从上一个阶段复制内容
COPY --from=builder /app/target/*.jar /app.jar
# 修改时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo
'Asia/Shanghai' >/etc/timezone && touch /app.jar
ENV JAVA_OPTS=""
ENV PARAMS=""
# 运行 jar 包
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom
$JAVA_OPTS -jar /app.jar $PARAMS" ]
<!-- 为了加速下载需要在 pom 文件中复制如下 -->
<repositories>
<repository>
<id> aliyun </id>
<name> Nexus Snapshot Repository </name>
<url> https://maven.aliyun.com/repository/public </url>
<layout> default </layout>
<releases>
<enabled> true </enabled>
</releases>
<!--snapshots 默认是关闭的 , 需要开启 -->
<snapshots>
<enabled> true </enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id> aliyun </id>
<name> Nexus Snapshot Repository </name>
<url> https://maven.aliyun.com/repository/public </url>
<layout> default </layout>
<releases>
<enabled> true </enabled>
</releases>
<snapshots>
<enabled> true </enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
###### 小细节
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo
'Asia/Shanghai' >/etc/timezone
或者
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo
'Asia/Shanghai' >/etc/timezone
可以让镜像时间同步。
## 容器同步系统时间 CST ( China Shanghai Timezone )
-v /etc/localtime:/etc/localtime:ro
# 已经不同步的如何同步?
docker cp /etc/localtime 容器 id:/etc/
docker build --build-arg url="git address" -t demo:test . :自动拉代码并构建镜像
FROM maven:3.6.1-jdk-8-alpine AS buildapp
# 第二阶段,把克隆到的项目源码拿过来
# COPY --from=gitclone * /app/
WORKDIR /app
COPY pom.xml .
COPY src .
RUN mvn clean package -Dmaven .test .skip = true
# /app 下面有 target
RUN pwd && ls -l
RUN cp /app/target/*.jar /app.jar
RUN ls -l
### 以上第一阶段结束,我们得到了一个 app.jar
## 只要一个 JRE
# FROM openjdk:8-jre-alpine
FROM openjdk:8u282-slim
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo
'Asia/Shanghai' >/etc/timezone
LABEL maintainer = "lanson"
# 把上一个阶段的东西复制过来
COPY --from = buildapp /app.jar /app.jar
# docker run -e JAVA_OPTS="-Xmx512m -Xms33 -" -e PARAMS="--spring.profiles=dev --server.port=8080" -jar /app/app.jar
# 启动 java 的命令
ENV JAVA_OPTS = ""
ENV PARAMS = ""
ENTRYPOINT [ "sh" , "-c" , "java -Djava.security.egd=file:/dev/./urandom
$JAVA_OPTS -jar /app.jar $PARAMS " ]


自己 写一个多阶段构建


1、自动从git下载指定的项目

2、把项目自动打包生成镜像

3、我们只需要运行镜像即可


十二、Images瘦身实践



选择最小的基础镜像

合并RUN环节的所有指令,少生成一些层

RUN期间可能安装其他程序会生成临时缓存,要自行删除。如:


# 开发期间,逐层验证正确的
RUN xxx
RUN xxx
RUN aaa \
aaa \
vvv \
#  生产环境
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion \
&& rm -rf /var/lib/apt/lists/*


  • 使用 .dockerignore 文件,排除上下文中无需参与构建的资源
  • 使用多阶段构建
  • 合理使用构建缓存加速构建。[--no-cache]

学习更多 Dockerfile 的写法: https://github.com/docker-library/


十三、springboot java 最终写法



FROM openjdk:8-jre-alpine
LABEL maintainer="lanson"
COPY target/*.jar /app.jar
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo
'Asia/Shanghai' >/etc/timezone && touch /app.jar
ENV JAVA_OPTS=""
ENV PARAMS=""
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom
$JAVA_OPTS -jar /app.jar $PARAMS" ]
# 运行命令 docker run -e JAVA_OPTS="-Xmx512m -Xms33 -" -e PARAMS="--spring.profiles=dev --server.port=8080" -jar /app/app.jar


目录
相关文章
|
10天前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker和Kubernetes入门
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
41 2
|
7天前
|
运维 Cloud Native 虚拟化
一文吃透云原生 Docker 容器,建议收藏!
本文深入解析云原生Docker容器技术,涵盖容器与Docker的概念、优势、架构设计及应用场景等,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
一文吃透云原生 Docker 容器,建议收藏!
|
1月前
|
Kubernetes Cloud Native 云计算
云原生入门:从Docker到Kubernetes的旅程
【10月更文挑战第2天】本文将带你走进云原生的世界,从基础的Docker容器技术开始,逐步深入到Kubernetes集群管理。我们将通过实际代码示例,探索如何利用这些工具构建、部署和管理现代云应用。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的知识和技能,让你在云原生领域迈出坚实的一步。
85 5
|
16天前
|
应用服务中间件 PHP nginx
Docker-compose 编排lnmp(dockerfile) 完成Wordpress
通过使用Docker Compose,我们可以轻松编排LNMP环境并部署WordPress。本文详细介绍了各组件的Dockerfile和配置文件编写,并通过docker-compose.yml文件实现了整个环境的自动化部署。这种方法不仅简化了部署过程,还提高了环境的可移植性和一致性。希望本文能帮助你更好地理解和使用Docker Compose来管理和部署复杂的应用程序。
43 3
|
25天前
|
Kubernetes Cloud Native 开发者
云原生技术入门:Kubernetes和Docker的协作之旅
【10月更文挑战第22天】在数字化转型的浪潮中,云原生技术成为推动企业创新的重要力量。本文旨在通过浅显易懂的语言,引领读者步入云原生的世界,着重介绍Kubernetes和Docker如何携手打造弹性、可扩展的云环境。我们将从基础概念入手,逐步深入到它们在实际场景中的应用,以及如何简化部署和管理过程。文章不仅为初学者提供入门指南,还为有一定基础的开发者提供实践参考,共同探索云原生技术的无限可能。
36 3
|
1月前
|
Kubernetes Cloud Native 开发者
探秘云原生计算:Kubernetes与Docker的协同进化
在这个快节奏的数字时代,云原生技术以其灵活性和可扩展性成为了开发者们的新宠。本文将带你深入了解Kubernetes和Docker如何共同塑造现代云计算的架构,以及它们如何帮助企业构建更加敏捷和高效的IT基础设施。
|
1月前
|
Docker 容器
docker中使用Dockerfile自动创建数据卷
【10月更文挑战第12天】
19 5
|
1月前
|
安全 Cloud Native Shell
云上攻防:云原生篇&Docker容器逃逸
本文介绍了Docker的基本概念及其对渗透测试的影响,重点讲解了容器逃逸的方法。Docker是一种轻量级的容器技术,与虚拟机相比,具有更高的便携性和资源利用率。然而,这也带来了安全风险,特别是容器逃逸问题。文章详细描述了三种常见的容器逃逸方法:不安全的配置、相关程序漏洞和内核漏洞,并提供了具体的检测和利用方法。此外,还介绍了几种特定的漏洞(如CVE-2019-5736和CVE-2020-15257)及其复现步骤,帮助读者更好地理解和应对这些安全威胁。
云上攻防:云原生篇&Docker容器逃逸
|
1月前
|
Kubernetes Cloud Native Docker
云原生入门:Kubernetes和Docker的协同之旅
【10月更文挑战第4天】在这篇文章中,我们将通过一次虚拟的旅行来探索云原生技术的核心——Kubernetes和Docker。就像乘坐一艘由Docker驱动的小船启航,随着波浪(代码示例)起伏,最终抵达由Kubernetes指挥的宏伟舰队。这不仅是一段技术上的旅程,也是理解现代云架构如何支撑数字世界的冒险。让我们扬帆起航,一探究竟!
|
1月前
|
消息中间件 NoSQL Kafka
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
41 4
下一篇
无影云桌面