From fdcb63f25168aaf9292c06f1743298750b2d6e6b Mon Sep 17 00:00:00 2001
From: Mateus Villar <mromeravillar@gmail.com>
Date: Wed, 21 Apr 2021 01:14:47 -0300
Subject: [PATCH] Added #9313: Add new fpm-alpine docker image and docker
 secrets support  (#9331)

* Add docker secret support

* Add docker secret support to selected environment variables below:

- APP_KEY_FILE        -> APP_KEY;

- DB_HOST_FILE        -> DB_HOST;
- DB_PORT_FILE        -> DB_PORT;
- DB_DATABASE_FILE    -> DB_DATABASE;
- DB_USERNAME_FILE    -> DB_USERNAME;
- DB_PASSWORD_FILE    -> DB_PASSWORD;

- REDIS_HOST_FILE     -> REDIS_HOST;
- REDIS_PASSWORD_FILE -> REDIS_PASSWORD;
- REDIS_PORT_FILE     -> REDIS_PORT;

- MAIL_HOST_FILE      -> MAIL_HOST;
- MAIL_PORT_FILE      -> MAIL_PORT;
- MAIL_USERNAME_FILE  -> MAIL_USERNAME;
- MAIL_PASSWORD_FILE  -> MAIL_PASSWORD;

* Add env file for docker secrets

* Added #9313: add new fpm-image using docker secrets

* Fix broken symlinks

* Add docker secrets support using shell script

* Remove old docker config php files
---
 Dockerfile.fpm-alpine       | 102 +++++++++++++++++++++++++++++++
 docker/docker-entrypoint.sh | 119 ++++++++++++++++++++++++++++++++++++
 docker/docker-secrets.env   |  54 ++++++++++++++++
 3 files changed, 275 insertions(+)
 create mode 100644 Dockerfile.fpm-alpine
 create mode 100755 docker/docker-entrypoint.sh
 create mode 100644 docker/docker-secrets.env

diff --git a/Dockerfile.fpm-alpine b/Dockerfile.fpm-alpine
new file mode 100644
index 000000000..3452a6f89
--- /dev/null
+++ b/Dockerfile.fpm-alpine
@@ -0,0 +1,102 @@
+ARG ENVIRONMENT=production
+ARG SNIPEIT_RELEASE=5.1.3
+ARG PHP_VERSION=7.4.16
+ARG PHP_ALPINE_VERSION=3.13
+ARG COMPOSER_VERSION=2.0.11
+
+# Cannot use arguments with 'COPY --from' workaround
+# https://github.com/moby/moby/issues/34482#issuecomment-454716952
+FROM composer:${COMPOSER_VERSION} AS composer
+
+# Final stage
+FROM php:${PHP_VERSION}-fpm-alpine${PHP_ALPINE_VERSION} AS source
+LABEL maintainer="Mateus Villar <mromeravillar@gmail.com>"
+
+ARG PACKAGES="\
+		mysql-client \
+"
+ARG DEV_PACKAGES="\
+		git \
+"
+ARG ENVIRONMENT
+ENV ENVIRONMENT ${ENVIRONMENT}
+ARG SNIPEIT_RELEASE
+ENV SNIPEIT_RELEASE ${SNIPEIT_RELEASE}
+
+# Cribbed from wordpress-fpm-alpine image
+# set recommended PHP.ini settings
+# see https://secure.php.net/manual/en/opcache.installation.php
+RUN set -eux; \
+	docker-php-ext-enable opcache; \
+	{ \
+		echo 'opcache.memory_consumption=128'; \
+		echo 'opcache.interned_strings_buffer=8'; \
+		echo 'opcache.max_accelerated_files=4000'; \
+		echo 'opcache.revalidate_freq=2'; \
+		echo 'opcache.fast_shutdown=1'; \
+	} > /usr/local/etc/php/conf.d/opcache-recommended.ini
+# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging
+RUN { \
+# https://www.php.net/manual/en/errorfunc.constants.php
+# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670
+		echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \
+		echo 'display_errors = Off'; \
+		echo 'display_startup_errors = Off'; \
+		echo 'log_errors = On'; \
+		echo 'error_log = /dev/stderr'; \
+		echo 'log_errors_max_len = 1024'; \
+		echo 'ignore_repeated_errors = On'; \
+		echo 'ignore_repeated_source = Off'; \
+		echo 'html_errors = Off'; \
+	} > /usr/local/etc/php/conf.d/error-logging.ini
+
+# Install php extensions inside docker containers easily
+# https://github.com/mlocati/docker-php-extension-installer
+COPY --from=mlocati/php-extension-installer:1.2.19 /usr/bin/install-php-extensions /usr/local/bin/
+RUN set -eux; \
+    install-php-extensions \
+        bcmath \
+        gd \
+        ldap \
+        mysqli \
+        pdo_mysql \
+        zip; \
+    rm -f /usr/local/bin/install-php-extensions; \
+# Install prerequisites packages
+    apk add --no-cache \
+        ${PACKAGES};
+
+COPY --from=composer /usr/bin/composer /usr/local/bin
+ARG COMPOSER_ALLOW_SUPERUSER=1
+RUN set -eux; \
+# Download and extract snipeit tarball
+	curl -o snipeit.tar.gz -fL "https://github.com/snipe/snipe-it/archive/v$SNIPEIT_RELEASE.tar.gz"; \
+	tar -xzf snipeit.tar.gz --strip-components=1 -C /var/www/html/; \
+	rm snipeit.tar.gz; \
+# Install composer php dependencies
+    if [ "$ENVIRONMENT" = "production" ]; then \
+        echo "production enviroment detected!"; \
+        composer update \
+            --no-cache \
+            --no-dev \
+            --optimize-autoloader \
+            --working-dir=/var/www/html; \
+    else \
+        echo "development enviroment detected!"; \
+        apk add --no-cache \
+            ${DEV_PACKAGES}; \
+        composer update \
+            --no-cache \
+			--prefer-source \
+            --optimize-autoloader \
+            --working-dir=/var/www/html; \
+    fi; \
+	rm -f /usr/local/bin/composer; \
+	chown -R www-data:www-data /var/www/html;
+
+VOLUME [ "/var/lib/snipeit" ]
+
+COPY --chown=www-data:www-data docker/docker-secrets.env /var/www/html/.env
+COPY --chmod=655 docker/docker-entrypoint.sh /usr/local/bin/docker-snipeit-entrypoint
+ENTRYPOINT [ "/usr/local/bin/docker-snipeit-entrypoint" ]
+CMD [ "/usr/local/bin/docker-php-entrypoint", "php-fpm" ]
\ No newline at end of file
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
new file mode 100755
index 000000000..3b783419e
--- /dev/null
+++ b/docker/docker-entrypoint.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+set -eo pipefail;
+
+# Cribbed from nextcloud docker official repo
+# https://github.com/nextcloud/docker/blob/master/docker-entrypoint.sh
+# usage: file_env VAR [DEFAULT]
+#    ie: file_env 'XYZ_DB_PASSWORD' 'example'
+# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
+#  "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
+file_env() {
+    local var="$1"
+    local fileVar="${var}_FILE"
+    local def="${2:-}"
+    local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//")
+    local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//")
+    if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then
+        echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
+        exit 1
+    fi
+    if [ -n "${varValue}" ]; then
+        export "$var"="${varValue}"
+    elif [ -n "${fileVarValue}" ]; then
+        export "$var"="$(cat "${fileVarValue}")"
+    elif [ -n "${def}" ]; then
+        export "$var"="$def"
+    fi
+    unset "$fileVar"
+}
+
+# Add docker secrets support for the variables below:
+file_env APP_KEY
+file_env DB_HOST
+file_env DB_PORT
+file_env DB_DATABASE
+file_env DB_USERNAME
+file_env DB_PASSWORD
+file_env REDIS_HOST
+file_env REDIS_PASSWORD
+file_env REDIS_PORT
+file_env MAIL_HOST
+file_env MAIL_PORT
+file_env MAIL_USERNAME
+file_env MAIL_PASSWORD
+
+echo [INFO docker entrypoint] Start script execution
+
+# Generate new app key if none is provided
+if [ -z "$APP_KEY" -a -z "$APP_KEY_FILE" ]
+then
+  echo "Please re-run this container with an environment variable \$APP_KEY"
+  echo "An example APP_KEY you could use is: "
+  php artisan key:generate --show
+  exit
+fi
+
+# Directory configuration
+rm -rf \
+  "/var/www/html/storage/private_uploads" \
+  "/var/www/html/public/uploads" \
+  "/var/www/html/storage/app/backups"
+
+# Create data directories
+for dir in \
+  'data/private_uploads' \
+  'data/uploads/accessories' \
+  'data/uploads/avatars' \
+  'data/uploads/barcodes' \
+  'data/uploads/categories' \
+  'data/uploads/companies' \
+  'data/uploads/components' \
+  'data/uploads/consumables' \
+  'data/uploads/departments' \
+  'data/uploads/locations' \
+  'data/uploads/manufacturers' \
+  'data/uploads/models' \
+  'data/uploads/suppliers' \
+  'dumps' \
+  'keys'
+do
+  [ ! -d "/var/lib/snipeit/$dir" ] && mkdir -p "/var/lib/snipeit/$dir"
+done
+
+# Sync /var/lib/snipeit (docker volume) with /var/www/html directory
+ln -fs \
+  "/var/lib/snipeit/data/private_uploads" "/var/www/html/storage/private_uploads"
+ln -fs \
+  "/var/lib/snipeit/data/uploads" "/var/www/html/public/uploads"
+ln -fs \
+  "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups"
+ln -fs \
+  "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key"
+ln -fs \
+  "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key"
+
+# If the Oauth DB files are not present copy the vendor files over to the db migrations
+if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ]
+then
+  cp -a /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/
+fi
+
+# Create laravel log file
+touch /var/www/html/storage/logs/laravel.log
+# Add correct permissions for files and directories
+chown www-data:www-data /var/www/html/storage/logs/laravel.log
+chown -R www-data:www-data \
+  /var/lib/snipeit/data \
+  /var/lib/snipeit/dumps \
+  /var/lib/snipeit/keys
+
+# Migrate/create database
+php artisan migrate --force
+# Clear cache files
+php artisan config:clear
+php artisan config:cache
+
+echo [INFO docker entrypoint] End script execution
+
+exec "$@" 
\ No newline at end of file
diff --git a/docker/docker-secrets.env b/docker/docker-secrets.env
new file mode 100644
index 000000000..45a777f5d
--- /dev/null
+++ b/docker/docker-secrets.env
@@ -0,0 +1,54 @@
+# --------------------------------------------
+# REQUIRED: BASIC APP SETTINGS
+# --------------------------------------------
+#APP_ENV=develop
+#APP_DEBUG=false
+#APP_KEY=Change_this_key_or_snipe_will_get_ya
+#APP_URL=http://127.0.0.1:32782
+#APP_TIMEZONE=US/Pacific
+#APP_LOCALE=en
+
+
+# --------------------------------------------
+# REQUIRED: DATABASE SETTINGS
+# --------------------------------------------
+DB_CONNECTION=mysql
+DB_PREFIX=null
+DB_DUMP_PATH='/usr/bin'
+
+
+# --------------------------------------------
+# REQUIRED: OUTGOING MAIL SERVER SETTINGS
+# --------------------------------------------
+MAIL_DRIVER=smtp
+MAIL_ENCRYPTION=${MAIL_ENV_ENCRYPTION}
+MAIL_FROM_ADDR=${MAIL_ENV_FROM_ADDR}
+MAIL_FROM_NAME=${MAIL_ENV_FROM_NAME}
+MAIL_REPLYTO_ADDR=${MAIL_ENV_FROM_ADDR}
+MAIL_REPLYTO_NAME=${MAIL_ENV_FROM_NAME}
+
+
+# --------------------------------------------
+# REQUIRED: IMAGE LIBRARY
+# This should be gd or imagick
+# --------------------------------------------
+IMAGE_LIB=gd
+
+
+# --------------------------------------------
+# OPTIONAL: SESSION SETTINGS
+# --------------------------------------------
+SESSION_LIFETIME=12000
+EXPIRE_ON_CLOSE=false
+ENCRYPT=false
+COOKIE_NAME=snipeit_session
+COOKIE_DOMAIN=null
+SECURE_COOKIES=false
+
+
+# --------------------------------------------
+# OPTIONAL: CACHE SETTINGS
+# --------------------------------------------
+CACHE_DRIVER=file
+SESSION_DRIVER=file
+QUEUE_DRIVER=sync
-- 
GitLab