将 Docker 用于多个 php 应用程序

Posted

技术标签:

【中文标题】将 Docker 用于多个 php 应用程序【英文标题】:Using Docker for multiple php applications 【发布时间】:2020-03-21 06:44:39 【问题描述】:

我最近从 Wamp(wampserver)迁移到 Docker(Windows 主机)。在使用 wamp 时,我能够拥有多个项目,例如以下文件结构

- wamp64
  - www/
    - project1/ 
    - project2/
    - ....

在 wamp 的 Apache 上,我定义了几个虚拟主机,所有项目都使用 wamp 的数据库,每个都有自己的架构。

因此,在必要时从project1project2project3 等切换上下文是很常见的。 通过访问http://localhost/projectX 之类的网址或相应的虚拟主机。

正如我目前所见,这在 Docker 上似乎并不那么简单。 我的第一种方法是在每个项目上设置不同的 Docker

- www/
  - project1/
       - dockerfile & docker-compose
  - project2/
       - dockerfile & docker-compose
  - projectX/
       - dockerfile & docker-compose
- data // this is where mysql data lie

我认为与我过去使用 wamp 相比,这似乎不太有效,因为每次我想更改上下文时,我都必须使用我目前正在工作的项目 docker-compose stopdocker-compose up我想切换到的项目,反之亦然。

我尝试了另一种方法,在单个 apache-php 容器(整个 www 文件夹)中运行所有项目

- www/
    dockerfile & docker-compose
    - project1/
    - project2/

这可以让我一次获得所有项目,但是使用这种方法,我面临两个严重的问题。

    docker build 耗时太长,可能是因为文件数量增加,而不是单个项目的数量减少 我无法在 mysql 中初始化一个以上的数据库模式,因此即使我设法让 2 或 3 个项目运行,也只有 1 个能够与相应的数据库通信。

我在第一种方法中的 docker-compose 文件看起来像这样

version: '3'

services:

  project1:
    build:
      context: . // contents of specific project directory
      dockerfile: .docker/Dockerfile

    image: project1

    ports:
      – 80:80

    volumes:
      – .:/app/project1

   links:
      – mysql

  mysql:

    image: mysql:5.7

    ports:
      – 13306:3306

    environment:

      MYSQL_DATABASE: docker
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      MYSQL_ROOT_PASSWORD: docker

    volumes:
      - ../data:var/lib/mysql

而我在第二种方法中的 docker-compose 文件看起来像这样

version: '3'

services:

  web-project:
    build:
      context: . // contents of www directory
      dockerfile: .docker/Dockerfile

    image: web-project

    ports:
      – 80:80

    volumes:
      – /project1:/app/project1
      – /project2:/app/project2
      – /projectX:/app/projectX

   links:
      – mysql

  mysql:

    image: mysql:5.7

    ports:
      – 13306:3306

    volumes:
      - /data:var/lib/mysql

mysql 数据的引用持久化Docker-Compose persistent data MySQL

【问题讨论】:

您是否为每次代码更改重新构建 Docker 映像?如果是这样,您可以使用开发中的卷来缓解这种情况。 为什么必须停止一个 Docker 项目并启动另一个单端口冲突? 您希望从使用 Docker 中获得哪些具体好处?您能否将工作中的非 Docker 设置用于日常开发,而仅将 Docker 设置用于生产部署? @DavidMaze 我最初从 Wamp 迁移到 Docker,因为我遇到了关于 memcache 扩展和 PHP 7.3 的不兼容问题。由于我的生产环境使用 LAMP 环境,我认为将本地设置与生产设置尽可能接近更合适 @halfer 似乎为单个项目了解 Docker 不同于在不同项目中使用它。我显然做错了什么,这就是我开始这个线程的原因,因为有一些可行的方法可以改进我使用 Docker 的方式。 【参考方案1】:

我认为对您来说最好的解决方案是在其自己的容器中运行每个项目。由于容器(应该)是轻量级的并且易于上下移动,因此这样做的开销应该是最小的。

