WSL2 Docker环境下Laravel Sail路径指向异常如何处理
WSL2下Laravel Sail路径助手返回容器路径导致文件上传异常
问题表现
WSL2环境中通过./vendor/bin/sail up启动Laravel项目时,public_path()、storage_path()等路径助手函数返回容器内路径,而非宿主机原始项目目录,导致文件上传功能异常。
路由中打印路径的测试代码:
Route::get('/', function () { dump(public_path()); dump(storage_path()); });
Web访问返回结果:
^ "/var/www/html/public" ^ "/var/www/html/storage"
排查过程
- 新建全新Laravel项目测试路径返回值
- 在其他设备复现测试
- WSL2命令行直接执行
php artisan storage:link,软链指向宿主机路径:
$ php artisan storage:link The [/home/ahming/example-app/public/storage] link has been connected to [/home/ahming/example-app/storage/app/public]. The links have been created.
- WSL2命令行直接执行
php artisan tinker,路径返回宿主机路径:
$ php artisan tinker Psy Shell v0.11.5 (PHP 8.1.7 - cli) by Justin Hileman >>> public_path() => "/home/ahming/example-app/public"
php artisan serve启动服务时路径返回正常,确认问题与Docker环境相关- 通过sail执行tinker时路径返回容器内路径,与web访问结果一致:
$ ./vendor/bin/sail artisan tinker Psy Shell v0.11.5 (PHP 8.1.7 — cli) by Justin Hileman >>> public_path() => "/var/www/html/public"
当前使用的docker-compose.yml配置:
# For more information: https://laravel.com/docs/sail version: '3' services: laravel.test: build: context: ./vendor/laravel/sail/runtimes/8.1 dockerfile: Dockerfile args: WWWGROUP: '${WWWGROUP}' image: sail-8.1/app extra_hosts: - 'host.docker.internal:host-gateway' ports: - '${APP_PORT:-80}:80' - '${HMR_PORT:-8080}:8080' environment: WWWUSER: '${WWWUSER}' LARAVEL_SAIL: 1 XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' volumes: - '.:/var/www/html' networks: - sail depends_on: - mysql mysql: image: 'mysql/mysql-server:8.0' ports: - '${FORWARD_DB_PORT:-3306}:3306' environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' MYSQL_ROOT_HOST: "%" MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 volumes: - 'sail-mysql:/var/lib/mysql' - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' networks: - sail healthcheck: test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] retries: 3 timeout: 5s phpmyadmin: image: 'phpmyadmin/phpmyadmin' links: - mysql:mysql ports: - '8000:80' environment: MYSQL_USERNAME: "${DB_USERNAME}" MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}" PMA_HOST: mysql networks: - sail networks: sail: driver: bridge volumes: sail-mysql: driver: local
问题根因
路径返回/var/www/html是Sail容器环境的正常表现,不是错误。
Sail的容器通过volume把宿主机项目目录挂载到容器内的/var/www/html路径,容器内运行的PHP(包括web请求、sail执行的artisan命令)识别到的项目根目录自然是容器内的挂载路径。
真正导致功能异常的是操作环境不统一:在WSL宿主机环境执行了storage:link命令,生成的软链指向宿主机的绝对路径,容器内的PHP进程无法识别这个路径对应的真实目录,才会出现文件访问、上传失败的问题。
解决方法
所有项目相关的artisan、composer、npm操作都统一通过sail在容器内执行,不要在WSL宿主机直接执行项目内的脚本命令:
- 先删除之前在宿主机生成的无效软链,直接删除项目下
public/storage文件即可 - 进入WSL的项目根目录,执行容器内的软链生成命令:
./vendor/bin/sail artisan storage:link
- 后续所有artisan操作都加sail前缀执行,比如:
# 清除配置缓存 ./vendor/bin/sail artisan config:clear # 执行数据库迁移 ./vendor/bin/sail artisan migrate # 进入tinker ./vendor/bin/sail artisan tinker
补充:容器内的
/var/www/html路径和宿主机项目目录是双向绑定的,容器内对文件的修改会实时同步到宿主机,不存在文件隔离的问题。路径助手返回容器内路径不会影响正常的web访问、文件存储逻辑,只要所有操作都在容器环境内执行,就不会出现路径不一致的问题。
内容的提问来源于stack exchange,提问作者AhMing
相关产品推荐
相关产品推荐

