最近在學習使用docker編排laravel執行環境,遇到了在容器部署專案無法訪問靜態資源的問題,最終得以解決,在這裡記錄一下
問題復現
在專案storage/app/public
目錄下有一張圖片img.png
:
並且已經在容器中執行php artisan storage:link
來建立了軟連結:
然後開啟瀏覽器,訪問localhost/storage/img.png
,結果返回404…
在這裡貼一下我的docker-compose.yml
檔案內容:
version: '3.7'
services:
app:
build:
context: ./docker
dockerfile: app.dockerfile
working_dir: /var/www
volumes:
- ./:/var/www:cached
environment:
- DB_CONNECTION=mysql
- DB_HOST=database
- DB_PORT=3306
- DB_DATABASE=iartisan
- DB_USERNAME=root
- DB_PASSWORD=123456
- REDIS_HOST=redis
- REDIS_PORT=6379
database:
build:
context: ./docker
dockerfile: database.dockerfile
restart: always
volumes:
- mysql_data:/var/lib/mysql:rw
- mysql_log:/var/log/mysql:rw
- mysql_config:/etc/mysql:rw
environment:
- MYSQL_ROOT_PASSWORD=$DB_PASSWORD
redis:
image: redis:5
proxy:
build:
context: ./docker
dockerfile: nginx.dockerfile
working_dir: /var/www
volumes:
- nginx_conf:/etc/nginx/conf.d:cached
- ./public:/var/www/public:cached
ports:
- 80:80
volumes:
mysql_data:
mysql_log:
mysql_config:
nginx_conf:
name: nginx_conf
networks:
default:
driver: bridge
app.dockerfile
檔案:
FROM php:7.4-fpm
COPY ./composer-setup.sh /
RUN apt-get clean \
&& cd /var/lib/apt \
&& mv lists lists.old \
&& mkdir -p lists/partial \
&& apt-get clean \
&& echo "deb http://mirrors.aliyun.com/debian/ buster main non-free contrib \n \
deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib \n \
deb http://mirrors.aliyun.com/debian-security buster/updates main \n \
deb-src http://mirrors.aliyun.com/debian-security buster/updates main \n \
deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib \n \
deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib" > /etc/apt/sources.list \
# 更新及安裝庫
&& apt-get update \
&& apt-get install -y libmagickwand-dev libmcrypt-dev libpq-dev libzip-dev zip \
# PHP擴充套件安裝
&& docker-php-ext-install -j$(nproc) pdo_mysql bcmath \
&& pecl install redis imagick mcrypt zip \
&& docker-php-ext-enable redis imagick mcrypt zip
nginx.dockerfile
和vhost.conf
檔案內容:
FROM nginx
COPY ./vhost.conf /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name 127.0.0.1;
index index.php index.html;
root /var/www/public;
error_log /var/log/nginx/error.log notice;
access_log /var/log/nginx/access.log main;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
解決流程
起初嘗試了docker 部署 Laravel,無法訪問 storage 目錄中的 檔案這個帖子中評論的解決方案,以為是目錄許可權問題,嘗試了給public/storage
切換到www-data
使用者或者許可權0777,結果都不行。
然後以為是路徑問題,嘗試了使用相對路徑的軟連結,結果不出意料,還是不行?
然而在容器外使用valet
或者php artisan serve
都是可以成功請求圖片的?
我還以為是nginx的問題,最後搞得我想用OSS來替代本地儲存了,最後看到了這篇問題:
Dockerized Laravel App, always 404 on assets
發現可能是資料卷的對映問題,然後修改了docker-compose.yml
的資料卷對映配置為對映專案根目錄:
volumes:
- nginx_conf:/etc/nginx/conf.d:cached
# - ./public:/var/www/public:cached
- ./:/var/www:cached
重新構建,然後訪問
真是太感動了?原來就是資料卷對映的問題
不過還有個值得注意的點,現在是可以訪問了,但是此時在
public
目錄下的storage
軟連結是相對路徑../storage/app/public
。經過測試,相對路徑的軟連結在容器內外都生效,而使用php artisan storage:link
所建立的軟連結是絕對路徑,而docker容器內的目錄是和宿主機不同的,這就導致了在哪種環境下執行的storage:link
命令,就只能在哪種環境下生效
本作品採用《CC 協議》,轉載必須註明作者和本文連結