我将展示的内容与第一种方法的不同之处在于 docker-compose 文件将为您编排您的容器。因此,它应该允许您的所有容器(项目)同时与您的数据库进行通信。 (鉴于您的项目不会不断地相互覆盖,并导致死锁)

文件夹结构:

- www/
    docker-compose.yml
    - project1/
      Dockerfile
    - project2/
      Dockerfile

Docker 编写

version: '3'
services:
  project1:
    build:
      context: /project1 #automatically finds Dockerfile
    container_name: project1
    ports:
      – 8081:80
    volumes:
      – .:/app/project
   links:
      – mysql
  project2:
    build:
      context: /project2 #automatically finds Dockerfile
    container_name: project2
    ports:
      – 8082:80
    volumes:
      – .:/app/project
   links:
      – mysql
  ...
  mysql:
    image: mysql:5.7
    ports:
      – 13306:3306
    volumes:
      - /data:var/lib/mysql

然后当你运行docker-compose up 时,它会在同一个网络中调出两个项目容器和一个数据库容器。请注意,每个项目都在其自己的端口上运行。所以你需要记住哪个端口链接到哪个容器。

【讨论】:

可以使用 Traefik 代理扩展上述设置,并在每个 Web 项目服务上使用标签,以在您选择的特定主机名上公开它们。我有这个在我自己的本地设置上运行。 现在已经快午夜了,所以我会在早上回到这里并给您发送一个想法,这样您就不必记住端口,并且可以根据需要使用特定的主机名。 我收到一条错误消息“无法找到指定的 Dockerfile:Dockerfile”,即使我明确指定了 .docker/Docker 文件位置 我包含了 dockerfile 指令并且构建工作正常! 回顾您的问题陈述,我确实错过了您将 dockerfile 保存在 .docker/Dockerfile 中的事实。你可以为每个项目使用一个共享的 Dockerfile,我仍然会使用 context 指令来明确每个容器卷都在它自己的目录中。 我同意,虽然它可以自动找到自己的 Dockerfile,但我认为出于维护等原因使用该指令更清楚。【参考方案2】:

创建一个***文件夹并将其放入 Dockerfile 在里面

FROM webdevops/php-apache-dev:7.2

# Add microsoft SQL support to PHP

