当前位置: 首页 > news >正文

docker系列11:Dockerfile入门

 传送门

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挂载容器卷

通过Dockerfile文件挂载容器卷回顾

在上一节中介绍了Dockerfile挂载容器卷,其中的Dockerfile文件如下:

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

该命令的大概意思就是:

  • FROM表示,从标准的ubuntu镜像为准
  • RUN表示执行shell命令,创建一个文件目录/myvol
  • 执行命令,打印"hello world"字符串到greeting文件
  • 最后VOLUME,就是这节要讲到卷挂载!

然后通过Dockerfile生成了一个镜像:

docker build -t getting-started .

并且成功运行该镜像,最后成功实现了容器卷的挂载!

那么什么是Dockerfile文件?Dockerfile的有哪些指令?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是一个文本文档,其中包含用户可以在命令行上调用的所有命令来组装镜像。

简单来说,可以通过Dockerfile文件来生成Docker镜像!首先Dockerfile文件是一个纯文本,然后在里面编写了一系列的指令,比如选择基础镜像(FROM)、拷贝文件(COPY)、运行脚本(RUN)等等,Docker 顺序执行这个文件里的所有步骤,最后就会创建出一个新的镜像出来。

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

从上面的流程可以看出,左边用户编写的Dockerfile文件通过Docker构建之后,成为了右边的镜像。这个镜像跟官方镜像无本质区别(前面从DockerHub上安装的nginx、redis),称为"民间"、"草根"镜像。

镜像分类

 从DockerHub上可以看到对镜像的分类大致有3种:

  • Docker官方镜像(Docker Official Image)
  • 认证镜像(Verified Publisher)
  • 非官方镜像(Sponsored OSS)

官方镜像

像上面提到的nginx、redis都属于官方镜像!

这种镜像都会带上官方构建的标签,属于Docker公司提供的"极品"镜像,不仅质量上乘(有专门的团队负责审核、发布和更新),而且安全性也有保障(经过了严格的漏洞扫描和安全检测),并且也是标准的Dockerfile编写范例,是使用的首选!

认证镜像

认证镜像由Docker认证的出版商提供的高质量镜像。这些产品由商业公司直接发布和维护,比如 Bitnami、Rancher、Ubuntu 等。

这种由大公司"出品"的镜像,一般来说也具有相当高的质量,是不错选择。不过由于Docker认证需要收钱,店大欺客:

因为成为“Verified publisher”是要给 Docker 公司交钱的,而很多公司不想花这笔“冤枉钱”,所以只在 Docker Hub 上开了公司账号,但并不加入认证。

--引自“虚伪”的 Docker 开始清退开源组织,不付费就删除所有镜像!|插件|云原生|存储库|应用程序|docker_网易订阅

所以有些不交钱认证的公司的镜像就被降级为"非官方镜像",比如OpenResty:

非官方镜像

队了上面2种,剩下的就是非官方镜像,也戏称为"民间"镜像!

对于这些镜像的选择,下载量是一个重要的参考标准。 这个时候就是韩信点兵,多多益善了!

这里面也包括我们自己的镜像,如果推送的DockerHub,也是归于这一类镜像中,后面会单开一节来讨论如果上传。

Dockfile有哪些指令

Dockerfile文件命名

在上面的例子中,通过命令docker build来构建的镜像。这是因为省略了-f参数,默认在当前目录下查看名字为Dockerfile的文件:

Specifies the filepath of the Dockerfile to use. If unspecified, a file named Dockerfile at the root of the build context is used by default.

所以一般对于编写的Dockerfile默认使用Dockerfile这个名字,如果要用其它名字,在build时用-f来指定!

指令详解

Dockerfile支持的指令不少,比如例子里面提到的FROM、RUN、VOLUME,更多的可以查看Dockerfile指令

FROM

有效的Dockerfile必须以FROM指令开头,命令格式为:

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

表示选择构建使用的基础镜像,比如ubuntu镜像。其中--platform用在多平台镜像中,一般不用指定:

The optional --platform flag can be used to specify the platform of the image in case FROM references a multi-platform image. For example, linux/amd64linux/arm64, or windows/amd64. By default, the target platform of the build request is used.

可选的--Platform标志可用于指定镜像的平台,以防FROM引用多平台镜像。例如,linux/amd64、linux/arm64或windows/amd64。默认情况下,使用构建请求的目标平台。

也可以指定镜像对应的tag,比如nginx的Dockerfile,选择debian操作系统,版本为bookworm-slim:

RUN

Run指令可以说是Dockerfile 里最重要的一个指令了 ,它可以执行任意的 Shell 命令它也是Dockerfile里面最复杂的一条指令了,这取决于对于shell的编写。比如例子里面的简单shell命令:

RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
  • 创建一个文件夹
  • 打印"hello world"到文件greeting文件中

 也可以特别复杂,比如nginx的RUN命令:

这整个就是一个复杂的shell脚本,因为太长了(RUN只能执行一行命令),所以采用续行符 \,命令之间也会用 && 来连接,这样保证在逻辑上是一行,如果写错了,build的时候会报错:

CMD

CMD指令设置从镜像运行容器时要执行的命令,格式为:

  • CMD ["executable","param1","param2"] (exec form)
  • CMD ["param1","param2"] (exec form, as default parameters to ENTRYPOINT)
  • CMD command param1 param2 (shell form)

比如,在容器运行之后,打印出当前目录,修改Dockerfile文件,ls -al

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
CMD ["ls", "-al"]
VOLUME /myvol

构建并运行容器,之后就会执行 ls -al命令:

Dockerfile中只能有一条CMD指令。如果列出多个CMD,则只有最后一个生效。这一点在官网上有明确说明:

There can only be one CMD instruction in a Dockerfile. If you list more than one CMD, only the last one takes effect. 

而且官网上也对RUN与CMD的区别做了说明:

Don't confuse RUN with CMDRUN actually runs a command and commits the result; CMD doesn't execute anything at build time, but specifies the intended command for the image.

不要混淆RUN和CMD。RUN实际上运行一个命令并提交结果;CMD在构建时不执行任何东西,但指定镜像的预期命令。 

图片来自: https://docs.docker.com/guides/docker-overview/

VOLUME

这个卷挂载命令在前面已经讨论过了,这里就不赘述了。

COPY

COPY指令顾名思义,就是复制命令,有点类似于cp命名,格式如下:

COPY [OPTIONS] <src> ... <dest>
COPY [OPTIONS] ["<src>", ... "<dest>"]

其中src表示源文件,dest表示目标文件。比如上面的例子中,在当前目录下建一个test_cp.txt文件,并打包进镜像中:

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
COPY ./test_cp.txt /tmp/test_cp.txt
VOLUME /myvol

然后重新构建并运行,发现构建成功之后,运行对应的镜像,容器中已经有了对应的文件,证明复制成功!

不过这里要注意的是, 拷贝的源文件必须是"构建上下文"路径里的,不能随意指定文件,甚至连绝对路径也不行。

如果要从本机向镜像复制文件,还要把这些文件放到一个专门的目录,然后在 docker build 里指定"构建上下文"到这个目录才行。在这里例子中,"构建上下文"为当前目录.

所以如果指定当前"构建上下文"为绝对路径:/root/test-docker

docker build -f Dockerfile_copy -t greetting_stared_cp3 /root/test-docker

Dockerfile里面COPY改为相对路径是可以的。由此得出,COPY只能基于相对路径来操作!

 这个原理呢,其实就要从docker build的说起了,跟Dockerfile没有多大关系,后面再讨论。 

WORKDIR

WORKDIR指令是设置工作目录,格式为:

WORKDIR /path/to/workdir

WORKDIR指令为Dockerfile中跟随它的任何RUN、CMD、ENTRYPOINT、COPY和ADD指令设置工作目录,默认为"/"目录下。 比如创建一个Dockerfile文件内容如下:

FROM ubuntu
WORKDIR /usr
WORKDIR share
WORKDIR bug
RUN pwd > greeting

 然后打包运行看下效果:

并且细心的观察就会发现,这个进入容器的运行目录,正是刚才通过WORKDIR设置的/usr/share/bug!所以WORKDIR也代表设置的容器运行的目录,这个通过退出容器再进去也能证实这一点:

在官方推荐指定这个WORKDIR的:

 Therefore, to avoid unintended operations in unknown directories, it's best practice to set your WORKDIR explicitly.

--因此,为了避免未知目录中的意外操作,最好的做法是显式设置WORKDIR。

EXPOSE

EXPOSE指令通知Docker容器在运行时侦听指定的网络端口,您可以指定端口侦听TCP还是UDP,如果不指定协议,则默认为TCP,格式为:

EXPOSE <port> [<port>/<protocol>...]

比如在docker系列7:docker安装ES 里面运行容器的命令里面通过-op指定了端口映射:

$ docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch

这个命令里面,-p表示容器对外暴露9200端口与主机的9200端口映射。但是如果Dockerfile里面也可以达到这种效果:

EXPOSE 9200

 对外暴露9200端口,默认是TCP协议。如果要支持UDP协议,要指定协议类型:

EXPOSE 9200/udp

或者一块暴露tcp、udp,要写2条指令:

EXPOSE 9200/tcp
EXPOSE 9200/udp

