推薦-Linux Namespace的一點理解

    下文的原文來自: http://blog.csdn.net/preterhuman_peak/article/details/40857117
    原文寫的非常好,下文中大部分文字描述來自原文,我僅做了一點理解性的插圖和實驗部分。

    由于本人水平有限,無法做到面面俱到,下文所寫均為我全部所知,簡略之處必是我涉足尚淺之處。還請觀者多給意見,我十分愿意彌補不足。

LinuxNamespace簡圖.png

采用Namespace的方式
1.全局資源通過命名空間來抽象,將各種全局資源放入容器中,實現隔離,但在容器外將不能為這些全局資源提供唯一性的ID.
2.本質上,命名空間建立了系統的不同視圖. 【注:命名空間就是一個容器.】
3.此前的每一項全局資源都必須包裝到容器數據結構中,只有資源和包含資源的命名空間構成的二元組仍然是全局唯一的。
4.隔離可讓容器間毫無關系,也允許容器間進行適度共享。
5. Chroot就是一種簡單的容器隔離機制。

       命名空間的實現需要兩個部分:每個子系統的命名空間結構,將此前所有的全局組件包裝到命名空間中;將給定進程關聯到所屬各個命名空間的機制。圖 2說明了具體情形。

<nsproxy.h>
struct nsproxy {
       atomic_t count;
       struct uts_namespace *uts_ns;
       struct ipc_namespace *ipc_ns;
       struct mnt_namespace *mnt_ns;
       struct pid_namespace *pid_ns;
       struct user_namespace *user_ns;
       struct net *net_ns;
};

PID Namespace

        PIDNamespace簡圖.png    

    當調用clone時,設定了CLONE_NEWPID,就會創建一個新的PID Namespace,clone出來的新進程將成為Namespace里的第一個進程。一個PID Namespace為進程提供了一個獨立的PID環境,PID Namespace內的PID將從1開始,在Namespace內調用fork,vfork或clone都將產生一個在該Namespace內獨立的PID。新創建的Namespace里的第一個進程在該Namespace內的PID將為1,就像一個獨立的系統里的init進程一樣。該Namespace內的孤兒進程都將以該進程為父進程,當該進程被結束時,該Namespace內所有的進程都會被結束。PID Namespace是層次性,新創建的Namespace將會是創建該Namespace的進程屬于的Namespace的子Namespace。子Namespace中的進程對于父Namespace是可見的,一個進程將擁有不止一個PID,而是在所在的Namespace以及所有直系祖先Namespace中都將有一個PID。系統啟動時,內核將創建一個默認的PID Namespace,該Namespace是所有以后創建的Namespace的祖先,因此系統所有的進程在該Namespace都是可見的。

IPC Namespace

    當調用clone時,設定了CLONE_NEWIPC,就會創建一個新的IPC Namespace,clone出來的進程將成為Namespace里的第一個進程。一個IPC Namespace有一組System V IPC objects 標識符構成,這標識符有IPC相關的系統調用創建。在一個IPC Namespace里面創建的IPC object對該Namespace內的所有進程可見,但是對其他Namespace不可見,這樣就使得不同Namespace之間的進程不能直接通信,就像是在不同的系統里一樣。當一個IPC Namespace被銷毀,該Namespace內的所有IPC object會被內核自動銷毀。

    PID Namespace和IPC Namespace可以組合起來一起使用,只需在調用clone時,同時指定CLONE_NEWPID和CLONE_NEWIPC,這樣新創建的Namespace既是一個獨立的PID空間又是一個獨立的IPC空間。不同Namespace的進程彼此不可見,也不能互相通信,這樣就實現了進程間的隔離。
注:
<1> IPC
       IPC(Inter-Process Communication)是共享"命名管道"的資源,它是為了讓進程間通信而開放的命名管道,通過提供可信任的用戶名和口令,連接雙方可以建立安全的通道并以此通道進行加密數據的交換,從而實現對遠程計算機的訪問。IPC是NT/2000的一項新功能,它有一個特點,即在同一時間內,兩個IP之間只允許建立一個連接。
          IPC原理簡圖.png

<2> System V
    System V和POSIX類似,但POSIX是專注于Linux系統設計的標準化.而System V和BSD則是UNIX設計標準化的一種范本.
    System V它是AT&T公司開發的UNIX系統,是UNIX眾多版本中的一種,AT&T共發行了4個版本,System V4是最成功的,它采用SysV初始化腳本(/etc/init.d)來控制啟停系統,System V Interface Definition(SVID)是SystemV如何工作的標準定義.

