Laravel 在 Docker 環境下訪問 storage 靜態資源 404 問題解決

oneSmile發表於2020-03-26

最近在學習使用docker編排laravel執行環境,遇到了在容器部署專案無法訪問靜態資源的問題,最終得以解決,在這裡記錄一下

問題復現

在專案storage/app/public目錄下有一張圖片img.png:

Laravel在Docker環境下訪問storage靜態資源404問題解決

並且已經在容器中執行php artisan storage:link來建立了軟連結:

Laravel在Docker環境下訪問storage靜態資源404問題解決

然後開啟瀏覽器,訪問localhost/storage/img.png,結果返回404…

Laravel在Docker環境下訪問storage靜態資源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.dockerfilevhost.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,結果都不行。

然後以為是路徑問題,嘗試了使用相對路徑的軟連結,結果不出意料,還是不行?

Laravel在Docker環境下訪問storage靜態資源404問題解決

然而在容器外使用valet或者php artisan serve都是可以成功請求圖片的?

Laravel在Docker環境下訪問storage靜態資源404問題解決

我還以為是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

重新構建,然後訪問

Laravel在Docker環境下訪問storage靜態資源404問題解決

真是太感動了?原來就是資料卷對映的問題

不過還有個值得注意的點,現在是可以訪問了,但是此時在public目錄下的storage軟連結是相對路徑../storage/app/public。經過測試,相對路徑的軟連結在容器內外都生效,而使用php artisan storage:link所建立的軟連結是絕對路徑,而docker容器內的目錄是和宿主機不同的,這就導致了在哪種環境下執行的storage:link命令,就只能在哪種環境下生效

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章