This commit is contained in:
DESKTOP-E17406D\boonkerz 2022-12-03 10:14:25 +01:00
commit e2f1581fbd
411 changed files with 4620 additions and 0 deletions

37
.docker/.env.example Normal file
View File

@ -0,0 +1,37 @@
# docker-compose env vars
# @see https://docs.docker.com/compose/reference/envvars/
COMPOSE_CONVERT_WINDOWS_PATHS=1
# application
APP_GROUP_NAME=application
# application
APP_SSH_PASSWORD=123456
# mysql
MYSQL_DATABASE=psc
MYSQL_PASSWORD=Wichtig1
MYSQL_ROOT_PASSWORD=Wichtig1
#APP_USER_NAME=application
#APP_USER_ID=10000
#APP_GROUP_ID=10001
APP_CODE_PATH_CONTAINER=/data/www
APP_CODE_PATH_HOST=../../src
APP_HOST=app.local
NETWORKS_DRIVER=bridge
NGINX_HOST_HTTP_PORT=80
NGINX_HOST_HTTPS_PORT=443
PHP_IDE_CONFIG=serverName=psc
VOLUMES_DRIVER=local
ALPINE_VERSION=3.12
COMPOSER_VERSION=2.2.5
MYSQL_VERSION=10.4.8
MONGODB_VERSION=5
NGINX_VERSION=1.21.5-alpine
PHP_VERSION=7.4

View File

@ -0,0 +1,47 @@
version: "2"
services:
mongodb:
image: mongo
ports:
- "11000:27017"
mysql:
image: registry.gitlab.com/printshopcreator/docker/docker_mysql:latest
ports:
- "11001:3306"
environment:
- MYSQL_ROOT_PASSWORD=Wichtig1
- MYSQL_DATABASE=psc
cron:
image: registry.gitlab.com/printshopcreator/docker/docker_cron:php7
environment:
- SYMFONY_DECRYPTION_SECRET=ZfzbggHk012ImxwsovgF0iLkJf7pUJlMJ+uBLNTHFxbwz0iwe7STUJhAyULlDSv9unBVXfPW3DFf/VuVw6vPCQ==%
volumes:
- .:/data/www/old
- .:/data/www/new
links:
- mysql:mysql
- mongodb:mongodb
php:
image: registry.gitlab.com/printshopcreator/docker/docker_php:php7
environment:
- ftpUsername=papedruck
- ftpPassword=27JSdjs62Jhs
- ftpHost=157.90.18.62
- ftpPort=20000
- ftpIp=157.90.18.62
- SYMFONY_DECRYPTION_SECRET=ZfzbggHk012ImxwsovgF0iLkJf7pUJlMJ+uBLNTHFxbwz0iwe7STUJhAyULlDSv9unBVXfPW3DFf/VuVw6vPCQ==%
links:
- mysql:mysql
- mongodb:mongodb
volumes:
- ./psc-source-v1:/data/www/old
- ./psc-source-v2:/data/www/new
tp:
image: registry.gitlab.com/printshopcreator/docker/docker_tp:v21x1x1
web:
image: registry.gitlab.com/printshopcreator/docker/docker_web:php7_tp
ports:
- "8001:80"
volumes:
- ./psc-source-v1:/data/www/old
- ./psc-source-v2:/data/www/new

View File