mount Namespace

    當調用clone時,設定了CLONE_NEWNS,就會創建一個新的mount Namespace。每個進程都存在于一個mount Namespace里面,mount Namespace為進程提供了一個文件層次視圖。如果不設定這個flag,子進程和父進程將共享一個mount Namespace,其后子進程調用mount或umount將會影響到所有該Namespace內的進程。如果子進程在一個獨立的mount Namespace里面,就可以調用mount或umount建立一份新的文件層次視圖。該flag配合pivot_root系統調用,可以為進程創建一個獨立的目錄空間。

Network Namespace

    當調用clone時,設定了CLONE_NEWNET,就會創建一個新的Network Namespace。一個Network Namespace為進程提供了一個完全獨立的網絡協議棧的視圖。包括網絡設備接口,IPv4和IPv6協議棧,IP路由表,防火墻規則,sockets等等。一個Network Namespace提供了一份獨立的網絡環境,就跟一個獨立的系統一樣。一個物理設備只能存在于一個Network Namespace中,可以從一個Namespace移動另一個Namespace中。虛擬網絡設備(virtual network device)提供了一種類似管道的抽象,可以在不同的Namespace之間建立隧道。利用虛擬化網絡設備,可以建立到其他Namespace中的物理設備的橋接。當一個Network Namespace被銷毀時,物理設備會被自動移回init Network Namespace,即系統最開始的Namespace。

UTS Namespace

    當調用clone時,設定了CLONE_NEWUTS,就會創建一個新的UTS Namespace。一個UTS Namespace就是一組被uname返回的標識符。新的UTS Namespace中的標識符通過復制調用進程所屬的Namespace的標識符來初始化。Clone出來的進程可以通過相關系統調用改變這些標識符,比如調用sethostname來改變該Namespace的hostname。這一改變對該Namespace內的所有進程可見。CLONE_NEWUTS和CLONE_NEWNET一起使用,可以虛擬出一個有獨立主機名和網絡空間的環境,就跟網絡上一臺獨立的主機一樣。

    以上所有clone flag都可以一起使用,為進程提供了一個獨立的運行環境。LXC正是通過clone時設定這些flag,為進程創建一個有獨立PID,IPC,FS,Network,UTS空間的container。一個container就是一個虛擬的運行環境,對container里的進程是透明的,它會以為自己是直接在一個系統上運行的。一個container就像傳統虛擬化技術里面的一臺安裝了OS的虛擬機,但是開銷更小,部署更為便捷。

    Linux Namespaces機制本身就是為了實現 container based virtualizaiton開發的。它提供了一套輕量級、高效率的系統資源隔離方案,遠比傳統的虛擬化技術開銷小,不過它也不是完美的,它為內核的開發帶來了更多的復雜性,它在隔離性和容錯性上跟傳統的虛擬化技術比也還有差距。

下面對Network Namespace在進行實踐介紹:
測試拓撲:

        NetworkNamespace拓撲圖.png

