Linux内核中的容器技术详解

张开发
2026/4/10 18:47:03 15 分钟阅读

分享文章

Linux内核中的容器技术详解
Linux内核中的容器技术详解引言容器技术是现代云计算和DevOps的基础Linux内核通过namespace和cgroups等机制实现了容器化隔离。本文将深入探讨Linux容器技术的底层实现原理包括资源隔离、容器编排和容器安全等方面。容器技术概述1. 容器 vs 虚拟机特性容器虚拟机启动时间秒级分钟级资源占用低高隔离级别进程级硬件级性能接近原生有损耗2. 容器生态Docker最流行的容器平台PodmanDocker的无守护进程替代品containerd容器运行时runc容器运行器Kubernetes容器编排平台Linux内核支持1. 必需的内核配置# 检查内核支持 grep -E CONFIG_NAMESPACES|CONFIG_CGROOPS|CONFIG_OVERLAY_FS /boot/config-$(uname -r) # 必需的配置选项 CONFIG_NAMESPACESy CONFIG_UTS_NSy CONFIG_IPC_NSy CONFIG_PID_NSy CONFIG_NET_NSy CONFIG_CGROUPSy CONFIG_CGROUP_NSy CONFIG_OVERLAY_FSy2. 内核模块# 加载必要的模块 modprobe overlay modprobe br_netfilter # 检查已加载的模块 lsmod | grep -E overlay|bridge|iptablenamespace隔离1. namespace类型#define CLONE_NEWNS 0x00020000 // Mount namespace #define CLONE_NEWUTS 0x04000000 // UTS namespace #define CLONE_NEWIPC 0x08000000 // IPC namespace #define CLONE_NEWPID 0x20000000 // PID namespace #define CLONE_NEWNET 0x40000000 // Network namespace #define CLONE_NEWUSER 0x10000000 // User namespace2. 创建namespace#define _GNU_SOURCE #include sched.h #include stdio.h #include stdlib.h #include unistd.h #include sys/wait.h int child(void *arg) { printf(Im in child namespace\n); printf(PID in namespace: %d\n, getpid()); // 执行shell execl(/bin/bash, /bin/bash, NULL); return 0; } int main() { char *stack; pid_t pid; // 分配栈空间 stack malloc(4096 * 1024); if (!stack) return 1; // 创建PID namespace pid clone(child, stack 4096 * 1024, CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD, NULL); if (pid 0) { perror(clone); return 1; } printf(Parent: child PID %d\n, pid); waitpid(pid, NULL, 0); return 0; }3. Network namespace# 创建network namespace ip netns add myns # 在namespace中执行命令 ip netns exec myns ip link list # 添加网络接口到namespace ip link add veth0 type veth peer name veth1 ip link set veth1 netns myns # 配置namespace中的接口 ip netns exec myns ip addr add 10.0.0.2/24 dev veth1 ip netns exec myns ip link set veth1 up # 删除namespace ip netns del myns # 查看所有namespace ip netns list ls /var/run/netns4. Mount namespace# 创建mount namespace unshare --mount # 挂载proc mount -t proc proc /proc # 挂载sys mount -t sysfs sys /sys # 创建新的挂载点 mount -t tmpfs tmpfs /tmp # 查看挂载 mount cat /proc/self/mountinfocgroups资源控制1. cgroups层次结构cgroup root ├── system.slice ├── user.slice └── docker.slice ├── abc123.service └── def456.service2. cgroups v1# 创建cgroup mkdir /sys/fs/cgroup/cpu/mycontainer # 设置CPU限制 echo 50000 /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_quota_us # 50% CPU echo 100000 /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_period_us # 设置内存限制 echo 512M /sys/fs/cgroup/memory/mycontainer/memory.limit_in_bytes echo 256M /sys/fs/cgroup/memory/mycontainer/memory.soft_limit_in_bytes # 设置IO限制 echo 8:0 wbps10485760 /sys/fs/cgroup/blkio/mycontainer/blkio.throttle.write_bps_device # 添加进程 echo pid /sys/fs/cgroup/cpu/mycontainer/tasks # 查看统计 cat /sys/fs/cgroup/cpu/mycontainer/cpu.stat3. cgroups v2# 检查cgroups v2 mount | grep cgroup2 # 创建cgroup mkdir /sys/fs/cgroup/mycontainer # 设置CPU限制 echo max 50000 100000 /sys/fs/cgroup/mycontainer/cpu.max # 设置内存限制 echo max 512M /sys/fs/cgroup/mycontainer/memory.max # 设置IO限制 echo 8:0 rbpsmax wbpsmax /sys/fs/cgroup/mycontainer/io.max # 添加进程 echo pid /sys/fs/cgroup/mycontainer/cgroup.procs4. libcgoup编程#include libcgroup.h int main() { struct cgroup *cgroup; struct cgroup_controller *cgc; int ret; cgroup_init(); // 创建cgroup cgroup cgroup_new_cgroup(mycontainer); if (!cgroup) return 1; // 添加CPU控制器 cgc cgroup_add_controller(cgroup, cpu); cgroup_controller_set_uint64(cgc, cpu.cfs_quota_us, 50000); cgroup_controller_set_uint64(cgc, cpu.cfs_period_us, 100000); // 添加内存控制器 cgc cgroup_add_controller(cgroup, memory); cgroup_controller_set_uint64(cgc, memory.limit_in_bytes, 512 * 1024 * 1024); // 创建cgroup ret cgroup_create_cgroup(cgroup, 0); if (ret) { fprintf(stderr, Failed to create cgroup\n); return 1; } // 添加进程 ret cgroup_add_task(cgroup, getpid()); // 清理 cgroup_free(cgroup); return 0; }Union文件系统1. OverlayFSOverlayFS将多个目录合并成单一的视图。overlay ├── lower (只读) │ └── usr/ │ └── bin/ ├── upper (读写) │ └── var/ └── work (工作目录)2. OverlayFS挂载# 创建目录 mkdir -p /mnt/overlay/{lower,upper,work,mnt} # lower层镜像内容 mount -t overlay overlay -o lowerdir/var/lib/docker/overlay2/lower,\ upperdir/var/lib/docker/overlay2/upper,\ workdir/var/lib/docker/overlay2/work \ /mnt/overlay/mnt3. OverlayFS在内核中#include linux/overlayfs.h // OverlayFS通过VFS实现不需要额外的系统调用 // 容器使用overlay存储驱动时Docker自动处理挂载容器网络1. 网络模型bridge默认网络模式host共享主机网络overlay跨主机网络macvlan为容器分配MAC地址none禁用网络2. Bridge网络# 创建网桥 ip link add br0 type bridge ip addr add 172.17.0.1/16 dev br0 ip link set br0 up # 创建veth对 ip link add veth0 type veth peer name veth1 # 一端连接到网桥 ip link set veth0 master br0 ip link set veth0 up # 另一端移到容器namespace ip link set veth1 netns container_pid ip netns exec container_pid ip addr add 172.17.0.2/16 dev veth1 ip netns exec container_pid ip link set veth1 up3. iptables规则# NAT规则 iptables -t nat -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE # 端口映射 iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80 # 过滤规则 iptables -A FORWARD -i docker0 -o docker0 -j ACCEPT容器存储1. 存储驱动overlay2当前推荐性能好aufs早期Docker使用devicemapper块级存储btrfs文件系统级存储zfs高级存储功能2. 数据卷# 创建volume docker volume create myvolume # 挂载volume docker run -v myvolume:/data debian # 绑定挂载主机目录 docker run -v /host/path:/container/path debian # tmpfs挂载 docker run --tmpfs /run debian3. 存储驱动切换# 查看当前存储驱动 docker info | grep Storage Driver # 修改存储驱动编辑/etc/docker/daemon.json { storage-driver: overlay2 }容器安全1. Seccomp# Docker默认seccomp配置 docker run --security-opt seccompdefault.json debian # 自定义seccomp docker run --security-opt seccomp/path/to/profile.json debian # 无seccomp限制 docker run --security-opt seccompunconfined debian2. Capabilities限制# 查看默认能力 docker run --rm debian cat /proc/self/status | grep Cap # 删除能力 docker run --cap-dropNET_RAW debian # 添加能力 docker run --cap-addNET_ADMIN debian # 完全删除能力 docker run --privileged debian3. AppArmor/SELinux# AppArmor docker run --security-opt apparmorprofile debian # SELinux docker run --security-opt labeltype:container_file_t debian # 禁用安全标签 docker run --security-opt labeldisable debianrunc容器运行1. runc概述runc是OCI容器运行时的参考实现。# 创建spec runc spec # 运行容器 runc run mycontainer # 列出容器 runc list # 停止容器 runc kill mycontainer # 删除容器 runc delete mycontainer2. spec文件{ ociVersion: 1.0.2, process: { terminal: true, user: { uid: 0, gid: 0 }, args: [/bin/bash], cwd: / }, root: { path: rootfs, readonly: true }, hostname: container, mounts: [ { destination: /proc, type: proc, source: proc } ], linux: { namespaces: [ {type: pid}, {type: network}, {type: ipc}, {type: uts}, {type: mount} ] } }容器编排1. Kubernetes架构Control Planekube-apiserveretcdkube-controller-managerkube-schedulerNodekubeletkube-proxycontainer runtime2. PodPod是Kubernetes最小的调度单位。apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx:1.21 ports: - containerPort: 80 resources: limits: memory: 128Mi cpu: 500m requests: memory: 64Mi cpu: 250m3. DeploymentapiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.21 ports: - containerPort: 80结论Linux容器技术通过namespace实现资源隔离通过cgroups实现资源限制通过overlayfs实现高效的镜像管理。这些内核机制共同构成了现代容器技术的基础。理解这些底层原理对于容器开发、运维和安全加固都有重要意义。

更多文章