In this example we are going to run composer to install Symfony application dependencies then copy vendor folder and the rest of the application files into container image. With this way our image will always come with the application by default so all we have to do is create a container and start using it. This is a well known practise but I just wanted to touch upon a basic implementation. The main purpose is to isolate application code and not expose it to host OS. I am not going to list the benefits here because they all have been written on the Internet. The main problem with this solution is, the size of the final docker image will depend on the application and vendor folder size.


Structure


.
├── bin
│   └── ...
├── composer.json
├── composer.lock
├── Readme.md
├── symfony.lock
├──.env
├──.gitignore
├──.dockerignore
├── config
│   └── ...
├── docker
│   ├── docker-compose.yml
│   ├── Makefile
│   ├── nginx
│   │   ├── app.conf
│   │   ├── Dockerfile
│   │   └── nginx.conf
│   └── php
│   ├── Dockerfile
│   ├── init.sh
│   ├── php.ini
│   └── www.conf
├── public
│   └── index.php
├── src
│   └── ...
├── var
│   └── ...
└── vendor
   └── ...

Files


I am just showing the content of important files. The rest is not too important.


.dockerignore


config/packages/dev/
config/packages/test/
var/
vendor/
.dockerignore
.gitignore
*.md

.git/
.idea/
.DS_Store/

docker-compose.yml


version: "3.4"

services:

sport_php:
build:
context: ".."
dockerfile: "docker/php/Dockerfile"
hostname: "sport-php"
environment:
PS1: "\\u@\\h:\\w\\$$ "

sport_nginx:
build:
context: ".."
dockerfile: "docker/nginx/Dockerfile"
hostname: "sport-nginx"
ports:
- "1080:80"
depends_on:
- "sport_php"
environment:
PS1: "\\u@\\h:\\w\\$$ "

Makefile


build:
@docker-compose build

up:
@docker-compose up -d

nginx/Dockerfile


FROM nginx:1.15.8-alpine

WORKDIR /app

COPY public/index.php /app/public/index.php

COPY docker/nginx/app.conf /etc/nginx/conf.d/default.conf
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf

php/Dockerfile


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

COPY composer.* /app/

RUN set -xe \
&& composer install --no-dev --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader

COPY . /app

RUN composer dump-autoload --no-dev --optimize --classmap-authoritative

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

RUN apk update \
&& apk add --no-cache $PHPIZE_DEPS \
git \
zip \
unzip \
&& docker-php-ext-install \
opcache \
pdo_mysql \
&& docker-php-ext-enable \
opcache \
&& rm -rf \
/var/cache/apk/* \
/var/lib/apt/lists/*

WORKDIR /app

COPY . /app

COPY --from=composer /app/vendor /app/vendor

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
COPY docker/php/init.sh /usr/local/bin/init.sh

RUN chmod +x /usr/local/bin/init.sh

CMD ["/usr/local/bin/init.sh"]

php/init.sh


#!/bin/sh
set -e

bin/console cache:warm

php-fpm --nodaemonize

Build and check


$ make -sC docker/ build up

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker_sport_php latest c7d3ba4a4c3a 22 hours ago 302MB
docker_sport_nginx latest 267a1d054046 22 hours ago 16.1MB
composer 1.8.5 78e8c9802c21 4 days ago 161MB
nginx 1.15.8-alpine b411e34b4606 4 months ago 16.1MB
php 7.2.13-fpm-alpine3.8 262e46e3d43c 5 months ago 77.7MB

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b0faa127f7d4 docker_sport_nginx "nginx -g 'daemon of…" 22 hours ago Up 22 hours 0.0.0.0:1080->80/tcp docker_sport_nginx_1
f929370e4a0e docker_sport_php "docker-php-entrypoi…" 22 hours ago Up 22 hours 9000/tcp docker_sport_php_1

$ docker exec -it docker_sport_nginx_1 ls -l public
-rw-r--r-- 1 root root 798 May 16 07:50 index.php

$ docker exec -it docker_sport_php_1 ls -la
-rw-r--r-- 1 root root 279 May 16 09:10 .env
drwxr-xr-x 2 root root 4096 May 16 07:50 bin
-rw-r--r-- 1 root root 1443 May 16 08:10 composer.json
-rw-r--r-- 1 root root 118858 May 16 08:10 composer.lock
drwxr-xr-x 4 root root 4096 May 17 07:00 config
drwxr-xr-x 4 root root 4096 Jun 4 20:32 docker
drwxr-xr-x 2 root root 4096 May 16 07:50 public
drwxr-xr-x 8 root root 4096 May 17 07:00 src
-rw-r--r-- 1 root root 5998 May 16 08:10 symfony.lock
drwxrwxrwx 4 root root 4096 Jun 4 20:33 var
drwxr-xr-x 11 root root 4096 Jun 4 20:32 vendor

If you run $ curl -i 0.0.0.0:1080 command in terminal, the application should work.