創建基本環境:

   (1) 創建虛擬設備:

            ip  netns  server         #創建虛擬server設備,其實就是創建一個子network namespace.
            ip  netns  router
            ip  netns  client
          
            ip netns list          #查看創建的Network namespace(虛擬設備)
                router
                server
                client

               
   (2) 創建虛擬接口并用虛擬網線將其連接:

            # 注:這些虛擬接口默認被添加到默認network namespace中.
            #     默認network namespace就是當前OS的network namespace,
            #     它是所有其他network namespace的父命名空間(容器)。
            ip  link  add  vethS  type  veth  peer  name  veth-srv
            ip  link  add  vethC  type  veth  peer  name  veth-cli
            
            ip link show |grep veth         #查看創建的虛擬接口
                15: veth-srv: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
                16: vethS: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
                17: veth-cli: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
                18: vethC: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000

   (3) 將虛擬接口綁定到各虛擬設備上:

              ip  link  set vethS netns   server       #將vethS綁定到Server上.
              ip  link  set veth-srv netns  router     #將veth-srv綁定到Router上.
              ip  link  set vethC netns   client    
              ip  link  set veth-cli netns  router
              
           # 注: ip  netns  exec <NetNamesapce_Name>  <Command>      #在指定Network Namespace中執行命令的格式.
               ip netns exec server ip link             # 查看Server上綁定的接口狀態.
                    11: lo: <LOOPBACK> mtu 16436 qdisc noop state DOWN 
                        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
                    16: vethS: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
                        link/ether 3a:0f:10:f6:09:eb brd ff:ff:ff:ff:ff:ff
                        
               ip netns exec router ip link            # 查看Router上綁定的接口狀態。
                    14: lo: <LOOPBACK> mtu 16436 qdisc noop state DOWN 
                        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
                    15: veth-srv: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
                        link/ether 2a:81:99:26:1c:15 brd ff:ff:ff:ff:ff:ff
                    17: veth-cli: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
                        link/ether b6:2a:b8:16:d8:b8 brd ff:ff:ff:ff:ff:ff

   (4) 為虛擬接口配置IP并啟動接口

       # 為虛擬Server的虛擬接口配置IP并啟動
            ip netns exec server ip addr add 10.0.1.2/24 dev vethS
            ip netns exec server ip addr add 1.1.1.1/24  dev  lo        #給loopback接口配置IP
            ip netns exec server ip link set dev vethS up               #開啟虛擬Server的vethS接口
            ip netns exec server ip link set dev  lo  up 
            
            ip netns exec server ip a
                11: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
                    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
                    inet 127.0.0.1/8 scope host lo
                    inet 1.1.1.1/24 scope global lo
                    inet6 ::1/128 scope host 
                       valid_lft forever preferred_lft forever
                # 注: vethS這里需要注意:<...UP:此表示vethS當前已為活動狀態>; 
                #       state DOWN:表示對端當前為不活動,這是因為router還沒配IP也沒啟動.
                16: vethS: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
                    link/ether 3a:0f:10:f6:09:eb brd ff:ff:ff:ff:ff:ff
                    inet 10.0.1.2/24 scope global vethS
                    
         # 為虛擬Router的虛擬接口配置IP并啟動.
            ip netns exec router ip addr add 10.0.1.1/24 dev veth-srv
            ip netns exec router ip addr add 10.0.2.1/24 dev veth-cli
            ip netns exec router ip link set dev veth-srv up
            ip netns exec router ip link set dev veth-cli up
            ip netns exec router sysctl -w net.ipv4.ip_forward=1        #開啟Router的轉發功能.以便模擬路由器.
            
        # 為虛擬Client的虛擬接口配置IP并啟動:
            ip netns exec client ip addr add 10.0.2.2/24 dev vethC
            ip netns exec client ip addr add 2.2.2.2/24 dev lo
            ip netns exec client ip link set dev vethC up   
            ip netns exec client ip link set dev lo up

   (5) 連通性測試

          ip netns exec server ping -c 2   1.1.1.1                # Server 測試 ping環回口.
                PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
                64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.197 ms
                64 bytes from 1.1.1.1: icmp_seq=2 ttl=64 time=0.067 ms
           ip netns exec server ping  -c 2 10.0.1.1              # Server測試ping Router的直連接口
                PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
                64 bytes from 10.0.1.1: icmp_seq=1 ttl=64 time=0.868 ms
                64 bytes from 10.0.1.1: icmp_seq=2 ttl=64 time=0.078 ms
          ip netns exec client ping 10.0.2.1                     # Client測試ping Router的直連接口
                PING 10.0.2.1 (10.0.2.1) 56(84) bytes of data.
                64 bytes from 10.0.2.1: icmp_seq=1 ttl=64 time=1.14 ms
                64 bytes from 10.0.2.1: icmp_seq=2 ttl=64 time=0.082 ms
          ip netns exec client ping 10.0.1.1                #Client測試ping Server端,不通
                connect: Network is unreachable

   (6) 在虛擬Server和Client上添加默認路由:

         # 上面測試可知Server和Client是無法到達彼此的,它們只能訪問到直連的Router.         
         ip netns exec client route add default gw 10.0.2.1      #給Client添加默認路由,指向Router.
         
         ip netns exec client ping 10.0.1.2       # 再次測試ping Server_IP,還是不通,這是因為Server不知道如何到達Client.            
         PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.            
             ^C  
             
         ip netns exec server route add default gw 10.0.1.1        #給Server添加默認路由.                   
         ip netns exec server ping 10.0.2.2            # 再次測試ping Client_IP 已經可以ping通. 
          PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data.          
          64 bytes from 10.0.2.2: icmp_seq=1 ttl=63 time=3.11 ms           
          64 bytes from 10.0.2.2: icmp_seq=2 ttl=63 time=0.102 ms                   
          
        ip netns exec server ping 2.2.2.2              # 但ping Client的loopback接口還是不通.     
         PING 2.2.2.2 (2.2.2.2) 56(84) bytes of data.            
         From 10.0.1.1 icmp_seq=1 Destination Net Unreachable            
         From 10.0.1.1 icmp_seq=2 Destination Net Unreachable

   (7) 為虛擬Router添加靜態路由

        #注: 指定到達1.1.1.0/24的網絡從接口10.0.1.1發出。
            ip netns exec router ip route add 1.1.1.0/24 via 10.0.1.1  
            ip netns exec router ip route add 2.2.2.0/24 via 10.0.2.1      
         
            ip netns exec router ip -s -s route list        #顯示虛擬Router上詳細的路由表條目.
                10.0.1.0/24 dev veth-srv  proto kernel  scope link  src 10.0.1.1 
                2.2.2.0/24 via 10.0.2.1 dev veth-cli 
                10.0.2.0/24 dev veth-cli  proto kernel  scope link  src 10.0.2.1 
                1.1.1.0/24 via 10.0.1.1 dev veth-srv   
           ip netns exec router route -n                #或直接使用route命令來查看路由表
                Kernel IP routing table
                Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
                10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 veth-srv
                2.2.2.0         10.0.2.1        255.255.255.0   UG    0      0        0 veth-cli
                10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 veth-cli
                1.1.1.0         10.0.1.1        255.255.255.0   UG    0      0        0 veth-srv    
    
          #再次從Server上測試
           ip netns exec server ping 2.2.2.2
                PING 2.2.2.2 (2.2.2.2) 56(84) bytes of data.
                64 bytes from 2.2.2.2: icmp_seq=1 ttl=63 time=5.06 ms
                64 bytes from 2.2.2.2: icmp_seq=2 ttl=63 time=0.101 ms
           ip netns exec client ping 1.1.1.1
                PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
                64 bytes from 1.1.1.1: icmp_seq=1 ttl=63 time=1.87 ms
                64 bytes from 1.1.1.1: icmp_seq=2 ttl=63 time=0.100 ms

   (8) 進一步測試SNAT.

      # 注:上面是假設知道怎么去未知網絡,因此采用了靜態路由。
      #    下面假設不知道怎么去未知網絡,因此下面采用NAT的方式讓Server訪問到Client的2.2.2.0/24的網絡。
        《1》先刪除Router添加的靜態路由
                ip netns exec router ip route del 1.1.1.0/24
                ip netns exec router ip route del 2.2.2.0/24
                
        《2》在Router上添加一條全局默認路由:
                # 注:這里測試讓Server可以ping 通Client的loopback接口.
                # 另注: 默認路由一次只能加一個來測試.
                ip netns exec router ip route add default scope global via 10.0.2.2
                
        《3》在Router上添加一條iptables的SNAT規則:
                ip netns exec router iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -o veth-cli -j SNAT --to-source 10.0.2.1
                
        《4》從Server上測試ping  Client_Loopback_IP
                ip netns exec server ping 2.2.2.2 -c 2
                    PING 2.2.2.2 (2.2.2.2) 56(84) bytes of data.
                    64 bytes from 2.2.2.2: icmp_seq=1 ttl=63 time=0.068 ms
                    64 bytes from 2.2.2.2: icmp_seq=2 ttl=63 time=0.099 ms
                    
                ip netns exec server ip route          #Server上的路由表
                        10.0.1.0/24 dev vethS  proto kernel  scope link  src 10.0.1.2 
                        default via 10.0.1.1 dev vethS 
                        
                ip netns exec client ip route           #Client上的路由表
                        10.0.2.0/24 dev vethC  proto kernel  scope link  src 10.0.2.2 
                        default via 10.0.2.1 dev vethC 
                        
                 ip netns exec router ip route          #Router上的路由表
                    10.0.1.0/24 dev veth-srv  proto kernel  scope link  src 10.0.1.1 
                    10.0.2.0/24 dev veth-cli  proto kernel  scope link  src 10.0.2.1 
                    default via 10.0.2.2 dev veth-cli   #這是在Router上添加的默認路由,出口是veth-cli.
                
                 ip netns exec router iptables -nL -v -t nat        #Router上的SNAT規則查看.
                        Chain PREROUTING (policy ACCEPT 4 packets, 336 bytes)
                         pkts bytes target     prot opt in     out     source               destination         
                        Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
                         pkts bytes target     prot opt in     out     source               destination         
                        
                             # 此為添加的SNAT規則
                            1    84 SNAT       all  --  *      veth-cli  10.0.1.0/24          0.0.0.0/0           to:10.0.2.1   
                        Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
                         pkts bytes target     prot opt in     out     source               destination         
                
                ip netns exec router iptables -nL -vv -t nat        #查看NAT的詳細信息
                        Chain PREROUTING (policy ACCEPT 4 packets, 336 bytes)
                         pkts bytes target     prot opt in     out     source               destination         
                        Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
                         pkts bytes target     prot opt in     out     source               destination         
                            1    84 SNAT       all  --  *      veth-cli  10.0.1.0/24          0.0.0.0/0           to:10.0.2.1 
                        Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
                         pkts bytes target     prot opt in     out     source               destination         
                        libiptc vlibxtables.so.4. 800 bytes.
                        Table `nat'
                        Hooks: pre/in/fwd/out/post = 0/ffffffff/ffffffff/1d8/98
                        Underflows: pre/in/fwd/out/post = 0/ffffffff/ffffffff/1d8/140
                        Entry 0 (0):
                        SRC IP: 0.0.0.0/0.0.0.0
                        DST IP: 0.0.0.0/0.0.0.0
                        Interface: `'/................to `'/................
                        Protocol: 0
                        Flags: 00
                        Invflags: 00
                        Counters: 4 packets, 336 bytes
                        Cache: 00000000
                        Target name: `' [40]
                        verdict=NF_ACCEPT
                        Entry 1 (152):
                        
                        SRC IP: 10.0.1.0/255.255.255.0
                        DST IP: 0.0.0.0/0.0.0.0
                        Interface: `'/................to `veth-cli'/XXXXXXXXX.......
                        Protocol: 0
                        Flags: 00
                        Invflags: 00
                        Counters: 1 packets, 86 bytes    #請注意這里
                        Cache: 00000000
                        Target name: `SNAT' [56]
                        
                        .......  下面內容省略。

   (9) 清理測試環境

           ip  netns  del  server
           ip  netns  del  router
           ip  netns  del  client

原創文章,作者:Wn1m,如若轉載,請注明出處:http://www.www58058.com/13656

(1)
Wn1mWn1m
上一篇 2016-03-28
下一篇 2016-03-29

相關推薦

  • N25期—第二周作業

    1、  Linux上的文件管理類命令都有哪些,其常用的使用方法及其相關示例演示。   一、文件權限管理類命令  chown:改變文件所有者  chown [OPTION]… [OWNER][:[GROUP]] FILE…  常用參數 -R:遞歸修改(改目錄就改目錄中的目錄及文件) &n…

    Linux干貨 2016-12-11
  • linux命令 kill命令詳則

    kill命令 kill用來刪除執行中的程序或工作。kill可將指定的信息送至程序。預設的信息(默認)為SIGTERM(15),可經指定程序終止。若仍無法終止該程序,可使用SIGKILL(9)信息嘗試強制刪除程序。程序或工作的編號可利用ps指令或job指令查看。 語法 kill(選項)(參數) 選項 -a:當處理當前進程時,不限制命令名和進程號的對應關系; &…

    2017-08-21
  • 網絡設備及工作

    集線器集線器又叫Hub,是一種多用于星形網絡組織的中心設備。具備中繼器放大信號的特點,集線器是一種半雙工,同一時間只能接收或發送數據,不能同時既接受又發送數據,是沖突型設備,共享帶寬,放大信號的同時放大噪聲,不隔離廣播,不能成環,不安全。 二層交換機二層交換機的工作原理能自學習構造MAC地址表,基于MAC地址表進行轉發、劃分沖突域,對MAC地址實現過濾等功能…

    Linux干貨 2017-10-30
  • haproxy實戰之haproxy實現mysql負載均衡

    haproxy實戰之haproxy實現mysql負載均衡 實驗目的haproxy + mysql實現負載均衡 1.準備機器,做好時間同步,域名主機名解析 192.168.42.151 [node2 haproxy] 192.168.42.152 [node3 mariadb] 192.168.42.153 [node4 mariadb] 2.node3,no…

    Linux干貨 2017-06-29
  • N22-第二周作業-對Linux的基礎操作命令的理解及用法示例

    1、Linux上的文件管理類命令都有哪些,其常用的使用方法及其相關示例演示。 Linux上文件管理類命令常用的有:pwd、ls、cd、cp、touch、mv、rm、rmdir   1)pwd:顯示當前工作目錄     2)ls:列出指定目錄下的內容    常用的選項有:   -a:列出目錄中的所有文…

    Linux干貨 2016-08-22

評論列表(1條)

  • stanley
    stanley 2016-03-28 23:21

    圖很專業,繪圖對于加深理解非常有效

欧美性久久久久