docker——项目部署

news2025/1/9 14:27:01

什么是Docker?

Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可抑制的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器完全使用沙盒机制,相互之间不会存在任何接口。几乎没有性能开销,可以很容易的在机器和数据中心运行。最重要的是,他们不依赖于任何语言、框架或者包装系统。

Docker是dotCloud公司开源的一个基于LXC的高级容器引擎,源码托管在Github上,基于go语言并且遵从Apache2.0协议开源。

Docker 为提供了一整套的解决方案,不仅解决了容器化问题,而且解决了分发问题,很快被各大厂商选择变成了云基础设施,厂商围绕 Docker 也开始了生态建设。

什么是虚拟化、容器化?

物理机:实际的服务器或者计算机。相对于虚拟机而言的对实体计算机的称呼。物理机提供给虚拟机以硬件环境,有时也称为“寄主”或“宿主”。

虚拟化:是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。

容器化:容器化是一种虚拟化技术,又称操作系统层虚拟化(Operating system level virtualization),这种技术将操作系统内核虚拟化,可以允许用户空间软件实例 instances)被分割成几个独立的单元,在内核中行,而不是只有一个单一实例运行。这个软件实例,也被称为是一个容器(containers)。对每个实例的拥有者与用户来说,他们使用的服务器程序,看起来就像是自己专用的。容器技术是虚拟化的一种。docker 是现今容器技术的事实标准。

为什么需要虚拟化、容器化?

其实虚拟化和容器化最主要的目的就是为了资源隔离,随着资源隔离的实现也带来了更大的利益。

  • 容器对比虚拟机更轻量,启动更快
    传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
    这是因为docker不需要加载内核了,所以启动更快。
  • 资源利用率高
    将利用率较低的服务器进行整合,用更少的硬件资源运行更多的业务,降低IT支出和运维管理成本。
  • 环境标准化
    一次构建,随处执行。 实现执行环境的标准化发布,部署和运维。开发过程中一个常
    见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些
    bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,
    确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类
    问题。
    在这里插入图片描述

docker image

docker images [OPTIONS] [REPOSITORY[:TAG]] 

关键参数

  • -a:列出本地所有的镜像(含中间印象层、默认情况下过滤掉中间镜像层)
  • –digests:显示镜像的摘要信息
  • -f:显示满足条件的镜像
  • –format:指定返回值的模版文件
  • –no-trunc:显示完整的镜像信息
  • -q:显示出镜像ID

docker pull

  • 拉取出需要的镜像

什么是dockerfile?

dockerfile是一个文本文件,其中包含了一条条的指令,用于构建镜像。

FROM 指定镜像
指定基础镜像,并且Dockerfile中第一条指令必须是FROM指令,且在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令。
语法格式如下:
FROM <image> 
FROM <image>:<tag> 

RUN 运行指定的命令
RUN <command> 

CMD 容器启动时要运行的命令
CMD command param1 param2

ENTRYPOINT-为容器指定默认运行程序
ENTRYPOINT command param1 param2

docker compose

什么是docker compose?
docker-compose是Docker官方的开源项目,使用python编写,实现上调用了Docker服务的API进行容器管理和编排,其官方定义和运行多个docker容器的应用。

dockere-compose有2个很重要的概念:

  • 服务:一个应用的服务,实际上可以包含若干运行相同镜像的实例
  • 项目:由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml中定义,整个docker-compose.yml定义一个项目。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

在这里插入图片描述

有了上面最基本的认识后,我来介绍一下我的项目及如何进行项目部署。
在我的项目中,有7个业务子服务

  • 入口网关子服务
  • 用户管理子服务
  • 好友管理子服务
  • 消息转发子服务
  • 消息存储子服务
  • 文件管理子服务
  • 语言转化子服务

每一个子服务都需要打包成一个镜像,要知道每个服务都需要链接很多库,这时候有2种方式

  • 手动将库一一拷贝到指定目录下
  • 用shell脚本来拷贝到指定目录下(我采取的方式)

下列是文件子服务需要链接的库:
在这里插入图片描述
这里我用wak命令将连接的库给提取了出来

ldd file_server | awk '{if (match($3,"/")){print $3}}'

在这里插入图片描述

然后我们需要将库给拷贝到指定的路径下

#!/bin/bash


#传递两个参数:
# 1. 可执行程序的路径名
# 2. 目录名称 --- 将这个程序的依赖库拷贝到指定目录下
declare depends
get_depends() {
    depends=$(ldd $1 | awk '{if (match($3,"/")){print $3}}')
    mkdir $2
    cp -Lr $depends $2
}

