
你以为你在用Docker?不,你在用Cgroups限制资源。你以为你在用Kubernetes?不,你在用Namespace做隔离。你以为你在用SDN?不,你在用Netfilter劫持网络包。
Cgroups(Control Groups)是Linux内核的"资源配给制"。没有它,Docker无法限制容器CPU,Kubernetes的ResourceQuota就是摆设。
查看当前系统Cgroups挂载点(先看看你家内核支持不):
# 查看Cgroups版本和挂载点
mount | grep cgroup
# 输出示例(v2版本统一挂载)
# cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)
# 如果是v1版本,会看到多个子系统
# tmpfs on /sys/fs/cgroup/cpu type tmpfs (rw,relatime)用Cgroups限制一个进程的CPU和内存(手动创建,不依赖Docker):
#!/bin/bash
# 在Cgroups v2下限制一个进程
# 1. 创建一个控制组(相当于Docker的容器)
sudo mkdir /sys/fs/cgroup/myapp
# 2. 设置CPU限制(只能使用50%的单核)
echo "50000 100000" > /sys/fs/cgroup/myapp/cpu.max
# 格式:quota period,50000/100000 = 50% CPU
# 3. 设置内存限制(最多使用512MB)
echo "536870912" > /sys/fs/cgroup/myapp/memory.max
# 4. 把当前shell进程加入这个控制组
echo $$ > /sys/fs/cgroup/myapp/cgroup.procs
# 5. 现在运行任何命令,都会被限制在50% CPU和512MB内存内
python3 -c "while True: pass" # 这个死循环只能吃50% CPU工程要点拆解:
/sys/fs/cgroup/下,不再分cpu/、memory/子目录exec你的进程验证限制是否生效(用Python动态检测):
# 用Python读取当前进程的Cgroups限制(仅10行)
import os
def get_cgroup_limit():
pid = os.getpid()
with open(f'/proc/{pid}/cgroup', 'r') as f:
# 读取当前进程所在的Cgroups路径
path = f.read().strip().split(':')[-1]
# 读取内存限制
with open(f'/sys/fs/cgroup{path}/memory.max', 'r') as f:
mem_limit = f.read().strip()
return f"Memory limit: {int(mem_limit) // 1024 // 1024} MB"
print(get_cgroup_limit()) # 输出: Memory limit: 512 MBCgroups管资源,Namespace管隔离。Linux有8种Namespace(Mount、UTS、IPC、PID、Network、User、Cgroup、Time),Docker默认用前6种。
核心:Network Namespace是SDN(软件定义网络)的基础
# 创建一个独立的网络命名空间(相当于一个虚拟路由器)
sudo ip netns add myns
# 查看所有命名空间
ip netns list
# 在命名空间内执行命令(完全隔离的网络栈)
sudo ip netns exec myns ip addr
# 输出只有lo(回环接口),没有eth0
# 创建虚拟网卡对(Veth Pair),一端连宿主机,一端进命名空间
sudo ip link add veth0 type veth peer name veth1
sudo ip link set veth1 netns myns
# 给两端配IP,命名空间就能和宿主机通信了
sudo ip addr add 10.0.0.1/24 dev veth0
sudo ip netns exec myns ip addr add 10.0.0.2/24 dev veth1
sudo ip netns exec myns ip link set veth1 up
sudo ip link set veth0 up
# 测试连通性(从宿主机ping命名空间)
ping 10.0.0.2 # 通了!Namespace的真相:
用Go语言创建Namespace(Docker的核心逻辑简化版):
package main
import (
"os"
"os/exec"
"syscall"
)
func main() {
// 这个程序会创建一个新的隔离环境
cmd := exec.Command("/bin/bash")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// 关键:设置Cloneflags,创建新的Namespace
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWNS | // Mount Namespace
syscall.CLONE_NEWUTS | // UTS Namespace(主机名)
syscall.CLONE_NEWPID | // PID Namespace
syscall.CLONE_NEWNET, // Network Namespace
}
cmd.Run() // 进入一个"伪容器"
}编译运行后:
ps aux看不到宿主机的进程(PID隔离)ip addr只有lo(网络隔离)hostname可以随便改(UTS隔离)云计算的负载均衡、安全组、NAT网关,底层都是Netfilter(内核网络钩子)+ iptables(规则表)。
iptables的5条链(数据包在Linux内核中的旅行路线):
# 查看当前防火墙规则(云服务器默认有安全组规则)
sudo iptables -L -v -n
# 关键链解释:
# PREROUTING: 数据包刚进网卡,还没决定去哪
# INPUT: 目标是本机
# FORWARD: 目标是其他机器(宿主机做路由器)
# OUTPUT: 本机发出的包
# POSTROUTING: 数据包即将离开网卡实现一个"云负载均衡器"(用iptables做4层转发,15行搞定):
#!/bin/bash
# 用iptables实现TCP负载均衡(轮询转发到3台后端服务器)
# 1. 开启IP转发(让Linux当路由器)
echo 1 > /proc/sys/net/ipv4/ip_forward
# 2. 配置NAT表转发规则(这就是云负载均衡器的本质)
# 当访问本机80端口时,轮询转发到后端
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 \
-m statistic --mode random --probability 0.33 \
-j DNAT --to-destination 10.0.1.10:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 \
-m statistic --mode random --probability 0.50 \
-j DNAT --to-destination 10.0.1.11:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 \
-j DNAT --to-destination 10.0.1.12:80
# 3. 开启SNAT让返回包能正确回到客户端
sudo iptables -t nat -A POSTROUTING -j MASQUERADE这条命令就是云厂商"负载均衡器"的底层原型,虽然生产环境用LVS或Nginx,但原理一致。
安全组本质(云服务器的防火墙):
# 云控制台点一下"放行80端口",底层执行的就是这条命令
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 拒绝所有其他端口(默认策略)
sudo iptables -P INPUT DROP
# 查看安全组规则(云厂商在宿主机上为每个虚拟机配置了独立规则)
sudo iptables -L INPUT -v -n云计算工程师的看家本领:不用控制台,ssh进机器用命令行查问题。
# 1. 查CPU使用率和负载(判断是否需要扩容)
top -bn1 | head -10
# 或者更简洁
uptime # 看1分钟、5分钟、15分钟负载
# 2. 查内存使用(判断是否OOM)
free -h
cat /proc/meminfo | grep -E "MemTotal|MemAvailable|SwapTotal"
# 3. 查磁盘IO(判断是不是磁盘瓶颈)
iostat -x 1 # 看%util是否接近100%
# 4. 查网络连接数(判断是不是被攻击了)
ss -ant | wc -l # 看总连接数
ss -ant | grep ESTAB | wc -l # 看活跃连接
# 5. 查系统日志(找错误根源)
journalctl -xe -n 50 --no-pager
dmesg | tail -20 # 内核日志,看有没有硬件错误一套组合拳排查"云服务器变慢":
#!/bin/bash
# 30秒快速诊断脚本(工程师必备)
echo "=== CPU负载 ===" && uptime
echo "=== 内存状态 ===" && free -h
echo "=== 磁盘使用 ===" && df -h
echo "=== 磁盘IO ===" && iostat -x 1 2 | grep -A 1 "Device"
echo "=== 网络连接 ===" && ss -s
echo "=== 系统错误 ===" && dmesg | tail -5很多云计算工程师张口Docker、闭口K8s,但连/proc目录下的进程信息都看不懂。
真相:
最后一句忠告:
云计算的上层(容器、编排、服务网格)都在变,但底层永远不变:Linux内核的Cgroups、Namespace、Netfilter。把这三大件吃透,不管你用AWS、Azure还是私有云,都能一眼看穿本质。
附加:用一行命令看透云服务器的"真实身份":
# 看这台"云主机"到底是虚拟机还是容器
cat /proc/1/cgroup
# 如果输出包含 /system.slice/docker-xxx.scope,说明你在容器里
# 如果输出包含 /machine.slice/libvirt-xxx,说明你在KVM虚拟机里
# 如果输出只有 /,那你是物理机或裸金属云这就是Linux云计算的魅力:一切皆文件,一切皆可查。你不需要相信云厂商的宣传,只需要读懂/proc和/sys。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。