在Nginx容器wsl2上运行Laravel时,Docker非常慢

dvtswwa3  于 2023-06-29  发布在  Docker
关注(0)|答案(9)|浏览(214)

我已经更新了Windows 10到2004最新版本,安装了wsl 2并更新了它,安装了docker和ubuntu。
当我用“Hello World”创建一个简单的 * index.php * 文件时,它工作得很好(响应:100- 400 ms),但是当我添加我的 Laravel 项目时,它变得很糟糕,因为它在执行请求之前加载了7秒,并且响应是4 - 7秒😢,即使 PHPMyAdmin 运行得非常顺利(响应:1 - 2秒)。
我的docker-compose.yml文件:

version: '3.8'
networks:
  laravel:

services:
  nginx:
    image: nginx:stable-alpine
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
      - mysql
      - phpmyadmin
    networks:
      - laravel

  mysql:
    image: mysql:latest
    container_name: mysql
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: secret
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    networks:
      - laravel

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    restart: always
    depends_on:
      - mysql
    ports:
      - 8081:80
    environment:
      PMA_HOST: mysql
      PMA_ARBITRARY: 1

  php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php
    volumes:
      - ./src:/var/www/html
    ports:
      - "9000:9000"
    networks:
      - laravel

  composer:
    image: composer:latest
    container_name: composer
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
    depends_on:
      - php
    networks:
      - laravel

  npm:
    image: node:latest
    container_name: npm
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
    entrypoint: ['npm']

  artisan:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: artisan
    volumes:
      - ./src:/var/www/html
    depends_on:
      - mysql
    working_dir: /var/www/html
    entrypoint: ['php', '/var/www/html/artisan']
    networks:
      - laravel

我一直在试图解决这个问题2天,但找不到答案。
谢谢

gwo2fgha

gwo2fgha1#

看起来像是在容器中安装Laravel项目。如果您将这些文件从Windows环境装载到WSL 2,这可能会导致非常糟糕的文件I/O,因为WSL 2当前在访问Windows环境中的文件时存在很多问题。此I/O问题截至2020年7月存在,您可以在GitHub here上找到该问题的持续状态。
我能想到的三种可能的解决方案可以暂时解决这个问题。

在问题解决之前,禁用docker基于WSL 2的引擎

由于此问题仅在WSL 2尝试访问Windows文件系统时发生,因此您可以选择禁用WSL 2 docker集成并在Windows环境中运行容器。您可以在Docker Desktop的UI中找到禁用它的选项:

将项目存储在WSL 2的Linux文件系统中

同样,由于当WSL 2尝试访问/mnt下的Windows文件系统的挂载点时会发生此问题,因此您可以选择将项目存储到WSL 2的Linux文件系统上。

构建自己的Dockerfiles

你可以选择创建自己的Dockerfiles,而不是挂载你的项目,你可以将所需的目录COPY到docker镜像中。这将导致构建性能低下,因为WSL 2仍然必须访问Windows文件系统才能构建这些docker镜像,但运行时性能会好得多,因为它不必每次都从Windows环境中检索这些文件。

zyfwsgd6

zyfwsgd62#

您只需将所有源项目移动到文件夹

\\wsl$\Ubuntu-20.04\home\<User Name>\<Project Name>

速度将非常快,这样的运行在Linux本机

之前

之后

zynd9foi

zynd9foi3#

您正在/mnt/xxx文件夹上运行项目,是吗?
因为wsl2 filesystem performance is much slower than wsl1 in /mnt.
如果你想要一个简短的解决方案,它在这里。适用于Ubuntu 18.04和Windows商店中的Debian:
1.进入Docker设置,打开Expose daemon on tcp://localhost:2375 without TLS并关闭Use the WSL 2 based engine
1.运行此命令:

