docker系列12:Dockerfile实战

news2024/11/15 11:21:11

 传送门

docker系列1:docker安装

docker系列2:阿里云镜像加速器

 docker系列3:docker镜像基本命令

docker系列4:docker容器基本命令

docker系列5:docker安装nginx

docker系列6:docker安装redis

docker系列7:docker安装ES

docker系列8:容器卷挂载(上)

docker系列9:容器卷挂载(下)

docker系列10:Dockerfile挂载容器卷

docker系列11:Dockerfile入门

Dockerfile文件回顾

在前面一节讨论过Dockerfile的定义,从官网的定义来看看:

Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. 

Docker可以通过读取Dockerfile中的指令自动构建镜像。Dockerfile是一个文本文档,其中包含用户可以在命令行上调用的所有命令来组装镜像。

https://docs.docker.com/build/guide/layers/

从上面的流程可以看出,大致为以下几个步骤:

  • 编写Dockerfile文件,里面通过指令定义各种步骤
  • 通过Docker读取Dockerfile文件,构建镜像
  • 镜像里面进行分层,每一条指令按顺序都会生成对应的一个层

Docker这种镜像分层的技术,使得把重复的部分抽取出来形成公共层达到复用的目的。这样的好处显而易见:

  • 相同的层可以在镜像之间共享,不用重复编写,效率得到了极大的提高,尤其是一些基础镜像

This is beneficial because it allows layers to be reused between images. For example, imagine you wanted to create another Python application. Due to layering, you can leverage the same Python base. This will make builds faster and reduce the amount of storage and bandwidth required to distribute the images.

这是有益的,因为它允许在镜像之间重用图层。例如,假设您想创建另一个Python应用程序。由于分层,您可以利用相同的Python基础。这将使构建更快,并减少分发镜像所需的存储量和带宽

  • 由于上个原因,可以对镜像做缓存,性能也得到提升
图片来自:https://docs.docker.com/build/guide/layers/#cached-layers

而这种镜像分层技术,再加上一种叫"union filesystem 联合文件系统"的技术把它们合并在一起,就形成了容器最终看到的文件系统,而它的底层实现依赖于OverlayFS

图片来自:https://docs.docker.com/engine/storage/drivers/overlayfs-driver/#image-and-container-layers-on-disk

打包自己的SpringBoot微服务镜像

前面讨论了这么多关于Dockerfile的定义、指令,也通过自定义Dockerfile来了演示Dockerfile文件的编写、构建及运行,但最终的目的还是要通过Docker来运行我们自己的应用,典型就是通过SpringBoot开发微服务。以原来的auth服务为例!

编写Dockerfile文件

先将微服务打包个包出来:

然后上传到服务器,以前面的test-docker目录为例:

创建Dockerfile文件,命名为Dockerfile_auth:

# 选择jdk8做为基础镜像
FROM java:8

# 将本机微服务jar包复制到镜像中
ADD auth-0.0.1-SNAPSHOT.jar /usr/local/bin

# 设置环境变量:jar包的路径
ENV AUTH_PATH=/usr/local/bin/auth-0.0.1-SNAPSHOT.jar

# for test
RUN echo ${AUTH_PATH}

# 容器启动时,执行微服务启动命令:java -jar auth-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar", "/usr/local/bin/auth-0.0.1-SNAPSHOT.jar"]

# 暴露端口8083
EXPOSE 8083

运行镜像

 运行上面的Dockerfile文件,生成镜像:

运行镜像auth:

然后进入容器:

  • 通过docker启动镜像:docker run -d --name auth1 auth -p 8083:8083
  • 进入容器:docker exec -it 4eca1df4d1a6 /bin/bash

执行curl请求之后,服务端进行了响应,表示服务运行成功了,通过docker运行的SpringBoot微服务成功!

Dockerfile指令详解

FROM基础镜像的选择

前面在讨论FROM指令的时候说过:有效的Dockerfile必须以FROM指令开头,必须要选择一个基础镜像!那对于java应用来说,jdk肯定是刚需(比买房还刚)了。在dockerhub上搜索结果如下:

官方镜像中,只有这一个选项那就是叫java的镜像了!所以只要指定对应的版本即可,在上面的Dockerfile中选择了java8! 这个也可以其它开源项目,比如前面讨论的xxl-job源码 里面编写的Dockerfile来对比:

在第一行中通过FROM指令指定了jdk的版本:openjdk:8-jre-slim

ADD与COPY的区别

在前面讨论过COPY指令,其实ADD指令跟COPY是类似的,命令格式也差不多,区别在于:

ADD and COPY are functionally similar. COPY supports basic copying of files into the container, from the build context or from a stage in a multi-stage build. ADD supports features for fetching files from remote HTTPS and Git URLs, and extracting tar files automatically when adding files from the build context.

