使用容器进行 PHP 开发

先决条件

完成 容器化 PHP 应用程序

概述

在本节中,你将学习如何为你的容器化应用程序设置开发环境。这包括

  • 添加本地数据库并持久化数据
  • 添加 phpMyAdmin 来与数据库交互
  • 配置 Compose 在你编辑和保存代码时自动更新正在运行的 Compose 服务
  • 创建一个包含开发依赖项的开发容器

添加本地数据库并持久化数据

你可以使用容器来设置本地服务,例如数据库。要为此示例应用程序执行此操作,你需要执行以下操作

  • 更新 `Dockerfile` 以安装连接到数据库的扩展
  • 更新 `compose.yaml` 文件以添加数据库服务和卷以持久化数据

更新 Dockerfile 以安装扩展

要安装 PHP 扩展,你需要更新 `Dockerfile`。在 IDE 或文本编辑器中打开你的 Dockerfile,然后更新内容。以下 `Dockerfile` 包含一行新代码,用于安装 `pdo` 和 `pdo_mysql` 扩展。所有注释都已删除。

# syntax=docker/dockerfile:1

FROM composer:lts as deps
WORKDIR /app
RUN --mount=type=bind,source=composer.json,target=composer.json \
    --mount=type=bind,source=composer.lock,target=composer.lock \
    --mount=type=cache,target=/tmp/cache \
    composer install --no-dev --no-interaction

FROM php:8.2-apache as final
RUN docker-php-ext-install pdo pdo_mysql
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY --from=deps app/vendor/ /var/www/html/vendor
COPY ./src /var/www/html
USER www-data

有关安装 PHP 扩展的更多详细信息,请参阅 PHP 的官方 Docker 镜像

更新 compose.yaml 文件以添加数据库和持久化数据

在 IDE 或文本编辑器中打开 `compose.yaml` 文件。你会注意到它已经包含了 PostgreSQL 数据库和卷的注释掉的指令。对于此应用程序,你将使用 MariaDB。有关 MariaDB 的更多详细信息,请参阅 MariaDB 官方 Docker 镜像

在 IDE 或文本编辑器中打开 `src/database.php` 文件。你会注意到它读取环境变量以连接到数据库。

在 `compose.yaml` 文件中,你需要更新以下内容:

  1. 取消注释并更新 MariaDB 的数据库指令。
  2. 向服务器服务添加一个密钥以传入数据库密码。
  3. 向服务器服务添加数据库连接环境变量。
  4. 取消注释卷指令以持久化数据。

以下是更新后的 `compose.yaml` 文件。所有注释都已删除。

services:
  server:
    build:
      context: .
    ports:
      - 9000:80
    depends_on:
      db:
        condition: service_healthy
    secrets:
      - db-password
    environment:
      - PASSWORD_FILE_PATH=/run/secrets/db-password
      - DB_HOST=db
      - DB_NAME=example
      - DB_USER=root
  db:
    image: mariadb
    restart: always
    user: root
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/mysql
    environment:
      - MARIADB_ROOT_PASSWORD_FILE=/run/secrets/db-password
      - MARIADB_DATABASE=example
    expose:
      - 3306
    healthcheck:
      test:
        [
          "CMD",
          "/usr/local/bin/healthcheck.sh",
          "--su-mysql",
          "--connect",
          "--innodb_initialized",
        ]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  db-data:
secrets:
  db-password:
    file: db/password.txt

注意

要了解有关 Compose 文件中指令的更多信息,请参阅 Compose 文件参考

在使用 Compose 运行应用程序之前,请注意此 Compose 文件使用 `secrets` 并指定一个 `password.txt` 文件来保存数据库的密码。你必须创建此文件,因为它不包含在源代码库中。

在 `docker-php-sample` 目录中,创建一个名为 `db` 的新目录,并在该目录中创建一个名为 `password.txt` 的文件。在 IDE 或文本编辑器中打开 `password.txt` 并添加以下密码。密码必须在一行上,文件中没有其他行。

example

保存并关闭 `password.txt` 文件。

现在你的 `docker-php-sample` 目录中应该包含以下内容。