无论EXPOSE设置如何,都可以在运行时使用-p标志覆盖。这是因为EXPOSE在Dockerfile中,一般运行时要结合真实宿主机的情况来映射端口,所以一般来说EXPOSE更多的是一种文档化的指引,告诉用户哪个服务暴露哪个端口。比如nginx的Dockerfile中,EXPOSE了80,但是真实使用的时候还是要通过-p来指定:

ENV

ENV指令用于设置环境变量,格式为:

ENV <key>=<value> ...

可以一次性设置多个变量:

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

 然后就可以在Dockerfile中引用这个变量了:

FROM ubuntu
ENV MY_NAME=DOCKER_ENV_TEST
RUN mkdir /myvol
RUN echo $MY_NAME > /myvol/greeting
VOLUME /myvol

然后打包运行看下效果:

通过ENV这种方式设置变量,官方并不推荐,就是因为在镜像里面也会生效,而不是仅仅在Docker构建过程中生效,所以一般推荐ARG:

If an environment variable is only needed during build, and not in the final image, consider setting a value for a single command instead.

Or using ARG, which is not persisted in the final image

ARG

对于ARG指令,刚才已经谈到了,用法跟ENV相似,区别就是在于 ARG 创建的变量只在镜像构建过程中可见,容器运行时不可见,而 ENV 创建的变量不仅能够在构建镜像的过程中使用,在容器运行时也能够以环境变量的形式被应用程序使用。所以可通过ARG 自行查看!

安全性问题

Dockerfile里面明确提到了,不建议使用变量来传递敏感数据,这又是另外一个话题了

MAINTAINER

MAINTAINER指令设置生成镜像的作者字段,格式为:

MAINTAINER <name>

比如在上面的Dockerfile增加作者信息:

总结

图片来自: 百度安全验证

命令式与声明式

上面介绍了Dockerfile文件与对应的指令,通过编写Dockerfile文件一步步的指定docker构建要执行的命令,“告诉”计算机每步该做什么,所有的步骤都列清楚,这样程序才能够一步步走下去,最后完成任务。这种就是命令式的文件,与之相反Kubernetes编写的YAML文件,就是"声明式"的:

apiVersion: v1
kind: Pod
metadata:name: ngx-podlabels:env: demoowner: chronospec:containers:- image: nginx:alpinename: ngxports:- containerPort: 80

 "声明式"不关心具体的过程,更注重结果(是不是有点耳熟?)

关于镜像的上传

在下一节,会尝试打包自己的镜像并推送到镜像仓库中,并用Dockerfile文件编写打包自己的java程序!

相关文章:

docker系列11:Dockerfile入门

传送门 docker系列1&#xff1a;docker安装 docker系列2&#xff1a;阿里云镜像加速器 docker系列3&#xff1a;docker镜像基本命令 docker系列4&#xff1a;docker容器基本命令 docker系列5&#xff1a;docker安装nginx docker系列6&#xff1a;docker安装redis docker系…...

LVS(Linux virual server)详解

目录 一、LVS&#xff08;Linux virual server&#xff09;是什么&#xff1f; 二、集群和分布式简介 2.1、集群Cluster 2.2、分布式 2.3、集群和分布式 三、LVS运行原理 3.1、LVS基本概念 3.2、LVS集群的类型 3.2.1 nat模式 3.2.2 DR模式 3.2.3、LVS工作模式总结 …...

Session共享方法

在Web开发中&#xff0c;会话&#xff08;Session&#xff09;管理是跟踪用户与服务器之间交互的一种常见方法。Session 共享通常指的是在一个应用集群或多个应用服务之间保持用户的会话状态一致。这在负载均衡、微服务架构或者分布式系统中尤为重要 一、基于SQL的session管理…...

Ubuntu 22.04 Docker安装笔记

1、准备一台虚机 可以根据《VMware Workstation安装Ubuntu 22.04笔记》来准备虚拟机。完成后&#xff0c;根据需求安装必要的软件&#xff0c;并设置root权限进行登录。 sudo apt update sudo apt install iputils-ping -y sudo apt install vim -y允许root ssh登录&#xff1…...

编程-设计模式 6:适配器模式

设计模式 6&#xff1a;适配器模式 定义与目的 定义&#xff1a;适配器模式将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。目的&#xff1a;该模式的主要目的是解决接口不匹配的问题&#xff0c;使得一个…...

ERC721 概念解释

目录 FeaturesVotesAccess ControlUpgradeabilityFeatures Mintable: 允许创建新的代币(minting)。合约的所有者或有权限的账户可以调用 mint 函数来生成新的代币,并将其分配给指定的地址。 Auto Increment Ids:自动递增 ID。每次创建新的代币时,代币的 ID 会自动递增,确保…...