get_depends ./gateway/build/gateway_server ./gateway/depends
get_depends ./file/build/file_server ./file/depends
get_depends ./friend/build/friend_server ./friend/depends
get_depends ./message/build/message_server ./message/depends
get_depends ./speech/build/speech_server ./speech/depends
get_depends ./transmite/build/transmite_server ./transmite/depends
get_depends ./user/build/user_server ./user/depends

cp /bin/nc ./gateway/
cp /bin/nc ./file/
cp /bin/nc ./friend/
cp /bin/nc ./message/
cp /bin/nc ./speech/
cp /bin/nc ./transmite/
cp /bin/nc ./user/
get_depends /bin/nc ./gateway/depends
get_depends /bin/nc ./file/depends
get_depends /bin/nc ./friend/depends
get_depends /bin/nc ./message/depends
get_depends /bin/nc ./speech/depends
get_depends /bin/nc ./user/depends
get_depends /bin/nc ./transmite/depends

其中nc命令可以作为客户端发起TCP和UDP连接,用于测试主机端口是否开放,还可以用来监听端口等。 这里不详细解释了

此时我们就完成了依赖库的指定,我们就可以来创建dockerfile了。
这里我是ubuntu22.04版本
在这里插入图片描述

# 声明基础镜像来源
FROM ubuntu:22.04
# 声明工作路径
WORKDIR /im
RUN mkdir -p /im/logs &&\
    mkdir -p /im/data &&\
    mkdir -p /im/conf &&\
    mkdir -p /im/bin
# 将可执行程序文件,拷贝进入镜像
COPY ./build/gateway_server /im/bin/
# 将可执行程序依赖,拷贝进入镜像
COPY ./depends/ /lib/x86_64-linux-gnu/

COPY ./nc /bin/
# 设置容器的启动默认操作 --- 运行程序
CMD /im/bin/gateway_server -flagfile=/im/conf/gateway_server.conf

但是,有7个子服务,如果一个一个创建容器,还是太麻烦了,所以有了docker-compose来编排容器。 当我们写完docker-compose后,只需要使用docker-compose up就可以将容器创建出来。

version: "3.8"

