GNS3 2.2.61 Docker Compose 部署指南

用 Docker Compose 部署 GNS3 2.2.61 服务端:顶层项目名 gns3-2.2.61-stack、宿主端口 8133 映射 3080、网络 10.89.63.0/24、数据卷持久化;含官方镜像拉取受限实测、Dynamips 能力集、VPCS 0.8.4 与 uBridge 0.9.19 依赖、KVM 直通缺失与 409/403 排障。

GNS3GNS3网络仿真Python2026/10/27

GNS3 2.2.61 Docker Compose 部署指南

目标:用一份 docker-compose.yml 把 GNS3 2.2.61 服务端跑起来,端口固定、网络固定、数据可持久化,并能通过浏览器与 REST 接口验证。本文所有命令与回显均来自实测环境(Ubuntu 26.04.1 + Docker 29.9.2 + Compose v5.6.1);GNS3 的组件构成与版本选型见 《GNS3 2.2.61 介绍与选型指南》,裸机安装路线见 《Ubuntu 22.04 安装 GNS3 2.2.61 服务端指南》。

一、环境信息与规划

本章先把宿主机版本、端口与网段钉死。Compose 部署最容易翻车的不是配置文件语法,而是端口冲突、网段冲突、以及容器权限不足导致 Dynamips/uBridge 起不来,所以这三件事在创建容器之前就要查清楚。

1.1 实测环境

项目实测值说明
宿主机系统Ubuntu 26.04.1 LTS内核 7.0.0-38-generic x86_64
Docker Engine29.9.2支持 Compose v2 规范
Docker Composev5.6.1docker compose 子命令
基础镜像ubuntu:22.04jammy,Python 3.10,与 GNS3 2.2.x 官方支持一致
服务端版本gns3-server 2.2.61镜像内 venv 安装,PyPI 2026-07-30 发布
镜像体积519 MB本地构建结果
服务端口8133 → 3080宿主 8133 映射容器 3080
网络10.89.63.0/24容器固定 IP 10.89.63.10
演示账号root / q1w2e3r4本文示例登录凭据

版本自查:

docker version --format '{{.Server.Version}}'
docker compose version --short
cat /etc/os-release | head -2
29.9.2
5.6.1
PRETTY_NAME="Ubuntu 26.04.1 LTS"
NAME="Ubuntu"

1.2 端口规划(8128–8152 段)

GNS3 只用 3080/tcp 提供 HTTP 与 WebSocket;节点 console 走服务端代理,不需要额外映射宿主端口。选端口前先把目标段扫一遍:

ss -ltn | awk '{print $4}' | grep -oE ':(81[2-5][0-9])$' | sort -u
:8121
:8122
:8123
:8129
:8130
:8131
:8132
:8135
:8137
:8150

在 8128–8152 区间内,8133 未被占用,本文选它;部署前用下面这条命令确认一次,返回空即空闲:

ss -ltnp | grep ':8133' || echo "8133 空闲"
8133 空闲

1.3 网络规划(10.89.56–75 槽位)

宿主上已有的 10.89.x 网段(含其他容器栈)必须避开,否则 Docker 会报 Pool overlaps with other one on this address space。先列出现存网段:

docker network ls --format '{{.Name}}' | while read n; do
  echo "$n $(docker network inspect "$n" --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null)"
done
bridge 172.17.0.0/16
dittofeed-v0.24.0-alpha.21-net 10.89.59.0/24
gns3-2.2.61-net 10.89.61.0/24
halo-2271-stack_halo-net 10.89.62.0/24
hoppscotch-v2026-9-stack_hoppscotch-net 10.89.56.0/24
host
none

已占用 56、59、61、62,本文选 10.89.63.0/24,网关 10.89.63.1,服务端固定 IP 10.89.63.10。

1.4 官方镜像现状(实测)

gns3/gns3-server 是 GNS3 官方在 Docker Hub 维护的镜像仓库。本次部署在拉取阶段遇到三类情况,均如实记录:

