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

JavaEE平台技术——预备知识(Maven、Docker)

JavaEE平台技术——预备知识(Maven、Docker)

  • 1. Maven
  • 2. Docker

在这里插入图片描述

在这里插入图片描述

在观看这个之前,大家请查阅前序内容。
😀JavaEE的渊源
😀😀JavaEE平台技术——预备知识(Web、Sevlet、Tomcat)

1. Maven

💻Maven和Docker在我们的课程设计中以及我们的JavaEE应用程序中,扮演着非常重要的角色。Maven是一个纯Java的开源项目,其主要功能类似于集成开发环境(IDE),除了代码编写外,IDE还负责编译、执行和测试代码,以及生成各种文档。尽管IDE可以完成这些任务,但由于不同的IDE之间存在巨大差异,比如有人使用IntelliJ IDEA,而另一些人喜欢使用Eclipse,甚至有人使用微软的VS Code,这使得不同IDE生成的工程文件无法互通。为了解决这个问题,我们需要选择一个与IDE无关的项目管理工具,这就是Maven。

💻Maven不仅仅用于工程管理,它还能够有效地管理Java Archive (Jar)包。传统上,在IDE中,我们需要手动引入不同的Jar包,而且这些Jar包的版本可能存在差异,导致冲突。然而,Maven提供了一个中央仓库,可以在代码编写过程中自动下载所需的Jar包,因此开发者无需关心Jar包的具体位置和版本,从而简化了开发流程。

💻在Maven中,所有项目的结构和文件命名都遵循一套标准的规范,这可以避免因项目结构不一致而导致的混乱。

Maven通过一个名为POM(Project Object Model)的XML文件来管理项目。POM文件描述了项目的所有信息和依赖关系,其中一个重要特性是可以在POM文件中声明项目所依赖的第三方库,Maven会从中央仓库自动下载这些依赖。

在这里插入图片描述

💻Maven的Jar包仓库位于用户目录下的隐藏目录.m2中,通过将Jar包从中央仓库下载到本地仓库,再从本地仓库复制到工程目录下,实现了对Jar包的管理和依赖解析。作为初学者,可能会遇到一些关于Jar包的问题,如果出现问题,可以尝试删除.m2目录并重新构建,不过这样做可能会导致编译过程变慢,因为Maven需要重新下载所有的依赖。

在这里插入图片描述

Maven通过三个概念(生命周期、阶段和插件及其目标)来管理构建、打包和编译的过程。

💻生命周期包括clean、default和site。

  • clean用于清理工程文件(比如编译出的class文件 打包的jar包)
  • default用于编译、测试和打包。
  • site用于生成项目报告和发布测试报告。(少用)

在项目开发过程中,我们通常会用到这些生命周期来管理项目的构建和测试过程,确保项目的可靠性和稳定性。

Clean💻
首先,我们谈到"clean"(清理)。对于每个生命周期中的中间阶段,它可以被进一步划分为若干个phase(阶段)。生命周期是独立的,彼此之间没有先后关系,它们各自是相互独立的。但是phase是有先后关系的。以最简单的"clean"为例,它包括三个phase:pre-clean(清理前),clean(清理),post-clean(清理后)。
在这里插入图片描述

根据名称,我们可以了解它们各自的功能:在进行清理前会做一些事情,在进行清理后又会做一些事情。默认情况下,既不做清理前的操作,也不做清理后的操作。清理操作指的是将所有内容清空。默认情况下有许多的phase。

Default💻
在这里插入图片描述

实际上,Default(默认)包含了许多的phase,这些phase可以在构建、编译和打包测试等过程中执行各种任务。每个phase都可以根据需求进行自定义,当然它们也有默认的定义。在这里我们不打算逐个phase地讲解它们的内容,而是重点介绍我们最常用的几个phase。这些phase的顺序是固定的。我们刚才说了,phase是有顺序的,即在进行任何一个阶段时,该阶段之前的所有阶段都会被执行。

比如说我们最常见的是在package这个阶段,我们可以看到几个橙色的阶段,其中包括prepare-package(准备打包)、test(测试)、compile(编译)和validate(验证)。

这些是我们常用的几个阶段。这意味着当我们要执行package阶段时,之前的阶段也会被执行。它首先会验证您的代码是否合法,然后对代码进行编译生成所需的 .class 文件,接着会对编译出的代码进行测试,一旦测试通过,就会对代码进行打包。如果任何一个phase失败,后续阶段就不会继续执行。例如,如果在编译过程中出现错误,测试阶段和打包阶段都不会执行。

