【kubernetes系列】flannel之vxlan模式分析

news2024/12/23 22:39:36

概述

在Kubernetes中要保证容器之间网络互通,网络至关重要。而Kubernetes本身并没有自己实现容器网络,而是而是借助CNI标准,通过插件化的方式自由接入进来。在容器网络接入进来需要满足如下基本原则:

  • Pod无论运行在任何节点都可以互相直接通信,而不需要借助NAT地址转换实现。
  • Node与Pod可以互相通信,在不限制的前提下,Pod可以访问任意网络。
  • Pod拥有独立的网络栈,Pod看到自己的地址和外部看见的地址应该是一样的,并且同个Pod内所有的容器共享同个网络栈。

kubernetes中的网络通信

kubernetes中的网络通信大致分为以下几种:

  • Pod内容器间的通信(lo)
  • Pod之间的通信 pod IP <—–> pod IP(flannel、calico)
  • Pod与Service之间的通信 podIP <—–> ClusterIP(iptables、ipvs)
  • Service与集群外部的通信 ClusterIP <—–> 集群外部

常见的CNI插件:

  • flannel
  • calico
  • canel
  • kube-router

Flannel

Flannel是CoreOS开源的,Overlay模式的CNI网络插件,Flannel在每个集群节点上运行一个flanneld的代理守护服务,为每个集群节点(host)分配一个子网(subnet),同时为节点上的容器组(pod)分配IP,在整个集群节点间构建一个虚拟的网络,实现集群内部跨节点通信。Flannel的数据包在集群节点间转发是由backend实现的,目前,已经支持核心官方推荐的模式有UDP、VXLAN、HOST-GW,以及扩展试用实验的模式有IPIP,AWS VPC、GCE、Ali VPC、Tencent VPC等路由,其中vxlan模式在实际的生产中使用最多,下面以vxlan模式为例。
在这里插入图片描述

从图里看每个宿主机都有一个flannel1(flannel.1)的设备,就是VXLAN所需的VTEP设备(flannel1“用于VXLAN报文的封装和解封装”),它既有IP地址也有MAC地址。如现在container1 访问 container2,当container1发出请求后,这个目的的地址是10.244.1.3的IP包,会先出现在cni0网桥,然后被路由到本机flanner1设备上处理,也就是说,来到了“隧道”的出口。既目的宿主机的VTEP设备(就是flannel1 设备)。
margu
当所有Node启动后,我们可以在k8s-m2上可以看到多个flannel1 网卡的路由信息,是因为flanneld启动后创建的。