ADD和COPY功能相似。COPY支持将文件从构建上下文或多阶段构建中的阶段基本复制到容器中。ADD支持从远程安全超文本传输协议和Git URL获取文件,以及从构建上下文添加文件时自动提取tar文件的功能。

 简而言之:

  • ADD支持从远程获取资源,COPY不行
  • ADD会自动解压tar包,COPY不会
  • 更多的可以查看ADD or COPY

可以通过一个简单的例子来验证一下上面的tar包自动解压功能:

分别创建copy、add的Dockerfile文件:Dockerfile_copy、Dockerfile_add:

FROM java:8
COPY a.txt b.tar /usr/local/test_copy/
WORKDIR /usr/local/test_copy
FROM java:8
ADD a.txt b.tar /usr/local/test_add/
WORKDIR /usr/local/test_add

再创建a.txt、b.tar文件:

分别构建Dockerfile_copy、Dockerfile_add:

然后分别运行对应的镜像,并进入对应的目录查看文件:

  • docker run -d --name dc5 dc ping 8.8.8.8 /bin/bash
  • docker exec -it bf6ea6082e51 /bin/bash

会发现通过ADD的文件已经自动解压了,而COPY的里面还是tar包

队此以外,COPY还有不少用法:

  • 比如上面的例子中,同时拷贝多个源文件:COPY file1.txt file2.txt /usr/src/things/
  • 支持正则表达式:COPY *.png /dest/,拷贝所有png结尾的文件;COPY index.?s /dest/,?是单字符通配符,匹配例如index. js和index.ts
  • 排除指定文件:COPY --exclude=*.txt hom* /mydir/,添加所有以“hom”开头的文件,不包括扩展名为. txt的文件
  • 指定文件的权限:COPY [--chown=<user>:<group>] [--chmod=<perms> ...] <src> ... <dest>:COPY --chown=55:mygroup files* /somedir/
    COPY --chown=bin files* /somedir/
    COPY --chown=1 files* /somedir/
    COPY --chown=10:11 files* /somedir/
    COPY --chown=myuser:mygroup --chmod=644 files* /somedir/ 

ENTRYPOINT

容器启动后,要启动微服务。一般执行微服务启动命令:java -jar auth-0.0.1-SNAPSHOT.jar

在上面的例子Dockerfile和XXL-job的Docker镜像Dockerfile中,发现启动命令都是用的ENTRYPOINT指令:

ENTRYPOINT ["executable", "param1", "param2"]

比如上面的指令:ENTRYPOINT ["java","-jar", "/usr/local/bin/auth-0.0.1-SNAPSHOT.jar"]

两种可能的执行形式
exec

这种形式称之为exec形式!比如前面的卷挂载的Dockerfile中:CMD ["ls", "-al"],也是exec形式。关于exec形式的说明在官网上有如下解释:

The exec form makes it possible to avoid shell string munging, and to invoke commands using a specific command shell, or any other executable. It uses a JSON array syntax, where each element in the array is a command, flag, or argument.

exec形式可以避免shell字符串修改,并使用特定的命令shell或任何其他可执行文件来调起命令。它使用JSON数组语法,其中数组中的每个元素都是命令、标志或参数。

而且官网上也推荐这种写法:

The exec form is best used to specify an ENTRYPOINT instruction, combined with CMD for setting default arguments that can be overridden at runtime.

exec形式最好用于指定ENTRYPOINT指令,结合CMD设置可以在运行时覆盖的默认参数。 

在这种形式下,对于shell变量是不会自动替换的:比如RUN [ "echo", "$HOME" ]指令,运行之后并不自动替换$HOME.这个原因在于:

Using the exec form doesn't automatically invoke a command shell.

使用exec表单不会自动调用命令shell。

If you want shell processing then either use the shell form or execute a shell directly with the exec form, for example: RUN [ "sh", "-c", "echo $HOME" ]

如果要使用shell生效,可以如下执行:RUN [ "sh", "-c", "echo $HOME" ]

 shell

而另一种执行形式,就是所谓的shell形式:

RUN source $HOME/.bashrc && echo $HOME

这种形式就是在shell环境中执行的:

Unlike the exec form, instructions using the shell form always use a command shell.

与exec形式不同,使用shell形式的指令始终使用命令shell。

比如将上面的Dockerfile修改一下,最后的应用启动命令从exec:

  • ENTRYPOINT ["java","-jar", "/usr/local/bin/auth-0.0.1-SNAPSHOT.jar"]

改为shell形式来执行:

  • ENTRYPOINT java -jar ${AUTH_PATH}

即修改为如下的Dockerfile文件:

# 选择jdk8做为基础镜像
FROM java:8

# 将本机微服务jar包复制到镜像中
ADD auth-0.0.1-SNAPSHOT.jar /usr/local/bin