# add microsoft packages to apt sources
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list
# install needed system packages as well as a few nice to have utils
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
  DEBIAN_FRONTEND=noninteractive apt-get -y upgrade && \
  ACCEPT_EULA=Y apt-get -y install msodbcsql17 unixodbc-dev less joe iputils-ping traceroute telnet && \
  apt-get purge -y --auto-remove && \
  rm -rf /var/lib/apt/lists/*
# install sqlsrv php extensions
RUN pecl install sqlsrv pdo_sqlsrv
# load the pdo extension 
RUN echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini
# load the mssql extension 
RUN echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini

# our docroot
WORKDIR /app

在***文件夹中运行以下命令:

docker build -t myphpdev:latest 。 -f Dockerfile

现在在同一个***文件夹中创建一个 docker-compose.yml 并将以下内容放入其中:

version: '3'
services:
  web_debug:
    image: myphpdev:latest
    ports:
      - 1080:80
    volumes:
      - .:/app
    environment:
      - PHP_XDEBUG_ENABLED=1
      - PHP_DATE_TIMEZONE="America/Los_Angeles"
      - PHP_MEMORY_LIMIT="512M"
      - PHP_MAX_EXECUTION_TIME="600"
      - PHP_MAX_INPUT_TIME="60"
      - PHP_POST_MAX_SIZE="512M"
      - PHP_UPLOAD_MAX_FILESIZE="512M"
      - PHP_ERROR_REPORTING="E_ALL & ~E_DEPRECATED & ~E_STRICT"
      - PHP_DISPLAY_ERRORS="1"
      - PHP_DISPLAY_STARTUP_ERRORS="1"
      - PHP_DEBUGGER="xdebug"
      - XDEBUG_CONFIG=remote_host=host.docker.internal

  mysql:
    image: mysql:5.7
    ports:
      - 13306:3306
    volumes:
      - ./data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password

# if you get errors about invalid or needing to use absolute paths
# you may need to down your stack then run the next line then up the stack
# SET COMPOSE_CONVERT_WINDOWS_PATHS=1

在同一个***文件夹中,为您的数据库持久性创建一个名为 data 的文件夹,并为每个站点创建一个文件夹。每个站点将在 http://localhost:1080/site_folder

根据需要调整/添加任何 PHP_ env vars 图像将在出现时根据 env vars 更新 php.ini。

以这种方式运行时,每个站点都必须使用相对链接而不是绝对链接进行设置,并且它们都将共享同一个数据库实例。

最少的资源密集配置是让每个站点共享同一个数据库实例,并让每个站点在实例上拥有自己的数据库。如果由于某种原因所有站点都必须使用相同的数据库名称,您也可以使用表前缀。

如果你不介意额外的资源使用,你可以复制 mysql 块,确保你有一个唯一的端口号和数据文件夹,并为每个站点打开一个完全独立的数据库服务器。

在容器内安装主机将允许您从主机端编辑站点文件夹的内容,并使用 xdebug 进行实时调试,而无需在每次想要迭代或上下文切换时重新构建您的 docker 环境。

如果您不想在站点中使用相对链接,您还可以通过添加一些 Apache 配置来设置虚拟主机,方法是将配置安装到 /opt/docker/etc/httpd/vhost.common.d/

查看 Dockerfile 中引用的图像的文档。它们在 php 版本的 Web 服务器和基本操作系统以及开发与生产设置方面有大量的变化。我在下面提供了他们文档的链接。

WebDevOps ApachePHP Docker Docs

【讨论】:

嗨,Paul,这个设置中的 my.docker/Dockerfile 在哪里?我没有看到它在任何地方被引用 此设置允许您在 IDE 中使用原始文件夹。不需要 docker 文件重建来迭代。这就是让它如此之快的原因。如果您确实需要自定义 docker 环境,您可以构建和标记您的 docker 映像,然后用您的替换 compose 文件中引用的映像,并且仍然将文件夹安装到您的映像上以进行快速迭代,而无需每次编辑文件时都重新构建。这有意义吗? 我在最初的问题中没有提到,在我的 docker 文件中,我为 php 安装了一些额外的模块,如 pdo mysql memcache 等。如果不包含 docker 文件,这些将如何初始化? 撰写文件中的图像几乎启用了每个 php 模块。如果它缺少你需要的,那么你将不得不使用我在之前的评论中提到的构建和标记方法。如果您不清楚这将如何工作,我可以更新我的答案以展示它的外观/工作方式。 如果您能更新 Paul 的回复,我将不胜感激,这可能对我或其他面临类似问题的人有用【参考方案3】:

Kyle 的回答我会非常小心。考虑这个例子

./project1/Dockerfile
./project2/Dockerfile
./shared.php

根据他的建议,您将无法在./project1/Dockerfile./project2/Dockerfile 中使用shared.php

所以不是

build:
  context: /project1 #automatically finds Dockerfile

做事

build:
  context: .
  dockerfile: ./project1/Dockerfile

这告诉系统可能包含共享文件的context文件夹与Dockerfile所在的文件夹不同,这是一个非常有用的分隔。

更多关于上下文的细节在这里https://***.com/a/53298876/1907888

【讨论】:

以上是关于将 Docker 用于多个 php 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

将 ehcache 用于通过 docker 部署的应用程序,违反无状态规则

Docker Compose安装使用,及搭建nginx+php+mysql基础应用实例

使用 Docker 同时运行多个 Web 开发环境

用于 mysql 的多个 docker 容器或具有多个数据库的一个实例

如何为多个PHP-FPM容器构建单一的Nginx Docker镜像

docker ERROR:对于 nginx 无法启动服务 nginx:驱动程序在编程外部连接时失败