docker系列11:Dockerfile入门

news2024/11/24 10:50:07

 传送门

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-pod
  labels:
    env: demo
    owner: chrono

spec:
  containers:
  - image: nginx:alpine
    name: ngx
    ports:
    - containerPort: 80

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

关于镜像的上传

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

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

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

相关文章

蒲公英G5-2250路由器之收集各种硬件的配置页面

前言&#xff1a;此篇文章是为了更好的让大家了解各个路由器的后台设置页面具体有哪些功能&#xff0c;更加的清晰直观&#xff01;&#xff08;如有雷同纯属巧合&#xff0c;如有侵权联系删除&#xff01;&#xff09; 云管理平台 本地地址IP/oraybox/login.html 本地配置页…

一把手带你了解Bigo Ads联动休闲真金游戏出海营销策略

一把手带你了解Bigo Ads联动休闲真金游戏出海营销策略 在探索Bigo Ads作为投放海外游戏广告的平台时&#xff0c;精准定位与创意融合成为了成功的关键。首先&#xff0c;深入理解目标市场的文化习俗与玩家偏好至关重要。不同地区的玩家对于游戏类型、画风乃至广告语言风格都有…

【链表OJ】常见面试题 3

文章目录 1.[环形链表II](https://leetcode.cn/problems/linked-list-cycle-ii/description/)1.1 题目要求1.2 快慢指针1.3 哈希法 2.[随机链表的复制](https://leetcode.cn/problems/copy-list-with-random-pointer/description/)2.1 题目要求2.2 迭代法 1.环形链表II 1.1 题目…

KEIL5芯片包下载

一、打开KEIL芯片包下载网址 Arm Keil | Devices 二、搜索要下载的芯片型号 三、安装

CSP初赛知识点讲解(二)

CSP初赛知识点讲解&#xff08;二&#xff09; 进制转换基本定义n进制转十进制十进制转n进制n进制转m进制小数的进制转换 例题训练&#xff08;四&#xff09; 进制转换 基本定义 十进制&#xff1a;逢十进一(包含数字0~9) ( 365 ) 10 3 1 0 2 6 1 0 1 5 1 0 0 (365)_{…

如何提高编程能力?(来自准大三学长的含泪建议)

种一棵树最好是十年前&#xff0c;其次是现在 想了解更多内容可以看我主页&#xff1a;GGBondlctrl-CSDN博客 1.前言 以下是小编的亲身经历哟 &#xff08;1&#xff09;大一&#xff0c;摆烂 -------和每个人一样&#xff0c;大学都是带着美好的憧憬&#xff0c;我开始学习…

Apache漏洞

四、 CVE-2021-41773 Apache HTTP Server 路径穿越漏洞 漏洞简介 该漏洞是由于Apache HTTP Server 2.4.49版本存在目录穿越漏洞,在路径穿越目录<Directory/>Require all granted</Directory>允许被访问的的情况下(默认开启)攻击者可利用该路径穿越漏洞读取到Web…

C++ 基础练习 - Chapter 12 (基础练习 完结版)

Review Questions 12.1 What is generic Programming? How is it implemented in C? Answer: Generic programming is an approach where generic types are used as parameters in algorithms so that they work for variety of suitable data types and data structures…

【Spring】通过Aspects实现面向切面编程(AOP)

目录 1.概念理解 2. 案例说明 1.概念理解 【注】一些概念来自&#xff1a;https://blog.csdn.net/Kaiser__/article/details/135894150 横切关注点 分散在每个各个模块中解决同一样的问题&#xff0c;如用户验证、日志管理、事务处理、数据缓存都属于横切关注点。这个概念不是…

【C++刷题】优选算法——贪心第一辑

什么是贪心算法 贪心策略&#xff1a;局部最优 -> 全局最优 “贪婪鼠目寸光” 1、把解决问题的过程分为若干步 2、解决每一步的时候&#xff0c;都选择当前看起来“最优的”解法 3、“希望”得到全局最优解 贪心算法的特点 贪心策略的提出是没有标准或者模板的 正确的贪心策…

项目小结(中)

一.文件分片上传 在文件上传的逻辑中&#xff0c;文件以MD5唯一&#xff0c;然后记录已经储存的文件md5&#xff0c;如果已上传&#xff0c;就秒传&#xff0c;并记录班级上传文件信息。 如果请求文件上传时&#xff0c;发现班级已经上传了一部分&#xff0c;这里就会把班级上…

秋招复习笔记——八股文部分:网络IP

终于来到了网络的最后一篇&#xff0c;继续加油&#xff01; IP 知识全家桶 IP 基本认识 IP 在 TCP/IP 参考模型中处于第三层&#xff0c;也就是网络层。 网络层的主要作用是&#xff1a;实现主机与主机之间的通信&#xff0c;也叫点对点&#xff08;end to end&#xff09…

【Vue3】Pinia修改数据

【Vue3】Pinia修改数据 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日子…

锐捷RCNA | 远程登录与路由技术

锐捷RCNA | 远程登录与路由技术 一、远程登录配置1. Telnet远程登录介绍2. 案例1--设置远程登录密码实现远程登录3. 案例2--定义不同用户账户实现远程用户权限隔离4. SSH远程登录介绍5. 案例--通过SSH功能远程管理设备 二、路由技术1. 直连路由的数据通信2. 间接路由的数据通信…

标准IO

fprintf和fscanf fprintf int printf(const char *format, ...); 把数据输出到终端 int fprintf(FILE *stream, const char *format, ...); 功能&#xff1a; 将format字符串中的内容&#xff0c;输出到stream文件流指针指向的文件中去&#xff0c;想要将数据以何种形式输…

基于XxlCrawler的Java执行JS渲染方式实战-以获取商飞C919飞行照片为例

目录 前言 一、抓取目标解析 1、原始网站介绍 2、列表页面结构解析 二、XxlCrawler的常规配置 1、PageVo对象的定义 2、定义XxlCrawler并启动 三、使用HtmlUnit来执行动态渲染 1、在pom.xml中加入htmlunit的引用 2、设置PageLoader加载器 3、执行抓取 四、总结 前言…

看,esp8266就是这么简单

材料准备 1.esp 8266 2.一条可以传输数据的数据线 3一台电脑 前言 如今是物联网的时代&#xff0c;例如“智能家居&#xff0c;无人驾驶……”&#xff0c;多方面的进行物联网改革与创新。那其中&#xff0c;物联网主要的是联网。那通常都是以“esp 8266”和“esp 32”占据了…

在Kylin服务器安装PostgreSQL16数据库

1、下载PostgreSQL16安装包 下载地址https://www.postgresql.org/ftp/source/v16.3/ 2、安装依赖和ICU库 查看服务器版本 yum install -y perl-ExtUtils-Embed readline-devel zlib-devel pam-devel libxml2-devel libxslt-devel openldap-devel python-devel gcc-c opens…

在抖音做电商推广,货架场非做不可

前一段时间跟几个做电商的朋友聊天&#xff0c;我发现大家的干劲儿还挺满的&#xff0c;讨论的话题也出奇地一致&#xff1a;要找新增量。 其中有个朋友是做服装品类的&#xff0c;做得还不错。我请教他秘诀&#xff0c;他说&#xff1a;做电商&#xff0c;推广拿量非常关键。…

MySQL笔记(七):索引

一、索引优化速度 创建对应字段的索引&#xff0c;只对该列有效&#xff0c;只能提高该列的查询速度 创建索引后&#xff0c;查询速度变快&#xff0c;但是表占用空间变大 create index 索引名 on 表名(需要创建索引的列)二、索引的原理 普通索引允许该字段重复 全文索引&#…