clear && sudo apt-get update && \
sudo curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh && sudo usermod -aG docker $USER && \
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose && \
echo "export PATH=\"$PATH:$HOME/.local/bin\"" >> ~/.profile && source ~/.profile && \
echo "export DOCKER_HOST=tcp://localhost:2375" >> ~/.bashrc && source ~/.bashrc && \
printf '[automount]\nroot = /\noptions = metadata' | sudo tee -a /etc/wsl.conf

我在这里写了关于如何将Docker Desktop与WSL 1集成的说明:https://github.com/CaliforniaMountainSnake/wsl-1-docker-integration

r8uurelv

r8uurelv4#

好吧,我得到了一个有趣的事实:))
在没有WSL 2的Windows上运行Docker。
请求具有TTFB 5.41s。这是index.php文件。我使用die()来检查哪里的时间更长,我发现如果我在terminate之后使用die(),TTFB变为~2.5s。

<?php
/**
 * Laravel - A PHP Framework For Web Artisans
 *
 * @package  Laravel
 * @author   Taylor Otwell <taylor@laravel.com>
 */

define('LARAVEL_START', microtime(true));

require __DIR__.'/../../application/vendor/autoload.php';

$app = require_once __DIR__.'/../../application/bootstrap/app.php';

#die(); <-- TTFB 1.72s
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send();

#die(); <-- TTFB 2.67s

$kernel->terminate($request, $response);

#die(); <-- TTFB 2.74s

#if there is no die in the file then TTFB is ~6s
wsxa1bj1

wsxa1bj15#

我在Windows 11上使用Laravel/Docker/Nginx时遇到了同样的问题。
我无法禁用“使用基于WSL 2的引擎”,因为它是灰色的,即使在Windows 11 Home上安装了Hyper-v(调整)。