[root@k8s-m2 ~]# ifconfig  flannel.1
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.0.0  netmask 255.255.255.255  broadcast 0.0.0.0
        ether 96:69:e2:7d:bd:32  txqueuelen 0  (Ethernet)
        RX packets 10177  bytes 977133 (954.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 10177  bytes 1787417 (1.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@k8s-m2 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.254   0.0.0.0         UG    0      0        0 ens32
10.244.0.0      0.0.0.0         255.255.255.0   U     0      0        0 cni0
10.244.1.0      10.244.1.0      255.255.255.0   UG    0      0        0 flannel.1
10.244.2.0      10.244.2.0      255.255.255.0   UG    0      0        0 flannel.1
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 ens32
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 ens32

从上图看到10.244.1.0就是k8s-m3的VTEP设备(flannel1)的IP地址,而这些VTEP设备之间通讯就需要想办法组成一个虚拟的二层网络,既:通过二层数据帧进行通信,而k8s-m2上的VTEP设备在收到原始报文后,就要想办法把原始报文加一个目的MAC地址,封装成二层数据帧,然后发送给目的VTEP设备。这里需要解决一个问题目的VTEP设备的MAC地址是什么?

根据路由表信息我们知道了目的VTEP设备的IP地址,而根据三层IP地址查询二层MAC地址正是ARP表的功能。而这里用ARP表的记录,也就是flanneld进程在Node2节点启动时,自动添加到Node1上的。如下:

$ ip neigh show dev flannel.1
10.244.1.0 lladdr e6:05:f1:5f:d7:13 PERMANENT
10.244.2.0 lladdr 46:1b:96:8c:b0:cf PERMANENT

有了这个MAC地址linux内核就可以开始二层封装了,上面提到的MAC地址,对宿主机的二层网络没有任何意义,所以上述封装的数据帧不能在宿主机的二层网络里传输,为了方便概述,我们把上述数据帧称为内部数据帧。所以Linux内核还要把内部数据帧进一步封装成宿主机网络的一个普通数据帧,好让它载着内部数据帧,通过外网网卡(如eth0 、ens33等)进行传输。这次封装我们称为外部数据帧,为了实现这个搭便车的机制,Linux内核在封装内部数据帧前面,加上特殊的VXLAN头,用来表示这个乘客实际上是VXLAN使用的数据帧。而这个VXLAN头里有一个重要的标志VNI,它是识别某个数据帧是不是应该归属自己处理的标志。而flannel中,VNI的值是1,这也是为什么宿主机的VTEP设备都叫做flannel1的原因。这个时候linux内核会把这数据帧封装一个UDP报文在转发出去。虽然k8s-m2的flannel1知道k8s-m3的flannel1的MAC地址,但是不知道k8s-m3对外网卡的MAC的地址,也就是UDP该发往那台主机,实际上flannel1还要扮演一个网桥的角色,在二层网络进行UDP转发,而在Linux内核里面,网桥设备进行转发的依据来自FDB的转发数据库。这个flannel网桥对应的FDB信息,就是flannel进程维护的,他的内容如下:

$  bridge fdb show flannel.1|grep  46:1b:96:8c:b0:cf
46:1b:96:8c:b0:cf dev flannel.1 dst 192.168.2.140 self permanent

我们可以看到发往的IP地址是192.168.2.142的主机,显然这台主机就是 k8s-m3,UDP要转发的目的也找到了。接下来就是宿主机网络封包的过程了。
在这里插入图片描述

下面让我们来看看,当有一个EventAdded到来时,flanneld如何进行配置,以及封包是如何在flannel网络中流动的。
在这里插入图片描述

借用上图所示,当主机B启动了一个flanneld的服务后,将从etcd中读取配置信息,并请求获取子网的租约。所有Node上的flanneld都依赖etcd cluster来做集中配置服务,etcd保证了所有node上flanned所看到的配置是一致的。同时每个node上的flanned监听etcd上的数据变化,实时感知集群中node的变化。flanneld一旦获取子网租约、配置后端后,会将一些信息写入/run/flannel/subnet.env文件。它会将自己的subnet 10.1.16.0/24和Public IP 192.168.0.101写入etcd中,它还会将vtep设备flannel.1的mac地址也写入etcd中。

之后,主机A会得到EventAdded事件,并从中获取主机B添加至etcd的各种信息。这个时候,它会在本机上添加三条信息:

  • 路由信息:所有通往目的地址10.1.16.0/24的封包都通过vtep设备flannel.1设备发出,发往的网关地址为10.1.16.0,即主机B中的flannel.1设备。
$ ip route list
...
10.1.16.0/24 via 10.1.16.0 dev flannel.1 onlink
...
  • fdb信息:MAC地址为flannel的mac地址,发往10.1.16.0的数据包都将通过vxlan首先发往目的地址192.168.0.101,即主机B
$ ip neigh show dev flannel.1
10.1.16.0 lladdr 46:1b:96:8c:b0:cf PERMANENT

$  bridge fdb show flannel.1  | grep46:1b:96:8c:b0:cf
46:1b:96:8c:b0:cf dev flannel.1 dst 192.168.0.101 self permanent
  • arp信息:网关地址10.1.16.0的MAC地址为flannel的mac地址
[root@k8s-m2 ~]# arp -v
Address                  HWtype  HWaddress           Flags Mask            Iface
....
10.1.16.0               ether   46:1b:96:8c:b0:cf   CM                    flannel.1
....

参数说明:

  • Network flannel使用CIDR格式(10.244.0.0/16)的网络地址,用于为pod的配置网络功能
  • SubnetLen表示每个主机分配的subnet大小,我们可以在初始化时对其指定,否则使用默认配置。在默认配置的情况下SubnetLen配置为24(表示24位子网掩码)。
  • SubnetMin是集群网络地址空间中最小的可分配的subnet,可以手动指定,否则默认配置为集群网络地址空间中第一个可分配的subnet。例如对于”10.244.0.0/16″,当SubnetLen为24时,第一个可分配的subnet为”10.244.1.0/24″
  • SubnetMax表示最大可分配的subnet,对于”10.244.0.0/16″,当subnetLen为24时,SubnetMax为”10.244.255.0/24″
  • Backend.Type 为flannel指定使用的backend的类型,类型分三种:vxlan、host-gw、udp,如未指定,则默认为“vxlan”
  • –ip-masq=true 为网桥上的IP地址开启IP伪装(代表需要为其配置SNAT)
    注意:Backend为vxlan时,其中会存储vtep设备的mac地址至etcd中

抓包分析

以flannel常用的vxlan模式发送icmp包为例,ping不在同一节点上的pod。如下,default命名空间下的两个nginx pod分别位于不同的节点上。

[root@k8s-m1 k8s-total]# kubectl get po -o wide
NAME                        READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
liveness-exec-pod           1/1     Running   1          4d18h   10.244.0.10   k8s-m2   <none>           <none>
my-nginx-5b8555d6b8-cdqbm   1/1     Running   1          4d18h   10.244.0.13   k8s-m2   <none>           <none>
my-nginx-5b8555d6b8-vxcsj   1/1     Running   1          7d1h    10.244.2.7    k8s-m1   <none>           <none>

由于只有liveness-exec-pod 这个容器自带有ping命名,我就用10.244.0.10 这个pod去ping另一个节点上的 10.244.2.7 这个ip的pod,如下:

#查看对应节点上生成的veth网卡,在如上的k8s-m2上
[root@k8s-m1 k8s-total]# kubectl exec -it liveness-exec-pod -- /bin/sh
/ # cat /sys/class/net/eth0/iflink
20

/ # route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.244.0.1      0.0.0.0         UG    0      0        0 eth0
10.244.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0
10.244.0.0      10.244.0.1      255.255.0.0     UG    0      0        0 eth0
#注意此次的eth0是容器内部的eth0

/ # ping 10.244.2.7
PING 10.244.2.7 (10.244.2.7): 56 data bytes
64 bytes from 10.244.2.7: seq=0 ttl=62 time=0.355 ms
64 bytes from 10.244.2.7: seq=1 ttl=62 time=0.436 ms
64 bytes from 10.244.2.7: seq=2 ttl=62 time=0.309 ms
#一直ping着

到k8s-m2进行抓包,抓取对应的网卡

#先查看路由,到10.244.2.0开始是到网卡flannel.1
[root@k8s-m2 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.254   0.0.0.0         UG    0      0        0 ens32
10.244.0.0      0.0.0.0         255.255.255.0   U     0      0        0 cni0
10.244.1.0      10.244.1.0      255.255.255.0   UG    0      0        0 flannel.1
10.244.2.0      10.244.2.0      255.255.255.0   UG    0      0        0 flannel.1
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 ens32
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker_gwbridge
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 ens32

[root@k8s-m2 ~]# ip a
17: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default 
    link/ether da:fa:5e:60:ad:7c brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
.....
20: vethc1f65864@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default 
    link/ether 66:55:12:cd:be:bb brd ff:ff:ff:ff:ff:ff link-netnsid 5
21: vethe06e914a@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default 
    link/ether 1e:d7:3e:c5:e1:e8 brd ff:ff:ff:ff:ff:ff link-netnsid 6
22: veth0e3aa9d1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default 
    link/ether 1a:16:64:f3:d5:8c brd ff:ff:ff:ff:ff:ff link-netnsid 7
23: veth3c3c8697@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default 
    link/ether 3e:5b:82:c3:c4:44 brd ff:ff:ff:ff:ff:ff link-netnsid 8
24: veth131f9e56@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default 
    link/ether 06:af:26:b3:fa:17 brd ff:ff:ff:ff:ff:ff link-netnsid 9

[root@k8s-m2 ~]# tcpdump -i vethc1f65864 -p icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vethc1f65864, link-type EN10MB (Ethernet), capture size 262144 bytes
14:38:32.734140 IP 10.244.0.10 > 10.244.0.13: ICMP echo request, id 32555, seq 265, length 64
14:38:32.734242 IP 10.244.0.13 > 10.244.0.10: ICMP echo reply, id 32555, seq 265, length 64
14:38:33.734364 IP 10.244.0.10 > 10.244.0.13: ICMP echo request, id 32555, seq 266, length 64
14:38:33.734431 IP 10.244.0.13 > 10.244.0.10: ICMP echo reply, id 32555, seq 266, length 64
14:38:34.734583 IP 10.244.0.10 > 10.244.0.13: ICMP echo request, id 32555, seq 267, length 64
14:38:34.734681 IP 10.244.0.13 > 10.244.0.10: ICMP echo reply, id 32555, seq 267, length 64
^C

[root@k8s-m2 ~]# tcpdump -i cni0 -p icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on cni0, link-type EN10MB (Ethernet), capture size 262144 bytes
15:06:25.449188 IP 10.244.0.10 > 10.244.2.7: ICMP echo request, id 3358, seq 15, length 64
15:06:25.449531 IP 10.244.2.7 > 10.244.0.10: ICMP echo reply, id 3358, seq 15, length 64
15:06:26.449342 IP 10.244.0.10 > 10.244.2.7: ICMP echo request, id 3358, seq 16, length 64
15:06:26.449604 IP 10.244.2.7 > 10.244.0.10: ICMP echo reply, id 3358, seq 16, length 64

[root@k8s-m2 ~]# tcpdump -i flannel.1  -p icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes
15:06:43.451706 IP 10.244.0.10 > 10.244.2.7: ICMP echo request, id 3358, seq 33, length 64
15:06:43.451957 IP 10.244.2.7 > 10.244.0.10: ICMP echo reply, id 3358, seq 33, length 64

[root@k8s-m2 ~]# tcpdump -i ens32  -p icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens32, link-type EN10MB (Ethernet), capture size 262144 bytes
15:06:54.411530 IP 192.168.2.141 > 14.119.104.189: ICMP echo request, id 1, seq 21189, length 64
15:06:54.448813 IP 14.119.104.189 > 192.168.2.141: ICMP echo reply, id 1, seq 21189, length 64

在flannel的vxlan模式下不在同一节点上的pod,通过抓包分析结果如下:

  • 容器内部的流量通过内部网卡eth0网桥先到达cni0网卡(上面是 cni0网卡地址是10.244.0.1)
  • cni0上的流量再根据相应宿主机上的路由表,报文将送到flannel.1设备(10.244.0.0)
  • flannel.1是一个tun设备,工作在三层,它接收到的是一个RAW IP包(无MAC信息)。它会查看数据包的目的ip,从flanneld获取对端隧道设备的必要信息,封装数据包并转发至eth0网卡。
  • 随后eth0网卡会将发送至另一个pod所在的宿主机,该宿主机的网卡接收到数据包,发现数据包为overlay数据包,解开外层封装,并发送内层封装到flannel.1设备
  • flannel.1 设备查看数据包,根据路由表匹配,将数据发送给cni0设备,然后转发给相应的pod。

处在同一节点上的pod其实是不会经过cni0和flannel的,直接通过docker0网桥进行转发。

更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出

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

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

相关文章

有趣的Python之基本语法(一篇足够)

目录 Python简介 基本数据类型 进入交互模式 input()函数 条件语句 逻辑运算符 列表list 元组 字典 循环语句 format()方法和f 定义函数 python中的标准库引入 引入第三方库模块 面向对象 读文件 写文件 异常处理 Python简介 面向对象编程、函数式编程和过程…

二 动手学深度学习v2笔记 —— 线性回归 + 基础优化算法

二 动手学深度学习v2 —— 线性回归 基础优化算法 目录: 线性回归基础优化方法 1. 线性回归 总结 线性回归是对n维输入的加权&#xff0c;外加偏差使用平方损失来衡量预测值和真实值的差异线性回归有显示解线性回归可以看作是单层神经网络 2. 基础优化方法 梯度下降 小批量…

4通道高速数据采集卡推荐哪些呢

FMC141是一款基于VITA57.4标准的4通道2.8GSPS/2.5GSPS/1.6GSPS采样率16位DA播放FMC子卡&#xff0c;该板卡为FMC标准&#xff0c;符合VITA57.4与VITA57.1规范&#xff0c;16通道的JESD204B接口通过FMC连接器连接至FPGA的高速串行端口。 该板卡采用TI公司的DAC39J84芯片&#x…

【玩转Linux】Linux输入子系统简介

(꒪ꇴ꒪ ),hello我是祐言博客主页&#xff1a;C语言基础,Linux基础,软件配置领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff01;送给读者的一句鸡汤&#x1f914;&#xff1a;集中起来的意志可以击穿顽石!作者水平很有限&#xff0c;如果发现错误&#x…

LeetCode每日一题Day1——买卖股票的最佳时机

✨博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;算法修炼之练气篇&#xff08;C\C版&#xff09; &#x1f353;专栏&#xff1a;算法修炼之筑基篇&#xff08;C\C版&#xff09; &#x1f433;专栏&#xff1a;算法修炼之练气篇&#xff08;Python版&#xff09; ✨…

青大数据结构【2016】

一、单选 二、简答 3.简述遍历二叉树的含义及常见的方法。

shiro550反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

漏洞原理 本文所有使用的脚本和工具都会在文末给出链接&#xff0c;希望读者可以耐心看到最后。 啥是shiro? Shiro是Apache的一个强大且易用的Java安全框架,用于执行身份验证、授权、密码和会话管理。使用 Shiro 易于理解的 API&#xff0c;可以快速轻松地对应用程序进行保…

代码随想录算法训练营之JAVA|第十七天| 654. 最大二叉树

今天是第17天刷leetcode&#xff0c;立个flag&#xff0c;打卡60天。 算法挑战链接 654. 最大二叉树https://leetcode.cn/problems/maximum-binary-tree/description/ 第一想法 错误的想法&#xff0c;就不说了。 看完代码随想录之后的想法 用递归模拟真实的过程 如果我…

【iOS】通知原理

我们可以通过看通知的实现机制来了解通知中心是怎么实现对观察者的引用的。由于苹果对Foundation源码是不开源的&#xff0c;我们具体就参考一下GNUStep的源码实现。GNUStep的源码地址为&#xff1a;GNUStep源码GitHub下载地址, 具体源码可以进行查看。 通知的主要流程 通知全…

AD21 PCB设计的高级应用(二)PCB常见走线等长设计

&#xff08;二&#xff09;PCB常见走线等长设计 1.蛇形线的等长设计2.DDR的等长分组3.等长的拓扑结构3.1 点对点连接3.2 T型拓扑结构3.3 菊花链拓扑结构 1.蛇形线的等长设计 在 PCB 设计中,网络等长调节目的就是为了尽可能地降低信号在 PCB上传输延迟的差异。在 Altium Desig…

C语言第十三课--------初阶指针的认识--------重要部分

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; &#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382;…

JavaSE类和对象(重点:this引用、构造方法)

目录 一、类的定义方式以及实例化 1.面向对象 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在Java的世界里一切皆为对象。 2.类的定义和使用 1.在java中定义类时需要用到class关键字 3.类的实例化 4.类实例化的使用 二、this引用 …

面试中常聊 AMS,你是否又真的了解?

在面试的时候&#xff0c;经常会被问到这些问题&#xff1a; 对Activity的启动流程了解吗&#xff1f;AMS在Android起到什么作用&#xff0c;简单分析下Android的源码system_server为什么要在Zygote中启动&#xff0c;而不是由init直接启动呢?为什么要专门使用Zygote进程去孵…

有点慌,新公司项目构建用的Gradle

入职新公司&#xff0c;构建项目的工具用的gradle&#xff0c;以前没用过&#xff0c;看到一个build.gradle&#xff0c;点进去&#xff0c;心里一句我曹&#xff0c;这写的都是些什么玩意&#xff0c;方得一批&#xff0c;赶紧去补了下课。 好吧&#xff0c;先学点语法&#…

根据选择内容自动生成正则表达式

地址: https://regex.ai/ 如何使用? 比如我这里有个需求: 提取图片路径中的文件名 https://wx4.sinaimg.cn/mw1024/0040jbadly1hg5nk0l3gtj62c0340kjl02.jpg 提取出0040jbadly1hg5nk0l3gtj62c0340kjl02.jpg 数据越多越准确 左边提供数据, 右边给出需要提取的数据, 点击run&…

地产变革中,物业等风来

2023年7月&#xff0c;也许是中国房地产行业变局中的一个大拐点。 中信建投研报表示&#xff0c;政治局会议指出当前我国房地产形势已发生重大变化&#xff0c;要适时调整优化政策&#xff0c;为行业形势定调……当前房地产行业β已至。 不久前&#xff0c;国家统计局公布了2…

Mag-Fluo-4 AM,镁离子荧光探针,是一种有用的细胞内镁离子指示剂

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ PART1----产品描述&#xff1a; 镁离子荧光探针Mag-Fluo-4 AM&#xff0c;具细胞膜渗透性&#xff0c;对镁离子&#xff08;Mg2&#xff09; 和钙离子&#xff08;Ca2&#xff09;的 Kd 值分别是 4.7mM 和 22mM&#xff0c…

运维:Multipass软件让你的虚拟机管理更简单高效

一、Multipass是什么&#xff1f; 官网&#xff1a;https://multipass.run/ 一提到虚拟机大家一般都会想到VMvare和Virtual Box这两个的虚拟机软件&#xff0c;这两个软件一个比较麻烦的地方是安装完虚拟机以后还需要下载操作系统镜像。小编偶然间发现了Multipass。这款轻量级的…

Flowable-子流程-嵌套子流程

目录 定义图形标记XML内容使用示例视频讲解 定义 内嵌子流程又叫嵌入式子流程&#xff0c;它是一个可以包含其它活动、分支、事件&#xff0c;等的活动。我们通 常意义上说的子流程通常就是指的内嵌子流程&#xff0c;它表现为将一个流程&#xff08;子流程&#xff09;定义在…

【C语言初阶(20)】调试练习题

文章目录 前言实例1实例2 前言 在我们开始调试之前&#xff0c;应该有个明确的思路&#xff1b;程序是如何完成工作的、变量到达某个步骤时的值应该是什么、出现的问题大概会在什么位置。这些东西在调试之前都需要先确认下来&#xff0c;不然自己都不知道自己在调试个什么东西…