Docker桌面版安装LNMP


Docker桌面版安装LNMP


引言

一直在windows中开发,为了便捷开发,不用搭建虚拟机等,可以使用桌面版docker解决这个问题。下面是多项目开发使用的LNMP环境。

WSL开头

如果没有启用WSL2,需要在命令行中执行以下命令。命令行以管理员身份打开:

1、启用WSL
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

2、启用虚拟机功能
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

wsl常用命令:

# 更新WSL2内核(报错0x800701bc时执行)
wsl --update

# 查看WSL状态
wsl --status

# 设置WSL2为默认
wsl --set-default-version 2

# 查看可安装发行版列表
wsl -l -o

# 安装指定版本
wsl --install -d Ubuntu-22.04

# 查看wsl已安装列表
wsl -l -v

# 终止Ubuntu22.04
wsl --terminate Ubuntu-22.04

# 卸载Ubuntu22.04
wsl --unregister Ubuntu-22.04

在文件资源管理器地址栏中通过 \\wsl$ 查看WSL安装的所有linux。

# 启动进入Ubuntu 22.04
wsl -d Ubuntu-22.04

# WSL中设置默认版本,以后直接wsl即可启动Ubuntu 22.04
wsl --set-default Ubuntu-22.04
wsl

# 查看版本(在Ubuntu中执行)
hostnamectl

如果不能访问外网,需要在命令行手动安装。命令行以管理员身份打开:

echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
echo "nameserver 114.114.114.114" | sudo tee -a /etc/resolv.conf

DNS有问题,临时解决一下:

baiyang@DESKTOP-PSDQHMG:/mnt/c/Windows/system32$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.19.160.1
baiyang@DESKTOP-PSDQHMG:/mnt/c/Windows/system32$
baiyang@DESKTOP-PSDQHMG:/mnt/c/Windows/system32$ echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
nameserver 8.8.8.8
baiyang@DESKTOP-PSDQHMG:/mnt/c/Windows/system32$ echo "nameserver 114.114.114.114" | sudo tee -a /etc/resolv.conf
nameserver 114.114.114.114
baiyang@DESKTOP-PSDQHMG:/mnt/c/Windows/system32$
baiyang@DESKTOP-PSDQHMG:/mnt/c/Windows/system32$ cat /etc/resolv.conf
nameserver 8.8.8.8
nameserver 114.114.114.114
baiyang@DESKTOP-PSDQHMG:/mnt/c/Windows/system32$

Docker开头

命令 作用
docker system df 查看磁盘占用
docker system df -v 查看磁盘占用明细
docker system prune 清理停止的容器、悬空镜像、未使用的网络和构建缓存
docker system prune -a 额外清理所有未使用的镜像
docker builder prune 只清理构建缓存
docker image prune -a 清理所有未使用的镜像
docker container prune 清理停止的容器
docker volume prune 清理未使用的卷
docker build --no-cache 单次构建跳过缓存

在 Docker 中,“清理缓存”通常指清理构建缓存、未使用的镜像、容器、网络和卷等占用的磁盘空间。

0、查看磁盘使用情况

# 查看磁盘使用情况
docker system df

- 显示镜像、容器、卷和构建缓存占用的磁盘空间。
- 加上 `-v` 可查看更详细的列表:
docker system df -v

1、清理所有未使用的资源(最常用)

docker system prune

- 清理**停止的容器**、**未使用的网络**、**悬空镜像**(dangling images)和**构建缓存**。
- 加上 `-a` 会额外删除所有未使用的镜像(不只是悬空镜像),释放更多空间。
docker system prune -a

- 加上 `-f` 跳过确认提示,直接执行。
docker system prune -a -f

2、单独清理构建缓存

docker builder prune

- 删除所有构建缓存。
- 加上 `-a` 强制删除所有缓存(包括当前正在使用的)。
docker builder prune -a

3、清理镜像

docker image prune

- 删除悬空镜像(`<none>:<none>`)。
- 加上 `-a` 删除所有未使用的镜像(即没有被任何容器引用的镜像)。

docker image prune -a

4、清理容器

docker container prune

- 删除所有已停止的容器。

5、清理卷(Volume)

