AI是良师益友,跟他学Ubuntu server2604搭建docker环境

还是因为不够强,否则不会失业。

大家好我是大龄程序员码农阿峰。今年47周岁,79年的。我差点失业了,我的linux技能现在好像把我保住了。我的感觉是不够强。所以还要继续学。今天展示一下我跟AI学Ubuntu server2604搭建docker环境。

宠辱不惊,闲看庭前花开花落;去留无意,漫随天外云卷云舒。

附安装过程(附件在这里!)

复制代码
#!/usr/bin/env bash
# 全新 Ubuntu 虚拟机:必须在 VirtualBox 本地控制台窗口执行。
# 此时系统还没有 SSH 服务,无法通过 ssh_run.py 远程下发本脚本。
set -e

sudo apt update
sudo apt install -y openssh-server

# 关键:设置开机自启(Ubuntu 服务单元名是 ssh,不是 sshd)
sudo systemctl enable ssh
sudo systemctl start ssh
# 也可以用一条命令替代上面两条:sudo systemctl enable --now ssh
# Ubuntu 24.04+ 的 socket 按需激活单元,保持启用即可
sudo systemctl enable ssh.socket 2>/dev/null || true

# 若启用了 ufw,放行 SSH(未启用时添加规则也无害)
sudo ufw allow OpenSSH || true

echo '--- 验证 ---'
systemctl is-enabled ssh
systemctl is-active ssh
sudo ss -ltnp | grep ':22' || true
ip -4 addr | grep inet

  

复制代码
#!/usr/bin/env bash
# 全新 Ubuntu 虚拟机:必须在 VirtualBox 本地控制台窗口执行。
# 此时系统还没有 SSH 服务,无法通过 ssh_run.py 远程下发本脚本。
set -e

sudo apt update
sudo apt install -y openssh-server

# 关键:设置开机自启(Ubuntu 服务单元名是 ssh,不是 sshd)
sudo systemctl enable ssh
sudo systemctl start ssh
# 也可以用一条命令替代上面两条:sudo systemctl enable --now ssh
# Ubuntu 24.04+ 的 socket 按需激活单元,保持启用即可
sudo systemctl enable ssh.socket 2>/dev/null || true

# 若启用了 ufw,放行 SSH(未启用时添加规则也无害)
sudo ufw allow OpenSSH || true

echo '--- 验证 ---'
systemctl is-enabled ssh
systemctl is-active ssh
sudo ss -ltnp | grep ':22' || true
ip -4 addr | grep inet
复制代码
set -e

echo "[1/6] Resolve newest available Portainer CE image tag"
IMAGE=""
for tag in 2.45.3 lts latest; do
  echo "--- trying portainer/portainer-ce:${tag}"
  if docker pull "portainer/portainer-ce:${tag}"; then
    IMAGE="portainer/portainer-ce:${tag}"
    break
  fi
done
if [ -z "$IMAGE" ]; then
  echo "ERROR: no usable Portainer CE image tag"
  exit 1
fi
echo "IMAGE=${IMAGE}"

echo "[2/6] Image metadata"
docker image inspect "$IMAGE" --format 'id={{.Id}} created={{.Created}} labels={{json .Config.Labels}}'

echo "[3/6] Create persistent volume"
docker volume create portainer_data

echo "[4/6] Start Portainer container"
docker rm -f portainer >/dev/null 2>&1 || true
docker run -d \
  -p 8000:8000 \
  -p 9443:9443 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  "$IMAGE"

