docker集群的详解以及超详细搭建
文章目录
- 一、问题引入
- 1. 多容器位于同一主机
- 2. 多容器位于不同主机
- 二、介绍
- 三、特性
- 四、概念
- 1. 节点nodes
- 2. 服务(service)和任务(task)
- 3. 负载均衡
- 五、docker网络
- 1. overlay网络
- 六、docker集群搭建
- 1. 环境介绍
- 2. 创建集群
- 3. 集群网络
- 4. 加入工作节点
- 七、部署可视化界面portainer
- 1. 部署单机模式
- 2. 部署集群模式
- 八、部署一个容器集群
- 1. 拉取镜像
- 2. 创建网络
- 3. 创建服务
- 4. 进入portainer查看busybox集群
- 5. 不同节点间容器的通信
- 6. 集群扩展
一、问题引入
在我们日常学习或开发过程中,如果我们的服务均采用docker容器的方式运行,比如提供后端接口服务的容器containerA
和提供数据存取服务的容器containerB
,如下图所示,不同的docker容器拥有各自的ip地址和端口号。
1. 多容器位于同一主机
本文假定一台主机只有一个docker进程。在这种情况下,容器AcontainerA
和容器BcontainerB
被同一个docker进程管理,容器之间的通信就可以通过目标容器ip+port进行直接访问,如下图所示
当容器AcontainerA
需要和容器BcontainerB
进行通信时,只需要在容器AcontainerA
中通过172.18.0.2:3306
即可完成通信。这种通信方式为同主机容器到容器的通信。
这种方式有个较明显的缺点就是将容器限制在一台主机了。如果要求将容器分布在不同的主机,那这个方法就行不通了。
下面来看看将容器分布在不同的主机如何操作。
2. 多容器位于不同主机
但是在企业级项目部署中往往存在多个主机协同提供服务的情况。例如,我们的后端接口服务容器containerA
位于主机AhostA
中,数据存储容器containerB
位于主机BhostB
中,在这种情况下,我们为了方便省事,往往会将数据存储容器containerB
的端口号(比如mysql的3306
)映射到主机BhostB
的3306
端口,当位于主机AhostA
的后端接口服务容器containerA
需要对数据进行操作时,通过主机A的ip:port
对其数据存储容器containerB
进行访问。如下图所示
在该示意图中,容器A要想与容器B通信,需要容器B将端口映射到宿主机hostB
中,当连接主机B的3306
端口时,根据映射规则,将访问请求转发到容器B中。这种通信方式为跨主机容器到主机再到容器的通信。
这种方式虽然做到了将容器分布在不同的主机,但是仍暴露出一个缺点,目标容器的端口不得不挂载到宿主机对应端口,且目标容器宿主机的端口也不得不对外开放,万一该端口被不法分子扫描到进行攻击,那就GG了。
针对以上两个方式所暴露出的缺点,当我们既希望将容器分布在不同的主机,又希望不暴露宿主机端口而是直接通过容器的ip:port
进行通信,docker官方推荐我们考虑一下集群环境。
二、介绍
Swam是Docker引擎内置(原生)的集群管理和编排工具。Docker Swarm是Docker官方三剑客项目之一,提供 Docker容器集群服务,是Docker官方对容器云生态进行支持的核心方案。使用它,用户可以将多个Docker主机封装为单个大型的虚拟Docker主机,快速打造一套容器云平台。Swarm mode内置kv存储功能,提供了众多的新特性,比如:具有容错能力的去中心化设计、内置服务发现、负载均衡、路由网格、动态伸缩、滚动更新、安全传输等。使得Docker原生的 Swam集群具备与Mesos ,Kubernetes竞争的实力。
一个集群由多个Docker主机组成,这些主机以集群模式运行,充当管理者(管理成员资格和委托)和工作者(运行群服务)。一个给定的Docker主机可以是一个管理者
manager
、一个工作者worker
,或者同时扮演这两个角色。创建服务时,您需要定义其最佳状态(副本数量、可用的网络和存储资源、服务对外开放的端口等)。Docker致力于保持这种理想状态。例如,如果一个工作节点变得不可用,Docker会将该节点的任务调度到其他节点上。任务是一个运行的容器,它是群服务的一部分,由群管理器管理,而不是一个独立的容器。
与独立容器相比,swarm服务的一个关键优势是,您可以修改服务的配置,包括它所连接的网络和卷,而无需手动重启服务。Docker将更新配置,停止使用过期配置的服务任务,并创建与所需配置匹配的新任务。
当Docker在swarm模式下运行时,您仍然可以在任何参与集群的Docker主机上运行独立的容器和swarm服务。独立容器和集群服务之间的一个关键区别是只有集群管理器可以管理集群,而独立容器可以在任何守护进程上启动。Docker守护进程可以作为管理人员、工作人员或两者参与到一个群体中。
三、特性
docker集群模式swarm mode
为我们提供了非常丰富的特性来满足不同的场景需求。
-
与Docker引擎集成的集群管理
使用Docker Engine CLI创建一组Docker引擎,可以在其中部署应用程序服务。不需要额外的编排软件来创建或管理一个群体。这不就是打算和
k8s
杠一杠呢? -
去中心化设计
Docker引擎在运行时处理任何专门化,而不是在部署时处理节点角色之间的差异。我们可以使用Docker引擎部署两种类型的节点,管理器和工作器。这意味着我们可以从单个磁盘映像构建整个swarm。
-
声明式服务模型
Docker引擎使用一种声明性的方法,让我们自定义应用程序堆栈中各种服务的期望状态。例如,我们可能会描述一个由带有消息队列服务的web前端服务和数据库后端组成的应用程序。
-
动态伸缩
对于每个服务,我们可以声明想要运行的任务数量。当扩大或缩小规模时,swarm manager会通过添加或删除任务来自动适应,以保持所需的状态。swarm manager节点持续监控集群状态,并协调实际状态和期望状态之间的任何差异。例如,如果我们设置一个服务来运行一个容器的10个副本,并且托管其中两个副本的工作机崩溃,管理器将创建两个新副本来替换崩溃的副本。群组管理器将新的副本分配给正在运行且可用的worker。
-
多主机网络
我们可以为服务指定叠加网络。当初始化或更新应用程序时,群管理器自动分配地址给覆盖网络上的容器。
-
服务发现
集群管理器节点为集群中的每个服务分配一个唯一的DNS名称和负载平衡运行容器。可以通过嵌入在swarm中的DNS服务器查询swarm中运行的每一个容器。
-
负载均衡
可以向外部负载平衡器公开服务端口。在内部,swarm允许我们指定如何在节点之间分发服务容器。
-
安全传输
群中的每个节点强制执行TLS相互认证和加密,以确保自身和所有其他节点之间的通信安全。我们可以选择使用自签名根证书或来自自定义根CA的证书。
-
滚动更新
在部署时,我们可以增量地将服务更新应用到节点。swarm manager允许您控制不同节点集的服务部署之间的延迟。如果出现任何问题,可以回滚到服务的前一个版本。
四、概念
在搭建docker集群之前,我们需要了解几个概念:节点(node)、服务(service)、任务(task)、负载均衡(loadbalance)。
1. 节点nodes
每个节点node都是docker集群中的每一个docker实例,当然也可以理解为运行docker进程的物理机。在集群中的所有节点中,又分为管理节点和工作节点。
-
管理节点
管理节点用于对docker集群的管理,对集群的操作命令都需要在管理节点中执行(例外:工作节点退出集群时需要在工作节点中执行退出命令),一个docker集群可以具有多个管理节点,在众多管理节点中通过
raft协议
选举出唯一一个leader节点。 -
工作节点
工作节点接收并执行来自管理节点分发的任务(task),默认地,管理节点也可以同时具有工作节点的功能。
2. 服务(service)和任务(task)
服务是对任务的定义,而任务执行于管理节点或工作节点。服务是docker集群的中心结构,也是用户与swarm交互的主要介质。
-
服务
docker集群中的服务类似于微服务系统中的服务,一个服务是一个或多个实例的集合。而在docker集群中,一个服务我们可以理解为多个提供相同服务的docker容器的集合。
在创建一个服务时,我们可以指定该服务使用的docker镜像,以及该服务能够创建的docker实例的副本数量。
如在一个docker集群中,主机A中有两个容器:mysqlA和redisA,主机B中有两个容器:mysqlB和redisB,那么主机A中的mysqlA和主机B中的mysqlB属于同一个服务,主机A中的redisA和主机B中的redisB属于同一个服务,并且由管理节点实现对服务的管理(如同微服务系统中的注册中心),如下图所示
-
任务
任务就是当我们需要调用集群中某一个服务时,管理节点从其管理的服务集合中找到该服务所对应的docker容器实例,然后向该实例指派一个任务,使其提供相应的服务。一旦任务被分配到某一个节点,则不允许再对其进行修改。
3. 负载均衡
当我们需要调用某一个服务时,管理节点自动对该服务所对应的节点进行负载均衡调用。例如微服务系统中服务注册中心的负载均衡机制。
五、docker网络
介绍完docker集群的概念,我们需要考虑一下在docker集群中,由于是多主机架构,那么什么样的网络驱动能使跨主机的容器相互通信呢?docker给我们提供的网络驱动有:bridge
、host
、overlay
、none
、ipvlan
、macvlan
。
-
bridge
默认的网络驱动。适用于同一主机中docker容器之间的通信。
-
host
移除docker容器与宿主机之间的网络隔离,直接使用宿主机的网络。
-
overlay
该网络驱动允许多个主机之间的docker容器相互通信。
-
none
脱机独立运行docker容器,无法与其他容器以及主机之间通信。
-
ipvlan
把对ipv4和ipv6的ip地址的控制权完全交给我们。
-
macvlan
允许我们对docker容器分配物理地址,使docker容器具有物理机表现。
在docker集群中我们使用overlay
网络实现多主机内容器之间的相互通信。
1. overlay网络
overlay网络驱动在多个Docker主机之间创建分布式网络。这个网络位于(覆盖)特定于主机的网络之上,允许连接到它的容器(包括集群服务容器)在启用加密(TLS)时安全地通信。Docker透明地处理往返于正确的Docker守护进程主机和正确的目的地容器的每个分组的路由。
六、docker集群搭建
1. 环境介绍
-
两台linux虚拟机
操作系统 主机名 主机ip docker版本 CentOS7 host10(管理节点) 192.168.10.10 v24.0.7 CentOS7 host20(工作节点) 192.168.10.20 v24.0.7 CentOS7 host30(工作节点) 192.168.10.30 v24.0.7 docker版本必须大于v1.12.0,docker的集群模式是从该版本开始的,该版本发行于2016.07.28,现在都已经2023年了,我们直接安装最新版,还能避免许多bug。
-
端口开放(或关闭防火墙)
2377/tcp:用于集群管理通信。
7946/tcp、7946/udp:集群中各节点之间的通信。
4789/udp:
overlay
网络使用。开放端口的命令如下
# --permanent表示永久生效 [root@host10 ~] firewall-cmd --zone=public --add-port=2377/tcp --permanent success [root@host10 ~] firewall-cmd --zone=public --add-port=7946/tcp --permanent success [root@host10 ~] firewall-cmd --zone=public --add-port=7946/udp --permanent success [root@host10 ~] firewall-cmd --zone=public --add-port=4789/udp --permanent success # 重新加载防火墙配置 [root@host10 ~] firewall-cmd --reload success
查看端口是否开放成功
# 查看已开放的端口列表 [root@host10 ~] firewall-cmd --zone=public --list-ports 2377/tcp 7946/tcp 7946/udp 4789/udp
关闭防火墙
# 关闭防火墙 [root@host10 ~] systemctl stop firewalld # 开机禁用防火墙 [root@host10 ~] systemctl disable firewalld
2. 创建集群
在管理节点host10创建集群,使用以下命令
[root@host10 ~] docker swarm init --advertise-addr 192.168.10.10
# 输出
Swarm initialized: current node (0cibl244fqcmh7k6x8a3kwkfp) is now a manager.To add a worker to this swarm, run the following command:docker swarm join --token SWMTKN-1-0glmg3n472i4bbpxrynjw0z0uoa7lnxagcfcgnwg40dd3mu4ga-eazqx6idqvn954nfpumn2vob0 192.168.10.10:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
--advertise-addr
用于配置一个ip地址,集群中其他节点使用此ip地址与管理节点实现通信。
创建集群的节点默认为管理节点。
另外,在输出中包含以下命令,用于其他工作节点加入该集群
docker swarm join --token SWMTKN-1-0glmg3n472i4bbpxrynjw0z0uoa7lnxagcfcgnwg40dd3mu4ga-eazqx6idqvn954nfpumn2vob0 192.168.10.10:2377
如果需要加入管理节点,则使用下面命令
docker swarm join-token manager --token SWMTKN-1-0glmg3n472i4bbpxrynjw0z0uoa7lnxagcfcgnwg40dd3mu4ga-eazqx6idqvn954nfpumn2vob0 192.168.10.10:2377
注意:该token有效期为24小时。如果该token已过期,则可以使用下面命令重新获取
[root@host10 ~] docker swarm join-token workerTo add a worker to this swarm, run the following command:docker swarm join --token SWMTKN-1-0glmg3n472i4bbpxrynjw0z0uoa7lnxagcfcgnwg40dd3mu4ga-eazqx6idqvn954nfpumn2vob0 192.168.10.10:2377
使用docker info
查看当前集群的详细信息
[root@host10 ~] docker infoClient: Docker Engine - CommunityVersion: 24.0.7Context: defaultDebug Mode: falsePlugins:buildx: Docker Buildx (Docker Inc.)Version: v0.11.2Path: /usr/libexec/docker/cli-plugins/docker-buildxcompose: Docker Compose (Docker Inc.)Version: v2.21.0Path: /usr/libexec/docker/cli-plugins/docker-composeServer:Containers: 0Running: 0Paused: 0Stopped: 0Images: 4Server Version: 24.0.7Storage Driver: overlay2......Swarm: activeNodeID: 0cibl244fqcmh7k6x8a3kwkfp......Raft:......Dispatcher:Heartbeat Period: 5 seconds......
很长很长
使用docker node ls
查看当前集群中的各个节点信息
[root@host10 ~] docker node lsID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
0cibl244fqcmh7k6x8a3kwkfp * host10 Ready Active Leader 24.0.7
其中,*
表示当前位于此节点中。
3. 集群网络
当我们在管理节点使用docker swarm init
初始化一个docker集群时,docker默认会创建两个网络:
overlay
驱动的网络,名称为ingress
,该网络用于处理集群中各个服务之间的控制与数据传输。当我们创建服务service
时,如果没有指定自定义的overlay
网络,则默认使用ingress
网络。bridge
驱动的网络,名称为docker_gwbridge
,该网络用于维持集群中各个节点之间的连接。
[root@host10 docker-scripts]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2d3e81dc418a bridge bridge local
5675307b8b8d docker_gwbridge bridge local
496c4eb3bb51 host host local
j4lsm97dkovz ingress overlay swarm
69df9100d962 myBridge bridge local
e72b30a2ea15 none null local
4. 加入工作节点
我们把host20和host30作为工作节点,加入到该集群。复制上面的命令,分别到到host20和host30两台主机中中执行
[root@host20 ~] docker swarm join --token SWMTKN-1-0glmg3n472i4bbpxrynjw0z0uoa7lnxagcfcgnwg40dd3mu4ga-eazqx6idqvn954nfpumn2vob0 192.168.10.10:2377This node joined a swarm as a worker.[root@host30 ~] docker swarm join --token SWMTKN-1-0glmg3n472i4bbpxrynjw0z0uoa7lnxagcfcgnwg40dd3mu4ga-eazqx6idqvn954nfpumn2vob0 192.168.10.10:2377This node joined a swarm as a worker.
恭喜,工作节点已加入到集群。
此时如果我们在host20节点中使用docker node ls
查看当前集群中的各个节点信息,则会出现下面信息
[root@host20 ~] docker node lsError response from daemon: This node is not a swarm manager. Worker nodes can not be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.
说明该命令只允许在管理节点中使用。我们在host10(管理节点)中再次执行此命令
[root@host10 docker-scripts] docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
0cibl244fqcmh7k6x8a3kwkfp * host10 Ready Active Leader 24.0.7
wfw312mxlolm6e8xgdwp6kndy host20 Ready Active 24.0.7
rctru4fdjrv6y7gsh6i3ek2lp host30 Ready Active 24.0.7
七、部署可视化界面portainer
现在集群已经搭建好了,下面我们使用portainer实现docker的可视化界面。
1. 部署单机模式
我们可以将portainer部署在docker集群的管理节点中,此时,portainer可以通过管理节点的docker进程实现对docker集群的可视化。
-
在管理节点拉取portainer的镜像
docker pull portainer/portainer-ce:latest
-
将portainer镜像运行为容器
docker run \-p 8000:8000 \-p 9443:9443 \-v /var/run/docker.sock:/var/run/docker.sock \-v portainer_data:/data \--name my-portainer \-d \--privileged=true \--restart=always \portainer/portainer-ce:latest
--privileged=true
用于赋予该容器root权限。 -
在浏览器访问
https://192.168.10.10:9443
,进入portainer创建页面。 -
创建用户以后,进入添加环境页面。有些朋友在这个页面没有
Get Started
选项,只有Add Environments
选项。 -
点击
Add Environments
选项,添加一个docker环境。我们选择
Standalone
单机模式的docker环境,点击下方按钮对该环境配置。 -
配置环境。
配置环境的方式有多种,通过
Agent
、API
、Socket
、Edge Agent Standard
四种方式。我们以Socket
方式为例,将该环境命名为host10-standard
。注意,该方式要求我们在运行portainer容器时添加挂载卷:
-v /var/run/docker.sock:/var/run/docker.sock
-
环境配置完成后,点击portainer首页,就可以在环境列表中看到我们刚才添加的环境
host1-standalone
了。 -
点击该环境,查看其详细信息
-
点击
Go to cluster visualizer
查看docker集群
2. 部署集群模式
portainer提供了以集群方式运行的能力,既然我们已经搭建好了具有三个节点的docker集群,那么我们尝试一下portainer的集群部署。
-
在管理节点下载部署文件
curl -L https://downloads.portainer.io/ce2-19/portainer-agent-stack.yml -o portainer-agent-stack.yml
该文件内容如下,主要就是根据镜像创建服务,以及挂载卷、网络配置、端口配置、副本配置等信息。
version: '3.2'services:agent:image: portainer/agent:2.19.3volumes:- /var/run/docker.sock:/var/run/docker.sock- /var/lib/docker/volumes:/var/lib/docker/volumesnetworks:- agent_networkdeploy:mode: globalplacement:constraints: [node.platform.os == linux]portainer:image: portainer/portainer-ce:2.19.3command: -H tcp://tasks.agent:9001 --tlsskipverifyports:- "9443:9443"- "9000:9000"- "8000:8000"volumes:- portainer_data:/datanetworks:- agent_networkdeploy:mode: replicatedreplicas: 1placement:constraints: [node.role == manager]networks:agent_network:driver: overlayattachable: truevolumes:portainer_data:
但是我们需要对该文件内容中
agent
部分增加一个端口挂载的配置,否则在后面创建环境时会因为连接失败而无法创建环境。services:agent:image: portainer/agent:2.19.3volumes:- /var/run/docker.sock:/var/run/docker.sock- /var/lib/docker/volumes:/var/lib/docker/volumesports:- "9001:9001"networks:- agent_networkdeploy:mode: globalplacement:constraints: [node.platform.os == linux]
-
在管理节点部署portainer集群
[root@host10 portainer]# docker stack deploy -c portainer-agent-stack.yml portainerCreating network portainer_agent_network Creating service portainer_agent Creating service portainer_portainer
可以看到,创建了一个网络
portainer_agent_network
、两个服务portainer_agent
和portainer_portainer
-
在任意节点查看网络,创建了一个
overlay
驱动的网络portainer_agent_network
。该网络会在集群中各个节点创建。[root@host10 portainer]# docker network lsNETWORK ID NAME DRIVER SCOPE 2d3e81dc418a bridge bridge local 5675307b8b8d docker_gwbridge bridge local 496c4eb3bb51 host host local j4lsm97dkovz ingress overlay swarm 69df9100d962 myBridge bridge local e72b30a2ea15 none null local 54cnuprrj5e4 portainer_agent_network overlay swarm
-
在管理节点查看服务。
[root@host10 portainer]# docker service lsID NAME MODE REPLICAS IMAGE PORTS mrjnxf734cki portainer_agent global 3/3 portainer/agent:2.19.3 tfgkmlb6rwwk portainer_portainer replicated 1/1 portainer/portainer-ce:2.19.3 *:8000->8000/tcp, *:9000->9000/tcp, *:9443->9443/tcp
-
在管理节点查看容器。
[root@host10 portainer]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d6d497046594 portainer/agent:2.19.3 "./agent" 4 minutes ago Up 4 minutes portainer_agent.0cibl244fqcmh7k6x8a3kwkfp.k3f1gkysdu64718ml6zm5cuzg8742edf0f3b7 portainer/portainer-ce:2.19.3 "/portainer -H tcp:/…" 4 minutes ago Up 4 minutes 8000/tcp, 9000/tcp, 9443/tcp portainer_portainer.1.otjp9rsp17v8f4l6u2ma1mg7a
-
在工作节点查看容器。与管理节点不同的是,工作节点只创建了
portainer/agent
容器,它是由管理节点在集群中创建的副本容器。[root@host20 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0e090ff0133d portainer/agent:2.19.3 "./agent" 5 minutes ago Up 5 minutes portainer_agent.wfw312mxlolm6e8xgdwp6kndy.iputjhsv1q8yudkv6i760e694
-
在浏览器访问
https://192.168.10.10:9443
,进入portainer页面。与部署单击模式不同的是,在选择环境类型时,我们应选择集群模式如下图所示
-
配置环境。
这次我们选择通过
Agent
的方式配置环境的连接。 -
完成配置后,在环境列表可以看到我们创建的portainer集群环境。
-
点击进入该环境,查看详细信息
-
进入集群页面,可以看到,我们在管理节点上部署的portainer容器根据服务的副本配置,在工作节点上也建立了相同的portainer容器副本。
八、部署一个容器集群
我们以创建busybox镜像的容器为例,创建docker容器集群。
1. 拉取镜像
在管理节点中使用以下命令拉取镜像
docker pull busybox
2. 创建网络
在管理节点中创建一个overlay
驱动的网络
[root@host10 ~]# docker network create -d overlay --attachable busybox_overlay_network
zjwmzvwlf4fgisos37i5876s9
注意,在集群环境中创建overlay
驱动网络时,一定要添加参数--attachable
,为了集群容器或单机容器与运行在其他节点中的容器建立通信。
3. 创建服务
在管理节点中创建服务
docker service create -td --name busybox_service --network busybox_overlay_network --replicas=2 busybox
--replicas=2
表示需要创建两个busybox容器的副本--network busybox_overlay_network
表示使用我们在上面创建的网络
4. 进入portainer查看busybox集群
在容器列表页面可以看到busybox
容器的集群,可以看到,两个busybox
容器分别位于host20
和host30
节点,ip地址分别为10.0.3.224
和10.0.3.225
。
5. 不同节点间容器的通信
对于busybox
容器集群的情况如下
主机 | 容器ip地址 |
---|---|
host20 | 10.0.3.225 |
host30 | 10.0.3.224 |
下面我们进入host20
主机的busybox
容器,去ping
位于host30
主机中的busybox
容器,可以ping
通,反之相同。
6. 集群扩展
上面我们创建busybox
容器集群时,设置其副本数量为2--replicas=2
,现在我们通过portainer对副本数量进行修改为3。
现在再看一下集群页面,可以发现busybox
容器已扩展到三个节点,如下图所示
到这里docker集群的入门搭建过程就结束了。
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————
相关文章:

docker集群的详解以及超详细搭建
文章目录 一、问题引入1. 多容器位于同一主机2. 多容器位于不同主机 二、介绍三、特性四、概念1. 节点nodes2. 服务(service)和任务(task)3. 负载均衡 五、docker网络1. overlay网络 六、docker集群搭建1. 环境介绍2. 创建集群3. 集群网络4. 加入工作节点 七、部署可视化界面po…...
4进制思路。。。。。。。。
猪猪 Hanke 特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke 吃鸡很特别,为什么特别呢?因为他有 1010 种配料(芥末、孜然等),每种配料可以放 11 到 33 克,任意烤…...

解决ansible批量加入新IP涉及known_hosts报错的问题
我们把一批新的IP加入到ansible的hosts文件,比如/etc/ansible/hosts,往往会有这样的提示, 因为本机的~/.ssh/known_hosts文件中并有fingerprint key串,使用ssh连接目标主机时,一般会提示是否将key字符串加入到~/.ssh/…...
vuepress----1、快速开始
创建项目工程 本文会帮助你从头搭建一个简单的 VuePress 文档。如果你想在一个现有项目中使用 VuePress 管理文档,从步骤 3 开始。 创建并进入一个新目录 mkdir vuepress-starter && cd vuepress-starter使用你喜欢的包管理器进行初始化 yarn init # npm i…...

C++ -- 每日选择题 -- Day2
第一题 1. 下面代码中sizeof(A)结果为() #pragma pack(2) class A {int i;union U{char str[13];int i;}u;void func() {};typedef char* cp;enum{red,green,blue}color; }; A:20 B:21 C:22 D:24 答案及解析…...

软件测评中心▏软件集成测试和功能测试之间的区别和联系简析
软件集成测试是在软件开发周期的后期阶段进行的测试活动,旨在验证系统各个组件之间的接口和交互是否正常工作。而功能测试是一种验证软件系统是否按照需求规格说明书所规定的功能进行正确实现的测试。接下来,我们来分别探讨一下软件集成测试和功能测试有…...

Selenium/webdriver介绍以及工作原理
最近在看一些底层的东西。driver翻译过来是驱动,司机的意思。如果将webdriver比做成司机,竟然非常恰当。 我们可以把WebDriver驱动浏览器类比成出租车司机开出租车。在开出租车时有三个角色: 乘客:他/她告诉出租车司机去哪里&…...

HTML5+CSS3+JS小实例:九宫格图片鼠标移入移出方向感知特效
实例:九宫格图片鼠标移入移出方向感知特效 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport&…...

在Rust中编写自动化测试
1.摘要 Rust中的测试函数是用来验证非测试代码是否是按照期望的方式运行的, 测试函数体通常需要执行三种操作:1.设置任何所需的数据或状态;2.运行需要测试的代码;3.断言其结果是我们所期望的。本篇文章主要探讨了Rust自动化测试的几种常见场景。 2.测试函数详解 在Rust项目工…...

羊大师提问,为什么吃得越咸越容易出现健康问题?
羊大师提问,为什么吃得越咸越容易出现健康问题? 在现代社会中,有一种追求咸味食物的趋势,许多人都钟爱于吃咸味食物。吃咸味食物往往容易导致健康问题,引发各种疾病。那么为什么吃的越咸越容易生病呢? 今…...

linux ld 链接器学习笔记
ld链接器笔记 1. 首先编写一段汇编代码 这里的汇编语法时 AT&T语法,是gcc原生支持的语法,底层使用 gas(gnu assembler) 完成汇编,相较于 Intel x86语法, AT&T 语法要更加古老,因此大多数人更加偏向于使用 Intel 的语法. nasm 编译器支持x86语法.自从2.10版本…...
栈模拟先序后序中序遍历(非递归遍历)
先序遍历: vector<int> preorderTraversal(TreeNode* u) {stack<TreeNode*>stk;vector<int>res;if(unullptr) return res;while(stk.size()||u){if(u){res.push_back(u->val);//遍历当前结点stk.push(u);//记录当前递归层uu->left;//遍历左…...
linux 内核软中断介绍
在介绍软中断之前,先来介绍一个概念:中断下半部: 为了避免处理复杂的中断嵌套,中断处理程序是在关闭中断的情况下执行的。可是,如果关闭中断的时间太长,可能导致中断请求丢失。例如周期时钟每隔 10 毫秒发送…...

软考:2024年软考高级:软件工程
软考:2024年软考高级: 提示:系列被面试官问的问题,我自己当时不会,所以下来自己复盘一下,认真学习和总结,以应对未来更多的可能性 关于互联网大厂的笔试面试,都是需要细心准备的 (1…...

Kubernetes(K8s)_15_CNI
Kubernetes(K8s)_15_CNI CNI网络模型UnderlayMAC VLANIP VLANDirect Route OverlayVXLAN CNI插件FlannelCalico CNI配置内置实现 CNI CNI(Container Network Interface): 实现容器网络连接的规范 Kubernetes将网络通信可分为: Pod内容器、Pod、Pod与Se…...
python 生成器的作用
1. 生成器 参考: https://www.cainiaojc.com/python/python-generator.html 1.1. 什么是生成器? 在 python 中,一边循环一边计算的机制,称为生成器:generator. 1.2. 生成器有什么优点? 1、节约内存。p…...

第十五届蓝桥杯(Web 应用开发)模拟赛 2 期-大学组(详细分析解答)
目录 1.相不相等 1.1 题目要求 1.2 题目分析 1.3 源代码 2.三行情书 2.1 题目要求 2.2 题目分析 2.3 源代码 3.电影院在线订票 3.1 题目要求 3.2 题目分析 3.3 源代码 4.老虎坤(不然违规发不出来) 4.1 题目要求 4.2 题目分析 4.3 源代码 …...

图解系列--HTTPS,认证
确保 Web 安全的HTTPS 1.HTTP 的缺点 1.1.通信使用明文可能会被窃听 加密处理防止被窃听 加密的对象可以有这么几个。 (1).通信的加密 HTTP 协议中没有加密机制,但可以通过和 SSL(Secure Socket Layer,安全套接层)或TLSÿ…...
element plus中表格的合计属性和例子
在 element plus 表格中,您可以使用 summary-method 属性来指定一个函数,计算表格中列的合计或平均值等。该函数应该返回一个对象,其中包含每个列的合计值。例如,如果您的表格数据是这样的: [{ name: John, age: 20, …...
计网Lesson1笔记
文章目录 几个简单概念计网的发展史阿帕网和RFCTCP/IP 协议互联网协议计网设计OSI 的七层架构TCP/IP 协议簇 几个简单概念 主机(host):指单个计算机,比如PC,或者其他电子设备。端系统(end system):指一块区域内的多个主机&#x…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...
大数据治理的常见方式
大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法,以下是几种常见的治理方式: 1. 数据质量管理 核心方法: 数据校验:建立数据校验规则(格式、范围、一致性等)数据清洗&…...