☰
给Docker装上图形界面:Ubuntu 16.04部署Portainer指南
2026/10/22 4:58:45 网站建设 项目流程

1. 为什么要给Docker装个图形界面:先聊点痛点和适用人群

玩Docker的人大致分两派。一派是终端党,敲命令敲出肌肉记忆,docker ps、docker exec -it这些指令跟呼吸一样自然;另一派是刚入门或者运维场景比较复杂的同学,面对一堆容器、镜像、网络、卷的关联关系,终端里全靠脑补拓扑,稍微复杂一点就晕头转向。我也曾经是前者,直到某天我在一台没有图形界面的服务器上,用命令行给某个应用排障排到凌晨两点,十几个容器互相依赖,网络链路交叉,日志文件散落各处——那一刻我意识到,生产级运维需要的不是更快的键盘速度,而是能一眼看穿全局的可视化视图。

Portainer就是来解决这个问题的。它是一个开源的Docker图形化管理面板,轻量级、部署简单,本体就是一个容器,拉起来之后通过浏览器访问,整个Docker环境的状态一览无余。容器启停、镜像拉取、日志查看、网络管理、数据卷配置,这些高频操作统统可以在网页上点鼠标完成。对新手来说,它是一根拐杖,帮你把Docker的命令行逻辑和可视化界面一一对应起来;对老手来说,它是一个效率工具,尤其在管理多台主机、多套环境(开发、测试、生产)的时候,Portainer提供的多环境管理能力能省下大量敲命令的时间。

这篇文章我用一台Ubuntu 16.04的服务器完整走了一遍部署流程,把从零到能用的每一步细节、遇到的坑、排查思路都记录下来。虽然16.04已经是老版本了,但国内还有大量存量服务器跑着这个系统,而且这套部署逻辑放在Ubuntu 18.04、20.04上几乎可以无缝迁移。如果你正在用带图形界面的云主机、虚拟机,或者手头有闲置的老机器想折腾容器化,这篇文章应该能帮你少走不少弯路。

2. 环境准备与三个老系统上必须处理的坑

2.1 Ubuntu 16.04的底子到底怎样

Ubuntu 16.04(Xenial Xerus)发布于2016年,官方支持周期早就过了,但不代表它不能干活。我手头这台机器配置很一般:双核CPU、4G内存、40G硬盘,跑一些轻量级的Web服务、定时任务、数据库容器绰绰有余。

选16.04作为演示环境,我需要先确认几件事:内核版本、网络环境、软件源可用性。执行下面的命令:

uname -a cat /etc/os-release

16.04默认内核是4.4系列,这个版本对Docker的支持相当成熟,不用担心内核兼容性问题。网络方面,国内服务器访问Docker官方源和镜像仓库有时会比较慢,所以我会在后面的步骤里顺带配置加速器,这一步很重要,尤其当你需要频繁拉取镜像的时候。

2.2 旧软件源失效与APT更新失败的处理

这是16.04机器上最经典的问题。官方源已经归档,直接apt-get update大概率会报404。我第一次操作时就踩了这个坑,满屏的"Failed to fetch"让人头大。

解决思路是把源指向Ubuntu的旧版本归档源(old-releases)。操作方法是编辑/etc/apt/sources.list,把里面的archive.ubuntu.com和security.ubuntu.com替换为old-releases.ubuntu.com。如果你的服务器在国内,强烈建议顺手换成国内镜像源的旧版地址,速度上的差别在后续安装依赖时体感很明显。

改完之后执行:

apt-get update apt-get upgrade -y

这一步不是可选项。Portainer容器本身依赖的底层库、Docker在安装时需要的依赖包,全都要靠正常的软件源才能拉下来。我见过有人跳过系统更新直接装Docker,结果装到一半报依赖缺失,回头再补反而更麻烦。

2.3 时区与系统字符集问题

旧系统上另外一个隐藏比较深的坑是时区和locale。如果系统时区不是Asia/Shanghai,容器日志的时间戳会跟你的预期差8个小时,排查问题时容易产生误导。我习惯在部署前统一设置:

timedatectl set-timezone Asia/Shanghai

locale问题则会影响容器内中文环境的正常显示。16.04默认可能只有C/POSIX locale,建议安装中文语言包并设置默认值:

apt-get install -y language-pack-zh-hans update-locale LANG=zh_CN.UTF-8