docker pull gns3/gns3-server:2.2.61
2.2.61: Pulling from gns3/gns3-server
(长时间无进展,最终 context deadline exceeded)
  • 直连 registry-1.docker.io 超时,docker manifest inspect 同样失败;
  • 通过第三方加速站查询 tag 列表可以看到 ["2.2.61","latest"],但取 manifest 返回:
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"repository","Class":"","Name":"gns3/gns3-server","Action":"pull"}]}]}
  • 换用其他镜像站分别遇到 "not in the allowlist" 与"免费节点当前繁忙"。

结论:本环境无法确认官方镜像是否已提供 2.2.61 tag,也无法直接从 Docker Hub 拉取。因此本文主路径是"用 ubuntu:22.04 本地构建同版本镜像"(第 2、3 章),保证版本号与裸机安装完全一致;如果你所在环境能正常访问 Docker Hub 或官方镜像已发布 2.2.61,可跳过构建,直接把 compose 里的 build: 段替换为 image: gns3/gns3-server:2.2.61(其余配置不变)。

二、目录结构与配置文件

一个可维护的栈目录应当把"配置、数据、日志"全部落在宿主目录,容器重建不丢数据。下文统一以 /opt/gns3-stack 作为栈目录,所有命令与回显均在该目录结构下实际执行过,路径可按需替换。

mkdir -p /opt/gns3-stack/{config,projects,images,logs}
tree -L 1 /opt/gns3-stack
/opt/gns3-stack
├── config
├── images
├── logs
└── projects

配置文件 /opt/gns3-stack/config/gns3_server.conf:

[Server]
host = 0.0.0.0
port = 3080
config_path = /etc/gns3
projects_path = /var/lib/gns3/projects
images_path = /var/lib/gns3/images
appliances_path = /var/lib/gns3/appliances
symbols_path = /var/lib/gns3/symbols
report_errors = false
local = false

[Qemu]
enable_kvm = false
qemu_path = /usr/bin/qemu-system-x86_64

[Dynamips]
dynamips_path = /usr/bin/dynamips

[VPCS]
vpcs_path = /usr/bin/vpcs

两点必须注意:

  • port = 3080 是容器内端口,宿主端口由 compose 的 ports 决定,不要把这里改成 8133;
  • enable_kvm = false 与本文环境一致(容器未直通 /dev/kvm)。若宿主 KVM 可用并已直通,改成 true 才会带上 -enable-kvm 启动参数。

各项参数的完整含义与默认值见《GNS3 2.2.61 配置参数详解》。

三、编写 Dockerfile

官方镜像不可用时最稳的做法是自己构建:基础镜像用 ubuntu:22.04,Python 用系统 3.10,gns3-server 用 pip 固定 2.2.61,Dynamips/VPCS/uBridge 三个节点后端一并装好。

FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive \
    PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple

RUN apt-get update \
 && apt-get install -y --no-install-recommends \
      python3 python3-venv python3-pip curl ca-certificates \
      qemu-system-x86 qemu-utils dynamips vpcs iproute2 procps \
      libpcap0.8 \
 && curl -fsSL -o /tmp/vpcs.deb \
      https://ppa.launchpadcontent.net/gns3/ppa/ubuntu/pool/main/v/vpcs/vpcs_0.8.4-1~jammy1_amd64.deb \
 && curl -fsSL -o /tmp/ubridge.deb \
      https://ppa.launchpadcontent.net/gns3/ppa/ubuntu/pool/main/u/ubridge/ubridge_0.9.19-1~jammy1_amd64.deb \
 && dpkg -i /tmp/vpcs.deb /tmp/ubridge.deb \
 && rm -f /tmp/vpcs.deb /tmp/ubridge.deb \
 && rm -rf /var/lib/apt/lists/*

RUN python3 -m venv /opt/gns3/venv \
 && /opt/gns3/venv/bin/pip install --upgrade pip \
 && /opt/gns3/venv/bin/pip install gns3-server==2.2.61

RUN mkdir -p /etc/gns3 /var/lib/gns3/projects /var/lib/gns3/images \
             /var/lib/gns3/appliances /var/lib/gns3/symbols /var/log/gns3

EXPOSE 3080

ENTRYPOINT ["/opt/gns3/venv/bin/gns3server"]
CMD ["--config", "/etc/gns3/gns3_server.conf", "--log", "/var/log/gns3/gns3_server.log"]

几个设计点,都是实测踩坑后定下来的:

  1. VPCS 必须升级到 0.8.x。Ubuntu 22.04 仓库里的 vpcs 是 0.5b2,GNS3 2.2.61 启动 VPCS 节点时会直接返回 409:

    {"message": "VPCS executable version must be >= 0.6.1 but not a 0.8", "status": 409}
    

    所以 Dockerfile 里额外用 GNS3 PPA 的 deb 覆盖安装 1:0.8.4-1~jammy1,构建日志可见:

    Unpacking vpcs (1:0.8.4-1~jammy1) over (0.5b2-2.2) ...
    Setting up vpcs (1:0.8.4-1~jammy1) ...
    
  2. uBridge 单独安装。它负责节点间链路(虚拟交换机侧),缺失时启动节点会报 uBridge is not available, path doesn't exist...。同样从 PPA 装 0.9.19,镜像内验证:

    docker exec gns3-2.2.61-server ubridge version
    
    uBridge version 0.9.19 running with libpcap version 1.10.1 (with TPACKET_V3)
    
  3. pip 使用国内源。直连 pypi.org 下载 14.7 MB 主包时会长时间卡住,构建阶段用 PIP_INDEX_URL 指向清华镜像;日志中的成功行为:

    Successfully installed Jinja2-3.1.6 MarkupSafe-3.0.4 aiofiles-25.1.0 ... gns3-server-2.2.61 ...
    
  4. 用 venv 而不是系统 pip。Ubuntu 22.04 的 Python 3.10 受 PEP 668 约束,系统级 pip install 会报 externally-managed-environment;venv 绕开该限制,也让升级/回滚只影响一个目录。

镜像构建并查看结果:

docker compose build
docker images gns3/gns3-server:2.2.61-local
REPOSITORY              TAG             IMAGE ID       CREATED         SIZE
gns3/gns3-server        2.2.61-local    d2e88f3aa232   1 minute ago    519MB

四、编写 docker-compose.yml

name: gns3-2.2.61-stack

services:
  gns3-server:
    build:
      context: .
      dockerfile: Dockerfile
    image: gns3/gns3-server:2.2.61-local
    container_name: gns3-2.2.61-server
    restart: unless-stopped
    ports:
      - "8133:3080"
    volumes:
      - ./config/gns3_server.conf:/etc/gns3/gns3_server.conf:ro
      - ./projects:/var/lib/gns3/projects
      - ./images:/var/lib/gns3/images
      - ./logs:/var/log/gns3
    environment:
      - TZ=Asia/Shanghai
    cap_add:
      - NET_ADMIN
      - NET_RAW
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://127.0.0.1:3080/v2/version"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s
    # 若宿主机 /dev/kvm 可用,取消下面两行注释,并在 gns3_server.conf 中设置 enable_kvm = true
    # devices:
    #   - "/dev/kvm:/dev/kvm"
    networks:
      gns3-net:
        ipv4_address: 10.89.63.10

networks:
  gns3-net:
    name: gns3-2.2.61-stack-net
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.63.0/24
          gateway: 10.89.63.1

逐项说明:

  • name: gns3-2.2.61-stack:Compose 顶层项目名,决定默认网络名前缀、容器分组名,docker compose ps/logs 都以它为准;

  • image + build 并存:首次用 build 产出镜像,后续 docker compose up -d 直接复用本地镜像;如能拉到官方镜像,删掉 build 改 image: gns3/gns3-server:2.2.61 即可;

  • ports: "8133:3080":宿主 8133 对容器 3080,只暴露一个 HTTP 端口,Web UI、REST、WebSocket 共用;

  • 三个 volume:projects、images 是业务数据(工程文件与 qcow2 磁盘),必须落在宿主;logs 挂载后容器内 --log 写出的日志可直接在宿主查看;

  • cap_add: NET_ADMIN, NET_RAW:这一项不能省。Ubuntu 的 /usr/bin/dynamips 带文件能力 cap_net_admin,cap_net_raw=eip,而 Docker 默认能力集不含这两项,直接执行会失败:

    docker exec gns3-2.2.61-server dynamips --version
    
    exec /usr/bin/dynamips: operation not permitted
    

    加上 cap_add 后恢复正常:

    Cisco Router Simulation Platform (version 0.2.14-amd64/Linux stable)
    
  • healthcheck:用 /v2/version 判定服务是否真正就绪,比只看容器 Up 更可靠;

  • devices: /dev/kvm:仅在宿主 KVM 可用时启用。本文宿主 /dev/kvm 节点存在但 QEMU 报 Could not access KVM kernel module: No such device,所以保持注释、enable_kvm = false,QEMU 节点走 TCG 纯软件模拟。

五、启动与验证

5.1 启动

docker compose up -d
 Network gns3-2.2.61-stack-net Creating
 Network gns3-2.2.61-stack-net Created
 Container gns3-2.2.61-server Creating
 Container gns3-2.2.61-server Created
 Container gns3-2.2.61-server Starting
 Container gns3-2.2.61-server Started

查看状态与健康检查:

docker compose ps
NAME                 IMAGE                           STATUS                    PORTS
gns3-2.2.61-server   gns3/gns3-server:2.2.61-local   Up 9 seconds (healthy)    0.0.0.0:8133->3080/tcp, [::]:8133->3080/tcp

5.2 接口与 Web UI

curl -s http://127.0.0.1:8133/v2/version
{
    "local": false,
    "version": "2.2.61"
}

访问根路径会 302 到内置 Web UI:

curl -s -o /dev/null -w 'HTTP %{http_code} redirect=%{redirect_url}\n' http://127.0.0.1:8133/
HTTP 302 redirect=http://127.0.0.1:8133/static/web-ui/bundled

页面标题即 GNS3 Web UI:

<!DOCTYPE html><html lang="en"><head>
    <meta charset="utf-8">
    <title>GNS3 Web UI</title>
    <base href="/static/web-ui/">

浏览器打开 http://<宿主IP>:8133/static/web-ui/bundled,用示例账号 root / q1w2e3r4 登录(若在配置里开启了 auth,见 C1 篇)。

5.3 计算节点注册情况

curl -s http://127.0.0.1:8133/v2/computes
[
    {
        "capabilities": {
            "node_types": [
                "cloud", "ethernet_hub", "ethernet_switch", "nat", "vpcs",
                "virtualbox", "dynamips", "frame_relay_switch", "atm_switch",
                "qemu", "vmware", "traceng", "docker", "iou"
            ],
            "platform": "linux",
            "version": "2.2.61"
        },
        "compute_id": "local",
        "connected": true,
        "cpu_usage_percent": 77.4,
        "host": "127.0.0.1",
        "last_error": null,
        "memory_usage_percent": 56.8,
        "name": "c33872afb0de",
        "port": 3080,
        "protocol": "http",
        "user": null
    }
]

local compute 已自动连上,说明 controller 与 compute 在同一进程内工作正常。

5.4 创建节点并启动(冒烟测试)

用接口建一个 VPCS 节点,验证节点后端真的能拉起来:

API=http://127.0.0.1:8133/v2
PID=$(curl -s -X POST $API/projects -H 'Content-Type: application/json' \
      -d '{"name":"b2-smoke"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["project_id"])')
echo "PID=$PID"

curl -s -X POST $API/projects/$PID/nodes -H 'Content-Type: application/json' \
     -d '{"name":"PC1","node_type":"vpcs","compute_id":"local"}' \
     | python3 -c 'import sys,json;d=json.load(sys.stdin);print("node",d["name"],d["node_id"],d["node_type"],d["status"])'
PID=801d2acc-c66b-4554-98f4-e8ab62ca94b5
node PC1 fed0a89c-05a6-4d02-a5a8-0afa60a4cbb7 vpcs stopped

启动节点并查看状态:

NID=fed0a89c-05a6-4d02-a5a8-0afa60a4cbb7
curl -s -o /dev/null -w 'start HTTP %{http_code}\n' -X POST $API/projects/$PID/nodes/$NID/start
curl -s $API/projects/$PID/nodes/$NID \
  | python3 -c 'import sys,json;d=json.load(sys.stdin);print("status",d["status"],"console",d.get("console"),"console_host",d.get("console_host"))'
start HTTP 200
status started console 5000 console_host 0.0.0.0

清理冒烟工程:

curl -s -X DELETE -o /dev/null -w 'delete HTTP %{http_code}\n' $API/projects/$PID
delete HTTP 204

六、权限、KVM 与常见故障

6.1 KVM 不可用时的表现

容器内默认没有 /dev/kvm:

docker exec gns3-2.2.61-server ls -l /dev/kvm
ls: cannot access '/dev/kvm': No such file or directory

此时 QEMU 节点只能走 TCG:

docker exec gns3-2.2.61-server qemu-system-x86_64 --version
QEMU emulator version 6.2.0 (Debian 1:6.2+dfsg-2ubuntu6.31)

要启用 KVM,必须同时满足三件事:宿主内核加载 kvm 模块并可访问 /dev/kvm、compose 里直通该设备、配置中 enable_kvm = true。本文实测宿主 /dev/kvm 存在但 QEMU 打开时报 Could not access KVM kernel module: No such device,因此这条路线在本环境未闭环,只验证了 TCG 路径。

6.2 节点启动返回 409 的两种典型原因

现象原样报错处理
VPCS 版本过旧{"message": "VPCS executable version must be >= 0.6.1 but not a 0.8", "status": 409}升级到 PPA 的 1:0.8.4-1~jammy1(本文 Dockerfile 已内置)
uBridge 缺失"uBridge is not available, path doesn't exist, or you just installed GNS3 and need to restart your user session to refresh user permissions."安装 ubridge(本文 Dockerfile 已内置 0.9.19)

6.3 Dynamips 报 operation not permitted

这是文件能力与容器能力集不匹配,不是二进制损坏:

exec /usr/bin/dynamips: operation not permitted

核对文件能力与容器有效能力:

docker exec gns3-2.2.61-server sh -c 'getcap /usr/bin/dynamips; grep CapEff /proc/self/status'
/usr/bin/dynamips cap_net_admin,cap_net_raw=eip
CapEff:	00000000a80435fb

补 cap_add: [NET_ADMIN, NET_RAW] 后 CapEff 包含对应位,Dynamips 即可执行。

6.4 工程打不开:403 The project is not opened

服务重启后,工程处于关闭状态,直接对节点操作会被拒:

{"message": "The project is not opened", "status": 403}

先打开工程再操作节点:

curl -s -o /dev/null -w 'open HTTP %{http_code}\n' -X POST $API/projects/$PID/open
open HTTP 200

6.5 日志位置

容器内服务日志由启动参数 --log 写入 /var/log/gns3/gns3_server.log,已挂载到宿主 ./logs:

tail -n 5 /opt/gns3-stack/logs/gns3_server.log
2026-10-27 13:44:07 INFO compute.py:436 Connected to compute 'local' WebSocket 'http://127.0.0.1:3080/v2/compute/notifications/ws'
2026-10-27 13:44:13 INFO web_log.py:232 10.89.63.1 ... "GET /v2/version HTTP/1.1" 200 229
2026-10-27 13:44:13 INFO web_log.py:232 10.89.63.1 ... "GET / HTTP/1.1" 302 200

注意:因为日志走了 --log 文件,docker compose logs 基本为空,排障要看挂载出来的文件。

七、数据持久化、升级与备份

  • 工程数据:projects/ 下每个工程一个目录(内含 .gns3 工程文件与节点配置),删除容器不影响;

  • 磁盘镜像:images/ 下的 qcow2/镜像文件是节点硬盘,GNS3 首启还会在此安装内置磁盘(empty8G、empty10G 等,约 12 MB),属正常行为;

  • 升级:改 Dockerfile 里的版本号(如 gns3-server==2.2.61 → 下一补丁版本)后 docker compose up -d --build,数据卷不变;

  • 备份:直接打包宿主目录即可,注意停栈后再打包,避免 qcow2 写入中断:

    docker compose stop
    tar czf gns3-backup-$(date +%F).tar.gz -C /opt gns3-stack/config gns3-stack/projects gns3-stack/images
    docker compose start
    
  • 回滚:镜像按版本打 tag(如 2.2.61-local),保留上一版本镜像,改 image 字段即可回退。

八、参考与延伸阅读