From 8bc5ea2d5e3899ac3e29ed94a9fee3e2e2975265 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Thu, 21 Nov 2019 12:54:22 +0800 Subject: [PATCH 01/16] Initial Docker support This commit adds: 1. A Dockerfile that runs PHP 7.2 FPM on Alpine Linux 2. A example docker-compose file that simplifies deployment --- .gitignore | 1 + Dockerfile | 31 ++++++++++++++++ docker-compose.yml.example | 18 ++++++++++ nginx.conf | 74 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml.example create mode 100644 nginx.conf diff --git a/.gitignore b/.gitignore index 0afb940b..9dc3413f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ Homestead.yaml .rnd /.expo /.vscode +docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..0525e49d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +FROM php:7.2-fpm-alpine + +# Use the default production configuration +RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" + +RUN apk add --no-cache curl git tar unzip libpng-dev libxml2-dev + +RUN docker-php-ext-install bcmath && \ + docker-php-ext-install ctype && \ + docker-php-ext-install json && \ + docker-php-ext-install gd && \ + docker-php-ext-install mbstring && \ + docker-php-ext-install pdo && \ + docker-php-ext-install pdo_mysql && \ + docker-php-ext-install tokenizer && \ + docker-php-ext-install xml && \ + curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \ + composer --version + +WORKDIR /var/www + +COPY . /var/www + +RUN composer install --optimize-autoloader && \ + php artisan config:cache && \ + chmod -R 755 storage bootstrap/cache && \ + chown -R www-data:www-data storage + +EXPOSE 9000 +CMD ["php-fpm"] + diff --git a/docker-compose.yml.example b/docker-compose.yml.example new file mode 100644 index 00000000..48bdda1a --- /dev/null +++ b/docker-compose.yml.example @@ -0,0 +1,18 @@ +version: '3.1' + +services: + + nginx: + image: nginx + expose: + - 80 + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + restart: always + + php: + build: . + expose: + - 9000 + restart: always + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 00000000..ecb9f59f --- /dev/null +++ b/nginx.conf @@ -0,0 +1,74 @@ +worker_processes 8; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 4096; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + + keepalive_timeout 65; + + server { + listen 80 default_server; + + root /var/www/public; + index index.php; + charset utf-8; + + access_log off; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + client_max_body_size 100m; + client_body_timeout 120s; + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + sendfile off; + + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header Content-Security-Policy "frame-ancestors 'self'"; + + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass php:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M"; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTP_PROXY ""; + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + fastcgi_connect_timeout 300; + fastcgi_send_timeout 300; + fastcgi_read_timeout 300; + include /etc/nginx/fastcgi_params; + } + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + location ~ /\.ht { + deny all; + } + } +} From 1cbc41c3cea3e9556297c2a72973b512fc7b71d6 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Tue, 3 Dec 2019 20:24:54 +0800 Subject: [PATCH 02/16] Simplify docker-ext-install in Dockerfile --- Dockerfile | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0525e49d..d12a2cb8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,15 +5,7 @@ RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" RUN apk add --no-cache curl git tar unzip libpng-dev libxml2-dev -RUN docker-php-ext-install bcmath && \ - docker-php-ext-install ctype && \ - docker-php-ext-install json && \ - docker-php-ext-install gd && \ - docker-php-ext-install mbstring && \ - docker-php-ext-install pdo && \ - docker-php-ext-install pdo_mysql && \ - docker-php-ext-install tokenizer && \ - docker-php-ext-install xml && \ +RUN docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml && \ curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \ composer --version From b6096aadfa80b6406efa0c048ce56262caf746bc Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Tue, 3 Dec 2019 21:31:56 +0800 Subject: [PATCH 03/16] Add MariaDB to docker-compose example 1. Gives an example set up of a MySQL database in docker-compose 2. `php` now depends on `db`, and `nginx` depends on `php`. This ensures the integrity of the stack. --- docker-compose.yml.example | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml.example b/docker-compose.yml.example index 48bdda1a..c58181df 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -3,7 +3,9 @@ version: '3.1' services: nginx: - image: nginx + image: nginx + depends_on: + - php expose: - 80 volumes: @@ -12,7 +14,17 @@ services: php: build: . + depends_on: + - db expose: - 9000 restart: always + db: + image: mariadb + restart: always + environment: + MYSQL_USER: crater + MYSQL_PASSWORD: crater + MYSQL_DATABASE: crater + From bf2e8c9c9921fcb6ca8a956f786f17fd96f19fe9 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 08:23:11 +0800 Subject: [PATCH 04/16] Use multi-stage build for Docker image 1. Allows to build the composer dependencies with official composer img 2. php-fpm --nodaemonize: Force to stay in foreground and ignore daemo- nize option from configuration file --- Dockerfile | 38 +++++++++++++++++++++++++++----------- nginx.conf | 2 +- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index d12a2cb8..94cc748e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,39 @@ -FROM php:7.2-fpm-alpine +FROM composer 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 + +FROM php:7.4.0-fpm-alpine # Use the default production configuration RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" -RUN apk add --no-cache curl git tar unzip libpng-dev libxml2-dev +RUN apk add --no-cache libpng-dev libxml2-dev && \ + docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml -RUN docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml && \ - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \ - composer --version +# Set container's working dir +WORKDIR /app + +# Copy everything from project root into php container's working dir +COPY . /app -WORKDIR /var/www +# Copy vendor folder from composer container into php container +COPY --from=composer /app/vendor /app/vendor -COPY . /var/www - -RUN composer install --optimize-autoloader && \ - php artisan config:cache && \ +RUN php artisan config:cache && \ chmod -R 755 storage bootstrap/cache && \ chown -R www-data:www-data storage EXPOSE 9000 -CMD ["php-fpm"] +CMD ["php-fpm", "--nodaemonize"] diff --git a/nginx.conf b/nginx.conf index ecb9f59f..47d52728 100644 --- a/nginx.conf +++ b/nginx.conf @@ -24,7 +24,7 @@ http { server { listen 80 default_server; - root /var/www/public; + root /app/public; index index.php; charset utf-8; From ec87e725478401b0b0efeee629af223ee64c16f7 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 08:26:31 +0800 Subject: [PATCH 05/16] Add .dockerignore file This excludes unnecessary files for production use on Docker image build. --- .dockerignore | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..1cf15ae2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.dockerignore +.gitignore +*.md +.git/ +.idea/ +.DS_Store/ +docker-compose.* +LICENSE +nginx.conf +yarn.lock From 146cf835b91d467dc2f985e997d22120da3e8bde Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 08:59:01 +0800 Subject: [PATCH 06/16] Fix composer install in Dockerfile --- Dockerfile | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 94cc748e..07550568 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,19 @@ FROM composer as composer -# Copy composer files from project root into composer container's working dir -COPY composer.* /app/ +# Copy everything from project root into composer container's working dir +COPY . /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 + && composer install --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader \ + && composer dump-autoload --optimize --classmap-authoritative FROM php:7.4.0-fpm-alpine # Use the default production configuration RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" -RUN apk add --no-cache libpng-dev libxml2-dev && \ +RUN apk add --no-cache libpng-dev libxml2-dev oniguruma-dev && \ docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml # Set container's working dir From 7b697a477e3be9feb00c52c956031f382f5b165e Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 11:20:50 +0800 Subject: [PATCH 07/16] Fix MariaDB config in Docker compose by specifying a root password. --- .gitignore | 1 + docker-compose.yml.example | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9dc3413f..5f355185 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ Homestead.yaml /.expo /.vscode docker-compose.yml +docker-compose.yaml diff --git a/docker-compose.yml.example b/docker-compose.yml.example index c58181df..e44200f8 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -27,4 +27,4 @@ services: MYSQL_USER: crater MYSQL_PASSWORD: crater MYSQL_DATABASE: crater - + MYSQL_ROOT_PASSWORD: crater From 7fe9a4c2a251d3ddeb58fceaaefe167d52e382be Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 14:49:57 +0800 Subject: [PATCH 08/16] Fix Dockerfile and docker-compose.yml 1. Generate a testing SQLite db on build 2. Optimize image layer caching 3. Fix permissions 4. Simplify nginx configuration 5. Fix nginx infinite redirect loop (couldn't access app folder) --- Dockerfile | 32 +++++++++++++++++++++++++------- nginx.conf | 23 +---------------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/Dockerfile b/Dockerfile index 07550568..92a45694 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,22 @@ +##### STAGE 1 ##### + FROM composer as composer +# Copy composer files from project root into composer container's working dir +COPY composer.* /app/ + +# Copy database directory for autoloader optimization +COPY database /app/database + +# Run composer to build dependencies in vendor folder +RUN composer install --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader + # Copy everything from project root into composer container's working dir COPY . /app -# Run composer to build dependencies in vendor folder -RUN set -xe \ - && composer install --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader \ - && composer dump-autoload --optimize --classmap-authoritative +RUN composer dump-autoload --optimize --classmap-authoritative + +##### STAGE 2 ##### FROM php:7.4.0-fpm-alpine @@ -25,10 +35,18 @@ COPY . /app # Copy vendor folder from composer container into php container COPY --from=composer /app/vendor /app/vendor -RUN php artisan config:cache && \ - chmod -R 755 storage bootstrap/cache && \ - chown -R www-data:www-data storage +RUN touch database/database.sqlite && \ + php artisan migrate && \ + php artisan config:cache && \ + php artisan passport:install && \ + php artisan key:generate && \ + chown -R www-data:www-data . && \ + chmod -R 755 . && \ + chmod -R 775 storage/framework/ && \ + chmod -R 775 storage/logs/ && \ + chmod -R 775 bootstrap/cache/ EXPOSE 9000 + CMD ["php-fpm", "--nodaemonize"] diff --git a/nginx.conf b/nginx.conf index 47d52728..36645fa7 100644 --- a/nginx.conf +++ b/nginx.conf @@ -22,7 +22,7 @@ http { keepalive_timeout 65; server { - listen 80 default_server; + listen 80 default_server; root /app/public; index index.php; @@ -34,41 +34,20 @@ http { try_files $uri $uri/ /index.php?$query_string; } - client_max_body_size 100m; - client_body_timeout 120s; - location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } - sendfile off; - add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header X-Robots-Tag none; add_header Content-Security-Policy "frame-ancestors 'self'"; location ~ \.php$ { - fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; - fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M"; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param HTTP_PROXY ""; - fastcgi_intercept_errors off; - fastcgi_buffer_size 16k; - fastcgi_buffers 4 16k; - fastcgi_connect_timeout 300; - fastcgi_send_timeout 300; - fastcgi_read_timeout 300; include /etc/nginx/fastcgi_params; } - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - location ~ /\.ht { - deny all; - } } } From 14d71fedb31434f168aa78c82a42345581d4dff7 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 14:54:28 +0800 Subject: [PATCH 09/16] Rename docker-compose.yml.example -> docker-compose.yaml.example --- ...-compose.yml.example => docker-compose.yaml.example | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) rename docker-compose.yml.example => docker-compose.yaml.example (82%) diff --git a/docker-compose.yml.example b/docker-compose.yaml.example similarity index 82% rename from docker-compose.yml.example rename to docker-compose.yaml.example index e44200f8..f41e6e85 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yaml.example @@ -6,10 +6,11 @@ services: image: nginx depends_on: - php - expose: - - 80 + ports: + - 8080:80 volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro + - app:/app restart: always php: @@ -18,6 +19,8 @@ services: - db expose: - 9000 + volumes: + - app:/app restart: always db: @@ -28,3 +31,6 @@ services: MYSQL_PASSWORD: crater MYSQL_DATABASE: crater MYSQL_ROOT_PASSWORD: crater + +volumes: + app: From 2fcd169270af019ae98227e837d54cc881c939aa Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 17:19:16 +0800 Subject: [PATCH 10/16] Downgrade Docker image php version to 7.3.12 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 92a45694..f575fb46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN composer dump-autoload --optimize --classmap-authoritative ##### STAGE 2 ##### -FROM php:7.4.0-fpm-alpine +FROM php:7.3.12-fpm-alpine # Use the default production configuration RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" From e539bb501d37dc1fb7b3f0aaf05a928c22504182 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 17:22:59 +0800 Subject: [PATCH 11/16] Docker: persistant database storage in example docker-compose.yaml --- docker-compose.yaml.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yaml.example b/docker-compose.yaml.example index f41e6e85..ddc8c058 100644 --- a/docker-compose.yaml.example +++ b/docker-compose.yaml.example @@ -26,6 +26,8 @@ services: db: image: mariadb restart: always + volumes: + - db:/var/lib/mysql environment: MYSQL_USER: crater MYSQL_PASSWORD: crater @@ -34,3 +36,4 @@ services: volumes: app: + db: From 0c71356f597f8f6278ed120dd877a8fb8c4340b6 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Wed, 4 Dec 2019 18:31:06 +0800 Subject: [PATCH 12/16] Docker: remove migration instruction --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f575fb46..c7d48286 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,6 @@ COPY . /app COPY --from=composer /app/vendor /app/vendor RUN touch database/database.sqlite && \ - php artisan migrate && \ php artisan config:cache && \ php artisan passport:install && \ php artisan key:generate && \ From 3692373cd29d0b5ec7e75e44887374793e1e0580 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Mon, 9 Dec 2019 19:25:57 +0800 Subject: [PATCH 13/16] Docker: switch from passport:install to passport:keys during build --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c7d48286..de172624 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ COPY --from=composer /app/vendor /app/vendor RUN touch database/database.sqlite && \ php artisan config:cache && \ - php artisan passport:install && \ + php artisan passport:keys && \ php artisan key:generate && \ chown -R www-data:www-data . && \ chmod -R 755 . && \ From c474e98925055013c22c92842911fee6caa24936 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Tue, 10 Dec 2019 23:40:59 +0800 Subject: [PATCH 14/16] Docker: copy example env file when building --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index de172624..c3fa5a83 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,6 +36,7 @@ COPY . /app COPY --from=composer /app/vendor /app/vendor RUN touch database/database.sqlite && \ + cp .env.example .env && \ php artisan config:cache && \ php artisan passport:keys && \ php artisan key:generate && \ From d8f6d03d1eefa17d129a17b769c9cac1a40b3aa7 Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Tue, 10 Dec 2019 23:52:23 +0800 Subject: [PATCH 15/16] Docker: rename nginx container name --- docker-compose.yaml.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-compose.yaml.example b/docker-compose.yaml.example index ddc8c058..590e4c2a 100644 --- a/docker-compose.yaml.example +++ b/docker-compose.yaml.example @@ -2,7 +2,7 @@ version: '3.1' services: - nginx: + web: image: nginx depends_on: - php @@ -37,3 +37,4 @@ services: volumes: app: db: + From 28990218041133af46a340e569fb3eaa5ceab45e Mon Sep 17 00:00:00 2001 From: Birkhoff Lee Date: Tue, 10 Dec 2019 23:53:28 +0800 Subject: [PATCH 16/16] Update example env in accordance w/ Docker setup --- .env.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 19e36d8c..e8c6a0c8 100644 --- a/.env.example +++ b/.env.example @@ -5,11 +5,11 @@ APP_LOG_LEVEL=debug APP_URL=http://crater.test DB_CONNECTION=mysql -DB_HOST=127.0.0.1 +DB_HOST=db DB_PORT=3306 DB_DATABASE=crater -DB_USERNAME=root -DB_PASSWORD=bytefury +DB_USERNAME=crater +DB_PASSWORD=crater BROADCAST_DRIVER=log CACHE_DRIVER=file