echo "[5/6] Wait for HTTPS UI on 9443"
OK=0
for i in $(seq 1 45); do
  code=$(curl -ksS -m 3 -o /dev/null -w '%{http_code}' https://127.0.0.1:9443/api/status 2>/dev/null || true)
  if [ "$code" = "200" ]; then
    OK=1
    echo "UI ready (HTTP 200 after ${i} checks)"
    break
  fi
  sleep 2
done
if [ "$OK" != "1" ]; then
  echo "WARN: UI not responding yet, check docker logs portainer"
fi

echo "[6/6] Final status"
docker ps --filter name=portainer --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
echo "--- /api/status ---"
curl -ksS https://127.0.0.1:9443/api/status || true
echo
echo "--- recent container logs ---"
docker logs portainer 2>&1 | tail -25

  

目录

[0. 先装 SSH,再配端口转发](#0. 先装 SSH,再配端口转发) [1. 登录并体检虚拟机](#1. 登录并体检虚拟机) [2. 安装 Docker Engine](#2. 安装 Docker Engine) [3. 自启 / 免 sudo / 加速](#3. 自启 / 免 sudo / 加速) [4. 验证 Docker](#4. 验证 Docker) [5. 部署 Portainer CE](#5. 部署 Portainer CE) [6. 打通宿主机 9443](#6. 打通宿主机 9443) [7. 首次初始化 Web UI](#7. 首次初始化 Web UI) [8. 常用运维命令](#8. 常用运维命令) [9. 踩坑与解决记录](#9. 踩坑与解决记录) [10. 本次结果快照](#10. 本次结果快照)
实操记录 · 2026-11-12

Ubuntu 26.04 安装 Docker 与 Portainer CE

从一台全新安装、默认没有 SSH 的 Ubuntu 虚拟机开始:先在 VirtualBox 本地控制台装好 OpenSSH 并设为开机自启,再经 NAT 端口转发连入,安装 Docker Engine 并部署 Portainer 社区版;所有命令均在本次环境中验证通过。
系统:Ubuntu 26.04.1 LTS (resolute) x86_64 SSH:127.0.0.1:2222 → 10.0.2.15:22 Docker 29.7.2 Portainer CE 2.45.3 LTS Web UI:https://127.0.0.1:9443

0全新虚拟机:先装 SSH,再配端口转发

最容易漏掉的前提: 刚装好的 Ubuntu(尤其 Desktop 版,或安装 Server 时未勾选 OpenSSH)默认没有 SSH 服务 ,22 端口无人监听。此时就算配好端口转发,宿主机连接也只会报 Connection refused。所以第一步必须在 VirtualBox 虚拟机窗口里,用安装系统时创建的账户本地登录操作;装好并启用 SSH 之后,才能进行后面所有远程步骤。

0.1 在虚拟机本地控制台安装 OpenSSH 并设为开机自启

虚拟机网卡是 NAT,安装系统时即可联网,直接在虚拟机窗口内执行:
VirtualBox 虚拟机窗口内执行(不是宿主机)复制

复制代码
sudo apt update
sudo apt install -y openssh-server

sudo systemctl enable ssh      # 关键:设置开机自启
sudo systemctl start ssh       # 立即启动服务
# 以上两条可合并为:sudo systemctl enable --now ssh

sudo ufw allow OpenSSH         # 若启用了 ufw,放行 22 端口
sudo ufw status verbose

systemctl is-enabled ssh       # 期望输出 enabled
systemctl is-active ssh        # 期望输出 active
sudo ss -ltnp | grep ':22'     # 期望看到 0.0.0.0:22 监听
ip -4 addr                     # 确认 NAT 地址为 10.0.2.15

三个细节: ① Ubuntu / Debian 的 SSH 服务单元名是 ssh(ssh.service),不是 sshd;systemctl enable ssh 不能省,否则虚拟机重启后 SSH 不会自动起来。② Ubuntu 24.04 起另有 ssh.socket 按需激活单元,可用 sudo systemctl enable --now ssh.socket 启用;本次实测 Ubuntu 26.04 上 ssh.service 与 ssh.socket 同时 enabled + active、22 端口正常监听,两者并不冲突。③ 本次环境 ufw 为 inactive,无需放行;若你的机器上 ufw 是 active,务必执行 sudo ufw allow OpenSSH(或 sudo ufw allow 22/tcp)。

同目录下的 install_ssh.sh 是这段命令的配套脚本,可在虚拟机本地窗口执行;它不能 通过 ssh_run.py 下发,因为此刻还没有 SSH 通道。

0.2 配置 NAT 端口转发

客户机 IP 为 10.0.2.15,宿主机不能直接访问;只有 0.1 的 SSH 服务在 22 端口监听后,转发规则才有意义。虚拟机关机状态下,在「设置 → 网络 → 网卡 1 (NAT) → 端口转发」添加 SSH 规则:

名称 协议 主机 IP 主机端口 子系统 IP 子系统端口
Rule 1 TCP 127.0.0.1 2222 10.0.2.15 22

等价的命令行写法(宿主机 PowerShell,需关机状态):
宿主机 PowerShell / CMD复制

复制代码
& "C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" modifyvm ubuntuserver --natpf1 "Rule 1,tcp,127.0.0.1,2222,10.0.2.15,22"

说明: 开机后先用 ssh -p 2222 afeng124@127.0.0.1 测试连通,通了再往下走。本次环境这条 2222 规则已存在,直接可用;后面第 6 步再补一条 9443 给 Portainer 使用,而且可以在虚拟机运行中动态添加。

1登录并体检虚拟机

确认第 0 章的 SSH 服务已启动、端口转发已配置后,用任意 SSH 客户端(MobaXterm / Windows Terminal 均可)连接,密码在交互提示时输入,不要写进脚本或文档:
宿主机终端复制

复制代码
ssh -p 2222 afeng124@127.0.0.1

进入系统后先确认版本、资源和网络可达性,这决定了后面用哪个软件源:
虚拟机内执行复制

复制代码
head -6 /etc/os-release
uname -m
free -h
df -h /
sudo -n true 2>/dev/null && echo "sudo 免密" || echo "sudo 需要密码"
for u in https://download.docker.com/linux/ubuntu/gpg \
         https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg \
         https://archive.ubuntu.com/ubuntu/ ; do
  echo "$(curl -sS -m 8 -o /dev/null -w '%{http_code}' "$u" 2>/dev/null)  $u"
done

本次实测的关键结论: download.docker.com 与 hub.docker.com 连接被重置(HTTP 000),但阿里云的 docker-ce 镜像仓库、GPG 密钥和 Ubuntu 源都返回 200。因此 Docker 官方 CE 包走阿里云镜像站,并额外配置容器镜像加速器。

另外,Ubuntu 24.04 起 APT 源改为 deb822 格式,位于 /etc/apt/sources.list.d/ubuntu.sources;用 grep /etc/apt/sources.list 查不到内容是正常现象,不代表源丢失。

2安装 Docker Engine(官方 CE 仓库 + 阿里云镜像)

2.1 安装依赖并导入 Docker 官方 GPG 密钥

虚拟机内执行复制

复制代码
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg apt-transport-https

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL --retry 3 https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg -o /tmp/docker-repo-key
sudo gpg --batch --yes --dearmor -o /etc/apt/keyrings/docker.gpg /tmp/docker-repo-key
sudo chmod a+r /etc/apt/keyrings/docker.gpg
rm -f /tmp/docker-repo-key

2.2 添加 docker-ce 仓库(自动匹配系统代号)

虚拟机内执行复制

复制代码
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu ${VERSION_CODENAME} stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt-get update

本次生成的源内容为:
/etc/apt/sources.list.d/docker.list复制

复制代码
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu resolute stable

2.3 安装引擎与插件

虚拟机内执行复制

复制代码
sudo apt-get install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

为什么不用系统自带的 docker.io? Ubuntu 源里虽然也有 29.1.3 版,但官方 CE 仓库能持续拿到最新安全更新,且 docker compose、buildx 插件版本配套更完整。本次共下载约 102 MB,受网络速率影响耗时约 5 分钟,属正常。

3配置开机自启、免 sudo 与镜像加速

虚拟机内执行复制

复制代码
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
id $USER

新建 /etc/docker/daemon.json,配置容器镜像加速(本次实测 daocloud、1ms.run、xuanyuan.me 三个节点可用)和日志轮转:
/etc/docker/daemon.json复制

复制代码
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}

虚拟机内执行复制

复制代码
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<'JSON'
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
JSON
sudo systemctl daemon-reload && sudo systemctl restart docker
docker info --format 'server={{.ServerVersion}} driver={{.Driver}} cgroup={{.CgroupDriver}}'

重要: 加入 docker 组后,已打开的旧 SSH 会话不会立即生效 。请重新登录一次(或执行 newgrp docker),之后才能不加 sudo 直接运行 docker 命令。
**安全提示:**docker 组成员等价于拥有宿主机 root 能力,只把账号授予可信使用者;生产环境请勿把 2375/2376 或 docker.sock 暴露到网络。

4验证 Docker

普通用户新会话执行复制

复制代码
docker version
docker compose version
docker buildx version
systemctl is-active docker && systemctl is-enabled docker
docker run --rm hello-world
docker pull alpine:latest && docker run --rm alpine:latest echo "alpine container OK"

本次实际输出摘要:
Docker Engine29.7.2
Docker Composev5.5.0
buildx / containerd0.36.1 / 2.3.3
存储 / Cgroupoverlayfs / systemd
服务状态active + enabled
测试容器hello-world、alpine 均成功
通过标准: docker run --rm hello-world 打印 "Hello from Docker!",且 docker pull alpine:latest 能下载成功 ------ 说明引擎、权限和镜像加速三条链路都正常。

5以 Docker 方式部署 Portainer CE

Portainer 社区版(Community Edition)以单个容器运行,通过挂载宿主机 /var/run/docker.sock 管理本机 Docker。GitHub 最新正式版为 2.45.3 LTS (2026-10-21 发布),本次直接固定该精确标签;官方文档默认使用滚动标签 portainer/portainer-ce:lts。
虚拟机内执行复制

复制代码
docker volume create portainer_data

docker run -d \
  -p 8000:8000 \
  -p 9443:9443 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:2.45.3
端口 用途 本次处理
9443 HTTPS Web UI / API,首次启动自动生成自签证书 已发布,供宿主机访问
8000 Edge Agent 反向隧道,仅边缘计算场景需要 按官方命令一并发布
9000 旧版 HTTP 端口(仅兼容用途) 未发布,减少暴露面

验证容器与版本:
虚拟机内执行复制

复制代码
docker ps --filter name=portainer
curl -ksS https://127.0.0.1:9443/api/status
docker logs portainer 2>&1 | tail -20

本次返回: {"Version":"2.45.3","InstanceID":"..."},容器 Up,重启策略 always,数据卷 portainer_data 挂载于 /var/lib/docker/volumes/portainer_data/_data;Web 首页 HTML 含 data-edition="CE",确认是社区版。

6打通宿主机到 9443 的访问

VirtualBox 的 controlvm natpf1 可以在虚拟机运行中直接追加 NAT 转发规则,不必关机:
宿主机 PowerShell(VBoxManage)复制

复制代码
& "C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" controlvm ubuntuserver natpf1 "portainer9443,tcp,127.0.0.1,9443,10.0.2.15,9443"
& "C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" showvminfo ubuntuserver --machinereadable | Select-String Forwarding

期望看到两条规则:
输出复制

复制代码
Forwarding(0)="Rule 1,tcp,127.0.0.1,2222,10.0.2.15,22"
Forwarding(1)="portainer9443,tcp,127.0.0.1,9443,10.0.2.15,9443"

持久化确认: 本次已检查 D:\vm\ubuntuserver\ubuntuserver.vbox,新增规则确实写入了配置文件,虚拟机重启后仍然有效。若使用图形界面补规则,则需关机后在「设置 → 网络 → 端口转发」新增同样的 9443 条目。

也可以完全不改 VirtualBox,改用 SSH 本地隧道临时访问(与 NAT 规则二选一,避免主机端口冲突):
宿主机终端复制

复制代码
ssh -p 2222 -L 9443:127.0.0.1:9443 afeng124@127.0.0.1

最后在宿主机浏览器打开 https://127.0.0.1:9443 ;自签证书会触发安全警告,选择「高级 → 继续访问」即可。本次宿主机实测 /api/status 与首页 / 均返回 HTTP 200。

7首次初始化 Portainer Web UI

  1. 首次启动会生成一次性 setup token,在虚拟机里查看:

虚拟机内执行复制

复制代码
docker logs portainer 2>&1 | grep -A1 setup_token
  1. 把 setup_token=... 后面的值粘贴到网页初始化页面。
  2. 创建管理员账号,密码至少 12 位;该账号拥有对宿主机 Docker 的完整控制权,请妥善保管。
  3. 环境选择 Local,即可进入仪表盘管理容器、镜像、卷、网络和 Stack。

**token 过期怎么办:**若打开页面时提示令牌失效或超时,重启容器会生成新令牌,重新取一次即可(数据不会丢失):
虚拟机内执行复制

复制代码
docker restart portainer && sleep 5 && docker logs portainer 2>&1 | grep -A1 setup_token

8常用运维命令

目的 命令
确认 / 设置 SSH 开机自启 systemctl is-enabled ssh / sudo systemctl enable ssh
查看 Docker 服务 systemctl status docker
查看 Portainer 状态 / 日志 docker ps --filter name=portainer / docker logs -f portainer
重启 Portainer docker restart portainer
查看资源占用 docker system df / df -h /
升级 Docker 引擎 sudo apt-get update && sudo apt-get install --only-upgrade -y docker-ce docker-ce-cli containerd.io
升级 Portainer(数据保留) docker stop portainer && docker rm portainer → docker pull portainer/portainer-ce:lts → 用第 5 步相同的 docker run 参数重建(仅改镜像标签)
修改镜像加速 编辑 /etc/docker/daemon.json 后执行 sudo systemctl restart docker
卸载 Portainer docker rm -f portainer;确认不再需要数据时再 docker volume rm portainer_data

升级要点: Portainer 的配置、账号与 Stack 定义都保存在 portainer_data 卷里,重建容器时只要卷名和挂载参数不变就不会丢数据;升级前建议在 Settings 里下载一次备份。

9踩坑与解决记录(本次实测)

现象 原因 处理方式
新装虚拟机 ssh -p 2222 ... 报 Connection refused / 连接超时 系统默认没有 openssh-server,或漏了 systemctl enable ssh 导致重启后服务未启动;ufw 为 active 时也可能拦截 22 在 VirtualBox 本地控制台执行 sudo apt install -y openssh-server 与 sudo systemctl enable ssh;ufw 开启时再执行 sudo ufw allow OpenSSH
服务名写成 sshd 提示 Unit not found Ubuntu / Debian 的单元名是 ssh 改用 sudo systemctl enable ssh / systemctl status ssh
download.docker.com 返回 000 / 连接被重置 当前网络无法直连 Docker 官方下载站 改用阿里云 docker-ce 镜像站配置官方仓库,GPG 密钥也从该镜像获取
hub.docker.com 不通,但 docker pull 需要拉镜像 Registry 访问受阻 在 daemon.json 配置多个 registry-mirrors,实测 hello-world、alpine 均拉取成功
grep /etc/apt/sources.list 没有输出 Ubuntu 26.04 使用 deb822 格式 *.sources 查看 /etc/apt/sources.list.d/ubuntu.sources,无需修复
官方仓库是否有 resolute(26.04)的包 新系统代号可能尚未同步 预检 dists/resolute/stable/binary-amd64/Packages.gz,确认有 29.x 版 docker-ce 后再安装
加入 docker 组后仍提示 permission denied 旧会话的用户组缓存未刷新 重新登录 SSH,或执行 newgrp docker
浏览器提示证书不安全 Portainer 9443 使用自签证书 本机环境选择继续访问;生产环境可在 UI 的 SSL 设置中换成自有证书
Portainer 初始化提示 token 无效 首次设置令牌有时效 docker restart portainer 后重新取日志中的 setup_token
APT 下载 102 MB 耗时约 5 分钟 网络速率约 326 kB/s 属正常,等待即可,勿中断 apt 进程

10本次结果快照与脚本清单

检查项 结果
操作系统 Ubuntu 26.04.1 LTS (resolute) x86_64,3.3 Gi 内存 / 25 G 磁盘
SSH 前置(实测) openssh-server 1:10.2p1-2ubuntu3.8;ssh.service 与 ssh.socket 均 enabled + active,22 端口监听;ufw 为 inactive
Docker 29.7.2(客户端与服务端一致),overlayfs,cgroup systemd,active + enabled
插件 Compose v5.5.0、buildx 0.36.1、containerd.io 2.3.3
权限 afeng124 在 docker 组,新会话免 sudo
镜像加速 3 个节点写入 /etc/docker/daemon.json,日志轮转 100m × 3
Portainer CE 2.45.3 LTS,容器 portainer,卷 portainer_data,restart=always
Web UI https://127.0.0.1:9443(宿主机 HTTP 200,/api/status 返回 2.45.3)

以下脚本已与本文档放在同一目录 D:\work\2026\ubuntu_2604\,可按需复用:

  • install_ssh.sh --- 全新虚拟机本地控制台安装并启用 SSH(须在 VirtualBox 窗口内执行,不能经 ssh_run.py 下发)
  • ssh_run.py --- 通过口令登录虚拟机并远程执行脚本(支持 --sudo、--file)
  • probe_vm.sh / probe_sources.sh / probe_repo.sh --- 环境、网络、仓库预检
  • install_docker.sh / configure_docker.sh / verify_docker.sh / final_check.sh --- Docker 安装、配置与验证
  • portainer_probe.sh / install_portainer.sh --- Portainer 端口预检与部署

用 ssh_run.py 在本目录复现后续流程(口令通过环境变量临时提供,不写入任何文件)。注意:第 0 章的 SSH 安装必须先在虚拟机本地控制台完成,否则下面第一条命令也连不上:
宿主机终端(先进入 D:\work\2026\ubuntu_2604)复制

复制代码
VM_PASS='登录口令' python ssh_run.py --file probe_vm.sh
VM_PASS='登录口令' python ssh_run.py --sudo --file install_docker.sh
VM_PASS='登录口令' python ssh_run.py --sudo --file configure_docker.sh
VM_PASS='登录口令' python ssh_run.py --file verify_docker.sh
VM_PASS='登录口令' python ssh_run.py --file install_portainer.sh

文档安全说明: 虚拟机登录口令与一次性 setup token 均未写入本文档,请通过交互输入或 docker logs 现场获取。 整理于 2026-11-12 · 基于 VirtualBox + Ubuntu 26.04.1 LTS 实机操作记录