这样的定义使用生命周期来定义我们的三个主要任务:
清理、构建和将构建结果发布到特定服务器上。在每个大任务中,通过定义一系列带有先后关系的phase,可以定义在这个任务中要执行哪些操作,以及这些操作的执行顺序。这些是默认的phase。

Site💻
在这里插入图片描述

site(网站)是用来发布(部署)的,因此可以看到在site阶段中,实际生成的是中间的site,并且还有pre-site和post-site,最终将生成的文档发布到特定的服务器上。在我们课程设计的代码中,实际上也使用了site和site-deploy phase。它用来生成我们的测试报告,并将测试报告发布到特定的服务器上,这样每个人都可以查看测试报告。这是site生命周期的应用。

第三个要介绍的是插件。我们已经定义了生命周期并定义了每个phase要执行的任务,这些任务都是由插件完成的。插件是在Maven中实际工作的组件。它们包括Maven自身提供的插件以及许多第三方插件。

因此,Maven能做什么其实说不好,关键在于Maven拥有哪些插件。只要Maven拥有某个插件,它就能执行该插件的任务。

💻许多第三方公司都为Maven开发了各种各样的插件,因此Maven可以执行各种各样的任务。当Maven执行任务时,它将这些插件绑定到相应的phase上。如前所述,phase是有顺序的,因此可以根据需要将插件绑定到特定的阶段。对于每个插件来说,它实际上可以执行多个任务。

💻例如,就我们之前的例子而言,我们的默认编译插件实际上可以执行两个任务:一是编译项目代码,二是编译测试代码。
在这里插入图片描述

💻由于工程代码和测试代码位于两个目录下,因此如果需要编译工程代码,它只会编译工程代码;如果需要编译测试代码,它只会编译测试代码。对于每个插件,它所执行的每个任务都称为"plugin goal"(插件目标)。您需要完整地标识要完成的任务,并告诉它您要使用哪个插件以及您要让该插件完成什么任务。

💻如上所述,compile-plugin用于compile的目标,它只会编译工程代码。
如果让它编译测试代码,那么就是testCompile。

插件与phase相关联,默认情况下它们是关联的,当然您可以修改这一关联。
正如我们之前提到的,在clean生命周期中的clean phase之前,有pre-clean phase和post-clean phase,这两者都是空的。clean phase执行的操作是maven-clean-plugin:clean的目标,它的功能是将上次构建的所有文件全部清除,将其清空并将目录删除。如果您希望执行其他操作,可以更改这个目标所绑定的插件。这是默认设置中我们常用的几个phase的示例。

在这里插入图片描述

例如,compile使用compile-plugin:compile的目标,我们可以看到编译了工程代码。 test-compile phase位于test之前,它使用的是maven-compile-plugin:testCompile来编译测试代码。

类似的例子不再一一讨论。因此,每个phase默认情况下都已绑定了plugin goal。这是site阶段所绑定的默认goal,我们不再一一讨论。

最后,我们将介绍一个特殊关系,称为父子关系,它是pom文件中的一个特殊关系。

💻严格来说,一个pom描述了一个工程所需的所有依赖以及构建和打包的方式,但是我们的课程设计是分为多个模块的,每个模块的要求是不同的,因为每个模块执行的内容不同,所以它们的依赖关系也不同,它们的构建打包方式也不同。

pom实际上支持继承关系。所谓继承就是将一些通用的内容定义在父pom中,将一些特定的内容定义在子pom中。如此格式,即在父pom中定义了许多子pom的共性内容,同时也可以管理所有子pom的版本号等内容。

在这里插入图片描述

💻有了Maven之后,整个过程变得相对简单。——我们有一个视频向大家展示在没有Maven的情况下,我们如何在IDE中运行之前提到的Servlet。有了Maven之后,我们可以使用Maven来运行它,我们使用两个示例来比较使用Idea和Maven来管理项目的差异。

💻这两个示例都是基于我们之前提到的Servlet示例,但我们创建了两个项目,一个是Idea项目,一个是Maven项目。
在GitHub上获取了这个项目之后,我们首先展示了如何在Idea中运行Servlet示例。
在这里插入图片描述

Idea是一个集成开发环境,因此在使用Idea管理项目时,我们需要配置许多相关信息。

💻💻首先在第二章的预备知识目录中,有两个项目,一个是Servlet_Idea,一个是Servlet_Maven,它们分别是使用Idea和Maven管理的项目。然后我们打开Idea项目,我们会发现在它的根目录下有一个Servlet_Idea.iml文件,这个文件是Idea项目管理文件。
在这里插入图片描述

💻我们右键选择这个文件,导入这个module,之后我们会发现所有的文件和目录都会有颜色,这表明Idea已经识别了这些不同类型的文件。然后我们打开一个Java文件,我们会发现Java文件中有许多红色部分。
在这里插入图片描述

