使用docker多阶段构建来运行composer安装并将应用程序复制到PHP容器镜像中

571 阅读2分钟

在这个例子中,我们将运行 composer 来安装应用程序的依赖性,然后将vendor 文件夹和其余的应用程序文件复制到容器镜像中。通过这种方式,我们的镜像将总是默认带有应用程序,所以我们所要做的就是创建一个容器并开始使用它。这是一个众所周知的做法,但我只想谈谈一个基本的实现。其主要目的是隔离应用程序代码,不将其暴露在主机操作系统上。我不打算在这里列举这些好处,因为它们都已经在互联网上写过了。这个解决方案的主要问题是,最终的docker镜像的大小将取决于应用程序和vendor 文件夹的大小。

结构

.
├── composer.json
├── docker
│   ├── docker-compose.yml
│   ├── Makefile
│   └── php
│       ├── Dockerfile
│       ├── php.ini
│       └── www.conf
├── .dockerignore
├── .gitignore
└── src
    └── index.php

文件

我只是展示了重要文件的内容。其余的就不太重要了。

Makefile

build:
	@docker-compose build

up:
	@docker-compose up -d

Docker文件

#
# STAGE 1: composer
#
FROM composer:1.8.5 as composer

# Copy composer files from project root into composer container's working dir
COPY composer.* /app/

# Run composer to build dependencies in vendor folder
RUN set -xe \
 && composer install --no-dev --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader

# Copy everything from project root into composer container's working dir
COPY . /app

# Generated optimized autoload files containing all classes from vendor folder and project itself
RUN composer dump-autoload --no-dev --optimize --classmap-authoritative

#
# STAGE 2: php
#
FROM php:7.2.13-fpm-alpine3.8

# Set container's working dir
WORKDIR /app

# Copy everything from project root into php container's working dir
COPY . /app
# Copy vendor folder from composer container into php container
COPY --from=composer /app/vendor /app/vendor

# Copy necessary files
COPY docker/php/php.ini /usr/local/etc/php/conf.d/php.override.ini
COPY docker/php/www.conf /usr/local/etc/php-fpm.d/www.conf

CMD ["php-fpm", "--nodaemonize"]

.dockerignore

.dockerignore
.gitignore
*.md
.git/
.idea/
.DS_Store/

docker-compose.yaml

这是可选的,但如果你想使用它,我就把它留下。如果你不想像我一样使用本地的docker命令,你可以在项目根目录下使用$ make -sC docker/ build up 命令。由你自己决定。

version: "3.4"

services:

  php:
    build:
      context: ".."
      dockerfile: "docker/php/Dockerfile"
    hostname: "php"

构建

构建镜像

$ docker build -t my_php_app:latest -f /absolute/path/to/project/docker/php/Dockerfile .

Successfully built c62632b82433
Successfully tagged my_php_app:latest
$ docker images
REPOSITORY        TAG                        IMAGE ID            CREATED             SIZE
my_php_app        latest                     c62632b82433        5 minutes ago       77.7MB

创建容器

$ docker run -itd --name my_php_app my_php_app:latest sh
4ec090d70437cf3312d735f754bcb5abcd96759fd8f76f24fbeb43e42c04f140
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
4ec090d70437        my_php_app:latest   "docker-php-entrypoi…"   4 seconds ago       Up 3 seconds        9000/tcp            my_php_app

验证容器内容

$ docker exec -it my_php_app sh
/app # ls -l
-rw-r--r--    1 root     root           133 Jun  3 20:23 composer.json
drwxr-xr-x    4 root     root          4096 Jun  3 20:33 docker
drwxr-xr-x    2 root     root          4096 Jun  3 20:39 src
drwxr-xr-x    4 root     root          4096 Jun  3 20:56 vendor

如果你在容器内运行php src/index.php 命令,它应该可以工作。