先说一个我自己真实遇到的场景:服务器上跑了二十几个容器,每次排查问题,最烦的不是容器跑挂,而是想确认某台机器上到底哪个容器占着端口、哪个容器日志刷得飞快,还得先 ssh 上去敲一串docker ps、docker logs、docker stats才能拼出全貌。后来我把 Portainer 装上,通过浏览器打开一个网页,所有容器的运行状态、日志、资源占用一目了然,很多日常操作直接从界面里点按钮就完成了。这篇东西就以 Ubuntu 16.04 为例,完整讲一遍 Portainer 的部署、核心功能、老系统上容易踩的坑,以及我实际用下来的经验和建议。
Portainer 本质上是一个 Docker 图形化管理工具,本身也是跑在 Docker 里的一个容器,体积小、资源占用低,不需要单独装数据库或者其他依赖环境,非常适合那种服务器数量不多、又不想上重型管理平台的团队和个人开发者。接下来我按实际操作顺序,从环境准备讲到功能使用,再把常见故障集中捋一遍。
1. 为什么Docker要配一个图形化管理工具,Portainer到底解决了什么问题
1.1 命令行管理Docker的痛点
我自己平时并不排斥命令行,甚至绝大多数操作都是先敲命令解决。但容器数量一旦多起来,命令行的短板会非常明显:docker ps -a输出越来越长,字段越堆越多;docker inspect的结果一屏根本放不下;docker logs要加--tail才能只看到末尾几十行;查一个容器的资源占用还得开另一条终端跑docker stats。如果同时排查十几个容器,这种“反复敲命令、反复翻屏”的效率就会很低。
另一个现实问题是协作。团队里不是所有人都有 Docker 基础,给一台测试服务器,有人连镜像和容器是什么都分不清,更别提在终端里敲docker run那一长串参数。这个时候,一个直观的 Web 界面能大幅降低使用门槛。Portainer 的价值就在这里:它把 Docker 原本那套 API 和命令行能力,封装成了图形界面里的按钮、表单和列表,你想要的信息直接展示在页面上,你要做的操作点一下就执行。
1.2 Portainer是什么,它适合谁
Portainer 是一个轻量级的容器管理平台,部署方式很简单,就是把一个镜像跑起来,通过浏览器访问它的管理页面。它能管理本机的 Docker,也能通过 Agent 方式管理远程机器,还支持 Swarm 集群和 Kubernetes 环境。社区版是免费的,日常单机、小集群场景基本够用,不需要折腾授权。
适合它的用户大概有这么几类:一是维护三五台以内 Linux 服务器,不想为监控和运维单独搭一套复杂系统的人;二是刚接触 Docker、对命令行不熟,希望用图形界面理解容器、镜像、卷之间关系的新手;三是需要把部分管理权限交给同事、又不想把服务器 root 密码交出去的团队。对我个人来说,Portainer 最大的贡献是“一屏看清全局”,登录之后首页就把容器状态、镜像数量、卷和网络情况列得明明白白,省去大量自己拼信息的功夫。
1.3 同类图形化方案怎么选
Docker 图形化管理的选择其实不算多,我也简单对比过另外几个方案,才最终稳定用 Portainer。
| 方案 | 定位 | 适用场景 | 备注 |
|---|---|---|---|
| Kitematic | Docker 官方出品的桌面客户端 | 个人开发机 | 已停止维护,功能有限 |
| Rancher | 面向 Kubernetes 和集群编排 | 生产级集群管理 | 偏重,资源占用高,适合大规模环境 |
| Cockpit | Linux 系统管理面板 | 系统级监控 | 侧重 OS 而不是 Docker 容器 |
| Portainer | 轻量容器管理 | 单机、Swarm、小集群、教育与测试 | 部署简单、社区版免费、上手快 |
选 Portainer 还有一个很实际的原因:在 Ubuntu 16.04 这种比较老的系统上,轻量意味着更少依赖、更少兼容性问题。它本身只是一个容器,对宿主机内核和系统库的要求远低于那些带 Agent、带数据库、带复杂依赖的管理平台。装上就能用,出问题也容易定位。
2. Ubuntu 16.04上搭建Docker环境,这一节最容易出问题
2.1 部署前先检查系统和内核
Portainer 虽然是容器,但它要做的核心事是通过 Docker 的 socket 控制宿主机上的 Docker 守护进程,所以宿主机先把 Docker 跑稳才是前提。Ubuntu 16.04 已经是比较老的发行版,默认内核是 4.4,部署前我建议先看几项基础信息。
lsb_release -a cat /etc/os-release uname -r docker --version docker info第一行查系统版本,第二行查详细的系统信息,第三行查内核,第四行和第五行确认 Docker 是否已经安装、存储驱动是什么。16.04 上如果之前装过旧版本 Docker,建议先把旧包清理掉再装新的,避免冲突:
sudo apt-get remove docker docker-engine docker.io containerd runc这个清理动作做完不会删除已有的镜像和容器目录,只是移除旧程序包,可以放心执行。
2.2 安装合适版本的Docker CE
Ubuntu 16.04 的代号是 xenial,Docker 官方软件源里一直有对应的版本目录。安装步骤比较常规:
sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo apt-get update sudo apt-get install -y docker-ce这里有个值得专门提醒的点:Ubuntu 16.04 自带的 systemd 版本偏老,如果直接装最新的 Docker CE(比如 23.0 以上的大版本),部分机器上可能出现服务和 cgroup 相关的兼容问题。我在实际部署中更倾向于指定版本安装,比较稳的是 20.10.x 或 19.03.x 这一类在 16.04 上验证充分的版本:
apt-cache madison docker-ce sudo apt-get install -y docker-ce=20.10.23安装完成后立刻设置开机自启并启动服务:
sudo systemctl enable docker sudo systemctl start docker sudo systemctl status docker顺便检查一下存储驱动。旧内核容易默认走 devicemapper,如果docker info里显示 Storage Driver 不是 overlay2,可以尝试调整配置,overlay2 在实际体验中稳定性更好。
2.3 docker.sock权限是整个管理链路的基础
这一步看起来不起眼,却是 Portainer 能不能正常工作的关键。Docker 守护进程默认监听在/var/run/docker.sock这个 Unix socket 上,它的属主是 root,属组是 docker。直接执行 docker 命令时如果不是 root,也不是 docker 组成员,就会看到 permission denied。
Portainer 容器要管理宿主机 Docker,必须把这个 socket 挂载进容器,本质上就是把宿主机的 Docker API 暴露给容器里的进程。如果权限不对,哪怕 Portainer 本身启动成功,登录后添加本地环境时也会报错,常见的就是连接 Docker daemon 时提示权限被拒。所以装完 Docker 后,我习惯先确认 socket 权限:
ls -l /var/run/docker.sock sudo usermod -aG docker $USER执行完usermod后记得重新登录或者重启终端,组权限才会生效。如果你打算让 Portainer 容器以 root 方式运行,对 socket 的访问一般没问题,但如果是受限制的容器环境,就必须格外注意这一层权限映射。
3. 部署Portainer的完整流程,从命令行到Compose一次讲清
3.1 规划持久化数据和端口
Portainer 自身的数据会存放在容器的/data目录里,包括账号信息、环境配置、授权记录等。如果不做持久化,容器一删,配置全部归零,每次升级都要重新初始化一遍管理员密码,非常麻烦。所以第一步就是创建一个持久化数据卷。
docker volume create portainer_data关于端口,Portainer 涉及的比较常见的有三个:8000 端口用于 Edge Agent 或反向代理场景的通道;9000 端口是 HTTP 管理界面;9443 端口是 HTTPS 管理界面。最简部署至少映射 9000,如果希望直接用浏览器 HTTPS 访问,就把 9443 也映射出来。Ubuntu 16.04 上如果启用了 ufw 防火墙,记得放行需要访问的端口。
3.2 用docker run快速部署
创建完数据卷,直接用一条 docker run 命令就能完成部署。我最常用的是这个组合:
docker run -d \ -p 8000:8000 \ -p 9000:9000 \ -p 9443:9443 \ --name portainer \ --restart=always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer-ce:latest拆开解释一下每个参数:
-d:后台运行。-p 8000:8000、-p 9000:9000、-p 9443:9443:把容器的三个端口映射到宿主机对应端口。--name portainer:给容器起个固定名字,方便后续 stop、start、logs。--restart=always:服务器重启后容器自动拉起,这个参数对生产环境非常省心。-v /var/run/docker.sock:/var/run/docker.sock:把宿主机的 Docker socket 挂进容器,这是 Portainer 能操作宿主 Docker 的关键。-v portainer_data:/data:把数据卷挂到容器的数据目录,确保持久化。
这里要说明一下镜像名。新版本官方镜像已经改为portainer/portainer-ce,如果你之前见过老的portainer/portainer镜像名,那是旧版本遗留,新装环境建议直接用portainer-ce。启动后浏览器访问http://服务器IP:9000,第一次打开会要求设置管理员账号密码。密码建议设长一点,因为这等同于你整个 Docker 主机的管理员入口。
3.3 用Docker Compose方式部署
如果你习惯用 docker-compose 管理多容器项目,也可以把 Portainer 纳入统一编排。Ubuntu 16.04 上常见的 Compose 文件写法是这样:
version: '3' services: portainer: image: portainer/portainer-ce:latest container_name: portainer restart: always ports: - "8000:8000" - "9000:9000" - "9443:9443" volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer_data:/data volumes: portainer_data:在 docker-compose 文件所在目录执行docker-compose up -d就可以。如果你在 16.04 上用的是老版本的 docker-compose v1,注意保留version: '3'这一行;如果系统上的 docker-compose 版本太旧导致语法解析报错,建议先升级 compose 工具再看。
3.4 用Agent方式纳管远程机器
Portainer 还有一个我很常用的玩法:当你有多台服务器时,不需要每一台都单独开一个 Portainer Web 界面,而是只需一台主管理节点,其他机器通过 Agent 方式接入。在被管理的目标机器上执行:
docker run -d \ -p 9001:9001 \ --name portainer_agent \ --restart=always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /var/lib/docker/volumes:/var/lib/docker/volumes \ portainer/agent:latest然后在 Portainer 主界面的“环境”中添加远程环境,类型选 Agent,地址填目标IP:9001,这台机器就会被纳入同一个管理面板。这样做的好处是:所有机器的容器状态、镜像清单、日志入口统一在一个页面里,不用挨个登录服务器去查。对于小团队维护几台机器,这种模式既轻量又够用。
4. 进入Portainer图形界面,核心功能实践
4.1 Dashboard先看全局状态
第一次登录 Portainer 后,会进入一个引导页面,让你选择要连接的“环境”。如果刚才启动容器时把 docker.sock 挂进去了,这里选 Local 就能直接管理本机 Docker。
进入主界面后,Dashboard 页面就是整套工具的“总览屏”。上面显示容器总数和运行数量、镜像数量、卷数量、网络数量,还有 CPU 和内存使用情况。很多之前需要用命令拼出来的信息,这里一眼就能看到。顶部还提供了环境切换入口,如果有多台机器通过 Agent 接入,可以在不同环境之间来回切换,不用重新登录。这个设计对日常巡检来说非常有用,我每次上服务器第一件事就是看一眼 Dashboard,确认没有容器处于异常重启状态。
4.2 容器管理:状态、日志、控制台
容器列表页是使用频率最高的页面。列表会展示所有容器,包括运行中和已停止的,每个容器一行,能直接看到镜像名、状态、启动时间、端口映射,还可以对容器进行 start、stop、restart、kill、remove、pause 等操作。这些操作原本要记住一堆命令,现在全部变成了按钮。
点击任意容器进入详情页,里面有几个特别实用的块:
- Logs:图形化查看容器日志,支持时间范围筛选。
- Stats:查看 CPU、内存、网络等实时资源占用。
- Console:直接进入容器的交互式终端。
- Inspect:查看完整的 JSON 配置信息,相当于图形化版的
docker inspect。
实际工作中最有帮助的是 Logs 和 Stats。容器频繁重启时,我第一个动作就是进 Logs 看启动报错;内存快吃满的时候,Stats 页能直观看到是哪个容器在产生压力。这套组合在定位问题时比在终端里一条条敲命令高效得多。
4.3 镜像管理、仓库配置与清理
Images 页面可以看到宿主机上所有已拉取的镜像,支持 Pull 新镜像、Build 镜像、删除无用镜像、清理悬空镜像等操作。对于不常敲命令的同事,在界面上填一个镜像名点 Pull 就能完成拉取,体验非常友好。
Registries 页面用来配置镜像仓库。默认已经包含 Docker Hub,如果你有私有仓库或者内网自建的 Registry,可以在这里加入配置,后续拉取和上传镜像都能直接选择对应仓库。配置好镜像加速地址也可以放在这个思路里,不过具体要看你的 Docker daemon 配置,Portainer 只是管理端,镜像加速仍然需要在 Docker 守护进程层面设置。
镜像多起来之后,最容易出现的就是“悬空镜像”堆积,也就是已经没有容器使用的旧镜像层。Portainer 的 Image 页面专门提供了清理功能,定期清一次能释放不少磁盘空间。
4.4 Stacks与App Templates,快速拉起一套服务
Stacks 功能相当于把 docker-compose 搬到了网页上。你可以新建一个 Stack,把 Compose 内容直接粘贴进去,Portainer 会自动解析并创建对应的容器和服务。这个功能适合部署多容器应用,比如一套 Web 服务加数据库加缓存,只要准备一份 Compose 文件,在界面上点几下就完成了。
App Templates 则更适合新手和测试环境。Portainer 内置了一批常用服务的部署模板,比如 Nginx、MySQL、Redis、WordPress 等,选择模板后填写少量参数就可以一键部署。测试环境临时起一个 Redis 或者 MySQL,用模板创建比手敲docker run参数要省事得多。虽然生产环境我一般还是会写镜像版本、资源限制等细节,但模板提供的起点确实有参考价值。
4.5 网络、卷和用户权限,别忽略这些隐藏重点
Networks 页面能看到当前 Docker 的 bridge、host、overlay 等网络,也可以新建自定义网络。Volumes 页面管理数据卷,创建、删除、查看挂载情况都很直观。这两个页面平时不常用,但当容器之间需要网络隔离、或者某个服务的持久化数据需要迁移时,图形界面的优势就会体现出来。
用户权限是很多人容易忽略的一块。Portainer 支持创建普通用户、配置团队、设置角色,更精细地控制每个人能操作的范围。如果只是需要让同事查看状态,不必给他服务器 root 权限,在 Portainer 里分配一个只读角色就可以。考虑到 Portainer 本身权限非常高,能管理它的人等于能管理整个 Docker 宿主机,所以我强烈建议不要只用一个超级管理员账号通吃,日常操作尽量用受限账号。这一点在多人协作的团队里尤其重要。
5. 常见问题与故障排查,直接照着查
5.1 界面打不开的排查顺序
部署完 Portainer,最常见的问题就是浏览器访问不到管理界面。我的排查顺序基本固定:
- 先确认容器有没有在运行:
docker ps -a | grep portainer。如果容器没起来,执行docker logs portainer看报错。 - 确认端口映射是否生效:
docker port portainer,对比输出结果和部署时填的端口是否一致。 - 检查防火墙:Ubuntu 16.04 上如果有 ufw 或 iptables 规则,先把 9000 端口的入方向放行。
- 在服务器本机试一下:
curl -I http://localhost:9000,能返回 HTTP 响应说明服务本身正常,问题大概率出在网络层。
按照这个顺序,多数情况都能快速定位。我遇到比较多的是防火墙规则没放行,或者部署时端口映射写错,比如写成了9000:80,导致浏览器访问 9000 时连接的是容器内 80 端口,自然打不开。
5.2 添加环境时报permission denied
第一次登录 Portainer,或者在环境列表里添加 Local 环境时,如果报错信息包含Got permission denied while trying to connect to the Docker daemon socket,基本都是 socket 权限问题。原因集中在几个方面:
- 容器启动时没有把
/var/run/docker.sock挂载进去。 - 宿主机 Docker socket 权限被改过,容器内部进程无法读取。
- Docker 被配置成了 TCP 远程模式,本地 socket 没有监听。
处理方式很简单:先检查宿主机 socket 是否存在且权限正确,确认 docker 组存在,再把当前用户加入 docker 组后重新登录。对于 Portainer 容器本身,确认启动命令里-v /var/run/docker.sock:/var/run/docker.sock没有被遗漏。这几个点逐一排查,问题就能解决。
5.3 版本兼容问题不能忽视
Ubuntu 16.04 属于老系统,Docker 和 Portainer 的版本搭配还是要留心。下面是我整理过的经验对照,可作为参考:
| 宿主机环境 | 适合的Docker版本 | Portainer版本建议 |
|---|---|---|
| Ubuntu 16.04 内核4.4 | Docker 18.09.x | Portainer 1.24.x |
| Ubuntu 16.04 内核4.4 | Docker 19.03.x | Portainer 2.x 早期版本 |
| Ubuntu 16.04 内核4.4 | Docker 20.10.x | Portainer 2.9+ 均可 |
| Ubuntu 18.04及以上 | Docker 20.10+/23.0+ | 最新 portainer-ce |
这个表格不是绝对的,但基本反映了我实际部署中的边界。新版本 Portainer 通常对 Docker API 的兼容性做得不错,真正约束更多来自宿主机系统和 Docker 版本。如果发现 Portainer 某些页面报错或者功能展示异常,先别急着怀疑软件本身,把 Docker 版本和 Portainer 版本对照检查一下,往往能发现线索。
5.4 更新、备份与恢复
Portainer 本身升级频率不高,但偶尔也需要更新。更新流程按顺序来:
docker pull portainer/portainer-ce:latest docker stop portainer docker rm portainer docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 \ --name portainer --restart=always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer-ce:latest升级前最好做一次备份。最稳妥的方式是直接把数据卷目录打包:先停掉容器,再压缩卷的_data目录内容。恢复时,把解压出来的文件放回新卷对应目录,再启动容器即可。Portainer 2.x 之后也提供了图形界面的备份功能,在 Settings 页面里可以导出备份包,恢复时在同样的入口选择备份文件。我自己的习惯是每次升级前都手动导出一份备份,宁可多备份,也不要在配置丢失后重来一遍。
6. 我在Ubuntu 16.04上用Portainer的几点体会
最后分享一些零散但实用的体会。第一,不要图省事把 Portainer 的 9000 端口直接暴露到公网。这工具权限太大,一旦被人扫到并弱口令登录,等于把整台 Docker 主机的控制权交出去。个人使用可以放在内网,或者用反向代理加 HTTPS 和访问认证。
第二,Ubuntu 16.04 本身已经比较老了,系统源、软件包和安全更新都不如新版本及时。如果你只是在一台内网测试机或者老设备上部署 Portainer,那没有问题;但如果条件允许,还是建议在部署新业务前把系统升级到仍在维护的版本。老系统上跑容器本身没问题,瓶颈更多在于系统底层的驱动和依赖支持。
第三,加上--restart=always这一个参数能省很多事。我遇到过服务器重启后整个服务起不来的情况,而 Portainer 因为有了这个参数,系统一开机就自动拉起来,配合宿主机的自动登录和网络配置,基本能做到无人值守恢复。
第四,给同事分配只读账号,是避免“误操作删容器”最直接的办法。在多人协作场景下,不是每个人都对 Docker 容器有清楚认知,一个只读权限足够让他们查看日志和状态,又不会导致误删生产数据。权限管理看似小事,长期下来能替你挡掉很多不必要的麻烦。
Portainer 这种图形化工具并不能替代对 Docker 本身的理解,但它确实降低了日常维护的操作成本。如果你也经常在终端里反复敲着同样的命令管理容器,花十分钟部署一个 Portainer,大概率会觉得这笔时间花得值。