虚拟化

半虚拟化

cpu:xen
I/O: xen ->net,blk
     KVM -> virtio
     完全虚拟化:HVM
     Memory:
        ->影子页表(shadow page table)
        ->英特尔EPT技术:快速虚拟缩影

常见的网络技术

  • 桥接类型:虚拟机借助于物理网卡和外部主机进行通信

  • 隔离:如vmare上使用的虚拟通道技术,专用的虚拟通道网络

  • 路由:将隔离模型中的接口的桥设备上面添加一对网卡或者附着在虚拟机网卡之上,跨主机之间需要有明确的路由表

  • NAT:在路由模型之上添加地址转换规则

  • 虚拟机管理工具:http://www.linux-kvm.org/page/Management_Tools

网络虚拟化

  • OpenVswitch:虚拟交换机技术,模拟一个全功能的交换机技术

  • VLAN,VXLAN(软隔离):虚拟局域网,通过一个交换机连接所有机器在一个lan中,同一个lan中的所有机器都在同一个广播域中,广播帧所能到达的范围,帧为mac地址封装后的,单播不确定的/多播帧都可以在同一个lan中(基于广播的协议DHCP,ARP等)广播多会消耗网络带宽及其性能,路由分割广播域。

    • Vlan的实现:基于MAC地址实现/交换机实现/IP地址实现/用户实现
  • 交换机接口的类型 -> 访问链接(access link)/汇聚链接(trunc link)

  • Vlan的汇聚方式:IEEE 802.1q协议(vlan专用)/ ISL(Inter Switch Link私有的思科协议)

Vlan之间的路由

  • 访问链接(router为每一个vlan提供一个接口)/汇聚链接(router只向交换机提供一个接口)

  • 三层交换机(路由模块基于交换模块汇聚在一起指明路由地址方式叫3层交换机)

modinfo 8021q   #查看协议
modprobe 8021q  #内核使用协议可以跨vlan配置
yum info vconfig    #用于实现配置和调整8021q的协议
ls /proc/net/vlan   #vlan配置

主机虚拟化的类型

  • TYPE-I
    • 在硬件级别的直接运行hypervisor -> xen/vmware ESX/ESXI
  • TYPE-II
    • 在硬件级别运行一个OS(Host OS),再在OS上运行一个VMM -> Vmware Workstation/Virtualbox

Linux目前最流行的开源虚拟化技术解决方案

  • 主机级别虚拟化 -> xen/kvm/virtualbox

  • 容器级 -> lxc/libcontainer/runC/openvz

  • 模拟器 -> qemu

KVM的组件

  • kvm.ko 内核模块 -> API

  • qemu-kvm(初始2M程序就可以模拟所有的系统级别组件,后被kvm采用后二次开发) -> 用户空间的工具程序

  • libvirt -> C/S架构提供操作系统之间相互的交互的(libvirt-client+virt-manager/libvir-daemon)

快速使用

grep -E -i "(svm|vmx)" /proc/cpuinfo    #查看是否支持虚拟化
modinfo kvm
lsmod | grep kvm
ls -lh /dev/kvm #查看是否可以使用KVM

Linux内核

nameSpace -> 主要用于隔离
    文件系统隔离
    网络隔离:网络资源的隔离包括网络设备IP地址(V4/V6),ip路由表防火墙/proc/net /sys/class/net 套接字等,虚拟以太网设备来模拟实现功能
    IPC隔离:同一个名称空间内的进程间通信,跨名称空间不通信
    用户和用户组隔离:docker都尚未实现,不安全用映射来实现
    PID隔离:对名称空间的PID重新标号,两个不同的名称空间可以使用相同的PID
    UTS隔离:Unix Time-Sharing System,提供主机名称和域名隔离

Cgroup -> 用于被namespace隔离的完成资源的配置,完成操作任务,资源计算权重设置管理任务等

linux中的隔离

User Namespace

User Namespace用来隔离用户和组ID,也就是说一个进程在Namespace里的用户和组ID与它在host里的ID可以不一样,这样说可能读者还不理解有什么实际的用处。User Namespace最有用的地方在于,host的普通用户进程在容器里可以是0号用户,也就是root用户。这样,进程在容器内可以做各种特权操作,但是它的特权被限定在容器内,离开了这个容器它就只有普通用户的权限了。

UTS Namespace

UTS Namespace用于对主机名和域名进行隔离,也就是uname系统调用使用的结构体struct utsname里的nodename和domainname这两个字段,UTS这个名字也是由此而来的。
那么,为什么要使用UTS Namespace做隔离?这是因为主机名可以用来代替IP地址,因此,也就可以使用主机名在网络上访问某台机器了,如果不做隔离,这个机制在容器里就会出问题。

golang实现隔离