# 设置环境变量:jar包的路径
ENV AUTH_PATH=/usr/local/bin/auth-0.0.1-SNAPSHOT.jar

# for test
RUN echo ${AUTH_PATH}

# 容器启动时,执行微服务启动命令:java -jar auth-0.0.1-SNAPSHOT.jar
ENTRYPOINT java -jar ${AUTH_PATH}

# 暴露端口8083
EXPOSE 8083

运行上面的Dockerfile文件,生成镜像,然后运行,效果同上!这个时候通过docker ps 来查看运行的容器,会发现一个现象:

从这里可以看出来,通过shell形式执行的命令,会默认在["/bin/bash", "-c"]下执行的(这里可以通过--no-trunc参数查看完整的启动命令):

["/bin/sh", "-c"] 则是默认的shell,如果要更改,docker也提供了对应的SHELL指令:

SHELL ["/bin/bash", "-c"]
RUN echo hello

具体可以看Use a different shell

关于CMD与ENTRYPOIT的区别

CMD与ENTRYPOIT的区别,网上也有很多解释:其中比较多的说法是在Docker容器中,CMD和ENTRYPOINT是两种不同的指令,用于定义容器启动时要执行的命令。CMD适用于设置默认命令和参数,而ENTRYPOINT适用于定义容器的主要入口点。其中CMD指令会被Docker run启动命令中参数被覆盖,而ENTRYPOINT会把Docker run启动命令参数进行追加!

在官网中也对两者的区别做了说明:

Both CMD and ENTRYPOINT instructions define what command gets executed when running a container. There are few rules that describe their co-operation.

  1. Dockerfile should specify at least one of CMD or ENTRYPOINT commands.

  2. ENTRYPOINT should be defined when using the container as an executable.

  3. CMD should be used as a way of defining default arguments for an ENTRYPOINT command or for executing an ad-hoc command in a container.

  4. CMD will be overridden when running the container with alternative arguments.

大致意思就是:

  • Dockerfile应至少指定一个CMD或ENTRYPOINT命令。
  • 将容器用作可执行文件时应定义ENTRYPOINT。
  • CMD应该用作定义ENTRYPOINT命令或在容器中执行ad-hoc命令的默认参数的一种方式。
  • 使用替代参数运行容器时,CMD将被覆盖。 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2071703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

红黑树、B+Tree、B—Tree

红黑树 B-Tree 这三个通常都是把内存全部加载到内存里&#xff0c;然后再内存中进行处理的&#xff0c;数据量通常不会很大。 内存一般容量都在GB级别&#xff0c;比如说现在常见的4G、8G或者16G。 如果要处理的数据规模非常大&#xff0c;大到内存根本存不下的时候。这个时候…

基于微信小程序靓丽内蒙古APP(源码+定制+辅导)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

验证码功能的思路和做法

验证码登录的思路和流程 步骤 1.导入依赖 <dependency><groupId>com.github.axet</groupId><artifactId>kaptcha</artifactId><version>0.0.9</version> </dependency> 2.写一个验证码的配置类 package com.lzy.config;im…

IM即时通讯软件,企业即时通讯系统就选WorkPlus

在现代企业中&#xff0c;高效的沟通和协作是推动业务发展的关键。随着科技的不断进步&#xff0c;团队成员和企业之间的沟通已经超越了传统的邮件和电话方式&#xff0c;转向了更实时、更便捷的方式&#xff0c;即即时通讯软件。在众多即时通讯软件中&#xff0c;WorkPlus作为…

滑动窗口解决子串问题

问题解析&#xff1a; 以这道题为例子&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;找长度最小的子数组&#xff0c;子数组和必须大于条件中的target 暴力解法&#xff1a;左右指针列举出每一种子数组的可能&#xff0c;每种可能去求子数组的和&#xff0c;找到最小的…

17 深入理解 C 语言 main 函数:返回值意义、命令行参数接收、跨环境差异及CMD乱码解决

目录 1 main 主函数 2 main 函数的返回值 2.1 返回值的意义 2.2 默认返回值 2.3 返回值类型 3 main 函数的参数 3.1 参数内容 3.2 案例&#xff1a;循环遍历主函数的参数 3.3 不传递参数 3.4 powershell 环境下传参 3.5 cmd 环境下传参 3.6 解决 cmd 输出乱码问题 …

pytorch深度学习基础 7 (简单的线性拟合+检验模型在验证集上的效果)

我们之前做的目的都是评估训练的损失&#xff0c;训练的损失Loss告诉我们&#xff0c;我们的模型是否能够完全拟合训练集&#xff0c;也就是说我们的模型是否有足够的能力处理数据中的相关信息。但是我们之前都是评价训练的好坏&#xff0c;并没有引入验证集。接下来我们就需要…

Java基础——自学习使用(多态)

