ubuntu vscode docker php 环境搭建

说明

php 有很多镜像, 但是本文不用任何构建好的 php 镜像, 而是从头自己制作. 无特殊需求, php 容器使用的基础镜像为 alpine , 如果有需要再更换为 ubuntu

alpine 版本

最终效果

目录结构

复制代码
├── app
├── app_bak
│   └── index.php
├── docker
│   └── php-base
│       ├── Dockerfile
│       ├── entrypoint.sh
│       └── xdebug.ini
├── docker-compose.yml
├── nginx
│   ├── conf
│   │   └── nginx.conf
│   ├── html
│   │   └── index.html
│   └── log
│       ├── access.log
│       └── error.log
├── php
│   └── php-fpm.d
│       └── www.conf
└── tmp.txt

新建 docker 网络

bash 复制代码
docker network create php-setup

nginx + php 环境搭建

nginx

新建目录
sh 复制代码
mkdir -p nginx/conf
mkdir -p nginx/log
mkdir -p nginx/html
nginx 配置文件
nginx 复制代码
#允许进程数量,建议设置为cpu核心数或者auto自动检测,注意Windows服务器上虽然可以启动多个processes,但是实际只会用其中一个
worker_processes  auto;

events {
    #单个进程最大连接数(最大连接数=连接数*进程数)
    #根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。
    worker_connections  1024;
}

http {
    #文件扩展名与文件类型映射表(是conf目录下的一个文件)
    include       mime.types;
    #默认文件类型,如果mime.types预先定义的类型没匹配上,默认使用二进制流的方式传输
    default_type  application/octet-stream;

	#sendfile指令指定nginx是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。
    # 如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度。
    sendfile        on;

     #长连接超时时间,单位是秒
    keepalive_timeout  65;

    # =============== 日志配置 ===============
    # 定义日志格式(可选,使用 main 格式)
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    # 设置一个 default server 返回 444(拒绝)或 404,用于捕获非法请求
    server {
        listen 80 default_server;
        server_name _;
        return 444;  # 关闭连接
    }
    
    server {
        listen 80;
        server_name www.kmphp84.com;
        root /usr/share/nginx/html;
        index index.html;
    }

}
docker-compose.yml
yml 复制代码
services:
  php-setup-nginx:
    image: nginx:1.18.0
    container_name: php-setup-nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/log:/var/log/nginx
      - ./nginx/html:/usr/share/nginx/html
    networks:
      php-setup:
        ipv4_address: 172.19.0.5
  
networks:
  php-setup:
    external: true
启动
复制代码
laolang@ghost:php-setup$ docker compose up -d
[+] Running 1/1
 ✔ Container php-setup-nginx  Started                                                                                                                                                      0.3s 
laolang@ghost:php-setup$ 
测试
  1. nginx/html 目录中添加一个 index.html , 然后随便写点内容
  2. 本地添加域名映射

alpine

如何运行

首先运行一个 alpine 容器, 后续有需要运行的命令可以先在这个容器中尝试, 没问题了再复制到 Dockerfile

注意:

  1. Alpine 镜像本身只是一个极简操作系统,不包含任何长期运行的服务(如 nginxphp-fpm 等),所以直接 run 会立刻退出。
  2. alpine 默认没有 bash , 所以需要使用 docker exec -it alpine /bin/sh 进入容器
复制代码
docker run -d --name alpine alpine:3.23 tail -f /dev/null
如何安装 php

第一步 替换源

清华源镜像参考 https://mirrors.tuna.tsinghua.edu.cn/help/alpine/

sh 复制代码
sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories

第二步 安装 php

alpine 使用 apk 安装软件

复制代码
apk add --no-cache php84 php84-fpm php84-curl
有哪些需要关注的文件

如何查看安装了哪些依赖

复制代码
/ # php --ini
Configuration File (php.ini) Path: /etc/php84
Loaded Configuration File:         /etc/php84/php.ini
Scan for additional .ini files in: /etc/php84/conf.d
Additional .ini files parsed:      /etc/php84/conf.d/00_curl.ini