数据结构(其五)--串

目录 12.串 12.1 基本操作 12.2 串的存储结构 12.3 字符串的模式匹配算法 (1).朴素模式匹配算法 (2).KMP算法 i.next[]数组的求解 ii.next[]数组的优化——nextval数组 iii.手算nextval数组 iiii.机算nextval数组 + KMP函数 12.串 串,即字符串(string),由零个或多…...

LeetCode Hot100 LRU缓存

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&#xff0c;否则返回 -…...

GESP C++ 2024年06月一级真题卷

一、单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 第 1 题 在 C 中&#xff0c;下列不可做变量的是 ( ) 。 A. five-Star B. five_star C. fiveStar D. _fiveStar 答案&#xff1a;A 解析&#xff1a;标识符命名规则&#xff0c;标识符由字母、数…...

在 Ubuntu Server 上配置静态 IP 地址

在 Ubuntu Server 上配置静态 IP 地址 测试时使用的Ubuntu server版本是22.04 一、Ubuntu 17.10之前版本 使用 ifupdown 配置文件来设置静态 IP。配置文件通常位于 /etc/network/interfaces。 1.1 编辑 /etc/network/interfaces 文件&#xff1a; sudo vim /etc/network/in…...

数据结构——栈的讲解(超详细)

前言&#xff1a; 小编已经在前面讲完了链表和顺序表的内容&#xff0c;下面我们继续乘胜追击&#xff0c;开始另一个数据结构&#xff1a;栈的详解&#xff0c;下面跟上小编的脚步&#xff0c;开启今天的学习之路&#xff01; 目录 1.栈的概念和结构 1.1.栈的概念 1.2.栈的结构…...

三防平板助力MES系统,实现工厂移动式生产报工

在当今竞争激烈的制造业环境中&#xff0c;提高生产效率、优化生产流程以及实现精准的生产管理已经成为企业生存和发展的关键。 MES系统作为连接企业计划层和控制层的桥梁&#xff0c;在实现生产过程的信息化、数字化和智能化方面发挥着重要作用。与此同时&#xff0c;三防平板…...

WEB渗透Bypass篇-常规函数绕过

常规函数绕过 <?php echo exec(whoami);?> ------------------------------------------------------ <?php echo shell_exec(whoami);?> ------------------------------------------------------ <?php system(whoami);?> ------------------------…...

C++从入门到起飞之——string类的模拟实现 全方位剖析!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1、多文件之间的关系 2、模拟实现常用的构造函数 2.1 无参构造函数 2.2 有参的构造函数 2.3 析构函…...

数据库国产化大趋势下,还需要学习Oracle吗?

由于众所周知的原因&#xff0c;近两年各行各业都开始了数据库国产化替代的进程&#xff0c;从国外商业数据库替换到国产或者开源数据库&#xff0c;相信很多的数据库从业人员会把部分精力转移到其他数据库产品的学习中&#xff0c;也有一些人在大肆的宣扬Oracle已经过时了&…...

WebLogic

二、WebLogic 2.1 后台弱口令GetShell 漏洞描述 通过弱口令进入后台界面&#xff0c;上传部署war包&#xff0c;getshell 影响范围 全版本(前提后台存在弱口令) 漏洞复现 默认账号密码:weblogic/Oracle123weblogic常用弱口令: Default Passwords | CIRT.net这里注意&am…...

Aspose.Words.dll 插入模板表格,使用的是邮件合并MailMerge功能,数据源是DataTable或list对象,实例

本实例中的实例功能有: 1、 Aspose.Words.dll 插入模板指定域替换为文字或html标签,见1 2、Aspose.Words.dll 插入模板表格,使用的是邮件合并MailMerge功能,数据源是DataTable或List对象(将list转换成DataTable),见1和2 3、word转换Pdf文件,见1 4、将多个word输出文…...

同时打开多个微信

注&#xff1a; 以下方法用到的 D:\微信\WeChat\WeChat.exe是我的电脑微信路径&#xff0c;可右击桌面微信快捷方式 > 属性 > 目标查看 以下方法都需要先关掉已登录的微信后操作 <一> 找到微信路径 新建一个txt文件输入以下内容 start D:\微信\WeChat\WeChat.exe …...

MPU6050的STM32数据读取

目录 1. 概述2. STM32G030对MPU6050的读取3. STM32F1xx对MPU6050的读取 1. 概述 项目中&#xff0c;往往需要根据不同的环境使用不同的芯片处理某些数据&#xff0c;当使用不同的芯片对六轴陀螺仪芯片MPU6050进行数据处理中&#xff0c;硬件的连接、I/O口的设置往往需要根据相…...

【微信小程序开发】——奶茶点餐小程序的制作(二)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...