package main

import (
    "log"
    "os"
    "os/exec"
    "syscall"
)

func main() {
    //指定被fork出来的新进程内的初始化命令
    cmd := exec.Command("sh")
    //使用Cloneflags标识符创建UTS
    cmd.SysProcAttr = & syscall.SysProcAttr{
        Cloneflags: syscall.CLONE_NEWUTS,
    }
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    if err := cmd.Run();err != nil {
        log.Fatal(err)
    }
}
  • syscall.CLONE_NEWUTS()

IPC Namespace

IPC是Inter-Process Communication的简写,也就是进程间通信。Linux提供了很多种进程间通信的机制,IPC Namespace针对的是SystemV IPC和Posix消息队列。这些IPC机制都会用到标识符,例如用标识符来区别不同的消息队列,然后两个进程通过标识符找到对应的消息队列进行通信等。
IPC Namespace能做到的事情是,使相同的标识符在两个Namespace中代表不同的消息队列,这样也就使得两个Namespace中的进程不能通过IPC进程通信了。

  • 宿主机中

  • 创建的容器中

  • syscall.CLONE_NEWIPC()

  • 新创建的容器中无法查看到宿主机的message queue,实现了IPC Namespace的进程通讯隔离

PID Namespace

PID Namespace是用来隔离进程ID的。同样一个进程在不同的PIDNamespace里可以拥有不同的PID。这样就可以理解,在docker container 里面,使用ps-ef经常会发现,在容器内,前台运行的那个进程PID是1,但是在容器外,使用ps-ef会发现同样的进程却有不同的PID,这就是PIDNamespace做的事情。以下的真实ID=16065但是在容器中看到的是1

  • syscall.CLONE_NEWPID

Mount namespace

Mount namespace通过隔离文件系统挂载点对隔离文件系统提供支持,它是历史上第一个Linux namespace,所以它的标识位比较特殊,就是CLONE_NEWNS。隔离后,不同mount namespace中的文件结构发生变化也互不影响。你可以通过/proc/[pid]/mounts查看到所有挂载在当前namespace中的文件系统,还可以通过/proc/[pid]/mountstats看到mount namespace中文件设备的统计信息,包括挂载文件的名字、文件系统类型、挂载位置等等。

  • 进程在创建mount namespace时,会把当前的文件结构复制给新的namespace。

  • 新namespace中的所有mount操作都只影响自身的文件系统,而对外界不会产生任何影响。这样做非常严格地实现了隔离,但是某些情况可能并不适用。

  • 比如父节点namespace中的进程挂载了一张CD-ROM,这时子节点namespace拷贝的目录结构就无法自动挂载上这张CD-ROM,因为这种操作会影响到父节点的文件系统。

  • 在不同的Namespace中看到的文件系统的层次是不同的,MountNameSpace中调用mount()/Unmount影响只是当前所处的Namespace.如:chroot()可以把一个目标变成根目录MountNamespace更加的彻底和灵活

在当前的Namespace中,sh进程是PID为1的进程。这就说明,当前的Mount Namespace中的mount和外部空间是隔离的,mount操作并没有影响到外部。Docker volume也是利用了这个特性。

Linux Network NameSpace

netns在内核实现,其控制功能由iproute所提供的netns的Objcet提供.这个Namespace会对网络相关的系统资源进行隔离,每个Network Namespace都有自己的网络设备、IP地址、路由表、/proc/net目录、端口号等。网络隔离的必要性是很明显的,举一个例子,在没有隔离的情况下,如果两个不同的容器都想运行同一个Web应用,而这个应用又需要使用80端口,那就会有冲突了。

linux中的资源限制

使用netns
ip netns list
ip netns add name
ip netns del name
ip netns

1.设置网桥
brctl addbr 名称
2.开启网卡
ip link set 名称 up
ifconfig
3.移除之前的网卡
ip addr del IP/掩码 dev 网卡
4.添加网桥绑定
ip addr IP/掩码 dev 名称
brctl addif 名称 网卡
5.创建内部桥接
brctl addbr 名称
6.up起来
ip link set 名称 up
开启路由转发
echo "net.ipv4.ip_forward = 1">>/etc/sysctl.conf
sysctl -p   刷新信息
7.查看当前的网桥信息
ip netns list
8.创建一堆虚拟网卡
ip link add type veth1.x veth peer name veth1.x
ip link show    查看信息
9.加入各自的名称空间中
ip link set veth1.x netns 网桥名称
ip link set veth1.x netns 网桥名称
ip link show    会发现创建的虚拟网卡消失了
10.去各自的名称空间查看相应的虚拟网卡
ip netns exec 网桥名称 ifconfig -a

发表评论

电子邮件地址不会被公开。 必填项已用*标注