Dockerfile应用的容器化

news2024/11/22 23:05:51

文章目录

  • Dockerfile应用的容器化
    • 应用的容器化——简介
    • 应用的容器化——详解
      • 单体应用容器化
        • 获取应用代码
        • 分析Dockerfile
        • 容器化当前应用/构建具体的镜像
        • 推送镜像到仓库
        • 运行应用程序
        • 测试
        • 总结
      • 最佳实践
        • 利用构建缓存
        • 合并镜像
    • 命令总结

Dockerfile应用的容器化

Docker 的核心思想是容器化,即将应用程序及其依赖项打包成一个可移植的容器,并通过容器来实现应用程序的快速部署、可靠性管理和跨平台运行。

应用的容器化——简介

完整的应用容器化过程主要分为以下几个步骤:

(1)编写应用代码

(2)创建一个Dockerfile,其中包括当前应用的描述、依赖以及该如何运行这个应用

(3)对该Dockerfile执行docker build 命令

(4)等待Docker 将应用程序(即应用被打包为一个Docker镜像)就能以镜像的形式交付并以容器的方式运行了。

image-20230606204515861

应用的容器化——详解

单体应用容器化

获取应用代码

从源代码仓库或本地文件系统中获取应用程序代码。

[root@localhost ceshi]# ls
  index.html  start.sh
# index.html 当服务需要用到的html文件
# start.sh 里面放置着开启http服务器的脚本

该目录下包含了全部的应用源码。

分析Dockerfile

Dockerfile 是用于构建 Docker 镜像的脚本文件,其中包含一系列指令和参数。下面是 Dockerfile 中常用的参数:

FROM          # 指定基础镜像,例如 FROM centos,表示使用 Centos Linux 作为基础镜像
MAINTAINER    # 镜像是谁写的,姓名+邮箱
RUN           # 镜像构建的时候需要运行的命令
ADD           # COPY文件会自动解压
WORKDIR       # 镜像的工作目录
VOLUME        # 挂载的目录
EXPOSE        # 声明容器将监听哪些端口,例如 EXPOSE 80,表示容器将监听 80 端口。
CMD           # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT    # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD       # 当构建一个被继承 Dockerfile 这个时候就会运行ONBUILD 的指令,触发指令
COPY          # 类似ADD,将我们文件拷贝到镜像中
ENV           # 构建的时候设置环境变量

在创建和编写Dockerfile需要注意些什么

  1. Dockerfile 文件必须位于上下文目录中 ,Docker 引擎会将该目录下的所有文件打包发送给 Docker daemon 进行构建。如果 Dockerfile 文件不在上下文目录中,则会出现构建失败的情况。
  2. Dockerfile 文件的文件名可选择为 Dockerfile,Docker 引擎会默认寻找该文件名作为构建镜像的脚本文件,否则在构建时你就要指定你的Dockerfile文件
  3. 使用大写字母 在 Dockerfile 中使用大写字母来命名指令和参数。例如,使用 FROM 而不是 from

了解了参数我们来创建一个自己的CentOS

[root@localhost ceshi]# vim Dockerfile 
FROM centos:centos7.9.2009
MAINTAINER CSQ
RUN yum install -y httpd
COPY index.html /var/www/html/index.html
COPY . /srv
WORKDIR /srv
RUN chmod 775 start.sh
EXPOSE 80
CMD ["./start.sh"]

Dockerfile主要包括两个用途

  • 对当前应用的描述
  • 指导Docker完成应用的容器化(创建一个包含当前应用的镜像)

具体分析每一步的作用

每个Dockerfile文件第一行都是FROM指令。FROM指令指定的镜像,会作为当前镜像的一个基础镜像层,当前应用的剩余内容会作为新增镜像层添加到基础镜像层之上。

image-20230607204435032

MAINTAINER CSQ:Dockerfile通过MAINTAINER 方式指定当前镜像维护者为CSQ,自己也可以在维护者后面添加更详细的信息有助于为该镜像潜在的使用者提供沟通途径。该操作不会创建一个新的镜像层。

RUN chmod 775 start.sh:给 /start.sh 文件添加可执行权限,会创建一个新的镜像层。

RUN yum install -y httpd:在容器中安装 httpd,会创建一个新的镜像层。

COPY index.html /var/www/html/index.html:将 Dockerfile 所在目录下的 index.html 文件复制到镜像中的 /var/www/html/ 目录下,会创建一个新的镜像层。