红色部分表示Idea不认识这些关键字。导致这种情况的原因可能是:

  • 一方面,项目原有的jdk可能与当前安装的Idea的jdk不一样;
  • 另一方面,JavaEE的Servlet相关库尚未导入。

为了使项目能够运行起来,我们需要在Idea中设置SDK和Servlet库。我们可以在File->Project Structure中找到SDK并设置为项目所需的SDK。
在这里插入图片描述

然后我们找到Tomcat的库,发现目前尚未设置,因此我们需要在Run->Edit Configuration中设置Tomcat的环境,包括指定Tomcat的安装目录等信息。
在这里插入图片描述

设置好Tomcat环境后,我们可以返回Project Structure,会发现在dependencies中的library中已经有了我们刚才设置的Tomcat 10.0.23。
在这里插入图片描述

接下来我们可以看到在Run->Edit Configuration中的Tomcat配置中,我们将刚才设置的artifacts部署到Tomcat服务器上,然后点击确定。

这样Idea的环境就配置好了。
在这里插入图片描述
在这里插入图片描述

太繁琐了!!!!!

接下来我们看一下在Maven中是如何做的。
我们的另一个目录中有Maven项目,在Maven项目中找到pom文件,您可能在课程中已经讲过pom文件包含了一个Maven项目所需的所有信息。因此,我们只需要右键单击pom文件,然后选择Add as Maven Project,然后您会发现所有的问题都解决了,代码中也不会有任何红色的部分,这表明Idea已经识别了所有的库。
在这里插入图片描述

此时右侧会出现一个Maven的小tab,我们打开Maven的tab会看到Maven的生命周期和phase。
在这里插入图片描述

然后我们选择package phase,让它执行打包操作。

完成打包后,我们在下面的plugins中使用Tomcat 7的plugin将其运行起来。这两步操作之后,我们的Servlet就可以正常运行了。
在这里插入图片描述

为什么Maven可以如此简单地完成配置?
💻因为它将所有的信息都写在了pom文件中,所有的库都会从Maven的中央仓库下载并安装到相应的位置。因此,相对于Idea来说,将一个Maven项目引入到任何一个IDE中都是非常方便的。

通过上述过程我们可以看到,Maven的配置过程要简单得多。最后我们来看一下在Maven的pom文件中放了什么样的内容。

<?xml version="1.0" encoding="UTF-8"?>
<!--    工程的根标签-->
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><!--    模型版本需要设置为 4.0。--><modelVersion>4.0.0</modelVersion><!--    工程组的标识。它在一个组织或者项目中通常是唯一的--><groupId>cn.edu.xmu.javaee</groupId><!--    工程的标识。它通常是工程的名称。--><artifactId>Servlet_Maven</artifactId><!--    工程的版本号。在 artifact 的仓库中,它用来区分不同的版本。--><version>1.0-SNAPSHOT</version><!--    打包的格式--><packaging>war</packaging><!--    定义属性,用在后面的定义中--><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!--    定义依赖关系--><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency></dependencies><!--    定义构建的方法--><build><sourceDirectory>src/main/java</sourceDirectory><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.10.1</version><configuration><source>11</source><target>11</target></configuration></plugin><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><configuration><port>8080</port><path>/</path><server>tomcat7</server></configuration></plugin></plugins></build>
</project>

首先是一个dependency,依赖是Servlet的API,但我们将其类型标记为provided。"provided"表示在打包时它实际上不会将这个库打包到我们最终的项目中,因为我们的项目依赖于Tomcat,而Tomcat本身就包含了这个库。但是在编译时,它会使用Maven中央仓库中的库来检查编译是否正常。但在运行时,实际上并不会包含Servlet库,而是使用了Tomcat库。这是一个dependency的示例。接下来我们可以看到我们使用了两个plugin。

💻一个plugin是Maven的plugin,用来做编译的,而另外一个plugin,则是运行我们的工程的,Tomcat的plugin,靠这两个plugin,我们就能够把整个项目把它编译好,然后把它运行起来,这就是一个Maven的例子。

💻没有Maven的时候我们大家在做十几步,才能在IDE里把它配出来跑,因为IDE需要知道所有的外部环境,有Maven以后所有的环境都描述在pom文件中间,你只要把import进去就可以跑,所以只有两步这个差异是非常明显的,所以今天在做所有的项目的时候,基本上就是用的Maven,或者另外一个等价的东西叫做graddle,但是我们课程都是用的Maven,Maven graddle其实是一样的,我们很多的东西都可以看到它既有,Maven的版本也有graddle版本。

在这里插入图片描述

2. Docker