docker volume prune

- 删除所有未使用的卷(volume 未被任何容器使用)。**注意**:卷存储数据,删除可能丢失持久化数据,谨慎操作。

6、清理网络

docker network prune

- 删除所有未被任何容器使用的网络。

7、构建时忽略缓存(不清理,仅跳过缓存)

如果您只是想让本次 `docker build` 不使用缓存,而不是删除所有历史缓存,可以使用 `--no-cache` 选项:

docker build --no-cache -t your-image .

这只会临时跳过缓存,不会影响其他构建的缓存。

8、一键彻底清理(慎用)

docker system prune -a --volumes -f

- 删除所有未使用的**容器**、**镜像**、**网络**、**卷**(包括未使用的卷)和**构建缓存**。
- **危险**:会永久删除所有未被使用的资源,可能导致数据丢失。

正文

条件准备

正常从 Docker https://www.docker.com/ 官网下载安装即可。

修改为国内源加速,在docker desktop的设置中setting配置即可,Docker Engine中写入下面内容,然后Apply应用并重启Docker Desktop:

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "registry-mirrors": [
    "https://docker.xuanyuan.me",
    "https://docker.1ms.run",
    "https://docker.m.daocloud.io",
    "https://docker.mirrors.ustc.edu.cn"
  ]
}

需要说明 docker config set --global registry-mirrors命令无效,不可用。

项目的目录结构如下:

D:\develop
├── DockerEnv
    ├── docker-multi-web
        ├── dockerfile                # PHP+Nginx基础镜像构建文件
        ├── nginx
            ├── nginx.conf            # Nginx主配置
            └── vhost                 # 多站点虚拟主机配置目录
                ├── site1.conf        # 站点1配置
                └── site2.conf        # 站点2配置
    ├── mysql-server
        ├── mysql-data                # MySQL持久化数据
├── www
    ├── site1                 # 项目1:test1.local
    │   └── index.php
    └── site2                 # 项目2:test2.local
        └── index.php

搭建网桥

搭建网桥docker network create web-net,如:

D:\develop\DockerEnv>docker network create web-net
2b27ad41e8489e7765f93e2fec27eb9321cf88e0d65969f438f7d3ea844d8de6

D:\develop\DockerEnv>

安装MySQL

MySQL 不要放进自定义 Image。如果把 MySQL 打包进镜像,删除容器会丢失数据库数据,无法持久化;分离容器更灵活,可单独重启、备份、更换 MySQL 版本。

Docker Hub 官方已经提供好现成的 mysql:8.0 官方镜像,直接 docker run 拉取启动即可,不需要自己打包 MySQL。

启动MySQL容器:

docker run -d --name mysql8 --network web-net -v D:/develop/DockerEnv/mysql-server/mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=testdb -e MYSQL_ROOT_HOST=% -p 3306:3306 mysql:8.0

加上 MYSQL_ROOT_HOST=%,否则外部 Windows、PHP 容器无法连接数据库。-e MYSQL_ROOT_HOST=% 允许 PHP 容器、本机 Navicat 全部访问,本地开发必备。

运行完成后在Docker Desktop中查看MySQL容器是否启动成功,Container、Image等。

外部连接时,连接地址不要使用 127.0.0.1,而要使用 mysql8 。

Nginx 配置

nginx.conf 内容:

user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log main;
    sendfile on;
    keepalive_timeout 65;
    # 加载所有站点虚拟主机配置
    include /etc/nginx/conf.d/*.conf;
}

项目配置

下面看几个项目的配置。

项目一

site1.conf 内容:

server {
    listen 80;
    server_name test1.local www.test1.local;
    root /usr/share/nginx/www/site1;
    index index.html index.htm index.php;

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

www/site1/index.php 内容:

<?php

echo "<h2>站点1 test1.local</h2>";
phpinfo();

项目二

site2.conf 内容:

server {
    listen 80;
    server_name test2.local www.test2.local;
    root /usr/share/nginx/www/site2;
    index index.html index.htm index.php;

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

www/site2/index.php 内容:

<?php

echo "<h2>站点2 test2.local</h2>";
// 测试mysql连接
$dsn = 'mysql:host=mysql8;dbname=testdb;charset=utf8';
try {
    $db = new PDO($dsn, 'root', '123456');
    echo "<p>MySQL连接成功</p>";
}catch (PDOException $e){
    echo "<p>数据库连接失败:".$e->getMessage()."</p>";
}

www/site2/index.php 内容:

<?php
    echo "hello world";
?>

hosts 配置

在宿主机的 C:\Windows\System32\drivers\etc\hosts 文件中添加:

127.0.0.1 test1.local
127.0.0.1 test2.local

如果提示无权限修改,可以用管理员权限打开记事本,然后用记事本打开该文件进行修改并保存。

安装 Nginx + PHP

接下来安装Nginx+PHP。

dockerfile 内容:

FROM quay.io/centos/centos:stream9-minimal

# 1. 替换 CentOS 基础源为阿里云
RUN sed -e 's|mirror.centos.org|mirrors.aliyun.com|g' \
        -e 's|mirror.stream.centos.org|mirrors.aliyun.com|g' \
        -i /etc/yum.repos.d/centos*.repo && \
    microdnf clean all && microdnf makecache

# 2. 强制移除 curl-minimal,再安装 dnf 和 curl
RUN rpm -e --nodeps curl-minimal && \
    microdnf install -y dnf curl && \
    microdnf clean all

# 3. 安装 epel-release 并替换为阿里云 EPEL 镜像
RUN dnf install -y epel-release && \
    sed -e 's|https://download.fedoraproject.org/pub|https://mirrors.aliyun.com/fedora-epel|g' \
        -i /etc/yum.repos.d/epel*.repo && \
    dnf clean all && dnf makecache

# 4. 安装 Remi 源并替换为清华镜像(国内唯一完整同步Remi)
RUN dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm && \
    sed -e 's|https://rpms.remirepo.net|https://mirrors.tuna.tsinghua.edu.cn/remi|g' \
        -i /etc/yum.repos.d/remi*.repo && \
    dnf clean all && dnf makecache

# 5. 安装 Nginx + 启用 php:remi-7.4 模块并安装全部组件 + 系统底层时区库
RUN dnf module enable -y php:remi-7.4 && \
    dnf install -y \
        nginx \
        php-fpm \
        php-cli \
        php-bcmath \
        php-mysqlnd \
        php-pdo \
        php-gd \
        php-zip \
        php-curl \
        php-mbstring \
        php-opcache \
        php-fileinfo \
        php-xml \
        php-redis \
        php-intl \
        php-sodium \
        vim unzip && \
    dnf clean all

# 6.安装 tzdata 并重装确保时区数据文件存在
RUN dnf install -y tzdata && \
    dnf reinstall -y tzdata

# 7. 新增创建www-data用户组和用户
RUN groupadd www-data && useradd -g www-data www-data

# 8. 修改 php-fpm 运行用户为 www-data,解决页面403权限
RUN sed -i 's/^user = apache/user = www-data/' /etc/php-fpm.d/www.conf && \
    sed -i 's/^group = apache/group = www-data/' /etc/php-fpm.d/www.conf && \
    sed -i 's/^listen = .*/listen = 127.0.0.1:9000/' /etc/php-fpm.d/www.conf

# 9. 统一设置系统时区+PHP时区配置,彻底消除时区报错
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo 'date.timezone = Asia/Shanghai' > /etc/php.d/99-timezone.ini

# 10. 安装 Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# 11. 手动创建 Composer 全局配置文件(阿里云镜像)
RUN mkdir -p /root/.composer && \
    echo '{"config": {"repositories": {"packagist": {"type": "composer", "url": "https://mirrors.aliyun.com/composer/"}}}}' > /root/.composer/config.json

# 12. 复制本地Nginx主配置 + 多站点虚拟主机目录
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf

# 13. 创建站点根目录并授权www-data读写权限
RUN mkdir -p /usr/share/nginx/www && \
    chown -R www-data:www-data /usr/share/nginx/www


EXPOSE 80

# 启动php-fpm + 前台运行nginx,防止容器自动退出
CMD ["sh", "-c", "mkdir -p /run/php-fpm && chown www-data:www-data /run/php-fpm && php-fpm -F & nginx -g 'daemon off;'"]