有人说这些跟Portainer没直接关系,但我的经验是,基础环境的整洁程度决定了后续部署的顺畅程度。容器技术本身不复杂,复杂的是底层系统的各种隐性差异。

3. 安装Docker并配置镜像加速:命令背后的选择

3.1 安装方式的选择:为什么用官方脚本而不是包管理器

Ubuntu 16.04的默认软件源里确实有Docker包,但版本非常老(1.12左右),老到连docker-compose的某些新语法都不支持。Portainer对Docker API版本有最低要求,老版本Docker虽然也能勉强跑,但部分功能会受限,比如某些Stack模板、容器健康检查的展示逻辑会出问题。

更靠谱的方式是用Docker官方提供的安装脚本:

curl -fsSL https://get.docker.com | sh

执行脚本之前先花10秒钟看看它在干什么。这个脚本本质上做了四件事:检测系统类型和架构、配置Docker官方或镜像源的软件源、安装依赖包、启动并设置开机自启。比起手工三步操作(添加源、更新索引、安装指定版本),脚本的容错性更好,尤其适合在不那么标准的系统环境里跑。

安装完成后验证一下:

docker --version systemctl status docker

看到版本号正常输出、服务状态是active,基础环境就绪。顺手把当前用户加入docker组,省得每一条命令都要sudo:

usermod -aG docker $USER

这一步对后续操作体验的提升是巨大的。注意加完组之后要重新登录会话才会生效。

3.2 配置镜像加速器:没有这一步,拉镜像会等到怀疑人生

Docker Hub在国内的访问速度,用过的人都懂。拉一个一两百MB的镜像,有时候能拖十分钟以上,还经常中途断开重试。配置镜像加速器的逻辑很简单:让Docker从国内能快速访问的镜像仓库拉取内容。

修改/etc/docker/daemon.json:

{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.nju.edu.cn" ] }

这些加速地址会定期更新,我不保证它们永远可用,但原则上多配置几个作为备用总是对的。配置完成后重启Docker生效:

systemctl restart docker

验证加速器是否生效:

docker info | grep -A 5 "Registry Mirrors"

这一步很多人会跳过,但我不建议省。Portainer部署过程中需要拉取两个镜像(本体和一个辅助配置镜像),网络速度直接决定了整个安装过程能不能在几分钟内完成。

4. Portainer部署步骤:两种模式我都给你跑了一遍

4.1 数据卷的规划:容器删除后数据不丢的关键

Portainer本身是个状态化应用——你的用户账号、环境配置、权限设置都存储在它的数据里。如果随随便便用docker run启动,容器一旦被误删,所有配置灰飞烟灭,到时候只能重来。

所以第一步是创建数据卷:

docker volume create portainer_data

数据卷是Docker专门用来持久化数据的机制,它独立于容器生命周期存在。即使容器被删除、重新创建,只要挂载同一个卷,数据就还在。这在生产环境里是黄金法则:有状态的应用一定要把数据放在卷或挂载目录里,而不是依赖容器内部的文件系统。

4.2 单机模式部署:最常用的方式

单机模式适用于一台服务器管理自己上面的Docker。执行下面的命令:

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.19.5

逐项解释一下参数:

  • -d:后台运行,终端不占用。
  • -p 8000:8000和-p 9443:9443:端口映射。8000是HTTP入口(新版用于某些代理场景),9443是HTTPS安全入口。旧版本可能用的是9000端口显式映射,我建议直接上9443,安全性和合规性都好一些。
  • --restart=always:服务器重启后Docker守护进程会自动拉起这个容器,这是生产环境必配项,不然服务器重启一次你的面板就没了一次。
  • -v /var/run/docker.sock:/var/run/docker.sock:挂载Docker的Unix套接字。Portainer就是靠这个套接字和Docker守护进程通信、获取容器和镜像信息的。这个挂载是它的灵魂,没有这行,Portainer就是个空壳面板,什么都管不了。
  • -v portainer_data:/data:把数据卷挂载到容器内的数据目录。

等容器状态显示healthy或者up,就可以通过浏览器访问了:https://你的服务器IP:9443。

4.3 多环境管理模式:Agent模式的部署差异

前面说的单机模式只能管一台服务器。如果你的服务器不止一台,或者想把开发机、测试机、生产机的Docker环境集中到一个面板里管理,那就需要Portainer Agent。

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:2.19.5

然后在主Portainer面板的"环境"页面里新增环境,类型选"Agent",填写被管理机器的IP和9001端口。通信层面Portainer和Agent之间走的是加密的私有通道,不需要在防火墙上额外暴露太多端口。

我实际体验下来的感受是:如果你只有一台服务器,单机模式完全够用;当你手头开始出现3台以上的机器,Agent模式带来的集中管理体验是质的飞跃。你可以从同一个浏览器窗口切换管理任意一台机器,不再需要SSH来回跳。

4.4 部署前必须想清楚的端口选择

端口选择这件事,我多说两句。9000端口在早期版本的Portainer里是默认HTTP端口,很多老的教程都在用。但是新版本默认是9443走HTTPS,8000和9000都各有用途。我在部署时直接用了9443,原因很简单:生产环境裸跑HTTP管理面板,账号密码在网络上明文传输,那跟裸奔没区别。Portainer的登录页自带HTTP基本认证保护(多一层),但底层通信是明文的话,抓包工具一样能拿到凭证。

如果你的场景里必须用HTTP(比如内网开发环境图省事),那就用-p 9000:9000显式映射。如果是为了外网访问的安全考虑,9443 + 反向代理 + 证书是更稳的组合。

5. 首次登录与中文界面设置:细节比你想的多

5.1 初始化管理员账号

部署完成后,浏览器访问https://服务器IP:9443,会看到安全警告(自签名证书导致的,属正常现象)。选择"高级"继续前往即可。

首次登录页会让你创建管理员账号。这里有个细节值得注意:用户名不能是"admin"。Portainer从某个版本开始强制要求管理员用户名不能叫admin,这是防止暴力破解的安全策略。你起一个不容易被猜到的用户名,配一个强度足够的密码。

密码强度要求是至少12位,必须包含大小写字母和数字。我建议加上特殊字符,毕竟这是管理整个Docker环境的入口账号,一旦泄露,所有容器、数据卷、网络都暴露在风险之下。

创建完账号,初次进入面板会有一个环境配置引导流程——询问你是管理本地Docker环境还是远程环境。这个页面直接选择"开始"即可,本地环境已经通过之前挂载的docker.sock自动检测到了。

5.2 中文化的两种思路

Portainer官方已经内置了多语言支持,包括简体中文。但UI语言切换不在主设置里,而是藏在每个用户的个人偏好设置中。

点击左下角的用户头像,进入"我的设置",在界面语言下拉框中选择简体中文,保存之后刷新页面,整个面板就切换成中文界面了。这一步对新手特别友好。虽然Docker生态的官方文档基本是英文,但Portainer的界面术语本就和Docker命令一一对应,切到中文后,"容器""镜像""卷""网络""栈"这些概念能让直觉理解的门槛大大降低。

如果你是前端开发者,或者有少量Node.js基础,甚至可以构建一个Portainer的中文语言包镜像来汉化得更彻底,官方文档里有相关说明。但对大多数人来说,内置的中文翻译准确度已经够了,没必要折腾。

5.3 进入主界面之后先看哪几个页面

设置完语言,我建议你先别急着乱点,按下面的顺序把面板的结构摸一遍:

  1. 仪表盘:一进来就能看到当前的CPU、内存使用率,以及运行中容器数、镜像数、卷数、网络数。这是整个环境的体检报告。
  2. 容器:显示所有容器及状态,支持批量启停、删除、查看日志、进入控制台。这里对应的是docker ps、docker logs、docker exec。
  3. 镜像:管理本地镜像列表,支持拉取、删除、构建(通过上传Dockerfile)。对应docker images、docker pull。
  4. 网络:查看所有自定义网络,能看到容器间的拓扑关系和连接状态。对应docker network。
  5. 卷:数据卷管理,能直观看到每个卷被哪个容器挂载着。对应docker volume。
  6. 栈(Stack):通过docker-compose的YAML文件一键部署多容器应用。这是Portainer最有价值的功能之一,后面我单独讲。

每个页面都和Docker命令的某一个维度精确对应。我在引导新手的时候常说一句话:你在Portainer里点的每一个按钮,本质上都是在替你在后台执行一条Docker命令。看懂了这个对应关系,使用面板的过程就是一个隐性的Docker命令学习过程。

6. 功能实战:堆栈编排、资源监控与权限管理

6.1 堆栈(Stack)功能:多容器应用的一键部署

我用一个实际案例来说明Stack功能的威力。假设你要部署一个WordPress博客,它至少需要两个容器:一个MySQL数据库和一个WordPress应用,并且两个容器需要通过网络互相通信,数据和配置需要持久化。

传统命令行方式需要分步创建网络、拉取镜像、运行容器、配置环境变量、处理数据卷,命令加起来有十几条。用Portainer的Stack,你只需要在"堆栈"页面里粘贴一个docker-compose YAML文件的内容,点击"部署",它就能自动完成所有工作。

我实际用的一个Compose文件长这样:

version: '3.3' services: db: image: mysql:5.7 restart: always volumes: - db_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest restart: always ports: - "8080:80" volumes: - wp_data:/var/www/html environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress volumes: db_data: wp_data:

点击部署后,Portainer会自动为这个Stack创建默认网络、创建数据卷、按依赖顺序启动容器(先数据库后应用)。整个过程只需要完成一次页面粘贴操作,这个功能对日常开发环境的搭建效率提升是肉眼可见的。

有现成的docker-compose.yml文件的话,也可以用Portainer的"从Git仓库部署"功能,配合Webhook,可以实现代码推送到仓库后自动更新容器,这就是一套简化版的持续部署流程。对中小型项目来说,这个能力其实已经够用了,不需要再额外上完整的CI/CD工具链。

6.2 容器操作体验:日志、终端、文件三件套

在"容器"页面点进任何一个运行中的容器,你会看到一个管理面板,里面有日志、控制台、文件浏览三个核心工具。

日志功能支持实时滚动,相当于docker logs -f的可视化版本。特别有用的地方在于:你可以按时间范围过滤日志,支持从某个错误信息的时间点前后回溯上下文,排障时不用再翻终端翻到头昏。

控制台功能支持在容器内部执行命令,相当于docker exec -it。很多人不知道这功能还能直接访问容器内的文件系统,通过"文件"标签页可以查看容器内任意路径的文件,甚至下载、上传文件。这个能力在调试容器内应用配置时非常实用——比如容器里某个配置文件写错了,终端里vi用起来费劲,直接在网页上编辑完保存,效率高得多。

6.3 资源监控:不用再专门装别的监控工具

Portainer自带的监控页面能展示CPU、内存、网络I/O、磁盘I/O的历史趋势图。虽然功能深度比不上Prometheus加Grafana的组合,但它的价值在于零配置、开箱即用。

我个人的使用习惯是:日常巡检看Portainer的监控仪表盘,一旦发现某个容器资源异常飙升,再切换去看它的日志细节定位原因。生产环境的监控告警才上Prometheus那套组合,普通项目或实验环境,Portainer自带的监控已经完全够用。

6.4 用户与权限:多人协作时的最小权限原则

如果同一台服务器有多个人在用,或者你想给同事分配一个只能查看、不能乱删容器的账号,Portainer的用户管理功能正好派上用场。

在"设置——用户"里可以创建新用户,然后通过"环境——分配访问权限"来限制该用户对某个环境的操作权限。Portainer的权限模型分几种:

权限级别能力范围
只读查看容器和镜像状态,不能执行任何变更操作
操作员可以管理容器,但一般不能修改系统设置
管理员完全控制所有功能和环境配置

我通常给负责业务代码的同事分配操作员权限,这样他们可以独立重启服务、查看日志,但不至于误删环境配置。这套权限模型对小型团队协作很有价值,毕竟生产服务器永远不是一个人应该瞎搞的地方。

7. 常见报错排查链路与加固手段

7.1 容器反复重启/日志能访问但服务不可用

有人会遇到一个现象:Portainer容器启动了,但浏览器访问时页面打不开,或者能打开首页但登录后页面刷新不出来。先从这几个方向排查。

第一,确认端口映射是否正确。用docker ps看容器的端口映射列,确认主机端口和容器端口没有配错。我之前遇到过一次是配置文件里把9443写成了443,结果应用监听的端口和暴露的端口根本对不上。

第二,检查防火墙。Ubuntu上如果启用了UFW,默认策略会丢弃外部对非标准端口的访问。执行:

ufw allow 9443/tcp ufw status

云服务器的话还要检查安全组规则,有时候服务器本地一切正常,但从外部就是访问不了,大概率是安全组没放行对应端口。

7.2 Portainer连不上Docker:套接字挂载问题在作怪

这个问题的典型症状是面板能登录,但打开环境时提示"无法连接Docker",环境状态显示为不可用。

原因几乎都在于启动Portainer容器时没有正确挂载Docker的套接字。确认启动命令里包含-v /var/run/docker.sock:/var/run/docker.sock这两行。如果没有,Portainer进程在容器内部无法和宿主机上的Docker守护进程通信,自然什么都看不到。

另外一个极端情况是Docker守护进程的监听方式不是Unix套接字而是TCP端口——但这种情况很少见,如果你没主动改过Docker服务配置,默认就是套接字模式。

7.3 给面板加一层安全护栏的四个手段

Portainer面板一旦暴露到公网,就等于把服务器上所有容器的管理权交给了能登录的人。即便登录页有密码保护,我还是会做下面这几件事:

第一,启用两因素认证。在"设置——认证"里启用TOTP认证,配合身份验证器App使用,给登录加上第二道锁。

第二,限制访问来源。生产环境面板不对全网开放,只允许特定IP段的机器访问。可以用防火墙规则实现:

ufw allow from 你的办公网段 to any port 9443 proto tcp

第三,通过反向代理隐藏面板入口。用Nginx做一层代理,路径设为类似/portainer这样不易猜到的路径,再加上一层HTTP Basic认证,访问难度就高了一截。注意反向代理配置中要保留长连接和WebSocket支持,否则Portainer的部分功能(比如实时日志流)会异常。

第四,定期备份portainer_data卷。这个操作很多人会忽略,但Portainer里所有配置、用户信息、环境关联全在这份数据里。备份方式很简单:

docker run --rm -v portainer_data:/data -v $(pwd):/backup alpine tar czf /backup/portainer_backup_$(date +%F).tar.gz -C /data .

恢复时解压到同名卷即可。

7.4 版本升级的正确姿势

Portainer升级并不复杂,但有风险点:如果从旧版本直接换成新版本容器,数据格式在某些大版本之间可能不兼容(尤其是从1.x升级到2.x)。

我的升级策略是:先备份数据卷,然后拉取新版本镜像,用相同的挂载参数启动,先观察数据和功能是否正常,至少跑一周确认没有异常后,再删除旧容器。这样做的好处是可以随时回滚——只要把容器换成旧版本镜像重新启动,数据卷一挂,配置就全回来了。这个方案比较保守,但对生产环境的平滑升级来说,稳定性远比最快版本重要。

8. 使用习惯上的几点个人体会

用过一段时间之后,我和Portainer之间磨合出了几个固定的工作习惯,分享给大家参考。

对于日常操作,大部分容器启停、日志查询我都在Portainer里完成,但涉及复杂的网络排障、文件系统深度查看,我依然会回到SSH终端。两者不是替代关系,而是互补——面板负责直观和效率,终端负责精细和自由。这一点想明白了,就不会纠结"到底该用哪个"。

对于新手入门,我会建议他们先把Portainer当作学习辅助工具,每个操作都去留意面板背后的Docker命令是什么,时间久了,命令行能力也自然涨上来了。上面说过,点击按钮的本质就是执行命令,把对应关系记熟之后,你等于同时会了两种操作方式。

对于Stack模板,我习惯把常用的几套Compose文件保存下来,包括数据库、缓存、日志收集等组合,部署新环境时复制粘贴就能跑起来。这也算是自己的一套“个人运维资产”,时间越久越值钱。

最后说一句关于版本的选择:Portainer社区版(CE)已经完全能满足个人和小团队的绝大部分需求,企业版多了RBAC细粒度权限、多集群管理这些高级功能,但它的服务注册门槛和费用对小规模使用来说没有必要。先用社区版跑起来,等规模到了再评估要不要升级,这是个理性的路径。

这篇文章从环境准备一路写到了安全加固和备份,覆盖了我在Ubuntu 16.04上部署Portainer的完整过程和思考。如果你按照这个流程操作,大概率能在半小时内把面板跑起来。过程中的任何报错,多半都能在前面提到的排查链路里找到方向。边用边学,边踩坑边积累,这才是接触一个新工具最真实的状态。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询