导读:让我们花一些时间来探讨Docker。Docker也是我们在这里使用的一个至关重要的技术。我们在第一堂课中提到,我们的目标是建立一个具有弹性和可扩展性的架构。我们希望我们编写的程序能够灵活部署。如果负载增加,它可以增加部署数量;如果负载减少,它也可以减少部署数量。然而,实现这种任意部署实际上需要一定的前提条件。我们知道每个应用程序都对其部署环境有一定的要求。例如,我们编写的程序可能依赖于特定版本的Java虚拟机(JVM),有些应用程序可能依赖于JRE11,有些可能依赖于JRE8。此外,某些程序可能还依赖于像之前提到的Apache Portable Runtime (APR) 等软件。因此,每个应用程序都有其独特的要求。问题是,我们如何将应用程序与其依赖的环境整合成一个整体,并将其部署在整个服务器上。

我们的Docker来了!!!!

这就是Docker的核心思想。Docker是一项虚拟化技术。在Docker出现之前,我们已经有了虚拟化技术。我们目前使用的服务器实际上都是虚拟机。那为什么还需要Docker呢?

实际上,虚拟机和Docker是不同的。虚拟机虚拟的是什么呢?它虚拟的是物理资源。可能在物理上只有一台机器,但是通过虚拟机技术,可以虚拟出许多台虚拟的机器。每台虚拟机都可以安装操作系统和其他软件。

而Docker虚拟的是什么呢?Docker虚拟的是操作系统。

在这里插入图片描述

就像这张图所示,目前的情况是,在下方有一台虚拟机,其上安装了操作系统,并在操作系统上安装了Docker引擎。通过这个引擎,您可以虚拟出不同的环境。每个环境看起来就像是一台独立的机器,但实际上它只是在操作系统上虚拟出来的环境。虚拟化环境的好处在于,每个应用程序都可以拥有自己独特的环境。由于每个应用程序的环境可能不同,它可以将应用程序和其环境作为一个整体部署在任意服务器上。它带着环境运行,而不受服务器环境的影响。

这种方法的基本思想是,所有应用程序实际上都基于相同的操作系统。它并不需要不同的操作系统。我们都是在Ubuntu 18.04的操作系统上运行我们的应用程序。应用程序之间的区别仅仅是它们的环境不同。因此,Docker将这些环境容器化,虚拟化出来,并使每个应用程序及其环境成为一个虚拟的独立单位,不会相互干扰。这就是Docker的作用。

现在Docker已经非常成熟了。这是因为目前大家普遍认为,虚拟化操作系统是有意义的,但对于我们的应用程序来说,虚拟化环境更加有用。因为应用程序可能始终使用Ubuntu操作系统,而不是一会儿想用Windows,一会儿想用Ubuntu。但每个应用程序对环境的要求可能不同。因此,Docker才会有其用武之地。

我们讲下一些Docker的基本概念,包括里头有两个基本概念,一个是镜像一个是容器

  • Docker镜像:应用环境的只读模板
  • Docker容器:运行和隔离应用的沙箱

镜像和容器是用来描述应用程序所依赖的环境的。镜像是只读的,而容器是可以修改的。如何理解这一点呢?

通常情况下,在安装一个应用程序时,大家会有这样的体验:安装一个应用程序后,您需要安装许多环境才能使该应用程序正常运行。例如,您安装了操作系统,但是Java程序无法运行,需要先安装虚拟机。一旦安装好虚拟机,Java程序才能在虚拟机上运行。虚拟机就是您需要在操作系统上安装的环境。我们可以将镜像视为一个只读的环境。举个例子,除了安装虚拟机之外,您可能还需要更改一些配置参数,如系统参数等。安装好虚拟机后,我们可以将其视为一个镜像。

实比如际上,镜像是分层的。在Docker中,镜像是分层的。每次安装一个组件,它就形成一层。您安装了Java虚拟机后,再安装其他组件,它们就会形成若干层叠在一起,最终构成您所使用的环境。一般来说,镜像中不会包含完整的Ubuntu操作系统,因为在镜像中包含完整的Ubuntu并没有意义。通常情况下,镜像中包含的是在Ubuntu操作系统上安装的其他组件。这些组件形成一个镜像,比如最常见的是在镜像上安装JVM,然后安装Tomcat。由于Tomcat是基于JVM的,所以安装JVM是一个镜像层,Tomcat是在JVM上另一个镜像层,最后您使用的就是这两个镜像层组成的环境。

