Docker – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Mon, 08 Jun 2026 12:02:44 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 从零到一:在 Trae CN + Docker 中搭建 Go + Gin 开发环境 https://www.shuijingwanwq.com/2026/06/08/16544/ https://www.shuijingwanwq.com/2026/06/08/16544/#respond Mon, 08 Jun 2026 12:02:40 +0000 https://www.shuijingwanwq.com/?p=16544 浏览量: 20

写在前面

最近我在 Ubuntu 26.04 上尝试使用 Trae CN 编辑器,配合 Docker 容器来开发一个 Go + Gin 的项目(go-gin-learning)。整个过程踩了一些坑,但也跑通了一套还算顺手的工作流。这篇文章就是一份完整的记录,希望能帮到遇到类似问题的朋友。

如果你已经看过我之前的博客(比如《在 Ubuntu 26.04 中基于 Docker Compose + Go 1.26.4 完成基础环境的搭建》),那这篇可以算是“下一篇”——从代码提交到容器运行,全部串起来。


一、宿主机上的准备工作

1.1 安装 Git 并配置用户信息

首先确保宿主机有 Git,然后设置全局用户名和邮箱(这些信息会写在每次 commit 里):

git config --global user.name "shuijingwan"
git config --global user.email "shuijingwanwq@163.com"

验证一下:

git config --global user.name
git config --global user.email

1.2 配置 GitHub 认证(使用 Token)

从 2021 年起 GitHub 不再支持密码认证,需要生成 Personal Access Token。

  • 登录 GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
  • 点击 Generate new token (classic)
  • 勾选 repo 权限,生成后复制 token(只显示一次)
  • 在宿主机终端执行:
git push origin main

当提示输入用户名时输入你的 GitHub 用户名,密码处粘贴刚才复制的 token。成功后 Git 会记住认证信息(如果配置了 credential helper)。

1.3 安装 Go(宿主机)

为了让 Trae CN 中的代码补全、语法跳转正常工作,需要在宿主机安装 Go。我选择了使用 APT 安装,简单省事:

sudo apt update
sudo apt install golang-go -y
go version

输出:go version go1.26.0 linux/amd64

其实系统“软件”中心里也有 Go 的 Snap 版本(见截图),但 APT 更轻量,且与容器内的 Go 版本兼容。

软件中心中 Go 的可用版本
软件中心中 Go 的可用版本

1.4 在 Trae CN 中安装 Go 扩展

打开 Trae CN 的扩展商店,搜索 Go,找到官方扩展(发布者为 golang)并安装。

扩展商店中的 Go 扩展
扩展商店中的 Go 扩展

安装完成后,按 Ctrl+Shift+P,输入 Go: Install/Update Tools,在弹出的列表中勾选 goplsdlvstaticcheck 等常用工具,点击确定。

选择要安装的 Go 工具
选择要安装的 Go 工具

等待安装完成,然后重新加载窗口。

至此,宿主机上的代码编辑环境已经就绪。

在 main.go 中输入 fmt. 应该能看到智能提示。
main.go 中输入 fmt. 应该能看到智能提示。

二、容器中的开发环境

2.1 让容器复用宿主机的 Git 配置

我们希望在容器内执行 git commit 时也能使用宿主机的用户名和邮箱。修改 docker-compose.yml,挂载 ~/.gitconfig

volumes:
  - ./:/code
  - ~/.gitconfig:/root/.gitconfig:ro

重启容器后,进入容器验证:

docker exec -it go-gin-learning sh
git config --global user.name   # 应显示 shuijingwan
git config --global user.email  # 应显示 shuijingwanwq@163.com

2.2 解决 Go 模块下载慢的问题

一开始容器内执行 go mod tidy 总是失败或超时,因为默认代理 goproxy.io 不稳定,而且每次容器重建都会清空缓存。

解决方案有两个:

  • 设置更稳定的代理:go env -w GOPROXY=https://goproxy.cn,direct
  • 持久化模块缓存:将宿主机的目录挂载到容器的 /go/pkg/mod

我采用了后者,在 docker-compose.yml 中添加:

volumes:
  - ~/go/pkg-mod-go-gin-learning:/go/pkg/mod

这样容器内的依赖包会存放在宿主机的一个专用目录中,即使容器删除也不会丢失。再次执行 go mod tidy 时,所有 go: downloading 都成功了。

2.3 运行 Gin 服务

在容器内执行:

go run main.go

看到如下输出说明服务启动成功:

[GIN-debug] Listening and serving HTTP on 0.0.0.0:8080

用浏览器访问 http://localhost:8080/albums,返回 JSON 数据,状态码 200。

浏览器中的请求响应正常
浏览器中的请求响应正常

这时在 Trae CN 的 Docker 扩展面板中,可以右键容器选择 Attach Shell,方便地打开容器终端。

Docker 扩展面板的容器操作菜单
Docker 扩展面板的容器操作菜单

三、总结与标准化展望

当前工作流小结

  1. 宿主机:负责 Git 操作、代码编辑、Go 语言服务器(gopls)。
  2. 容器:负责运行 go rungo test,依赖模块通过挂载的缓存目录持久化。
  3. Trae CN:通过 Go 扩展提供智能补全,通过 Docker 扩展附加到容器终端,做到“编辑在宿主机,运行在容器”。

虽然 Dev Containers 在 Trae CN 上暂时不可用,但通过“宿主机 Go + 容器运行 + 缓存持久化”的组合,我们依然获得了一个高效、可靠的开发环境。
(顺便说一句,.devcontainer/devcontainer.json 我并没有删除,因为团队里其他使用 VS Code 的成员可能还需要它。)

未来可以标准化的点

  • 使用 Makefile 封装常用命令:比如 make runmake testmake tidy,减少手动输入。
  • 集成 Air 热加载:在容器内安装 air,保存文件后自动重启服务,提升开发效率。
  • 将环境配置写成脚本:把 docker-compose.yml 的 volumes 设置、代理配置、依赖安装等写成 setup.sh,方便新成员快速加入。
  • 考虑使用 Remote – SSH:如果未来团队都在同一台服务器上开发,可以改用 SSH 远程开发,彻底统一环境。
]]>
https://www.shuijingwanwq.com/2026/06/08/16544/feed/ 0
在 Trae CN 中尝试 Dev Containers:一次不太成功的踩坑记录 https://www.shuijingwanwq.com/2026/06/08/16533/ https://www.shuijingwanwq.com/2026/06/08/16533/#respond Mon, 08 Jun 2026 10:23:47 +0000 https://www.shuijingwanwq.com/?p=16533 浏览量: 36

写在前面

这篇博客就是想简单记录一下:我在 Trae CN 里折腾微软官方 Dev Containers 扩展的过程。先说结论:折腾了一圈,发现 Trae CN 目前(2026 年 6 月)还不支持 Dev Containers。所以这篇文章不会给出什么“完美方案”,最后只会留个引子——下一步我打算试试另一条路:宿主机 Go + 容器内运行 + Docker 扩展辅助,如果跑通了,再单独写一篇分享。

项目背景:我现在在 Ubuntu 26.04 上用 Trae CN 写 go-gin-learninghttps://github.com/shuijingwan/go-gin-learning),一个 Go + Gin 的小项目。

之前已经完成的两篇博客(都是已经发过的):

  1. 《在 Ubuntu 26.04 中基于 Docker Compose + Go 1.26.4 完成基础环境的搭建》
    https://www.shuijingwanwq.com/2026/06/03/15587/
    这篇主要把 Docker 环境、容器启动、MySQL/Redis 网络啥的都弄好了。
  2. 《Go + Gin 实战 RESTful API:从环境搭建(WSL/Docker/VS Code)到 Git 提交与 GitHub 托管》
    https://www.shuijingwanwq.com/2026/04/03/9416/
    这篇是在 Windows WSL + Docker + VS Code 上已经成功跑通的一套完整流程。现在我想在 Ubuntu + Docker + Trae CN 上把同样的事情再实现一遍。

所以这篇其实是一个中间的小插曲:我想试试在 Trae CN 里能不能也用 Dev Containers 把整个编辑器“搬进”容器里,结果发现…暂时不行。


一、为啥想试 Dev Containers?

用过 VS Code 的同学应该知道,Dev Containers 这个功能真的很香:你可以把整个开发环境(包括 Go 版本、工具链、扩展、终端)全部塞进一个 Docker 容器里。团队协作或者换机器的时候,打开项目点一下“Reopen in Container”就能直接开始干活,不用再装一堆东西。

之前在 Windows + WSL + VS Code 上我已经用得很顺手了(就是第二篇博客里写的那样)。所以换到 Ubuntu + Trae CN 之后,自然也想复刻一下这个体验。于是就有了下面的折腾过程。


二、踩坑过程实录

2.1 先配一下扩展市场地址

Trae CN 默认的扩展市场地址是空的,得自己填。我在设置里把 application.extensionMarketUrl 改成了 https://marketplace.visualstudio.com/

[截图 3:修改 application.extensionMarketUrl 设置]

[截图 3:修改 application.extensionMarketUrl 设置]

2.2 安装官方 Dev Containers 扩展

地址配好之后,就能在扩展商店搜到微软官方的 ms-vscode-remote.remote-containers 了。点击安装。

[截图 4:官方 Dev Containers 扩展的详情页]

[截图 4:官方 Dev Containers 扩展的详情页]

装完一看,状态栏写着 “用户已全局禁用此扩展”。嗯?我啥也没干啊……

[截图 5:扩展显示“用户已全局禁用此扩展”及右键菜单]

[截图 5:扩展显示“用户已全局禁用此扩展”及右键菜单]

2.3 尝试各种“启用”姿势

  • 点扩展详情页里的 “启用(工作区)” → 没反应。
  • 用命令面板 Extensions: Enable Extension 选 Dev Containers → 还是没反应。
  • 甚至在工作区设置里强行加上 "extensions.enabled" 配置 → 依然无效。
[截图 7:工作区设置中添加强制启用配置]

[截图 7:工作区设置中添加强制启用配置]

2.4 换个市场源试试?

我把市场地址换成 https://open-vsx.org/,重启 Trae CN 再搜 Dev Containers —— 结果发现 open-vsx 里根本搜不到微软官方的这个扩展,只出来一个叫 “Artizo Dev Containers for Trae” 的社区版。

[截图 8:社区版 Artizo Dev Containers for Trae 扩展(仅展示,我没敢装)]

[截图 8:社区版 Artizo Dev Containers for Trae 扩展(仅展示,我没敢装)]

说实话,对社区版我有点顾虑,没敢随便装。

2.5 最后试试离线安装 VSIX

我想,既然在线不行,那就手动下载 VSIX 文件吧。从 VS Code 市场扒下来一个 ms-vscode-remote.remote-containers-0.459.1.vsix,然后在 Trae CN 里用 “从 VSIX 安装” 导进去。

[截图 9:从本地 VSIX 文件安装扩展的文件选择对话框]

[截图 9:从本地 VSIX 文件安装扩展的文件选择对话框]

安装过程看着很正常,但装完之后……还是 “用户已全局禁用”。这就说明问题不在下载或安装环节,而是扩展本身跟 Trae CN 的激活机制不兼容。

2.6 顺手装了 Docker 扩展

虽然 Dev Containers 没戏,但我顺手把 ms-azuretools.vscode-docker(Container Tools)装上了,这个后面还能用。

[截图 1:Trae CN 扩展商店中 Docker 扩展的安装界面]

[截图 1:Trae CN 扩展商店中 Docker 扩展的安装界面]

另外 Docker 侧边栏里容器也在正常运行。

2.7 去官方论坛看了一眼

最后去 Trae 官方论坛搜了一下,果然有人问过:【反馈】Dev Containers 扩展无法使用。官方回复很明确:目前尚不支持 Dev Containers

好吧,死心了。


三、结论就是:目前真的不支持

总结一下这次尝试的结果:

  • 官方扩展装上了,但始终显示“用户已全局禁用”,没法激活。
  • open-vsx 市场根本搜不到官方版,只有一个社区版(我没装)。
  • 手动 VSIX 安装也救不了,一样禁用。
  • 官方论坛确认了:不支持。

所以,如果你也想在 Trae CN 里复现 VS Code 那种“一键进入容器”的开发体验,暂时别折腾了


四、那接下来打算怎么办?

虽然 Dev Containers 走不通,但开发还是得继续啊。我准备换一个思路,试试 “宿主机 Go + 容器内运行 + Docker 扩展辅助” 这种混合模式。大致的想法是:

  • 宿主机装个 Go SDK,让 Trae CN 的代码补全、跳转这些能正常工作。
  • 容器继续负责运行和测试,通过 Docker 扩展的“Attach Shell”在 IDE 里直接操作容器内的终端。
  • Git 操作用 Trae CN 自带的源代码管理面板(实际调的是宿主机的 Git),代码通过 volumes 挂载自动同步。

这个方案还没有正式跑起来,只是我下一步的计划。如果能顺利跑通,我再单独写一篇博客分享具体的配置和用法。

]]>
https://www.shuijingwanwq.com/2026/06/08/16533/feed/ 0
Ubuntu 26.04 + Docker 搭建 Go Gin 开发环境(全记录) https://www.shuijingwanwq.com/2026/06/03/15587/ https://www.shuijingwanwq.com/2026/06/03/15587/#respond Wed, 03 Jun 2026 11:44:06 +0000 https://www.shuijingwanwq.com/?p=15587 浏览量: 37

从 Windows WSL2 无缝迁移到 Ubuntu 裸机,基于现有 MySQL/Redis 容器构建 Go 开发环境,并接入自定义网络。

📌 前言

之前一直在 Windows 10 + WSL2 中学习 go-gin-learning 项目,现在换到了全新的 Ubuntu 26.04 系统。希望继续使用 Docker 来隔离开发环境,同时复用已经部署好的 MySQL 8.0 和 Redis 7.2 容器(位于自定义网络 services_dev-network 中)。

本文记录了从零开始配置的全部步骤,包含:

  • 系统工具检查与安装
  • Docker 环境验证
  • 项目代码克隆
  • 编写 Dockerfile 预装 git
  • 编写 docker-compose.yml 接入现有网络
  • 容器内运行 Gin 应用并测试连通性
  • 常见问题与避坑建议

🧰 一、准备工作:检查系统已有工具

在 Ubuntu 中养成“先检查,后安装”的习惯,可以避免重复操作。

1.1 检查 Git

git --version

输出示例(已安装):

git version 2.53.0

若未安装,执行:

sudo apt install git -y

1.2 检查 Docker

docker --version
docker compose version

输出示例

Docker version 29.5.2, build 79eb04c
Docker Compose version v5.1.4

若未安装,请参考 Docker 官方文档 安装。

建议:将当前用户加入 docker 组,避免每次输入 sudo

sudo usermod -aG docker $USER

然后注销并重新登录


🌐 二、确认已有数据库网络环境

之前已经在 ~/docker/services 中通过 docker-compose.yml 运行了 MySQL 8.0 和 Redis 7.2,并创建了自定义网络 services_dev-network

2.1 查看网络

docker network ls | grep dev-network

输出

71f462c6ef91   services_dev-network   bridge    local

2.2 查看数据库容器状态

docker ps --filter "name=mysql80" --filter "name=redis72"

输出

CONTAINER ID   IMAGE       ...   NAMES
9ec38ca384b6   redis:7.2   ...   redis72
4e93fd2e2c3f   mysql:8.0   ...   mysql80

💡 关键信息

  • MySQL 容器名:mysql80,内部端口 3306,宿主机映射端口 3307
  • Redis 容器名:redis72,内部端口 6379
  • 网络名:services_dev-network注意前缀,由 ~/docker/services 目录名派生)

📁 三、创建代码目录并克隆项目

选择一个语义清晰的目录存放项目代码,这里使用 ~/code(全小写,符合 Linux 惯例)。

mkdir -p ~/code
cd ~/code
git clone https://github.com/shuijingwan/go-gin-learning.git
cd go-gin-learning

检查项目结构:

ls -la

🐳 四、编写 Dockerfile(预装 git)

为了不在每次进入容器时手动安装 git,我们创建一个自定义镜像。

创建 Dockerfile

FROM golang:1.26-alpine

# 安装 git(go mod 下载某些依赖时需要)
RUN apk add --no-cache git

# 设置工作目录,与后面的 docker-compose 保持一致
WORKDIR /code

# 保持容器运行(开发模式)
CMD ["tail", "-f", "/dev/null"]

📌 说明

  • 使用 Alpine 版本镜像,体积小
  • apk add --no-cache 不保留缓存,减小镜像大小
  • WORKDIR /code 后续可以省略 docker-compose 中的 working_dir,但为了明确,两边都保留也没问题

⚙️ 五、编写 docker-compose.yml(接入现有网络)

关键点:

  • 使用 build: . 而不是 image: ...
  • 加入外部网络 services_dev-network
  • 传递数据库连接所需的环境变量
  • 删除已过时的 version 字段

最终 docker-compose.yml 内容:

services:
  go:
    build: .
    container_name: go-gin-learning
    working_dir: /code
    volumes:
      - ./:/code
    ports:
      - "8080:8080"
    tty: true
    stdin_open: true
    environment:
      - GOPROXY=https://goproxy.io,direct
      - GOSUMDB=sum.golang.google.cn
      - CGO_ENABLED=0
      # 数据库连接配置(使用现有网络中的服务名)
      - DB_HOST=mysql80
      - DB_PORT=3306
      - DB_USER=root
      - DB_PASSWORD=mystrongpwd80
      - DB_NAME=go_gin
      - REDIS_HOST=redis72
      - REDIS_PORT=6379
      - REDIS_PASSWORD=myredispass
    networks:
      - services_dev-network

networks:
  services_dev-network:
    external: true

⚠️ 注意

  • DB_PASSWORDREDIS_PASSWORD 要与 ~/docker/services/docker-compose.yml 中的密码完全一致
  • 容器间通信使用内部端口 3306 和 6379,而不是宿主机映射的 3307。

🚀 六、构建并启动开发容器

# 停止并删除旧容器(如果有)
docker compose down

# 构建镜像(--no-cache 确保重新安装 git)
docker compose build --no-cache

# 启动容器(后台运行)
docker compose up -d

查看运行状态:

docker ps --filter "name=go-gin-learning"

🧪 七、进入容器并验证连接

7.1 进入容器

docker exec -it go-gin-learning sh

此时提示符变为 /code #

7.2 验证 git 已安装

git --version

应输出类似 git version 2.52.0

7.3 测试网络连通性

# 安装测试工具(仅调试用,正式镜像可不加)
apk add iputils mysql-client redis

# ping 数据库容器
ping -c 2 mysql80
ping -c 2 redis72

7.4 测试 MySQL 连接(禁用 SSL)

MySQL 8.0 默认要求 SSL,但在容器内部使用 --ssl=0 即可绕过证书验证:

mariadb -h mysql80 -P 3306 -u root -pmystrongpwd80 -e "SHOW DATABASES;" --ssl=0

预期输出:如图1

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

💡 若使用 mysql 命令,请用 --ssl-mode=DISABLED

7.5 测试 Redis 连接

redis-cli -h redis72 -a myredispass PING

预期输出:如图2

预期输出:如图2
PONG

🏃 八、运行 Gin 应用

在容器内执行:

go run main.go

看到如下日志表示成功:如图3

看到如下日志表示成功:如图3
go: downloading github.com/go-playground/locales v0.14.1
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:	export GIN_MODE=release
 - using code:	gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /albums                   --> main.getAlbums (3 handlers)
[GIN-debug] GET    /albums/:id               --> main.getAlbumByID (3 handlers)
[GIN-debug] POST   /albums                   --> main.postAlbums (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on 0.0.0.0:8080
[GIN] 2026/06/03 - 11:19:14 | 404 |  1.219µs |      172.18.0.1 | GET      "/"
[GIN] 2026/06/03 - 11:19:14 | 404 |    778ns |      172.18.0.1 | GET      "/favicon.ico"
[GIN] 2026/06/03 - 11:19:45 | 200 | 147.412µs |      172.18.0.1 | GET      "/albums"


在宿主机测试 API

打开另一个终端,执行:

curl http://localhost:8080/albums

或直接在浏览器访问 http://localhost:8080/albums

📸 浏览器显示 JSON 数据,如图4


🧹 九、常用管理命令

操作命令
启动开发容器cd ~/code/go-gin-learning && docker compose up -d
停止容器docker compose down
重新构建镜像docker compose build --no-cache
查看日志docker compose logs -f
进入容器docker exec -it go-gin-learning sh
重启 MySQL/Redis(若需要)cd ~/docker/services && docker compose restart

⚠️ 十、避坑指南

10.1 容器内 git 缺失导致 go run 失败

现象

unable to resolve git version: exec: "git": executable file not found in $PATH

解决:使用自定义 Dockerfile 安装 git,见第四章。

10.2 MySQL 连接报 TLS/SSL 错误

现象

ERROR 2026 (HY000): TLS/SSL error: Certificate verification failure

解决:在连接命令中添加 --ssl=0(mariadb)或 --ssl-mode=DISABLED(mysql)。

10.3 容器无法访问 MySQL/Redis

原因:未加入正确的网络,或网络名称写错。

解决

  • 确认 docker network ls 中有 services_dev-network
  • 检查 docker-compose.yml 中 networks 名称是否完全一致(包括下划线)
  • 在容器内 ping mysql80 测试

10.4 宿主机无法访问 8080 端口

原因:Gin 监听的是 127.0.0.1:8080 而不是 0.0.0.0:8080,导致端口映射失效。

解决:在代码中设置 router.Run(":8080")router.Run("0.0.0.0:8080")


📝 十一、总结

通过本次实践,我实现了:

  1. ✅ 在 Ubuntu 26.04 上搭建完整的 Go 开发环境
  2. ✅ 利用已有的 MySQL/Redis 容器(独立部署)和自定义网络
  3. ✅ 构建带 git 的 Go 1.26 Alpine 开发镜像
  4. ✅ 编写 docker-compose.yml 挂载代码并接入外部网络
  5. ✅ 在容器内成功运行 Gin 应用并验证数据库连通性

这种“数据库与代码分离容器”的模式非常适合多项目共用基础设施,既节省资源,又保持环境一致性。

下一步,便可以:

  • main.go 中编写连接 MySQL/Redis 的业务逻辑
  • 使用任意代码编辑器(如 VS Code、Sublime 等)直接编辑项目文件,保存后容器内实时同步
  • docker-compose.yml 加入版本控制,与队友共享环境配置

🔗 参考资料

]]>
https://www.shuijingwanwq.com/2026/06/03/15587/feed/ 0
配置开发环境:使用 Docker 管理多版本 MySQL 与 Redis https://www.shuijingwanwq.com/2026/06/01/15331/ https://www.shuijingwanwq.com/2026/06/01/15331/#respond Mon, 01 Jun 2026 08:48:33 +0000 https://www.shuijingwanwq.com/?p=15331 浏览量: 27

