目录

安装incus部署lxc容器

这篇文章介绍了如何安装incus

注意
注1、本人使用的系统为debian13

1 安装incus

1.1 命令安装incus

sudo apt install incus-base

安装btrfs

sudo apt install btrfs-progs

1.2 配置incus

初始化incus,全部默认下一步即可

incus admin init

检查内核转发是否已开启 (1 为开启)

sysctl net.ipv4.ip_forward

创建一个alpine容器

incus launch images:alpine/edge alpine01

进入容器 (Shell)

incus shell alpine01

其他incus命令

查看所有容器状态        incus list
停止容器               incus stop my-debian
启动已有的容器          incus start my-debian
删除容器(需先停止)	incus delete my-debian
查看容器详细信息	incus info my-debian

1.3 配置容器静态ipv4

查看网桥网段

incus network show incusbr0

配置静态IP,重启生效

# 语法:incus config device set <容器名> <网卡名> ipv4.address <静态IP>
incus config device set alpine01 eth0 ipv4.address 10.1.168.165
incus config device override alpine01 eth0 ipv4.address=10.1.168.165   # 首次使用解绑模板eth0

1.4 关闭Incus防火墙

incus network set incusbr0 ipv4.firewall false
incus network set incusbr0 ipv6.firewall false

1.5 配置端口转发

编辑配置文件

sudo nano /etc/nftables.conf

放置如下内容

#!/usr/sbin/nft -f

# 清除旧规则
flush ruleset

# 定义变量
define WAN_IF = "ens18"          # !!!请根据实际情况修改此网卡名!!!
define BRIDGE_IF = "incusbr0"    # Incus 默认网桥名

# ==========================================
# 1. 过滤表:负责安全性(谁能进,谁能过)
# ==========================================
table inet filter {
    chain input {
        type filter hook input priority filter; policy drop;

        # 允许本地回环
        iif "lo" accept
        # 允许已建立和关联的连接 (回包)
        ct state established,related accept
        # 允许 Ping (可选)
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept

        # 允许管理服务:宿主机 SSH 。相当于宿主机防火墙
        tcp dport 22 accept
        tcp dport 80 accept

        # 兼容 Incus:允许容器获取 IP (DHCP) 和请求 DNS
        iifname $BRIDGE_IF udp dport { 53, 67 } accept
        iifname $BRIDGE_IF tcp dport { 53, 67 } accept
    }

    chain forward {
        type filter hook forward priority filter; policy drop;

        # 允许已建立和关联的连接
        ct state established,related accept

        # 允许容器访问外部网络
        iifname $BRIDGE_IF oifname $WAN_IF accept

        # 允许容器之间互相通信
        iifname $BRIDGE_IF oifname $BRIDGE_IF accept

        # 【核心安全规则】
        # 自动放行在 NAT 表中命中转发规则的所有流量 (含 TCP 和 UDP)
        ct status dnat accept
    }

    chain output {
        type filter hook output priority filter; policy accept;
    }
}

# ==========================================
# 2. NAT表:负责转发逻辑(改写目标地址)
# ==========================================
table ip nat {
    # 端口转发映射映射表
    # 结构: [ 协议 . 外部端口 ] : [ 内部IP . 内部端口 ]
    map port_forward_map {
        type inet_proto . inet_service : ipv4_addr . inet_service
        elements = {
            tcp . 56256 : 10.239.122.103 . 22,
            tcp . 8080  : 10.239.122.42 . 80,
            udp . 8080  : 10.239.122.42 . 80,
            udp . 51820 : 10.239.122.43 . 51820
        }
    }

    chain prerouting {
        type nat hook prerouting priority dstnat; policy accept;

        # 核心转发指令:基于协议和端口自动查找 Map 并执行 DNAT
        dnat ip addr . port to meta l4proto . th dport map @port_forward_map
    }

    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;

        # 伪装出口流量,让容器能上网
        oifname $WAN_IF masquerade
    }
}

验证文件

sudo nft -c -f /etc/nftables.conf

应用配置