├── docker-php-sample/
│ ├── .git/
│ ├── db/
│ │ └── password.txt
│ ├── src/
│ ├── tests/
│ ├── .dockerignore
│ ├── .gitignore
│ ├── compose.yaml
│ ├── composer.json
│ ├── composer.lock
│ ├── Dockerfile
│ ├── README.Docker.md
│ └── README.md

运行以下命令来启动你的应用程序。

$ docker compose up --build

打开浏览器,在 https://127.0.0.1:9000/database.php 查看应用程序。你应该会看到一个简单的 Web 应用程序,其中包含文本和一个计数器,每次刷新时都会递增。

按终端中的 `ctrl+c` 停止你的应用程序。

验证数据是否持久存储在数据库中

在终端中,运行 `docker compose rm` 删除你的容器,然后运行 `docker compose up` 再次运行你的应用程序。

$ docker compose rm
$ docker compose up --build

刷新 https://127.0.0.1:9000/database.php 并验证之前的计数是否仍然存在。如果没有卷,则删除容器后数据库数据不会持久化。

按终端中的 `ctrl+c` 停止你的应用程序。

添加 phpMyAdmin 来与数据库交互

你可以通过更新 `compose.yaml` 文件轻松地向你的应用程序堆栈添加服务。

更新你的 `compose.yaml` 以添加 phpMyAdmin 的新服务。有关更多详细信息,请参阅 phpMyAdmin 官方 Docker 镜像。以下是更新后的 `compose.yaml` 文件。

services:
  server:
    build:
      context: .
    ports:
      - 9000:80
    depends_on:
      db:
        condition: service_healthy
    secrets:
      - db-password
    environment:
      - PASSWORD_FILE_PATH=/run/secrets/db-password
      - DB_HOST=db
      - DB_NAME=example
      - DB_USER=root
  db:
    image: mariadb
    restart: always
    user: root
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/mysql
    environment:
      - MARIADB_ROOT_PASSWORD_FILE=/run/secrets/db-password
      - MARIADB_DATABASE=example
    expose:
      - 3306
    healthcheck:
      test:
        [
          "CMD",
          "/usr/local/bin/healthcheck.sh",
          "--su-mysql",
          "--connect",
          "--innodb_initialized",
        ]
      interval: 10s
      timeout: 5s
      retries: 5
  phpmyadmin:
    image: phpmyadmin
    ports:
      - 8080:80
    depends_on:
      - db
    environment:
      - PMA_HOST=db
volumes:
  db-data:
secrets:
  db-password:
    file: db/password.txt

在终端中,运行 `docker compose up` 再次运行你的应用程序。

$ docker compose up --build

在浏览器中打开https://127.0.0.1:8080访问 phpMyAdmin。使用用户名root和密码example登录。现在您可以通过 phpMyAdmin 与数据库交互。

按终端中的 `ctrl+c` 停止你的应用程序。

自动更新服务

使用 Compose Watch 在您编辑并保存代码时自动更新正在运行的 Compose 服务。有关 Compose Watch 的更多详细信息,请参阅使用 Compose Watch

在 IDE 或文本编辑器中打开您的compose.yaml文件,然后添加 Compose Watch 指令。以下是更新后的compose.yaml文件。

services:
  server:
    build:
      context: .
    ports:
      - 9000:80
    depends_on:
      db:
        condition: service_healthy
    secrets:
      - db-password
    environment:
      - PASSWORD_FILE_PATH=/run/secrets/db-password
      - DB_HOST=db
      - DB_NAME=example
      - DB_USER=root
    develop:
      watch:
        - action: sync
          path: ./src
          target: /var/www/html
  db:
    image: mariadb
    restart: always
    user: root
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/mysql
    environment:
      - MARIADB_ROOT_PASSWORD_FILE=/run/secrets/db-password
      - MARIADB_DATABASE=example
    expose:
      - 3306
    healthcheck:
      test:
        [
          "CMD",
          "/usr/local/bin/healthcheck.sh",
          "--su-mysql",
          "--connect",
          "--innodb_initialized",
        ]
      interval: 10s
      timeout: 5s
      retries: 5
  phpmyadmin:
    image: phpmyadmin
    ports:
      - 8080:80
    depends_on:
      - db
    environment:
      - PMA_HOST=db