本文是「从 Windows 到 Ubuntu:迁移与配置完全指南」系列的开发环境篇。
适合已经完成 Ubuntu 系统安装,希望搭建高效、隔离、多版本数据库环境的开发者。


为什么要用 Docker 管理数据库?

在 Windows 下我习惯用 WSL2 + Docker 跑独立的数据库容器,迁移到 Ubuntu 后自然延续这一方式。相比直接在宿主机安装:

  • 多版本共存:同一台机器同时运行 MySQL 5.7 和 8.0,Redis 任意版本,互不干扰。
  • 环境隔离:每个项目的数据库独立或按版本共享,配置不打架。
  • 轻量易清理:容器停止即释放资源,数据卷保留,删除无残留。
  • 版本锁死mysql:5.7 镜像永远对应 5.7 最新版,不会因系统升级自动变更。

本文以 MySQL 5.7、MySQL 8.0、Redis 7.2 为例,搭建三个独立容器,供后续 Go/PHP 项目共用。


一、安装 Docker 引擎(纯命令行,不用 Docker Desktop)

Ubuntu 的“软件”或“应用中心”无法搜到 Docker Desktop,这是 Linux 发行版软件分发的特点——专业工具通常需要手动添加官方软件源。官方源安装更轻量、稳定。

1. 卸载可能冲突的旧包(全新系统可跳过)

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
  sudo apt remove -y $pkg
done

如果你是全新安装的 Ubuntu 26.04,这些包本来就不存在,此步骤可跳过。

2. 添加 Docker 官方 GPG 密钥和软件源

sudo apt update
sudo apt install -y ca-certificates curl

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl --http1.1 -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update

踩坑记录:如果 curl 下载 GPG 时报 curl: (16) Error in the HTTP2 framing layer,加上参数 --http1.1 即可解决。

3. 安装 Docker 引擎及 Compose 插件

sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

4. 将当前用户加入 docker 组(免 sudo 执行)

sudo usermod -aG docker $USER

必须注销并重新登录(或重启),否则 docker 命令仍需要 sudo。

5. 验证安装

docker --version          # 输出如 Docker version 29.5.2
docker compose version    # 输出 Docker Compose version v2.x

二、网络与镜像拉取问题排查(真实踩坑实录)

在 VPN 环境下,拉取第一个测试镜像时就遇到了网络超时。以下是完整的排查和解决过程。

2.1 第一次尝试:直接运行 hello-world

docker run hello-world

输出:

Unable to find image 'hello-world:latest' locally
docker: Error response from daemon: failed to resolve reference "docker.io/library/hello-world:latest": failed to do request: Head "https://registry-1.docker.io/v2/library/hello-world/manifests/latest": dial tcp 128.242.240.85:443: i/o timeout

2.2 重启 Docker 服务,再次尝试

sudo systemctl restart docker
docker run hello-world

仍然超时,这次 IP 变成了 31.13.69.245

dial tcp 31.13.69.245:443: i/o timeout

2.3 检查宿主机能否访问 Docker Hub

curl -I https://registry-1.docker.io/v2/

输出:

HTTP/1.1 200 Connection established

HTTP/2 401 
date: Sun, 31 May 2026 10:04:04 GMT
content-type: application/json
content-length: 87
...

这说明宿主机网络正常(返回 401 是因为没有认证,但连接已建立),问题出在 Docker 守护进程自身。

2.4 配置国内镜像加速器(第一次尝试)

创建 /etc/docker/daemon.json,使用中科大、网易、百度镜像:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ]
}
EOF
sudo systemctl daemon-reload
docker run hello-world

结果依然超时(IP 变为 103.97.3.19):

dial tcp 103.97.3.19:443: i/o timeout

2.5 再次重启 Docker,问题依旧

sudo systemctl restart docker
docker run hello-world

这次错误变了:

dial tcp: lookup docker.mirrors.ustc.edu.cn on 127.0.0.53:53: no such host

说明镜像加速器的域名无法解析 —— VPN 影响了 DNS。

2.6 最终方案:使用 DaoCloud 镜像 + 指定公共 DNS

修改 /etc/docker/daemon.json,同时配置镜像和 DNS:

sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://docker.m.daocloud.io"],
  "dns": ["8.8.8.8", "1.1.1.1"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
docker run hello-world

这次终于成功拉取并运行:

latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete 
d5e71e642bf5: Download complete 
Digest: sha256:0e760fdfbc48ba8041e7c6db999bb40bfca508b4be580ac75d32c4e29d202ce1
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
...

结论:在 VPN 环境下,Docker 守护进程可能无法正确使用系统 DNS,需要显式指定公共 DNS(如 8.8.8.8)并配合一个可用的镜像加速器。DaoCloud 镜像 docker.m.daocloud.io 在此环境中可用。


三、部署 MySQL 5.7 / 8.0 和 Redis 7.2 容器

3.1 创建项目目录

mkdir -p ~/docker/services
cd ~/docker/services

3.2 编写 docker-compose.yml

cat > docker-compose.yml << 'EOF'
version: "3.8"      # 新版 Docker Compose 可省略该行,会有警告但无影响

networks:
  dev-network:
    driver: bridge

services:
  mysql57:
    image: mysql:5.7
    container_name: mysql57
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: mystrongpwd57
    ports:
      - "3306:3306"
    volumes:
      - ./data/mysql57:/var/lib/mysql
    networks:
      - dev-network

  mysql80:
    image: mysql:8.0
    container_name: mysql80
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: mystrongpwd80
    ports:
      - "3307:3306"
    volumes:
      - ./data/mysql80:/var/lib/mysql
    networks:
      - dev-network
    command: --default-authentication-plugin=mysql_native_password

  redis:
    image: redis:7.2
    container_name: redis72
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - ./data/redis72:/data
    command: redis-server --requirepass myredispass --appendonly yes
    networks:
      - dev-network
EOF

避坑提醒:MySQL 8.0 需要添加 --default-authentication-plugin=mysql_native_password,否则某些旧客户端连接会报 caching_sha2_password 错误。

3.3 第一次启动(遇到网络波动)

docker compose up -d

输出显示:

WARN[0000] the attribute `version` is obsolete...
[+] up 19/24
 ✘ Image mysql:8.0  Error failed to resolve reference ... EOF

错误原因是拉取 MySQL 8.0 时认证失败(EOF),可能是镜像加速器暂时性问题。

3.4 直接重试,成功

docker compose up -d

这次所有镜像都拉取成功:

[+] up 25/34
 ✔ Image mysql:5.7   Pulled
 ✔ Image redis:7.2   Pulled
 ✔ Image mysql:8.0   Pulled
 ✔ Network services_dev-network Created
 ✔ Container mysql57 Started
 ✔ Container redis72 Started
 ✔ Container mysql80 Started

经验:Docker Hub 或镜像加速器偶发性网络问题,重试一次往往就能解决。


四、验证容器运行及连接测试

4.1 查看容器状态

docker ps

输出:

CONTAINER ID   IMAGE       COMMAND                   STATUS          PORTS                                                    NAMES
9ec38ca384b6   redis:7.2   "docker-entrypoint.s…"   45 seconds ago   Up 42 seconds   0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp              redis72
4e93fd2e2c3f   mysql:8.0   "docker-entrypoint.s…"   45 seconds ago   Up 42 seconds   33060/tcp, 0.0.0.0:3307->3306/tcp, [::]:3307->3306/tcp   mysql80
29598dd51087   mysql:5.7   "docker-entrypoint.s…"   45 seconds ago   Up 42 seconds   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp   mysql57

4.2 连接 MySQL 5.7

docker exec -it mysql57 mysql -uroot -pmystrongpwd57

进入 MySQL 命令行,执行 exit 退出。

4.3 连接 MySQL 8.0

docker exec -it mysql80 mysql -uroot -pmystrongpwd80

同样成功进入。

4.4 连接 Redis

docker exec -it redis72 redis-cli -a myredispass

输出提示 Warning: Using a password with '-a' ... may not be safe(仅安全警告,不影响使用),然后进入 127.0.0.1:6379> 提示符。

至此,三个数据库容器均已正常运行。

至此,三个数据库容器均已正常运行。

五、供项目容器连接(网络互通)

数据库容器位于自定义网络 services_dev-network(由 docker-compose 自动创建)。项目容器只需加入同一外部网络,即可通过 容器名 访问。

示例 docker-compose.yml 片段:

networks:
  default:
    external:
      name: services_dev-network

services:
  go-app:
    image: golang:1.26-alpine
    networks:
      - default
    environment:
      DB_HOST: mysql57         # 或 mysql80
      REDIS_HOST: redis72

代码中连接 mysql57:3306redis72:6379 即可。


六、版本选择说明与注意事项

服务版本主流程度生命周期提醒
MySQL 5.75.7.44占约 18.8%,属于遗留系统常用版本已于 2023 年 10 月 EOL,不再有官方安全更新,非必要不建议新项目使用
MySQL 8.08.0.46当前最主流(占比 58%)官方支持将于 2026 年 4 月 30 日 结束,后续需升级到 8.4 LTS
Redis 7.27.2.x稳定且成熟开源分支 Valkey 的基础版本,可放心使用

若为新项目,推荐直接使用 MySQL 8.4 LTS(支持至 2031 年)和 Redis 7.2


七、日常管理命令速查

操作命令
启动所有服务cd ~/docker/services && docker compose up -d
停止所有服务cd ~/docker/services && docker compose down
单独重启 MySQL 8.0docker restart mysql80
查看 MySQL 5.7 日志docker logs -f mysql57
进入 Redis 命令行docker exec -it redis72 redis-cli -a 密码
清理未使用的镜像/容器docker system prune -a
备份数据卷tar -czf mysql57-backup.tar.gz ~/docker/services/data/mysql57

八、总结

至此,我们完成了一套干净、可复用的数据库容器环境:

  • MySQL 5.7 → 端口 3306
  • MySQL 8.0 → 端口 3307
  • Redis 7.2 → 端口 6379

所有数据持久化在 ~/docker/services/data/,容器随系统启动自动运行。后续任何 Go、PHP、Node.js 项目,只需通过 Docker 网络连接这些容器名,即可快速获得多版本数据库支持。


本文命令均在 Ubuntu 26.04 下验证通过,Docker 版本 29.5.2。
如有疑问或交流,欢迎在评论区留言。

]]>
https://www.shuijingwanwq.com/2026/06/01/15331/feed/ 0
使用 Docker + VS Code Dev Container 搭建 Python 音乐闹钟开发环境(WSL 实战记录) https://www.shuijingwanwq.com/2026/04/22/9567/ https://www.shuijingwanwq.com/2026/04/22/9567/#respond Wed, 22 Apr 2026 07:30:53 +0000 https://www.shuijingwanwq.com/?p=9567 浏览量: 167

一、背景:为什么要做这个环境

为了学习 AI 编程工具(如通义灵码),我准备实现一个“音乐闹钟”小项目。
在开始编码之前,我先搭建一套可复用的 Python Dev Container 开发环境。

二、技术栈说明

  • Windows 10
  • WSL2 (Ubuntu)
  • Docker
  • VS Code
  • Python 3.10 (Alpine)
  • Dev Container

三、项目目录结构(核心重点)

music-alarm/
├── .devcontainer/
│ └── devcontainer.json
├── docker-compose.yml
├── main.py
├── requirements.txt
├── .gitignore
└── README.md

✔ 解释每个文件作用
📁 .devcontainer/devcontainer.json
VS Code Dev Container 配置文件
用于定义:

  • 使用哪个 Docker 服务
  • 工作目录
  • 插件
  • 自动安装依赖
    📁 docker-compose.yml
    定义 Python 运行环境容器
  • Python 镜像
  • 代码挂载
  • 工作目录 /app
  • 保持容器运行
    📁 main.py
    音乐闹钟核心逻辑入口
    后续会在这里实现:
  • 定时任务
  • 播放音乐
    📁 requirements.txt(预留)
    未来 AI / 音乐闹钟依赖管理文件
    例如:
    schedule
    playsound
    📁 .gitignore
    用于忽略:
  • Python 缓存
  • IDE 文件
  • 环境变量

四、Dev Container 配置说明(重点).devcontainer/devcontainer.json

{
  "name": "Python Music Alarm Dev Container",

  "dockerComposeFile": ["../docker-compose.yml"],
  "service": "python",
  "workspaceFolder": "/app",

  "shutdownAction": "stopCompose",

  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance",
        "ms-azuretools.vscode-docker",
        "eamodio.gitlens"
      ],
      "settings": {
        "terminal.integrated.defaultProfile.linux": "sh",
        "python.defaultInterpreterPath": "/usr/local/bin/python"
      }
    }
  },

  "remoteUser": "root",

  "postCreateCommand": "apk update &amp;&amp; apk add git &amp;&amp; pip install --upgrade pip"
}

五、docker-compose.yml 说明(重点)

该文件用于启动 Python 开发容器,并挂载本地代码:
volumes:

  • ./:/app

👉 核心意义:

保证代码在宿主机(WSL)保存,不会随容器销毁而丢失

services:
  python:
    image: python:3.10-alpine
    container_name: python-music-alarm

    working_dir: /app

    volumes:
      - ./:/app

    tty: true
    stdin_open: true

    command: tail -f /dev/null

    # &#x2714; 关键:保证 Git / VS Code 兼容
    environment:
      - PYTHONDONTWRITEBYTECODE=1
      - PYTHONUNBUFFERED=1

六、VS Code 使用方式(操作步骤)

Step 1:打开项目
code .
Step 2:进入 Dev Container
Ctrl + Shift + P
→ Dev Containers: Reopen in Container
Step 3:确认环境
python –version
git –version
Step 4:打开 Git UI
Ctrl + Shift + G
Step 5:文件 – 将工作区另存为 C:\Users\Thinkpad\VSCodeWorkspaces\python-music-alarm-app.code-workspace,便于后期直接从文件打开工作区

七、验证环境是否成功,在 GitHub 上的目录结构如图1

验证环境是否成功,在 GitHub 上的目录结构


✔ Python 可运行
✔ Git 可用
✔ VS Code 进入 Dev Container
✔ 代码可持久化(不会丢)

八、本篇总结
通过 Docker + Dev Container,我完成了一套标准化 Python 开发环境。
这为后续使用通义灵码实现“音乐闹钟”项目打下了基础。

]]>
https://www.shuijingwanwq.com/2026/04/22/9567/feed/ 0
WSL-Ubuntu 下 Docker 搭建 Hyperf:从启动失败到最佳开发结构 https://www.shuijingwanwq.com/2026/04/08/9440/ https://www.shuijingwanwq.com/2026/04/08/9440/#respond Wed, 08 Apr 2026 08:41:34 +0000 https://www.shuijingwanwq.com/?p=9440 浏览量: 204

1、参考:在 WSL-Ubuntu 中 Docker 下安装 Hyperf。现在启动失败:[ERROR] RedisException: Connection refused。如图1

参考:在 WSL-Ubuntu 中 Docker 下安装 Hyperf。现在启动失败:[ERROR] RedisException: Connection refused。


[ERROR] RedisException: Connection refused in /data/project/hyperf-skeleton/vendor/hyperf/redis/src/RedisConnection.php:318
Stack trace:
<h1>0 /data/project/hyperf-skeleton/vendor/hyperf/redis/src/RedisConnection.php(318): Redis-&gt;connect()</h1>
<h1>1 /data/project/hyperf-skeleton/vendor/hyperf/redis/src/RedisConnection.php(129): Hyperf\Redis\RedisConnection-&gt;createRedis()</h1>
<h1>2 /data/project/hyperf-skeleton/vendor/hyperf/redis/src/RedisConnection.php(83): Hyperf\Redis\RedisConnection-&gt;reconnect()</h1>
<h1>3 /data/project/hyperf-skeleton/vendor/hyperf/redis/src/Pool/RedisPool.php(58): Hyperf\Redis\RedisConnection-&gt;__construct()</h1>
<h1>4 /data/project/hyperf-skeleton/vendor/hyperf/pool/src/Pool.php(160): Hyperf\Redis\Pool\RedisPool-&gt;createConnection()</h1>
<h1>5 /data/project/hyperf-skeleton/vendor/hyperf/pool/src/Pool.php(45): Hyperf\Pool\Pool-&gt;getConnection()</h1>
<h1>6 /data/project/hyperf-skeleton/vendor/hyperf/redis/src/Redis.php(126): Hyperf\Pool\Pool-&gt;get()</h1>
<h1>7 /data/project/hyperf-skeleton/vendor/hyperf/redis/src/Redis.php(40): Hyperf\Redis\Redis-&gt;getConnection()</h1>
<h1>8 /data/project/hyperf-skeleton/vendor/hyperf/async-queue/src/Driver/RedisDriver.php(188): Hyperf\Redis\Redis-&gt;__call()</h1>
<h1>9 /data/project/hyperf-skeleton/vendor/hyperf/async-queue/src/Driver/RedisDriver.php(80): Hyperf\AsyncQueue\Driver\RedisDriver-&gt;move()</h1>
<h1>10 /data/project/hyperf-skeleton/vendor/hyperf/async-queue/src/Driver/Driver.php(68): Hyperf\AsyncQueue\Driver\RedisDriver-&gt;pop()</h1>
<h1>11 /data/project/hyperf-skeleton/vendor/hyperf/async-queue/src/Process/ConsumerProcess.php(51): Hyperf\AsyncQueue\Driver\Driver-&gt;consume()</h1>
<h1>12 /data/project/hyperf-skeleton/vendor/hyperf/process/src/AbstractProcess.php(101): Hyperf\AsyncQueue\Process\ConsumerProcess-&gt;handle()</h1>
<h1>13 [internal function]: Hyperf\Process\AbstractProcess-&gt;Hyperf\Process{closure}()</h1>
<h1>14 {main}</h1>


2、HyPerf 连接 Redis 失败,大概率是以下三者之一导致(Redis 没启动 / 地址写错 / 端口不通)。我现在是本地开发环境,最终决定架构如下:

WSL(开发环境)

├── dev-mysql(共用)
├── dev-redis(共用)

├── hyperf 项目
├── laravel 项目
├── 其他 PHP 项目

3、创建一个公共网络



ubuntu@DESKTOP-H4MGQIU:~$ docker network create dev-net
4b1b11f4edbeb6ea2dc17600e5366ddffa4e1fd1eec9d0c6da546764d9fe919c


4、启动 Redis



ubuntu@DESKTOP-H4MGQIU:~$ docker network create dev-net
4b1b11f4edbeb6ea2dc17600e5366ddffa4e1fd1eec9d0c6da546764d9fe919c
ubuntu@DESKTOP-H4MGQIU:~$ docker run -d \
--name dev-redis \
--network dev-net \
-p 6379:6379 \
redis:alpine
Unable to find image 'redis:alpine' locally
alpine: Pulling from library/redis
911c6948605d: Pull complete
80ad90552b45: Pull complete
4f4fb700ef54: Pull complete
794ebd49c5d4: Pull complete
e14f845a52ff: Pull complete
8b960ad4ebe4: Pull complete
589002ba0eae: Pull complete
1eff8ef023e3: Download complete
3130250ed578: Download complete
Digest: sha256:2afba59292f25f5d1af200496db41bea2c6c816b059f57ae74703a50a03a27d0
Status: Downloaded newer image for redis:alpine
01c8cedc5e855b78766d3232fe7df6b55ca822256c94ece0cd510e1bcab246ef


5、启动 MySQL 8



ubuntu@DESKTOP-H4MGQIU:~$ docker run -d \
--name dev-mysql8 \
--network dev-net \
-e MYSQL_ROOT_PASSWORD=root \
-p 3306:3306 \
mysql:8
Unable to find image 'mysql:8' locally
8: Pulling from library/mysql
91c980086743: Pull complete
eba8eed90d75: Pull complete
d4c7048d1cf1: Pull complete
50200b0c89a3: Pull complete
3cd28adefbd9: Pull complete
03f8ae82fc56: Pull complete
43105b2d4e4a: Pull complete
4d14d7bf02a4: Pull complete
1a7d4892b7d2: Pull complete
68420c358694: Pull complete
09ed159fbec4: Download complete
0ad5e3bd9c41: Download complete
Digest: sha256:da906917ca4ace3ba55538b7c2ee97a9bc865ef14a4b6920b021f0249d603f3d
Status: Downloaded newer image for mysql:8
232e8abe63d581fcbf5effab51e84eb4bb046255c8851635e58cfe1d8a85c7e6


6、让 Hyperf 加入这个网络,验证是否成功,验证是否成功。符合预期。如图2

让 Hyperf 加入这个网络,验证是否成功,验证是否成功


