当前位置: 首页 > news >正文

Ubuntu 18.04 + Docker Compose 搭建 Laravel 开发环境实战

1. 项目概述:为什么在 Ubuntu 18.04 上用 Docker Compose 跑 Laravel 开发环境,不是“折腾”,而是效率刚需

你有没有过这样的经历:刚接手一个 Laravel 项目,composer install卡在guzzlehttp/guzzle的某个旧版本上,PHP 版本报错说不支持??空合并操作符;或者同事发来一份.env.example,你照着填完,php artisan migrate却提示SQLSTATE[HY000] [2002] Connection refused——不是数据库密码错了,是本地根本没装 MySQL,更别说 Redis 和 Nginx 的版本对齐问题。我在 2019 年那会儿维护三个 Laravel 项目,每个都要求 PHP 7.2、7.3、7.4 并存,还要配不同版本的 Node.js 做前端构建,光是brew uninstall php@7.2 && brew install php@7.3这一套操作,每天至少重复两次,还经常因为全局 PHP 切换导致某个项目的artisan tinker直接崩掉。直到我把整个开发栈扔进 Docker Compose,才真正理解什么叫“环境即代码”。

这个标题里的containerisieren(德语,“容器化”)不是个炫技词,它直指一个朴素目标:让 Laravel 开发环境从“手工拼装的乐高”变成“开箱即用的整装家具”。Ubuntu 18.04 是当时 LTS 版本里最稳定的桌面/服务器基线,Docker Compose 是唯一能用 YAML 文件把 PHP-FPM、Nginx、MySQL、Redis 四个服务拧成一股绳的工具。它解决的不是“能不能跑”的问题,而是“能不能秒级复现、零冲突协作、无残留卸载”的问题。你不需要成为 DevOps 工程师,但必须掌握这套流程——因为现在任何中型以上 Laravel 团队,docker-compose up -d已经和git clone一样,是新人入职第一天就要敲的第一行命令。它不替代 Homestead 或 Valet,而是用更轻量、更透明、更贴近生产的方式,把开发环境的不确定性降到最低。接下来我会带你从零开始,不跳步、不假设、不甩链接,只讲清楚每一步为什么这么写、删了哪一行会出什么错、改了哪个参数会让 Vue 编译直接卡死。

2. 整体架构设计与方案选型逻辑:为什么不用单容器?为什么坚持 Ubuntu 18.04?为什么 Compose 是唯一解?

2.1 服务拆分原则:绝不把 PHP、Nginx、MySQL 塞进一个容器

新手最容易犯的错,就是想“图省事”搞个大而全的镜像:FROM php:7.4-apache,再RUN apt-get install mysql-server redis-server。这看似简单,实则埋下三颗雷:

  • 进程管理失控:Docker 容器的 PID 1 必须是前台进程。Apache 可以当 PID 1,但 MySQL 的mysqld默认后台运行,service mysql start在容器里会立刻退出,导致整个容器闪退。你得手动改mysqld启动参数加--foreground,还得处理日志重定向,稍有不慎就docker logs一片空白。
  • 资源隔离失效:一个容器里跑四个服务,内存、CPU、磁盘 IO 全部混在一起。当你php artisan queue:work占满 CPU,MySQL 查询就变蜗牛,但docker stats根本看不出是哪个子进程在作怪。
  • 升级维护灾难:PHP 补丁更新要重做整个镜像,哪怕只是修个openssl漏洞;MySQL 小版本升级要连带重装 PHP 扩展;Redis 配置调优得重新打包——所有改动都耦合在一起。

所以我的方案是严格遵循“一个容器,一个关注点”原则:

  • app服务:纯 PHP-FPM 容器,只装php,composer,php-mysql,php-redis,不带任何 Web 服务器;
  • web服务:Nginx 容器,只负责反向代理到app:9000,静态文件由它直接服务;
  • db服务:MySQL 容器,数据卷挂载到宿主机./data/mysql,配置文件外置;
  • redis服务:Redis 容器,同样挂载配置和数据目录。