/ # 

php-fpm 的默认配置文件路径

直接启动 php-fpm84 , 然后查看进程就可以看到使用的是哪个配置文件

复制代码
/ # php-fpm84
/ # ps aux 
PID   USER     TIME  COMMAND
    1 root      0:00 tail -f /dev/null
   13 root      0:00 /bin/sh
   26 root      0:00 {php-fpm84} php-fpm: master process (/etc/php84/php-fpm.conf)
   27 nobody    0:00 {php-fpm84} php-fpm: pool www
   28 nobody    0:00 {php-fpm84} php-fpm: pool www
   29 root      0:00 ps aux
/ # 

可以看到 include 的是 /etc/php84/php-fpm.d/www.conf

复制代码
/etc/php84 # tail /etc/php84/php-fpm.conf
; used in logs and stats. There is no limitation on the number of pools which
; FPM can handle. Your system will tell you anyway :)

; Include one or more files. If glob(3) exists, it is used to include a bunch of
; files from a glob(3) pattern. This directive can be used everywhere in the
; file.
; Relative path can also be used. They will be prefixed by:
;  - the global prefix if it's been set (-p argument)
;  - /usr otherwise
include=/etc/php84/php-fpm.d/*.conf
/etc/php84 # ls -l /etc/php84/php-fpm.d/
total 24
-rw-r--r--    1 root     root         22133 Dec 20 12:36 www.conf
/etc/php84 # 

/etc/php84/php-fpm.d/www.conf 复制到本地

复制代码
docker cp alpine:/etc/php84/php-fpm.d/www.conf .

php

修改 www.conf
  1. 使用 www-data 而不是 nobody 用户运行 php-fpm

  2. php-fpm 默认监听127.0.0.1 , 当 phpnginx 不在一个容器时, nginx 容器将无法连接到 php 容器

    user = www-data
    group = www-data

    listen = 0.0.0.0:9000

Dockerfile
docker 复制代码
# 基础镜像使用 java8
FROM alpine:3.23
# 作者
LABEL maintainer="khl <xiaodaima2016@163.com>"
# 设置时区
ENV TZ=Asia/Shanghai

# 设置镜像源
RUN sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories

# 安装依赖
RUN apk add --no-cache \
    php84 \
    php84-fpm \
    php84-curl

# 安全地创建 www-data 用户/组(如果尚未存在)
RUN if ! getent group www-data > /dev/null 2>&1; then \
        addgroup -g 82 -S www-data; \
    fi && \
    if ! getent passwd www-data > /dev/null 2>&1; then \
        adduser -u 82 -D -S -G www-data www-data; \
    fi


# 复制入口脚本
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# 设置工作目录(应用代码将挂载到这里)
WORKDIR /var/www/html

# 启动脚本
ENTRYPOINT ["/entrypoint.sh"]
entrypoint
sh 复制代码
#!/bin/sh
set -e

echo "🚀 Starting PHP-FPM 8.4..."

# 前台运行 PHP-FPM(关键!)
exec php-fpm84 --nodaemonize --fpm-config /etc/php84/php-fpm.d/www.conf
修改 nginx

注意:

  1. 修改了 root
  2. 添加了 php 文件处理
nginx 复制代码
#允许进程数量,建议设置为cpu核心数或者auto自动检测,注意Windows服务器上虽然可以启动多个processes,但是实际只会用其中一个
worker_processes  auto;

events {
    #单个进程最大连接数(最大连接数=连接数*进程数)
    #根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。
    worker_connections  1024;
}

http {
    #文件扩展名与文件类型映射表(是conf目录下的一个文件)
    include       mime.types;
    #默认文件类型,如果mime.types预先定义的类型没匹配上,默认使用二进制流的方式传输
    default_type  application/octet-stream;

	#sendfile指令指定nginx是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。
    # 如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度。
    sendfile        on;

     #长连接超时时间,单位是秒
    keepalive_timeout  65;

    # =============== 日志配置 ===============
    # 定义日志格式(可选,使用 main 格式)
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    # 设置一个 default server 返回 444(拒绝)或 404,用于捕获非法请求
    server {
        listen 80 default_server;
        server_name _;
        return 444;  # 关闭连接
    }
    
    server {
        listen 80;
        server_name www.kmphp84.com;
        root /var/www/html;
        index index.php index.html;

        # 处理 .php 文件
        location ~ \.php$ {
            fastcgi_pass php-setup-app:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_hide_header X-Powered-By;
        }
    }

}
修改 docker-compose.yml

注意:

  1. nginx 容器添加了一个路径映射
  2. 添加了 php 容器
yml 复制代码
services:
  php-setup-nginx:
    image: nginx:1.18.0
    container_name: php-setup-nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/log:/var/log/nginx
      - ./nginx/html:/usr/share/nginx/html
      - ./app:/var/www/html
    networks:
      php-setup:
        ipv4_address: 172.19.0.5

  php-setup-app:
    image: khl/php-base:0.0.1
    container_name: php-setup-app
    volumes:
      - ./app:/var/www/html
      - ./php/php-fpm.d/www.conf:/etc/php84/php-fpm.d/www.conf
    networks:
      php-setup:
        ipv4_address: 172.19.0.7
    extra_hosts:
      - "host.docker.internal:host-gateway"

networks:
  php-setup:
    external: true
测试

php 文件内容如下

php 复制代码
<?php

// 设置时区
date_default_timezone_set('Asia/Shanghai'); 

// 经典 Hello World
echo "Hello, World!" . "<br />";

// 输出 php 版本
echo "PHP version: " . PHP_VERSION . "<br />";

// 当前时间
echo "Current time: " . date('Y-m-d H:i:s') . "<br />";

?>

访问效果

laravel

生成 laravel 项目并复制到本地

alpine 容器中执行如下命令安装 laravel 需要的依赖

复制代码
apk add --no-cache \
    php84 \
    php84-fpm \
    composer \
    php84-dom \
    php84-fileinfo \
    php84-iconv \
    php84-mbstring \
    php84-openssl \
    php84-session \
    php84-tokenizer \
    php84-xml \
    php84-xmlwriter \
    php84-zip \
    php84-phar \
    php84-pdo \
    php84-pdo_sqlite \
    php84-xdebug

然后生成 laravel 项目

复制代码
composer create-project laravel/laravel example-app "11.6.0"

将此 example-app 复制到本地并重命名为 app, 然后执行如下命令

复制代码
find app -type d -exec chmod 755 {} \;

最终配置文件

php Dockerfile
docker 复制代码
# 基础镜像使用 java8
FROM alpine:3.23
# 作者
LABEL maintainer="khl <xiaodaima2016@163.com>"
# 设置时区
ENV TZ=Asia/Shanghai

# 设置镜像源
RUN sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories

# 安装依赖
RUN apk add --no-cache \
    php84 \
    php84-fpm \
    composer \
    php84-dom \
    php84-fileinfo \
    php84-iconv \
    php84-mbstring \
    php84-openssl \
    php84-session \
    php84-tokenizer \
    php84-xml \
    php84-xmlwriter \
    php84-zip \
    php84-phar \
    php84-pdo \
    php84-pdo_sqlite \
    php84-xdebug

# 安全地创建 www-data 用户/组(如果尚未存在)
RUN if ! getent group www-data > /dev/null 2>&1; then \
        addgroup -g 82 -S www-data; \
    fi && \
    if ! getent passwd www-data > /dev/null 2>&1; then \
        adduser -u 82 -D -S -G www-data www-data; \
    fi


# 复制 xdebug 配置文件
COPY xdebug.ini /etc/php84/conf.d/99-xdebug.ini

# 复制入口脚本
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# 设置工作目录(应用代码将挂载到这里)
WORKDIR /var/www/html

# 启动脚本
ENTRYPOINT ["/entrypoint.sh"]
php-fpm.d/www.conf

关键配置, 完整文件可以自行复制

{.line-numbers} 复制代码
user = www-data
group = www-data

listen = 0.0.0.0:9000
nginx
nginx 复制代码
#允许进程数量,建议设置为cpu核心数或者auto自动检测,注意Windows服务器上虽然可以启动多个processes,但是实际只会用其中一个
worker_processes  auto;

events {
    #单个进程最大连接数(最大连接数=连接数*进程数)
    #根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。
    worker_connections  1024;
}

http {
    #文件扩展名与文件类型映射表(是conf目录下的一个文件)
    include       mime.types;
    #默认文件类型,如果mime.types预先定义的类型没匹配上,默认使用二进制流的方式传输
    default_type  application/octet-stream;

	#sendfile指令指定nginx是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。
    # 如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度。
    sendfile        on;

     #长连接超时时间,单位是秒
    keepalive_timeout  65;

    # =============== 日志配置 ===============
    # 定义日志格式(可选,使用 main 格式)
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    # 设置一个 default server 返回 444(拒绝)或 404,用于捕获非法请求
    server {
        listen 80 default_server;
        server_name _;
        return 444;  # 关闭连接
    }
    
    server {
        listen 80;
        server_name www.kmphp84.com;
        root /var/www/html/public;
        index index.php index.html;

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

        # 处理 .php 文件
        location ~ \.php$ {
            fastcgi_pass php-setup-app:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_hide_header X-Powered-By;
        }
    }

}
docker-compose.yml
yml 复制代码
services:
  php-setup-nginx:
    image: nginx:1.18.0
    container_name: php-setup-nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/log:/var/log/nginx
      - ./nginx/html:/usr/share/nginx/html
      - ./app:/var/www/html
    networks:
      php-setup:
        ipv4_address: 172.19.0.5

  php-setup-app:
    image: khl/php-base:0.0.1
    container_name: php-setup-app
    volumes:
      - ./app:/var/www/html
      - ./php/php-fpm.d/www.conf:/etc/php84/php-fpm.d/www.conf
    networks:
      php-setup:
        ipv4_address: 172.19.0.7
    extra_hosts:
      - "host.docker.internal:host-gateway"

networks:
  php-setup:
    external: true

laravel 修改配置

目录无权限

此时 laravel 应用已经可以访问, 但是在报错

最简单的办法就是直接修改本地目录的权限

复制代码
chmod -R 777 storage bootstrap/cache
sqlite 连接报错

这是因为 laravel 默认使用 sqlitesession 存储, 修改为 file 即可

laravel 项目跟目录的 .env 修改如下内容即可

复制代码
SESSION_DRIVER=file

debug

laravel 项目跟目录添加 .vscode/launch.json

json 复制代码
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "xdebug",
      "type": "php",
      "request": "launch",
      "port": 9003,
      "pathMappings": {
        "/var/www/html": "${workspaceFolder}"
      }
    }
  ]
}

然后在 routes/web.php 中打个断点, 访问应用首页即可

相关推荐
CodeMartain13 小时前
Dify Windows 原生部署(无 Docker、纯本地)
运维·docker·容器
不正经的小寒14 小时前
PHP 8.4 核心特性
php
llrraa201015 小时前
配置docker国内镜像源
运维·docker·容器
starvapour15 小时前
Ubuntu切换到Fcitx5中文输入法
linux·运维·ubuntu
木欣欣粉皮16 小时前
解决Ubuntu 26.04的挂起状态唤醒问题
linux·运维·ubuntu
阿正的梦工坊16 小时前
【Typescript】08-keyof-typeof-索引访问类型
linux·ubuntu·typescript
不正经的小寒16 小时前
PHP 8.3 核心特性
php
华为云开发者联盟16 小时前
告别繁琐操作,华为云码道 + Docker重塑远程开发体验
人工智能·学习·docker·华为云·软件开发·华为云码道
xiaobobo333017 小时前
Ubuntu如何安装Vmware-tools和root用户
ubuntu·root用户·vmware-tools
轩Scott17 小时前
Ubuntu开机卡Logo?NVIDIA驱动修复全攻略
linux·ubuntu