第10章 Network Namespace基础
学习目标
- 理解Linux Namespace的隔离机制
- 掌握veth pair的创建和使用
- 了解容器网络的基础实现
- 能够手动构建容器网络环境
🔬 原理
Linux Namespace
Namespace类型:
- net:网络栈隔离
- pid:进程ID隔离
- mount:文件系统挂载点隔离
- uts:主机名隔离
- ipc:进程间通信隔离
- user:用户ID隔离
- cgroup:控制组隔离
网络Namespace特点:
- 独立的网卡列表
- 独立的路由表
- 独立的iptables规则
- 独立的socket
veth pair
veth特点:
- 虚拟网卡对
- 一端发送,另一端接收
- 可在不同Namespace间通信
veth工作原理:
Namespace A Namespace B
| |
veth0 ←────────→ veth1
| |
应用A 应用B
容器网络模型
容器网络需求:
- 容器间通信
- 容器与宿主机通信
- 容器与外网通信
实现方案:
- veth + bridge:经典方案
- macvlan:直接使用物理网卡
- ipvlan:共享物理网卡
- overlay:跨主机通信
️ 实现
Namespace创建
// namespace_create.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/utsname.h>
int main() {
pid_t pid;
// 创建子进程
pid = fork();
if (pid == 0) {
// 子进程:创建新的网络Namespace
if (unshare(CLONE_NEWNET) < 0) {
perror("unshare");
exit(1);
}
// 在新的Namespace中执行命令
execl("/bin/bash", "bash", NULL);
} else if (pid > 0) {
// 父进程:等待子进程
wait(NULL);
} else {
perror("fork");
return 1;
}
return 0;
}
veth pair创建
// veth_create.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_link.h>
int create_veth_pair(const char *name1, const char *name2) {
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0) {
perror("socket");
return -1;
}
// 创建veth pair
struct ifreq ifr;
strcpy(ifr.ifr_name, name1);
ifr.ifr_data = (char*)name2;
if (ioctl(sock, SIOCSIFNAME, &ifr) < 0) {
perror("ioctl");
close(sock);
return -1;
}
close(sock);
return 0;
}
int main() {
if (create_veth_pair("veth0", "veth1") < 0) {
return 1;
}
printf("veth pair created: veth0 <-> veth1\n");
return 0;
}
🛠️ 命令
Namespace管理
# 创建Namespace
sudo ip netns add ns1
# 列出Namespace
ip netns list
# 在Namespace中执行命令
sudo ip netns exec ns1 ip addr show
# 删除Namespace
sudo ip netns del ns1
veth pair管理
# 创建veth pair
sudo ip link add veth0 type veth peer name veth1
# 查看veth pair
ip link show type veth
# 删除veth pair
sudo ip link del veth0
网络配置
# 配置IP地址
sudo ip addr add 10.0.0.1/24 dev veth0
# 启动接口
sudo ip link set veth0 up
# 配置路由
sudo ip route add 10.0.0.0/24 dev veth0
代码
容器网络构建程序
// container_network.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
int create_namespace(const char *name) {
char cmd[256];
snprintf(cmd, sizeof(cmd), "ip netns add %s", name);
return system(cmd);
}
int create_veth_pair(const char *name1, const char *name2) {
char cmd[256];
snprintf(cmd, sizeof(cmd), "ip link add %s type veth peer name %s", name1, name2);
return system(cmd);
}
int move_interface_to_namespace(const char *ifname, const char *nsname) {
char cmd[256];
snprintf(cmd, sizeof(cmd), "ip link set %s netns %s", ifname, nsname);
return system(cmd);
}
int configure_interface(const char *nsname, const char *ifname, const char *ip) {
char cmd[256];
snprintf(cmd, sizeof(cmd), "ip netns exec %s ip addr add %s dev %s", nsname, ip, ifname);
if (system(cmd) != 0) return -1;
snprintf(cmd, sizeof(cmd), "ip netns exec %s ip link set %s up", nsname, ifname);
return system(cmd);
}
int main() {
// 创建两个Namespace
if (create_namespace("ns1") != 0) {
printf("Failed to create ns1\n");
return 1;
}
if (create_namespace("ns2") != 0) {
printf("Failed to create ns2\n");
return 1;
}
// 创建veth pair
if (create_veth_pair("veth1", "veth2") != 0) {
printf("Failed to create veth pair\n");
return 1;
}
// 移动接口到Namespace
if (move_interface_to_namespace("veth1", "ns1") != 0) {
printf("Failed to move veth1 to ns1\n");
return 1;
}
if (move_interface_to_namespace("veth2", "ns2") != 0) {
printf("Failed to move veth2 to ns2\n");
return 1;
}
// 配置IP地址
if (configure_interface("ns1", "veth1", "10.0.0.1/24") != 0) {
printf("Failed to configure veth1\n");
return 1;
}
if (configure_interface("ns2", "veth2", "10.0.0.2/24") != 0) {
printf("Failed to configure veth2\n");
return 1;
}
printf("Container network created successfully!\n");
printf("Test connectivity:\n");
printf("sudo ip netns exec ns1 ping 10.0.0.2\n");
return 0;
}
编译运行:
gcc container_network.c -o container_network
sudo ./container_network
🧪 实验
实验1:创建基础Namespace
目标:创建和配置网络Namespace
步骤:
# 1. 创建Namespace
sudo ip netns add ns1
sudo ip netns add ns2
# 2. 查看Namespace
ip netns list
# 3. 在Namespace中查看网络
sudo ip netns exec ns1 ip addr show
sudo ip netns exec ns2 ip addr show
# 4. 删除Namespace
sudo ip netns del ns1
sudo ip netns del ns2
预期结果:
- 理解Namespace隔离
- 掌握Namespace管理
- 验证网络隔离
实验2:veth pair通信
目标:使用veth pair实现Namespace间通信
步骤:
# 1. 创建Namespace
sudo ip netns add ns1
sudo ip netns add ns2
# 2. 创建veth pair
sudo ip link add veth1 type veth peer name veth2
# 3. 移动接口到Namespace
sudo ip link set veth1 netns ns1
sudo ip link set veth2 netns ns2
# 4. 配置IP地址
sudo ip netns exec ns1 ip addr add 10.0.0.1/24 dev veth1
sudo ip netns exec ns2 ip addr add 10.0.0.2/24 dev veth2
# 5. 启动接口
sudo ip netns exec ns1 ip link set veth1 up
sudo ip netns exec ns2 ip link set veth2 up
# 6. 测试连通性
sudo ip netns exec ns1 ping -c 3 10.0.0.2
sudo ip netns exec ns2 ping -c 3 10.0.0.1
预期结果:
- 理解veth pair原理
- 掌握Namespace间通信
- 验证网络配置
实验3:容器网络构建
目标:构建完整的容器网络环境
步骤:
# 1. 创建Namespace
sudo ip netns add container1
sudo ip netns add container2
sudo ip netns add container3
# 2. 创建veth pair
sudo ip link add veth1 type veth peer name veth1-br
sudo ip link add veth2 type veth peer name veth2-br
sudo ip link add veth3 type veth peer name veth3-br
# 3. 创建bridge
sudo ip link add br0 type bridge
sudo ip link set br0 up
# 4. 连接veth到bridge
sudo ip link set veth1-br master br0
sudo ip link set veth2-br master br0
sudo ip link set veth3-br master br0
sudo ip link set veth1-br up
sudo ip link set veth2-br up
sudo ip link set veth3-br up
# 5. 移动veth到Namespace
sudo ip link set veth1 netns container1
sudo ip link set veth2 netns container2
sudo ip link set veth3 netns container3
# 6. 配置IP地址
sudo ip netns exec container1 ip addr add 10.0.0.1/24 dev veth1
sudo ip netns exec container2 ip addr add 10.0.0.2/24 dev veth2
sudo ip netns exec container3 ip addr add 10.0.0.3/24 dev veth3
# 7. 启动接口
sudo ip netns exec container1 ip link set veth1 up
sudo ip netns exec container2 ip link set veth2 up
sudo ip netns exec container3 ip link set veth3 up
# 8. 测试连通性
sudo ip netns exec container1 ping -c 3 10.0.0.2
sudo ip netns exec container1 ping -c 3 10.0.0.3
sudo ip netns exec container2 ping -c 3 10.0.0.3
预期结果:
- 理解容器网络架构
- 掌握bridge配置
- 验证多容器通信
实验4:外网访问配置
目标:配置容器访问外网
步骤:
# 1. 启用IP转发
sudo sysctl -w net.ipv4.ip_forward=1
# 2. 配置NAT
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/24 ! -o br0 -j MASQUERADE
# 3. 配置默认路由
sudo ip netns exec container1 ip route add default via 10.0.0.1
sudo ip netns exec container2 ip route add default via 10.0.0.1
sudo ip netns exec container3 ip route add default via 10.0.0.1
# 4. 测试外网访问
sudo ip netns exec container1 ping -c 3 8.8.8.8
sudo ip netns exec container1 nslookup google.com
预期结果:
- 理解NAT配置
- 掌握外网访问
- 验证网络功能
排错
常见问题排查
问题1:Namespace创建失败
# 检查权限
sudo ip netns add ns1
# 检查Namespace数量限制
cat /proc/sys/user/max_user_namespaces
# 增加限制
sudo sysctl -w user.max_user_namespaces=10000
问题2:veth pair创建失败
# 检查接口名称冲突
ip link show
# 使用不同的名称
sudo ip link add veth0 type veth peer name veth1
# 检查内核支持
modprobe veth
问题3:Namespace间无法通信
# 检查接口状态
sudo ip netns exec ns1 ip link show
# 检查IP配置
sudo ip netns exec ns1 ip addr show
# 检查路由
sudo ip netns exec ns1 ip route show
排错清单
- [ ] 检查Namespace创建(ip netns list)
- [ ] 验证veth pair状态(ip link show)
- [ ] 确认IP配置(ip addr show)
- [ ] 检查路由表(ip route show)
- [ ] 测试连通性(ping、telnet)
- [ ] 查看系统日志(dmesg、/var/log/syslog)
- [ ] 检查权限(sudo、用户组)