这一块用了好长时间,说一下里面的注意点。基础镜像用的是centos:stream9精简版,为了国内加速,CentOS 基础源换为了阿里云。里面多处安装用到了dnf,但基础镜像 quay.io/centos/centos:stream9-minimal 默认的仓库配置中,没有可用的 dnf 包(尽管 microdnf 是内置的,但microdnf 本身是轻量级包管理器,好多包的安装还是要用到dnf),有些地方也要用到curl(尽管 curl-minimal 是内置的,但有些下载是要用到curl的,而curl 包与 curl-minimal 冲突),我们需要强制移除 curl-minimal,再安装 dnf 和 curl。还有centos:stream9精简版底层是缺少系统底层时区库,安装Composer会用到。Composer 全局配置文件改为阿里云,命令行总是无法执行,无奈改为手动创建。php-fpm 一般是用socket实现,绑定地址 /run/php-fpm/www.sock,这是一个临时目录,在容器启动时需要创建该目录;但这里改下来有问题,最后改为了 127.0.0.1:9000 端口监听。php-fpm -F前台运行会阻塞后面nginx -g 'daemon off;'的执行,所以不能用&&,而是改为&。

centos:stream9-minimal 为精简镜像,有意删除了 /usr/share/zoneinfo,导致tzdata安装不完整,需要重新安装dnf reinstall -y tzdata。之后 第10步 可以修改看一下能否正常安装:

# 11. 设置 Composer 全局为阿里云镜像
php -d date.timezone=Asia/Shanghai composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

生成镜像:

docker build -t centos9-nginx-php74 .

创建容器:

docker run -d --name centos9-nginx-php74 --network web-net -v D:/develop/www:/usr/share/nginx/www -v D:/develop/DockerEnv/docker-multi-web/nginx/vhost:/etc/nginx/conf.d -p 8080:80 centos9-nginx-php74

浏览器访问,查看效果:

  • 站点 1:http://test1.local:8080
  • 站点 2:http://test2.local:8080

另外php可以安装的几个拓展:

连接协议
soap
swoole

进程管理
sysvsem
posix
shmop

新项目配置

和第二个项目一样,除了项目文件,另外需要写site3.conf配置,修改hosts文件。

重启容器:

docker restart centos9-nginx-php74

PHP8.3 安装

dockerfile 内容:

FROM quay.io/centos/centos:stream9

# 1. 替换 CentOS 基础源为阿里云
RUN sed -e 's|mirror.centos.org|mirrors.aliyun.com|g' \
        -e 's|mirror.stream.centos.org|mirrors.aliyun.com|g' \
        -i /etc/yum.repos.d/centos*.repo && \
    microdnf clean all && microdnf makecache

# 2. 强制移除 curl-minimal,再安装 dnf 和 curl
RUN rpm -e --nodeps curl-minimal && \
    microdnf install -y dnf curl && \
    microdnf clean all

# 3. 安装 epel-release 并替换为阿里云 EPEL 镜像
RUN dnf install -y epel-release && \
    sed -e 's|https://download.fedoraproject.org/pub|https://mirrors.aliyun.com/fedora-epel|g' \
        -i /etc/yum.repos.d/epel*.repo && \
    dnf clean all && dnf makecache

# 4. 安装 Remi 源并替换为清华镜像(国内唯一完整同步Remi)
RUN dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm && \
    sed -e 's|https://rpms.remirepo.net|https://mirrors.tuna.tsinghua.edu.cn/remi|g' \
        -i /etc/yum.repos.d/remi*.repo && \
    dnf clean all && dnf makecache

# 5. 安装 Nginx + 启用 php:remi-7.4 模块并安装全部组件 + 系统底层时区库
RUN dnf module enable -y php:remi-7.4 && \
    dnf install -y \
        nginx \
        git \
        php-fpm \
        php-cli \
        php-bcmath \
        php-mysqlnd \
        php-pdo \
        php-gd \
        php-zip \
        php-curl \
        php-mbstring \
        php-opcache \
        php-fileinfo \
        php-xml \
        php-redis \
        php-intl \
        php-sodium \
        vim unzip && \
    dnf clean all