安装完环境后,我们可能需要更改其配置。例如,在Tomcat中可能需要更改一些值。我们可以将需要更改的配置保存在容器中,而不是将其保存为只读的。因为不同的Tomcat可能具有不同的配置,但是JVM和Tomcat可能会被重复使用。因此,我们可以将配置更改保存在容器中。因此,容器和镜像共同构成我们最终的环境。但是容器和镜像的区别在于,容器是由镜像生成的。您可以在容器中随意更改或安装任何东西,但是这些更改不会被保存。如果删除了容器,更改也会被删除。而镜像是会被保存下来的,它会一直存在。

实际上,在最终使用时,我们使用的是容器。容器是由镜像生成的,您可以对容器进行进一步的更改,但是容器不会保存这些更改。容器与容器之间是隔离的。我们可以将容器看作是一台独立的虚拟机。它具有独立的IP地址,就像一台独立的机器一样使用。但实际上它是在操作系统中虚拟出来的。这就是Docker的一些应用。
在这里插入图片描述
镜像和容器就是类和实例的关系

  • 我们从后面的开始讲,我们最开始是首先要有镜像,所以我们用这个命令能够看到,本地的所有的镜像。
    docker images:列出本地镜像

  • 然后由镜像生容器,去从一个镜像里头,产出一个容器,容器出来以后你在容器,里头就可以任意去改配置,然后形成你最终要用的东西。
    docker run:由镜像创建容器并运行一个命令

  • 你可以启动停止和重启一个容器,这都不会去让这个容器死亡掉。
    docker startlstop/restart:启动/停止重启容器

  • 但是这条命令会让容器死亡掉,会删掉一个容器,你在容器里头改的那些内容就没了,这个容器就没有了。
    docker rm :删除一个或多个容器

  • ps可以列出当前的所有的容器,一个镜像可以出多个容器,因为每个容器可以任意去改配置,ps可以看到,所有的容器以及容器和镜像的关系。
    docker ps:列出服务器上的容器

  • ps都可以看镜像能不能删,镜像也可以删,用rmi可以把镜像删掉
    docker rmi :删除个或多个镜像

产生镜像的方式有很多种,其中最常用且推荐的方式是使用一个描述文件来生成镜像。这个描述文件被称为DockerfileDockerfile实际上包含了一系列指令,指令并不多,稍加介绍后大家就能了解,主要有以下几条指令:

  1. FROM:指定基础镜像。可以基于另一个镜像构建新的镜像。由于镜像是分层的,您可以在现有镜像的基础上安装新的组件,从而形成一个新的镜像。

  2. MAINTAINER:描述镜像是由谁创建的。

  3. RUN:在镜像中执行命令。通常用于安装软件。例如,您可以基于一个基础镜像,然后使用RUN命令安装Tomcat。

  4. EXPOSE:将容器的端口暴露出来。我们稍后会讨论为什么要这样做。

  5. ADD:将文件复制到镜像中。

  6. ARGS:为镜像指定参数。

此外还有两个指令,即ENTRYPOINTCMD,它们在容器启动时继续执行命令。这两个指令只能使用其中之一,如果同时写了两个,那么只有后面那条指令会起作用。这两条指令的区别在于,ENTRYPOINT是不可覆盖的,如果要覆盖,则需要添加参数,而CMD是可以覆盖的。因此,通常会综合使用ENTRYPOINT和CMD来达到我们的目的。

在这里插入图片描述

让我们看一个例子,这个例子是我们以后会频繁使用的Dockerfile。这个Dockerfile的基础镜像是jdk11,这个基础镜像已经在Docker的库中存在,因此我们不需要再安装JDK11或进行其他RUN操作。所以我们使用了基础镜像JDK11,它提供了一个带有JDK11的虚拟机。操作系统的第一层是一个虚拟机。在这个基础镜像上,第一条指令只是提示了一下是谁创建的这个镜像。然后我们指定了当前工作目录是/app。因此,在镜像中会有一个当前的工作目录/app。

这个例子中有一个传参。我们之后会使用这个参数来传递文件名,因为我们现在并不知道文件名,所以我们需要在镜像中拷贝一个文件。ADD命令就是用来拷贝文件的。我们将传入的文件拷贝到镜像的/app目录下,并将其命名为app.jar

接下来,我们要将容器的8080端口暴露出来。这是因为8080端口实际上是Tomcat的默认端口。我们计划让外部可以访问,所以我们将其暴露出来。然后在最后写了一个ENTRYPOINT和CMD。ENTRYPOINT是用来执行一个java -jar这样的命令。我们现在写了两条命令,实际上是java -jar,后面跟着app.jar。这些命令的目的是将拷贝进来的Jar文件运行起来。

这就是我们以后会经常使用的一个Dockerfile示例。使用这个Dockerfile,它可以生成一个镜像。当我们完成了工程,将代码变成Jar包并将Jar包拷贝到其中后,这个Dockerfile就可以生成一个镜像。然后我们可以将这个镜像拷贝到任何一台服务器上并运行它。当您启动这个容器时,它会自动执行后面的命令,并将应用在jdk11的服务器上运行起来。