COPY . /srv : 将当前目录下的所有文件复制到 容器内的 /srv目录下,会创建一个新的镜像层。

WORKDIR /srv:Dockerfile 通过 WORKDIR 指令,为Dckerfile中尚未执行的指令设置工作目录。该目录与镜像有关,并且会作为元数据记录到镜像配置中,但不会创建新的镜像层。

EXPOSE 80:因为当前应用需要通过TCP端口80对外提供一个Web服务,所以在Dockerfile中通过EXPOSE 80 指令来完成相应端口的设置。这个配置会作为元数据被保存下来,并不会产生新的镜像层。

CMD ["./start.sh"]:容器启动后默认执行的命令,并不会产生新的镜像层。

目前镜像一共包含10层,如下图所示

image-20230609144228997

容器化当前应用/构建具体的镜像

接下来就算构建自己的镜像了!,下面的目命令会构建一个名为 web:v1.0 的镜像,命令后的【.】表示Docker镜像构建的时候,使用当前目录作为构建上下文

一定要在命令最后包含这个点,并且执行命令前,确认当前目录是你包含Dockerfile和应用代码的目录

# 通过这个文件构建镜像
# 命令 docker build -t 镜像名:[tag]  -f dockerfile路径 .
[root@localhost ceshi]# docker build -t web:v1.0 .
Sending build context to Docker daemon  4.096kB
Step 1/9 : FROM centos:centos7.9.2009
 ---> eeb6ee3f44bd
Step 2/9 : MAINTAINER CSQ
 ---> Running in 0189981f25a3
Removing intermediate container 0189981f25a3
 ---> c6d8ef18c3de
Step 3/9 : RUN yum install -y httpd
 ---> Running in 90f24717dd91
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
 * base: mirrors.huaweicloud.com
 * extras: mirrors.huaweicloud.com
 * updates: mirrors.bfsu.edu.cn
Complete!
Removing intermediate container 90f24717dd91
 ---> 909aa4b4a773
Step 4/9 : COPY index.html /var/www/html/index.html
 ---> 39539a6f3d77
Step 5/9 : COPY . /srv
 ---> aae2ee95e7ef
Step 6/9 : WORKDIR /srv
 ---> Running in 2d03bd7d7609
Removing intermediate container 2d03bd7d7609
 ---> ac81a36893bc
Step 7/9 : RUN chmod 775 start.sh
 ---> Running in 72b1cafd7673
Removing intermediate container 72b1cafd7673
 ---> 6a235fbc2631
Step 8/9 : EXPOSE 80
 ---> Running in 32d41d6a8470
Removing intermediate container 32d41d6a8470
 ---> 336e359c7dc7
Step 9/9 : CMD ["./start.sh"]
 ---> Running in 1c8c819dbb8f
Removing intermediate container 1c8c819dbb8f
 ---> 6107859f4850
Successfully built 6107859f4850
Successfully tagged web:v1.0

命令结束后,检查本地Docker镜像库是否包含了刚刚构建的镜像

[root@localhost ceshi]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
web                 v1.0                6107859f4850        4 minutes ago       445MB
centos              centos7.9.2009      eeb6ee3f44bd        21 months ago       204MB

现在应用以及容器化成功了!

可以通过 docker inspect web:v1.0 来确认刚刚构建的镜像配置是否正确。这个命令会列出Dockerfile中设置的所有配置选项

推送镜像到仓库

在创建一个镜像之后,将其保存在一个镜像仓库服务是一个很不错的方式。这样存储镜像会比较安全,并且可以被其他人访问使用。Docker Hub就算这样一个开放的公共镜像仓库服务,并且这也是docker push 命令默认的推送地址

推送镜像之前,需要先使用Docker ID 登录Docker Hub。除此之外,还需要为待推送的镜像打上合适的标签。(没有Docker Hub 可以自己注册一个)

接下来使用命令登录Docker Hub

[root@localhost ceshi]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: ayuqaq
Password: 

Login Succeeded

推送Docker 镜像之前,还需要为镜像打上标签。者是因为Docker在镜像推送的过程中需要如下信息

  • Registry(镜像仓库服务)
  • Repository(镜像仓库)
  • Tag(镜像标签)