一、多态的定义 父类的引用指向子类的对象。 B继承A&#xff0c;A abnew B();——父类引用指向子类的对象。 二、创建对象了解多态的内部结构 &#xff08;1&#xff09;父类即A类对象的内存结构图 &#xff08;2&#xff09;子类即B类对象的内存结构图 由于B中重写了父类A中…

EazyDraw for Mac 矢量图绘制设计软件

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功 三、运行测试安装完成&#xff01;&#xff01;&#xff01; 效果 一、下载软件 下载软件…

SSRF和CSRF实战复现

文章目录 SSRFWeb-Hacking-Lab-master1、Centos未授权访问2、Ubuntu未授权访问3、Ubuntu传入公钥访问4、ssrf_redis_lab_pickle_redis_lab CSRF:windphp SSRF SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 f…

第三课《排序》

前言 排序是将一组数据&#xff0c;按照指定的顺序或要求来进行排列的过程。是数据结构相关课程和内容较为重要和核心的内容之一&#xff0c;常常作为考试题和面试题目来考察学生和面试者&#xff0c;因此熟练掌握经典的排序算法原理和代码实现是非常重要的 本文介绍了几大较为…

AJAX(5)——Promise

Promise Promise对象用于表示一个异步操作的最终完成或失败及其结果值 语法&#xff1a; //创建Promise对象const p new Promise((resolve, reject) > {//执行异步代码setTimeout(() > {// resolve(成功结果)reject(new Error(失败结果))}, 2000)})//获取结果p.then(r…

坚鹏讲人才第13期:个人数字化转型——个人与时代的共赢之选

坚鹏讲人才第13期&#xff1a;个人数字化转型——个人与时代的共赢之选 在这个日新月异的时代&#xff0c;数字化转型已经成为当今时代的必然趋势&#xff0c;它不仅改变了我们的生活方式&#xff0c;也正在改变着各行各业的运营模式。数字化时代&#xff0c;不仅需要数字化企…

网络udp及ipc内存共享

大字符串找小字符串 调试 1. 信号处理函数注册&#xff1a;•一旦使用 signal 函数注册了信号处理函数&#xff0c;该函数就会一直有效&#xff0c;直到程序结束或者显式地取消注册。2. 注册多次的影响&#xff1a;•如果多次注册同一信号的处理函数&#xff0c;最后一次注册的…

快9月了刚结束基础,武忠祥强化vs张宇18讲应该如何选择?

快9月了&#xff0c;最近有一部分同学刚结束基础&#xff0c;在后台提问&#xff1a;强化到底该学武忠祥还是张宇18讲&#xff1f;其实这个问题&#xff0c;如果你是6月份开始强化&#xff0c;很好回答&#xff0c;但是现在已经快9月份了&#xff0c;很多同学都开始做真题了&am…

代码随想录 刷题记录-16 贪心算法(1)贪心理论基础及习题

一、理论基础 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心的套路&#xff08;什么时候用贪心&#xff09; 贪心算法并没有固定的套路。 所以唯一的难点就是如何通过局部最优&#xff0c;推出整体最优。 靠自己手动模拟&#xff0c…

深度学习 回归问题

1. 梯度下降算法 深度学习中, 梯度下降算法是是一种很重要的算法. 梯度下降算法与求极值的方法非常类似, 其核心思想是求解 x ′ x x′, 使得 x ′ x x′ 在取 x ⋆ x^{\star} x⋆ 时, 可以使得 l o s s 函数 loss函数 loss函数 的值最小. 其中, 在求解 x ′ x x′ 的过…

罗德与施瓦茨RS、UPV 音频分析仪 250KHZ 双通道分析仪UPL

罗德与施瓦茨 UPV 音频分析仪的规格包括&#xff1a; 模拟 双通道分析仪&#xff1a;带宽高达 250 kHz 生成正弦波信号&#xff1a;单通道最高 185 kHz&#xff08;需要 B1&#xff09;和双通道最高 80 kHz FFT本底噪声&#xff1a;< -140dB 固有频率响应&#xff08;20 …

链动 2+1 模式小程序 AI 智能名片商城源码培训邀约策略研究

摘要&#xff1a;本文深入剖析链动 21 模式小程序 AI 智能名片商城源码的培训邀约策略&#xff0c;从该源码的价值出发&#xff0c;阐述邀约的重要性&#xff0c;并详细介绍具体的邀约策略&#xff0c;旨在为相关培训活动提供切实可行的指导&#xff0c;提高邀约成功率&#xf…

前端如何快速切换node版本:nvm

安装之前最好卸载计算机已经安装的node&#xff08;通过Windows菜单找到Node.js的卸载程序&#xff0c;运行卸载程序&#xff09;。下载nvm安装包&#xff1a;nvm安装地址。安装nvm&#xff0c;选择nvm安装根路径指定nodejs的安装路径打开命令行&#xff0c;输入nvm -v 可查看版…