版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
手把手带你搞定4大容器网络问题一直以来,网络都是容器中令人头疼的问题。本文的主要目的是带你解决容器网络问题,让你不再对它恐惧。使用容器总是感觉像变魔术一样。对那些了解其内部原理的人来说,它是一种很好的方式;而对那些不了解其内部原理的人来说,这是一种可怕的方式。幸运的是,我们研究容器化技术的内部原理已经很长一段时间了。我们甚至发现,容器只是隔离的、受限制的Linux进程,镜像并不是运行容器所必须的,相反——要构建一个镜像,我们需要运行一些容器。现在,让我们来解决下容器网络问题。或者,更准确地说,是单主机容器网络问题。在本文中,我们将回答以下问题:如何虚拟化网络资源,使容器认为它们中的每一个都有一个专用的网络堆栈?如何将容器变成友好的邻居,防止它们相互干扰,并教它们如何很好地沟通?怎样从容器内部访问外部世界(比如互联网)?如何从外部世界(即端口发布)访问运行在一台机器上的容器?因此,很明显,单主机容器网络只不过是一些众所周知的Linux工具的简单组合:网络命名空间虚拟以太网设备(veth)虚拟网络交换机(网桥)IP路由和网络地址转换(NAT)不管怎样,不需要任何代码就可以让网络魔法发生……1前提条件任何还算不错的Linux发行版可能都足矣。本文中的所有例子都是在一个全新的vagrantCentOS8虚拟机上完成的:$vagrantinitcentos/8$vagrantup$vagrantssh[vagrant@localhost~]$uname-aLinuxlocalhost.localdomain4.18.0-147.3.1.el8_1.x86_64简单起见,在本文中,我们不打算依赖任何成熟的容器化解决方案(例如docker或podman)。相反,我们将关注基本概念,并使用最简单的工具来实现我们的学习目标。2通过网络命名空间隔离容器Linux网络堆栈是由什么组成的?很明显,是网络设备的集合。还有什么?可能是路由规则集。不要忘了还有netfilter钩子集,包括由iptables规则定义的。我们可以快速创建一个不是很完善的inspect-net-stack.sh脚本:#!/usr/bin/envbashecho">Networkdevices"iplinkecho-e"\n>Routetable"iprouteecho-e"\n>Iptablesrules"iptables--list-rules在运行它之前,让我们稍微修改下iptables规则,让其更容易识别:$sudoiptables-NROOT_NS之后,在我的机器上执行inspect脚本会产生以下输出:$sudo./inspect-net-stack.sh>Networkdevices1:lo:mtu65536qdiscnoqueuestateUNKNOWNmodeDEFAULTgroupdefaultqlen1000link/loopback00:00:00:00:00:00brd00:00:00:00:00:002:eth0:mtu1500qdiscfq_codelstateUPmodeDEFAULTgroupdefaultqlen1000link/ether52:54:00:e3:27:77brdff:ff:ff:ff:ff:ff>Routetabledefaultviadeveth0protodhcpmetric100/24deveth0protokernelscopelinksrc5metric100>Iptablesrules-PINPUTACCEPT-PFORWARDACCEPT-POUTPUTACCEPT-NROOT_NS之所以对这个输出感兴趣,是因为我们想确保即将创建的每个容器都将获得一个单独的网络堆栈。你可能已经听说过,用于容器隔离的其中一个Linux名称空间是网络命名空间(networknamespace)。按照manip-netns的说法,“网络命名空间在逻辑上是网络堆栈的另一个副本,有自己的路由、防火墙规则和网络设备。”简单起见,这将是我们在本文中使用的唯一命名空间。与其创建完全隔离的容器,不如将范围限制在网络堆栈中。创建网络命名空间的一种方法是ip工具——是事实标准iproute2工具集的一部分:$sudoipnetnsaddnetns0$ipnetnsnetns0如何开始使用刚刚创建的命名空间?有一个可爱的Linux命令叫做nsenter。它输入一个或多个指定的名称空间,然后执行给定的程序:$sudonsenter--net=/var/run/netns/netns0bash#Thenewlycreatedbashprocesslivesinnetns0$sudo./inspect-net-stack.sh>Networkdevices1:lo:mtu65536qdiscnoopstateDOWNmodeDEFAULTgroupdefaultqlen1000link/loopback00:00:00:00:00:00brd00:00:00:00:00:00>Routetable>Iptablesrules-PINPUTACCEPT-PFORWARDACCEPT-POUTPUTACCEPT从上面的输出可以清楚地看出,在netns0命名空间内运行的bash进程看到的是一个完全不同的网络堆栈。没有路由规则,没有自定义iptables链,只有一个环回网络设备。到目前为止,一切顺利……3使用虚拟以太网设备(veth)将容器连接到主机如果我们不能与一个专用的网络堆栈通信,那么它就没那么有用了。幸运的是,Linux为此提供了一个合适工具——虚拟以太网设备!按照manveth的说法,“veth设备是虚拟以太网设备。它们可以作为网络命名空间之间的隧道,创建一个连接到另一个命名空间中物理网络设备的桥,但也可以作为独立的网络设备使用。”虚拟以太网设备总是成对出现。不用担心,让我们看一下创建命令就会明白了:$
sudo
ip
link
add
veth0
type
veth
peer
name
ceth0通过这个命令,我们刚刚创建了一对相互连接的虚拟以太网设备。名称veth0和ceth0是任起的:$iplink1:lo:mtu65536qdiscnoqueuestateUNKNOWNmodeDEFAULTgroupdefaultqlen1000link/loopback00:00:00:00:00:00brd00:00:00:00:00:002:eth0:mtu1500qdiscfq_codelstateUPmodeDEFAULTgroupdefaultqlen1000link/ether52:54:00:e3:27:77brdff:ff:ff:ff:ff:ff5:ceth0@veth0:mtu1500qdiscnoopstateDOWNmodeDEFAULTgroupdefaultqlen1000link/ether66:2d:24:e3:49:3fbrdff:ff:ff:ff:ff:ff6:veth0@ceth0:mtu1500qdiscnoopstateDOWNmodeDEFAULTgroupdefaultqlen1000link/ether96:e8:de:1d:22:e0brdff:ff:ff:ff:ff:ff创建后,veth0和ceth0都驻留在主机的网络堆栈(也称为根网络命名空间)上。为了连接根命名空间和netns0命名空间,我们需要将一个设备保留在根命名空间中,并将另一个设备移到netns0中:$sudoiplinksetceth0netnsnetns0#Listallthedevicestomakesureoneofthemdisappearedfromtherootstack$iplink1:lo:mtu65536qdiscnoqueuestateUNKNOWNmodeDEFAULTgroupdefaultqlen1000link/loopback00:00:00:00:00:00brd00:00:00:00:00:002:eth0:mtu1500qdiscfq_codelstateUPmodeDEFAULTgroupdefaultqlen1000link/ether52:54:00:e3:27:77brdff:ff:ff:ff:ff:ff6:veth0@if5:mtu1500qdiscnoopstateDOWNmodeDEFAULTgroupdefaultqlen1000link/ether96:e8:de:1d:22:e0brdff:ff:ff:ff:ff:fflink-netnsnetns0一旦我们打开设备并分配了正确的IP地址,任何出现在其中一台设备上的数据包都会立即出现在连接两个命名空间的对端设备上。让我们从根命名空间开始:$sudoiplinksetveth0up$sudoipaddradd1/16devveth0接下来是etns0:$sudonsenter--net=/var/run/netns/netns0$iplinksetloup#whoops$iplinksetceth0up$ipaddradd0/16devceth0$iplink1:lo:mtu65536qdiscnoqueuestateUNKNOWNmodeDEFAULTgroupdefaultqlen1000link/loopback00:00:00:00:00:00brd00:00:00:00:00:005:ceth0@if6:mtu1500qdiscnoqueuestateUPmodeDEFAULTgroupdefaultqlen1000link/ether66:2d:24:e3:49:3fbrdff:ff:ff:ff:ff:fflink-netnsid0通过veth设备连接网络命名空间现在可以检查下连接了:#From`netns0`,pingroot'sveth0$ping-c21PING1(1)56(84)bytesofdata.64bytesfrom1:icmp_seq=1ttl=64time=0.038ms64bytesfrom1:icmp_seq=2ttl=64time=0.040ms---1pingstatistics---2packetstransmitted,2received,0%packetloss,time58msrttmin/avg/max/mdev=0.038/0.039/0.040/0.001ms#Leave`netns0`$exit#Fromrootnamespace,pingceth0$ping-c20PING0(0)56(84)bytesofdata.64bytesfrom0:icmp_seq=1ttl=64time=0.073ms64bytesfrom0:icmp_seq=2ttl=64time=0.046ms---0pingstatistics---2packetstransmitted,2received,0%packetloss,time3msrttmin/avg/max/mdev=0.046/0.059/0.073/0.015ms同时,如果我们试图从netns0命名空间访问任何其他地址,都会失败:#Insiderootnamespace$ipaddrshowdeveth02:eth0:mtu1500qdiscfq_codelstateUPgroupdefaultqlen1000link/ether52:54:00:e3:27:77brdff:ff:ff:ff:ff:ffinet5/24brd55scopeglobaldynamicnoprefixrouteeth0valid_lft84057secpreferred_lft84057secinet6fe80::5054:ff:fee3:2777/64scopelinkvalid_lftforeverpreferred_lftforever#Rememberthis5$sudonsenter--net=/var/run/netns/netns0#Tryhost'seth0$ping5connect:Networkisunreachable#TrysomethingfromtheInternet$pingconnect:Networkisunreachable不过,这很容易解释。对于这样的数据包,在netns0的路由表中没有路由。其中,唯一的条目显示了如何到达/16网络:#From`netns0`namespace:$iproute/16devceth0protokernelscopelinksrc0Linux有很多方法来填充路由表。其中之一是从直接连接的网络接口提取路由。记住,在命名空间创建后,netns0的路由表是空的。但随后我们添加了ceth0设备,并为它分配了一个IP地址0/16。由于我们使用的不是一个简单的IP地址,而是地址和网络掩码的组合,网络堆栈会设法从中提取路由信息。每个发往/16网络的数据包将通过ceth0设备发送。但是任何其他的包都会被丢弃。类似地,在根命名空间中有一条新路由:在公众号编程技术圈后台回复“Java”,获取一份惊喜礼包。#From`root`namespace:$iproute#...omitedlines.../16devveth0protokernelscopelinksrc1现在,我们已经回答了我们的第一个问题。我们现在知道了如何隔离、虚拟化和连接Linux网络堆栈。4通过虚拟网络交换机(网桥)实现容器互连容器化的整个理念可以归结为有效的资源共享。也就是说,每台机器一个容器的情况并不常见。相反,我们的目标是在共享环境中运行尽可能多的隔离进程。那么,如果我们按照上面的veth方法将多个容器放在同一主机上,会发生什么呢?让我们添加第二个容器:#Fromrootnamespace$sudoipnetnsaddnetns1$sudoiplinkaddveth1typevethpeernameceth1$sudoiplinksetceth1netnsnetns1$sudoiplinksetveth1up$sudoipaddradd1/16devveth1$sudonsenter--net=/var/run/netns/netns1$iplinksetloup$iplinksetceth1up$ipaddradd0/16devceth1我最喜欢的部分,检查连接:#From`netns1`wecannotreachtherootnamespace!$ping-c21PING1(1)56(84)bytesofdata.From0icmp_seq=1DestinationHostUnreachableFrom0icmp_seq=2DestinationHostUnreachable---1pingstatistics---2packetstransmitted,0received,+2errors,100%packetloss,time55mspipe2#Butthereisaroute!$iproute/16devceth1protokernelscopelinksrc0#Leaving`netns1`$exit#Fromrootnamespacewecannotreachthe`netns1`$ping-c20PING0(0)56(84)bytesofdata.From1icmp_seq=1DestinationHostUnreachableFrom1icmp_seq=2DestinationHostUnreachable---0pingstatistics---2packetstransmitted,0received,+2errors,100%packetloss,time23mspipe2#From`netns0`weCANreach`veth1`$sudonsenter--net=/var/run/netns/netns0$ping-c21PING1(1)56(84)bytesofdata.64bytesfrom1:icmp_seq=1ttl=64time=0.037ms64bytesfrom1:icmp_seq=2ttl=64time=0.046ms---1pingstatistics---2packetstransmitted,2received,0%packetloss,time33msrttmin/avg/max/mdev=0.037/0.041/0.046/0.007ms#Butwestillcannotreach`netns1`$ping-c20PING0(0)56(84)bytesofdata.From0icmp_seq=1DestinationHostUnreachableFrom0icmp_seq=2DestinationHostUnreachable---0pingstatistics---2packetstransmitted,0received,+2errors,100%packetloss,time63mspipe2有点不对劲……netns1遇到问题。由于某些原因,它不能与根通信,我们也不能从根命名空间访问它。然而,由于两个容器都位于同一个IP网络/16中,我们现在可以从netns0容器与主机的veth1进行通信。非常有趣……我花了些时间才想明白,但显然我们面临的是路由冲突。让我们检查下根命名空间中的路由表:$iproute#...omitedlines...#/16devveth0protokernelscopelinksrc1/16devveth1protokernelscopelinksrc1虽然在添加了第二个veth对后,根的网络堆栈学习到了新的路由/16devveth1protokernelscopelinksrc1,但是,现有的路由中已经有一条针对同一网络的路由。当第二个容器试图pingveth1设备时,将选择第一个路由,这会破坏连接。如果我们删除第一条路由sudoiproutedelete/16devveth0protokernelscopelinksrc1,并重新检查连接,情况就会反过来,即netns1的连接将恢复,但netns0就有问题了。我相信,如果我们为netns1选择另一个IP网络,一切就没问题了。然而,多个容器位于一个IP网络中是一个合理的用例。因此,我们需要以某种方式调整veth方法…看看Linux网桥——另一种虚拟网络设施!Linux网桥的行为就像一个网络交换机。它会在连接到它的接口之间转发数据包。因为它是一个交换机,所以它是在L2(即以太网)层完成这项工作的。让我们试着操作下吧。但首先,我们需要清理现有的设置,因为到目前为止,我们所做的一些配置更改实际上已经不再需要了。删除网络命名空间就足够了:$sudoipnetnsdeletenetns0$sudoipnetnsdeletenetns1#Butifyoustillhavesomeleftovers...$sudoiplinkdeleteveth0$sudoiplinkdeleteceth0$sudoiplinkdeleteveth1$sudoiplinkdeleteceth1快速重建两个容器。注意,我们没有给新的veth0和veth1设备分配任何IP地址:$sudoipnetnsaddnetns0$sudoiplinkaddveth0typevethpeernameceth0$sudoiplinksetveth0up$sudoiplinksetceth0netnsnetns0$sudonsenter--net=/var/run/netns/netns0$iplinksetloup$iplinksetceth0up$ipaddradd0/16devceth0$exit$sudoipnetnsaddnetns1$sudoiplinkaddveth1typevethpeernameceth1$sudoiplinksetveth1up$sudoiplinksetceth1netnsnetns1$sudonsenter--net=/var/run/netns/netns1$iplinksetloup$iplinksetceth1up$ipaddradd0/16devceth1$exit确保主机上没有新路由:$iproutedefaultviadeveth0protodhcpmetric100/24deveth0protokernelscopelinksrc5metric100最后,创建网桥接口:$sudoiplinkaddbr0typebridge$sudoiplinksetbr0up现在,将veth0和veth1两端都连接到网桥上:$sudoiplinksetveth0masterbr0$sudoiplinksetveth1masterbr0然后检查容器之间的连接:$sudonsenter--net=/var/run/netns/netns0$ping-c20PING0(0)56(84)bytesofdata.64bytesfrom0:icmp_seq=1ttl=64time=0.259ms64bytesfrom0:icmp_seq=2ttl=64time=0.051ms---0pingstatistics---2packetstransmitted,2received,0%packetloss,time2msrttmin/avg/max/mdev=0.051/0.155/0.259/0.104ms$sudonsenter--net=/var/run/netns/netns1$ping-c20PING0(0)56(84)bytesofdata.64bytesfrom0:icmp_seq=1ttl=64time=0.037ms64bytesfrom0:icmp_seq=2ttl=64time=0.089ms---0pingstatistics---2packetstransmitted,2received,0%packetloss,time36msrttmin/avg/max/mdev=0.037/0.063/0.089/0.026ms真令人愉快!一切正常。使用这种新方法,我们根本没有配置veth0和veth1。我们只在ceth0和ceth1端分配了两个IP地址。但是,由于它们都在同一个以太网段(记住,我们将它们连接到虚拟交换机),所以L2层上有连接:$sudonsenter--net=/var/run/netns/netns0$ipneigh0devceth0lladdr6e:9c:ae:02:60:deSTALE$exit$sudonsenter--net=/var/run/netns/netns1$ipneigh0devceth1lladdr66:f3:8c:75:09:29STALE$exit恭喜,我们学会了如何将容器变成友好的邻居,防止它们相互干扰,并保持连接性。5访问外部世界(IP路由和伪装)容器之间可以通信了。但它们可以和主机(即根命名空间)通信吗?$sudonsenter--net=/var/run/netns/netns0$ping5#eth0addressconnect:Networkisunreachable很明显,netns0中没有相应的路由:$iproute/16devceth0protokernelscopelinksrc0根命名空间也不能和容器通信:#Useexittoleave`netns0`first:$ping-c20PING0(0)56(84)bytesofdata.From23icmp_seq=1DestinationNetUnreachableFrom23icmp_seq=2DestinationNetUnreachable---0pingstatistics---2packetstransmitted,0received,+2errors,100%packetloss,time3ms$ping-c20PING0(0)56(84)bytesofdata.From23icmp_seq=1DestinationNetUnreachableFrom23icmp_seq=2DestinationNetUnreachable---0pingstatistics---2packetstransmitted,0received,+2errors,100%packetloss,time3ms为了在根命名空间和容器命名空间之间建立连接,我们需要为网桥网络接口分配IP地址:$
sudo
ip
addr
add
/16
dev
br0一旦我们给网桥接口分配了IP地址,我们的主机路由表上就会多一条路由:$iproute#...omittedlines.../16devbr0protokernelscopelinksrc$ping-c20PING0(0)56(84)bytesofdata.64bytesfrom0:icmp_seq=1ttl=64time=0.036ms64bytesfrom0:icmp_seq=2ttl=64time=0.049ms---0pingstatistics---2packetstransmitted,2received,0%packetloss,time11msrttmin/avg/max/mdev=0.036/0.042/0.049/0.009ms$ping-c20PING0(0)56(84)bytesofdata.64bytesfrom0:icmp_seq=1ttl=64time=0.059ms64bytesfrom0:icmp_seq=2ttl=64time=0.056ms---0pingstatistics---2packetstransmitted,2received,0%packetloss,time4msrttmin/avg/max/mdev=0.056/0.057/0.059/0.007ms容器可能还具有ping网桥接口的能力,但它们仍然无法连接到主机的eth0。我们需要为容器添加默认路由:在公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。$sudonsenter--net=/var/run/netns/netns0$iprouteadddefaultvia$ping-c25PING5(5)56(84)bytesofdata.64bytesfrom5:icmp_seq=1ttl=64time=0.036ms64bytesfrom5:icmp_seq=2ttl=64time=0.053ms---5pingstatistics---2packetstransmitted,2received,0%packetloss,time14msrttmin/avg/max/mdev=0.036/0.044/0.053/0.010ms#Andrepeatthechangefor`netns1`这项更改基本上把主机变成了路由器,网桥接口成了容器的默认网关。很好,我们将容器与根命名空间连接起来了。现在,让我们尝试将它们与外部世界连接起来。默认情况下,在Linux中数据包转发(即路由器功能)是禁用的。我们需要打开它:#Intherootnamespacesudobash-c'echo1>/proc/sys/net/ipv4/ip_forward'又到我最喜欢的部分了,检查连接:$sudonsenter--net=/var/run/netns/netns0$ping#hangsindefinitelylongforme...还是不行。我们漏了什么吗?如果容器向外部世界发送数据包,那么目标服务器将不能将数据包发送回容器,因为容器的IP地址是私有的。也就是说,只有本地网络才知道特定IP的路由规则。世界上有很多容器共享完全相同的私有IP地址0。解决这个问题的方法叫做网络地址转换(NAT)。在进入外部网络前,由容器发出的数据包将其源IP地址替换为主机的外部接口地址。主机还将跟踪所有现有的映射,并且在数据包到达时,它会在将其转发回容器之前还原IP地址。听起来很复杂,但我有个好消息要告诉你!有了iptables模块,我们只需要一个命令就可以实现:$
sudo
iptables
-t
nat
-A
POSTROUTING
-s
/16
!
-o
br0
-j
MASQUERADE这个命令相当简单。我们正在向POSTROUTING链的nat表添加一条新规则,要求伪装所有源自/16网络的数据包,但不是通过网桥接口。检查连接:$sudonsenter--net=/var/run/netns/netns0$ping-c2PING()56(84)bytesofdata.64bytesfrom:icmp_seq=1ttl=61time=43.2ms64bytesfrom:icmp_seq=2ttl=61time=36.8ms---pingstatistics---2packetstransmitted,2received,0%packetloss,time2msrttmin/avg/max/mdev=36.815/40.008/43.202/3.199ms注意,我们遵循的是默认允许(bydefault-allow)策略,这在现实世界中可能相当危险。对于每个链,主机默认的iptables策略都是ACCEPT:sudoiptables-S-PINPUTACCEPT-PFORWARDACCEPT-POUTPUTACCEPT相反,作为一个很好的例子,Docker默认限制了一切,然后只启用已知路径的路由。以下是在CentOS8机器上(在5005端口上暴露了单个容器)Docker守护进程生成的转储规则:$sudoiptables-tfilter--list-rules-PINPUTACCEPT-PFORWARDDROP-POUTPUTACCEPT-NDOCKER-NDOCKER-ISOLATION-STAGE-1-NDOCKER-ISOLATION-STAGE-2-NDOCKER-USER-AFORWARD-jDOCKER-USER-AFORWARD-jDOCKER-ISOLATION-STAGE-1-AFORWARD-odocker0-mconntrack--ctstateRELATED,ESTABLISHED-jACCEPT-AFORWARD-odocker0-jDOCKER-AFORWARD-idocker0!-odocker0-jACCEPT-AFORWARD-idocker0-odocker0-jACCEPT-ADOCKER-d/32!-idocker0-odocker0-ptcp-mtcp--dport5000-jACCEPT-ADOCKER-ISOLATION-STAGE-1-idocker0!-odocker0-jDOCKER-ISOLATION-STAGE-2-ADOCKER-ISOLATION-STAGE-1-jRETURN-ADOCKER-ISOLATION-STAGE-2-odocker0-jDROP-ADOCKER-ISOLATION-STAGE-2-jRETURN-ADOCKER-USER-jRETURN$sudoiptables-tnat--list-rules-PPREROUTINGACCEPT-PINPUTACCEPT-PPOSTROUTINGACCEPT-POUTPUTACCEPT-NDOCKER-APREROUTING-maddrtype--dst-typeLOCAL-jDOCKER-APOSTROUTING-s/16!-odocker0-jMASQUERADE-APOSTROUTING-s/32-d/32-ptcp-mtcp--dport5000-jMASQUERADE-AOUTPUT!-d/8-maddrtype--dst-typeLOCAL-jDOCKER-ADOCKER-idocker0-jRETURN-ADOCKER!-idocker0-ptcp-mtcp--dport5005-jDNAT--to-destination:5000$sudoiptables-tmangle--list-rules-PPREROUTINGACCEPT-PINPUTACCEPT-PFORWARDACCEPT-POUTPUTACCEPT-PPOSTROUTINGACCEPT$sudoiptables-traw--list-rules-PPREROUTINGACCEPT-POUTPUTACCEPT6从外部访问容器(端口发布)我们都知道,有一种做法是将容器端口发布到主机的部分(或全部)接口。但端口发布的真正含义是什么?假设我们有一个在容器内运行的服务器:$sudonsenter--net=/var/run/netns/netns0$python3-mhttp.server--bind05000如果我们试图从主机向这个服务器进程发送一个HTTP请求,一切都没问题(好吧,根命名空间和所有容器接口之间都有连接,为什么没有呢?):#Fromrootnamespace$curl0:5000#...omitedlines...但是,如果我们要从外部访问该服务器,我们将使用哪个IP地址?我们知道的唯一IP地址可能是主机的外部接口地址eth0:$curl5:5000curl:(7)Failedtoconnec
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年度广告发布合同的投放要求与效果评估2篇
- 04版健身中心设备采购与安装合同2篇
- 2024年度七源知识产权商业秘密许可合同
- 2024年度企业销售激励机制劳动合同
- 2024年度汽车销售退货政策合同3篇
- 2024年度智能医疗系统开发及部署合同
- 2024年度艺人经纪合同-影视行业
- 2024年度供应链管理咨询合作协议
- 2024年度白酒生产原料采购合同
- 2024年度甲乙双方关于纺织工厂建设的借款合同
- 湖北省武汉市汉阳区2024-2025学年九年级上学期期中语文卷
- 中华人民共和国能源法
- 2024-2030年中国冷库及冷风机行业竞争趋势及未来发展策略分析报告
- 华为近三年财务分析报告范文
- 《义务教育数学课程标准(2022年版)》初中内容解读
- 2024浙江省执业药师继续教育答案-中医虚症辨证用药
- 2024年第九届学宪法、讲宪法题库(含答案)
- 2024年广东省公务员录用考试《行测》试题及答案解析
- 浙江省杭州市2025届高三上学期一模英语试题 含答案
- 2025届高三化学一轮复习 原电池 化学电源(第一课时)课件
- 第五单元作文 记述与动物的相处 课件七年级语文上册人教版2024
评论
0/150
提交评论