当我们在使用Docker命令进行镜像推送时,如果没有明确指定Registry和Tag的值,Docker会默认使用docker.io作为Registry,使用latest作为Tag。但是,Docker并没有默认值可供Repository使用,而是从被推送的镜像中的REPOSITORY属性值获取。因此,在进行镜像推送时,我们需要明确指定Repository的值,否则Docker会报错。

执行docker images命令后发现当前的镜像仓库名称为web:v1.0,意味着在执行docker push命令时,会尝试将镜像推送到docker.io/web:v1.0中。但是,当前用户ayuqaq没有访问web这个镜像仓库的权限,只能尝试推送到自己的ayuqaq命名空间下。因此,需要为当前镜像重新打一个标签,加上ayuqaq的ID作为命名空间,例如ayuqaq/web:v1.0,以便成功地将镜像推送到自己的命名空间下。

为镜像打标签命令的格式

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# SOURCE_IMAGE表示原始镜像名称,可以是镜像ID或者镜像名称加上标签名
# TAG表示原始镜像的标签,默认为latest
# TARGET_IMAGE表示打好标签后的目标镜像名称,可以包含命名空间,也可以不包含
[root@localhost ceshi]# docker tag web:v1.0 ayuqaq/web:latest
[root@localhost ceshi]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ayuqaq/web          latest              6107859f4850        6 minutes ago       445MB
web                 v1.0                6107859f4850        6 minutes ago       445MB
centos              centos7.9.2009      eeb6ee3f44bd        21 months ago       204MB

现在将该镜像推送到Docker Hub

[root@localhost ceshi]# docker push ayuqaq/web:latest
The push refers to repository [docker.io/ayuqaq/web]
d10a5034e7a0: Pushed 
894e08c192f4: Pushed 
2de26a085520: Pushed 
0d4e9442311f: Pushed 
174f56854903: Layer already exists 
latest: digest: sha256:77f20a3da4e6d35ea56260ffac2438d551f9e62bc083f2ac328fff6d6575c872 size: 1363

下图展示了Docker如何确定镜像所要推送的目的仓库

image-20230609145324141

运行应用程序

运行这个应用程序很简单

[root@localhost ceshi]# docker run -d -p 8888:80 --name webserver web:v1.0
# docker run:创建并启动一个新的容器。
# -d:在后台运行容器。
# -p 8888:80:将主机的8888端口映射到容器内部的80端口。
# --name webserver:指定容器的名称为webserver。
# web:v1.0:使用web:v1.0镜像作为容器的基础镜像。

接下来验证一下程序是否真的运行,并且对外提供服务的端口是否正常工作

image-20230609145401958

从上面的输出可以看到,容器已经正常运行。需要注意的是,8888端口已经成功映射到了80之上,并且任意外部主机都可以通过8888端口访问容器。

测试

打开浏览器,输入 localhost:8888 就可以访问到了(localhost是自己的主机IP)

image-20230609145617546

如果没有出现如上页面,尝试下面的检查来确认原因所在

  • 使用 docker ps 指令来确认容器已经启动并且正常运行。容器名称是 webserver,并且从输出内容中可以看到 0.0.0.0:8888->80/tcp
  • 确认防火墙或者其他网络安全设置没有阻止访问Docker 主机的8888端口

总结

Dockerfile 中的注释行,都是以#开头的

除了注释之外,每一行都是一条命令。指令的格式和指令参数:RUN command

指令是不区分大小写的,但是通常采用大写的方式,这样Dockerfile的可读性会高一些

docker build 命令会按行来解析Dockerfile 中的指令并顺序执行

部分指令会在镜像中创建新的镜像层,其他指令只会增加或修改镜像的元数据信息。

上面例子中,新增镜像层指令包括 FROM RUN 以及 COPY

而新增元数据指令包括 EXPOSE、WORKDIR、ENV、CMD。关于如何区分命令是否会新建镜像层,一个基本原则是,如果指令的作用是向镜像中增添新的文件或者程序,那么这条指令就会新建镜像层;如果之上高速Docker如何完成构建或者如何运行应用程序,那么就只会增加镜像的元数据

可以通过docker history来查看构建镜像的过程中都执行了哪些指令

image-20230609145437126

上面的输出内容中,有两点需要注意的。

首先,每行内容都对应了Dockerfile中的一条指令(顺序是自下而上的) CREATED BY 这一行还展示了当前行具体对应Dockerfile中的哪条指令

