LXC 搭建 K8s 集群计划通

posts/deploy-kubernetes-cluster-on-lxc

最近尝试了一种比较轻量的 k8s 集群搭建方式。在单机 Arch Linux Host(kernel 7.1.7-arch1-1)上通过 LXC 创建多个容器节点,然后在这些 LXC 容器内部运行 k8s。这种方式相比直接使用虚拟机资源占用更低且创建节点速度更快(4个节点+宿主机内存占用仅为2GB)。

整体架构如下:

                    Host Linux
                        |
                  lxcbr0 Bridge
                        |
    +------------+------------+------------+
    |            |            |            |
LXC Node1    LXC Node2    LXC Node3     LXC Node4
    |            |            |            |
kubelet      kubelet      kubelet       kubelet
    |            |            |            |
               k8s Cluster

环境准备

Host 安装基础组件

sudo pacman -S lxc lxcfs dnsmasq

其中:

  • lxc 提供 Linux Container 管理能力
  • lxcfs 提供容器内部更准确的 /proc 信息
  • dnsmasq 为 LXC 网络提供 DHCP/DNS 服务

配置 LXC 网络

LXC 默认可以通过 lxc-net 创建 NAT 网络。编辑 /etc/default/lxc-net

USE_LXC_BRIDGE="true"
LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.3.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.3.0/24"

这里创建一个 10.0.3.0/24 网段,Host 地址为 10.0.3.1,后续 k8s 节点会使用 10.0.3.x 地址。

启动网络服务:

sudo systemctl enable --now lxc-net

检查:

ip addr show lxcbr0

应该可以看到:

4: lxcbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 10.0.3.1/24 brd 10.0.3.255 scope global lxcbr0
       valid_lft forever preferred_lft forever

创建 LXC 节点

使用官方 download template 创建 Arch Linux 容器。一共需要 4 个节点,重复以下命令依次创建 arch-lxc-1 ~ arch-lxc-4。下面以 arch-lxc-1 为例:

sudo lxc-create \
    -n arch-lxc-1 \
    -t download \
    -- \
    -d archlinux \
    -r current \
    -a amd64

参数说明:

参数说明
-n容器名称
-t download使用下载模板
-dLinux 发行版
-rRelease
-aCPU 架构

启动,这里的-d 表示 daemon 模式运行:

sudo lxc-start arch-lxc-1 -d

进入容器:

sudo lxc-attach arch-lxc-1

能进去的话就说明容器没什么问题了。

为 k8s 修改 LXC 配置

k8s 默认需要访问 cgroup、proc、sys、/dev/kmsg等,而普通 LXC 容器默认限制较多,需要调整。

以下配置需要对所有 4 个 LXC 节点 (arch-lxc-1 ~ arch-lxc-4) 各执行一次,下面以 arch-lxc-1 为例。

编辑 /var/lib/lxc/arch-lxc-1/config,加入:

# 嵌套容器与特权设备访问
lxc.include = /usr/share/lxc/config/nesting.conf
lxc.apparmor.profile = unconfined
lxc.cgroup2.devices.allow = a
lxc.mount.auto = proc:mixed sys:rw cgroup:rw

# k8s 额外需要
features = nesting=1,keyctl=1
lxc.mount.entry = /dev/kmsg dev/kmsg none bind,create=file
lxc.mount.entry = proc proc proc rw,nosuid,nodev,noexec,relatime 0 0

重启容器:

lxc-stop arch-lxc-1
lxc-start arch-lxc-1

Host 开启 k8s 必需 Kernel Module

k8s 网络需要 overlay filesystem 和 bridge netfilter。需要在 Host 上加载:

sudo modprobe overlay
sudo modprobe br_netfilter

设置开机加载 /etc/modules-load.d/k8s.conf

overlay
br_netfilter

LXC 安装 containerd

以下操作需要在每个 LXC 节点内重复执行。

进入 LXC 节点:

sudo lxc-attach arch-lxc-1

官方 download template 拉下来的容器 keyring 可能过期,先同步一下:

pacman -Sy

安装 containerd:

pacman -S containerd

启动:

systemctl enable --now containerd

生成默认配置:

mkdir /etc/containerd
containerd config default \
    | tee /etc/containerd/config.toml

k8s 推荐使用 systemd cgroup,修改 /etc/containerd/config.toml

sed -i \
's/SystemdCgroup = false/SystemdCgroup = true/' \
/etc/containerd/config.toml

重启:

systemctl restart containerd

测试:

ctr version

正常情况下可以看到 containerd client/server 信息。

Client:
  Version:  v2.3.3
  Revision: aad11006b869517fcd3009450b6f82da282e1a9b.m
  Go version: go1.26.5-X:nodwarf5

Server:
  Version:  v2.3.3
  Revision: aad11006b869517fcd3009450b6f82da282e1a9b.m
  UUID: 418cba5e-e128-4af5-ae41-f91cea65ea19

安装 k8s 组件

以下操作需要在每个 LXC 节点内重复执行。

pacman -S kubeadm kubelet

此处不要 enable kubelet,kubeadm init 之前启动会立即报错,master init 成功后再启用即可。

配置 k8s 网络参数

以下操作需要在每个 LXC 节点内重复执行。

创建 /etc/sysctl.d/k8s.conf

sudo tee /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
EOF

加载:

sudo sysctl --system

检查各节点 IP,master 节点的 IP(例如 10.0.3.49)后面 kubeadm init 要用:

ip addr

初始化 k8s Master

使用 kubeadm:

sudo kubeadm init \
    --apiserver-advertise-address=10.0.3.49 \
    --pod-network-cidr=192.168.0.0/16

参数说明:

  • apiserver-advertise-address:指定 k8s API Server 对外监听地址。这里使用 LXC 网络地址 10.0.3.49
  • pod-network-cidr:指定 Pod 网络范围,例如 192.168.0.0/16,后续安装 CNI 时需要保持一致。

这个初始化需要一段时间,几分钟后看到以下输出:

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.3.49:6443 --token <token> \
        --discovery-token-ca-cert-hash sha256:<hash>

init 成功后启用 kubelet:

sudo systemctl enable --now kubelet

KUBECONFIG 持久化到 /etc/environment

echo 'KUBECONFIG=/etc/kubernetes/admin.conf' | sudo tee -a /etc/environment

接着部署 Calico CNI(pod 网络需要):

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.2/manifests/calico.yaml

稍等片刻后,把 init 末尾的 kubeadm join 命令在另外三个容器内执行一遍即可。

三个 worker join 后也需要 enable kubelet,确保重启后自启:

sudo systemctl enable kubelet

所有节点加入后验证集群:

kubectl get nodes

四个节点均为 Ready

NAME         STATUS   ROLES           AGE   VERSION
arch-lxc-1   Ready    control-plane   23h   v1.36.3
arch-lxc-2   Ready    <none>          23h   v1.36.3
arch-lxc-3   Ready    <none>          23h   v1.36.3
arch-lxc-4   Ready    <none>          23h   v1.36.3

总结

整体流程:Host 装 LXC + 配网 → 拉 4 个 Arch 容器 → 改 LXC config 让其支持 k8s → 节点内装 containerd + kubeadm/kubelet + 调 sysctl → master init → 部署 Calico CNI → worker join → kubectl get nodes 验证。

LXC 运行 k8s 是一个非常适合学习 k8s 原理的方案。

相比 Docker-in-Docker:

  • LXC 提供更完整的 Linux 环境
  • kubelet/containerd 可以按照接近真实服务器的方式运行
  • 节点创建速度非常快

但是也需要处理 cgroup、AppArmor、proc mount、kernel module 等问题。