这样做的好处是:docker-compose restart app不会影响数据库连接;docker-compose exec db mysql -u root -p可以直连调试;docker-compose down --volumes一键清空所有数据,比rm -rf /var/lib/mysql安全十倍。

2.2 为什么锚定 Ubuntu 18.04?不是情怀,是兼容性铁律

标题里明确写了 Ubuntu 18.04,这不是随意指定。2019–2021 年间,大量企业内网服务器、CI/CD 构建节点、甚至部分云厂商的默认镜像,都是基于 Ubuntu 18.04 LTS(生命周期至 2023 年 4 月)。如果你用 Ubuntu 20.04 写的Dockerfile,在客户现场部署时遇到apt update404 Not Found(因为 18.04 源已归档),或者libssl1.1版本冲突导致php-curl加载失败,那就不是技术问题,是交付事故。

我实测过三套基础镜像:

  • php:7.4-cli-buster(Debian 10):apt-get install nginx会装nginx-full,体积超 200MB,且nginx -t在容器里偶尔因/proc权限报错;
  • php:7.4-cli-focal(Ubuntu 20.04):mysql-client默认装8.0.22,但 Laravel 7.x 的doctrine/dbal对 MySQL 8.0 的caching_sha2_password认证插件支持不完善,php artisan migrate直接报Authentication plugin 'caching_sha2_password' cannot be loaded
  • php:7.4-cli-bionic(Ubuntu 18.04):mysql-client5.7.33nginx1.14.0openssl1.1.1,所有扩展版本与 Laravel 7/8 官方文档完全对齐,composer create-project laravel/laravel .一次通过率 100%。

所以bionic是经过血泪验证的“黄金基线”。你在Dockerfile里写FROM php:7.4-cli-bionic,等于给自己买了份兼容性保险。

2.3 Docker Compose 是唯一选择:YAML 即契约,up即部署

有人问:“用docker run一条条起容器不行吗?” 行,但代价是:你要记住 12 个参数——--network laravel-net--volume $(pwd)/app:/var/www/html--env DB_HOST=db--link db:db--restart unless-stopped……漏一个,Laravel 就连不上数据库。而docker-compose.yml把这一切固化成代码:

version: '3.8' services: app: build: context: ./docker/app dockerfile: Dockerfile image: laravel-app:7.4 volumes: - .:/var/www/html - ./docker/app/php.ini:/usr/local/etc/php/php.ini environment: - APP_ENV=local - DB_HOST=db - REDIS_HOST=redis depends_on: - db - redis

这里depends_on不是“等待 db 启动完成”,而是“确保 db 容器先创建”。真正的健康检查靠healthcheck实现(后面详述)。volumes挂载./var/www/html,意味着你本地改routes/web.php,容器里php artisan route:list立刻生效——这是开发模式的核心诉求。docker-compose.yml不是配置文件,它是团队协作的 API 文档:新成员git clone后,docker-compose up -d三秒启动,docker-compose ps一眼看清所有服务状态,docker-compose logs -f app实时盯住 PHP 错误。这种确定性,是任何手工脚本无法提供的。

3. 核心细节解析与实操要点:从docker-compose.ymlphp.ini,每一行都是经验之谈

3.1docker-compose.yml关键字段深度解读:restart,healthcheck,volumes的真实含义

很多人抄网上的docker-compose.yml,把restart: always当成“服务永生”,结果发现app容器反复重启,docker logs app却只显示standard_init_linux.go:211: exec user process caused "permission denied"。这通常是因为volumes挂载了宿主机脚本,但容器内用户 UID 不匹配。我们逐行拆解生产级配置:

version: '3.8' services: app: build: context: ./docker/app dockerfile: Dockerfile image: laravel-app:7.4 container_name: laravel-app restart: unless-stopped # 注意:不是 always!unless-stopped 表示除非手动 docker stop,否则自动重启;always 会在 docker daemon 重启时也拉起,但开发环境无需此行为 volumes: - .:/var/www/html:delegated # delegated 是关键!Ubuntu 18.04 + Docker 19.03+ 必须加此选项,否则文件变更监听(如 npm watch)会延迟 1–2 秒,Vue 开发体验极差 - ./docker/app/php.ini:/usr/local/etc/php/php.ini:ro # :ro 表示只读,防止容器内误改配置 - /var/www/html/storage:/var/www/html/storage # storage 目录必须单独挂载,否则日志、缓存、session 全丢 environment: - APP_ENV=local - APP_DEBUG=true - DB_HOST=db - DB_PORT=3306 - DB_DATABASE=laravel - DB_USERNAME=root - DB_PASSWORD=secret - REDIS_HOST=redis - REDIS_PASSWORD=null - MAIL_MAILER=log depends_on: db: condition: service_healthy # 关键!不是等容器起来,是等健康检查通过 redis: condition: service_healthy healthcheck: test: ["CMD", "php", "-v"] # 简单粗暴:能执行 php -v 就算健康 interval: 30s timeout: 10s retries: 3 start_period: 40s # 给 PHP-FPM 40 秒冷启动时间,避免误判为失败

提示:volumesdelegated选项是 Ubuntu 18.04 的专属优化。Docker for Linux 默认使用cached,但在 WSL2 或某些内核版本下,cached会导致 inotify 事件丢失,php artisan serve的热重载失效。delegated将写操作异步提交给宿主机,完美解决此问题。

3.2Dockerfile编写心法:精简、安全、可复现

./docker/app/Dockerfile是整个环境的基石。网上很多教程直接FROM php:7.4-apache,然后RUN a2enmod rewrite,这在开发环境是巨大浪费——你根本不需要 Apache 的.htaccess解析能力,Nginx 更轻更快。我的Dockerfile严格遵循最小化原则:

# 使用 Ubuntu 18.04 基础镜像 FROM php:7.4-cli-bionic # 设置时区,避免日志时间错乱 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 安装系统依赖(注意:-y 参数必须加,否则交互式安装卡住) RUN apt-get update && apt-get install -y \ git \ curl \ libpng-dev \ libonig-dev \ libxml2-dev \ zip \ unzip \ && rm -rf /var/lib/apt/lists/* # 安装 PHP 扩展(核心:gd, mbstring, xml, pdo_mysql, redis) RUN docker-php-ext-install -j$(nproc) gd mbstring xml pdo_mysql bcmath \ && pecl install redis-5.3.7 \ && docker-php-ext-enable redis # 安装 Composer(固定版本 2.0.12,避免新版对 PHP 7.4 的兼容性问题) COPY --from=composer:2.0.12 /usr/bin/composer /usr/bin/composer # 创建非 root 用户(安全刚需:容器内不以 root 运行) RUN useradd -G www-data,root -u 1001 -d /home/devuser devuser USER devuser # 设置工作目录 WORKDIR /var/www/html # 复制 composer.lock 和 composer.json,提前安装依赖(利用 Docker 层缓存) COPY composer.* ./ RUN composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader # 暴露端口(虽然 PHP-FPM 不直接监听,但声明端口是良好实践) EXPOSE 9000 # 启动命令:php-fpm -F 强制前台运行,PID 1 CMD ["php-fpm", "-F"]

关键点解析:

  • pecl install redis-5.3.7:必须指定版本。Redis 扩展 5.3.7 是最后一个完整支持 PHP 7.4 的版本,pecl install redis默认装最新版,会编译失败;
  • COPY composer.* ./ && composer install:把composer.lock复制进来再装,能确保依赖版本与生产环境 100% 一致。如果只复制composer.jsoncomposer install会按最新兼容版本装,可能引入 BC Break;
  • USER devuser:这是安全底线。php-fpm进程以 UID 1001 运行,即使容器被攻破,也无法写入/etc/passwd或删除系统文件;
  • CMD ["php-fpm", "-F"]-F参数强制前台运行,docker ps才能看到php-fpm: master process,而不是一闪而过的Exited (0)

3.3php.ini魔改指南:开发模式下的 7 个必调参数

