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 中打个断点, 访问应用首页即可

相关推荐
thulium_2 小时前
vscode 使用
ide·vscode·编辑器
Maybe I Simple2 小时前
二进制打包|phar打包
php·webman
程序终结者2 小时前
CDH6.3.2集群docker容器化离线部署客户端parcel+配置全流程详解
运维·docker·容器
ERP面壁者3 小时前
Docker小白搭建xxl-job,mysql的过程日志
mysql·docker·容器
Danileaf_Guo3 小时前
OSPF路由引入的陷阱:为何Ubuntu上静态路由神秘消失?深挖FRR路由分类机制
linux·运维·网络·ubuntu·智能路由器
张某人的胡思乱想3 小时前
windows远程ubuntu
linux·运维·ubuntu
winfreedoms3 小时前
wsl ubuntu的基础配置
linux·ubuntu·wsl·基础配置
青花锁3 小时前
Mac电脑安装Docker
macos·docker·容器
zorro_z3 小时前
ThinkPHP8学习篇(十四):模板
php