# 6.安装 tzdata 并重装确保时区数据文件存在
RUN dnf install -y tzdata && \
    dnf reinstall -y tzdata

# 7. 新增创建www-data用户组和用户
RUN groupadd www-data && useradd -g www-data www-data

# 8. 修改 php-fpm 运行用户为 www-data,解决页面403权限
RUN sed -i 's/^user = apache/user = www-data/' /etc/php-fpm.d/www.conf && \
    sed -i 's/^group = apache/group = www-data/' /etc/php-fpm.d/www.conf && \
    sed -i 's/^listen = .*/listen = 127.0.0.1:9000/' /etc/php-fpm.d/www.conf

# 9. 统一设置系统时区+PHP时区配置,彻底消除时区报错
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo 'date.timezone = Asia/Shanghai' > /etc/php.d/99-timezone.ini

# 10. 安装 Composer
RUN curl -sS https://mirrors.aliyun.com/composer/composer.phar | php -- --install-dir=/usr/local/bin --filename=composer

# 11. 手动创建 Composer 全局配置文件(阿里云镜像)
RUN mkdir -p /root/.composer && \
    echo '{"config": {"repositories": {"packagist": {"type": "composer", "url": "https://mirrors.aliyun.com/composer/"}}}}' > /root/.composer/config.json

# 12. 复制本地Nginx主配置 + 多站点虚拟主机目录
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf

# 13. 创建站点根目录并授权www-data读写权限
RUN mkdir -p /usr/share/nginx/www && \
    chown -R www-data:www-data /usr/share/nginx/www


EXPOSE 80

# 启动php-fpm + 前台运行nginx,防止容器自动退出
CMD ["sh", "-c", "mkdir -p /run/php-fpm && chown www-data:www-data /run/php-fpm && php-fpm -F & nginx -g 'daemon off;'"]

centos:stream9-minimal 为精简镜像,缺少好多东西,我们直接用centos:stream9,需要时我们也可以把git安装上。

生成镜像:

docker build -t centos9-nginx-php83 .

创建容器:

docker run -d --name centos9-nginx-php83 --network web-net -v D:/develop/www:/usr/share/nginx/www -v D:/develop/DockerEnv/docker-multi-web/nginx/vhost:/etc/nginx/conf.d -p 8081:80 centos9-nginx-php83

安装Redis

在 D:\develop\DockerEnv\redis-server 目录下创建 redis.conf 文件,内容如下:

# 允许远程连接(Docker环境下通常注释掉 bind 或设为 0.0.0.0)
# bind 127.0.0.1 
bind 0.0.0.0

# 关闭保护模式(如果设置了密码,可以保持 yes;若需兼容旧客户端可设 no)
protected-mode no

# 设置密码
requirepass 123456

# 开启 AOF 持久化
appendonly yes

# 内存限制与淘汰策略(防止内存溢出)
maxmemory 256mb
maxmemory-policy allkeys-lru

# 日志级别
loglevel notice

执行命令启动 Redis 容器:

docker run -d  --name redis74  --network web-net  -v D:/develop/DockerEnv/redis-server/redis-data:/data -v D:/develop/DockerEnv/redis-server/redis.conf:/usr/local/etc/redis/redis.conf  -p 6379:6379  redis:7.4 redis-server /usr/local/etc/redis/redis.conf

外部连接时,宿主机连接地址要使用 127.0.0.1:6379,同一个宿主机内的其他docker容器中使用 web-net:6379连接。

Compose 编排

上面安装好了 MySQL 和 Redis,下面按照:官方镜像 + 职责分离 + Compose 编排 + 复用已有网络, 来安装 php:8.5-fpm 和 nginx 两个独立容器,不自己拼 LNMP 大镜像。PHP 升级只换 tag,Nginx 调参只动配置,互不影响。

先看一下环境:

C:\Users\Administrator>wsl -l -v
NAME              STATE           VERSION

- docker-desktop    Running         2