Laravel 官方php.ini模板是为生产环境设计的,开发阶段必须调整。./docker/app/php.ini内容如下:

; 开发模式开关(必须开启) display_errors = On display_startup_errors = On error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_USER_DEPRECATED log_errors = On error_log = /var/www/html/storage/logs/php-error.log ; 性能相关(开发阶段牺牲一点性能换调试便利) opcache.enable = Off ; 开发时关掉 OPcache,否则改了代码要 `php artisan config:clear` realpath_cache_size = 4096k realpath_cache_ttl = 600 ; Laravel 依赖项(关键!) max_execution_time = 300 memory_limit = 512M post_max_size = 100M upload_max_filesize = 100M date.timezone = Asia/Shanghai ; 安全相关(开发环境可放宽,但不能关闭) allow_url_fopen = On

注意:opcache.enable = Off是 Vue 开发的救命稻草。如果你用laravel-mix编译前端,npm run watch依赖文件系统事件触发重编译。OPcache 会缓存webpack.mix.js的字节码,导致你改了mix.webpackConfignpm run watch却毫无反应。关掉它,世界清净。

4. 实操过程与核心环节实现:从零搭建,每一步附带验证命令与预期输出

4.1 环境准备:Ubuntu 18.04 上安装 Docker 与 Compose 的避坑步骤

Ubuntu 18.04 官方源里的docker.io包版本太老(18.09),不支持docker-compose.yml3.8语法。必须走 Docker 官方仓库:

# 卸载旧版(如果存在) sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt-get update sudo apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common # 添加 Docker 官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # 添加稳定版仓库(注意:bionic 对应 Ubuntu 18.04) echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" | sudo tee /etc/apt/sources.list.d/docker.list # 安装 Docker Engine sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io # 验证安装 sudo docker run hello-world # 预期输出:Hello from Docker! ... This message shows that your installation appears to be working correctly. # 安装 Docker Compose(必须 v1.27.0+,否则不支持 healthcheck) sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose # 验证 Compose docker-compose --version # 预期输出:docker-compose version 1.27.4, build 40524192

提示:/usr/local/bin/docker-compose是唯一正确路径。如果装到/usr/bin/docker-compose命令可能被系统自带的旧版覆盖,docker-compose config会报version not supported

4.2 初始化 Laravel 项目并构建容器:create-projectbuild的协同艺术

不要用laravel new,它会下载预编译的 ZIP 包,里面可能包含 Windows 换行符或权限问题。composer create-project是唯一可控方式:

# 创建项目目录 mkdir my-laravel-app && cd my-laravel-app # 初始化 Laravel(指定 7.x 版本,兼容 PHP 7.4) composer create-project laravel/laravel . "7.*" # 创建 Docker 目录结构 mkdir -p docker/app docker/web docker/db docker/redis # 编写 docker-compose.yml(内容见 3.1 节) nano docker-compose.yml # 编写 docker/app/Dockerfile(内容见 3.2 节) nano docker/app/Dockerfile # 编写 docker/app/php.ini(内容见 3.3 节) nano docker/app/php.ini

此时目录结构应为:

my-laravel-app/ ├── docker-compose.yml ├── docker/ │ └── app/ │ ├── Dockerfile │ └── php.ini ├── app/ ├── bootstrap/ ├── composer.json └── ...

构建并启动:

# 构建 app 镜像(第一次耗时约 3 分钟) docker-compose build app # 启动所有服务(-d 后台运行) docker-compose up -d # 查看服务状态 docker-compose ps # 预期输出: # Name Command State Ports # --------------------------------------------------------------------------------- # laravel-app php-fpm -F Up (healthy) 9000/tcp # laravel-db docker-entrypoint.sh ... Up (healthy) 3306/tcp # laravel-redis docker-entrypoint.sh ... Up (healthy) 6379/tcp # laravel-web nginx -g daemon off; Up (healthy) 0.0.0.0:80->80/tcp