ubuntu@DESKTOP-H4MGQIU:~$ docker network connect dev-net hyperf
ubuntu@DESKTOP-H4MGQIU:~$ docker inspect hyperf
[
{
"Id": "9232c1fa90d72165f31c1e1adc4fdc897a665a1e9e580242af4a342765f7154a",
"Created": "2026-03-19T11:07:00.928914099Z",
"Path": "/bin/sh",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 2188,
"ExitCode": 0,
"Error": "",
"StartedAt": "2026-03-23T09:23:00.14362394Z",
"FinishedAt": "2026-03-23T09:16:50.3053747Z"
},
"Image": "sha256:3cbda08f3892507d760d31bba8b68aeb4b916333055bbf05cf46ea18c67fc935",
"ResolvConfPath": "/var/lib/docker/containers/9232c1fa90d72165f31c1e1adc4fdc897a665a1e9e580242af4a342765f7154a/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/9232c1fa90d72165f31c1e1adc4fdc897a665a1e9e580242af4a342765f7154a/hostname",
"HostsPath": "/var/lib/docker/containers/9232c1fa90d72165f31c1e1adc4fdc897a665a1e9e580242af4a342765f7154a/hosts",
"LogPath": "/var/lib/docker/containers/9232c1fa90d72165f31c1e1adc4fdc897a665a1e9e580242af4a342765f7154a/9232c1fa90d72165f31c1e1adc4fdc897a665a1e9e580242af4a342765f7154a-json.log",
"Name": "/hyperf",
"RestartCount": 0,
"Driver": "overlayfs",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/home/ubuntu/wwwroot/hyperf-skeleton:/data/project"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "bridge",
"PortBindings": {
"9501/tcp": [
{
"HostIp": "",
"HostPort": "9501"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
49,
188
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "private",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": true,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": [
"label=disable"
],
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": [],
"BlkioDeviceWriteBps": [],
"BlkioDeviceReadIOps": [],
"BlkioDeviceWriteIOps": [],
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": null,
"PidsLimit": null,
"Ulimits": [],
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": null,
"ReadonlyPaths": null
},
"Storage": {
"RootFS": {
"Snapshot": {
"Name": "overlayfs"
}
}
},
"Mounts": [
{
"Type": "bind",
"Source": "/home/ubuntu/wwwroot/hyperf-skeleton",
"Destination": "/data/project",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
"Config": {
"Hostname": "9232c1fa90d7",
"Domainname": "",
"User": "root",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"9501/tcp": {}
},
"Tty": true,
"OpenStdin": true,
"StdinOnce": true,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"SW_VERSION=v6.1.7",
"COMPOSER_VERSION=2.9.4",
"COMPOSER_ALLOW_SUPERUSER=1",
"PHPIZE_DEPS=autoconf dpkg-dev dpkg file g++ gcc libc-dev make php81-dev php81-pear pkgconf re2c pcre-dev pcre2-dev zlib-dev libtool automake libaio-dev openssl-dev curl-dev"
],
"Cmd": null,
"Image": "hyperf/hyperf:8.1-alpine-v3.18-swoole",
"Volumes": null,
"WorkingDir": "/data/project",
"Entrypoint": [
"/bin/sh"
],
"Labels": {
"license": "MIT",
"maintainer": "Hyperf Developers <a href="&#109;&#x61;&#x69;&#x6c;&#x74;&#111;&#x3a;&#103;&#x72;&#111;&#x75;&#112;&#x40;&#104;&#121;&#112;&#101;r&#x66;&#x2e;&#105;&#x6f;">&#103;&#x72;&#x6f;&#117;&#112;&#x40;&#104;&#x79;p&#101;&#114;&#102;&#46;&#x69;&#111;</a>",
"version": "1.0"
}
},
"NetworkSettings": {
"SandboxID": "31c7e20513fa9eb5bc38e9e5225b797b4cd2391ed9f0a9700e4f3b3460190dfd",
"SandboxKey": "/var/run/docker/netns/31c7e20513fa",
"Ports": {
"9501/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "9501"
},
{
"HostIp": "::",
"HostPort": "9501"
}
]
},
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"DriverOpts": null,
"GwPriority": 0,
"NetworkID": "b874ea6a38fefb11a4bf500d54ffe2365d3e22de5fc57610d7379bbb177b6be5",
"EndpointID": "1ecfdc26abb9841bca3f3f158d0d2fae70bad4db686d7837ed1fada1a177da55",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"MacAddress": "16:1e:f4:8e:99:5f",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": null
},
"dev-net": {
"IPAMConfig": {},
"Links": null,
"Aliases": [],
"DriverOpts": {},
"GwPriority": 0,
"NetworkID": "4b1b11f4edbeb6ea2dc17600e5366ddffa4e1fd1eec9d0c6da546764d9fe919c",
"EndpointID": "c03c1b28859f6e6dd736ce2c891e33226a428a9e8ca5232971626df2dfd9b907",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.5",
"MacAddress": "ce:80:6d:68:f9:90",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": [
"hyperf",
"9232c1fa90d7"
]
}
}
},
"ImageManifestDescriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:2852fa7c75e5f7c8b36dbc0ffaff8c6d7f1227f8454dbb0ab3cbccecb617da9c",
"size": 1055,
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
}
]
ubuntu@DESKTOP-H4MGQIU:~$ docker exec -it hyperf sh
/data/project # ping dev-redis
PING dev-redis (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.393 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.203 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.360 ms
64 bytes from 172.18.0.2: seq=3 ttl=64 time=0.136 ms
64 bytes from 172.18.0.2: seq=4 ttl=64 time=0.104 ms
64 bytes from 172.18.0.2: seq=5 ttl=64 time=0.250 ms
64 bytes from 172.18.0.2: seq=6 ttl=64 time=0.080 ms
64 bytes from 172.18.0.2: seq=7 ttl=64 time=0.077 ms
64 bytes from 172.18.0.2: seq=8 ttl=64 time=0.110 ms
64 bytes from 172.18.0.2: seq=9 ttl=64 time=0.080 ms
^C
--- dev-redis ping statistics ---
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max = 0.077/0.179/0.393 ms
/data/project # ping dev-mysql8
PING dev-mysql8 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.392 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.338 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.230 ms
64 bytes from 172.18.0.3: seq=3 ttl=64 time=0.355 ms
^C
--- dev-mysql8 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.230/0.328/0.392 ms
/data/project #


7、修改 Hyperf 配置,让它连到 Redis / MySQL。修改 Redis 配置,打开文件:.env ,修改相关变量。如图3

修改 Hyperf 配置,让它连到 Redis / MySQL。修改 Redis 配置,打开文件:.env ,修改相关变量。

8、再次启动 Hyperf 服务,启动成功。如图4

再次启动 Hyperf 服务,启动成功


/data/project/hyperf-skeleton # php bin/hyperf.php start
[DEBUG] [command] Commands registered by Hyperf\Command\Listener\RegisterCommandListener
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Command\Listener\RegisterCommandListener listener.
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Config\Listener\RegisterPropertyHandlerListener listener.
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\DbConnection\Listener\RegisterConnectionResolverListener listener.
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\ExceptionHandler\Listener\ExceptionHandlerListener listener.
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler listener.
[DEBUG] Event Hyperf\Framework\Event\BeforeMainServerStart handled by Hyperf\Process\Listener\BootProcessListener listener.
[INFO] Worker#1 started.
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\AfterWorkerStartListener listener.
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener.
[INFO] Worker#2 started.
[INFO] Worker#3 started.
[INFO] Worker#0 started.
[INFO] HTTP Server listening at 0.0.0.0:9501
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\AfterWorkerStartListener listener.
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\AfterWorkerStartListener listener.
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\AfterWorkerStartListener listener.
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener.
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener.
[DEBUG] Event Hyperf\Framework\Event\OnManagerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener.
[DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener.
[INFO] Process[queue.default.0] start.
[DEBUG] Event Hyperf\Process\Event\BeforeProcessHandle handled by Hyperf\Process\Listener\LogBeforeProcessStartListener listener.
[DEBUG] Event Hyperf\Process\Event\BeforeProcessHandle handled by Hyperf\Server\Listener\InitProcessTitleListener listener.



9、HTTP 服务已经启动,可以通过 http://localhost:9501 访问。如图5

HTTP 服务已经启动,可以通过 http://localhost:9501 访问
]]>
https://www.shuijingwanwq.com/2026/04/08/9440/feed/ 0
在 WSL-Ubuntu 中 Docker 下安装 Hyperf https://www.shuijingwanwq.com/2026/04/07/9435/ https://www.shuijingwanwq.com/2026/04/07/9435/#comments Tue, 07 Apr 2026 09:50:54 +0000 https://www.shuijingwanwq.com/?p=9435 浏览量: 297

1、第一步:在 WSL 里创建本地项目目录(比如 ~/wwwroot/hyperf-skeleton)



ubuntu@DESKTOP-H4MGQIU:~/wwwroot$ mkdir -p ~/wwwroot/hyperf-skeleton


2、修改挂载目录,适配本地目录的路径。参考:Hyperf 官方文档 Docker 下开发



ubuntu@DESKTOP-H4MGQIU:~/wwwroot$ docker run --name hyperf \
-v ~/wwwroot/hyperf-skeleton:/data/project \
-w /data/project \
-p 9501:9501 -it \
--privileged -u root \
--entrypoint /bin/sh \
hyperf/hyperf:8.1-alpine-v3.18-swoole
Unable to find image 'hyperf/hyperf:8.1-alpine-v3.18-swoole' locally
8.1-alpine-v3.18-swoole: Pulling from hyperf/hyperf
5715dfbf9dd7: Pull complete
bfa571bff938: Pull complete
58de83433912: Pull complete
44cf07d57ee4: Pull complete
471a4d85c85c: Download complete
Digest: sha256:3cbda08f3892507d760d31bba8b68aeb4b916333055bbf05cf46ea18c67fc935
Status: Downloaded newer image for hyperf/hyperf:8.1-alpine-v3.18-swoole
/data/project #


3、在容器内创建项目 ,创建项目失败,报错:Your requirements could not be resolved to an installable set of packages.。如图1

在容器内创建项目 ,创建项目失败,报错:Your requirements could not be resolved to an installable set of packages.


/data/project # composer create-project hyperf/hyperf-skeleton
Creating a "hyperf/hyperf-skeleton" project at "./hyperf-skeleton"
Installing hyperf/hyperf-skeleton (v3.1.3)
<ul>
 	<li>Downloading hyperf/hyperf-skeleton (v3.1.3)</li>
 	<li>Installing hyperf/hyperf-skeleton (v3.1.3): Extracting archive
Created project in /data/project/hyperf-skeleton</li>
</ul>
<blockquote>@php -r "file_exists('.env') || copy('.env.example', '.env');"
Installer\Script::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies</blockquote>
What time zone do you want to setup ?
[n] Default time zone for php.ini
Make your selection or type a time zone name, like Asia/Shanghai (n):
Asia/Shanghai

Do you want to use Database (MySQL Client) ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y
<ul>
 	<li>Adding package hyperf/database (~3.1.0)</li>
 	<li>Adding package hyperf/db-connection (~3.1.0)

Do you want to use Redis Client ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y</li>
 	<li>Adding package hyperf/redis (~3.1.0)</li>
 	<li>Copying config/autoload/redis.php

Which RPC protocol do you want to use ?
[1] JSON RPC with Service Governance
[2] JSON RPC
[3] gRPC
[n] None of the above
Make your selection or type a composer package name and version (n): n

Which config center do you want to use ?
[1] Apollo
[2] Aliyun ACM
[3] ETCD
[4] Nacos
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/constants component ?
[y] yes
[n] None of the above
Make your selection (n): y</li>
 	<li>Adding package hyperf/constants (~3.1.0)</li>
 	<li>Copying app/Constants/ErrorCode.php</li>
 	<li>Copying app/Exception/BusinessException.php

Do you want to use hyperf/async-queue component ? (A simple redis queue component)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): y</li>
 	<li>Adding package hyperf/async-queue (~3.1.0)</li>
 	<li>Copying config/autoload/async_queue.php</li>
 	<li>Copying app/Process/AsyncQueueConsumer.php</li>
 	<li>Copying app/Listener/QueueHandleListener.php</li>
 	<li>Copying config/autoload/redis.php

Do you want to use hyperf/amqp component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/model-cache component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/elasticsearch component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/tracer component ? (An open tracing protocol component, adapte with Zipkin etc.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use pestphp/pest component ? (Pest is a testing framework with a focus on simplicity,
meticulously designed to bring back the joy of testing in PHP.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): y</li>
 	<li>Adding package pestphp/pest (^2.34)</li>
 	<li>Copying test/Feature/ExampleTest.php</li>
 	<li>Copying test/Unit/ExampleTest.php</li>
 	<li>Copying test/Pest.php</li>
 	<li>Copying test/TestCase.php
Remove installer
Removing composer.lock from .gitignore
Removing Expressive installer classes, configuration, tests and docs
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

Problem 1
<ul>
 	<li>Root composer.json requires pestphp/pest ^2.34 -&gt; satisfiable by pestphp/pest[v2.34.0, …, 2.x-dev].</li>
 	<li>brianium/paratest[v7.9.0, …, v7.11.2] require php ~8.3.0 || ~8.4.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.12.0, …, 7.x-dev] require php ~8.3.0 || ~8.4.0 || ~8.5.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.4.3, …, v7.5.7] require php ~8.2.0 || ~8.3.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.4.8, …, v7.8.4] require php ~8.2.0 || ~8.3.0 || ~8.4.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.8.5, …, 7.8.x-dev] require php ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>pestphp/pest v2.34.0 conflicts with phpunit/phpunit 10.5.63.</li>
 	<li>pestphp/pest v2.34.0 conflicts with phpunit/phpunit 10.5.x-dev.</li>
 	<li>pestphp/pest v2.34.0 requires phpunit/phpunit ^10.5.10 -&gt; satisfiable by phpunit/phpunit[10.5.62, 10.5.63, 10.5.x-dev].</li>
 	<li>pestphp/pest v2.34.3 requires brianium/paratest ^7.4.3 -&gt; satisfiable by brianium/paratest[v7.4.3, …, 7.x-dev].</li>
 	<li>pestphp/pest[v2.36.1, …, 2.x-dev] require php ^8.2.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.1 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.2 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.4 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.5 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.6 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.9 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.35.0 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.35.1 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.36.0 (conflict analysis result)</li>
</ul>
</li>
</ul>
/data/project #


4、报错核心原因如下:
PHP 版本不匹配:容器里的 PHP 是 8.1.27,但 Pest(测试框架)的新版本要求 PHP ≥ 8.2,我的 PHP 8.1 满足不了;
依赖连锁冲突:Pest 依赖的 brianium/paratest、phpunit/phpunit 等组件,也要求更高版本的 PHP,最终导致 Composer 无法解析出一套能安装的依赖包。