其次,从这个输出内容中,可以观察到只有5条指令会新建镜像层(就是SIZE列对应的数值不为0的指令),分别对应着 Dockerfile 中的 FROM 、RUN以及 COPY 指令。虽然其他指令看上去跟这些新建镜像层的指令并无区别,但是实际上它们只在镜像中新增了元数据信息。这些指令看上去之所以没有区别,是因为Docker对之前构建镜像层方式的兼容。

可以通过 docker inspect 指令来确认确实只有5个层被创建了

image-20230609150840081

使用FROM 命令引用官方基础镜像是一个很好的习惯,因为官方镜像通常会遵循一些最佳实践,并且能够帮助使用者规避一些已知的问题。除此之外,使用FROM的时候选择一个相对较小的镜像文件通常也能规避一些潜在的问题。

最佳实践

利用构建缓存

Docker的构建过程是利用了缓存机制的,这个机制可以让构建过程更快。比如说,第一次构建一个Docker镜像需要花费一定的时间,因为要拉取基础镜像并构建镜像层。但是如果在一个全新的Docker主机上再次构建同样的镜像,基本上可以立即完成,因为第一次构建的内容已经被缓存下来了,可以被后续的构建过程复用。

在构建过程中,Docker会检查每一条指令对应的镜像层是否在缓存中存在,如果存在,就会使用缓存中的镜像层;如果不存在,就会基于这条指令构建新的镜像层。通过这个缓存机制,可以显著加快构建过程。

如下Dockerfile案例

FROM centos:centos7.9.2009
RUN yum install -y httpd
COPY index.html /var/www/html/index.html
COPY . /srv
WORKDIR /srv
RUN chmod 775 start.sh
EXPOSE 80
CMD ["./start.sh"]

第一条指令告诉Docker使用 centos:centos7.9.2009 作为基础镜像。如果主机中已经存在这个镜像,那么构建时会直接跳到下一条指令:如果镜像不存在,则会从Docker Hub(docker.io)拉取。

下一条指令(RUN yum install…) 对镜像执行了一条命令,此时Docker会检查构建缓存中是否存在基于同一基础镜像,并且执行了相同指令的镜像层。在此例中,Docker 会检查缓存中是否存在一个基于centos:centos7.9.2009镜像并且执行了RUN yum install -y httpd指令构建得到的镜像层

如果找到该镜像层,Docker 会跳过这条指令,并链接到这个已经存在的镜像层,然后继续构建;如果无法找到符合要求的镜像层,则设置缓存无效并构建该镜像层。此处"设置缓存无效"作用于本次构建的后续部分。也就是说Dockerfile中接下来的指令将全部执行而不会尝试查找构建缓存。

假设Docker已经在缓存中找到了该指令对应的镜像层(缓存命中),并且假设这个镜像层的ID是AAA

下一条指令会复制一些代码到镜像中(COPY index.html …)。因为上一条指令命中了缓存,Docker会继续查找是否有一个缓存的镜像层也是基于AAA层并执行了COPY 。 /src 命令。如果有,Docker会链接到这个缓存的镜像层并继续执行后续的指令;如果没有,则构建镜像层,并对后续的构建操作设置缓存无效

假设Docker已经有一个对应该指令的缓存镜像层(缓存命中),并且假设这个镜像层的ID是BBB

那么Docker将继续执行Dockerfile中剩余的指令。

首先,一旦有指令在缓存中未命中(没有该指令对应的镜像层),则后续的整个构建过程将不再使用缓存。在编写Dockerfile时须特别注意这一点,尽量将易于发生变化的指令置于Dcokerfile文件的后方执行。这意味着缓存未命中的情况将直到构建的后期才会出现——从而构建过程能够经理从缓存中获益

通过对doker build 命令加入 --no-cache=true 参数可以强制忽略对缓存的使用

COPY和ADD指令也会检查上次一构建后是否发生了变化

Docker会计算每一个被复制文件的Checksum值,并与缓存镜像层中同一文件的Checksum进行对比,如果不匹配,那么就认为缓存无效并构建新的镜像层。

合并镜像

合并镜像并非一个最佳实践,因为这种方式利弊参半

总体来说,Docker 会遵循正常的方式构建镜像,但之后会增加一个额外的步骤,将所有的内容合并到一个镜像层中。