services:
  etcd:
    image: quay.io/coreos/etcd:v3.3.25
    container_name: etcd-service
    environment:
      - ETCD_NAME=etcd-s1
      - ETCD_DATA_DIR=/var/lib/etcd
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://0.0.0.0:2379
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      - ./middle/data/etcd:/var/lib/etcd:rw
    ports:
      - 2379:2379
    restart: always
  mysql:
    image: mysql:8.0.39
    container_name: mysql-service
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      - ./sql:/docker-entrypoint-initdb.d/:rw
      - ./middle/data/mysql:/var/lib/mysql:rw
    ports:
      - 3306:3306
    restart: always
  redis:
    image: redis:6.0.16
    container_name: redis-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      - ./middle/data/redis:/var/lib/redis:rw
    ports:
      - 6379:6379
    restart: always
  elasticsearch:
    image: elasticsearch:7.17.21
    container_name: elasticsearch-service
    environment:
      - "discovery.type=single-node"
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      - ./middle/data/elasticsearch:/data:rw
    ports:
      - 9200:9200
      - 9300:9300
    restart: always
  rabbitmq:
    image: rabbitmq:3.9.13
    container_name: rabbitmq-service
    environment:
      RABBITMQ_DEFAULT_USER: root
      RABBITMQ_DEFAULT_PASS: 123456
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      - ./middle/data/rabbitmq:/var/lib/rabbitmq:rw
    ports:
      - 5672:5672
    restart: always

  file_server:
    build: ./file
    #image: server-user_server
    container_name: file_server-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      # 挂载的信息: entrypoint.sh文件 数据目录(im/logs, im/data), 配置文件
      - ./conf/file_server.conf:/im/conf/file_server.conf
      - ./middle/data/logs:/im/logs:rw
      - ./middle/data/data:/im/data:rw
      - ./entrypoint.sh:/im/bin/entrypoint.sh
    ports:
      - 10002:10002
    restart: always
    entrypoint:
      # 跟dockerfile中的cmd比较类似,都是容器启动后的默认操作--替代dockerfile中的cmd
      /im/bin/entrypoint.sh -h 172.20.253.66 -p 2379 -c "/im/bin/file_server -flagfile=/im/conf/file_server.conf"
    depends_on:
      - etcd
  friend_server:
    build: ./friend
    #image: file-server:v1
    container_name: friend_server-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      # 挂载的信息: entrypoint.sh文件 数据目录(im/logs, im/data), 配置文件
      - ./conf/friend_server.conf:/im/conf/friend_server.conf
      - ./middle/data/logs:/im/logs:rw
      - ./middle/data/data:/im/data:rw
      - ./entrypoint.sh:/im/bin/entrypoint.sh
    ports:
      - 10006:10006
    restart: always
    depends_on:
      - etcd
      - mysql
      - elasticsearch
    entrypoint:
      # 跟dockerfile中的cmd比较类似,都是容器启动后的默认操作--替代dockerfile中的cmd
      /im/bin/entrypoint.sh -h 172.20.253.66 -p 2379,3306,9200 -c "/im/bin/friend_server -flagfile=/im/conf/friend_server.conf"
  gateway_server:
    build: ./gateway
    #image: file-server:v1
    container_name: gateway_server-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      # 挂载的信息: entrypoint.sh文件 数据目录(im/logs, im/data), 配置文件
      - ./conf/gateway_server.conf:/im/conf/gateway_server.conf
      - ./middle/data/logs:/im/logs:rw
      - ./middle/data/data:/im/data:rw
      - ./entrypoint.sh:/im/bin/entrypoint.sh
    ports:
      - 9000:9000
      - 9001:9001
    restart: always
    depends_on:
      - etcd
      - redis
    entrypoint:
      # 跟dockerfile中的cmd比较类似,都是容器启动后的默认操作--替代dockerfile中的cmd
      /im/bin/entrypoint.sh -h 172.20.253.66 -p 2379,6379 -c "/im/bin/gateway_server -flagfile=/im/conf/gateway_server.conf"
  message_server:
    build: ./message
    #image: file-server:v1
    container_name: message_server-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      # 挂载的信息: entrypoint.sh文件 数据目录(im/logs, im/data), 配置文件
      - ./conf/message_server.conf:/im/conf/message_server.conf
      - ./middle/data/logs:/im/logs:rw
      - ./middle/data/data:/im/data:rw
      - ./entrypoint.sh:/im/bin/entrypoint.sh
    ports:
      - 10005:10005
    restart: always
    depends_on:
      - etcd
      - mysql
      - elasticsearch
      - rabbitmq
    entrypoint:
      # 跟dockerfile中的cmd比较类似,都是容器启动后的默认操作--替代dockerfile中的cmd
      /im/bin/entrypoint.sh -h 172.20.253.66 -p 2379,3306,9200,5672 -c "/im/bin/message_server -flagfile=/im/conf/message_server.conf"
  speech_server:
    build: ./speech
    #image: file-server:v1
    container_name: speech_server-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      # 挂载的信息: entrypoint.sh文件 数据目录(im/logs, im/data), 配置文件
      - ./conf/speech_server.conf:/im/conf/speech_server.conf
      - ./middle/data/logs:/im/logs:rw
      - ./middle/data/data:/im/data:rw
      - ./entrypoint.sh:/im/bin/entrypoint.sh
    ports:
      - 10001:10001
    restart: always
    depends_on:
      - etcd
    entrypoint:
      # 跟dockerfile中的cmd比较类似,都是容器启动后的默认操作--替代dockerfile中的cmd
      /im/bin/entrypoint.sh -h 172.20.253.66 -p 2379 -c "/im/bin/speech_server -flagfile=/im/conf/speech_server.conf"
  transmite_server:
    build: ./transmite
    #image: file-server:v1
    container_name: transmite_server-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      # 挂载的信息: entrypoint.sh文件 数据目录(im/logs, im/data), 配置文件
      - ./conf/transmite_server.conf:/im/conf/transmite_server.conf
      - ./middle/data/logs:/im/logs:rw
      - ./middle/data/data:/im/data:rw
      - ./entrypoint.sh:/im/bin/entrypoint.sh
    ports:
      - 10004:10004
    restart: always
    depends_on:
      - etcd
      - mysql
      - rabbitmq
    entrypoint:
      # 跟dockerfile中的cmd比较类似,都是容器启动后的默认操作--替代dockerfile中的cmd
      /im/bin/entrypoint.sh -h 172.20.253.66 -p 2379,3306,5672 -c "/im/bin/transmite_server -flagfile=/im/conf/transmite_server.conf"
  user_server:
    build: ./user
    #image: file-server:v1
    container_name: user_server-service
    volumes:
      # 1. 希望容器内的程序能够访问宿主机上的文件
      # 2. 希望容器内程序运行所产生的数据文件能落在宿主机上
      # 挂载的信息: entrypoint.sh文件 数据目录(im/logs, im/data), 配置文件
      - ./conf/user_server.conf:/im/conf/user_server.conf
      - ./middle/data/logs:/im/logs:rw
      - ./middle/data/data:/im/data:rw
      - ./entrypoint.sh:/im/bin/entrypoint.sh
    ports:
      - 10003:10003
    restart: always
    depends_on:
      - etcd
      - mysql
      - redis
      - elasticsearch
    entrypoint:
      # 跟dockerfile中的cmd比较类似,都是容器启动后的默认操作--替代dockerfile中的cmd
      /im/bin/entrypoint.sh -h 172.20.253.66 -p 2379,3306,5672,9200 -c "/im/bin/user_server -flagfile=/im/conf/user_server.conf"