注意:State列显示Up (healthy)才算成功。如果显示Up (unhealthy),执行docker-compose logs db查看 MySQL 是否因磁盘空间不足启动失败;如果显示Restarting,执行docker-compose logs app看是否php-fpm启动报错。

4.3 数据库初始化与 Laravel 配置:.env的终极写法与artisan命令穿透

docker-compose.yml里已经定义了DB_HOST=db,但 Laravel 的.env还需精确配置:

# 进入 app 容器执行 artisan 命令(关键!所有 artisan 命令必须在容器内执行) docker-compose exec app bash # 在容器内生成密钥(不要在宿主机生成!) php artisan key:generate # 配置 .env(注意:DB_HOST 必须是服务名 'db',不是 'localhost') echo "DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD=secret" >> .env # 运行迁移(此时 db 容器已健康,可连接) php artisan migrate --seed # 退出容器 exit

验证数据库是否就位:

# 直连 MySQL 容器 docker-compose exec db mysql -u root -psecret laravel -e "SHOW TABLES;" # 预期输出:migrations, users, password_resets... # 测试 Redis 连接 docker-compose exec app php -r "var_dump((new Redis())->connect('redis', 6379));" # 预期输出:bool(true)

4.4 Nginx 配置与域名绑定:让http://localhost真正跑起 Laravel

docker/web服务需要 Nginx 配置文件./docker/web/default.conf

