封面插图by@芸草冰
在本次迁移系统之前,我从来没有接触过Docker,对Docker的理解停留在他是在操作系统中的一个隔离分区,类似于虚拟机。
在本次服务器迁移的过程中,我有一些服务必须依赖于Docker才能安装,于是我接触了Docker镜像与容器。
在撰写本文章时,我还仅仅作为Docker的极初学者,仅完成了Docker的部署、容器创建、镜像拉取操作,并不有太深的理解。
Docker在宝塔面板中独立为一个分区,点击后会在系统中自动创建Docker环境,这是我对Docker的最初了解。
在宝塔自带的Docker应用商店中,可以直接安装众多Docker应用,也可以直接在Docker中创建网站,不过宝塔Docker网站仅支持Nginx,而我的网站为Apache,这里就没办法体验了。
这次我需要在Docker中安装的应用一共有两个,分别是Uptime Kuma和AllinSSL。前者用于我网站的可用性监控,后者为我域名的SSL证书自动续签服务。
在应用商店中很方便的就搜索到了这两个应用,点击安装后即可自动创建。
安装后,根据安装时设置的信息,即可通过IP地址+端口的形式进入应用,这点比较方便。但进入服务后就引申出了撰写本文的原因。
在Uptime Kuma中,我安装的是宝塔提供的最新版本,但应用提示有更新可用。而本文讨论的主旨问题即是——如何更新Docker中的应用。
在我最开始的理解中,Docker与WordPress有一些相似,即Docker为一个平台,安装的应用则与插件类似,如果需要升级插件,那么直接点击升级即可。
事实上这并不正确,Docker有容器与镜像的区别。我的理解是,可以将镜像认为是安装包,而容器则是独立运行这个安装包的一个环境,而Docker则是提供这一整套流程的一个解决方案,镜像与镜像之间;容器与容器之间互不干扰。
而我现在需要升级应用,即可以理解成以下步骤:停止容器的运行 > 将容器与原来的镜像解耦 > 拉取新版本的镜像 > 将容器与新版本的镜像绑定
理解是这么理解,但实际操作还是有一定困难。
首先我发现在宝塔Docker面板中的“容器”菜单下,找到需要升级的容器,点击“管理”,即可找到“升级容器”的选项,在这里可以直接升级容器,默认拉取的是最新版本的镜像,即“latest”版本。但在最初拉取的时候,也是拉取“latest”版本,那么系统中就已存在“latest”版本;再次进行拉取则直接调用了系统中的“latest”版本的镜像,并没有在服务器中进行拉取。这可能是宝塔的问题。
那么发现这个问题后,该如何解决呢?
所有的Docker镜像拉取都默认从Docker Hub中拉取,我们可以直接访问Docker Hub的官网,在搜索栏搜索“作者/软件名”即可找到需要拉取的镜像。
点击进入后,即可在右侧找到拉取指令,点击三个点按钮,复制或者记下版本号,下一步回到宝塔面板中进行操作。
回到宝塔面板后,我们在升级容器选项中输入刚刚命令中冒号后方的内容,即2.0.0-beta.4,点击升级,这时候弹出了一个窗口:
宝塔提示我们说升级操作会丢失未持久化的数据,我不以为然,直接按了确定按钮。出事了,我的Uptime Kuma中的数据全部丢失,这是为什么?
查阅资料显示可能有三种可能:
- 容器升级的本质是替换:Docker 容器是由镜像创建的实例。升级容器通常意味着停止旧容器,并用新镜像创建一个新容器。默认情况下,容器内部产生的所有数据都存储在容器的可写层中,这些数据是临时的,会随旧容器一起被删除。
- 未使用数据持久化:如果在创建或升级容器时,没有将容器内的重要目录(如数据库文件、网站目录、配置文件等)通过卷(Volume) 或绑定挂载(Bind Mount) 的方式持久化到宿主机上,那么旧容器删除后,数据自然就丢失了。
- 宝塔面板的操作方式:在宝塔面板中操作 Docker,有时可能忽略了背后对容器进行的是删除并重新创建的操作,而不是简单的重启。如果新容器没有继承旧容器的数据卷配置,数据就会丢失。
而我后续又在容器中新建并配置了存储卷,再次进行升级,还是丢失了数据,又查阅了资料,可能的原因是:
- 在宝塔面板或命令行中,所谓的“升级容器”通常不是原地升级。它的标准流程是:
- 拉取新的镜像 (
docker pull
) - 停止并删除旧的容器 (
docker stop
&&docker rm
) - 用新镜像创建一个全新的容器 (
docker run
)
- 拉取新的镜像 (
- 关键点在于:当你执行第3步
docker run
时,你必须明确地、再次地指定挂载参数(-v
),告诉新容器:“请使用旧容器之前用的那个卷”。如果你没指定,或者指定的卷名/路径不对,Docker 就会默认为这个新容器创建一个全新的、空空如也的卷。旧卷连同里面的数据依然存在,但新容器根本没用它,所以你看到的就是一个“空”的容器。
好吧,那么我该有什么标准化的流程去安全的升级我的容器呢?
我找到了Docker Compose。
Docker Compose的升级,是对编排工具版本的更新,需要手动下载新版本或通过包管理器操作。Docker Compose通过声明式配置能确保数据卷的稳定性,而宝塔的升级更关注Docker服务而非具体容器的数据管理。
特性维度 | Docker Compose | 宝塔面板升级 |
---|---|---|
升级对象 | 主要升级应用容器(通过修改image 标签或docker-compose pull )和Docker Compose工具本身 | 主要升级Docker引擎底层软件本身,对容器内应用数据的持久化关注较少 |
操作方式 | 命令行为主,需在项目目录执行docker-compose pull 和docker-compose up -d 等命令 | 图形界面(GUI)为主,在软件商店点击升级按钮或通过命令行更新系统软件包 |
配置与数据管理 | 声明式配置(docker-compose.yml 文件),数据卷挂载配置清晰,升级通常不影响现有数据卷,数据持久性更可靠 | 依赖界面操作,配置易被忽略(如重建容器时未正确挂载卷),易导致数据丢失 |
复杂度与学习曲线 | 需学习YAML语法和CLI命令,初期门槛稍高,但自动化程度高 | 图形化操作,简单直观,易于上手 |
适用场景 | 复杂应用编排、多容器项目、追求部署一致性和可重复性的生产环境 | 简单容器管理、快速入门和简单部署、偏好图形化操作的场景 |
因此,使用Docker Compose可以更安全保存我容器内的数据,并且我的所有基础设施配置(容器、网络、卷)都固化在了 docker-compose.yml
这个文本文件中,是可版本化、可重复的。
升级和配置的方式也很简单。我之前没有使用过Docker Compose,首先在服务器中创建docker-compose.yml文件,这里我以我升级Uptime Kuma的配置为例,你需要在yml文件中撰写以下内容:
services:
uptime-kuma:
image: louislam/uptime-kuma:2.0.0-beta.4 # 使用你当前的特定版本
container_name: uptime-kuma # 可以自定义容器名
restart: always # 停止后马上重启
ports:
- "33001:3001" # 主机端口:容器端口
volumes:
- /www/dk_project/:/app/data # 数据目录挂载(保持读写权限)
networks:
baota_net:
ipv4_address: 172.19.0.3 # 固定IP地址
networks:
baota_net:
external: true # 使用已存在的网络
name: baota_net # 指定网络名称
保存配置后,我们需要运行Docker Compose。在命令行中输入docker-compose pull拉取配置文件中指定的镜像。
等待拉取完成后输入docker-compose up -d命令来重新启动容器
现在,我们访问ip+指定端口即可进入软件,发现容器升级完成并且数据没有丢失。如果需要删除旧的镜像,在宝塔Docker面板中,点击“本地镜像”,找到旧版本的容器删除即可。
从一无所知的Docker白纸,到现在略知一二的Docker初学者,我发现Docker与WordPress、Linux一样,也是越往下研究越有趣。尽管还有很多知识是以囫囵吞枣的形式让我知晓并运用的。对于Docker Compose的运用也只是一些皮毛,在上方的截图中还有报错,我也是写到这里才知道那个报错是什么含义。
宝塔面板给我提供了不少便利,也让我可以方便的部署、上手很多内容,很多原来需要繁琐修改配置的内容现在可以低代码甚至于按一下按钮就可以解决。但一键化脚本总不能百分百的覆盖自己的需求,在精进的过程中仍然需要接触、需要学习命令行和代码的用法。这或许才是学习计算机知识的乐趣吧。(笑)