From 7145ec03cfe82f9b03130e25209deaff1f3fef30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <dunglas@gmail.com>
Date: Sat, 22 Apr 2017 20:29:25 +0200
Subject: [PATCH] Add Docker support

---
 Dockerfile                       | 70 ++++++++++++++++++++++++++++++++
 docker-compose.yml               | 36 ++++++++++++++++
 docker/nginx/conf.d/default.conf | 35 ++++++++++++++++
 docker/php/install-composer.sh   | 17 ++++++++
 docker/php/php.ini               |  9 ++++
 docker/php/start.sh              | 16 ++++++++
 web/index.php                    | 36 ++++++++++++++++
 7 files changed, 219 insertions(+)
 create mode 100644 Dockerfile
 create mode 100644 docker-compose.yml
 create mode 100644 docker/nginx/conf.d/default.conf
 create mode 100755 docker/php/install-composer.sh
 create mode 100644 docker/php/php.ini
 create mode 100644 docker/php/start.sh
 create mode 100644 web/index.php

diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..e3204f0
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,70 @@
+FROM php:7.1-fpm-alpine
+
+RUN apk add --no-cache --virtual .persistent-deps \
+		git \
+		icu-libs \
+		make \
+		zlib
+
+ENV APCU_VERSION 5.1.8
+
+RUN set -xe \
+	&& apk add --no-cache --virtual .build-deps \
+		$PHPIZE_DEPS \
+		icu-dev \
+		zlib-dev \
+	&& docker-php-ext-install \
+		intl \
+		pdo_mysql \
+		zip \
+	&& pecl install \
+		apcu-${APCU_VERSION} \
+	&& docker-php-ext-enable --ini-name 20-apcu.ini apcu \
+	&& docker-php-ext-enable --ini-name 05-opcache.ini opcache \
+	&& apk del .build-deps
+
+COPY docker/php/php.ini /usr/local/etc/php/php.ini
+
+COPY docker/php/install-composer.sh /usr/local/bin/docker-app-install-composer
+
+RUN chmod +x /usr/local/bin/docker-app-install-composer
+
+RUN set -xe \
+	&& apk add --no-cache --virtual .fetch-deps \
+		openssl \
+	&& docker-app-install-composer \
+	&& mv composer.phar /usr/local/bin/composer \
+	&& apk del .fetch-deps
+
+# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
+ENV COMPOSER_ALLOW_SUPERUSER 1
+
+RUN composer global require "hirak/prestissimo:^0.3" --prefer-dist --no-progress --no-suggest --optimize-autoloader --classmap-authoritative \
+	&& composer clear-cache
+
+WORKDIR /srv/api-platform
+
+COPY composer.json ./
+COPY composer.lock ./
+
+RUN mkdir -p \
+		var/cache \
+		var/logs \
+		var/sessions \
+	&& composer install --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress --no-suggest \
+	&& composer clear-cache \
+# Permissions hack because setfacl does not work on Mac and Windows
+	&& chown -R www-data var
+
+COPY etc etc/
+COPY src src/
+COPY var var/
+COPY web web/
+
+RUN composer dump-autoload --optimize --classmap-authoritative --no-dev
+
+COPY docker/php/start.sh /usr/local/bin/docker-app-start
+
+RUN chmod +x /usr/local/bin/docker-app-start
+
+CMD ["docker-app-start"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..590fc27
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,36 @@
+version: '3'
+
+services:
+  #db:
+  #  image: mysql:5.7
+  #  environment:
+  #    MYSQL_DATABASE: symfony
+  #    MYSQL_USER: symfony
+  #    MYSQL_PASSWORD: symfony
+  #    MYSQL_RANDOM_ROOT_PASSWORD: 'true'
+  #  volumes:
+  #    - db-data:/var/lib/mysql
+  #  healthcheck:
+  #    test: mysql --user=api_platform --password=api_platform -e "SELECT 1" api_platform
+
+  php:
+    build: .
+    #depends_on:
+    #  - db
+    volumes:
+      - ./:/srv/api-platform
+    env_file:
+      - .env
+
+  nginx:
+    image: nginx:1.11-alpine
+    depends_on:
+      - php
+    ports:
+      - '80:80'
+    volumes:
+      - ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
+      - ./:/srv/api-platform
+
+#volumes:
+#  db-data:
diff --git a/docker/nginx/conf.d/default.conf b/docker/nginx/conf.d/default.conf
new file mode 100644
index 0000000..501def4
--- /dev/null
+++ b/docker/nginx/conf.d/default.conf
@@ -0,0 +1,35 @@
+server {
+    root /srv/api-platform/web;
+
+    location / {
+        # try to serve file directly, fallback to app.php
+        try_files $uri /index.php$is_args$args;
+    }
+    location ~ ^/index\.php(/|$) {
+        fastcgi_pass php:9000;
+        fastcgi_split_path_info ^(.+\.php)(/.*)$;
+        include fastcgi_params;
+        # When you are using symlinks to link the document root to the
+        # current version of your application, you should pass the real
+        # application path instead of the path to the symlink to PHP
+        # FPM.
+        # Otherwise, PHP's OPcache may not properly detect changes to
+        # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
+        # for more information).
+        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
+        fastcgi_param DOCUMENT_ROOT $realpath_root;
+        # Prevents URIs that include the front controller. This will 404:
+        # http://domain.tld/app.php/some-path
+        # Remove the internal directive to allow URIs like this
+        internal;
+    }
+
+    # return 404 for all other php files not matching the front controller
+    # this prevents access to other php files you don't want to be accessible.
+    location ~ \.php$ {
+      return 404;
+    }
+
+    error_log /var/log/nginx/app_error.log;
+    access_log /var/log/nginx/app_access.log;
+}
diff --git a/docker/php/install-composer.sh b/docker/php/install-composer.sh
new file mode 100755
index 0000000..6f01e38
--- /dev/null
+++ b/docker/php/install-composer.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+EXPECTED_SIGNATURE=$(wget -q -O - https://composer.github.io/installer.sig)
+php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
+ACTUAL_SIGNATURE=$(php -r "echo hash_file('SHA384', 'composer-setup.php');")
+
+if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
+then
+    >&2 echo 'ERROR: Invalid installer signature'
+    rm composer-setup.php
+    exit 1
+fi
+
+php composer-setup.php --quiet
+RESULT=$?
+rm composer-setup.php
+exit $RESULT
diff --git a/docker/php/php.ini b/docker/php/php.ini
new file mode 100644
index 0000000..2f8c7eb
--- /dev/null
+++ b/docker/php/php.ini
@@ -0,0 +1,9 @@
+apc.enable_cli = 1
+date.timezone = UTC
+session.auto_start = Off
+short_open_tag = Off
+
+# http://symfony.com/doc/current/performance.html
+opcache.max_accelerated_files = 20000
+realpath_cache_size = 4096K
+realpath_cache_ttl = 600
diff --git a/docker/php/start.sh b/docker/php/start.sh
new file mode 100644
index 0000000..952fae9
--- /dev/null
+++ b/docker/php/start.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -xe
+
+# Detect the host IP
+export DOCKER_BRIDGE_IP=$(ip ro | grep default | cut -d' ' -f 3)
+
+if [ "APP_ENV" = 'prod' ]; then
+	composer install --prefer-dist --no-dev --no-progress --no-suggest --optimize-autoloader --classmap-authoritative
+else
+	composer install --prefer-dist --no-progress --no-suggest
+fi
+
+# Permissions hack because setfacl does not work on Mac and Windows
+chown -R www-data var
+
+exec php-fpm
diff --git a/web/index.php b/web/index.php
new file mode 100644
index 0000000..e5458ff
--- /dev/null
+++ b/web/index.php
@@ -0,0 +1,36 @@
+<?php
+
+use App\Kernel;
+use Symfony\Component\Dotenv\Dotenv;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Debug\Debug;
+
+require __DIR__.'/../vendor/autoload.php';
+
+if (getenv('APP_DEBUG')) {
+    // This check prevents access to debug front controllers that are deployed by accident to production servers.
+    // Feel free to remove this, extend it, or make something more sophisticated.
+    $whitelistedIps = ['127.0.0.1', '::1'];
+
+    // Allow access from the host
+    if ($dockerBridgeIp = getenv('DOCKER_BRIDGE_IP')) {
+        $whitelistedIps[] = $dockerBridgeIp;
+    }
+    if (isset($_SERVER['HTTP_CLIENT_IP'])
+        || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
+        || !(in_array(@$_SERVER['REMOTE_ADDR'], $whitelistedIps) || php_sapi_name() === 'cli-server')
+    ) {
+        header('HTTP/1.0 403 Forbidden');
+        exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
+    }
+
+    Debug::enable();
+}
+
+// Request::setTrustedProxies(['0.0.0.0/0'], Request::HEADER_FORWARDED);
+
+$kernel = new Kernel(getenv('APP_ENV'), getenv('APP_DEBUG'));
+$request = Request::createFromGlobals();
+$response = $kernel->handle($request);
+$response->send();
+$kernel->terminate($request, $response);