5、最快解决方法(放弃安装 Pest,先跑通项目),退出当前失败的安装流程:重新执行创建项目命令(跳过 Pest),选择 n。提示: Project directory “/data/project/hyperf-skeleton” is not empty.。在容器的 /data/project 目录下,执行清空命令:rm -rf ./* ./.??* 。如图2

最快解决方法(放弃安装 Pest,先跑通项目)


/data/project # composer create-project hyperf/hyperf-skeleton
Creating a "hyperf/hyperf-skeleton" project at "./hyperf-skeleton"

In CreateProjectCommand.php line 368:

Project directory "/data/project/hyperf-skeleton" is not empty.

create-project [-s|--stability STABILITY] [--prefer-source] [--prefer-dist] [--prefer-install PREFER-INSTALL] [--repository REPOSITORY] [--repository-url REPOSITORY-URL] [--add-repository] [--dev] [--no-dev] [--no-custom-installers] [--no-scripts] [--no-progress] [--no-secure-http] [--keep-vcs] [--remove-vcs] [--no-install] [--no-audit] [--audit-format AUDIT-FORMAT] [--no-security-blocking] [--ignore-platform-req IGNORE-PLATFORM-REQ] [--ignore-platform-reqs] [--ask] [--] [<package> [<directory> [<version>]]]



6、在容器内创建项目 在 遇见 pestphp/pest 时,选择 n,创建项目成功。



/data/project # composer create-project hyperf/hyperf-skeleton
Creating a "hyperf/hyperf-skeleton" project at "./hyperf-skeleton"
Installing hyperf/hyperf-skeleton (v3.1.3)
<ul>
 	<li>Installing hyperf/hyperf-skeleton (v3.1.3): Extracting archive
Created project in /data/project/hyperf-skeleton</li>
</ul>
<blockquote>@php -r "file_exists('.env') || copy('.env.example', '.env');"
Installer\Script::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies</blockquote>
What time zone do you want to setup ?
[n] Default time zone for php.ini
Make your selection or type a time zone name, like Asia/Shanghai (n):
Asia/Shanghai

Do you want to use Database (MySQL Client) ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y
<ul>
 	<li>Adding package hyperf/database (~3.1.0)</li>
 	<li>Adding package hyperf/db-connection (~3.1.0)

Do you want to use Redis Client ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y</li>
 	<li>Adding package hyperf/redis (~3.1.0)</li>
 	<li>Copying config/autoload/redis.php

Which RPC protocol do you want to use ?
[1] JSON RPC with Service Governance
[2] JSON RPC
[3] gRPC
[n] None of the above
Make your selection or type a composer package name and version (n): n

Which config center do you want to use ?
[1] Apollo
[2] Aliyun ACM
[3] ETCD
[4] Nacos
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/constants component ?
[y] yes
[n] None of the above
Make your selection (n): y</li>
 	<li>Adding package hyperf/constants (~3.1.0)</li>
 	<li>Copying app/Constants/ErrorCode.php</li>
 	<li>Copying app/Exception/BusinessException.php

Do you want to use hyperf/async-queue component ? (A simple redis queue component)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): y</li>
 	<li>Adding package hyperf/async-queue (~3.1.0)</li>
 	<li>Copying config/autoload/async_queue.php</li>
 	<li>Copying app/Process/AsyncQueueConsumer.php</li>
 	<li>Copying app/Listener/QueueHandleListener.php</li>
 	<li>Copying config/autoload/redis.php

Do you want to use hyperf/amqp component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/model-cache component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/elasticsearch component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/tracer component ? (An open tracing protocol component, adapte with Zipkin etc.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use pestphp/pest component ? (Pest is a testing framework with a focus on simplicity,
meticulously designed to bring back the joy of testing in PHP.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n
Remove installer
Removing composer.lock from .gitignore
Removing Expressive installer classes, configuration, tests and docs
Loading composer repositories with package information
Updating dependencies
Lock file operations: 135 installs, 0 updates, 0 removals</li>
 	<li>Locking carbonphp/carbon-doctrine-types (3.2.0)</li>
 	<li>Locking clue/ndjson-react (v1.3.0)</li>
 	<li>Locking composer/pcre (3.3.2)</li>
 	<li>Locking composer/semver (3.4.4)</li>
 	<li>Locking composer/xdebug-handler (3.0.5)</li>
 	<li>Locking doctrine/inflector (2.1.0)</li>
 	<li>Locking doctrine/instantiator (1.5.0)</li>
 	<li>Locking evenement/evenement (v3.0.2)</li>
 	<li>Locking fidry/cpu-core-counter (1.3.0)</li>
 	<li>Locking fig/http-message-util (1.1.5)</li>
 	<li>Locking friendsofphp/php-cs-fixer (v3.94.2)</li>
 	<li>Locking graham-campbell/result-type (v1.1.4)</li>
 	<li>Locking guzzlehttp/guzzle (7.10.0)</li>
 	<li>Locking guzzlehttp/promises (2.3.0)</li>
 	<li>Locking guzzlehttp/psr7 (2.9.0)</li>
 	<li>Locking hamcrest/hamcrest-php (v2.1.1)</li>
 	<li>Locking hyperf/async-queue (v3.1.64)</li>
 	<li>Locking hyperf/cache (v3.1.67)</li>
 	<li>Locking hyperf/code-parser (v3.1.63)</li>
 	<li>Locking hyperf/codec (v3.1.63)</li>
 	<li>Locking hyperf/collection (v3.1.64)</li>
 	<li>Locking hyperf/command (v3.1.64)</li>
 	<li>Locking hyperf/conditionable (v3.1.63)</li>
 	<li>Locking hyperf/config (v3.1.63)</li>
 	<li>Locking hyperf/constants (v3.1.63)</li>
 	<li>Locking hyperf/context (v3.1.63)</li>
 	<li>Locking hyperf/contract (v3.1.63)</li>
 	<li>Locking hyperf/coordinator (v3.1.63)</li>
 	<li>Locking hyperf/coroutine (v3.1.65)</li>
 	<li>Locking hyperf/database (v3.1.67)</li>
 	<li>Locking hyperf/db-connection (v3.1.66)</li>
 	<li>Locking hyperf/devtool (v3.1.66)</li>
 	<li>Locking hyperf/di (v3.1.67)</li>
 	<li>Locking hyperf/dispatcher (v3.1.63)</li>
 	<li>Locking hyperf/engine (v2.15.0)</li>
 	<li>Locking hyperf/engine-contract (v1.14.0)</li>
 	<li>Locking hyperf/event (v3.1.63)</li>
 	<li>Locking hyperf/exception-handler (v3.1.63)</li>
 	<li>Locking hyperf/framework (v3.1.63)</li>
 	<li>Locking hyperf/guzzle (v3.1.66)</li>
 	<li>Locking hyperf/http-message (v3.1.65)</li>
 	<li>Locking hyperf/http-server (v3.1.65)</li>
 	<li>Locking hyperf/laminas-mime (v3.0.0)</li>
 	<li>Locking hyperf/logger (v3.1.63)</li>
 	<li>Locking hyperf/macroable (v3.1.63)</li>
 	<li>Locking hyperf/memory (v3.1.63)</li>
 	<li>Locking hyperf/model-listener (v3.1.63)</li>
 	<li>Locking hyperf/pipeline (v3.1.63)</li>
 	<li>Locking hyperf/pool (v3.1.66)</li>
 	<li>Locking hyperf/process (v3.1.63)</li>
 	<li>Locking hyperf/redis (v3.1.66)</li>
 	<li>Locking hyperf/serializer (v3.1.63)</li>
 	<li>Locking hyperf/server (v3.1.63)</li>
 	<li>Locking hyperf/stdlib (v3.1.63)</li>
 	<li>Locking hyperf/stringable (v3.1.65)</li>
 	<li>Locking hyperf/support (v3.1.65)</li>
 	<li>Locking hyperf/tappable (v3.1.63)</li>
 	<li>Locking hyperf/testing (v3.1.63)</li>
 	<li>Locking laminas/laminas-stdlib (3.20.0)</li>
 	<li>Locking mockery/mockery (1.6.12)</li>
 	<li>Locking monolog/monolog (3.10.0)</li>
 	<li>Locking myclabs/deep-copy (1.13.4)</li>
 	<li>Locking nesbot/carbon (2.73.0)</li>
 	<li>Locking nikic/fast-route (v1.3.0)</li>
 	<li>Locking nikic/php-parser (v4.19.5)</li>
 	<li>Locking phar-io/manifest (2.0.4)</li>
 	<li>Locking phar-io/version (3.2.1)</li>
 	<li>Locking php-di/phpdoc-reader (2.2.1)</li>
 	<li>Locking phpoption/phpoption (1.9.5)</li>
 	<li>Locking phpstan/phpstan (1.12.33)</li>
 	<li>Locking phpunit/php-code-coverage (10.1.16)</li>
 	<li>Locking phpunit/php-file-iterator (4.1.0)</li>
 	<li>Locking phpunit/php-invoker (4.0.0)</li>
 	<li>Locking phpunit/php-text-template (3.0.1)</li>
 	<li>Locking phpunit/php-timer (6.0.0)</li>
 	<li>Locking phpunit/phpunit (10.5.63)</li>
 	<li>Locking psr/clock (1.0.0)</li>
 	<li>Locking psr/container (2.0.2)</li>
 	<li>Locking psr/event-dispatcher (1.0.0)</li>
 	<li>Locking psr/http-client (1.0.3)</li>
 	<li>Locking psr/http-factory (1.1.0)</li>
 	<li>Locking psr/http-message (2.0)</li>
 	<li>Locking psr/http-server-handler (1.0.2)</li>
 	<li>Locking psr/http-server-middleware (1.0.2)</li>
 	<li>Locking psr/log (3.0.2)</li>
 	<li>Locking psr/simple-cache (3.0.0)</li>
 	<li>Locking ralouphie/getallheaders (3.0.3)</li>
 	<li>Locking react/cache (v1.2.0)</li>
 	<li>Locking react/child-process (v0.6.7)</li>
 	<li>Locking react/dns (v1.14.0)</li>
 	<li>Locking react/event-loop (v1.6.0)</li>
 	<li>Locking react/promise (v3.3.0)</li>
 	<li>Locking react/socket (v1.17.0)</li>
 	<li>Locking react/stream (v1.4.0)</li>
 	<li>Locking sebastian/cli-parser (2.0.1)</li>
 	<li>Locking sebastian/code-unit (2.0.0)</li>
 	<li>Locking sebastian/code-unit-reverse-lookup (3.0.0)</li>
 	<li>Locking sebastian/comparator (5.0.5)</li>
 	<li>Locking sebastian/complexity (3.2.0)</li>
 	<li>Locking sebastian/diff (5.1.1)</li>
 	<li>Locking sebastian/environment (6.1.0)</li>
 	<li>Locking sebastian/exporter (5.1.4)</li>
 	<li>Locking sebastian/global-state (6.0.2)</li>
 	<li>Locking sebastian/lines-of-code (2.0.2)</li>
 	<li>Locking sebastian/object-enumerator (5.0.0)</li>
 	<li>Locking sebastian/object-reflector (3.0.0)</li>
 	<li>Locking sebastian/recursion-context (5.0.1)</li>
 	<li>Locking sebastian/type (4.0.0)</li>
 	<li>Locking sebastian/version (4.0.1)</li>
 	<li>Locking swoole/ide-helper (5.1.8)</li>
 	<li>Locking swow/psr7-plus (v1.1.2)</li>
 	<li>Locking symfony/console (v6.4.35)</li>
 	<li>Locking symfony/deprecation-contracts (v3.6.0)</li>
 	<li>Locking symfony/event-dispatcher (v6.4.32)</li>
 	<li>Locking symfony/event-dispatcher-contracts (v3.6.0)</li>
 	<li>Locking symfony/filesystem (v6.4.34)</li>
 	<li>Locking symfony/finder (v6.4.34)</li>
 	<li>Locking symfony/http-foundation (v6.4.35)</li>
 	<li>Locking symfony/options-resolver (v6.4.30)</li>
 	<li>Locking symfony/polyfill-ctype (v1.33.0)</li>
 	<li>Locking symfony/polyfill-intl-grapheme (v1.33.0)</li>
 	<li>Locking symfony/polyfill-intl-normalizer (v1.33.0)</li>
 	<li>Locking symfony/polyfill-mbstring (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php80 (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php81 (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php83 (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php84 (v1.33.0)</li>
 	<li>Locking symfony/process (v6.4.33)</li>
 	<li>Locking symfony/service-contracts (v3.6.1)</li>
 	<li>Locking symfony/stopwatch (v6.4.24)</li>
 	<li>Locking symfony/string (v6.4.34)</li>
 	<li>Locking symfony/translation (v6.4.34)</li>
 	<li>Locking symfony/translation-contracts (v3.6.1)</li>
 	<li>Locking theseer/tokenizer (1.3.1)</li>
 	<li>Locking vlucas/phpdotenv (v5.6.3)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 135 installs, 0 updates, 0 removals</li>
 	<li>Downloading composer/pcre (3.3.2)</li>
 	<li>Downloading doctrine/inflector (2.1.0)</li>
 	<li>Downloading doctrine/instantiator (1.5.0)</li>
 	<li>Downloading symfony/deprecation-contracts (v3.6.0)</li>
 	<li>Downloading psr/container (2.0.2)</li>
 	<li>Downloading symfony/service-contracts (v3.6.1)</li>
 	<li>Downloading symfony/stopwatch (v6.4.24)</li>
 	<li>Downloading symfony/process (v6.4.33)</li>
 	<li>Downloading symfony/polyfill-php84 (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-php81 (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-php80 (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-mbstring (v1.33.0)</li>
 	<li>Downloading symfony/options-resolver (v6.4.30)</li>
 	<li>Downloading symfony/finder (v6.4.34)</li>
 	<li>Downloading symfony/polyfill-ctype (v1.33.0)</li>
 	<li>Downloading symfony/filesystem (v6.4.34)</li>
 	<li>Downloading psr/event-dispatcher (1.0.0)</li>
 	<li>Downloading symfony/event-dispatcher-contracts (v3.6.0)</li>
 	<li>Downloading symfony/event-dispatcher (v6.4.32)</li>
 	<li>Downloading symfony/polyfill-intl-normalizer (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-intl-grapheme (v1.33.0)</li>
 	<li>Downloading symfony/string (v6.4.34)</li>
 	<li>Downloading symfony/console (v6.4.35)</li>
 	<li>Downloading sebastian/diff (5.1.1)</li>
 	<li>Downloading react/event-loop (v1.6.0)</li>
 	<li>Downloading evenement/evenement (v3.0.2)</li>
 	<li>Downloading react/stream (v1.4.0)</li>
 	<li>Downloading react/promise (v3.3.0)</li>
 	<li>Downloading react/cache (v1.2.0)</li>
 	<li>Downloading react/dns (v1.14.0)</li>
 	<li>Downloading react/socket (v1.17.0)</li>
 	<li>Downloading react/child-process (v0.6.7)</li>
 	<li>Downloading fidry/cpu-core-counter (1.3.0)</li>
 	<li>Downloading psr/log (3.0.2)</li>
 	<li>Downloading composer/xdebug-handler (3.0.5)</li>
 	<li>Downloading composer/semver (3.4.4)</li>
 	<li>Downloading clue/ndjson-react (v1.3.0)</li>
 	<li>Downloading friendsofphp/php-cs-fixer (v3.94.2)</li>
 	<li>Downloading guzzlehttp/promises (2.3.0)</li>
 	<li>Downloading ralouphie/getallheaders (3.0.3)</li>
 	<li>Downloading psr/http-message (2.0)</li>
 	<li>Downloading psr/http-factory (1.1.0)</li>
 	<li>Downloading guzzlehttp/psr7 (2.9.0)</li>
 	<li>Downloading hyperf/tappable (v3.1.63)</li>
 	<li>Downloading hyperf/macroable (v3.1.63)</li>
 	<li>Downloading hyperf/conditionable (v3.1.63)</li>
 	<li>Downloading hyperf/stringable (v3.1.65)</li>
 	<li>Downloading hyperf/contract (v3.1.63)</li>
 	<li>Downloading hyperf/collection (v3.1.64)</li>
 	<li>Downloading hyperf/engine-contract (v1.14.0)</li>
 	<li>Downloading hyperf/engine (v2.15.0)</li>
 	<li>Downloading hyperf/context (v3.1.63)</li>
 	<li>Downloading hyperf/coroutine (v3.1.65)</li>
 	<li>Downloading hyperf/support (v3.1.65)</li>
 	<li>Downloading phpoption/phpoption (1.9.5)</li>
 	<li>Downloading graham-campbell/result-type (v1.1.4)</li>
 	<li>Downloading vlucas/phpdotenv (v5.6.3)</li>
 	<li>Downloading php-di/phpdoc-reader (2.2.1)</li>
 	<li>Downloading nikic/php-parser (v4.19.5)</li>
 	<li>Downloading hyperf/stdlib (v3.1.63)</li>
 	<li>Downloading hyperf/pipeline (v3.1.63)</li>
 	<li>Downloading hyperf/code-parser (v3.1.63)</li>
 	<li>Downloading hyperf/di (v3.1.67)</li>
 	<li>Downloading hyperf/coordinator (v3.1.63)</li>
 	<li>Downloading hyperf/command (v3.1.64)</li>
 	<li>Downloading hyperf/codec (v3.1.63)</li>
 	<li>Downloading hyperf/async-queue (v3.1.64)</li>
 	<li>Downloading psr/simple-cache (3.0.0)</li>
 	<li>Downloading hyperf/cache (v3.1.67)</li>
 	<li>Downloading hyperf/config (v3.1.63)</li>
 	<li>Downloading hyperf/constants (v3.1.63)</li>
 	<li>Downloading hyperf/pool (v3.1.66)</li>
 	<li>Downloading hyperf/event (v3.1.63)</li>
 	<li>Downloading symfony/translation-contracts (v3.6.1)</li>
 	<li>Downloading symfony/translation (v6.4.34)</li>
 	<li>Downloading psr/clock (1.0.0)</li>
 	<li>Downloading carbonphp/carbon-doctrine-types (3.2.0)</li>
 	<li>Downloading nesbot/carbon (2.73.0)</li>
 	<li>Downloading hyperf/database (v3.1.67)</li>
 	<li>Downloading hyperf/model-listener (v3.1.63)</li>
 	<li>Downloading fig/http-message-util (1.1.5)</li>
 	<li>Downloading hyperf/framework (v3.1.63)</li>
 	<li>Downloading hyperf/db-connection (v3.1.66)</li>
 	<li>Downloading hyperf/devtool (v3.1.66)</li>
 	<li>Downloading psr/http-client (1.0.3)</li>
 	<li>Downloading swow/psr7-plus (v1.1.2)</li>
 	<li>Downloading laminas/laminas-stdlib (3.20.0)</li>
 	<li>Downloading hyperf/laminas-mime (v3.0.0)</li>
 	<li>Downloading hyperf/http-message (v3.1.65)</li>
 	<li>Downloading psr/http-server-handler (1.0.2)</li>
 	<li>Downloading psr/http-server-middleware (1.0.2)</li>
 	<li>Downloading hyperf/dispatcher (v3.1.63)</li>
 	<li>Downloading hyperf/exception-handler (v3.1.63)</li>
 	<li>Downloading guzzlehttp/guzzle (7.10.0)</li>
 	<li>Downloading hyperf/guzzle (v3.1.66)</li>
 	<li>Downloading monolog/monolog (3.10.0)</li>
 	<li>Downloading hyperf/logger (v3.1.63)</li>
 	<li>Downloading hyperf/memory (v3.1.63)</li>
 	<li>Downloading hyperf/process (v3.1.63)</li>
 	<li>Downloading hyperf/redis (v3.1.66)</li>
 	<li>Downloading hyperf/serializer (v3.1.63)</li>
 	<li>Downloading hyperf/server (v3.1.63)</li>
 	<li>Downloading symfony/polyfill-php83 (v1.33.0)</li>
 	<li>Downloading symfony/http-foundation (v6.4.35)</li>
 	<li>Downloading sebastian/version (4.0.1)</li>
 	<li>Downloading sebastian/type (4.0.0)</li>
 	<li>Downloading sebastian/recursion-context (5.0.1)</li>
 	<li>Downloading sebastian/object-reflector (3.0.0)</li>
 	<li>Downloading sebastian/object-enumerator (5.0.0)</li>
 	<li>Downloading sebastian/global-state (6.0.2)</li>
 	<li>Downloading sebastian/exporter (5.1.4)</li>
 	<li>Downloading sebastian/environment (6.1.0)</li>
 	<li>Downloading sebastian/comparator (5.0.5)</li>
 	<li>Downloading sebastian/code-unit (2.0.0)</li>
 	<li>Downloading sebastian/cli-parser (2.0.1)</li>
 	<li>Downloading phpunit/php-timer (6.0.0)</li>
 	<li>Downloading phpunit/php-text-template (3.0.1)</li>
 	<li>Downloading phpunit/php-invoker (4.0.0)</li>
 	<li>Downloading phpunit/php-file-iterator (4.1.0)</li>
 	<li>Downloading theseer/tokenizer (1.3.1)</li>
 	<li>Downloading sebastian/lines-of-code (2.0.2)</li>
 	<li>Downloading sebastian/complexity (3.2.0)</li>
 	<li>Downloading sebastian/code-unit-reverse-lookup (3.0.0)</li>
 	<li>Downloading phpunit/php-code-coverage (10.1.16)</li>
 	<li>Downloading phar-io/version (3.2.1)</li>
 	<li>Downloading phar-io/manifest (2.0.4)</li>
 	<li>Downloading myclabs/deep-copy (1.13.4)</li>
 	<li>Downloading phpunit/phpunit (10.5.63)</li>
 	<li>Downloading nikic/fast-route (v1.3.0)</li>
 	<li>Downloading hyperf/http-server (v3.1.65)</li>
 	<li>Downloading hyperf/testing (v3.1.63)</li>
 	<li>Downloading hamcrest/hamcrest-php (v2.1.1)</li>
 	<li>Downloading mockery/mockery (1.6.12)</li>
 	<li>Downloading phpstan/phpstan (1.12.33)</li>
 	<li>Downloading swoole/ide-helper (5.1.8)</li>
 	<li>Installing composer/pcre (3.3.2): Extracting archive</li>
 	<li>Installing doctrine/inflector (2.1.0): Extracting archive</li>
 	<li>Installing doctrine/instantiator (1.5.0): Extracting archive</li>
 	<li>Installing symfony/deprecation-contracts (v3.6.0): Extracting archive</li>
 	<li>Installing psr/container (2.0.2): Extracting archive</li>
 	<li>Installing symfony/service-contracts (v3.6.1): Extracting archive</li>
 	<li>Installing symfony/stopwatch (v6.4.24): Extracting archive</li>
 	<li>Installing symfony/process (v6.4.33): Extracting archive</li>
 	<li>Installing symfony/polyfill-php84 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-php81 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-php80 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-mbstring (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/options-resolver (v6.4.30): Extracting archive</li>
 	<li>Installing symfony/finder (v6.4.34): Extracting archive</li>
 	<li>Installing symfony/polyfill-ctype (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/filesystem (v6.4.34): Extracting archive</li>
 	<li>Installing psr/event-dispatcher (1.0.0): Extracting archive</li>
 	<li>Installing symfony/event-dispatcher-contracts (v3.6.0): Extracting archive</li>
 	<li>Installing symfony/event-dispatcher (v6.4.32): Extracting archive</li>
 	<li>Installing symfony/polyfill-intl-normalizer (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-intl-grapheme (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/string (v6.4.34): Extracting archive</li>
 	<li>Installing symfony/console (v6.4.35): Extracting archive</li>
 	<li>Installing sebastian/diff (5.1.1): Extracting archive</li>
 	<li>Installing react/event-loop (v1.6.0): Extracting archive</li>
 	<li>Installing evenement/evenement (v3.0.2): Extracting archive</li>
 	<li>Installing react/stream (v1.4.0): Extracting archive</li>
 	<li>Installing react/promise (v3.3.0): Extracting archive</li>
 	<li>Installing react/cache (v1.2.0): Extracting archive</li>
 	<li>Installing react/dns (v1.14.0): Extracting archive</li>
 	<li>Installing react/socket (v1.17.0): Extracting archive</li>
 	<li>Installing react/child-process (v0.6.7): Extracting archive</li>
 	<li>Installing fidry/cpu-core-counter (1.3.0): Extracting archive</li>
 	<li>Installing psr/log (3.0.2): Extracting archive</li>
 	<li>Installing composer/xdebug-handler (3.0.5): Extracting archive</li>
 	<li>Installing composer/semver (3.4.4): Extracting archive</li>
 	<li>Installing clue/ndjson-react (v1.3.0): Extracting archive</li>
 	<li>Installing friendsofphp/php-cs-fixer (v3.94.2): Extracting archive</li>
 	<li>Installing guzzlehttp/promises (2.3.0): Extracting archive</li>
 	<li>Installing ralouphie/getallheaders (3.0.3): Extracting archive</li>
 	<li>Installing psr/http-message (2.0): Extracting archive</li>
 	<li>Installing psr/http-factory (1.1.0): Extracting archive</li>
 	<li>Installing guzzlehttp/psr7 (2.9.0): Extracting archive</li>
 	<li>Installing hyperf/tappable (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/macroable (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/conditionable (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/stringable (v3.1.65): Extracting archive</li>
 	<li>Installing hyperf/contract (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/collection (v3.1.64): Extracting archive</li>
 	<li>Installing hyperf/engine-contract (v1.14.0): Extracting archive</li>
 	<li>Installing hyperf/engine (v2.15.0): Extracting archive</li>
 	<li>Installing hyperf/context (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/coroutine (v3.1.65): Extracting archive</li>
 	<li>Installing hyperf/support (v3.1.65): Extracting archive</li>
 	<li>Installing phpoption/phpoption (1.9.5): Extracting archive</li>
 	<li>Installing graham-campbell/result-type (v1.1.4): Extracting archive</li>
 	<li>Installing vlucas/phpdotenv (v5.6.3): Extracting archive</li>
 	<li>Installing php-di/phpdoc-reader (2.2.1): Extracting archive</li>
 	<li>Installing nikic/php-parser (v4.19.5): Extracting archive</li>
 	<li>Installing hyperf/stdlib (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/pipeline (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/code-parser (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/di (v3.1.67): Extracting archive</li>
 	<li>Installing hyperf/coordinator (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/command (v3.1.64): Extracting archive</li>
 	<li>Installing hyperf/codec (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/async-queue (v3.1.64): Extracting archive</li>
 	<li>Installing psr/simple-cache (3.0.0): Extracting archive</li>
 	<li>Installing hyperf/cache (v3.1.67): Extracting archive</li>
 	<li>Installing hyperf/config (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/constants (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/pool (v3.1.66): Extracting archive</li>
 	<li>Installing hyperf/event (v3.1.63): Extracting archive</li>
 	<li>Installing symfony/translation-contracts (v3.6.1): Extracting archive</li>
 	<li>Installing symfony/translation (v6.4.34): Extracting archive</li>
 	<li>Installing psr/clock (1.0.0): Extracting archive</li>
 	<li>Installing carbonphp/carbon-doctrine-types (3.2.0): Extracting archive</li>
 	<li>Installing nesbot/carbon (2.73.0): Extracting archive</li>
 	<li>Installing hyperf/database (v3.1.67): Extracting archive</li>
 	<li>Installing hyperf/model-listener (v3.1.63): Extracting archive</li>
 	<li>Installing fig/http-message-util (1.1.5): Extracting archive</li>
 	<li>Installing hyperf/framework (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/db-connection (v3.1.66): Extracting archive</li>
 	<li>Installing hyperf/devtool (v3.1.66): Extracting archive</li>
 	<li>Installing psr/http-client (1.0.3): Extracting archive</li>
 	<li>Installing swow/psr7-plus (v1.1.2): Extracting archive</li>
 	<li>Installing laminas/laminas-stdlib (3.20.0): Extracting archive</li>
 	<li>Installing hyperf/laminas-mime (v3.0.0): Extracting archive</li>
 	<li>Installing hyperf/http-message (v3.1.65): Extracting archive</li>
 	<li>Installing psr/http-server-handler (1.0.2): Extracting archive</li>
 	<li>Installing psr/http-server-middleware (1.0.2): Extracting archive</li>
 	<li>Installing hyperf/dispatcher (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/exception-handler (v3.1.63): Extracting archive</li>
 	<li>Installing guzzlehttp/guzzle (7.10.0): Extracting archive</li>
 	<li>Installing hyperf/guzzle (v3.1.66): Extracting archive</li>
 	<li>Installing monolog/monolog (3.10.0): Extracting archive</li>
 	<li>Installing hyperf/logger (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/memory (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/process (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/redis (v3.1.66): Extracting archive</li>
 	<li>Installing hyperf/serializer (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/server (v3.1.63): Extracting archive</li>
 	<li>Installing symfony/polyfill-php83 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/http-foundation (v6.4.35): Extracting archive</li>
 	<li>Installing sebastian/version (4.0.1): Extracting archive</li>
 	<li>Installing sebastian/type (4.0.0): Extracting archive</li>
 	<li>Installing sebastian/recursion-context (5.0.1): Extracting archive</li>
 	<li>Installing sebastian/object-reflector (3.0.0): Extracting archive</li>
 	<li>Installing sebastian/object-enumerator (5.0.0): Extracting archive</li>
 	<li>Installing sebastian/global-state (6.0.2): Extracting archive</li>
 	<li>Installing sebastian/exporter (5.1.4): Extracting archive</li>
 	<li>Installing sebastian/environment (6.1.0): Extracting archive</li>
 	<li>Installing sebastian/comparator (5.0.5): Extracting archive</li>
 	<li>Installing sebastian/code-unit (2.0.0): Extracting archive</li>
 	<li>Installing sebastian/cli-parser (2.0.1): Extracting archive</li>
 	<li>Installing phpunit/php-timer (6.0.0): Extracting archive</li>
 	<li>Installing phpunit/php-text-template (3.0.1): Extracting archive</li>
 	<li>Installing phpunit/php-invoker (4.0.0): Extracting archive</li>
 	<li>Installing phpunit/php-file-iterator (4.1.0): Extracting archive</li>
 	<li>Installing theseer/tokenizer (1.3.1): Extracting archive</li>
 	<li>Installing sebastian/lines-of-code (2.0.2): Extracting archive</li>
 	<li>Installing sebastian/complexity (3.2.0): Extracting archive</li>
 	<li>Installing sebastian/code-unit-reverse-lookup (3.0.0): Extracting archive</li>
 	<li>Installing phpunit/php-code-coverage (10.1.16): Extracting archive</li>
 	<li>Installing phar-io/version (3.2.1): Extracting archive</li>
 	<li>Installing phar-io/manifest (2.0.4): Extracting archive</li>
 	<li>Installing myclabs/deep-copy (1.13.4): Extracting archive</li>
 	<li>Installing phpunit/phpunit (10.5.63): Extracting archive</li>
 	<li>Installing nikic/fast-route (v1.3.0): Extracting archive</li>
 	<li>Installing hyperf/http-server (v3.1.65): Extracting archive</li>
 	<li>Installing hyperf/testing (v3.1.63): Extracting archive</li>
 	<li>Installing hamcrest/hamcrest-php (v2.1.1): Extracting archive</li>
 	<li>Installing mockery/mockery (1.6.12): Extracting archive</li>
 	<li>Installing phpstan/phpstan (1.12.33): Extracting archive</li>
 	<li>Installing swoole/ide-helper (5.1.8): Extracting archive
27 package suggestions were added by new dependencies, use <code>composer suggest</code> to see details.
Generating optimized autoload files</li>
</ul>
<blockquote>rm -rf runtime/container
114 packages you are using are looking for funding.
Use the <code>composer fund</code> command to find out more!
No security vulnerability advisories found.
/data/project #


]]>
https://www.shuijingwanwq.com/2026/04/07/9435/feed/ 1
Go + Gin 实战 RESTful API:从环境搭建(WSL/Docker/VS Code)到 Git 提交与 GitHub 托管 https://www.shuijingwanwq.com/2026/04/03/9416/ https://www.shuijingwanwq.com/2026/04/03/9416/#respond Fri, 03 Apr 2026 04:11:30 +0000 https://www.shuijingwanwq.com/?p=9416 浏览量: 196

1、参考:使用 Go 和 Gin 构建 RESTful API(Go.dev) https://go.dev/doc/tutorial/web-service-gin — 使用 Gin 构建简单 Web 服务的 Go 官方教程。

2、安装 Go。Docker Compose 一键启动(参考 Hyperf 项目化)。我想要 “写好配置,一条命令启动整个开发环境”,用 docker-compose.yml 最为方便,和 Hyperf 的 Docker Compose 用法几乎一样。创建项目文件夹:web-service-gin



ubuntu@DESKTOP-H4MGQIU:~/wwwroot$ mkdir web-service-gin
ubuntu@DESKTOP-H4MGQIU:~/wwwroot$ cd web-service-gin
ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ pwd
/home/ubuntu/wwwroot/web-service-gin


3、创建 docker-compose.yml



version: '3.8'

services:
  go:
    image: golang:1.23-alpine
    container_name: go-gin-tutorial
    working_dir: /app
    volumes:
      - ./:/app         # 本地代码挂载
    ports:
      - "8080:8080"     # 映射端口最好加引号
    tty: true
    stdin_open: true
    environment:
      - GOPROXY=https://goproxy.io,direct
    command: tail -f /dev/null   # 容器启动后保持运行状态


4、启动容器(进入 Go 环境), 报错:WSL Ubuntu 里只装了 Docker,没装 Docker Compose。



ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ docker-compose up -d
Command 'docker-compose' not found, but can be installed with:
sudo snap install docker          # version 28.4.0, or
sudo apt  install docker-compose  # version 1.29.2-1
See 'snap info docker' for additional versions.
ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ sudo apt update && sudo apt install -y docker-compose
[sudo] password for ubuntu:
Get:1 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Hit:2 https://download.docker.com/linux/ubuntu jammy InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy InRelease
Hit:4 https://packages.redis.io/deb jammy InRelease
Get:5 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
Get:6 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [127 kB]
Get:7 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [3328 kB]
Get:8 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 c-n-f Metadata [30.4 kB]
Fetched 3743 kB in 7s (575 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
62 packages can be upgraded. Run 'apt list --upgradable' to see them.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  docker-ce docker-ce-cli python3-attr python3-certifi python3-chardet python3-distutils python3-docker python3-dockerpty python3-docopt python3-dotenv python3-idna python3-jsonschema
  python3-lib2to3 python3-pyrsistent python3-requests python3-setuptools python3-texttable python3-urllib3 python3-websocket
Suggested packages:
  cgroupfs-mount | cgroup-lite python-attr-doc python-jsonschema-doc python3-openssl python3-socks python-requests-doc python-setuptools-doc
Recommended packages:
  docker.io
The following NEW packages will be installed:
  docker-compose python3-attr python3-certifi python3-chardet python3-distutils python3-docker python3-dockerpty python3-docopt python3-dotenv python3-idna python3-jsonschema
  python3-lib2to3 python3-pyrsistent python3-requests python3-setuptools python3-texttable python3-urllib3 python3-websocket
The following packages will be upgraded:
  docker-ce docker-ce-cli
2 upgraded, 18 newly installed, 0 to remove and 60 not upgraded.
Need to get 40.4 MB of archives.
After this operation, 7757 kB of additional disk space will be used.
Get:1 https://download.docker.com/linux/ubuntu jammy/stable amd64 docker-ce-cli amd64 5:29.3.1-1~ubuntu.22.04~jammy [16.4 MB]
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-lib2to3 all 3.10.8-1~22.04 [77.6 kB]
Get:3 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-distutils all 3.10.8-1~22.04 [139 kB]
Get:4 http://archive.ubuntu.com/ubuntu jammy/main amd64 python3-certifi all 2020.6.20-1 [150 kB]
Get:5 http://archive.ubuntu.com/ubuntu jammy/main amd64 python3-chardet all 4.0.0-1 [98.0 kB]
Get:6 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-idna all 3.3-1ubuntu0.1 [52.1 kB]
Get:7 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-urllib3 all 1.26.5-1~exp1ubuntu0.6 [98.7 kB]
Get:8 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-requests all 2.25.1+dfsg-2ubuntu0.3 [48.8 kB]
Get:9 http://archive.ubuntu.com/ubuntu jammy/universe amd64 python3-websocket all 1.2.3-1 [34.7 kB]
Get:10 http://archive.ubuntu.com/ubuntu jammy/universe amd64 python3-docker all 5.0.3-1 [89.3 kB]
Get:11 http://archive.ubuntu.com/ubuntu jammy/universe amd64 python3-dockerpty all 0.4.1-2 [11.1 kB]
Get:12 http://archive.ubuntu.com/ubuntu jammy/universe amd64 python3-docopt all 0.6.2-4 [26.9 kB]
Get:13 http://archive.ubuntu.com/ubuntu jammy/universe amd64 python3-dotenv all 0.19.2-1 [20.5 kB]
Get:14 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-attr all 21.2.0-1ubuntu1 [43.9 kB]
Get:15 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-setuptools all 59.6.0-1.2ubuntu0.22.04.3 [340 kB]
Get:16 http://archive.ubuntu.com/ubuntu jammy/main amd64 python3-pyrsistent amd64 0.18.1-1build1 [55.5 kB]
Get:17 http://archive.ubuntu.com/ubuntu jammy/main amd64 python3-jsonschema all 3.2.0-0ubuntu2 [43.1 kB]
Get:18 http://archive.ubuntu.com/ubuntu jammy/universe amd64 python3-texttable all 1.6.4-1 [11.4 kB]
Get:19 http://archive.ubuntu.com/ubuntu jammy/universe amd64 docker-compose all 1.29.2-1 [95.8 kB]
Get:20 https://download.docker.com/linux/ubuntu jammy/stable amd64 docker-ce amd64 5:29.3.1-1~ubuntu.22.04~jammy [22.6 MB]
Fetched 40.4 MB in 10s (3969 kB/s)
(Reading database ... 24579 files and directories currently installed.)
Preparing to unpack .../00-docker-ce-cli_5%3a29.3.1-1~ubuntu.22.04~jammy_amd64.deb ...
Unpacking docker-ce-cli (5:29.3.1-1~ubuntu.22.04~jammy) over (5:29.3.0-1~ubuntu.22.04~jammy) ...
Preparing to unpack .../01-docker-ce_5%3a29.3.1-1~ubuntu.22.04~jammy_amd64.deb ...
Unpacking docker-ce (5:29.3.1-1~ubuntu.22.04~jammy) over (5:29.3.0-1~ubuntu.22.04~jammy) ...
Selecting previously unselected package python3-lib2to3.
Preparing to unpack .../02-python3-lib2to3_3.10.8-1~22.04_all.deb ...
Unpacking python3-lib2to3 (3.10.8-1~22.04) ...
Selecting previously unselected package python3-distutils.
Preparing to unpack .../03-python3-distutils_3.10.8-1~22.04_all.deb ...
Unpacking python3-distutils (3.10.8-1~22.04) ...
Selecting previously unselected package python3-certifi.
Preparing to unpack .../04-python3-certifi_2020.6.20-1_all.deb ...
Unpacking python3-certifi (2020.6.20-1) ...
Selecting previously unselected package python3-chardet.
Preparing to unpack .../05-python3-chardet_4.0.0-1_all.deb ...
Unpacking python3-chardet (4.0.0-1) ...
Selecting previously unselected package python3-idna.
Preparing to unpack .../06-python3-idna_3.3-1ubuntu0.1_all.deb ...
Unpacking python3-idna (3.3-1ubuntu0.1) ...
Selecting previously unselected package python3-urllib3.
Preparing to unpack .../07-python3-urllib3_1.26.5-1~exp1ubuntu0.6_all.deb ...
Unpacking python3-urllib3 (1.26.5-1~exp1ubuntu0.6) ...
Selecting previously unselected package python3-requests.
Preparing to unpack .../08-python3-requests_2.25.1+dfsg-2ubuntu0.3_all.deb ...
Unpacking python3-requests (2.25.1+dfsg-2ubuntu0.3) ...
Selecting previously unselected package python3-websocket.
Preparing to unpack .../09-python3-websocket_1.2.3-1_all.deb ...
Unpacking python3-websocket (1.2.3-1) ...
Selecting previously unselected package python3-docker.
Preparing to unpack .../10-python3-docker_5.0.3-1_all.deb ...
Unpacking python3-docker (5.0.3-1) ...
Selecting previously unselected package python3-dockerpty.
Preparing to unpack .../11-python3-dockerpty_0.4.1-2_all.deb ...
Unpacking python3-dockerpty (0.4.1-2) ...
Selecting previously unselected package python3-docopt.
Preparing to unpack .../12-python3-docopt_0.6.2-4_all.deb ...
Unpacking python3-docopt (0.6.2-4) ...
Selecting previously unselected package python3-dotenv.
Preparing to unpack .../13-python3-dotenv_0.19.2-1_all.deb ...
Unpacking python3-dotenv (0.19.2-1) ...
Selecting previously unselected package python3-attr.
Preparing to unpack .../14-python3-attr_21.2.0-1ubuntu1_all.deb ...
Unpacking python3-attr (21.2.0-1ubuntu1) ...
Selecting previously unselected package python3-setuptools.
Preparing to unpack .../15-python3-setuptools_59.6.0-1.2ubuntu0.22.04.3_all.deb ...
Unpacking python3-setuptools (59.6.0-1.2ubuntu0.22.04.3) ...
Selecting previously unselected package python3-pyrsistent:amd64.
Preparing to unpack .../16-python3-pyrsistent_0.18.1-1build1_amd64.deb ...
Unpacking python3-pyrsistent:amd64 (0.18.1-1build1) ...
Selecting previously unselected package python3-jsonschema.
Preparing to unpack .../17-python3-jsonschema_3.2.0-0ubuntu2_all.deb ...
Unpacking python3-jsonschema (3.2.0-0ubuntu2) ...
Selecting previously unselected package python3-texttable.
Preparing to unpack .../18-python3-texttable_1.6.4-1_all.deb ...
Unpacking python3-texttable (1.6.4-1) ...
Selecting previously unselected package docker-compose.
Preparing to unpack .../19-docker-compose_1.29.2-1_all.deb ...
Unpacking docker-compose (1.29.2-1) ...
Setting up python3-dotenv (0.19.2-1) ...
Setting up python3-attr (21.2.0-1ubuntu1) ...
Setting up python3-texttable (1.6.4-1) ...
Setting up python3-docopt (0.6.2-4) ...
Setting up python3-chardet (4.0.0-1) ...
Setting up python3-certifi (2020.6.20-1) ...
Setting up python3-idna (3.3-1ubuntu0.1) ...
Setting up python3-urllib3 (1.26.5-1~exp1ubuntu0.6) ...
Setting up docker-ce-cli (5:29.3.1-1~ubuntu.22.04~jammy) ...
Setting up python3-pyrsistent:amd64 (0.18.1-1build1) ...
Setting up python3-lib2to3 (3.10.8-1~22.04) ...
Setting up python3-websocket (1.2.3-1) ...
Setting up python3-dockerpty (0.4.1-2) ...
Setting up python3-distutils (3.10.8-1~22.04) ...
Setting up python3-setuptools (59.6.0-1.2ubuntu0.22.04.3) ...
Setting up python3-jsonschema (3.2.0-0ubuntu2) ...
Setting up docker-ce (5:29.3.1-1~ubuntu.22.04~jammy) ...
Setting up python3-requests (2.25.1+dfsg-2ubuntu0.3) ...
Setting up python3-docker (5.0.3-1) ...
Setting up docker-compose (1.29.2-1) ...
Processing triggers for man-db (2.10.2-1) ...
ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ docker-compose --version
docker-compose version 1.29.2, build unknown
ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ docker-compose up -d
Creating network "web-service-gin_default" with the default driver
Pulling go (golang:1.23-alpine)...
1.23-alpine: Pulling from library/golang
4f4fb700ef54: Pull complete
9824c27679d3: Pull complete
8371a51cbc44: Pull complete
d5791340ef18: Pull complete
d3178a7b2709: Pull complete
28f6f92c256d: Download complete
d1ac4f409af1: Download complete
Digest: sha256:383395b794dffa5b53012a212365d40c8e37109a626ca30d6151c8348d380b5f
Status: Downloaded newer image for golang:1.23-alpine
Creating go-gin-tutorial ... done
ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ docker-compose exec go sh
/app # ls -la
total 12
drwxr-xr-x    2 1000     1000          4096 Mar 30 03:36 .
drwxr-xr-x    1 root     root          4096 Mar 30 03:40 ..
-rw-r--r--    1 1000     1000           272 Mar 30 03:36 docker-compose.yml


5、创建一个可以管理依赖项的模块。运行该go mod init命令,并指定代码所在模块的路径。



/app # go mod init example/web-service-gin
go: creating new go.mod: module example/web-service-gin


6、打算用 GoLand(Windows)直接编辑 WSL 里的 Go 代码,以配合我的 Docker 环境。我的 Go 代码存在 WSL Ubuntu 的文件夹里,GoLand 可以直接访问 WSL 文件,就像访问本地文件夹一样。现在的代码在这里:~/wwwroot/web-service-gin。在 Windows 里访问这个路径,就是:\wsl$\Ubuntu\home\ubuntu\wwwroot\web-service-gin。 GoLand 打开这个文件夹,打开 GoLand,点 Open(打开),把上面复制的路径直接粘贴到文件夹地址栏,按回车,选择文件夹 → OK。现在就能在 Windows GoLand 里编辑、修改、保存 WSL 里的 Go 代码了。而且修改会实时同步到 Docker 容器里!如图1

在 Windows 里访问这个路径,就是:\wsl$\Ubuntu\home\ubuntu\wwwroot\web-service-gin

7、配置 GoLand 连接 WSL 里的 Docker(关键)
重启后:
文件 → 设置 → 构建、执行、部署 → Docker
左上角 + 添加连接
连接类型选择:WSL(重点:不要选 Docker Desktop)
发行版下拉选择:Ubuntu
底部显示「连接成功」即可
应用 → 确定。如图2

配置 GoLand 连接 WSL 里的 Docker

8、文件 → 设置 → 运行目标,添加 → 选 Docker Compose,点击右上角 +选择:✅ Docker Compose。运行目标(Docker Compose)配置完成后,GoLand 会获得:只管【运行】,不管【代码提示】
它的作用只有:
点 ▶️ 运行时
代码在 Docker 容器里执行。如图3

文件 → 设置 → 运行目标,添加 → 选 Docker Compose

9、项目默认目标:go。如图4

项目默认目标:go

10、代码提示、自动补全、语法识别 必须靠 GOROOT
GoLand 要想识别:
string
int
fmt
函数跳转
自动补全
必须配置:本地 GOROOT这是 IDE 硬性规则。打开 WSL Ubuntu 终端,复制运行:



# 1. 下载 Go 1.23(和容器版本一样)
wget https://dl.google.com/go/go1.23.0.linux-amd64.tar.gz

# 2. 安装到 Linux 标准路径:/usr/local/go
sudo tar -C /usr/local -xzf go1.23.0.linux-amd64.tar.gz

# 3. 配置环境变量
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

# 4. 验证安装成功
go version


11、打开 GoLand 设置 → Go → GOROOT
点 + 添加
选择 WSL
自动找到 /usr/local/go
确定 → 应用。如图5

打开 GoLand 设置 → Go → GOROOT

12、创建数据,创建一个名为 main.go 的文件。将在这个文件中编写 Go 代码。



package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// album represents data about a record album.
type album struct {
	ID     string  `json:"id"`
	Title  string  `json:"title"`
	Artist string  `json:"artist"`
	Price  float64 `json:"price"`
}

// albums slice to seed record album data.
var albums = []album{
	{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
	{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
	{ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

func main() {
	router := gin.Default()
	router.GET("/albums", getAlbums)

	router.Run("0.0.0.0:8080") // 监听所有网卡
}

// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
	c.IndentedJSON(http.StatusOK, albums)
}


13、现在 IDE 有一些报错的提示:

无法解析符号’github.com’
无法解析符号’gin-gonic’
无法解析符号’gin’
未解析的引用 ‘Default’。如图6

现在 IDE 有一些报错的提示

14、打开 WSL 终端,在 WSL 直接执行:go get github.com/gin-gonic/gin



ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ go get github.com/gin-gonic/gin
go: downloading github.com/gin-gonic/gin v1.12.0
go: github.com/gin-gonic/gin@v1.12.0 requires go >= 1.25.0; switching to go1.25.8
go: downloading github.com/gin-contrib/sse v1.1.0
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading github.com/quic-go/quic-go v0.59.0
go: downloading golang.org/x/net v0.51.0
go: downloading github.com/bytedance/sonic v1.15.0
go: downloading github.com/goccy/go-json v0.10.5
go: downloading github.com/json-iterator/go v1.1.12
go: downloading github.com/goccy/go-yaml v1.19.2
go: downloading github.com/pelletier/go-toml/v2 v2.2.4
go: downloading github.com/ugorji/go/codec v1.3.1
go: downloading go.mongodb.org/mongo-driver/v2 v2.5.0
go: downloading google.golang.org/protobuf v1.36.10
go: downloading github.com/go-playground/validator/v10 v10.30.1
go: downloading golang.org/x/sys v0.41.0
go: downloading github.com/quic-go/qpack v0.6.0
go: downloading github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
go: downloading github.com/modern-go/reflect2 v1.0.2
go: downloading github.com/gabriel-vasile/mimetype v1.4.12
go: downloading github.com/go-playground/universal-translator v0.18.1
go: downloading github.com/leodido/go-urn v1.4.0
go: downloading golang.org/x/crypto v0.48.0
go: downloading golang.org/x/text v0.34.0
go: downloading github.com/bytedance/gopkg v0.1.3
go: downloading github.com/cloudwego/base64x v0.1.6
go: downloading golang.org/x/arch v0.22.0
go: downloading github.com/go-playground/locales v0.14.1
go: downloading github.com/klauspost/cpuid/v2 v2.3.0
go: downloading github.com/bytedance/sonic/loader v0.5.0
go: downloading github.com/twitchyliquid64/golang-asm v0.15.1
go: updating go.mod: open /home/ubuntu/wwwroot/web-service-gin/go.mod: permission denied

15、反省一下,感觉现在这样太痛苦了。这种 “容器里装依赖、容器外装依赖” 的用法,是错误、混乱、反人类的!** 容器的优势就是环境统一、隔离、不用乱装东西。现在被用成了:一边容器、一边 WSL,精神分裂!真正正确的开发模式只有两种:只用 WSL 的 Go,不用 Docker 跑开发;全部在 Docker 里,WSL 什么都不装;

16、仔细排查原因,找到了根源,在 文件 → 设置 → 构建、执行、部署 → Docker 中,虚拟机路径:/home/ubuntu/wwwroot/web-service-gin,这个路径是 WSL 中的路径。** 正确的路径 不应该是 WSL 路径!应该是【容器内部的路径】!**。虚拟机路径修改为:/app。如图7

虚拟机路径修改为:/app

17、发现 GOROOT 中仍然不提供 Docker 的选项。GoLand 在「没有 Docker Desktop」的环境下,就是无法直接选择容器内的 GOROOT!最终决定,放弃 GoLand,改用 VS Code + Dev Containers

18、Windows 安装 VS Code,VS Code 扩展商店安装:Dev Containers(微软官方)、WSL、Docker

19、启动容器,报错:ERROR: for go ‘ContainerConfig’,这是老容器 + Python V1 的兼容性问题

<pre class="wp-block-syntaxhighlighter-code">

ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ docker-compose up -d
Recreating 814a800e96e6_go-gin-tutorial ...

ERROR: for 814a800e96e6_go-gin-tutorial  'ContainerConfig'

ERROR: for go  'ContainerConfig'
Traceback (most recent call last):
  File "/usr/bin/docker-compose", line 33, in <module>
    sys.exit(load_entry_point('docker-compose==1.29.2', 'console_scripts', 'docker-compose')())
  File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 81, in main
    command_func()
  File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 203, in perform_command
    handler(command, command_options)
  File "/usr/lib/python3/dist-packages/compose/metrics/decorator.py", line 18, in wrapper
    result = fn(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 1186, in up
    to_attach = up(False)
  File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 1166, in up
    return self.project.up(
  File "/usr/lib/python3/dist-packages/compose/project.py", line 697, in up
    results, errors = parallel.parallel_execute(
  File "/usr/lib/python3/dist-packages/compose/parallel.py", line 108, in parallel_execute
    raise error_to_reraise
  File "/usr/lib/python3/dist-packages/compose/parallel.py", line 206, in producer
    result = func(obj)
  File "/usr/lib/python3/dist-packages/compose/project.py", line 679, in do
    return service.execute_convergence_plan(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 579, in execute_convergence_plan
    return self._execute_convergence_recreate(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 499, in _execute_convergence_recreate
    containers, errors = parallel_execute(
  File "/usr/lib/python3/dist-packages/compose/parallel.py", line 108, in parallel_execute
    raise error_to_reraise
  File "/usr/lib/python3/dist-packages/compose/parallel.py", line 206, in producer
    result = func(obj)
  File "/usr/lib/python3/dist-packages/compose/service.py", line 494, in recreate
    return self.recreate_container(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 612, in recreate_container
    new_container = self.create_container(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 330, in create_container
    container_options = self._get_container_create_options(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 921, in _get_container_create_options
    container_options, override_options = self._build_container_volume_options(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 960, in _build_container_volume_options
    binds, affinity = merge_volume_bindings(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 1548, in merge_volume_bindings
    old_volumes, old_mounts = get_container_data_volumes(
  File "/usr/lib/python3/dist-packages/compose/service.py", line 1579, in get_container_data_volumes
    container.image_config['ContainerConfig'].get('Volumes') or {}
KeyError: 'ContainerConfig'

</pre>

20、进入目录:~/wwwroot/web-service-gin,执行 :code .。是否信任此文件夹中的文件的作者? 是。如图8

进入目录:~/wwwroot/web-service-gin,执行 :code .。是否信任此文件夹中的文件的作者? 是


ubuntu@DESKTOP-H4MGQIU:~/wwwroot/web-service-gin$ code .
Installing VS Code Server for Linux x64 (cfbea10c5ffb233ea9177d34726e6056e89913dc)
Downloading: 100%
Unpacking: 100%
Unpacked 3690 files and folders to /home/ubuntu/.vscode-server/bin/cfbea10c5ffb233ea9177d34726e6056e89913dc.
Looking for compatibility check script at /home/ubuntu/.vscode-server/bin/cfbea10c5ffb233ea9177d34726e6056e89913dc/bin/helpers/check-requirements.sh
Running compatibility check script
Compatibility check successful (0)


21、删除 .idea 目录,这是 Goland 留下的。准备 Dev Container 配置文件,直接用已有 Docker 镜像,新建:.devcontainer/devcontainer.json


{
  "name": "Go Gin Dev Container",
  "dockerComposeFile": ["../docker-compose.yml"],
  "service": "go",
  "workspaceFolder": "/app",
  "settings": {
    "terminal.integrated.shell.linux": "/bin/sh"
  },
  "extensions": [
    "golang.Go"
  ],
  "forwardPorts": [8080],
  "remoteUser": "root"
}

解释:

dockerComposeFile 指向 docker-compose.yml
service 是希望 VS Code 连接的服务(这里是 go)
workspaceFolder 是代码挂载目录 /app
extensions 自动在容器里安装 Go 插件
forwardPorts 映射容器端口到 VS Code
remoteUser 可选,如果容器里默认用户不是 root

22、VS Code 打开容器
打开 VS Code,进入项目目录
按 F1 → 输入 Dev Containers: Reopen in Container
VS Code 会根据 devcontainer.json 和 docker-compose.yml 启动容器并挂载代码
打开终端,会发现直接在容器里(/app),Go 版本和 Docker 镜像一致

⚡ 提示:如果容器启动慢,可以先用 docker-compose up -d 启动容器,再用 Dev Container 连接。如图9

VS Code 打开容器

23、开发流程建议
用 Dev Container 打开项目
直接在容器终端运行 Go 或 PHP 命令
容器里安装依赖(go mod tidy、composer install 等)
在 VS Code 中调试、运行、测试
不需要关心 WSL 上是否安装 Go/PHP

24、多项目 + 多容器流程图

┌─────────────────────────────────────────────────────────────┐
│ VS Code │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Project-Go │ │ Project-PHP74 │ │ Project-PHP81 │ │
│ │ Workspace │ │ Workspace │ │ Workspace │ │
│ │ (.code-workspace) │ │ (.code-workspace) │ │ (.code-workspace) │ │
│ │ Dev Container │ │ Dev Container │ │ Dev Container │ │
│ │ Service: go │ │ Service: php74 │ │ Service: php81 │ │
│ │ Image: golang:1.23 │ │ Image: php:7.4-fpm │ │ Image: php:8.1-fpm │ │
│ │ Ports: 8080 │ │ Ports: 8000 │ │ Ports: 8001 │ │
│ └─────────────┬───────┘ └─────────────┬───────┘ └─────────────┬───────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Docker Container Go │ │ Docker Container │ │ Docker Container │ │
│ │ Version: 1.23 │ │ PHP 7.4 FPM │ │ PHP 8.1 FPM │ │
│ │ /app ← 挂载项目代码 │ │ /app ← 挂载项目代码 │ │ /app ← 挂载项目代码 │ │
│ │ 端口 8080 映射本地 │ │ 端口 8000 映射本地 │ │ 端口 8001 映射本地 │ │
│ └─────────────────────┘ └─────────────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

说明:

  • 每个 VS Code 窗口对应一个独立 Workspace(项目)
  • 每个 Workspace 使用独立 Dev Container 连接对应 Docker 容器
  • 容器内挂载 /app 到对应项目代码,开发和运行环境完全一致
  • 不同项目端口独立映射,本地访问互不冲突

25、以下是 web-service-gin 项目的完整流程图,显示 VS Code、Dev Container、Docker 容器、挂载路径和端口映射,完全贴合本地开发环境。

┌───────────────────────────────────────────────────────────────────────────────┐
│ VS Code Window │
│ (web-service-gin Workspace) │
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Dev Container (Go) │ │
│ │ Service: go │ │
│ │ Image: golang:1.23-alpine │ │
│ │ WorkspaceFolder: /app │ │
│ │ Extensions: golang.Go │ │
│ │ ForwardPorts: 8080 │ │
│ │ RemoteUser: root │ │
│ └───────────────┬───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Docker Container (Go) │ │
│ │ Container Name: go-gin-tutorial │ │
│ │ Go Version: 1.23 │ │
│ │ Command: tail -f /dev/null │ │
│ │ Working Dir: /app │ │
│ │ Volume Mount: ./ (本地代码) → /app │ │
│ │ Port Mapping: 8080 → 8080 (本地访问 Gin Web) │ │
│ │ Environment: GOPROXY=https://goproxy.io,direct │ │
│ └───────────────────────────────────────────────┘ │
│ │
│ 编辑流程:VS Code 编辑器 → Dev Container → Docker 容器运行 → 本地端口访问 Web │
└───────────────────────────────────────────────────────────────────────────────┘

26、以下是 宽屏版多项目组合图,展示 Go + PHP74 + PHP81 三个项目的 VS Code Workspace、Dev Container、Docker 容器、挂载路径和端口映射,横向排列,方便直观理解多项目、多语言、多容器的本地开发环境:

┌───────────────────────────────────────────────────────────────────────────────────────────────┐
│ VS Code Windows │
│ (各自 Workspace 独立窗口) │
│ │
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
│ │ Project-Go Workspace │ │ Project-PHP74 Workspace │ │ Project-PHP81 Workspace │ │
│ │ (.code-workspace) │ │ (.code-workspace) │ │ (.code-workspace) │ │
│ │ Dev Container: go │ │ Dev Container: php74 │ │ Dev Container: php81 │ │
│ │ Image: golang:1.23-alpine │ │ Image: php:7.4-fpm │ │ Image: php:8.1-fpm │ │
│ │ ForwardPorts: 8080 │ │ ForwardPorts: 8000 │ │ ForwardPorts: 8001 │ │
│ │ RemoteUser: root │ │ RemoteUser: root │ │ RemoteUser: root │ │
│ └───────────────┬─────────────┘ └───────────────┬─────────────┘ └───────────────┬─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
│ │ Docker Container Go │ │ Docker Container PHP 7.4 │ │ Docker Container PHP 8.1 │ │
│ │ Name: go-gin-tutorial │ │ Name: php74-dev │ │ Name: php81-dev │ │
│ │ Version: 1.23 │ │ Version: 7.4 FPM │ │ Version: 8.1 FPM │ │
│ │ Working Dir: /app │ │ Working Dir: /app │ │ Working Dir: /app │ │
│ │ Volume Mount: ./ → /app │ │ Volume Mount: ./ → /app │ │ Volume Mount: ./ → /app │ │
│ │ Port Mapping: 8080 → 8080 │ │ Port Mapping: 8000 → 8000 │ │ Port Mapping: 8001 → 8001 │ │
│ │ Command: tail -f /dev/null │ │ Command: tail -f /dev/null │ │ Command: tail -f /dev/null │ │
│ │ Environment: GOPROXY=… │ │ │ │ │ │
│ └─────────────────────────────┘ └─────────────────────────────┘ └─────────────────────────────┘ │
│ │
│ 开发流程说明: │
│ VS Code 编辑 → Dev Container → Docker 容器运行 → 挂载代码 → 本地端口访问 Web/服务 │
│ 多项目、多语言版本独立,端口互不冲突,环境一致 │
└───────────────────────────────────────────────────────────────────────────────────────────────┘

图示说明

  1. VS Code Windows / Workspace
    每个项目对应一个 VS Code 窗口
    .code-workspace 配置独立
    插件、调试、终端完全隔离
  2. Dev Container
    连接对应 Docker 容器
    WorkspaceFolder 映射 /app
    ForwardPorts 映射本地访问端口
    插件和调试工具在容器内部运行
  3. Docker 容器
    Go / PHP 版本与镜像一致
    挂载本地代码,容器内修改即生效
    容器端口映射到本地端口,访问服务方便
    每个容器独立运行,不会影响其他项目
  4. 开发流程
    在 VS Code 编辑器编辑代码
    代码挂载到 Dev Container → Docker 容器
    容器运行服务或编译命令
    本地浏览器访问对应端口

优势

每个项目都是独立环境,类似 PHPStorm SDK + 项目隔离
多语言版本支持(Go + PHP74 + PHP81)
端口映射互不冲突,可同时运行多个服务
VS Code 窗口对应项目 Workspace,完全独立

27、我现在要如何将 APP [开发容器: GO GIN DEV CONTAINER] 转换为一个工作区呢?在 VS Code 中直接引用容器路径
打开 命令面板(Ctrl+Shift+P / Cmd+Shift+P)
输入 Save Workspace As…
点击 显示本地,保存至 C:\Users\Thinkpad\VSCodeWorkspaces\go-gin-tutorial-app.code-workspace。如图10

我现在要如何将 APP [开发容器: GO GIN DEV CONTAINER] 转换为一个工作区呢?

28、新开 vs code 后,文件 – 从文件打开工作区 – 显示本地 – C:\Users\Thinkpad\VSCodeWorkspaces\go-gin-tutorial-app.code-workspace。

29、现在在 vs code 中,问题:could not import github.com/gin-gonic/gin (no required module provides package “github.com/gin-gonic/gin”)。这是 Go Modules 依赖没安装或者未初始化 的典型错误。如图11

现在在 vs code 中,问题:could not import github.com/gin-gonic/gin (no required module provides package "github.com/gin-gonic/gin")

30、运行代码 开始将 Gin 模块作为依赖项进行跟踪。在命令行中,使用该go get 命令将 github.com/gin-gonic/gin 模块添加为模块的依赖项。使用点号参数表示“获取当前目录中代码的依赖项”。在 VS Code 里进入容器执行命令,默认打开的就是容器内的终端,路径应该是 /app,Go 已解析并下载此依赖项,以满足import 在上一步中添加的声明。如图12

在命令行中,使用该go get 命令将 github.com/gin-gonic/gin 模块添加为您的模块的依赖项。


/app # pwd
/app
/app # go get .
go: github.com/gin-gonic/gin@v1.12.0 requires go >= 1.25.0 (running go 1.23.12; GOTOOLCHAIN=local)
/app # 

31、在包含 main.go 的目录中,从命令行运行代码。使用点号参数表示“在当前目录中运行代码”。报错:


/app # go run .
main.go:6:2: no required module provides package github.com/gin-gonic/gin; to add it:
        go get github.com/gin-gonic/gin
/app # 

32、找到了根源,当前容器里的 Go 版本是 1.23.12,Gin v1.12.0 需要 Go ≥ 1.25.0,所以即使执行了 go get . 或 go get github.com/gin-gonic/gin,也会失败,VS Code 就提示:no required module provides package github.com/gin-gonic/gin。

33、编辑 docker-compose.yml,升级 Go 镜像版本,golang:1.23-alpine 修改为 golang:1.26-alpine



version: '3.8'

services:
  go:
    image: golang:1.26-alpine
    container_name: go-gin-tutorial
    working_dir: /app
    volumes:
      - ./:/app         # 本地代码挂载
    ports:
      - "8080:8080"     # 映射端口最好加引号
    tty: true
    stdin_open: true
    environment:
      - GOPROXY=https://goproxy.io,direct
    command: tail -f /dev/null   # 容器启动后保持运行状态


34、容器重建流程(VS Code 内完成)
修改 docker-compose.yml 升级 Go 镜像版本
命令面板 Ctrl+Shift+P → 输入:
Dev Containers: Rebuild and Reopen in Container
VS Code 会销毁旧容器并基于新镜像创建新容器
打开终端执行第 4 步命令,Gin 环境就绪

✅ 工作区 .code-workspace 和本地代码不会丢失
✅ 容器里的 Go 版本和 Gin 依赖都是最新

35、再次执行 go get . 命令,未提示版本问题,正确执行。


/app # go get .
go: downloading github.com/gin-gonic/gin v1.12.0
go: downloading github.com/gin-contrib/sse v1.1.0
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading golang.org/x/net v0.51.0
go: downloading github.com/quic-go/quic-go v0.59.0
go: downloading github.com/go-playground/validator/v10 v10.30.1
go: downloading github.com/goccy/go-yaml v1.19.2
go: downloading github.com/pelletier/go-toml/v2 v2.2.4
go: downloading github.com/bytedance/sonic v1.15.0
go: downloading github.com/ugorji/go/codec v1.3.1
go: downloading github.com/goccy/go-json v0.10.5
go: downloading go.mongodb.org/mongo-driver/v2 v2.5.0
go: downloading github.com/json-iterator/go v1.1.12
go: downloading google.golang.org/protobuf v1.36.10
go: downloading golang.org/x/sys v0.41.0
go: downloading github.com/quic-go/qpack v0.6.0
go: downloading github.com/gabriel-vasile/mimetype v1.4.12
go: downloading github.com/go-playground/universal-translator v0.18.1
go: downloading github.com/leodido/go-urn v1.4.0
go: downloading golang.org/x/crypto v0.48.0
go: downloading golang.org/x/text v0.34.0
go: downloading github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
go: downloading github.com/modern-go/reflect2 v1.0.2
go: downloading github.com/go-playground/locales v0.14.1
go: downloading github.com/bytedance/gopkg v0.1.3
go: downloading github.com/cloudwego/base64x v0.1.6
go: downloading golang.org/x/arch v0.22.0
go: downloading github.com/klauspost/cpuid/v2 v2.3.0
go: downloading github.com/bytedance/sonic/loader v0.5.0
go: downloading github.com/twitchyliquid64/golang-asm v0.15.1
go: upgraded go 1.23.12 => 1.25.0
go: added github.com/bytedance/gopkg v0.1.3
go: added github.com/bytedance/sonic v1.15.0
go: added github.com/bytedance/sonic/loader v0.5.0
go: added github.com/cloudwego/base64x v0.1.6
go: added github.com/gabriel-vasile/mimetype v1.4.12
go: added github.com/gin-contrib/sse v1.1.0
go: added github.com/gin-gonic/gin v1.12.0
go: added github.com/go-playground/locales v0.14.1
go: added github.com/go-playground/universal-translator v0.18.1
go: added github.com/go-playground/validator/v10 v10.30.1
go: added github.com/goccy/go-json v0.10.5
go: added github.com/goccy/go-yaml v1.19.2
go: added github.com/json-iterator/go v1.1.12
go: added github.com/klauspost/cpuid/v2 v2.3.0
go: added github.com/leodido/go-urn v1.4.0
go: added github.com/mattn/go-isatty v0.0.20
go: added github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
go: added github.com/modern-go/reflect2 v1.0.2
go: added github.com/pelletier/go-toml/v2 v2.2.4
go: added github.com/quic-go/qpack v0.6.0
go: added github.com/quic-go/quic-go v0.59.0
go: added github.com/twitchyliquid64/golang-asm v0.15.1
go: added github.com/ugorji/go/codec v1.3.1
go: added go.mongodb.org/mongo-driver/v2 v2.5.0
go: added golang.org/x/arch v0.22.0
go: added golang.org/x/crypto v0.48.0
go: added golang.org/x/net v0.51.0
go: added golang.org/x/sys v0.41.0
go: added golang.org/x/text v0.34.0
go: added google.golang.org/protobuf v1.36.10
/app # 

36、在包含 main.go 的目录中,从命令行运行代码。使用点号参数表示“在当前目录中运行代码”。



/app # go run .




代码运行后,就拥有了一个可以向其发送请求的 HTTP 服务器。

37、Windows 浏览器访问:http://localhost:8080/albums ,响应状态:(失败)net::ERR_EMPTY_RESPONSE。修改 main.go,router.Run(“0.0.0.0:8080”) // 监听所有网卡。显示预先提供给服务的数据。如图13

Windows 浏览器访问:http://localhost:8080/albums


[
    {
        "id": "1",
        "title": "Blue Train",
        "artist": "John Coltrane",
        "price": 56.99
    },
    {
        "id": "2",
        "title": "Jeru",
        "artist": "Gerry Mulligan",
        "price": 17.99
    },
    {
        "id": "3",
        "title": "Sarah Vaughan and Clifford Brown",
        "artist": "Sarah Vaughan",
        "price": 39.99
    }
]

68、生成 GitHub 的 Personal Access Token(个人访问令牌)。
我30 秒手把手教生成 Token,一次搞定,以后再也不用输密码!
一步一步生成 GitHub Token
打开 GitHub 右上角头像 → Settings
左侧最下面 → Developer settings
点击 Personal access tokens → Tokens (classic)
点击右上角 Generate new token → Generate new token (classic)
填写:
Note:填 go-gin-learning(随便写,方便自己记)
Expiration:选 90 days 或者 No expiration
Select scopes:勾选 repo(全勾第一项就行)
拉到最下面 → Generate token
复制生成的一串以 ghp_ 开头的代码(只显示一次,关掉就没了!)如图14

生成 GitHub 的 Personal Access Token(个人访问令牌)

69、决定将代码提交至 GitHub,创建仓库:https://github.com/shuijingwan/go-gin-learning 。在容器里的 /app 目录(vs code 下的终端),直接执行下面 全部命令:

<pre class="wp-block-syntaxhighlighter-code">

/app # git init
/bin/sh: git: not found
/app # apk add git
( 1/13) Installing brotli-libs (1.2.0-r0)
( 2/13) Installing c-ares (1.34.6-r0)
( 3/13) Installing libunistring (1.4.1-r0)
( 4/13) Installing libidn2 (2.3.8-r0)
( 5/13) Installing nghttp2-libs (1.68.0-r0)
( 6/13) Installing nghttp3 (1.13.1-r0)
( 7/13) Installing libpsl (0.21.5-r3)
( 8/13) Installing zstd-libs (1.5.7-r2)
( 9/13) Installing libcurl (8.17.0-r1)
(10/13) Installing libexpat (2.7.5-r0)
(11/13) Installing pcre2 (10.47-r0)
(12/13) Installing git (2.52.0-r0)
(13/13) Installing git-init-template (2.52.0-r0)
Executing busybox-1.37.0-r30.trigger
OK: 23.4 MiB in 32 packages
/app # git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: will change to "main" in Git 3.0. To configure the initial branch name
hint: to use in all of your new repositories, which will suppress this warning,
hint: call:
hint:
hint:   git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:   git branch -m <name>
hint:
hint: Disable this message with "git config set advice.defaultBranchName false"
Initialized empty Git repository in /app/.git/
/app # echo "# go-gin-learning" >> README.md
/app # cat > .gitignore << 'EOF'
> /bin
> /dist
> /vendor/
> .env
> .env.test
> .idea/
> .vscode/
> .DS_Store
> EOF
/app # git add .
fatal: detected dubious ownership in repository at '/app'
To add an exception for this directory, call:

        git config --global --add safe.directory /app
/app # git config --global --add safe.directory /app
/app # git add .
/app # git commit -m "feat: 初始化Go Gin项目,集成容器开发环境"
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@e4dccfba01fb.(none)')
/app # git config --global user.name "shuijingwan"
/app # git config --global user.email "shuijingwanwq@163.com"
/app # git commit -m "feat: 初始化Go Gin项目,集成容器开发环境"
[master (root-commit) 023e682] feat: 初始化Go Gin项目,集成容器开发环境
 7 files changed, 188 insertions(+)
 create mode 100644 .devcontainer/devcontainer.json
 create mode 100644 .gitignore
 create mode 100644 README.md
 create mode 100644 docker-compose.yml
 create mode 100644 go.mod
 create mode 100644 go.sum
 create mode 100644 main.go
/app # git branch -M main
/app # git remote add origin https://github.com/shuijingwan/go-gin-learning.git
/app # git push -u origin main
Username for 'https://github.com': shuijingwan
Password for 'https://shuijingwan@github.com': 
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 4 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (10/10), 5.21 KiB | 313.00 KiB/s, done.
Total 10 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/shuijingwan/go-gin-learning.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.
/app # 
</pre>

70、查看 GitHub 上的仓库目录,发现 .devcontainer 被提交了。现在仓库目录结构如下

/go-gin-learning
├── .devcontainer/ ✅ 应该提交
│ └── devcontainer.json
├── .gitignore ✅ 应该提交
├── README.md ✅ 应该提交
├── docker-compose.yml ✅ 应该提交
├── go.mod
├── go.sum
└── main.go

]]>
https://www.shuijingwanwq.com/2026/04/03/9416/feed/ 0
在 WSL-Ubuntu 中 Docker 下安装 Hyperf https://www.shuijingwanwq.com/2026/03/20/9355/ https://www.shuijingwanwq.com/2026/03/20/9355/#respond Fri, 20 Mar 2026 03:32:36 +0000 https://www.shuijingwanwq.com/?p=9355 浏览量: 151

1、第一步:在 WSL 里创建本地项目目录(比如 ~/wwwroot/hyperf-skeleton)



ubuntu@DESKTOP-H4MGQIU:~/wwwroot$ mkdir -p ~/wwwroot/hyperf-skeleton


2、修改挂载目录,适配本地目录的路径。参考:Hyperf 官方文档 Docker 下开发



ubuntu@DESKTOP-H4MGQIU:~/wwwroot$ docker run --name hyperf \
-v ~/wwwroot/hyperf-skeleton:/data/project \
-w /data/project \
-p 9501:9501 -it \
--privileged -u root \
--entrypoint /bin/sh \
hyperf/hyperf:8.1-alpine-v3.18-swoole
Unable to find image 'hyperf/hyperf:8.1-alpine-v3.18-swoole' locally
8.1-alpine-v3.18-swoole: Pulling from hyperf/hyperf
5715dfbf9dd7: Pull complete
bfa571bff938: Pull complete
58de83433912: Pull complete
44cf07d57ee4: Pull complete
471a4d85c85c: Download complete
Digest: sha256:3cbda08f3892507d760d31bba8b68aeb4b916333055bbf05cf46ea18c67fc935
Status: Downloaded newer image for hyperf/hyperf:8.1-alpine-v3.18-swoole
/data/project #


3、在容器内创建项目 ,创建项目失败,报错:Your requirements could not be resolved to an installable set of packages.。如图1

在容器内创建项目 ,创建项目失败,报错:Your requirements could not be resolved to an installable set of packages.


/data/project # composer create-project hyperf/hyperf-skeleton
Creating a "hyperf/hyperf-skeleton" project at "./hyperf-skeleton"
Installing hyperf/hyperf-skeleton (v3.1.3)
<ul>
 	<li>Downloading hyperf/hyperf-skeleton (v3.1.3)</li>
 	<li>Installing hyperf/hyperf-skeleton (v3.1.3): Extracting archive
Created project in /data/project/hyperf-skeleton</li>
</ul>
<blockquote>@php -r "file_exists('.env') || copy('.env.example', '.env');"
Installer\Script::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies</blockquote>
What time zone do you want to setup ?
[n] Default time zone for php.ini
Make your selection or type a time zone name, like Asia/Shanghai (n):
Asia/Shanghai

Do you want to use Database (MySQL Client) ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y
<ul>
 	<li>Adding package hyperf/database (~3.1.0)</li>
 	<li>Adding package hyperf/db-connection (~3.1.0)

Do you want to use Redis Client ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y</li>
 	<li>Adding package hyperf/redis (~3.1.0)</li>
 	<li>Copying config/autoload/redis.php

Which RPC protocol do you want to use ?
[1] JSON RPC with Service Governance
[2] JSON RPC
[3] gRPC
[n] None of the above
Make your selection or type a composer package name and version (n): n

Which config center do you want to use ?
[1] Apollo
[2] Aliyun ACM
[3] ETCD
[4] Nacos
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/constants component ?
[y] yes
[n] None of the above
Make your selection (n): y</li>
 	<li>Adding package hyperf/constants (~3.1.0)</li>
 	<li>Copying app/Constants/ErrorCode.php</li>
 	<li>Copying app/Exception/BusinessException.php

Do you want to use hyperf/async-queue component ? (A simple redis queue component)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): y</li>
 	<li>Adding package hyperf/async-queue (~3.1.0)</li>
 	<li>Copying config/autoload/async_queue.php</li>
 	<li>Copying app/Process/AsyncQueueConsumer.php</li>
 	<li>Copying app/Listener/QueueHandleListener.php</li>
 	<li>Copying config/autoload/redis.php

Do you want to use hyperf/amqp component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/model-cache component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/elasticsearch component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/tracer component ? (An open tracing protocol component, adapte with Zipkin etc.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use pestphp/pest component ? (Pest is a testing framework with a focus on simplicity,
meticulously designed to bring back the joy of testing in PHP.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): y</li>
 	<li>Adding package pestphp/pest (^2.34)</li>
 	<li>Copying test/Feature/ExampleTest.php</li>
 	<li>Copying test/Unit/ExampleTest.php</li>
 	<li>Copying test/Pest.php</li>
 	<li>Copying test/TestCase.php
Remove installer
Removing composer.lock from .gitignore
Removing Expressive installer classes, configuration, tests and docs
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

Problem 1
<ul>
 	<li>Root composer.json requires pestphp/pest ^2.34 -&gt; satisfiable by pestphp/pest[v2.34.0, …, 2.x-dev].</li>
 	<li>brianium/paratest[v7.9.0, …, v7.11.2] require php ~8.3.0 || ~8.4.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.12.0, …, 7.x-dev] require php ~8.3.0 || ~8.4.0 || ~8.5.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.4.3, …, v7.5.7] require php ~8.2.0 || ~8.3.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.4.8, …, v7.8.4] require php ~8.2.0 || ~8.3.0 || ~8.4.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>brianium/paratest[v7.8.5, …, 7.8.x-dev] require php ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>pestphp/pest v2.34.0 conflicts with phpunit/phpunit 10.5.63.</li>
 	<li>pestphp/pest v2.34.0 conflicts with phpunit/phpunit 10.5.x-dev.</li>
 	<li>pestphp/pest v2.34.0 requires phpunit/phpunit ^10.5.10 -&gt; satisfiable by phpunit/phpunit[10.5.62, 10.5.63, 10.5.x-dev].</li>
 	<li>pestphp/pest v2.34.3 requires brianium/paratest ^7.4.3 -&gt; satisfiable by brianium/paratest[v7.4.3, …, 7.x-dev].</li>
 	<li>pestphp/pest[v2.36.1, …, 2.x-dev] require php ^8.2.0 -&gt; your php version (8.1.27) does not satisfy that requirement.</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.1 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.2 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.4 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.5 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.6 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.34.9 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.35.0 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.35.1 (conflict analysis result)</li>
 	<li>Conclusion: don't install pestphp/pest v2.36.0 (conflict analysis result)</li>
</ul>
</li>
</ul>
/data/project #


4、报错核心原因如下:
PHP 版本不匹配:容器里的 PHP 是 8.1.27,但 Pest(测试框架)的新版本要求 PHP ≥ 8.2,我的 PHP 8.1 满足不了;
依赖连锁冲突:Pest 依赖的 brianium/paratest、phpunit/phpunit 等组件,也要求更高版本的 PHP,最终导致 Composer 无法解析出一套能安装的依赖包。

5、最快解决方法(放弃安装 Pest,先跑通项目),退出当前失败的安装流程:重新执行创建项目命令(跳过 Pest),选择 n。提示: Project directory “/data/project/hyperf-skeleton” is not empty.。在容器的 /data/project 目录下,执行清空命令:rm -rf ./* ./.??* 。如图2

提示: Project directory "/data/project/hyperf-skeleton" is not empty.。在容器的 /data/project 目录下,执行清空命令:rm -rf ./* ./.??*


/data/project # composer create-project hyperf/hyperf-skeleton
Creating a "hyperf/hyperf-skeleton" project at "./hyperf-skeleton"

In CreateProjectCommand.php line 368:

Project directory "/data/project/hyperf-skeleton" is not empty.

create-project [-s|--stability STABILITY] [--prefer-source] [--prefer-dist] [--prefer-install PREFER-INSTALL] [--repository REPOSITORY] [--repository-url REPOSITORY-URL] [--add-repository] [--dev] [--no-dev] [--no-custom-installers] [--no-scripts] [--no-progress] [--no-secure-http] [--keep-vcs] [--remove-vcs] [--no-install] [--no-audit] [--audit-format AUDIT-FORMAT] [--no-security-blocking] [--ignore-platform-req IGNORE-PLATFORM-REQ] [--ignore-platform-reqs] [--ask] [--] [<package> [<directory> [<version>]]]



6、在容器内创建项目 在 遇见 pestphp/pest 时,选择 n,创建项目成功。



/data/project # composer create-project hyperf/hyperf-skeleton
Creating a "hyperf/hyperf-skeleton" project at "./hyperf-skeleton"
Installing hyperf/hyperf-skeleton (v3.1.3)
<ul>
 	<li>Installing hyperf/hyperf-skeleton (v3.1.3): Extracting archive
Created project in /data/project/hyperf-skeleton</li>
</ul>
<blockquote>@php -r "file_exists('.env') || copy('.env.example', '.env');"
Installer\Script::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies</blockquote>
What time zone do you want to setup ?
[n] Default time zone for php.ini
Make your selection or type a time zone name, like Asia/Shanghai (n):
Asia/Shanghai

Do you want to use Database (MySQL Client) ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y
<ul>
 	<li>Adding package hyperf/database (~3.1.0)</li>
 	<li>Adding package hyperf/db-connection (~3.1.0)

Do you want to use Redis Client ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (yes): y</li>
 	<li>Adding package hyperf/redis (~3.1.0)</li>
 	<li>Copying config/autoload/redis.php

Which RPC protocol do you want to use ?
[1] JSON RPC with Service Governance
[2] JSON RPC
[3] gRPC
[n] None of the above
Make your selection or type a composer package name and version (n): n

Which config center do you want to use ?
[1] Apollo
[2] Aliyun ACM
[3] ETCD
[4] Nacos
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/constants component ?
[y] yes
[n] None of the above
Make your selection (n): y</li>
 	<li>Adding package hyperf/constants (~3.1.0)</li>
 	<li>Copying app/Constants/ErrorCode.php</li>
 	<li>Copying app/Exception/BusinessException.php

Do you want to use hyperf/async-queue component ? (A simple redis queue component)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): y</li>
 	<li>Adding package hyperf/async-queue (~3.1.0)</li>
 	<li>Copying config/autoload/async_queue.php</li>
 	<li>Copying app/Process/AsyncQueueConsumer.php</li>
 	<li>Copying app/Listener/QueueHandleListener.php</li>
 	<li>Copying config/autoload/redis.php

Do you want to use hyperf/amqp component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/model-cache component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/elasticsearch component ?
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use hyperf/tracer component ? (An open tracing protocol component, adapte with Zipkin etc.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n

Do you want to use pestphp/pest component ? (Pest is a testing framework with a focus on simplicity,
meticulously designed to bring back the joy of testing in PHP.)
[y] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n
Remove installer
Removing composer.lock from .gitignore
Removing Expressive installer classes, configuration, tests and docs
Loading composer repositories with package information
Updating dependencies
Lock file operations: 135 installs, 0 updates, 0 removals</li>
 	<li>Locking carbonphp/carbon-doctrine-types (3.2.0)</li>
 	<li>Locking clue/ndjson-react (v1.3.0)</li>
 	<li>Locking composer/pcre (3.3.2)</li>
 	<li>Locking composer/semver (3.4.4)</li>
 	<li>Locking composer/xdebug-handler (3.0.5)</li>
 	<li>Locking doctrine/inflector (2.1.0)</li>
 	<li>Locking doctrine/instantiator (1.5.0)</li>
 	<li>Locking evenement/evenement (v3.0.2)</li>
 	<li>Locking fidry/cpu-core-counter (1.3.0)</li>
 	<li>Locking fig/http-message-util (1.1.5)</li>
 	<li>Locking friendsofphp/php-cs-fixer (v3.94.2)</li>
 	<li>Locking graham-campbell/result-type (v1.1.4)</li>
 	<li>Locking guzzlehttp/guzzle (7.10.0)</li>
 	<li>Locking guzzlehttp/promises (2.3.0)</li>
 	<li>Locking guzzlehttp/psr7 (2.9.0)</li>
 	<li>Locking hamcrest/hamcrest-php (v2.1.1)</li>
 	<li>Locking hyperf/async-queue (v3.1.64)</li>
 	<li>Locking hyperf/cache (v3.1.67)</li>
 	<li>Locking hyperf/code-parser (v3.1.63)</li>
 	<li>Locking hyperf/codec (v3.1.63)</li>
 	<li>Locking hyperf/collection (v3.1.64)</li>
 	<li>Locking hyperf/command (v3.1.64)</li>
 	<li>Locking hyperf/conditionable (v3.1.63)</li>
 	<li>Locking hyperf/config (v3.1.63)</li>
 	<li>Locking hyperf/constants (v3.1.63)</li>
 	<li>Locking hyperf/context (v3.1.63)</li>
 	<li>Locking hyperf/contract (v3.1.63)</li>
 	<li>Locking hyperf/coordinator (v3.1.63)</li>
 	<li>Locking hyperf/coroutine (v3.1.65)</li>
 	<li>Locking hyperf/database (v3.1.67)</li>
 	<li>Locking hyperf/db-connection (v3.1.66)</li>
 	<li>Locking hyperf/devtool (v3.1.66)</li>
 	<li>Locking hyperf/di (v3.1.67)</li>
 	<li>Locking hyperf/dispatcher (v3.1.63)</li>
 	<li>Locking hyperf/engine (v2.15.0)</li>
 	<li>Locking hyperf/engine-contract (v1.14.0)</li>
 	<li>Locking hyperf/event (v3.1.63)</li>
 	<li>Locking hyperf/exception-handler (v3.1.63)</li>
 	<li>Locking hyperf/framework (v3.1.63)</li>
 	<li>Locking hyperf/guzzle (v3.1.66)</li>
 	<li>Locking hyperf/http-message (v3.1.65)</li>
 	<li>Locking hyperf/http-server (v3.1.65)</li>
 	<li>Locking hyperf/laminas-mime (v3.0.0)</li>
 	<li>Locking hyperf/logger (v3.1.63)</li>
 	<li>Locking hyperf/macroable (v3.1.63)</li>
 	<li>Locking hyperf/memory (v3.1.63)</li>
 	<li>Locking hyperf/model-listener (v3.1.63)</li>
 	<li>Locking hyperf/pipeline (v3.1.63)</li>
 	<li>Locking hyperf/pool (v3.1.66)</li>
 	<li>Locking hyperf/process (v3.1.63)</li>
 	<li>Locking hyperf/redis (v3.1.66)</li>
 	<li>Locking hyperf/serializer (v3.1.63)</li>
 	<li>Locking hyperf/server (v3.1.63)</li>
 	<li>Locking hyperf/stdlib (v3.1.63)</li>
 	<li>Locking hyperf/stringable (v3.1.65)</li>
 	<li>Locking hyperf/support (v3.1.65)</li>
 	<li>Locking hyperf/tappable (v3.1.63)</li>
 	<li>Locking hyperf/testing (v3.1.63)</li>
 	<li>Locking laminas/laminas-stdlib (3.20.0)</li>
 	<li>Locking mockery/mockery (1.6.12)</li>
 	<li>Locking monolog/monolog (3.10.0)</li>
 	<li>Locking myclabs/deep-copy (1.13.4)</li>
 	<li>Locking nesbot/carbon (2.73.0)</li>
 	<li>Locking nikic/fast-route (v1.3.0)</li>
 	<li>Locking nikic/php-parser (v4.19.5)</li>
 	<li>Locking phar-io/manifest (2.0.4)</li>
 	<li>Locking phar-io/version (3.2.1)</li>
 	<li>Locking php-di/phpdoc-reader (2.2.1)</li>
 	<li>Locking phpoption/phpoption (1.9.5)</li>
 	<li>Locking phpstan/phpstan (1.12.33)</li>
 	<li>Locking phpunit/php-code-coverage (10.1.16)</li>
 	<li>Locking phpunit/php-file-iterator (4.1.0)</li>
 	<li>Locking phpunit/php-invoker (4.0.0)</li>
 	<li>Locking phpunit/php-text-template (3.0.1)</li>
 	<li>Locking phpunit/php-timer (6.0.0)</li>
 	<li>Locking phpunit/phpunit (10.5.63)</li>
 	<li>Locking psr/clock (1.0.0)</li>
 	<li>Locking psr/container (2.0.2)</li>
 	<li>Locking psr/event-dispatcher (1.0.0)</li>
 	<li>Locking psr/http-client (1.0.3)</li>
 	<li>Locking psr/http-factory (1.1.0)</li>
 	<li>Locking psr/http-message (2.0)</li>
 	<li>Locking psr/http-server-handler (1.0.2)</li>
 	<li>Locking psr/http-server-middleware (1.0.2)</li>
 	<li>Locking psr/log (3.0.2)</li>
 	<li>Locking psr/simple-cache (3.0.0)</li>
 	<li>Locking ralouphie/getallheaders (3.0.3)</li>
 	<li>Locking react/cache (v1.2.0)</li>
 	<li>Locking react/child-process (v0.6.7)</li>
 	<li>Locking react/dns (v1.14.0)</li>
 	<li>Locking react/event-loop (v1.6.0)</li>
 	<li>Locking react/promise (v3.3.0)</li>
 	<li>Locking react/socket (v1.17.0)</li>
 	<li>Locking react/stream (v1.4.0)</li>
 	<li>Locking sebastian/cli-parser (2.0.1)</li>
 	<li>Locking sebastian/code-unit (2.0.0)</li>
 	<li>Locking sebastian/code-unit-reverse-lookup (3.0.0)</li>
 	<li>Locking sebastian/comparator (5.0.5)</li>
 	<li>Locking sebastian/complexity (3.2.0)</li>
 	<li>Locking sebastian/diff (5.1.1)</li>
 	<li>Locking sebastian/environment (6.1.0)</li>
 	<li>Locking sebastian/exporter (5.1.4)</li>
 	<li>Locking sebastian/global-state (6.0.2)</li>
 	<li>Locking sebastian/lines-of-code (2.0.2)</li>
 	<li>Locking sebastian/object-enumerator (5.0.0)</li>
 	<li>Locking sebastian/object-reflector (3.0.0)</li>
 	<li>Locking sebastian/recursion-context (5.0.1)</li>
 	<li>Locking sebastian/type (4.0.0)</li>
 	<li>Locking sebastian/version (4.0.1)</li>
 	<li>Locking swoole/ide-helper (5.1.8)</li>
 	<li>Locking swow/psr7-plus (v1.1.2)</li>
 	<li>Locking symfony/console (v6.4.35)</li>
 	<li>Locking symfony/deprecation-contracts (v3.6.0)</li>
 	<li>Locking symfony/event-dispatcher (v6.4.32)</li>
 	<li>Locking symfony/event-dispatcher-contracts (v3.6.0)</li>
 	<li>Locking symfony/filesystem (v6.4.34)</li>
 	<li>Locking symfony/finder (v6.4.34)</li>
 	<li>Locking symfony/http-foundation (v6.4.35)</li>
 	<li>Locking symfony/options-resolver (v6.4.30)</li>
 	<li>Locking symfony/polyfill-ctype (v1.33.0)</li>
 	<li>Locking symfony/polyfill-intl-grapheme (v1.33.0)</li>
 	<li>Locking symfony/polyfill-intl-normalizer (v1.33.0)</li>
 	<li>Locking symfony/polyfill-mbstring (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php80 (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php81 (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php83 (v1.33.0)</li>
 	<li>Locking symfony/polyfill-php84 (v1.33.0)</li>
 	<li>Locking symfony/process (v6.4.33)</li>
 	<li>Locking symfony/service-contracts (v3.6.1)</li>
 	<li>Locking symfony/stopwatch (v6.4.24)</li>
 	<li>Locking symfony/string (v6.4.34)</li>
 	<li>Locking symfony/translation (v6.4.34)</li>
 	<li>Locking symfony/translation-contracts (v3.6.1)</li>
 	<li>Locking theseer/tokenizer (1.3.1)</li>
 	<li>Locking vlucas/phpdotenv (v5.6.3)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 135 installs, 0 updates, 0 removals</li>
 	<li>Downloading composer/pcre (3.3.2)</li>
 	<li>Downloading doctrine/inflector (2.1.0)</li>
 	<li>Downloading doctrine/instantiator (1.5.0)</li>
 	<li>Downloading symfony/deprecation-contracts (v3.6.0)</li>
 	<li>Downloading psr/container (2.0.2)</li>
 	<li>Downloading symfony/service-contracts (v3.6.1)</li>
 	<li>Downloading symfony/stopwatch (v6.4.24)</li>
 	<li>Downloading symfony/process (v6.4.33)</li>
 	<li>Downloading symfony/polyfill-php84 (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-php81 (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-php80 (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-mbstring (v1.33.0)</li>
 	<li>Downloading symfony/options-resolver (v6.4.30)</li>
 	<li>Downloading symfony/finder (v6.4.34)</li>
 	<li>Downloading symfony/polyfill-ctype (v1.33.0)</li>
 	<li>Downloading symfony/filesystem (v6.4.34)</li>
 	<li>Downloading psr/event-dispatcher (1.0.0)</li>
 	<li>Downloading symfony/event-dispatcher-contracts (v3.6.0)</li>
 	<li>Downloading symfony/event-dispatcher (v6.4.32)</li>
 	<li>Downloading symfony/polyfill-intl-normalizer (v1.33.0)</li>
 	<li>Downloading symfony/polyfill-intl-grapheme (v1.33.0)</li>
 	<li>Downloading symfony/string (v6.4.34)</li>
 	<li>Downloading symfony/console (v6.4.35)</li>
 	<li>Downloading sebastian/diff (5.1.1)</li>
 	<li>Downloading react/event-loop (v1.6.0)</li>
 	<li>Downloading evenement/evenement (v3.0.2)</li>
 	<li>Downloading react/stream (v1.4.0)</li>
 	<li>Downloading react/promise (v3.3.0)</li>
 	<li>Downloading react/cache (v1.2.0)</li>
 	<li>Downloading react/dns (v1.14.0)</li>
 	<li>Downloading react/socket (v1.17.0)</li>
 	<li>Downloading react/child-process (v0.6.7)</li>
 	<li>Downloading fidry/cpu-core-counter (1.3.0)</li>
 	<li>Downloading psr/log (3.0.2)</li>
 	<li>Downloading composer/xdebug-handler (3.0.5)</li>
 	<li>Downloading composer/semver (3.4.4)</li>
 	<li>Downloading clue/ndjson-react (v1.3.0)</li>
 	<li>Downloading friendsofphp/php-cs-fixer (v3.94.2)</li>
 	<li>Downloading guzzlehttp/promises (2.3.0)</li>
 	<li>Downloading ralouphie/getallheaders (3.0.3)</li>
 	<li>Downloading psr/http-message (2.0)</li>
 	<li>Downloading psr/http-factory (1.1.0)</li>
 	<li>Downloading guzzlehttp/psr7 (2.9.0)</li>
 	<li>Downloading hyperf/tappable (v3.1.63)</li>
 	<li>Downloading hyperf/macroable (v3.1.63)</li>
 	<li>Downloading hyperf/conditionable (v3.1.63)</li>
 	<li>Downloading hyperf/stringable (v3.1.65)</li>
 	<li>Downloading hyperf/contract (v3.1.63)</li>
 	<li>Downloading hyperf/collection (v3.1.64)</li>
 	<li>Downloading hyperf/engine-contract (v1.14.0)</li>
 	<li>Downloading hyperf/engine (v2.15.0)</li>
 	<li>Downloading hyperf/context (v3.1.63)</li>
 	<li>Downloading hyperf/coroutine (v3.1.65)</li>
 	<li>Downloading hyperf/support (v3.1.65)</li>
 	<li>Downloading phpoption/phpoption (1.9.5)</li>
 	<li>Downloading graham-campbell/result-type (v1.1.4)</li>
 	<li>Downloading vlucas/phpdotenv (v5.6.3)</li>
 	<li>Downloading php-di/phpdoc-reader (2.2.1)</li>
 	<li>Downloading nikic/php-parser (v4.19.5)</li>
 	<li>Downloading hyperf/stdlib (v3.1.63)</li>
 	<li>Downloading hyperf/pipeline (v3.1.63)</li>
 	<li>Downloading hyperf/code-parser (v3.1.63)</li>
 	<li>Downloading hyperf/di (v3.1.67)</li>
 	<li>Downloading hyperf/coordinator (v3.1.63)</li>
 	<li>Downloading hyperf/command (v3.1.64)</li>
 	<li>Downloading hyperf/codec (v3.1.63)</li>
 	<li>Downloading hyperf/async-queue (v3.1.64)</li>
 	<li>Downloading psr/simple-cache (3.0.0)</li>
 	<li>Downloading hyperf/cache (v3.1.67)</li>
 	<li>Downloading hyperf/config (v3.1.63)</li>
 	<li>Downloading hyperf/constants (v3.1.63)</li>
 	<li>Downloading hyperf/pool (v3.1.66)</li>
 	<li>Downloading hyperf/event (v3.1.63)</li>
 	<li>Downloading symfony/translation-contracts (v3.6.1)</li>
 	<li>Downloading symfony/translation (v6.4.34)</li>
 	<li>Downloading psr/clock (1.0.0)</li>
 	<li>Downloading carbonphp/carbon-doctrine-types (3.2.0)</li>
 	<li>Downloading nesbot/carbon (2.73.0)</li>
 	<li>Downloading hyperf/database (v3.1.67)</li>
 	<li>Downloading hyperf/model-listener (v3.1.63)</li>
 	<li>Downloading fig/http-message-util (1.1.5)</li>
 	<li>Downloading hyperf/framework (v3.1.63)</li>
 	<li>Downloading hyperf/db-connection (v3.1.66)</li>
 	<li>Downloading hyperf/devtool (v3.1.66)</li>
 	<li>Downloading psr/http-client (1.0.3)</li>
 	<li>Downloading swow/psr7-plus (v1.1.2)</li>
 	<li>Downloading laminas/laminas-stdlib (3.20.0)</li>
 	<li>Downloading hyperf/laminas-mime (v3.0.0)</li>
 	<li>Downloading hyperf/http-message (v3.1.65)</li>
 	<li>Downloading psr/http-server-handler (1.0.2)</li>
 	<li>Downloading psr/http-server-middleware (1.0.2)</li>
 	<li>Downloading hyperf/dispatcher (v3.1.63)</li>
 	<li>Downloading hyperf/exception-handler (v3.1.63)</li>
 	<li>Downloading guzzlehttp/guzzle (7.10.0)</li>
 	<li>Downloading hyperf/guzzle (v3.1.66)</li>
 	<li>Downloading monolog/monolog (3.10.0)</li>
 	<li>Downloading hyperf/logger (v3.1.63)</li>
 	<li>Downloading hyperf/memory (v3.1.63)</li>
 	<li>Downloading hyperf/process (v3.1.63)</li>
 	<li>Downloading hyperf/redis (v3.1.66)</li>
 	<li>Downloading hyperf/serializer (v3.1.63)</li>
 	<li>Downloading hyperf/server (v3.1.63)</li>
 	<li>Downloading symfony/polyfill-php83 (v1.33.0)</li>
 	<li>Downloading symfony/http-foundation (v6.4.35)</li>
 	<li>Downloading sebastian/version (4.0.1)</li>
 	<li>Downloading sebastian/type (4.0.0)</li>
 	<li>Downloading sebastian/recursion-context (5.0.1)</li>
 	<li>Downloading sebastian/object-reflector (3.0.0)</li>
 	<li>Downloading sebastian/object-enumerator (5.0.0)</li>
 	<li>Downloading sebastian/global-state (6.0.2)</li>
 	<li>Downloading sebastian/exporter (5.1.4)</li>
 	<li>Downloading sebastian/environment (6.1.0)</li>
 	<li>Downloading sebastian/comparator (5.0.5)</li>
 	<li>Downloading sebastian/code-unit (2.0.0)</li>
 	<li>Downloading sebastian/cli-parser (2.0.1)</li>
 	<li>Downloading phpunit/php-timer (6.0.0)</li>
 	<li>Downloading phpunit/php-text-template (3.0.1)</li>
 	<li>Downloading phpunit/php-invoker (4.0.0)</li>
 	<li>Downloading phpunit/php-file-iterator (4.1.0)</li>
 	<li>Downloading theseer/tokenizer (1.3.1)</li>
 	<li>Downloading sebastian/lines-of-code (2.0.2)</li>
 	<li>Downloading sebastian/complexity (3.2.0)</li>
 	<li>Downloading sebastian/code-unit-reverse-lookup (3.0.0)</li>
 	<li>Downloading phpunit/php-code-coverage (10.1.16)</li>
 	<li>Downloading phar-io/version (3.2.1)</li>
 	<li>Downloading phar-io/manifest (2.0.4)</li>
 	<li>Downloading myclabs/deep-copy (1.13.4)</li>
 	<li>Downloading phpunit/phpunit (10.5.63)</li>
 	<li>Downloading nikic/fast-route (v1.3.0)</li>
 	<li>Downloading hyperf/http-server (v3.1.65)</li>
 	<li>Downloading hyperf/testing (v3.1.63)</li>
 	<li>Downloading hamcrest/hamcrest-php (v2.1.1)</li>
 	<li>Downloading mockery/mockery (1.6.12)</li>
 	<li>Downloading phpstan/phpstan (1.12.33)</li>
 	<li>Downloading swoole/ide-helper (5.1.8)</li>
 	<li>Installing composer/pcre (3.3.2): Extracting archive</li>
 	<li>Installing doctrine/inflector (2.1.0): Extracting archive</li>
 	<li>Installing doctrine/instantiator (1.5.0): Extracting archive</li>
 	<li>Installing symfony/deprecation-contracts (v3.6.0): Extracting archive</li>
 	<li>Installing psr/container (2.0.2): Extracting archive</li>
 	<li>Installing symfony/service-contracts (v3.6.1): Extracting archive</li>
 	<li>Installing symfony/stopwatch (v6.4.24): Extracting archive</li>
 	<li>Installing symfony/process (v6.4.33): Extracting archive</li>
 	<li>Installing symfony/polyfill-php84 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-php81 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-php80 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-mbstring (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/options-resolver (v6.4.30): Extracting archive</li>
 	<li>Installing symfony/finder (v6.4.34): Extracting archive</li>
 	<li>Installing symfony/polyfill-ctype (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/filesystem (v6.4.34): Extracting archive</li>
 	<li>Installing psr/event-dispatcher (1.0.0): Extracting archive</li>
 	<li>Installing symfony/event-dispatcher-contracts (v3.6.0): Extracting archive</li>
 	<li>Installing symfony/event-dispatcher (v6.4.32): Extracting archive</li>
 	<li>Installing symfony/polyfill-intl-normalizer (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/polyfill-intl-grapheme (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/string (v6.4.34): Extracting archive</li>
 	<li>Installing symfony/console (v6.4.35): Extracting archive</li>
 	<li>Installing sebastian/diff (5.1.1): Extracting archive</li>
 	<li>Installing react/event-loop (v1.6.0): Extracting archive</li>
 	<li>Installing evenement/evenement (v3.0.2): Extracting archive</li>
 	<li>Installing react/stream (v1.4.0): Extracting archive</li>
 	<li>Installing react/promise (v3.3.0): Extracting archive</li>
 	<li>Installing react/cache (v1.2.0): Extracting archive</li>
 	<li>Installing react/dns (v1.14.0): Extracting archive</li>
 	<li>Installing react/socket (v1.17.0): Extracting archive</li>
 	<li>Installing react/child-process (v0.6.7): Extracting archive</li>
 	<li>Installing fidry/cpu-core-counter (1.3.0): Extracting archive</li>
 	<li>Installing psr/log (3.0.2): Extracting archive</li>
 	<li>Installing composer/xdebug-handler (3.0.5): Extracting archive</li>
 	<li>Installing composer/semver (3.4.4): Extracting archive</li>
 	<li>Installing clue/ndjson-react (v1.3.0): Extracting archive</li>
 	<li>Installing friendsofphp/php-cs-fixer (v3.94.2): Extracting archive</li>
 	<li>Installing guzzlehttp/promises (2.3.0): Extracting archive</li>
 	<li>Installing ralouphie/getallheaders (3.0.3): Extracting archive</li>
 	<li>Installing psr/http-message (2.0): Extracting archive</li>
 	<li>Installing psr/http-factory (1.1.0): Extracting archive</li>
 	<li>Installing guzzlehttp/psr7 (2.9.0): Extracting archive</li>
 	<li>Installing hyperf/tappable (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/macroable (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/conditionable (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/stringable (v3.1.65): Extracting archive</li>
 	<li>Installing hyperf/contract (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/collection (v3.1.64): Extracting archive</li>
 	<li>Installing hyperf/engine-contract (v1.14.0): Extracting archive</li>
 	<li>Installing hyperf/engine (v2.15.0): Extracting archive</li>
 	<li>Installing hyperf/context (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/coroutine (v3.1.65): Extracting archive</li>
 	<li>Installing hyperf/support (v3.1.65): Extracting archive</li>
 	<li>Installing phpoption/phpoption (1.9.5): Extracting archive</li>
 	<li>Installing graham-campbell/result-type (v1.1.4): Extracting archive</li>
 	<li>Installing vlucas/phpdotenv (v5.6.3): Extracting archive</li>
 	<li>Installing php-di/phpdoc-reader (2.2.1): Extracting archive</li>
 	<li>Installing nikic/php-parser (v4.19.5): Extracting archive</li>
 	<li>Installing hyperf/stdlib (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/pipeline (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/code-parser (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/di (v3.1.67): Extracting archive</li>
 	<li>Installing hyperf/coordinator (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/command (v3.1.64): Extracting archive</li>
 	<li>Installing hyperf/codec (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/async-queue (v3.1.64): Extracting archive</li>
 	<li>Installing psr/simple-cache (3.0.0): Extracting archive</li>
 	<li>Installing hyperf/cache (v3.1.67): Extracting archive</li>
 	<li>Installing hyperf/config (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/constants (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/pool (v3.1.66): Extracting archive</li>
 	<li>Installing hyperf/event (v3.1.63): Extracting archive</li>
 	<li>Installing symfony/translation-contracts (v3.6.1): Extracting archive</li>
 	<li>Installing symfony/translation (v6.4.34): Extracting archive</li>
 	<li>Installing psr/clock (1.0.0): Extracting archive</li>
 	<li>Installing carbonphp/carbon-doctrine-types (3.2.0): Extracting archive</li>
 	<li>Installing nesbot/carbon (2.73.0): Extracting archive</li>
 	<li>Installing hyperf/database (v3.1.67): Extracting archive</li>
 	<li>Installing hyperf/model-listener (v3.1.63): Extracting archive</li>
 	<li>Installing fig/http-message-util (1.1.5): Extracting archive</li>
 	<li>Installing hyperf/framework (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/db-connection (v3.1.66): Extracting archive</li>
 	<li>Installing hyperf/devtool (v3.1.66): Extracting archive</li>
 	<li>Installing psr/http-client (1.0.3): Extracting archive</li>
 	<li>Installing swow/psr7-plus (v1.1.2): Extracting archive</li>
 	<li>Installing laminas/laminas-stdlib (3.20.0): Extracting archive</li>
 	<li>Installing hyperf/laminas-mime (v3.0.0): Extracting archive</li>
 	<li>Installing hyperf/http-message (v3.1.65): Extracting archive</li>
 	<li>Installing psr/http-server-handler (1.0.2): Extracting archive</li>
 	<li>Installing psr/http-server-middleware (1.0.2): Extracting archive</li>
 	<li>Installing hyperf/dispatcher (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/exception-handler (v3.1.63): Extracting archive</li>
 	<li>Installing guzzlehttp/guzzle (7.10.0): Extracting archive</li>
 	<li>Installing hyperf/guzzle (v3.1.66): Extracting archive</li>
 	<li>Installing monolog/monolog (3.10.0): Extracting archive</li>
 	<li>Installing hyperf/logger (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/memory (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/process (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/redis (v3.1.66): Extracting archive</li>
 	<li>Installing hyperf/serializer (v3.1.63): Extracting archive</li>
 	<li>Installing hyperf/server (v3.1.63): Extracting archive</li>
 	<li>Installing symfony/polyfill-php83 (v1.33.0): Extracting archive</li>
 	<li>Installing symfony/http-foundation (v6.4.35): Extracting archive</li>
 	<li>Installing sebastian/version (4.0.1): Extracting archive</li>
 	<li>Installing sebastian/type (4.0.0): Extracting archive</li>
 	<li>Installing sebastian/recursion-context (5.0.1): Extracting archive</li>
 	<li>Installing sebastian/object-reflector (3.0.0): Extracting archive</li>
 	<li>Installing sebastian/object-enumerator (5.0.0): Extracting archive</li>
 	<li>Installing sebastian/global-state (6.0.2): Extracting archive</li>
 	<li>Installing sebastian/exporter (5.1.4): Extracting archive</li>
 	<li>Installing sebastian/environment (6.1.0): Extracting archive</li>
 	<li>Installing sebastian/comparator (5.0.5): Extracting archive</li>
 	<li>Installing sebastian/code-unit (2.0.0): Extracting archive</li>
 	<li>Installing sebastian/cli-parser (2.0.1): Extracting archive</li>
 	<li>Installing phpunit/php-timer (6.0.0): Extracting archive</li>
 	<li>Installing phpunit/php-text-template (3.0.1): Extracting archive</li>
 	<li>Installing phpunit/php-invoker (4.0.0): Extracting archive</li>
 	<li>Installing phpunit/php-file-iterator (4.1.0): Extracting archive</li>
 	<li>Installing theseer/tokenizer (1.3.1): Extracting archive</li>
 	<li>Installing sebastian/lines-of-code (2.0.2): Extracting archive</li>
 	<li>Installing sebastian/complexity (3.2.0): Extracting archive</li>
 	<li>Installing sebastian/code-unit-reverse-lookup (3.0.0): Extracting archive</li>
 	<li>Installing phpunit/php-code-coverage (10.1.16): Extracting archive</li>
 	<li>Installing phar-io/version (3.2.1): Extracting archive</li>
 	<li>Installing phar-io/manifest (2.0.4): Extracting archive</li>
 	<li>Installing myclabs/deep-copy (1.13.4): Extracting archive</li>
 	<li>Installing phpunit/phpunit (10.5.63): Extracting archive</li>
 	<li>Installing nikic/fast-route (v1.3.0): Extracting archive</li>
 	<li>Installing hyperf/http-server (v3.1.65): Extracting archive</li>
 	<li>Installing hyperf/testing (v3.1.63): Extracting archive</li>
 	<li>Installing hamcrest/hamcrest-php (v2.1.1): Extracting archive</li>
 	<li>Installing mockery/mockery (1.6.12): Extracting archive</li>
 	<li>Installing phpstan/phpstan (1.12.33): Extracting archive</li>
 	<li>Installing swoole/ide-helper (5.1.8): Extracting archive
27 package suggestions were added by new dependencies, use <code>composer suggest</code> to see details.
Generating optimized autoload files</li>
</ul>
<blockquote>rm -rf runtime/container
114 packages you are using are looking for funding.
Use the <code>composer fund</code> command to find out more!
No security vulnerability advisories found.
/data/project #


]]>
https://www.shuijingwanwq.com/2026/03/20/9355/feed/ 0
在 Laravel 6 中,在队列执行过程中,一些视图文件未执行的排查分析 https://www.shuijingwanwq.com/2023/12/19/8288/ https://www.shuijingwanwq.com/2023/12/19/8288/#respond Tue, 19 Dec 2023 03:17:28 +0000 https://www.shuijingwanwq.com/?p=8288 浏览量: 81 1、参考:在 Laravel 6 中,在队列执行过程中,每一个任务的执行,皆会执行 View::addLocation($location);,然而每一个任务皆只会取第 1 个任务的 $location 。但是发现后续在生产环境中仍然存在问题。在队列执行过程中,一些视图文件未执行(”setting_migrations”:[])。如图1
在队列执行过程中,一些视图文件未执行("setting_migrations":[])

图1



INSERT INTO "" ("source_db", "store_name", "id", "theme_installation_id", "theme_installation_version_preset_id", "from_version", "to_version", "processing", "processing_failed", "step", "failed_message", "extra", "created_at", "updated_at") VALUES ('aws_db12', 'buglcexk30', 5, 5, 5, 'v2.11.1', 'v3.4.0', 0, 0, 7, '', '{"setting_migrations":[],"theme_download_paths":{"zip_path":"/theme_downloads/2023/11/07/1699423025.8743.1229090882.zip","destination":"/theme_downloads/2023/11/07/1699423025.8743.1229090882"}}', '2023-11-08 05:57:02', '2023-11-08 05:57:13');
INSERT INTO "" ("source_db", "store_name", "id", "theme_installation_id", "theme_installation_version_preset_id", "from_version", "to_version", "processing", "processing_failed", "step", "failed_message", "extra", "created_at", "updated_at") VALUES ('aws_db18', 'carver10', 7, 7, 7, 'v2.11.1', 'v3.4.0', 0, 0, 7, '', '{"setting_migrations":[{"file":"v3.0.0/migrate_product_detail.php","exec_at":"2023-11-08 05:57:11"},{"file":"2023_07_11_10_custom_mobile_layout/migrate_product_detail.php","exec_at":"2023-11-08 05:57:11"}],"theme_download_paths":{"zip_path":"/theme_downloads/2023/11/07/1699423022.7951.958836417.zip","destination":"/theme_downloads/2023/11/07/1699423022.7951.958836417"}}', '2023-11-08 05:57:01', '2023-11-08 05:57:11');
INSERT INTO "" ("source_db", "store_name", "id", "theme_installation_id", "theme_installation_version_preset_id", "from_version", "to_version", "processing", "processing_failed", "step", "failed_message", "extra", "created_at", "updated_at") VALUES ('aws_db3', 'cisfioadre59', 8, 8, 8, 'v2.11.1', 'v3.4.0', 0, 0, 7, '', '{"setting_migrations":[],"theme_download_paths":{"zip_path":"/theme_downloads/2023/11/07/1699423022.7315.1637916782.zip","destination":"/theme_downloads/2023/11/07/1699423022.7315.1637916782"}}', '2023-11-08 05:57:01', '2023-11-08 05:57:11');


2、由于在测试环境一直未复现,最后决定尽量模拟生产环境的部署方式。从单机部署为集群,在 Raccher 的工作负载中,点击 Pod 可用副本数 右侧的 +,添加一个 Pod。尝试复现此缺陷。如图2
由于在测试环境一直未复现,最后决定尽量模拟生产环境的部署方式。从单机部署为集群,在 Raccher 的工作负载中,点击 Pod 可用副本数 右侧的 +,添加一个 Pod。尝试复现此缺陷

图2

3、最后发现原因在于队列服务器为集群模式,在集群模式下,队列任务之间存在一定的依赖关系被破坏。我举例说明一下,在 A 机器上执行了队列 InstallThemeToDb ,那么在这台机器上存在解压缩后的主题包文件。但是在队列 InstallThemeToDb执行完成后,会触发下一个队列 MigrateThemeSettings 的执行,但是这个队列可能在 B 机器 上执行了。此时,这个队列的执行依赖于之前解压缩后的主题包文件,可是 ,B 机器上不存在。进而导致主题迁移文件未执行到。 4、现在存在3种解决方案: (1)将 2 个 Job 合并为 1 个; (2)想办法强制让两个 job 在同一台机器上执行; (3)不同的机器共享一个存储,然后解压缩的主题包文件都放在共享存储上。这种方案要保证没有时间上的延迟才行了; 5、最终决定采用第 2 个方案:想办法强制让两个 job 在同一台机器上执行。如果您想立即(同步)执行队列任务,可以使用 dispatchNow 方法。使用此方法时,队列任务将不会排队,并立即在当前进程中运行。


MigrateThemeSettings::dispatchNow($this->themeInstallationTask);


6、当在 队列 MigrateThemeSettings 中抛出异常时,并未执行 MigrateThemeSettings 中的 failed 方法,而是执行的 InstallThemeToDb 中的 failed 方法。符合预期。如图3
当在 队列 MigrateThemeSettings 中抛出异常时,并未执行 MigrateThemeSettings 中的 failed 方法,而是执行的 InstallThemeToDb 中的 failed 方法。符合预期

图3

7、当在 队列 MigrateThemeSettings 中查找 解压缩后的主题包文件 时,不再出现找不到的情况,符合预期。]]>
https://www.shuijingwanwq.com/2023/12/19/8288/feed/ 0