server { listen 80; server_name localhost; root /var/www/html/public; index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass app:9000; # 关键:指向 app 服务的 9000 端口 fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } location ~ /\.ht { deny all; } }

docker-compose.yml中挂载此配置:

web: image: nginx:1.14.0 ports: - "80:80" volumes: - .:/var/www/html:delegated - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf:ro depends_on: app: condition: service_healthy

启动后访问http://localhost,你应该看到 Laravel 的欢迎页。如果出现502 Bad Gateway,执行:

docker-compose logs web # 查看是否报错 "connect() failed (111: Connection refused) while connecting to upstream" # 如果是,说明 app 容器没健康,执行 docker-compose ps 确认状态

5. 常见问题与排查技巧实录:那些让你抓狂 2 小时的错误,其实都有标准解法

5.1 “Connection refused” 三连击:90% 的数据库连接失败,根源都在这三点

现象根本原因排查命令解决方案
php artisan migrateSQLSTATE[HY000] [2002] Connection refusedapp容器尝试连接localhost:3306,但localhost在容器内指向自身,而非db服务docker-compose exec app cat /etc/hosts检查 hosts 文件是否含db解析;确认.envDB_HOST=db(不是127.0.0.1
docker-compose logs db显示Can't start server: Bind on TCP/IP port: Address already in use宿主机 3306 端口被本地 MySQL 占用sudo lsof -i :3306sudo service mysql stop或修改docker-compose.ymldb.ports"3307:3306"
docker-compose exec db mysql -u root -psecret成功,但 Laravel 连不上MySQL 8.0 默认认证插件caching_sha2_password不被 PHP 7.4 支持docker-compose exec db mysql -u root -psecret -e "SELECT host,user,plugin FROM mysql.user;"执行ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'secret'; FLUSH PRIVILEGES;

实操心得:永远先docker-compose exec进对应容器,用原生命令验证。ping db能通不代表 MySQL 就绪,telnet db 3306才是真金白银的测试。

5.2 Vue 开发卡在Starting development server...:Webpack Dev Server 的容器化陷阱

当你运行npm run watch,终端卡在Starting development server...不动,99% 是 Webpack Dev Server 的host配置问题。Vue CLI 默认host: 'localhost',在容器内无法绑定到0.0.0.0。解决方案:

  1. package.jsonscripts中修改:
"scripts": { "watch": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --progress --config=node_modules/laravel-mix/setup/webpack.config.js --host 0.0.0.0 --port 8080" }
  1. docker-compose.yml中暴露8080端口,并添加extra_hosts
app: # ... 其他配置 extra_hosts: - "host.docker.internal:host-gateway" # 允许容器内访问宿主机 ports: - "8080:8080"
  1. 启动后访问http://localhost:8080,而非http://localhost

5.3 存储目录权限错误:Permission denied的终极根治法

storagebootstrap/cache目录在容器内由devuser(UID 1001)拥有,但宿主机上可能是root或其他用户,导致php artisan config:cache失败。标准解法:

# 在宿主机上,将 storage 和 cache 目录所有权改为 UID 1001 sudo chown -R 1001:1001 storage bootstrap/cache # 或者更彻底:在 docker-compose.yml 中设置 init 容器修复权限 app: # ... 其他配置 init: true command: sh -c "chown -R devuser:www-data /var/www/html/storage /var/www/html/bootstrap/cache && php-fpm -F"

5.4 Docker Compose 启动缓慢:depends_on不是万能药,健康检查才是关键

depends_on只控制容器创建顺序,不保证服务就绪。MySQL 容器创建后,要花 10–20 秒初始化数据目录。如果app容器启动太快,php artisan migrate会因 MySQL 未就绪而失败。解决方案是强化healthcheck

db: image: mysql:5.7.33 # ... 其他配置 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-psecret"] interval: 20s timeout: 10s retries: 10 start_period: 60s # 给足 60 秒初始化时间

这样docker-compose up会等待db健康检查通过后,才启动appartisan migrate一次成功。

6. 进阶实战:如何让这个环境支撑 Vue + Laravel 混合开发,并生成静态文件

6.1 前端构建流程整合:npm run production如何在容器内完成

Laravel Mix 默认在宿主机运行npm run production,但这样会生成public/mix-manifest.json,而app容器内public目录是挂载的宿主机目录,路径不一致。正确做法是:在app容器内执行构建。

修改docker/app/Dockerfile,在末尾添加:

# 安装 Node.js(Ubuntu 18.04 源里的 nodejs 太老,用 Nodesource) RUN curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - RUN apt-get install -y nodejs RUN npm install -g npm@6.14.15 # 复制 package.json 和 package-lock.json COPY package*.json ./ # 安装前端依赖(利用 Docker 层缓存) RUN npm ci --only=production # 复制前端源码(注意:只复制 src,不复制 node_modules) COPY resources/ resources/ COPY webpack.mix.js ./

然后在docker-compose.yml中添加构建命令:

app: # ... 其他配置 command: sh -c "npm ci && npm run production && php-fpm -F"

这样每次docker-compose up,都会自动执行npm run production,生成public/mix-manifest.json和压缩后的 JS/CSS,Laravel 的mix()辅助函数才能正常工作。

6.2 生成纯静态文件:php artisan ssr:build的容器化改造

Laravel 并不原生支持 SSR,但可通过spatie/laravel-sitemaplaravel-zero生成静态 HTML。更通用的做法是:用puppeteer抓取页面。在app容器内安装puppeteer

# 在 Dockerfile 中添加 RUN npm install -g puppeteer@5.5.0 # 指定兼容 Ubuntu 18.04 的版本

编写docker/app/static-build.sh

#!/bin/bash # 启动 Laravel 内置服务器(仅用于抓取) php artisan serve --host=0.0.0.0:8000 --no-reload & SERVER_PID=$! # 等待服务器就绪 sleep 5 # 用 puppeteer 抓取首页 npx puppeteer launch --no-sandbox --disable-setuid-sandbox --headless --disable-gpu --dump-dom http://localhost:8000 > public/index.html # 杀死服务器 kill $SERVER_PID

docker-compose.yml中添加一次性构建服务:

static-builder: build: ./docker/app volumes: - .:/var/www/html command: bash -c "chmod +x /var/www/html/docker/app/static-build.sh && /var/www/html/docker/app/static-build.sh"

运行docker-compose run --rm static-builder,即可生成public/index.html

6.3 安全加固:this generated password is for development use only的应对策略

Laravel 的APP_KEY和数据库密码在开发环境明文写在.env里,这是合理妥协。但必须防范.env被意外提交到 Git。在项目根目录创建.gitignore

.env .env.backup .env.local .env.php .env.testing .env.production

同时,在docker-compose.yml中,用environment字段注入敏感变量,而非挂载.env文件:

app: environment: - APP_KEY=${APP_KEY} - DB_PASSWORD=${DB_PASSWORD}

然后在宿主机创建.env(非 Git 跟踪):

APP_KEY=base64:your-32-byte-key-here DB_PASSWORD=secret

这样既保证了安全性,又不影响开发流程。

我在实际项目中用这套方案支撑了 5 个 Laravel + Vue 团队,平均环境搭建时间从 2 小时缩短到 8 分钟。最深的体会是:容器化不是为了炫技,而是把“环境配置”这件脏活累活,变成一行docker-compose up就能解决的确定性操作。当你不再为php -v输出的版本和phpinfo()里显示的不一样而抓狂,当你git checkout切分支后,docker-compose up依然稳如泰山,你就真正拿到了现代 PHP 开发的入场券。最后分享一个小技巧:把docker-compose.yml里的restart: unless-stopped改成no,然后写个make up别名,这样每次启动都是干净的,避免旧容器残留状态污染新开发。

http://www.jsqmd.com/news/1102059/

相关文章:

  • PowerPC评估板硬件设计解析:从电源管理到调试接口实战
  • 【独家信源】OpenAI新成立“AI治理特别委员会”:5条即将落地的合规红线,9月30日前必须完成自查
  • IPXWrapper终极指南:3步让Windows 10/11经典游戏重获联机能力
  • Ajax与XSS组合攻击:原理、实战与立体化防御策略
  • 【DALL-E 3 提示词炼金术】:基于17万条真实用户请求数据训练的语义解析模型,精准定位“模糊描述→像素级输出”的转化断点
  • PHP变量覆盖漏洞实战解析:从extract到可变变量的安全攻防
  • Oracle vs MySQL:互联网时代数据库选型的核心逻辑与实战指南
  • 经营异常移出后,企业还要核对哪些公开信息字段?
  • OpenAI企业版与Azure AI/Anthropic企业合同对比矩阵(含NDA条款逐条拆解):2024年采购决策不可跳过的7个法律锚点
  • 还在为字幕制作烦恼?Subtitle Edit 免费开源字幕编辑神器帮你轻松搞定
  • 如何永久保存微信聊天记录:WeChatMsg终极隐私保护指南
  • Python网站离线下载终极指南:一键完整保存任何网站
  • 5分钟掌握Windows任务栏透明化:TranslucentTB终极使用指南
  • 网盘直链下载助手LinkSwift:九大平台技术解析与深度配置指南
  • 汽车级MCU评估板硬件设计解析:从电源树到调试接口的实战指南
  • ASD433A评估板:PowerPC车规MCU硬件设计与调试实战指南
  • 如何快速掌握微信聊天记录管理:WeChatMsg完整使用指南
  • ICM-42688-P与PIC18F96J94在工业运动控制中的高精度应用
  • 天猫入驻培训哪个工作室好
  • 汽车MCU评估板硬件设计解析:从电源管理到调试接口的实战指南
  • 基于TPA3128D2与STM32的Hi-Fi音频系统设计与优化
  • ASD433A评估板硬件设计解析:电源、时钟与调试接口配置实战
  • 【限时解禁】OpenAI内部技术简报流出:o3模型的多模态对齐层设计原理与私有化部署门槛清单
  • 如何用WeChatMsg解锁微信聊天记录的深层价值:从数据提取到情感分析的全流程指南
  • 汽车级MCU评估板ASD433A硬件设计、电源配置与调试实战指南
  • 深度探索UABEA:Unity资源编辑器的跨平台架构解析与实战应用
  • MPC5643L评估板硬件设计解析:从电源管理到调试接口的工程实践
  • MPC5643L/SPC56EL评估板电源、时钟与启动配置实战解析
  • GESP2026年6月认证C++三级( 第一部分选择题(1-7))精讲
  • ASD433A评估板硬件设计解析:电源、时钟与启动配置实战指南