sudo nft -f /etc/nftables.conf

进入容器 (Shell)

incus shell alpine01

命令行临时添加,重启后失效

# 同时增加一条 TCP 转发
sudo nft add element ip nat port_forward_map { tcp . 7777 : 10.239.122.41 . 7777 }

# 同时增加一条 UDP 转发
sudo nft add element ip nat port_forward_map { udp . 7777 : 10.239.122.41 . 7777 }

自动保存当前运行的规则。如果你通过命令行临时添加了很多规则,懒得再去手动改文件,可以直接把内存中运行的“完美状态”覆盖到配置文件里:

sudo sh -c "nft list ruleset > /etc/nftables.conf"

注意:这会把文件顶部的#!/usr/sbin/nft -f等注释删掉,但规则是完整的。

2 打包lxc镜像

2.1 手动打包镜像

安装debootstrap

sudo apt install debootstrap tar xz-utils

创建一个干净的工作目录

mkdir -p ~/incus-build/rootfs
cd ~/incus-build

构建Rootfs根文件系统

sudo debootstrap --variant=minbase --arch=amd64 bookworm ./rootfs http://mirrors.tuna.tsinghua.edu.cn/debian/

现在的 rootfs 目录只是的一堆死文件,我们需要进入内部进行配置,否则容器启动会报错或无法联网。

sudo chroot ./rootfs /bin/bash

设置 PATH 环境变量

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

配置网络(Incus 依赖 DHCP,必须配置)

# 安装网络工具和 SSH
apt-get update
apt-get install -y iproute2 iputils-ping curl openssh-server

# 配置网卡自动获取 IP (systemd-networkd 方式)
mkdir -p /etc/systemd/network
cat <<EOF > /etc/systemd/network/eth0.network
[Match]
Name=eth0

[Network]
DHCP=yes
EOF

# 启用网络服务
systemctl enable systemd-networkd

设置 root 密码(否则你进不去)

echo "root:password" | chpasswd

允许 root 登录 SSH

sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

清理垃圾并退出

apt-get clean
rm -rf /var/lib/apt/lists/*
exit

编写元数据 (Metadata)模板

#在工作目录下创建模板文件夹
mkdir templates

配置自动主机名 (Hostname)

#在工作目录下创建模板文件夹
cd templates
nano hostname.tpl

文件内容

{{ container.name }}

编写/etc/hosts模板 (templates/hosts.tpl)

nano hosts.tpl

文件内容

127.0.0.1   localhost
127.0.1.1   {{ container.name }}

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

工作目录下创建 metadata.yaml

cat <<EOF > metadata.yaml
architecture: "x86_64"
creation_date: $(date +%s)
properties:
  description: "My Scratch Debian 12"
  os: "debian"
  release: "bookworm"
EOF

配置 metadata.yaml

architecture: "x86_64"
creation_date: 1706870400
properties:
  description: "Debian with Auto-Hostname"
  os: "debian"
  release: "bookworm"

# 核心配置在这里
templates:
  # 1. 目标文件在容器内的绝对路径
  /etc/hostname:
    # 什么时候触发替换?(create=创建时, copy=从快照恢复时, start=每次启动时)
    when:
      - create
      - copy
    # 使用哪个模板文件?(相对于 metadata 压缩包内的 templates/ 目录)
    template: hostname.tpl

  # 2. 配置 hosts 文件
  /etc/hosts:
    when:
      - create
      - copy
    template: hosts.tpl

打包 Metadata

tar -cJvf ./metadata.tar.xz metadata.yaml templates/

打包 Rootfs: 关键点: 必须进入 rootfs 目录内部打包,且使用 –numeric-owner 保持 UID/GID 为数字,防止跨系统用户映射错误

cd rootfs
sudo tar --numeric-owner -cJvf ../rootfs.tar.xz .
cd ..

导入并测试

# 导入镜像
incus image import metadata.tar.xz rootfs.tar.xz --alias debian-sid

# 启动容器测试
incus launch debian-sid debian01

# 查看是否运行
incus list

# 进入容器
incus shell debian01