现在我已经通过docker pull将需要用到的中间件镜像给拉取了下来。
在这里插入图片描述
此时进行docker-compose up -d 将容器启动起来。
在这里插入图片描述
在这里插入图片描述

此时我们所有的子服务都打包成了一个镜像,并且已经启动(通过docker container ls -a可以查看)。
在这里插入图片描述
在这里插入图片描述

此时所有子服务就在docker中启动起来了,就可以直接来提供服务,不需要自己来解决库依赖问题以及Linux版本问题。

最后我们只需要将运行程序和其依赖的库打包,就可以在任何服务器上运行。只需要简单的拉取和运行,这就是为什么docker风靡全球的原因。

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

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

相关文章

LabVIEW-TestExec SL

文章目录 新建LabVIEW .llb库链接vi至TestExec SLTestPlan调用调用自定义动作创建变量配置动作参数 注意事项 新建LabVIEW .llb库 创建一个文件夹用来存放文件。在此文件夹下创建两个文件夹&#xff0c;分别命名为Actions和Bin。其中&#xff0c;Actions用于存放动作&#xff…

数据结构--数组

一.线性和非线性 线性&#xff1a;除首尾外只有一个唯一的前驱和后继。eg&#xff1a;数组&#xff0c;链表等。 非线性&#xff1a;不是线性的就是非线性。 二.数组是什么&#xff1f; 数组是一个固定长度的存储相同数据类型的数据结构&#xff0c;数组中的元素被存储在一…

NFS-Ganesha 核心架构解读

NFSv4 简要概述 NFS 这个协议( NFSv2 )最初由 Sun Microsystems 在 1984 年设计提出&#xff0c;由于存在一些不足&#xff0c;因此在随后由几家公司联合推出了 NFSv3。到了 NFSv4 时&#xff0c;开发完全由 IETF 主导&#xff0c;设计目标是&#xff1a; 提高互联下的 NFS 访…

Simulink对仿真数据进行FFT频谱分析

1 问题引入 在仿真阶段&#xff0c;经常会遇到有些仿真结果的数据需要进行频谱分析&#xff0c;如何快速便捷地操作&#xff0c;这里介绍其中一种简单的方法。主要利用 Simulink 中 Scope 显示的数据进行保存并进行 FFT 频谱分析&#xff0c;按下文操作即可。 2 实战 2.1 将…

Python实现贪吃蛇 经典解压小游戏!附源码

大家应该都玩过诺基亚上面的贪吃蛇吧&#xff0c;那是一段美好的童年回忆&#xff0c;本文将带你一步步用python语言实现一个snake小游戏&#xff01; 基础环境必备 版本&#xff1a;Python3 ●系统&#xff1a;Windows ●相关模块&#xff1a;pygame pip install pygame安…

Taro React-Native IOS 打包发布

http网络请求不到 配置 fix react-native facebook::flipper::SocketCertificateProvider‘ (aka ‘int‘) is not a function or func_rn运行debug提示flipper-CSDN博客 Xcode 15&#xff08;iOS17&#xff09;编译适配报错_no template named function in namespace std-CS…

Chrome使用IE内核

Chrome使用IE内核 1.下载扩展程序IE Tab 2.将下载好的IE Tab扩展程序拖拽到扩展程序界面&#xff0c;之后重启chrome浏览器即可

C++基础:Pimpl设计模式的实现

2024/11/14: 在实现C17的Any类时偶然接触到了嵌套类的实现方法以及Pimpl设计模式&#xff0c;遂记录。 PIMPL &#xff08; Private Implementation 或 Pointer to Implementation &#xff09;是通过一个私有的成员指针&#xff0c;将指针所指向的类的内部实现数据进行隐藏。 …

深入理解AIGC背后的核心算法:GAN、Transformer与Diffusion Models