AAAAAAA

为什么要分成两句话来写呢?实际上这样做并没有多大意义,只是为了展示一下可以这么做。因为这个可以在运行时被覆盖,java -jar到底运行哪个Jar包其实是可以覆盖的,但对此没有意义。镜像中间实际上只有一个Jar包,在本地/app目录下找到第二个Jar包是没有意义的。不过这样做的一个作用是代表ENTRYPOINT和CMD是可以分开写的,而且CMD可以在启动时指定要启动的Jar包,可以从外部传参而不会有问题。

最后,我们要谈论一个问题。在一台虚拟机上可以运行多个容器,容器和容器之间的程序该如何通讯呢?因为所有的容器之间是被相互隔离的,它们是不能相互访问的。为了解决这个问题,Docker在服务器平台上提供了一个集群,叫做Swarm集群

Swarm集群的作用是将我们在若干台服务器上运行的容器作为一个集群来管理,统一控制这些容器之间应该运行什么样的服务。通过将主服务和从服务全部加入集群,它可以将整个集群作为一个整体来提供服务。只需要启动主服务,然后将剩余的服务加入,剩下的事情就会搞定。因此,从操作的角度来说,我们需要补充一些关于Docker集群的概念。

它的结构是这样的,所有的服务器被分为两类,一类是manager,另一类是worker。Manager在整个集群中负责管理和协调所有的服务。我们所有的操作也都在Manager上进行。Worker基本上不动,只要装好它能够运行的Docker的image。
在这里插入图片描述

我们在Docker中有两个概念,一个是只读的Image,另一个是能够运行的容器,即container。在worker上只要装好它能够运行的image,在manager上也可以装image,其实manager也是一个worker,它是平等的。

这是总的结构,由manager和worker组成。它的特点是去中心化,也就是所有的manager和worker实际上都可以运行我们的Docker。至于它运行哪个Docker,是由它自己去调度的。我们只需要告诉它你要运行3份还是运行4份,它自己去调度说它运行什么。所有的服务器构成了一个服务器的主机网络。它在内部采用了Overlay网络。

Overlay网络是一个虚拟网络

  • 利用它本身提供的Overlay网络,就能够实现所有的容器互通。关键是,它给我们带来了最大的好处,就是因为每一个节点的IP是会发生改变的,所以它也提供了一些有限的服务发现机制。
  • 另外,它还具有负载平衡的功能。如果你访问其中的任何一台服务器,它都会将其转发给集群中真正负责这项任务的那台服务器。至于它会转发给谁,它会根据动态负载平衡来决定。

总的特点主要有三个方面。首先,需要选择一台机器作为Manager,并在该Manager上初始化Swarm,创建一个Swarm集群。通过一条命令创建完成后,系统会返回一个命令,用于让其他Worker加入集群,其中包含一个Token,会在屏幕上显示出来。您可以复制此命令,并在要加入集群的其他服务器上执行。这样,Swarm就会很简单地建立起来了。在Manager启动后,它还会返回一条命令,让您在其他服务器上运行。您只需将此命令复制并在所有服务器上执行一次,就可以建立一个Swarm集群。初始时,一个是Manager,其余都是Worker。由于只有一个Manager,其他操作相对简单。如果有多个Manager,操作会相对复杂。在初始实验中,只需建立一个Manager和一组Worker就足够了。

建立好Swarm后,我们如何运行Docker呢?只需要两步。首先,确保您的Docker可以运行。在每个Worker上都必须有Docker的镜像。如果Worker上没有相应的镜像,即使您让其运行Docker,它也无法运行。因为镜像是只读的,保存在文件中。那么如何建立Docker的镜像呢?在我们所有的代码中,今年的所有代码中我都加了Dockerfile。在原有的代码基础上,加上了Dockerfile,而原本的代码中仅限于使用Maven。最终只需执行package命令即可打出一个Jar包,整个过程就结束了。