C:\Users\Administrator>
C:\Users\Administrator>docker ps
CONTAINER ID   IMAGE                 COMMAND                   CREATED        STATUS      PORTS                                         NAMES
a30b1a6ccf85   centos9-nginx-php74   "sh -c 'mkdir -p /ru…"   2 months ago   Up 9 days   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp       centos9-nginx-php74
d5046d1e795e   redis:7.4             "docker-entrypoint.s…"   2 months ago   Up 9 days   0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp   redis74
2009b3504497   mysql:8.0             "docker-entrypoint.s…"   2 months ago   Up 9 days   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp   mysql8

C:\Users\Administrator>
C:\Users\Administrator>docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
835013813fdf   bridge    bridge    local
32c352e4a5ca   host      host      local
0671617bb89a   none      null      local
e9ba8523abf9   web-net   bridge    local

C:\Users\Administrator>
C:\Users\Administrator>docker network inspect web-net
[
    {
        "Name": "web-net",
        "Id": "e9ba8523abf9e6dabf39a46e3eef7505af94ce5b74f45cd01fb8db12c9e6dd3c",
        "Created": "2026-08-08T16:17:21.675273113Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv4": true,
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Options": {
            "com.docker.network.enable_ipv4": "true",
            "com.docker.network.enable_ipv6": "false"
        },
        "Labels": {},
        "Containers": {
            "2009b35044971280f3944e05dd912fa404f21a469163511fc8b4ddc48cb20fa1": {
                "Name": "mysql8",
                "EndpointID": "faedafb85b2938b8334c182c053290b5c1e2eb2be2da6ccfc777b021be38c71c",
                "MacAddress": "22:10:d7:e4:0b:6b",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "a30b1a6ccf85b51acb6dc0cf3e82c69d406b0bff15edede48cee4b153a3565ec": {
                "Name": "centos9-nginx-php74",
                "EndpointID": "3c57656f1de8fb77de983a492be80382c898c51dc3dc8dcf979ddc4deccaa57a",
                "MacAddress": "f2:34:9a:d6:7e:c7",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "d5046d1e795e62948c2c13b215925b6a530ad373f7f4a2501dc5c814064e099f": {
                "Name": "redis74",
                "EndpointID": "0b36d099a93cc71ab4b0caa8c0b53418b2f819ab14a20b690573be9c3e32a9de",
                "MacAddress": "8a:db:e3:94:65:2c",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Status": {
            "IPAM": {
                "Subnets": {
                    "172.18.0.0/16": {
                        "IPsInUse": 6,
                        "DynamicIPsAvailable": 65530
                    }
                }
            }
        }
    }
]

C:\Users\Administrator>
C:\Users\Administrator>docker network inspect web-net --format " "
mysql8 172.18.0.4/16
centos9-nginx-php74 172.18.0.2/16
redis74 172.18.0.3/16


C:\Users\Administrator>
C:\Users\Administrator>wsl -d docker-desktop
docker-desktop:/tmp/docker-desktop-root/run/desktop/mnt/host/c/Users/Administrator#
docker-desktop:/tmp/docker-desktop-root/run/desktop/mnt/host/c/Users/Administrator# pwd
/tmp/docker-desktop-root/run/desktop/mnt/host/c/Users/Administrator
docker-desktop:/tmp/docker-desktop-root/run/desktop/mnt/host/c/Users/Administrator#
docker-desktop:/tmp/docker-desktop-root/run/desktop/mnt/host/c/Users/Administrator# cd ~
docker-desktop:~#
docker-desktop:~# pwd
/root
docker-desktop:~#
docker-desktop:~# ll /home
-sh: ll: not found
docker-desktop:~#
docker-desktop:~# ls /home
docker-desktop:~#
docker-desktop:~# cat /etc/passwd
root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
docker-desktop:~#

可以发现:

  1. docker-desktop 是 Alpine 迷你容器式 WSL 发行版
  2. 用户是 root,家目录:/root
  3. shell 是 sh
  4. 已有 docker 网络:web-net,我们继续复用它

另外:Windows 资源管理器 \\wsl.localhost\docker-desktop ,对应 WSL 内 / 根目录。

安装 PHP8.5 与 Ngnix

我们在 root 目录下创建 lnmp-web 目录,用于存放 LNMP 相关文件。下面是具体的目录结构:

/root/lnmp-web/
├── docker-compose.yml
├── php
│   ├── Dockerfile
│   └── conf.d
│       └── 99-custom.ini
├── nginx
│   ├── conf.d
│   │   └── catch.conf
│   └── logs
└── www
    └── catchadmin  # 示例:CatchAdmin项目代码

如果用户不是 root,可以在家目录下创建目录,如 /home/sam/lnmp-web/。

catchadmin 是一个基于 Laravel-12 的PHP项目,不要把代码放 Windows 的 C 盘挂载目录 /mnt/c/xxx,不然 IO 会很慢,全部放在 WSL 内部路径。

先把各文件内容写好,再进行安装。

/root/lnmp-web/php/Dockerfile 文件内容:

FROM php:8.5-fpm

RUN apt-get update && apt-get install -y --no-install-recommends \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libzip-dev \
    libicu-dev \
    libonig-dev \
    tzdata \
    git \
    unzip \
    && rm -rf /var/lib/apt/lists/*

RUN docker-php-ext-configure gd --with-freetype --with-jpeg

RUN docker-php-ext-install -j$(nproc) \
    bcmath \
    ctype \
    fileinfo \
    gd \
    intl \
    mbstring \
    opcache \
    pdo_mysql \
    zip

RUN pecl install redis \
    && docker-php-ext-enable redis

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

COPY conf.d/*.ini /usr/local/etc/php/conf.d/

WORKDIR /var/www/html

/root/lnmp-web/php/conf.d/99-custom.ini 文件内容:

date.timezone = Asia/Shanghai
memory_limit = 256M
upload_max_filesize = 20M
post_max_size = 20M
max_execution_time = 120

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=128
opcache.max_accelerated_files=15000
opcache.max_wasted_percentage=10
opcache.revalidate_freq=60
opcache.validate_timestamps=1

/root/lnmp-web/docker-compose.yml 文件内容(核心,包含 nginx 服务定义):

services:
  php85:
    build: ./php
    container_name: php85
    restart: unless-stopped
    networks:
      - web-net
    volumes:
      - ./www:/var/www/html
      - ./php/conf.d:/usr/local/etc/php/conf.d
    environment:
      TZ: Asia/Shanghai

  nginx:
    image: nginx:stable
    container_name: nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    networks:
      - web-net
    volumes:
      - ./www:/var/www/html
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/logs:/var/log/nginx
    depends_on:
      - php85

networks:
  web-net:
    external: true

/root/lnmp-web/nginx/conf.d/catch.conf 文件内容:

server {
    listen 80;
    server_name catch.test;

    root /var/www/html/catchadmin/public;
    index index.php;

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 7d;
        try_files $uri =404;
    }

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass php85:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 128k;
    }

    location ~ /\.env { deny all; }
    location ~ composer\.json { deny all; }
}

在 Windows CMD / PowerShell 中执行 compose:

docker compose -f \\wsl$\docker-desktop\root\lnmp-web\docker-compose.yml up -d --build

不要在 WSL 中执行 docker / docker compose 命令,否则会报错。所有 docker compose、docker ps、docker network 全部在 Windows CMD / PowerShell 执行。

如果 mysql、redis 未接入 web-net 网络,需要把 mysql、redis 接入 web-net 网络:

docker network connect web-net mysql
docker network connect web-net redis

然后再执行上面的 docker compose 命令。

部署 CatchAdmin

在 Windows 资源管理器往 \\wsl.localhost\docker-desktop\root\lnmp-web\www\ 上传代码包,然后再进容器 composer install 安装依赖。

docker exec -it php85 bash
cd /var/www/html/catchadmin
composer install
cp .env.example .env
php artisan key:generate

然后配置.env,权限,迁移:

chown -R www-data:www-data /var/www/html/catchadmin/storage /var/www/html/catchadmin/bootstrap/cache
php artisan migrate
php artisan db:seed

修改 C:\Windows\System32\drivers\etc\hosts 文件,添加 catch.test 记录:

127.0.0.1 catch.test

浏览器访问 http://catch.test

后续修改 nginx 配置后的重载命令(CMD):

docker exec nginx nginx -t
docker exec nginx nginx -s reload

附录

执行过程:



返回