当镜像中层数太多时,合并是一个不错的优化方式。例如,创建一个新的基础镜像,以便基于它来构建其他镜像的时候,这个基础镜像就最好被合并为一层。

缺点是,合并的镜像将无法共享镜像层。这回导致存储空间的低效利用,而且push和pull操作的镜像体积更大。

执行docker build 命令时,可以通过增加 --squash 参数来创建一个合并的镜像。

image-20230609193344331

上图,两个镜像内容完全一样,但一个经过合并,一个没有经过合并。如果将这两个镜像都上传到Docker Hub上,那么不经过合并的镜像只需要上传差异部分的镜像层即可,而经过合并的镜像则需要上传全部的镜像层,即使这些镜像层与已经上传的其他镜像的镜像层完全一样。

命令总结

docker build 命令会读取Dcokerfile,并将应用程序容器化。使用-t参数位镜像打标签,使用 -f 参数指定Dockerfile 的路径与名称,使用-f参数可以指定位于任何路径下的任意名称的Dockerfile。构建上下文是指应用文件存放的位置,可能是本地Docker主机上的一个目录或一个远程git仓库。

FROM          # 指定基础镜像,例如 FROM centos,表示使用 Centos Linux 作为基础镜像
MAINTAINER    # 镜像是谁写的,姓名+邮箱
RUN           # 镜像构建的时候需要运行的命令
ADD           # COPY文件会自动解压
WORKDIR       # 镜像的工作目录
VOLUME        # 挂载的目录
EXPOSE        # 声明容器将监听哪些端口,例如 EXPOSE 80,表示容器将监听 80 端口。
CMD           # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT    # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD       # 当构建一个被继承 Dockerfile 这个时候就会运行ONBUILD 的指令,触发指令
COPY          # 类似ADD,将我们文件拷贝到镜像中
ENV           # 构建的时候设置环境变量

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

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

相关文章

为什么网络安全缺口大,招聘却很少?

2023 年我国网络空间安全人才数量缺口超过了 140 万,就业人数却只有 10 多万,缺口高达了 93%。这里就有人会问了: 1、网络安全行业为什么这么缺人? 2、明明人才那么稀缺,为什么招聘时招安全的人员却没有那么多呢&am…

头部大模型公司进京赶考,向量数据库成为应考神器

日前,由品玩主办的「模型思辨」国内大模型产业生态研讨会在北京举办,Zilliz 与 360 集团、阿里巴巴、昆仑万维等来自大模型产业链的头部公司及投资机构参会,会上 Zilliz 创始人兼首席执行官星爵、360 集团创始人周鸿祎、昆仑万维创始人方汉等…

C++ 类设计的实践与理解

前言 C代码提供了足够的灵活性,因此对于大部分工程师来说都很难把握。本文介绍了写好C代码需要遵循的最佳实践方法,并在最后提供了一个工具可以帮助我们分析C代码的健壮度。 1. 尽可能尝试使用新的C标准 到2023年,C已经走过了40多个年头。新…

如何进行微服务测试?

微服务测试是一种特殊的测试类型,因为它涉及到多个独立的服务。以下是进行微服务测试的一般性步骤: 1. 确定系统架构 了解微服务架构对成功测试至关重要。确定每个微服务的职责、接口、依赖项和通信方式。了解这些信息可以帮助您更好地规划测试用例和测…

day09——线性回归

线性回归 一、什么是线性回归1,定义与公式2,线性回归的特征与目标的关系 二、线性回归的损失和优化原理1,损失函数2,优化算法 三、API四、实操:波士顿房价预测1,数据来源:scikit-learn2&#xf…

Acgis中实现栅格经纬度和行政区关联

写在前面 我是一个Acgis小白,写这篇博客是为了记录完成过程,如果有更高效的办法欢迎分享~ 我用的是Arcgis10.2。 需求描述 目前已有意大利的shp文件,希望将意大利划分成0.1*0.1经纬度的栅格,并且关联每个栅格中心点所属的省份信…

DBeaver复制数据库(数据库表结构以及内容)

一、 首先先建立一个数据库 (已有请忽略此步骤) (名字 字符集等按需要自己填写) 二、选择要复制的数据库 2.1右键选择 工具->转储数据库 2.2选择要导出的数据 2.3 选择要导出的路径 2.4 点击开始,等待导出完…

Revit中绘制弯曲的靠背栏杆和生成过梁