深入理解AIGC背后的核心算法&#xff1a;GAN、Transformer与Diffusion Models 前言 随着人工智能技术的发展&#xff0c;AIGC&#xff08;AI Generated Content&#xff0c;人工智能生成内容&#xff09;已经不再是科幻电影中的幻想&#xff0c;而成为了现实生活中的一种新兴力…

LeetCode面试经典150题C++实现,更新中

用C实现下面网址的题目 https://leetcode.cn/problems/merge-sorted-array/?envTypestudy-plan-v2&envIdtop-interview-150 1、数组\字符串 88合并两个有序数组 以下是使用 C 实现合并两个有序数组的代码及测试用例 C代码实现 #include <iostream> #include &l…

python怎么安装numpy

1、在python官网https://pypi.python.org/pypi/numpy中找到安装的python版本对应的numpy版本。 例如&#xff1a; python版本是&#xff1a; 下载的对应numpy版本是&#xff1a; 2、将numpy下载到python的安装目录下的scripts文件夹中&#xff1b; 3、然后在cmd中执行以下命…

js中typeOf无法区分数组对象

[TOC]&#xff08;js中typeOf无法区分数组对象) 前提&#xff1a;很多时候我们在JS中用typeOf来判断值类型&#xff0c;如&#xff1a;typeOf ‘abc’//string ,typeOf 123 //number; 但当判断对象为数组时返回的仍是’object’ 这时候我们可以使用Object.prototype.toString.c…

JavaScript方法修改 input type=file 样式

html中的<input type "file">的样式很难修改&#xff0c;又跟页面风格很不匹配。我就尝试了几种方法&#xff0c;但是不管是用label还是用opacity:0都很麻烦&#xff0c;还老是出问题&#xff0c;所以最后还是用JavaScript来解决。 下面附上代码&#xff1a;…

JS爬虫实战之TikTok_Shop验证码

TikTok_Shop验证码逆向 逆向前准备思路1- 确认接口2- 参数确认3- 获取轨迹参数4- 构建请求5- 结果展示 结语 逆向前准备 首先我们得有TK Shop账号&#xff0c;否则是无法抓取到数据的。拥有账号后&#xff0c;我们直接进入登录。 TikTok Shop 登录页面 思路 逆向步骤一般分为…

MDBook 使用指南

MDBook 是一个灵感来自 Gitbook 的强大工具&#xff0c;专门用于创建电子书和文档。它能够将 Markdown 编写的内容编译成静态网站&#xff0c;非常适合项目文档、教程和书籍的发布。 个人实践过许多文档方案&#xff0c;如 hexo、hugo、WordPress、docsify 和 mdbook 等&#…

力扣 LeetCode 28. 找出字符串中第一个匹配项的下标(Day4:字符串)

解题思路&#xff1a; KMP算法 需要先求得最长相等前后缀&#xff0c;并记录在next数组中&#xff0c;也就是前缀表&#xff0c;前缀表是用来回退的&#xff0c;它记录了模式串与主串(文本串)不匹配的时候&#xff0c;模式串应该从哪里开始重新匹配。 next[ j - 1 ] 记录了 …

海思3403对RTSP进行目标检测

1.概述 主要功能是调过live555 testRTSPClient 简单封装的rtsp客户端库&#xff0c;拉取RTSP流&#xff0c;然后调过3403的VDEC模块进行解码&#xff0c;送个NPU进行目标检测&#xff0c;输出到hdmi&#xff0c;这样保证了开发没有sensor的时候可以识别其它摄像头的视频流&…

Python学习26天

集合 # 定义集合 num {1, 2, 3, 4, 5} print(f"num&#xff1a;{num}\nnum数据类型为&#xff1a;{type(num)}") # 求集合中元素个数 print(f"num中元素个数为&#xff1a;{len(num)}") # 增加集合中的元素 num.add(6) print(num) # {1,2,3,4,5,6} # 删除…

图论-代码随想录刷题记录[JAVA]

文章目录 前言深度优先搜索理论基础所有可达路径岛屿数量岛屿最大面积孤岛的总面积沉默孤岛Floyd 算法dijkstra&#xff08;朴素版&#xff09;最小生成树之primkruskal算法 前言 新手小白记录第一次刷代码随想录 1.自用 抽取精简的解题思路 方便复盘 2.代码尽量多加注释 3.记录…

测试自动化如何和业务流程结合?

测试自动化框架固然重要&#xff0c;但是最终自动化的目的都是为了业务服务的。 那测试自动化如何对业务流程产生积极影响&#xff1f; 业务流程的重要性 测试自动化项目并非孤立存在&#xff0c;其生命周期与被测试的应用程序紧密相关。项目的价值在于被整个开发团队所使用&a…