今年的代码中间,我正在逐步地为我们今天将要讲述的所有代码中间逐步添加一些更新。实际上,我已经在每个代码中添加了一个Dockerfile。此外,我们还添加了一个插件,将其绑定到了package后面的一个阶段上。我们还记得我们之前讨论过的内容,在默认生命周期中,它包含了若干个阶段,所有的阶段按顺序执行。一般我们会使用package,因为package意味着代码已经编译、测试通过并打包完成,生成了一个JAR包。而installdeploy会将其安装到Maven仓库并部署到远端的Maven仓库,我们通常不会使用。现在我在代码中加入了一个插件,将其绑定到了package后面的阶段。我查看了一下package后面的阶段,发现只剩下integration-test,我们打算之后还会用到它,所以不能绑定到该阶段上。我将其绑定到了pre-integration-test阶段,这意味着在集成测试之前执行。pre-integration-test阶段在package阶段之后,因此,当您在自己的笔记本电脑或台式机上运行代码时,您不需要打包成Docker镜像,因为您可能没有安装Docker环境。您只需运行到package阶段即可,运行到package阶段就意味着已经打出了JAR包。然后,如果您使用Spring Boot的插件运行,只需运行它即可。但是,如果您要在我们的服务器上运行,则需要运行到pre-integration-test阶段。因为pre-integration-test阶段之前是package阶段,实际上在完成前面的工作(编译完成后),它会将其编译为Docker的镜像文件,并安装到服务器上。每个您需要运行的内容都需要在服务器上安装对应的镜像。安装完成后,它就可以在服务器上运行了。如果没有安装,它也不会出错,只是在那台机器上不会运行这个任务。换句话说,如果您在集群中要运行某个Docker,而某台worker没有安装对应的镜像,它肯定是不会运行的,只有安装了镜像的才会运行。因此,这是我们需要事先说明的一个问题。整个运行过程实际上是很简单的。如果这些worker和Manager上都已经安装了镜像,那么您只需要在Manager上创建一个服务即可,创建服务的命令就是Docker run命令。这将使得Docker容器作为一个服务在集群中运行。然后您告诉它您是要运行一份还是两份,如果您告诉它运行一份,它会在所有的机器中挑选一台有镜像的机器来运行。如果您告诉它运行两份,它将在有镜像的两台机器上运行。这就是引入Swarm后的一种工作方式。引入Swarm后,我们将会发现实验变得相对简单,我们的环境配置也会相对简单。

在这里插入图片描述

相关文章:

JavaEE平台技术——预备知识(Maven、Docker)

JavaEE平台技术——预备知识&#xff08;Maven、Docker&#xff09; 1. Maven2. Docker 在观看这个之前&#xff0c;大家请查阅前序内容。 &#x1f600;JavaEE的渊源 &#x1f600;&#x1f600;JavaEE平台技术——预备知识&#xff08;Web、Sevlet、Tomcat&#xff09; 1. M…...

【ChatOCR】OCR+LLM定制化关键信息抽取(附开源大语言模型汇总整理)

目录 背景技术方案存在的问题及解决思路关键信息提取结果其他解决方案替换文心一言LangChain大型多模态模型&#xff08;Large Multimodal Model, LMM&#xff09; 开源大模型汇总LLaMA —— Meta 大语言模型Stanford Alpaca —— 指令调优的 LLaMA 模型Lit-LLaMA —— 基于 na…...

【位运算】XOR Construction—CF1895D

XOR Construction—CF1895D 参考文章 翻译 题目要求构造一个长度为 n n n 的数组 b b b&#xff0c;满足以下条件&#xff1a; 数组 b b b 中包含从 0 0 0 到 n − 1 n-1 n−1 的每个整数&#xff0c;且每个整数仅出现一次&#xff1b;对于 i i i 从 1 1 1 到 n − …...

解决Visual Studio Code 控制台中文乱码问题