以下是我找到的最佳解决方案:
1 .将项目复制到WSL文件夹中

  • 打开Windows资源管理器并键入以下地址:*wsl.localhost*\
  • 选择您的WSL示例,然后将项目复制到**/home/yourUsername/**

完整的URL将类似于:*wsl.localhost\ubuntu\home\username\yourProject*

2.启动docker容器

从这个文件夹打开一个终端,然后启动你的容器
例如:docker-compose up -d

3. Visual Studio代码

  • 从Visual Studio打开项目文件夹:* CTRL + P,>Remote-WSL:在WSL中打开文件夹...
  • 从命令行打开项目文件夹:* code --remote wsl+Ubuntu /home/username/yourProject
pod7payv

pod7payv6#

您可以从合成文件中排除vendor文件夹,如

volumes:
  - ./www:/var/www
  - vendor:/var/www/vendor
dffbzjpn

dffbzjpn7#

这是提高速度的粗略方法,但这里是:

问题

vendor目录加载composer依赖项的速度目前非常慢,该目录通过WSL 2从Windows上的项目根目录Map到docker容器。

解决方案

将vendor目录复制到docker镜像,并使用它,而不是项目根目录中的Map目录。
使用MySQL数据库和Apache PHP 7.4以及composer自动加载的项目结构如下所示:

db
    - init.sql
dev
    - db
        - Dockerfile
        - data.sql
    - www
        - Dockerfile
        - vendor-override.php
    - docker-compose.yaml
src
    - ...
vendor
    - ...
composer.json
index.php
...

这里的想法是将开发内容与主根目录分开。

dev/docker-compose.yaml

version: '3.8'
services:
  test-db:
    build:
      context: ../
      dockerfile: dev/db/Dockerfile

  test-www:
    build:
      context: ../
      dockerfile: dev/www/Dockerfile
    ports:
      - {insert_random_port_here}:80
    volumes:
      - ../:/var/www/html

这里我们有两个服务,一个用于MySQL数据库,另一个用于Apache with PHP,它将web根/var/www/htmlMap到我们的项目根。这使Apache能够查看项目源文件(srcindex.php)。

dev/db/Dockerfile

FROM mysql:5.7.24

# Add initialize script (adding 0 in front of it, makes sure it is executed first as the scripts are loaded alphabetically)
ADD db/init.sql /docker-entrypoint-initdb.d/0init.sql

# Add test data (adding 99 infront of it, makes sure it is executed last)
ADD dev/db/data.sql /docker-entrypoint-initdb.d/99data.sql

dev/www/Dockerfile

FROM php:7.4.0-apache-buster

# Install PHP extensions and dependencies required by them
RUN apt-get update -y & \
    apt-get install -y libzip-dev libpng-dev libssl-dev libxml2-dev libcurl4-openssl-dev & \
    docker-php-ext-install gd json pdo pdo_mysql mysqli ftp simplexml curl

# Enable apache mods and .htaccess files
RUN a2enmod rewrite & \
    sed -e '/<Directory \/var\/www\/>/,/<\/Directory>/s/AllowOverride None/AllowOverride All/' -i /etc/apache2/apache2.conf

# Add composer to improve loading speed since its located inside linux
ADD vendor /var/www/vendor
ADD dev/www/vendor-override.php /var/www/
RUN chmod -R 777 /var/www & \
    mkdir /var/www/html/src & \
    ln -s /var/www/html/src /var/www/src

# Expose html dir for easier deployments
VOLUME /var/www/html

我在PHP 7.4中使用了官方的Apache buster镜像。
1.在这里,我们将vendor目录和vendor-override.php复制到webroot目录(/var/www)之上的目录,这样就不会干扰项目根目录。

ADD vendor /var/www/vendor
ADD dev/www/vendor-override.php /var/www/

1.接下来,我们为每个人设置读写执行权限,以便Apache可以读取它。这是必要的,因为它在webroot之外。

chmod -R 777 /var/www

1.现在这里的技巧是确保composer从src目录自动加载类。这个问题可以通过在项目根目录中创建一个从/var/www/src//var/www/html/src的链接来解决。

mkdir /var/www/html/src
ln -s /var/www/html/src /var/www/src

dev/www/vendor-override.php

# Override default composer dependencies to be loaded from inside docker. This is used because
# loading files over mapped volumes is really slow on WSL 2.
require_once "/var/www/vendor/autoload.php";

只需在docker镜像中使用vendor目录即可。

index.php

$fixFile = "../vendor-override.php";

if (file_exists($fixFile))
    require_once $fixFile;
else
    require_once "vendor/autoload.php";
    
...

如果检测到vendor-override.php文件,则使用该文件而不是项目根目录中的文件。这确保了index.php在docker镜像中加载dir,这要快得多。

composer.json

{
  "autoload": {
    "psr-4": {
      "Namespace\\": ["src"]
    }
  },
  ...
}

简单的自动加载设置将“Namespace”Map到项目根目录中的src目录。

注意事项

  • index.php从项目根目录加载vendor-override.php而不是vendor
  • PSR-4自动加载是通过链接解决的

缺点

缺点是每次更新依赖项时都必须构建Docker镜像。

r6hnlfcb

r6hnlfcb8#

默认情况下,docker容器php:8.0-apache中不启用opcache。在dockerfile中添加:

RUN docker-php-ext-install opcache
COPY ./opcache.ini /usr/local/etc/php/conf.d/opcache.ini

创建文件opcache.ini:

[opcache]
opcache.enable=1
; 0 means it will check on every request
; 0 is irrelevant if opcache.validate_timestamps=0 which is desirable in production
opcache.revalidate_freq=0
opcache.validate_timestamps=1
opcache.max_accelerated_files=10000
opcache.memory_consumption=192
opcache.max_wasted_percentage=10
opcache.interned_strings_buffer=16
opcache.fast_shutdown=1
n6lpvg4x

n6lpvg4x9#

我刚刚从PowerShell启用了Hyper-V:

DISM /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V

重新启动,现在它工作得相当好。我没有改变任何其他东西。
查看有关如何启用Hyper-V here的详细信息。

相关问题