一、Revit中怎么绘制弯曲的靠背栏杆 栏杆通常我们见过位于在阳台处,但是在我们的古建筑中很常见到一种靠背栏杆,例如凉亭里面就很常见这种栏杆。那么如何绘制呢? 利用公制栏杆——支柱进行绘制 要运用放样工具进行绘制,设置一个工作平面&…

中国电子学会2023年05月份青少年软件编程Scratch图形化等级考试试卷四级真题(含答案)

2023-05 Scratch四级真题 分数:100 题数:24 测试时长:90min 一、单选题(共10题,共30分) 1. 下列积木运行后的结果是?(B)(说明:逗号后面无空格)&#xff…

mysql join 与 拆分成单表查询如何选择

参考以下文章,不错 数据库联表查询时,是直接使用join好还是分别查询到数据后自己处理较好? - 知乎 一,声明 1,数据量 首先场景是多个表数据量比较大,可能达到百万级 2,结论:最…

springboot项目启动指定对应环境的方法

1. 多环境准备 今天教大家一种多环境profile的写法,当然也可创建多个yml文件。如下所示: spring:application:name: cms-discovery-eureka-ha --- # 区分多环境 spring:profiles: peer1 server:port: 9092 eureka:in…

十、ELK安装ElastAlert 2插件飞书机器人告警(docker)

实现效果 1.创建相应挂载目录和文件 可任意位置,挂载对上就行,方便直接在宿主机修改配置。 /data/feishu-alert/config.yaml /data/feishu-alert/rules 2.编写config.yaml配置文件(/data/feishu-alert/config.yaml) #指定告警文件存放目录 rules_fo…

从C语言到C++_16(list的介绍和常用接口函数)

目录 1. list 介绍和简单使用 1.1 list介绍 1.2 list简单接口函数 1.3 push_back 和遍历 1.4 list常规接口函数使用 2. list 的其它接口函数 2.1 splice 接合 2.2 remove 删完一个值 2.3 sort和reverse 本章完。 list是个双向带头循环链表。 带头双向循环链表我们在…

21份软件测试全流程文档模板(标准版)

1、需求说明书 2、功能测试计划 3、功能测试用例 4、业务流程测试用例 5、系统安装配置说明书 6、阶段功能测试报告 7、性能测试计划 8、性能测试用例 9、性能测试报告 10、系统功能测试报告 11、需求变更说明书 12、用户建议说明书 13、验收测试报告 14、产品发布说明书 15、系…

redis下载安装

本文主要介绍如果在Centos7下安装Redis。 1.安装依赖 redis是由C语言开发&#xff0c;因此安装之前必须要确保服务器已经安装了gcc&#xff0c;可以通过如下命令查看机器是否安装&#xff1a; <span style"color:#000000"><span style"background-c…

Matlab论文插图绘制模板第101期—人口金字塔图

在之前的文章中&#xff0c;分享了Matlab双向柱状图的绘制模板&#xff1a; 进一步&#xff0c;再来分享一种特殊的双向柱状图&#xff1a;人口金字塔图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自…

Lecture 17 Machine Translation

目录 Statistical MTNeural MTAttention MechanismEvaluationConclusion Machine translation (MT) is the task of translating text from one source language to another target language why? Removes language barrierMakes information in any languages accessible t…

Polarion工作流插件(自定义)

创建插件命名插件配置插件Condition&Function package com.polarion.capital.example.conditions;import com.polarion.alm.tracker.model.IWorkItem; import com.polarion.alm.tracker.workflow.IArguments; import com.polarion.alm.tracker.workflow.ICallContext; impo…

TIME_WAIT的处理方式

TIME_WAIT 是什么 TIME_WAIT 是指在 TCP 连接关闭时&#xff0c;等待所有分组确认被接收的状态&#xff0c;这个状态会持续 2MSL&#xff08;Maximum Segment Lifetime&#xff09;的时间&#xff0c;以确保所有分组都被接收。在这段时间内&#xff0c;该连接不能被重用。MSL …

Jmeter 实现 grpc服务 压测

一、Jmeter安装与配置 网上有很多安装与配置文章&#xff0c;在此不做赘述 二、Jmeter gRPC Request 插件安装 插件下载地址&#xff1a;JMeter Plugins :: JMeter-Plugins.org 将下载文件解压后放到Jmeter安装目录下 /lib/ext 然后在终端输入Jmeter即可打开 Jmeter GUI界面…