volumes:
  db-data:
secrets:
  db-password:
    file: db/password.txt

运行以下命令以使用 Compose Watch 运行您的应用程序。

$ docker compose watch

打开浏览器并验证应用程序是否正在https://127.0.0.1:9000/hello.php运行。

现在,您本地机器上应用程序源文件的任何更改都将立即反映在正在运行的容器中。

在 IDE 或文本编辑器中打开hello.php,并将字符串Hello, world!更新为Hello, Docker!

保存对hello.php的更改,然后等待几秒钟以使应用程序同步。刷新https://127.0.0.1:9000/hello.php,并验证更新后的文本是否出现。

在终端中按ctrl+c停止 Compose Watch。在终端中运行docker compose down以停止应用程序。

创建开发容器

此时,当您运行容器化应用程序时,Composer 不会安装开发依赖项。虽然这个小型镜像适合生产环境,但它缺少您在开发时可能需要的工具和依赖项,并且不包含tests目录。您可以使用多阶段构建在同一个 Dockerfile 中为开发和生产构建阶段。有关更多详细信息,请参阅多阶段构建

Dockerfile中,您需要更新以下内容

  1. deps阶段拆分为两个阶段。一个阶段用于生产 (prod-deps),另一个阶段 (dev-deps) 用于安装开发依赖项。
  2. 创建一个通用的base阶段。
  3. 为开发创建一个新的development阶段。
  4. 更新final阶段以从新的prod-deps阶段复制依赖项。

以下是更改前后的Dockerfile


# syntax=docker/dockerfile:1

FROM composer:lts as deps
WORKDIR /app
RUN --mount=type=bind,source=composer.json,target=composer.json \
    --mount=type=bind,source=composer.lock,target=composer.lock \
    --mount=type=cache,target=/tmp/cache \
    composer install --no-dev --no-interaction

FROM php:8.2-apache as final
RUN docker-php-ext-install pdo pdo_mysql
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY --from=deps app/vendor/ /var/www/html/vendor
COPY ./src /var/www/html
USER www-data
# syntax=docker/dockerfile:1

FROM composer:lts as prod-deps
WORKDIR /app
RUN --mount=type=bind,source=./composer.json,target=composer.json \
    --mount=type=bind,source=./composer.lock,target=composer.lock \
    --mount=type=cache,target=/tmp/cache \
    composer install --no-dev --no-interaction

FROM composer:lts as dev-deps
WORKDIR /app
RUN --mount=type=bind,source=./composer.json,target=composer.json \
    --mount=type=bind,source=./composer.lock,target=composer.lock \
    --mount=type=cache,target=/tmp/cache \
    composer install --no-interaction

FROM php:8.2-apache as base
RUN docker-php-ext-install pdo pdo_mysql
COPY ./src /var/www/html

FROM base as development
COPY ./tests /var/www/html/tests
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
COPY --from=dev-deps app/vendor/ /var/www/html/vendor

FROM base as final
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY --from=prod-deps app/vendor/ /var/www/html/vendor
USER www-data

通过添加一条指令来定位开发阶段,更新您的compose.yaml文件。

以下是compose.yaml文件的更新部分。

services:
  server:
    build:
      context: .
      target: development
      # ...

您的容器化应用程序现在将安装开发依赖项。

运行以下命令来启动你的应用程序。

$ docker compose up --build

打开浏览器并在https://127.0.0.1:9000/hello.php查看应用程序。您仍然应该看到简单的“Hello, Docker!”应用程序。

按终端中的 `ctrl+c` 停止你的应用程序。

虽然应用程序看起来相同,但您现在可以使用开发依赖项。继续下一节,了解如何使用 Docker 运行测试。

总结

在本节中,您了解了如何设置 Compose 文件以添加本地数据库并持久化数据。您还学习了如何在更新代码时使用 Compose Watch 自动同步应用程序。最后,您学习了如何创建包含开发所需依赖项的开发容器。

相关信息

后续步骤

下一节,您将学习如何使用 Docker 运行单元测试。