@ -0,0 +1,19 @@
version: '3.7'
services:
php-base:
image: ${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/php-base-${ENV?}:${TAG?}
build:
context: ../../
dockerfile: ./.docker/images/php/base/Dockerfile
args:
- ALPINE_VERSION=${ALPINE_VERSION?}
- APP_CODE_PATH=${APP_CODE_PATH_CONTAINER?}
- APP_GROUP_ID=${APP_GROUP_ID?}
- APP_GROUP_NAME=${APP_GROUP_NAME?}
- APP_USER_ID=${APP_USER_ID?}
- APP_USER_NAME=${APP_USER_NAME?}
- COMPOSER_VERSION=${COMPOSER_VERSION?}
- ENV=${ENV?}
- TARGET_PHP_VERSION=${PHP_VERSION?}
target: ${ENV?}

View File

@ -0,0 +1,110 @@
version: '3.7'
networks:
network:
driver: ${NETWORKS_DRIVER?}
volumes:
mysql:
name: mysql-${ENV?}
driver: ${VOLUMES_DRIVER?}
mongodb:
name: mongodb-${ENV?}
driver: ${VOLUMES_DRIVER?}
services:
php-fpm:
environment:
- PHP_IDE_CONFIG=${PHP_IDE_CONFIG?}
# cap_add and security_opt are required to enable strace
# @see https://stackoverflow.com/a/46676868
cap_add:
- "SYS_PTRACE"
security_opt:
- "seccomp=unconfined"
volumes:
- ${APP_CODE_PATH_HOST?}:${APP_CODE_PATH_CONTAINER?}
networks:
- network
extra_hosts:
- host.docker.internal:host-gateway
php-cron:
environment:
- PHP_IDE_CONFIG=${PHP_IDE_CONFIG?}
volumes:
- ${APP_CODE_PATH_HOST?}:${APP_CODE_PATH_CONTAINER?}
cap_add:
- "SYS_PTRACE"
security_opt:
- "seccomp=unconfined"
extra_hosts:
- host.docker.internal:host-gateway
web:
volumes:
- ${APP_CODE_PATH_HOST?}:${APP_CODE_PATH_CONTAINER?}
ports:
- "${NGINX_HOST_HTTP_PORT:-80}:80"
- "${NGINX_HOST_HTTPS_PORT:-443}:443"
networks:
network:
aliases:
- ${APP_HOST?}
depends_on:
- php-fpm
tp:
image: registry.gitlab.com/printshopcreator/docker/docker_tp:v21x1x1
networks:
- network
application:
image: ${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/application-${ENV?}:${TAG?}
build:
context: ../
dockerfile: ./images/php/application/Dockerfile
args:
- BASE_IMAGE=${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/php-base-${ENV?}:${TAG?}
- APP_SSH_PASSWORD=${APP_SSH_PASSWORD?}
- ENV=${ENV?}
environment:
- PHP_IDE_CONFIG=${PHP_IDE_CONFIG?}
# cap_add and security_opt are required to enable strace
# @see https://stackoverflow.com/a/46676868
cap_add:
- "SYS_PTRACE"
security_opt:
- "seccomp=unconfined"
volumes:
- ${APP_CODE_PATH_HOST?}:${APP_CODE_PATH_CONTAINER?}
ports:
- "${APPLICATION_SSH_HOST_PORT:-2222}:22"
tty: true
networks:
- network
extra_hosts:
- host.docker.internal:host-gateway
mongodb:
image: mongo:${MONGODB_VERSION?}
platform: linux/amd64
volumes:
- mongodb:/data/db
networks:
- network
ports:
- "${MONGODB_HOST_PORT:-27017}:27017"
mysql:
image: mariadb:${MYSQL_VERSION?}
platform: linux/amd64
environment:
- MYSQL_DATABASE=${MYSQL_DATABASE:-application_db}
- MYSQL_USER=${MYSQL_USER:-application_user}
- MYSQL_PASSWORD=${MYSQL_PASSWORD?}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD?}
- TZ=${TIMEZONE:-UTC}
volumes:
- mysql:/var/lib/mysql
command: mysqld --sql_mode="ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" --character-set-server=utf8 --collation-server=utf8_slovenian_ci --init-connect='SET NAMES UTF8;' --innodb-flush-log-at-trx-commit=0
networks:
- network
ports:
- "${MYSQL_HOST_PORT:-3306}:3306"

View File

@ -0,0 +1,31 @@
version: '3.7'
services:
php-fpm:
image: ${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/php-fpm-${ENV?}:${TAG?}
build:
context: ../
dockerfile: ./images/php/fpm/Dockerfile
target: ${ENV?}
args:
- BASE_IMAGE=${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/php-base-${ENV?}:${TAG?}
- TARGET_PHP_VERSION=${PHP_VERSION?}
php-cron:
image: ${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/php-cron-${ENV?}:${TAG?}
build:
context: ../
dockerfile: ./images/php/cron/Dockerfile
target: ${ENV?}
args:
- BASE_IMAGE=${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/php-base-${ENV?}:${TAG?}
web:
image: ${DOCKER_REGISTRY?}/${DOCKER_NAMESPACE?}/web-${ENV?}:${TAG?}
build:
context: ../
dockerfile: ./images/nginx/Dockerfile
target: ${ENV?}
args:
- NGINX_VERSION=${NGINX_VERSION?}
- APP_CODE_PATH=${APP_CODE_PATH_CONTAINER?}

View File

@ -0,0 +1,10 @@
ARG NGINX_VERSION
FROM nginx:${NGINX_VERSION} as base
COPY --chown=nginx:nginx ./images/nginx/conf.d/default.conf /etc/nginx/conf.d
ARG APP_CODE_PATH
RUN sed -i "s#__NGINX_ROOT_NEW;#$APP_CODE_PATH/new/web;#" /etc/nginx/conf.d/default.conf
RUN sed -i "s#__NGINX_ROOT_OLD;#$APP_CODE_PATH/old/public;#" /etc/nginx/conf.d/default.conf
FROM base as local

View File

@ -0,0 +1,103 @@
server {
index index.php index.html app.php;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
set $frontRoot __NGINX_ROOT_NEW;
set $sfApp app.php; # Change to app.php for prod
client_max_body_size 1000M;
root __NGINX_ROOT_OLD;
charset UTF-8;
location / {
client_max_body_size 1024M;
try_files $uri $uri/ @notfile;
location ~ \.php$ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
#
# Om nom nom cookies
#
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,apikey';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Credentials true always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header Access-Control-Expose-Headers Access-Control-Allow-Origin always;
fastcgi_temp_path /tmp/fastcgi 1 2;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-fpm:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SERVER_NAME $http_host;
include fastcgi_params;
fastcgi_pass_header *;
}
}
location @notfile {
rewrite ^(.*) /index.php last;
}
location /apps/ { # Static files
client_max_body_size 1024M;
root $frontRoot;
rewrite ^/apps/(.*)$ /$1 break;
try_files $uri @sfFront;
}
#location /w2p/ {
# proxy_pass http://tp:8080/w2p/;
# proxy_temp_path /tmp/proxy;
#}
location @sfFront { # Symfony
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
#
# Om nom nom cookies
#
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,apikey';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Credentials true always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header Access-Control-Expose-Headers Access-Control-Allow-Origin always;
fastcgi_temp_path /tmp/fastcgi 1 2;
fastcgi_pass php-fpm:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $frontRoot/$sfApp;
fastcgi_param SCRIPT_NAME /apps/$sfApp;
fastcgi_param REQUEST_URI /apps$uri?$args;
fastcgi_param SERVER_NAME $http_host;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param HTTPS off;
}
}

View File

@ -0,0 +1,35 @@
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
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 off;
#tcp_nopush on;
keepalive_timeout 65;
client_body_temp_path /tmp 1 2;
client_body_buffer_size 256k;
client_body_in_file_only off;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

View File

@ -0,0 +1,28 @@
ARG BASE_IMAGE
FROM ${BASE_IMAGE} as base
FROM base as prod
USER $APP_USER_NAME
FROM base as ci
USER $APP_USER_NAME
FROM base as local
#RUN apt install -y \
# openssh-server
#
#ARG APP_SSH_PASSWORD
#RUN echo "$APP_USER_NAME:$APP_SSH_PASSWORD" | chpasswd 2>&1
#
## Required to start sshd, otherwise the container will error out on startup with the message
## "sshd: no hostkeys available -- exiting."
## @see https://stackoverflow.com/a/65348102/413531
#RUN ssh-keygen -A
#
## we use SSH deployment configuration in PhpStorm for local development
#EXPOSE 22
#
#CMD ["/usr/sbin/sshd", "-D"]

View File

@ -0,0 +1,9 @@
export PS1='$(whoami):$(pwd)# '
alias ll='ls -l'
alias lc='ls --color=auto'
# see https://stackoverflow.com/questions/4188324/bash-completion-of-makefile-target
# -h to grep to hide filenames
# -s to grep to hide error messages
# include Makefile and .make directory
complete -W "\`grep -shoE '^[a-zA-Z0-9_.-]+:([^=]|$)' ?akefile .make/*.mk | sed 's/[^a-zA-Z0-9_.-]*$//' | grep -v PHONY\`" make

View File

@ -0,0 +1,227 @@
ARG COMPOSER_VERSION
ARG TARGET_PHP_VERSION
FROM composer:${COMPOSER_VERSION} as composer
FROM php:${TARGET_PHP_VERSION}-fpm as base
# make build args available as ENV variables to downstream images
# so that we don't have to pass the same build args again
ARG APP_USER_ID
ARG APP_GROUP_ID
ARG APP_USER_NAME
ARG APP_GROUP_NAME
ARG APP_CODE_PATH
ARG ENV
ENV APP_USER_ID=${APP_USER_ID}
ENV APP_GROUP_ID=${APP_GROUP_ID}
ENV APP_USER_NAME=${APP_USER_NAME}
ENV APP_GROUP_NAME=${APP_GROUP_NAME}
ENV APP_CODE_PATH=${APP_CODE_PATH}
ENV TARGET_PHP_VERSION=${TARGET_PHP_VERSION}
ENV ENV=${ENV}
RUN addgroup -gid $APP_GROUP_ID $APP_GROUP_NAME && \
adduser --disabled-password --uid $APP_USER_ID --shell /bin/bash --ingroup $APP_GROUP_NAME $APP_USER_NAME && \
mkdir -p $APP_CODE_PATH && \
chown $APP_USER_NAME: $APP_CODE_PATH
# install git-secret
# @see https://git-secret.io/installation#alpine
ADD https://gitsecret.jfrog.io/artifactory/api/security/keypair/public/repositories/git-secret-apk /etc/apk/keys/git-secret-apk.rsa.pub
# FYI, we are NOT using a cache mount to store the apk cache via
# RUN --mount=type=cache,target=/var/cache/apk ln -vs /var/cache/apk /etc/apk/cache && \
# @see https://github.com/FernandoMiguel/BuildKit#new-dockerfile
# @see https://wiki.alpinelinux.org/wiki/Local_APK_cache#Enabling_Local_Cache_on_HDD_installs
# because we run --update anyways to get the latest files
RUN apt update && \
apt install -y \
bash \
git \
git-secret \
# required for git-secret
gawk \
gnupg \
make \
strace \
sudo \
vim
# Install intl
RUN apt-get update && apt-get install -y \
libicu-dev \
libssl-dev \
libcurl4-openssl-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
libxml2-dev \
libmagickwand-dev \
git \
zlib1g-dev \
unzip \
libzip-dev \
mupdf-tools \
imagemagick \
libmcrypt-dev
# Install fileinfo
RUN docker-php-ext-install -j$(nproc) fileinfo
# Install intl
RUN docker-php-ext-install -j$(nproc) intl
# Install mongodb
RUN pecl install mongodb \
&& docker-php-ext-enable mongodb
# Install mcrypt
RUN pecl install mcrypt \
&& docker-php-ext-enable mcrypt
# Install curl
RUN docker-php-ext-install -j$(nproc) curl
# Install Zip
RUN docker-php-ext-install zip
# Install gd
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd
# Install soap
RUN docker-php-ext-install -j$(nproc) soap
# Install imagick
RUN pecl install imagick \
&& docker-php-ext-enable imagick
# Install mysql
RUN docker-php-ext-install -j$(nproc) pdo_mysql
# Install opcache
RUN docker-php-ext-install -j$(nproc) opcache
RUN apt-get update && apt-get install -y \
libc-client-dev libkrb5-dev libldap2-dev && \
rm -r /var/lib/apt/lists/*
# Install ldap
RUN docker-php-ext-install -j$(nproc) ldap
RUN docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \
docker-php-ext-install -j$(nproc) imap
# make bash default shell
RUN sed -e 's;/bin/ash$;/bin/bash;g' -i /etc/passwd
COPY ./.docker/images/php/base/conf.d/zz-app.ini $PHP_INI_DIR/conf.d/zz-app.ini
COPY ./.docker/images/php/base/conf.d/zz-app-${ENV}.ini $PHP_INI_DIR/conf.d/zz-ppp-${ENV}.ini
COPY ./.docker/images/php/base/.bashrc /home/${APP_USER_NAME}/.bashrc
COPY ./.docker/images/php/base/.bashrc /root/.bashrc
COPY --from=composer /usr/bin/composer /usr/local/bin/composer
# Fix git permission issue:
# `git` introduced a security feature to throw an error if the parent directory
# of the `.git` directory is owned by another user.
# @see https://github.blog/2022-04-12-git-security-vulnerability-announced/
# @see https://github.com/actions/checkout/issues/760
#
# Since we might not have full control over the owner
# ( see e.g. https://github.com/docker/for-win/issues/12742 )
# we will add the $APP_CODE_PATH as a "safe" directory to the global git config via
# git config --system --add safe.directory "/path/to/git/parent/folder"
# @see https://git-scm.com/docs/git-config/2.36.0#Documentation/git-config.txt-safedirectory
#
# Without this fix, git-secret will emit the error
# git-secret: abort: not in dir with git repo. Use 'git init' or 'git clone', then in repo use 'git secret init'
RUN git config --system --add safe.directory "$APP_CODE_PATH"
WORKDIR $APP_CODE_PATH
FROM base as codebase
# By only copying the composer files required to run composer install
# the layer will be cached and only invalidated when the composer dependencies are changed
COPY ./new/composer.json /dependencies/new/
COPY ./new/composer.lock /dependencies/new/
# use a cache mount to cache the composer dependencies
# this is essentially a cache that lives in Docker BuildKit (i.e. has nothing to do with the host system)
RUN --mount=type=cache,target=/tmp/.composer \
cd /dependencies/new && \
# COMPOSER_HOME=/tmp/.composer sets the home directory of composer that
# also controls where composer looks for the cache
# so we don't have to download dependencies again (if they are cached)
# @see https://stackoverflow.com/a/60518444 for the correct if-then-else syntax:
# - end all commands with ; \
# - except THEN and ELSE
if [ "$ENV" == "prod" ] ; \
then \
# on production, we don't want test dependencies
COMPOSER_HOME=/tmp/.composer composer install --no-scripts --no-plugins --no-progress -o --no-dev; \
else \
COMPOSER_HOME=/tmp/.composer composer install --no-scripts --no-plugins --no-progress -o; \
fi
# copy the full codebase
COPY . /codebase
# move the dependencies
RUN mv /dependencies/vendor /codebase/new/vendor
# remove files we don't require in the image to keep the image size small
RUN cd /codebase && \
rm -rf .docker/ .build/ .infrastructure/ && \
if [ "$ENV" == "prod" ] ; \
then \
# on production, we don't want tests
rm -rf tests/; \
fi
# Remove all secrets that are NOT required for the given ENV:
# `find /codebase/.secrets -type f -print` lists all files in the .secrets directory
# `grep -v "/\(shared\|$ENV\)/"` matches only the files that are NOT in the shared/ or $ENV/ (e.g. prod/) directories
# `grep -v ".secret\$"` ensures that we remove all files that are NOT ending in .secret
# FYI:
# the "$" has to be escaped with a "\"
# "Escaping is possible by adding a \ before the variable"
# @see https://docs.docker.com/engine/reference/builder/#environment-replacement
# `xargs rm -f` retrieves the remaining file and deletes them
# FYI:
# `xargs` is necessary to convert the stdin to args for `rm`
# @see https://stackoverflow.com/a/20307392/413531
# the `-f` flag is required so that `rm` doesn't fail if no files are matched
RUN find /codebase/.secrets -type f -print | grep -v "/\(shared\|$ENV\)/" | xargs rm -f && \
find /codebase/.secrets -type f -print | grep -v ".secret\$" | xargs rm -f && \
# list the remaining files for debugging purposes
find /codebase/.secrets -type f -print
# We need a git repository for git-secret to work (can be an empty one)
RUN cd /codebase && \
git init
FROM base as prod
# We will use a custom ENTRYPOINT to decrypt the secrets when the container starts.
# This way, we can store the secrets in their encrypted form directly in the image.
# Note: Because we defined a custom ENTRYPOINT, the default CMD of the base image
# will be overriden. Thus, we must explicitly re-define it here via `CMD ["/bin/sh"]`.
# This behavior is described in the docs as:
# "If CMD is defined from the base image, setting ENTRYPOINT will reset CMD to an empty value. In this scenario, CMD must be defined in the current image to have a value."
# @see https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact
COPY ./.docker/images/php/base/decrypt-secrets.sh /decrypt-secrets.sh
RUN chmod +x /decrypt-secrets.sh
CMD ["/bin/sh"]
ENTRYPOINT ["/decrypt-secrets.sh"]
COPY --from=codebase --chown=$APP_USER_NAME:$APP_GROUP_NAME /codebase $APP_CODE_PATH
COPY --chown=$APP_USER_NAME:$APP_GROUP_NAME ./.build/build-info $APP_CODE_PATH/build-info
FROM base as ci
COPY --from=codebase --chown=$APP_USER_NAME:$APP_GROUP_NAME /codebase $APP_CODE_PATH
FROM base as local
# add app user to sudoers
# see https://ostechnix.com/add-delete-and-grant-sudo-privileges-to-users-in-alpine-linux/ for adding sudo
# see https://askubuntu.com/a/340669 for not requiring a sudo pw
RUN echo "root ALL=(ALL) NOPASSWD: ALL " | tee -a "/etc/sudoers.d/users" && \
echo "${APP_USER_NAME} ALL=(ALL) NOPASSWD: ALL " | tee -a "/etc/sudoers.d/users"
RUN pecl install xdebug

View File

@ -0,0 +1,6 @@
opcache.validate_timestamps = "1"
; "disable" (recheck on every request) on dev
opcache.revalidate_freq = "0"
; enable assert() statements for development
assert.exception = 1
zend.assertions = 1

View File

@ -0,0 +1,15 @@
opcache.validate_timestamps = "1"
; "disable" (recheck on every request) on dev
opcache.revalidate_freq = "0"
opcache.enable = off
; enable assert() statements for development
assert.exception = 1
zend.assertions = 1
; Note:
display_error=1
error_reporting=E_ALL
zend_extension=xdebug
xdebug.client_host=host.docker.internal
xdebug.start_with_request=yes
xdebug.mode=develop,debug

View File

@ -0,0 +1,6 @@
opcache.validate_timestamps = "1"
; "disable" (recheck on every request) on dev
opcache.revalidate_freq = "0"
; enable assert() statements for development
assert.exception = 1
zend.assertions = 1

View File

@ -0,0 +1,13 @@
; https://www.scalingphpbook.com/blog/2014/02/14/best-zend-opcache-settings.html
opcache.enable_cli = 1
opcache.enable = 1
opcache.fast_shutdown = 1
; check with find . -type f -print | grep php | wc -l
opcache.max_accelerated_files = 25000
opcache.validate_timestamps = 0
opcache.memory_consumption=64
opcache.interned_strings_buffer=12
memory_limit = -1
disable_functions =

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
# exit immediately on error
set -e
# initialize make
make make-init ENVS="ENV=prod GPG_PASSWORD=$GPG_PASSWORD"
# read the secret gpg key
make gpg-init
# Only decrypt files required for production
files=$(make secret-list | grep "/\(shared\|prod\)/" | tr '\n' ' ')
make secret-decrypt-with-password FILES="$files"
cp .secrets/prod/app.env .env
# treat this script as a "decorator" and execute any other command after running it
# @see https://www.pascallandau.com/blog/structuring-the-docker-setup-for-php-projects/#using-entrypoint-for-pre-run-configuration
exec "$@"

View File

@ -0,0 +1,22 @@
ARG BASE_IMAGE
FROM ${BASE_IMAGE} as base
COPY ./images/php/cron/conf.d/psc /etc/cron.d/
COPY ./images/php/cron/bin/ /usr/bin/
RUN chmod +x /usr/bin/start-cron.sh
RUN chmod +x /usr/bin/set-env.sh
RUN apt-get update && apt-get install -y cron rsyslog
RUN sed -i '/imklog/s/^/#/' /etc/rsyslog.conf
FROM base as prod
USER $APP_USER_NAME
FROM base as ci
USER $APP_USER_NAME
FROM base as local
CMD ["/usr/bin/set-env.sh"]

View File

@ -0,0 +1,5 @@
#!/bin/bash
# start-cron.sh
declare -p > /container.env
/usr/bin/start-cron.sh

View File

@ -0,0 +1,8 @@
#!/bin/bash
# start-cron.sh
rsyslogd
cron
touch /var/log/cron.log
chmod -R 0777 /data/www/new/var/cache
chmod -R 0777 /data/www/new/var/log
tail -F /var/log/syslog /var/log/cron.log

View File

@ -0,0 +1,5 @@
SHELL=/bin/bash
BASH_ENV=/container.env
#
* * * * * www-data cd /data/www/new/web && /usr/local/bin/php /data/www/new/bin/console --env=prod application:queue:do >> /var/log/cron.log 2>&1
#

View File

@ -0,0 +1,21 @@
ARG BASE_IMAGE
FROM ${BASE_IMAGE} as base
RUN echo ${TARGET_PHP_VERSION}
COPY ./images/php/fpm/php-fpm.d/ /etc/php7/php-fpm.d/
COPY ./images/php/fpm/conf.d/zz-app-fpm.ini $PHP_INI_DIR/conf.d/
COPY ./images/php/fpm/conf.d/policy.xml /etc/ImageMagick-6/policy.xml
RUN sed -i "s/__APP_USER_NAME/$APP_USER_NAME/" /etc/php7/php-fpm.d/* \
&& sed -i "s/__APP_GROUP_NAME/$APP_GROUP_NAME/" /etc/php7/php-fpm.d/*
USER $APP_USER_NAME
EXPOSE 9000
CMD ["php-fpm", "-F"]
FROM base as prod
FROM base as local

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policymap [
<!ELEMENT policymap (policy)+>
<!ATTLIST policymap xmlns CDATA #FIXED ''>
<!ELEMENT policy EMPTY>
<!ATTLIST policy xmlns CDATA #FIXED '' domain NMTOKEN #REQUIRED
name NMTOKEN #IMPLIED pattern CDATA #IMPLIED rights NMTOKEN #IMPLIED
stealth NMTOKEN #IMPLIED value CDATA #IMPLIED>
]>
<!--
Configure ImageMagick policies.
Domains include system, delegate, coder, filter, path, or resource.
Rights include none, read, write, execute and all. Use | to combine them,
for example: "read | write" to permit read from, or write to, a path.
Use a glob expression as a pattern.
Suppose we do not want users to process MPEG video images:
<policy domain="delegate" rights="none" pattern="mpeg:decode" />
Here we do not want users reading images from HTTP:
<policy domain="coder" rights="none" pattern="HTTP" />
The /repository file system is restricted to read only. We use a glob
expression to match all paths that start with /repository:
<policy domain="path" rights="read" pattern="/repository/*" />
Lets prevent users from executing any image filters:
<policy domain="filter" rights="none" pattern="*" />
Any large image is cached to disk rather than memory:
<policy domain="resource" name="area" value="1GP"/>
Define arguments for the memory, map, area, width, height and disk resources
with SI prefixes (.e.g 100MB). In addition, resource policies are maximums
for each instance of ImageMagick (e.g. policy memory limit 1GB, -limit 2GB
exceeds policy maximum so memory limit is 1GB).
Rules are processed in order. Here we want to restrict ImageMagick to only
read or write a small subset of proven web-safe image types:
<policy domain="delegate" rights="none" pattern="*" />
<policy domain="filter" rights="none" pattern="*" />
<policy domain="coder" rights="none" pattern="*" />
<policy domain="coder" rights="read|write" pattern="{GIF,JPEG,PNG,WEBP}" />
-->
<policymap>
<!-- <policy domain="system" name="shred" value="2"/> -->
<!-- <policy domain="system" name="precision" value="6"/> -->
<!-- <policy domain="system" name="memory-map" value="anonymous"/> -->
<!-- <policy domain="system" name="max-memory-request" value="256MiB"/> -->
<!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
<policy domain="resource" name="memory" value="256MiB"/>
<policy domain="resource" name="map" value="512MiB"/>
<policy domain="resource" name="width" value="16KP"/>
<policy domain="resource" name="height" value="16KP"/>
<!-- <policy domain="resource" name="list-length" value="128"/> -->
<policy domain="resource" name="area" value="128MB"/>
<policy domain="resource" name="disk" value="1GiB"/>
<!-- <policy domain="resource" name="file" value="768"/> -->
<!-- <policy domain="resource" name="thread" value="4"/> -->
<!-- <policy domain="resource" name="throttle" value="0"/> -->
<!-- <policy domain="resource" name="time" value="3600"/> -->
<!-- <policy domain="coder" rights="none" pattern="MVG" /> -->
<policy domain="module" rights="read | write" pattern="{PS,PDF,XPS}" />
<!-- <policy domain="delegate" rights="none" pattern="HTTPS" /> -->
<!-- <policy domain="path" rights="none" pattern="@*" /> -->
<!-- <policy domain="cache" name="memory-map" value="anonymous"/> -->
<!-- <policy domain="cache" name="synchronize" value="True"/> -->
<!-- <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/> -->
<!-- <policy domain="system" name="pixel-cache-memory" value="anonymous"/> -->
<!-- <policy domain="system" name="shred" value="2"/> -->
<!-- <policy domain="system" name="precision" value="6"/> -->
<!-- not needed due to the need to use explicitly by mvg: -->
<!-- <policy domain="delegate" rights="none" pattern="MVG" /> -->
<!-- use curl -->
<policy domain="delegate" rights="none" pattern="URL" />
<policy domain="delegate" rights="none" pattern="HTTPS" />
<policy domain="delegate" rights="none" pattern="HTTP" />
<!-- in order to avoid to get image with password text -->
<policy domain="path" rights="none" pattern="@*"/>
</policymap>

View File

@ -0,0 +1,11 @@
; overriding defaults
default_socket_timeout=4000
request_terminate_timeout=4000
max_execution_time = 4000
max_input_vars = 10000
memory_limit=1024M
date.timezone=Europe/Berlin
upload_max_filesize = 1024M
post_max_size = 1024M
intl.default_locale=de
short_open_tag=On

View File

@ -0,0 +1,15 @@
error_log = /proc/self/fd/2
[www]
access.log = /proc/self/fd/1
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
catch_workers_output = yes
user = __APP_USER_NAME
group = __APP_GROUP_NAME
listen = 0.0.0.0:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
!.env.example
.env
.idea
src/

View File

@ -0,0 +1,22 @@
##@ [Application: Setup]
.PHONY: setup
setup: ## Setup the application
"$(MAKE)" composer ARGS="--working-dir=/data/www/new install"
"$(MAKE)" setup-db
.PHONY: setup-db
setup-db: ## Setup the DB tables
$(DOCKER_COMPOSE) cp ./.setup $(DOCKER_SERVICE_NAME_PHP_MYSQL):/setup
$(DOCKER_COMPOSE) exec -T $(DOCKER_SERVICE_NAME_PHP_MYSQL) bash -c 'mysql --password=$$MYSQL_ROOT_PASSWORD psc < /setup/mysql/backup.sql'
$(DOCKER_COMPOSE) cp ./.setup $(DOCKER_SERVICE_NAME_PHP_MONGODB):/setup
$(DOCKER_COMPOSE) exec -T $(DOCKER_SERVICE_NAME_PHP_MONGODB) bash -c 'mongorestore /setup/mongodb/'
.PHONY: composer
composer: ## Run composer commands. Specify the command e.g. via ARGS="install"
$(EXECUTE_IN_APPLICATION_CONTAINER) composer $(ARGS);
.PHONY: phpunit
phpunit: ## Run PHPUNIT
$(EXECUTE_IN_APPLICATION_CONTAINER) /data/www/new/vendor/bin/phpunit;

View File

@ -0,0 +1,31 @@
##@ [Application: Commands]
# @see https://stackoverflow.com/a/43076457
.PHONY: restart-php-fpm
restart-php-fpm: ## Restart the php-fpm service
"$(MAKE)" execute-in-container DOCKER_SERVICE_NAME=$(DOCKER_SERVICE_NAME_PHP_FPM) COMMAND="kill -USR2 1"
.PHONY: execute-in-container
execute-in-container: ## Execute a command in a container. E.g. via "make execute-in-container DOCKER_SERVICE_NAME=php-fpm COMMAND="echo 'hello'"
@$(if $(DOCKER_SERVICE_NAME),,$(error DOCKER_SERVICE_NAME is undefined))
@$(if $(COMMAND),,$(error COMMAND is undefined))
$(EXECUTE_IN_ANY_CONTAINER) $(COMMAND)
.PHONY: execute-in-application-container
execute-in-application-container: ## Execute a command in a container. E.g. via "make execute-in-container DOCKER_SERVICE_NAME=php-fpm COMMAND="echo 'hello'"
@$(if $(COMMAND),,$(error COMMAND is undefined))
$(EXECUTE_IN_APPLICATION_CONTAINER) $(COMMAND)
.PHONY: copy-in-mysql
copy-in-mysql: ## Execute a command in a container. E.g. via "make execute-in-container DOCKER_SERVICE_NAME=php-fpm COMMAND="echo 'hello'"
@$(if $(FROM),,$(error FROM is undefined))
@$(if $(TO),,$(error TO is undefined))
$(COPY_IN_MYSQL_CONTAINER)
.PHONY: enable-xdebug
enable-xdebug: ## Enable xdebug in the given container specified by "DOCKER_SERVICE_NAME". E.g. "make enable-xdebug DOCKER_SERVICE_NAME=php-fpm"
"$(MAKE)" execute-in-container APP_USER_NAME="root" DOCKER_SERVICE_NAME=$(DOCKER_SERVICE_NAME) COMMAND="sed -i 's/.*zend_extension=xdebug/zend_extension=xdebug/' '/etc/php8/conf.d/zz-app-local.ini'"
.PHONY: disable-xdebug
disable-xdebug: ## Disable xdebug in the given container specified by "DOCKER_SERVICE_NAME". E.g. "make disable-xdebug DOCKER_SERVICE_NAME=php-fpm"
"$(MAKE)" execute-in-container APP_USER_NAME="root" DOCKER_SERVICE_NAME=$(DOCKER_SERVICE_NAME) COMMAND="sed -i 's/.*zend_extension=xdebug/;zend_extension=xdebug/' '/etc/php8/conf.d/zz-app-local.ini'"

109
.make/03-application-qa.mk Normal file
View File

@ -0,0 +1,109 @@
##@ [Application: QA]
# variables
CORES?=$(shell (nproc || sysctl -n hw.ncpu) 2> /dev/null)
# constants
## files
ALL_FILES=./
APP_FILES=src/
TEST_FILES=tests/
## bash colors
RED:=\033[0;31m
GREEN:=\033[0;32m
YELLOW:=\033[0;33m
NO_COLOR:=\033[0m
# Tool CLI config
PHPUNIT_CMD=php vendor/bin/phpunit
PHPUNIT_ARGS= -c phpunit.xml
PHPUNIT_FILES=
PHPSTAN_CMD=php -d xdebug.mode=off -d memory_limit=-1 vendor/bin/phpstan analyse
PHPSTAN_ARGS=--level=9
PHPSTAN_FILES=$(APP_FILES) $(TEST_FILES)
PHPCS_CMD=php -d xdebug.mode=off -d memory_limit=-1 vendor/bin/phpcs
PHPCS_ARGS=--parallel=$(CORES) --standard=psr12
PHPCS_FILES=$(APP_FILES)
PHPCBF_CMD=php -d xdebug.mode=off -d memory_limit=-1 vendor/bin/phpcbf
PHPCBF_ARGS=$(PHPCS_ARGS)
PHPCBF_FILES=$(PHPCS_FILES)
PARALLEL_LINT_CMD=php -d xdebug.mode=off -d memory_limit=-1 vendor/bin/parallel-lint
PARALLEL_LINT_ARGS=-j 4 --exclude vendor/ --exclude .docker --exclude .git
PARALLEL_LINT_FILES=$(ALL_FILES)
COMPOSER_REQUIRE_CHECKER_CMD=php -d xdebug.mode=off -d memory_limit=-1 vendor/bin/composer-require-checker
COMPOSER_REQUIRE_CHECKER_ARGS=--ignore-parse-errors
# call with NO_PROGRESS=true to hide tool progress (makes sense when invoking multiple tools together)
NO_PROGRESS?=false
ifeq ($(NO_PROGRESS),true)
PHPSTAN_ARGS+= --no-progress
PARALLEL_LINT_ARGS+= --no-progress
else
PHPCS_ARGS+= -p
PHPCBF_ARGS+= -p
endif
# Use NO_PROGRESS=false when running individual tools.
# On NO_PROGRESS=true the corresponding tool has no output on success
# apart from its runtime but it will still print
# any errors that occured.
define execute
if [ "$(NO_PROGRESS)" = "false" ]; then \
eval "$(EXECUTE_IN_APPLICATION_CONTAINER) bash -c 'cd new && $(1) $(2) $(3) $(4)'"; \
else \
START=$$(date +%s); \
printf "%-35s" "$@"; \
if OUTPUT=$$(eval "$(EXECUTE_IN_APPLICATION_CONTAINER) bash -c 'cd new && $(1) $(2) $(3) $(4)'" 2>&1); then \
printf " $(GREEN)%-6s$(NO_COLOR)" "done"; \
END=$$(date +%s); \
RUNTIME=$$((END-START)) ;\
printf " took $(YELLOW)$${RUNTIME}s$(NO_COLOR)\n"; \
else \
printf " $(RED)%-6s$(NO_COLOR)" "fail"; \
END=$$(date +%s); \
RUNTIME=$$((END-START)) ;\
printf " took $(YELLOW)$${RUNTIME}s$(NO_COLOR)\n"; \
echo "$$OUTPUT"; \
printf "\n"; \
exit 1; \
fi; \
fi
endef
.PHONY: test
test: ## Run all tests
@$(EXECUTE_IN_APPLICATION_CONTAINER) $(PHPUNIT_CMD) $(PHPUNIT_ARGS) $(ARGS)
.PHONY: phplint
phplint: ## Run phplint on all files
@$(call execute,$(PARALLEL_LINT_CMD),$(PARALLEL_LINT_ARGS),$(PARALLEL_LINT_FILES), $(ARGS))
.PHONY: phpcs
phpcs: ## Run style check on all application files
@$(call execute,$(PHPCS_CMD),$(PHPCS_ARGS),$(PHPCS_FILES), $(ARGS))
.PHONY: phpcbf
phpcbf: ## Run style fixer on all application files
@$(call execute,$(PHPCBF_CMD),$(PHPCBF_ARGS),$(PHPCBF_FILES), $(ARGS))
.PHONY: phpstan
phpstan: ## Run static analyzer on all application and test files
@$(call execute,$(PHPSTAN_CMD),$(PHPSTAN_ARGS),$(PHPSTAN_FILES), $(ARGS))
.PHONY: composer-require-checker
composer-require-checker: ## Run dependency checker
@$(call execute,$(COMPOSER_REQUIRE_CHECKER_CMD),$(COMPOSER_REQUIRE_CHECKER_ARGS),"", $(ARGS))
.PHONY: qa
qa: ## Run code quality tools on all files
@"$(MAKE)" -j $(CORES) -k --no-print-directory --output-sync=target qa-exec NO_PROGRESS=true
.PHONY: qa-exec
qa-exec: phpstan \
phplint \
phpcs
#composer-require-checker \

144
.make/04-docker.mk Normal file
View File

@ -0,0 +1,144 @@
# For local builds we always want to use "latest" as tag per default
ifeq ($(ENV),local)
TAG:=latest
endif
# Enable buildkit for docker and docker-compose by default for every environment.
# For specific environments (e.g. MacBook with Apple Silicon M1 CPU) it should be turned off to work stable
# - this can be done in the .make/.env file
COMPOSE_DOCKER_CLI_BUILD?=1
DOCKER_BUILDKIT?=1
export COMPOSE_DOCKER_CLI_BUILD
export DOCKER_BUILDKIT
# Container names
## must match the names used in the docker-composer.yml files
DOCKER_SERVICE_NAME_WEB:=web
DOCKER_SERVICE_NAME_PHP_BASE:=php-base
DOCKER_SERVICE_NAME_PHP_FPM:=php-fpm
DOCKER_SERVICE_NAME_PHP_CRON:=cron
DOCKER_SERVICE_NAME_PHP_MYSQL:=mysql
DOCKER_SERVICE_NAME_PHP_MONGODB:=mongodb
DOCKER_SERVICE_NAME_APPLICATION:=application
# FYI:
# Naming convention for images is $(DOCKER_REGISTRY)/$(DOCKER_NAMESPACE)/$(DOCKER_SERVICE_NAME)-$(ENV)
# e.g. docker.io/dofroscra/nginx-local
# $(DOCKER_REGISTRY)---^ ^ ^ ^ docker.io
# $(DOCKER_NAMESPACE)-------------^ ^ ^ dofroscra
# $(DOCKER_SERVICE_NAME)------------------^ ^ nginx
# $(ENV)-----------------------------------------^ local
DOCKER_DIR:=./.docker
DOCKER_ENV_FILE:=$(DOCKER_DIR)/.env
DOCKER_COMPOSE_DIR:=$(DOCKER_DIR)/docker-compose
DOCKER_COMPOSE_FILE:=$(DOCKER_COMPOSE_DIR)/docker-compose.yml
DOCKER_COMPOSE_FILE_LOCAL:=$(DOCKER_COMPOSE_DIR)/docker-compose.local.yml
DOCKER_COMPOSE_FILE_PHP_BASE:=$(DOCKER_COMPOSE_DIR)/docker-compose-php-base.yml
DOCKER_COMPOSE_PROJECT_NAME:=tp_$(ENV)
# we need a couple of environment variables for docker-compose so we define a make-variable that we can
# then reference later in the Makefile without having to repeat all the environment variables
DOCKER_COMPOSE_COMMAND:=ENV=$(ENV) \
TAG=$(TAG) \
DOCKER_REGISTRY=$(DOCKER_REGISTRY) \
DOCKER_NAMESPACE=$(DOCKER_NAMESPACE) \
APP_USER_ID=$(APP_USER_ID) \
APP_GROUP_ID=$(APP_GROUP_ID) \
APP_USER_NAME=$(APP_USER_NAME) \
docker compose -p $(DOCKER_COMPOSE_PROJECT_NAME) --env-file $(DOCKER_ENV_FILE)
DOCKER_COMPOSE:=$(DOCKER_COMPOSE_COMMAND) -f $(DOCKER_COMPOSE_FILE) -f $(DOCKER_COMPOSE_FILE_LOCAL)
DOCKER_COMPOSE_PHP_BASE:=$(DOCKER_COMPOSE_COMMAND) -f $(DOCKER_COMPOSE_FILE_PHP_BASE)
EXECUTE_IN_ANY_CONTAINER?=
EXECUTE_IN_CRON_CONTAINER?=
EXECUTE_IN_APPLICATION_CONTAINER?=
EXECUTE_IN_MONGODB_CONTAINER?=
EXECUTE_IN_mYSQL_CONTAINER?=
COPY_IN_ANY_CONTAINER?=
COPY_IN_CRON_CONTAINER?=
COPY_IN_APPLICATION_CONTAINER?=
COPY_IN_MONGODB_CONTAINER?=
COPY_IN_mYSQL_CONTAINER?=
DOCKER_SERVICE_NAME?=
FROM?=
TO?=
# we can pass EXECUTE_IN_CONTAINER=true to a make invocation in order to execute the target in a docker container.
# Caution: this only works if the command in the target is prefixed with a $(EXECUTE_IN_*_CONTAINER) variable.
# If EXECUTE_IN_CONTAINER is NOT defined, we will check if make is ALREADY executed in a docker container.
# We still need a way to FORCE the execution in a container, e.g. for Gitlab CI, because the Gitlab
# Runner is executed as a docker container BUT we want to execute commands in OUR OWN docker containers!
EXECUTE_IN_CONTAINER?=
ifndef EXECUTE_IN_CONTAINER
# check if 'make' is executed in a docker container, see https://stackoverflow.com/a/25518538/413531
# `wildcard $file` checks if $file exists, see https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html
# i.e. if the result is "empty" then $file does NOT exist => we are NOT in a container
ifeq ("$(wildcard /.dockerenv)","")
EXECUTE_IN_CONTAINER=true
endif
endif
ifeq ($(EXECUTE_IN_CONTAINER),true)
EXECUTE_IN_ANY_CONTAINER:=$(DOCKER_COMPOSE) exec -T --user $(APP_USER_NAME) $(DOCKER_SERVICE_NAME)
EXECUTE_IN_APPLICATION_CONTAINER:=$(DOCKER_COMPOSE) exec -w /data/www/new -T --user $(APP_USER_NAME) $(DOCKER_SERVICE_NAME_APPLICATION)
EXECUTE_IN_CRON_CONTAINER:=$(DOCKER_COMPOSE) exec -T --user $(APP_USER_NAME) $(DOCKER_SERVICE_NAME_PHP_CRON)
EXECUTE_IN_MYSQL_CONTAINER:=$(DOCKER_COMPOSE) exec -T $(DOCKER_SERVICE_NAME_PHP_MYSQL)
EXECUTE_IN_MONGODB_CONTAINER:=$(DOCKER_COMPOSE) exec -T $(DOCKER_SERVICE_NAME_PHP_MONGODB)
COPY_IN_ANY_CONTAINER:=$(DOCKER_COMPOSE) cp $(FROM) $(DOCKER_SERVICE_NAME):$(TO)
COPY_IN_APPLICATION_CONTAINER:=$(DOCKER_COMPOSE) cp $(FROM) $(DOCKER_SERVICE_NAME_APPLICATION):$(TO)
COPY_IN_CRON_CONTAINER:=$(DOCKER_COMPOSE) cp $(FROM) $(DOCKER_SERVICE_NAME_PHP_CRON):$(TO)
COPY_IN_MYSQL_CONTAINER:=$(DOCKER_COMPOSE) cp $(FROM) $(DOCKER_SERVICE_NAME_PHP_MYSQL):$(TO)
COPY_IN_MONGODB_CONTAINER:=$(DOCKER_COMPOSE) cp $(FROM) $(DOCKER_SERVICE_NAME_PHP_MONGODB):$(TO)
endif
##@ [Docker]
.PHONY: docker-clean
docker-clean: ## Remove the .env file for docker
@rm -f $(DOCKER_ENV_FILE)
.PHONY: validate-docker-variables
validate-docker-variables: .docker/.env
@$(if $(TAG),,$(error TAG is undefined))
@$(if $(ENV),,$(error ENV is undefined))
@$(if $(DOCKER_REGISTRY),,$(error DOCKER_REGISTRY is undefined - Did you run make-init?))
@$(if $(DOCKER_NAMESPACE),,$(error DOCKER_NAMESPACE is undefined - Did you run make-init?))
@$(if $(APP_USER_ID),,$(error APP_USER_ID is undefined - Did you run make-init?))
@$(if $(APP_GROUP_ID),,$(error APP_GROUP_ID is undefined - Did you run make-init?))
@$(if $(APP_USER_NAME),,$(error APP_USER_NAME is undefined - Did you run make-init?))
.docker/.env:
@cp $(DOCKER_ENV_FILE).example $(DOCKER_ENV_FILE)
.PHONY:docker-build-image
docker-build-image: validate-docker-variables ## Build all docker images OR a specific image by providing the service name via: make docker-build DOCKER_SERVICE_NAME=<service>
$(DOCKER_COMPOSE) build $(DOCKER_SERVICE_NAME)
.PHONY: docker-build-php
docker-build-php: validate-docker-variables ## Build the php base image
$(DOCKER_COMPOSE_PHP_BASE) build $(DOCKER_SERVICE_NAME_PHP_BASE)
.PHONY: docker-build
docker-build: docker-build-php docker-build-image ## Build the php image and then all other docker images
.PHONY: docker-up
docker-up: validate-docker-variables ## Create and start all docker containers. To create/start only a specific container, use DOCKER_SERVICE_NAME=<service>
$(DOCKER_COMPOSE) up -d $(DOCKER_SERVICE_NAME)
.PHONY: docker-down
docker-down: validate-docker-variables ## Stop and remove all docker containers.
@$(DOCKER_COMPOSE) down
.PHONY: docker-config
docker-config: validate-docker-variables ## List the configuration
@$(DOCKER_COMPOSE) config
.PHONY: docker-prune
docker-prune: ## Remove ALL unused docker resources, including volumes
@docker system prune -a -f --volumes

5
.make/05-symfony.mk Normal file
View File

@ -0,0 +1,5 @@
##@ [Application: Symfony]
.PHONY: console
console: ## Run composer commands. Specify the command e.g. via ARGS="install"
$(EXECUTE_IN_APPLICATION_CONTAINER) php "/data/www/new/bin/console" $(ARGS);

26
.make/variables.env Normal file
View File

@ -0,0 +1,26 @@
DOCKER_REGISTRY=gitlab.com/boonkerz
DOCKER_NAMESPACE=boonkerz
APP_USER_NAME=application
APP_USER_ID=10000
APP_GROUP_ID=10001
APP_CODE_PATH_CONTAINER=/data/www
DOCKER_SERVICE_NAME_WEB:=web
DOCKER_SERVICE_NAME_PHP_BASE:=php-base
DOCKER_SERVICE_NAME_PHP_FPM:=php-fpm
DOCKER_SERVICE_NAME_PHP_CRON:=php-cron
DOCKER_SERVICE_NAME_APPLICATION:=application
DOCKER_SERVICE_NAME_MYSQL:=mysql
DOCKER_SERVICE_NAME_MONGODB:=mongodb
# VM / instance names
VM_NAME_APPLICATION=$(DOCKER_SERVICE_NAME_APPLICATION)-vm
VM_NAME_PHP_FPM=$(DOCKER_SERVICE_NAME_PHP_FPM)-vm
VM_NAME_PHP_CRON=$(DOCKER_SERVICE_NAME_PHP_CRON)-vm
VM_NAME_WEB=$(DOCKER_SERVICE_NAME_WEB)-vm
VM_NAME_MYSQL=$(DOCKER_SERVICE_NAME_MYSQL)-vm
VM_NAME_MONGODB=$(DOCKER_SERVICE_NAME_MONGODB)-vm
# Helpers
ALL_VM_SERVICE_NAMES=$(VM_NAME_APPLICATION):$(DOCKER_SERVICE_NAME_APPLICATION) $(VM_NAME_PHP_FPM):$(DOCKER_SERVICE_NAME_PHP_FPM) $(VM_NAME_PHP_CRON):$(DOCKER_SERVICE_NAME_PHP_CRON) $(VM_NAME_WEB):$(DOCKER_SERVICE_NAME_WEB)

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Some files were not shown because too many files have changed in this diff Show More