C和CPP运行编码指定 "code-runner.executorMap": {"c": "cd $dir && gcc -fexec-charsetGBK $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt","cpp": "cd $dir && g -fexec-charsetGBK $…...

React Native自学笔记

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…...

程序员笔记本电脑选 windows 还是 MAC

计算机选择是每个进入 IT 行业同学的第一个重要选择&#xff0c;那么你是怎么选择的呢&#xff1f; 选择操作系统&#xff08;Windows还是macOS&#xff09;取决于程序员的需求、偏好和工作流程。每个操作系统都有其优点和缺点&#xff0c;下面将分别讨论它们&#xff0c;以帮助…...

蓝桥杯每日一题2023.11.5

题目描述 方格分割 - 蓝桥云课 (lanqiao.cn) 题目分析 对于每个图我们可以从中间开始搜索&#xff0c;如果到达边界点就说明找到了一种对称的方法&#xff0c;我们可以直接对此进行答案记录每次进行回溯就会找到不同的图像&#xff0c;如果是一样的图像则算一种情况&#xff…...

多媒体应用设计师 2023年(含答案回忆版)

以下是小红书上的回忆版 软考考完疯狂回忆&#xff0c;多媒体应用设计师选择题 1.pattern 2.effective 3.merge 4.applications 5.graphic 6.udp 7.rtp 8.rtsp 9.10cm 10.永久 11…97 12.工作技术管理标准 13.管理型元数据 14.premiere 15.wave 16.500km/h 17.3M 18.44000 19.…...

[Machine Learning][Part 8]神经网络的学习训练过程

目录 训练过程 一、建立模型&#xff1a; 二、建立损失函数 J(w,b): 三、寻找最小损失函数的(w,b)组合 为什么需要激活函数 激活函数种类 二分法逻辑回归模型 线性回归模型 回归模型 训练过程 一、建立模型&#xff1a; 根据需求建立模型&#xff0c;从前面神经网络的…...

Git 内容学习

一、Git 的理解 Git是一个分布式版本控制系统&#xff08;Distributed Version Control System&#xff0c;简称 DVCS&#xff09;&#xff0c;用于对项目源代码进行管理和跟踪变更。分为两种类型的仓库&#xff1a;本地仓库和远程仓库。 二、Git 的工作流程 详解如下&#x…...

Zookeeper3.7.1分布式安装部署

上传安装文件到linux系统上面 解压安装文件到安装目录 [zhangflink9wmwtivvjuibcd2e package]$ tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz -C /opt/software/3. 修改解压文件名 [zhangflink9wmwtivvjuibcd2e software]$ mv apache-zookeeper-3.7.1-bin/ zookeeper-3.7…...

CSS必学:元素之间的空白与行内块的幽灵空白问题

作者:WangMin 格言:努力做好自己喜欢的每一件事 CSDN原创文章 博客地址 &#x1f449; WangMin 我们在开发的过程中&#xff0c;难免会出现一些难以预料的问题。那么其中&#xff0c;CSS空白现象就是非常常见的问题之一。虽然它已经被发现很久&#xff0c;但仍然有许多新手和经…...

C++类中对构造函数的重载

C类中对构造函数的重载 C 允许在同一作用域中的某个函数和运算符指定多个定义&#xff0c;分别称为函数重载和运算符重载。 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明&#xff0c;但是它们的参数列表和定义&#xff08;实现&#xff09;不…...

QtC++与QLabel详解

介绍 QLabel 类是Qt中的一个用于显示文本或图像的控件类&#xff0c;通常用于用户界面中以提供静态文本或图片显示的功能。以下是对QLabel在Qt中的作用的详细解释&#xff1a; 文本和图像显示&#xff1a; QLabel 可以用来显示文本和图像。这使得它成为显示标签、标题、说明或…...

090基于web+springboot的中小企业设备管理系统

欢迎大家关注&#xff0c;一起好好学习&#xff0c;天天向上 文章目录 一项目简介技术介绍 二、功能组成三、效果图四、 文章目录 一项目简介 本中小企业设备管理系统管理员有个人中心&#xff0c;用户管理&#xff0c;员工管理&#xff0c;设备信息管理&#xff0c;配件信息管…...

input 调起键盘 ,键盘距离输入框底部太近

input 调起键盘 &#xff0c;键盘距离输入框底部太近 解决方法 cursorSpacing‘20’ 单位是 ‘px’ <input cursorSpacing20 type"text" v-model"replyMain" />距离底部距离 20px &#xff0c;输入框距离键盘距离是20px...

前端深拷贝与浅拷贝的实现

1、浅拷贝和深拷贝的定义 1.1、浅拷贝 有两种方式&#xff0c;一种是把一个对象里面的所有的属性值和方法都复制给另一个对象&#xff0c;另一种是直接把一个对象赋给另一个对象&#xff0c;使得两个都指向同一个对象。浅拷贝对内存地址的复制&#xff0c;让目标对象指针和源…...

哆啦百宝箱APP

专门为年轻人设计的APP&#xff0c;主打的免费、无恶心广告、不获取任何个人信息。 哆啦百宝箱 ● 永久免费 ● 无恶心广告 ● 种类巨多 ● 全民参与 ● 爆款功能 ● 用心创造 哆啦百宝箱 提供了从日常、图片、查询、设备、趣味、娱乐等多方面的功能&#xff0c; 操作简单&a…...

lv9 嵌入式开发 数据库sqlite

1 数据库基本概念 数据&#xff08;Data&#xff09; 能够输入计算机并能被计算机程序识别和处理的信息集合 数据库 &#xff08;Database&#xff09; 数据库是在数据库管理系统管理和控制之下&#xff0c;存放在存储介质上的数据集合 2 常用的数据库 大型数据库…...

「Verilog学习笔记」异步复位的串联T触发器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 这道题目里我们有两个需要明确的点&#xff1a; 1. 什么是异步复位 2. 什么是串联的T触发器 关于第一个点&#xff0c;可以看我的这篇文章&#xff0c;已经整理好了&a…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

Spring AI与Spring Modulith核心技术解析

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

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...