Docker进阶教程 - 1 Dockerfile

更好的阅读体验:点这里 ( www.doubibiji.com

1 Dockerfile

Dockerfile 是做什么的?

我们前面说到,制作镜像的方法主要有两种方式:

  • 使用 docker commit 命令;
  • 使用 Dockerfile 文件。

但是使用 docker commit 命令很麻烦,每次都要进入容器修改容器然后提交。我们可以通过 Dockerfile 通过一条一条的指令和参数来构成脚本文件,通过脚本文件来生成镜像,这样就很方便。


下面就来讲解通过 Dockerfile 来编排镜像。

使用 Dockerfile 是构建镜像的步骤如下:

1、编写一个 Dockerfile 文件;

2、使用 docker build 命令运行脚本文件,构建成为一个镜像;

3、使用 docker run 命令运行镜像;

4、如果需要,可以使用 docker push 命令发布镜像到镜像仓库(DockerHub 、阿里云仓库等)。


1.1 使用Dockerfile构建镜像

在前面我们通过运行 Ubuntu 镜像生成一个容器,在容器中安装 vim 编辑器,然后使用 docker commit 命令生成一个新的镜像。

下面使用 Dockerfile ,基于 Ubuntu22.04,安装 vimifconfig 命令,生成一个新的 Ubuntu 镜像。

1 编写 Dockerfile 文件

随便在一个目录下创建一个文件,例如我在 /home/doubi 目录下,名称为 Dockerfile,名称是固定的,内容如下:

FROM ubuntu:22.04# 更新 apt
RUN apt update# 安装 vim
RUN apt install -y vim# 安装 ifconfig
RUN apt install -y net-tools

FROM 是 Dockerfile 第一行非注释代码,表示我们的镜像是基于哪个镜像来创建的。

RUN 用于在构建镜像的时候运行 Shell 命令,这里运行了三条命令,用来安装 vimifconfig 命令。指令是很简单的。

Dockerfile 中的命令的关键字必须是大写字母,#表示注释。


但是上面的 Dockerfile 可以进行优化,因为构建镜像时,Dockerfile 的每⼀条 RUN 指令都会在镜像上构建⼀层,为了减⼩镜像⽂件⼤⼩,可以将多个 RUN 命令合并为一条命令,从而减少镜像的层数。

所以上面的 Dockerfile 可以改写为如下:

FROM ubuntu:22.04# 安装 vim 和 ifconfig
RUN apt update && apt install -y vim && apt install -y net-tools

2 构建镜像

下面执行 docker build 命令,运行脚本文件,构建成为一个镜像:

docker build -t myubuntu:1.0.0 .			# 后面有一个"点"
  • docker build:这是 Docker 的构建命令,用于根据 Dockerfile 中的指令创建 Docker 镜像;

  • -t myubuntu:1.0.0 :指定构建的镜像的名称为myubuntu,同时设置版本标签为 1.0.0;

  • . :这个参数指定了 Dockerfile 所在的路径,. 表示当前目录。Docker 会在当前目录下寻找名为 Dockerfile 的文件,并根据其中的指令构建镜像。


构建需要一点时间,构建完成,可以看到在本地生成了镜像:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3 运行镜像

镜像已经生成了,下面运行一下使用 Dockerfile 生成的镜像,查看一下是否有 vimifconfig

运行镜像:

docker run -it myubuntu:1.0.0 /bin/bash

运行后,查看容器中是否有 vimifconfig 命令,可以看到我们自己的镜像已经包含了 vimifconfig

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


上面使用 Dockerfile 构建镜像比使用 docker commit 构建镜像方便多了。

1.2 查看官方容器

我们之前使用的 Tomcat、Redis 等容器,在 dockerhub 上查看,其实这些容器也是使用 Dockerfile 来构建的。

例如在 dockerhub 上搜索 redis 容器,进入到容器详情页面,提供了 Dockefile 的链接:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


点击链接可以跳转到容器的 Dockerfile 页面,查看容器 Dockerfile 的详细内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当然对于我们来说一般也不用编写这么复杂的镜像,只需要了解原理,看得懂简单的镜像编写即可。

1.3 Dockerfile 常用命令

上面我们实现了自定义的 Ubuntu 镜像构建,里面用到了 FROMRUN 命令,在 Dockerfile 中还有一些常用的命令。

下面简单的介绍一下常用的命令。

1 FROM

FROM 指令指明构建的新镜像是基于哪个基础镜像,如果没有选择 tag,那么默认值为 latest。

语法:

FROM <image>:<tag>

举个栗子:

构建的镜像是基于 ubuntu22.04 来构建:

# 基于ubuntu22.04来构建镜像
FROM ubuntu:22.04

2 LABEL

LABEL 指令用于向镜像添加元数据,提供关于镜像的描述信息。这些标签可以包含有关项目、维护者、版本、许可证等信息。

语法:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

举个栗子:

# 使用LABEL向镜像描述信息
LABEL version="1.0" maintainer="doubibiji@qq.com" description="My custom Docker image"

LABEL 指令可以省略,添加也没有实际的影响。

3 RUN

RUN 命令可以在构建镜像时执行命令。这个命令接收两种格式:ShellExec

Shell 形式

语法:

RUN <command>

举个栗子:

构建的新镜像中我们想在 /home/doubi 目录下创建一个 hello 目录。

RUN mkdir -p /home/doubi/hello

也可以执行指令来安装软件、配置环境等。例如安装 vim 命令:

RUN apt update && apt install -y vim

Exec 形式

在 Exec 形式中,命令是一个数组,指定了可执行文件及其参数。这种形式适用于避免 Shell 字符串处理的一些潜在问题,同时也提供了更直观的命令执行方式。

示例:

RUN ["apt", "update", "&&", "apt", "install", "-y", "vim"]

这是与上述 Shell 形式等效的命令,使用哪种格式,看你自己,我还是喜欢 Shell 格式的。

注意:RUN 命令会在执行 docker build 命令的时候执行。每⼀条 RUN 指令都会在镜像上构建⼀层,为了减⼩镜像⽂件⼤⼩,可以将多个 RUN 命令合并为一条命令,从而减少镜像的层数。合并会降低可读性,需要根据实际情况权衡可读性和减小层数之间做个平衡。

4 COPY

COPY 指令可以拷贝文件或目录到镜像中。

语法:

COPY <src> <dest>

举个栗子:复制 jar 包到 镜像文件中:

# 将hello-springboot-0.0.1-SNAPSHOT.jar复制到镜像文件中,目标名称为app.jar
COPY hello-springboot-0.0.1-SNAPSHOT.jar app.jar

5 ADD

ADD 指令可以拷贝文件或目录到镜像中,类似于 COPY,但支持更多功能。

语法:

ADD <src> <dest>

src 可以是一个本地文件或者是一个本地压缩文件,压缩文件会自动解压。还可以是一个 url,如果把 src 写成一个 url,那么 ADD 就类似于 wget 命令,然后自动下载和解压。

举个栗子:

通过 url 下载文件到镜像的 /tmp/ 目录下,并解压:

ADD https://example.com/file.tar.gz /tmp/

6 WORKDIR

WORKDIR 命令用于设置工作目录,此后的 RUN、CMD、ENTRYPOINT、COPY 、AND 等命令将在这个工作目录下执行。

语法:

WORKDIR 路径

WORKDIR 命令可以多次使用,每次使用都会改变当前工作目录。

举个栗子:

WORKDIR /path/to/directory

如果设置的目录不存在会自动创建。

7 ENV

ENV 命令用于在构建镜像过程中设置环境变量,这些环境变量是一直存在于镜像中的。

语法:

# 格式1
ENV key value
# 格式2:可以使用=
ENV key1=value1 key2=value2

举个栗子:

# 设置一个名为 "WORK_HOME" 的环境变量
ENV WORK_HOME /home/doubi# 引用WORK_HOME环境变量
WORKDIR $WORK_HOME

环境变量可以在后续的RUN、WORKDIR命令中使用。

如果在 Dockerfile 中使用 ENV 指令设置了环境变量,那么在使用 docker run 命令的时候,可以使用 -e 参数覆盖 Dockerfile 中设置的值。这在需要动态配置容器时非常有用,比如根据运行时的条件来设置不同的环境变量值。

举个栗子:

# 设置Spring Boot配置文件环境变量,默认为dev  
ENV SPRING_PROFILES_ACTIVE=prod  

在运行容器的时候,可以使用 -e 参数覆盖 Dockerfile 中的环境变量:

docker run -d -e SPRING_PROFILES_ACTIVE=dev -p 8080:8080 my_image

8 ARG

ARG 命令与 ENV 命令作用一样,和 ENV 命令不同的是:这些变量只在构建过程中有效,构建完成后不会被保留在最终的镜像中。

语法:

ARG key[=value]
  • name :参数的名称。
  • default_value :参数的默认值,可以缺省。

构建过程中,ARG 定义的参数可以用于在 Dockerfile 中的各个指令中,并在 docker build 命令中被覆盖。它对于在构建时动态地传递参数非常有用。

举个栗子:

# 定义构建参数  
ARG VERSION=latest  
ARG BUILD_DATE  # 使用构建参数设置环境变量  
ENV APP_VERSION=$VERSION  
ENV BUILD_DATE=$BUILD_DATE 

在构建的时候,可以通过 --build-arg 传递参数:

# 可以传递多个参数
docker build --build-arg VERSION=1.0.0 --build-arg BUILD_DATE=$(date) -t my-image .

9 EXPOSE

EXPOSE 命令的作用就是对外暴漏端口。但是并不是打开端口,而是声明,实际还是在运行 docker run 命令的时候,通过 -p 参数指定。

语法:

EXPOSE <port> [<port>/<protocol>...]
  • <port>:要暴露的端口号。
  • <protocol>:可选参数,指定要使用的协议(如 tcpudp)。

举个栗子:

# 暴露80端口
EXPOSE 80# 暴露多个端口
EXPOSE 80 443# 指定端口和协议
EXPOSE 8080/tcp

可以一次指定多个端口,或者指定多个端口和协议的组合。

10 CMD

CMD 命令用于为容器指定默认的执行命令或应用程序。当容器启动时,这个命令将被执行,可以用来启动容器中的应用程序。

什么意思,是不是有点蒙?

前面的 RUN 命令是在构建镜像的时候执行,也就是执行 docker build 命令的时候执行;而 CMD 命令是启动容器的时候执行,也就是执行 docker run 命令的时候执行。

查看官方的 Tomcat 镜像的 Dockerfile,可以看到最后一行脚本是:

CMD ["catalina.sh", "run"]

catalina.sh run 命令也就是启动 Tomcat 的命令。如果没有这行命令,在使用 docker run 命令启动 Tomcat 容器的时候,容器是启动起来了,但是容器中的 Tomcat 没有被启动。所以 CMD 命令可以用来启动容器中的应用程序的。

如果在 Dockerfile 中存在多个 CMD 命令,只有最后一个会生效。


CMD 命令的语法和 RUN 命令相似,也支持 ShellExec 两种格式:

# Shell格式
CMD <command># Exec格式
CMD ["参数1", "参数2", ...]

需要注意:CMD中定义的命令会被 docker run 之后的参数替换

什么意思呢?看下面的指令:

docker run -it -p 8080 tomcat /bin/bash

上面的 /bin/bash 就是 docker run 之后的参数,会替换掉 Tomcat Dockerfile文件中的 CMD ["catalina.sh", "run"] 命令中的参数,导致容器启动了,但是 Tomcat 没有被启动,所以一定要注意。

11 ENTRYPOINT

ENTRYPOINT 命令用于指定容器启动时执行的命令,它与 CMD 命令有些相似。同样在一个 Dockerfile 中只能有一个 ENTRYPOINT 命令。如果在 Dockerfile 中定义了多个 ENTRYPOINT,则只有最后一个 ENTRYPOINT 命令会生效,而之前的将被忽略。

ENTRYPOINT 命令也支持 ShellExec 两种格式:

# Shell格式
ENTRYPOINT <command># Exec格式
ENTRYPOINT ["参数1", "参数2", ...]

但是 ENTRYPOINTCMD 有一些关键的区别。

前面说到 CMD中定义的命令会被 docker run 之后的参数替换,但是ENTRYPOINT 命令不会。如果用户在运行容器时提供了命令,那么这些用户提供的命令将作为参数传递给 ENTRYPOINT 指定的命令。

举个栗子,比如我们的 Dockerfile 中有如下命令:

ENTRYPOINT ["echo", "Hello, Docker!"]

那么在使用 docker run 命令运行镜像的时候,后面添加了 “Custom command” 参数:

# 启动容器
docker run -it my-image "Custom command"

那么启动容器执行的指令将会是 echo "Hello, Docker!" "Custom command"


ENTRYPOINT 可以和 CMD 一起使用,当需要使用变参的时候,可以使用 CMDENTRYPOINT 传递参数,此时的 CMD 作用发生了变化,不再是运行命令,而是将 CMD 的内容作为参数传递给 ENTRYPOINT 命令。

举个栗子:

FROM nginxENTRYPOINT ["nginx", "-c"]
CMD ["/etc/nginx/nginx.conf"]

上面的 Dockerfile,在运行容器的时候,相当于执行了指令 nginx -c /etc/nginx/nginx.confCMD 的内容作为参数传递给 ENTRYPOINT 命令。

如果想要在运行容器的时候,传递参数,覆盖 /etc/nginx/nginx.conf,使用另外一个配置文件,那么可以在启动容器的时候指定参数:

docker run -it mynginx -c /etc/nginx/new.conf

那么相当于执行了指令 nginx -c /etc/nginx/new.conf

12 VOLUME

VOLUME 命令用来做匿名挂载,在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

语法:

# 方式1
VOLUME <路径># 方式2
VOLUME <路径1> <路径2># 方式3
VOLUME ["<路径1>", "<路径2>"...]

一个 Dockerfile 可以包含多个 VOLUME 命令,指定多个需要持久化存储的目录。

举个栗子:

FROM ubuntu:latest
VOLUME /data
VOLUME /config

在运行容器时,你可以使用 -v 选项来将宿主机上的目录挂载到 VOLUME 声明的目录上。例如:

docker run -v /host/data:/data -v /host/config:/config my-image

1.4 构建Tomcat镜像

dockerhub 上已经有了 Tomcat 镜像了,这里我们只是为了学习 Dockerfile 的常用命令,使用上面的命令构建我们自己的 Tomcat 镜像。

1 准备文件

查看 Tomcat 官方镜像的 Dockerfile,100多行很复杂,因为官方镜像是在 Dockerfile 中下载和安装 Tomcat,这里我们简单一点,先下载好 Tomcat 安装包,然后将安装包使用 ADD 命令将安装包拷贝到镜像中。

所以首先在 Tomcat 官网下载安装包,官网: https://tomcat.apache.org/

这里我下载 Tomcat10 的 apache-tomcat-10.1.19.tar.gz 包。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2 编写Dockerfile

下面开始编写 Dockerfile:

# 设置基础镜像为 Ubuntu 22.04  
FROM ubuntu:22.04  # 设置环境变量,防止在安装时有提示  
ARG DEBIAN_FRONTEND=noninteractive  # 更新软件包列表  
RUN apt-get update \  # 安装jdk  && apt install -y openjdk-17-jdk-headless \# 安装软件包之后清理APT缓存&& rm -rf /var/lib/apt/lists/*# 设置工作目录  
WORKDIR /opt  # 使用 ADD 命令拷贝并解压 Tomcat 压缩包  
ADD apache-tomcat-10.1.19.tar.gz /opt/  # 重命名解压后的目录
RUN mv apache-tomcat-10.1.19 tomcat# 暴露 Tomcat 默认的端口  
EXPOSE 8080  # 启动 Tomcat  
CMD ["/opt/tomcat/bin/catalina.sh", "run"]

上面的 RUN 命令如果太长,可以使用 \ 进行换行。

Tomcat 需要 JDK,所以先安装 JDK,然后将 apache-tomcat-10.1.19 添加到镜像中,然后启动 Tomcat,学了 Dockerfile 常用的命令,上面的脚本还是容器看得懂的。

3 构建镜像

Dockerfile 编写完成了,下面执行 docker build 命令,来构建镜像。

这里需要将 apache-tomcat-10.1.19.tar.gz 包和 Dockerfile 放在宿主机的同一个目录下,然后执行 docker build 命令:

docker build -t my-tomcat:10.1.19 .			# 后面有个点

构建如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4 运行容器

镜像已经构建完成,下面运行容器:

docker run -d -p 8080:8080 my-tomcat:10.1.19

运行后,可查看正在运行的容器:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5 访问Tomcat

运行容器后,可以访问宿主机的8080端口,来访问 Tomcat 了:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

完成!

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

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

相关文章

C语言学习过程总结(16)——指针(4)

一、数组名的理解 我们直接使用%p打印出地址来看看&arr【0】 和 arr的不同&#xff1a; int main() {int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] %p\n", &arr[0]);printf("arr %p\n", arr);} 、 很容易看出来两者的输出…

最强AI换脸工具Rope使用教程,Rope整合包下载【全网最全安装步骤】

Rope的汉化整合包&#xff08;包含模型&#xff09;以及下面教程所涉及到的所有安装包我都打包好了&#xff0c;需要的小伙伴可以关注文章底部公众号&#xff0c;回复关键词【rope】获取。 AI换脸软件简介必读 Rope 是一个免费开源的 AI 换脸软件&#xff0c;它具有图形化界面…

MySQL之旅

本文字数&#xff1a;11653&#xff1b;估计阅读时间&#xff1a;30 分钟 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 介绍 "简单是终级的精致。"- --列奥纳多达芬奇 虽然我们喜欢在 ClickHouse 为用户宣布新功能&#…

【代码】提取图像轮廓坐标并保存为YOLOv8所需的txt格式

该段代码的应用场景为对图像标注过后&#xff0c;想要对图像进行裁切&#xff0c;但是标签不能裁切&#xff0c;所以将原图像按照标签进行二值化后&#xff0c;将二值化后的图像进行裁切&#xff0c;然后使用opencv对裁切后的图像进行处理&#xff0c;识别出白色区域轮廓&#…

用c++实现计数排序、颜色排序问题

3.3.1 计数排序 【问题】 假设待排序记录均为整数且取自区间[0,k],计数排序(count sort)的基本思想是对每一个记录x&#xff0c;确定小于x的记录个数&#xff0c;然后直接将x放在应该的位置。例如&#xff0c;小于x的记录个数是10,则x就位于第11个位置。 【想法】 对于待排序序…

vulnhub-----SickOS靶机

文章目录 1.信息收集2.curl命令反弹shell提权利用POC 1.信息收集 ┌──(root㉿kali)-[~/kali/vulnhub/sockos] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:10:3c:9b, IPv4: 10.10.10.10 Starting arp-scan 1.9.8 with 256…

移动端研发技术的进化历程

移动端研发技术 移动端研发技术主要分为原生开发和跨平台开发。本章主要介绍一下移动开发技术的过去、当下和未来&#xff0c;一步一步介绍移动技术的进化历程。 原生开发 原生应用程序是指某一个移动平台&#xff08;比如iOS或Android&#xff09;所特有的应用&#xff0c;使…

【C/C++】C语言开发者必读:迈向C++的高效编程之旅

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方…

《1w实盘and大盘基金预测 day5》

从周预测到每天的预测都非常准。 主要的问题&#xff0c;操作股票情绪起伏太大&#xff0c;对一些个股把握不准&#xff08;医疗乱我心&#xff09;&#xff0c;整体情况还是非常好的。得分A 本周行情展望&#xff08;基本得到验证&#xff09;&#xff1a; 大盘应该还是震荡…

章节2:单词本该这样记

为什么我们记不住单词&#xff1f; 单词不是被胡编乱造出来的&#xff0c;单词是有规律的&#xff0c;单词是符合人类的逻辑的。 单词实际意思结构意义历史文化 我们要怎么记单词&#xff1f; 掌握单词的结构规律了解与单词有关的历史文化灵活巧计&#xff0c;不要太拘泥于…

vue2+vant2+Laravel7 实现多图上传到七牛云

后端接口 1、路由&#xff0c;在 routes/api.php 中 Route::resource(photos, PhotoController)->only(store);2、创建对应控制器 <?php namespace App\Http\Controllers; use Illuminate\Http\Request;class PhotoController extends Controller {/**** 上传图片* p…

网络安全行业真的很内卷吗?

有一个特别流行的词语叫做“内卷”&#xff1a; 城市内卷太严重了&#xff0c;年轻人不好找工作&#xff1b;教育内卷&#xff1b;考研内卷&#xff1b;当然还有计算机行业内卷…… 这里的内卷当然不是这个词原本的意思&#xff0c;而是“过剩”“饱和”的替代词。 按照网络安…

【GPT-SOVITS-03】SOVITS 模块-生成模型解析

说明&#xff1a;该系列文章从本人知乎账号迁入&#xff0c;主要原因是知乎图片附件过于模糊。 知乎专栏地址&#xff1a; 语音生成专栏 系列文章地址&#xff1a; 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…

每日五道java面试题之mybatis篇(三)

目录&#xff1a; 第一题. MyBatis的框架架构设计是怎么样的?第二题. 为什么需要预编译?第三题. Mybatis都有哪些Executor执行器&#xff1f;它们之间的区别是什么&#xff1f;第四题. Mybatis中如何指定使用哪一种Executor执行器&#xff1f;第五题. Mybatis是否支持延迟加载…

龙芯新世界系统(安同AOCS OS)安装Cinnamon桌面最新版6.0.4

龙芯的新世界系统安同AOCS OS是十分优秀的操作系统&#xff0c;处于纯社区方式运行&#xff0c;她的各组件更新得很及时&#xff0c;很多组件都处于最新的状态&#xff0c;给我们安装使用最新的开源软件提供了很好的基础。由于本人一直使用Cinnamon桌面环境&#xff0c;各方面都…

鸿蒙开发实战:【Faultloggerd部件】

theme: z-blue 简介 Faultloggerd部件是OpenHarmony中C/C运行时崩溃临时日志的生成及管理模块。面向基于 Rust 开发的部件&#xff0c;Faultloggerd 提供了Rust Panic故障日志生成能力。系统开发者可以在预设的路径下找到故障日志&#xff0c;定位相关问题。 架构 Native In…

【Linux】对进程PCB的理解查看进程信息的方法

一、学习准备&#xff1a;对操作系统工作模式的理解 首先我们要清楚的是&#xff0c;操作系统是一个进行软硬件资源管理的软件。操作系统对下要管理好底层硬件。每一个硬件的生产产商都会给他们的产品提供对应的驱动程序&#xff0c;驱动程序是特定于某一硬件或系统设备的软件组…

【CTF web1】

CTF web 一、CTF web -PHP弱类型1、是否相等&#xff1f;2、转换规则: 二、CTF web -md5绕过1、若类型比较绕过2、null绕过3、碰撞绕过 三、习题 一、CTF web -PHP弱类型 1、是否相等&#xff1f; &#xff1a;在进行比较的时候&#xff0c;会先判断两种字符串的类型是否相等&…

Flink程序员开发利器本地化WebUI生成

前言 在flink程序开发或者调试过程中&#xff0c;每次部署到集群上都需要不断打包部署&#xff0c;其实是比较麻烦的事情&#xff0c;其实flink一直就提供了一种比较好的方式使得开发同学不用部署就可以观察到flink执行情况。 上代码 第一步&#xff1a;开发之前需要引入在本…

快速获取网页所有图片/获取网页电子资源内的图片

有时候看一些电子资源/电子教案过程中&#xff0c; 想把这些图下载下来&#xff0c;但是不能一个个截图 在之前的文章介绍了使用IDM软件下载所有的图片的方式&#xff0c;这种方式需要获取一个图片的地址并迭代 但是今天又发现了一种更快捷方式&#xff0c;是在浏览器控制台…