想要完成一个基本的容器,容器所需要做的六项隔离
Linux 内核中就提供了这六种命名空间(namespace) 隔离的系统调用
序号 | Name space | 系统调用参数 | 隔离内容 |
---|---|---|---|
1 | UTS | CLONE_NEWUTS | 主机名与域名 |
2 | IPC | CLONE_NEWIPC | 信号量、共享内存 |
3 | PID | CLONE_NEWPID | 进程编号 |
4 | Network | CLONE_NEWNET | 网络设备 |
5 | Mount | CLONE_NEWNS | 挂载点、文件系统 |
6 | User | CLONE_NEWUSER | 用户和用户组 |
Linux 内核实现namespace 的主要目的就是为了实现轻量级虚拟化(容器)服务.在同一个namespace 下的进程可以感知彼此的变化,面对外界的进程一无所知,这样就可以让容器中的进程产生错觉
创建虚拟根
[root@es2 ~]# mkdir vroot
[root@es2 ~]# yum -y install --installroot=/root/vroot bash yum coreutils
[root@es2 ~]# cd vroot
[root@es2 vroot]# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
- 查看隔离空间命令的帮助信息命令
[root@es2 ~]# man unshare
[root@es2 ~]# man setns
例如:
- 序号(1) :主机名隔离空间的使用 (以下使用同一台机器,两个终端,以1,2区别)
2]# ushare --uts //开启命名空间
2]# hostname bbb //设置主机名
2]# bash
2]# exit
1]# echo $HOSTNAME //终端2改变了,但是终端1未影响
- 序号(2) : 文件系统mount 与用户user 隔离 unshare --mount
--------- 终端1----------
1]# mount -l // 查看可用的mount 文件
1]# cd /var/tmp
1]# lftp 192.168.1.254
lftp 192.168.1.254:-> ls
lftp 192.168.1.254:/> cd ios/
lftp 192.168.1.254:/iso>get RHEL7-extras.iso
lftp 192.168.1.254:/iso> bye
tmp]# ls
tmp]# unshare --mount
tmp]# mount -t iso9660 -o loop,ro RHEL7-extras.iso /mnt/
tmp]# mount -l | grep iso
--------- 终端2----------
2]# mount -l | grep iso 终端2 看不见
- 序号(3) : IPC & PID 隔离 unshare --pid --ipc --fork --mount --proc /bin/bash
--------- 终端1----------
1]# ps -ef
1]# systemctl stop docker
1]# pstree -p
systemd(1)
1]# unshare --pid --ipc --fork --mount-proc /bin/bash
1]#pstree -p
bash(1)
1]# kill -9 2346 //在终端2上随便找一个进程杀死,由于已隔离,无法杀死
--------- 终端2----------
(下列操作为关闭docker及删除网卡.如果未开启docker ,无需做下面内容)
2]# yum install bridge-utils
2]# ip link set dev docker0 down
2]# ip help link
2]# ip link help link
2]# ip link del link dev docker0
2]# brctl show
2]# ifconfig
- 序号(4) : Network 网络隔离 unshare --net /bin/bash
--------- 终端1---------
1]# ifconfig
--------- 终端2----------
2]# unshare --net /bin/bash
2]# ifconfig //已无网卡
2]# ifconfig -a //仅有本地回环地址
2]# ifconfig lo up //启动回环
制作网络虚拟交换机
1]# ip link add name docker0 type bridge stp_state 1 //docker可改任意名 bridge 虚拟交换机 stp_state 1 打开协议
1]# ifconfig -a
1]# ip link set dev docker0 up //开启虚拟交换机电源
1]# ifconfig
1]# ip addr add 172.17.0.1/16 brd 172.17.255.255 dev docker0 //设置ip地址
1]# ifconfig
制作虚拟网卡(一对两口的设备)
1]# ip link add lnic0 type veth peer name rnic0 //lnic0 本地网卡 rnic0 容器插入网卡
1]# ifconfig -a //能看见,但未使用
1]# ip netns list //查看命名空间
1]# mkdir -p /var/run/netns
1]# cd /var/run/netns
1]# ls
去另一个终端查看命名空间进程
2 ]# echo $$ // (以12345为例)
12345
返回终端
1]# ln -s /proc/12345/ns/net /var/run/netns/12345
1]# ll
1]# ip netns list
1]# ifconfig -a
1]# ip link set rnic0 netns 12345 name eth0
2]# ifconfig -a //会出现eth0
2]# ifconfig eth0 up
1]# ip netns exec 12345 ip addr add dev eth0 172.17.0.2/16 brd 172.17.255.255 //设置ip地址
2]# ifconfig
2]# ping 172.17.0.1 //ping 不通 (虚拟交换机只连接了一头)
1]# ip link set dev lnic0 master docker0 // (设置虚拟交换机连接容器)
1]# ip link set dev lnic0 up //启动
2]# ping 172.17.0.1 //ping 不通 (未开启路由转发)
1]#sysctl -w net.ipv4.ip_forward=1 //开启路由转发
2]# ping 172.17.0.1
2]# ping 192.168.1.254 //ping不通 (未设置网关)
2]# ip route replace default via 172.17.0.1 //设置网关
2]# ping 192.168.1.254 //ping通
2]# pstree -p
systemd(1)
开启并运行容器
完整版1(终端2)
2]# cd vroot/
2]#touch docker //为了区别真实根和虚拟根
2]# ushare --uts --mount --pid --ipc --fork --mount-proc
2]# mount --bind /proc /root/vroot/proc
2]# hostname mydocker
2]# /usr/sbin/chroot /root/vroot
2]# yum install psmisc vim net-tools
2]# ls /
2]# pstree -p
bash(1)
2]# ifconfig
eth0 :172.17.0.2
2]#
完整版2 (终端1)
1]# systemd-nspawn -M aabb -D /root/vroot --network-bridge=docker0
ooxx]# ifconfig -a
ooxx]# yum -y install iproute
ooxx]# ip link set host0 name eth0
ooxx]# ifconfig -a
ooxx]# ifconfig eth0 172.17.0.3/16
ooxx]# ip route replace ddefault via 172.17.0.1
ooxx]# yum provides ping
ooxx]# yum -y install iputils
补充及总结命令
- 没有网卡怎么办?创建虚拟设备,加入命名空间
- ip link add lnic0 type veth peer name rnic0 mkdir -p /var/run/netns
- ln -s /proc/
${PID}/ns/net /var/run/netns/
${PID} - ip link set rnic0 netns ${PID} name eth0
命名空间 加chroot 构建容器
- 创建命名空间vhost
- ip netns add vhost
- ip netns list
- 设置虚拟交换机
- ip link add name docker0 type bridge stp_state 1
- ip link set dev docker0 up
- ip addr add 172.17.0.1/16 brd 172.17.255.255 dev docker0
- 创建虚拟网卡,并添加虚拟交换机
- ip link add name global_nic type veth peer name ns_nic
- ip link set dev global_nic promisc on
- ip link set dev global _nic promisc on
- ip link set dev global_nic master docker0
- 把虚拟网卡添加进命名空间,并设置ip 网关 (vhost为pid号)
- ip link set ns_nic netns vhost name eth0
- ip netns exec vhost ip link set dev lo up
- ip netns exec vhost ip link set dev eth0 up
- ip netns exec vhost ip addr add dev eth0 172.17.0.2/16 brd 172.17.255.255
- 开启路由转发,让命名空间极其可以访问外部网络
- sysctl -w net.ipv4.ip_forward=1
- 创建命名空间,与 根目录,并进入命名空间
- ushare --uts --mount --pid --ipc --fork --mount -proc
- 虚拟目录 映射访问内存
- mount --bind /proc /root/vroot/proc
- 设置主机名
- hostname vhost
- 进入虚拟目录
- ip netns exec vhost /usr/sbin/chroot /root/vroot
这么多步骤太麻烦怎么办?
- 一条命令搞定(利用系统本身的命令)
- systemd-nspawn -M aabb -D /root/vroot --network-bridge=docker0