From 5eee04b5b181ce32cce2d930263fd9fd6f79a8f8 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 18 Sep 2017 11:54:12 +0100 Subject: [PATCH] Implement image templating (#102) * Use templating to build the PHP images * Use PHP 7.0 in the example Docker Compose files We can't install a version of Magento that's compatible with 7.1 at the moment * Fix CS issues in the Builder script * Add instructions on building --- 7.0-cli/Dockerfile | 72 +-- ...ocker-environment => docker-entrypoint.sh} | 13 +- 7.0-fpm/Dockerfile | 44 +- ...ocker-environment => docker-entrypoint.sh} | 11 +- 7.0-fpm/etc/php.ini | 3 - 7.1-cli/Dockerfile | 82 ++-- 7.1-cli/docker-entrypoint.sh | 76 ++++ 7.1-fpm/Dockerfile | 50 +-- 7.1-fpm/bin/docker-environment | 45 -- .../docker-entrypoint.sh | 12 +- README.md | 33 +- builder.php | 275 ++++++++++++ config.json | 100 +++++ docker-compose-build.yml | 6 +- docker-compose.yml | 6 +- src/Dockerfile | 58 +++ src/Dockerfile-cli | 43 ++ src/Dockerfile-fpm | 6 + src/bin/mageconfigsync | 5 + src/bin/magedbm2 | 5 + src/bin/magento-command | 9 + src/bin/magento-extension-installer | 425 ++++++++++++++++++ src/bin/magento-installer | 94 ++++ src/bin/magerun2 | 5 + src/bin/run-cron | 4 + src/docker-entrypoint.sh | 85 ++++ src/etc/mail.ini | 2 + {7.1-cli => src}/etc/php-fpm.conf | 0 src/etc/php-xdebug.ini | 12 + src/etc/php.ini | 3 + 30 files changed, 1409 insertions(+), 175 deletions(-) rename 7.0-cli/{bin/docker-environment => docker-entrypoint.sh} (97%) rename 7.0-fpm/{bin/docker-environment => docker-entrypoint.sh} (92%) create mode 100755 7.1-cli/docker-entrypoint.sh delete mode 100755 7.1-fpm/bin/docker-environment rename 7.1-cli/bin/docker-environment => 7.1-fpm/docker-entrypoint.sh (84%) create mode 100644 builder.php create mode 100644 config.json create mode 100644 src/Dockerfile create mode 100644 src/Dockerfile-cli create mode 100644 src/Dockerfile-fpm create mode 100755 src/bin/mageconfigsync create mode 100755 src/bin/magedbm2 create mode 100755 src/bin/magento-command create mode 100755 src/bin/magento-extension-installer create mode 100755 src/bin/magento-installer create mode 100755 src/bin/magerun2 create mode 100755 src/bin/run-cron create mode 100644 src/docker-entrypoint.sh create mode 100644 src/etc/mail.ini rename {7.1-cli => src}/etc/php-fpm.conf (100%) create mode 100644 src/etc/php-xdebug.ini create mode 100644 src/etc/php.ini diff --git a/7.0-cli/Dockerfile b/7.0-cli/Dockerfile index c9340b9..ed0df5f 100644 --- a/7.0-cli/Dockerfile +++ b/7.0-cli/Dockerfile @@ -1,8 +1,5 @@ # -# Command line, PHP 7.0, Magento 2 compatible container. -# -# Credit to Mark Shust for the basis of this -# Dockerfile in the https://github.com/mageinferno/docker-magento2-php project. +# This file is automatically generated. Do not edit directly. # FROM php:7.0-cli @@ -12,19 +9,19 @@ MAINTAINER Nick Jones # Install dependencies RUN apt-get update \ && apt-get install -y \ - cron \ - rsyslog \ - libfreetype6-dev \ - libicu-dev \ - libjpeg62-turbo-dev \ - libmcrypt-dev \ - libpng12-dev \ - libxslt1-dev \ - mysql-client \ - git \ - sendmail-bin \ - sendmail \ - sudo + libfreetype6-dev \ + libicu-dev \ + libjpeg62-turbo-dev \ + libmcrypt-dev \ + libpng12-dev \ + libxslt1-dev \ + sendmail-bin \ + sendmail \ + sudo \ + cron \ + rsyslog \ + mysql-client \ + git # Configure the gd library RUN docker-php-ext-configure \ @@ -45,6 +42,28 @@ RUN docker-php-ext-install \ # Install the 2.4 version of xdebug that's compatible with php7 RUN pecl install -o -f xdebug-2.4.0 +ENV PHP_MEMORY_LIMIT 2G +ENV PHP_ENABLE_XDEBUG false +ENV MAGENTO_ROOT /var/www/magento + +ENV DEBUG false +ENV UPDATE_UID_GID false + +ADD docker-entrypoint.sh /docker-entrypoint.sh + +RUN ["chmod", "+x", "/docker-entrypoint.sh"] + +ENTRYPOINT ["/docker-entrypoint.sh"] + +ENV COMPOSER_ALLOW_SUPERUSER 1 +ENV COMPOSER_GITHUB_TOKEN "" +ENV COMPOSER_MAGENTO_USERNAME "" +ENV COMPOSER_MAGENTO_PASSWORD "" +ENV COMPOSER_BITBUCKET_KEY "" +ENV COMPOSER_BITBUCKET_SECRET "" + +VOLUME /root/.composer/cache + # Get composer installed to /usr/local/bin/composer RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer @@ -57,33 +76,14 @@ RUN curl -LO https://s3.eu-west-2.amazonaws.com/magedbm2-releases/magedbm2.phar # Install mageconfigsync and move to /usr/local/bin RUN curl -L https://github.com/punkstar/mageconfigsync/releases/download/0.5.0-beta.1/mageconfigsync-0.5.0-beta.1.phar > mageconfigsync.phar && chmod +x ./mageconfigsync.phar && mv ./mageconfigsync.phar /usr/local/bin -VOLUME /root/.composer/cache - ADD bin/* /usr/local/bin/ ADD etc/php.ini /usr/local/etc/php/conf.d/zz-magento.ini ADD etc/php-xdebug.ini /usr/local/etc/php/conf.d/zz-xdebug-settings.ini ADD etc/mail.ini /usr/local/etc/php/conf.d/zz-mail.ini -ENV PHP_MEMORY_LIMIT 2G -ENV PHP_ENABLE_XDEBUG false -ENV MAGENTO_ROOT /var/www/magento - -ENV COMPOSER_ALLOW_SUPERUSER 1 -ENV COMPOSER_GITHUB_TOKEN "" -ENV COMPOSER_MAGENTO_USERNAME "" -ENV COMPOSER_MAGENTO_PASSWORD "" -ENV COMPOSER_BITBUCKET_KEY "" -ENV COMPOSER_BITBUCKET_SECRET "" -ENV DEBUG false -ENV UPDATE_UID_GID false -ENV UPLOAD_MAX_FILESIZE 64M - -RUN ["chmod", "+x", "/usr/local/bin/docker-environment"] RUN ["chmod", "+x", "/usr/local/bin/magento-installer"] RUN ["chmod", "+x", "/usr/local/bin/magento-command"] RUN ["chmod", "+x", "/usr/local/bin/magerun2"] RUN ["chmod", "+x", "/usr/local/bin/run-cron"] -ENTRYPOINT ["/usr/local/bin/docker-environment"] - CMD ["bash"] diff --git a/7.0-cli/bin/docker-environment b/7.0-cli/docker-entrypoint.sh similarity index 97% rename from 7.0-cli/bin/docker-environment rename to 7.0-cli/docker-entrypoint.sh index d292b3e..12c5f54 100755 --- a/7.0-cli/bin/docker-environment +++ b/7.0-cli/docker-entrypoint.sh @@ -31,6 +31,7 @@ fi mkdir -p $MAGENTO_ROOT chown www-data:www-data $MAGENTO_ROOT + CRON_LOG=/var/log/cron.log # Setup Magento cron @@ -43,13 +44,14 @@ touch $CRON_LOG echo "cron.* $CRON_LOG" > /etc/rsyslog.d/cron.conf service rsyslog start + + # Configure Sendmail if required if [ "$ENABLE_SENDMAIL" == "true" ]; then /etc/init.d/sendmail start fi - -# Configure PHP +# Substitute in php.ini values [ ! -z "${PHP_MEMORY_LIMIT}" ] && sed -i "s/!PHP_MEMORY_LIMIT!/${PHP_MEMORY_LIMIT}/" /usr/local/etc/php/conf.d/zz-magento.ini [ ! -z "${UPLOAD_MAX_FILESIZE}" ] && sed -i "s/!UPLOAD_MAX_FILESIZE!/${UPLOAD_MAX_FILESIZE}/" /usr/local/etc/php/conf.d/zz-magento.ini @@ -57,6 +59,7 @@ fi docker-php-ext-enable xdebug && \ echo "Xdebug is enabled" + # Configure composer [ ! -z "${COMPOSER_GITHUB_TOKEN}" ] && \ composer config --global github-oauth.github.com $COMPOSER_GITHUB_TOKEN @@ -64,8 +67,10 @@ fi [ ! -z "${COMPOSER_MAGENTO_USERNAME}" ] && \ composer config --global http-basic.repo.magento.com \ $COMPOSER_MAGENTO_USERNAME $COMPOSER_MAGENTO_PASSWORD - + [ ! -z "${COMPOSER_BITBUCKET_KEY}" ] && [ ! -z "${COMPOSER_BITBUCKET_SECRET}" ] && \ - composer config --global bitbucket-oauth.bitbucket.org $COMPOSER_BITBUCKET_KEY $COMPOSER_BITBUCKET_SECRET + composer config --global bitbucket-oauth.bitbucket.org $COMPOSER_BITBUCKET_KEY $COMPOSER_BITBUCKET_SECRET + exec "$@" + diff --git a/7.0-fpm/Dockerfile b/7.0-fpm/Dockerfile index a4ca25b..b46ad2e 100644 --- a/7.0-fpm/Dockerfile +++ b/7.0-fpm/Dockerfile @@ -1,8 +1,5 @@ # -# FPM, PHP 7.0, Magento 2 compatible container. -# -# Credit to Mark Shust for the basis of this -# Dockerfile in the https://github.com/mageinferno/docker-magento2-php project. +# This file is automatically generated. Do not edit directly. # FROM php:7.0-fpm @@ -12,15 +9,15 @@ MAINTAINER Nick Jones # Install dependencies RUN apt-get update \ && apt-get install -y \ - cron \ - libfreetype6-dev \ - libicu-dev \ - libjpeg62-turbo-dev \ - libmcrypt-dev \ - libpng12-dev \ - libxslt1-dev \ - sendmail-bin \ - sendmail + libfreetype6-dev \ + libicu-dev \ + libjpeg62-turbo-dev \ + libmcrypt-dev \ + libpng12-dev \ + libxslt1-dev \ + sendmail-bin \ + sendmail \ + sudo # Configure the gd library RUN docker-php-ext-configure \ @@ -41,23 +38,20 @@ RUN docker-php-ext-install \ # Install the 2.4 version of xdebug that's compatible with php7 RUN pecl install -o -f xdebug-2.4.0 -VOLUME /root/.composer/cache - -ADD bin/* /usr/local/bin/ -ADD etc/php.ini /usr/local/etc/php/conf.d/zz-magento.ini -ADD etc/mail.ini /usr/local/etc/php/conf.d/zz-mail.ini -ADD etc/php-xdebug.ini /usr/local/etc/php/conf.d/zz-xdebug-settings.ini -ADD etc/php-fpm.conf /usr/local/etc/ - ENV PHP_MEMORY_LIMIT 2G ENV PHP_ENABLE_XDEBUG false ENV MAGENTO_ROOT /var/www/magento -ENV MAGENTO_RUN_MODE developer + ENV DEBUG false ENV UPDATE_UID_GID false -ENV UPLOAD_MAX_FILESIZE 64M -RUN ["chmod", "+x", "/usr/local/bin/docker-environment"] +ADD docker-entrypoint.sh /docker-entrypoint.sh + +RUN ["chmod", "+x", "/docker-entrypoint.sh"] + +ENTRYPOINT ["/docker-entrypoint.sh"] + +ENV MAGENTO_RUN_MODE developer +ENV UPLOAD_MAX_FILESIZE 64M -ENTRYPOINT ["/usr/local/bin/docker-environment"] CMD ["php-fpm", "-F"] diff --git a/7.0-fpm/bin/docker-environment b/7.0-fpm/docker-entrypoint.sh similarity index 92% rename from 7.0-fpm/bin/docker-environment rename to 7.0-fpm/docker-entrypoint.sh index 8cd91c6..25fd692 100755 --- a/7.0-fpm/bin/docker-environment +++ b/7.0-fpm/docker-entrypoint.sh @@ -27,12 +27,18 @@ if [[ "$UPDATE_UID_GID" = "true" ]]; then groupmod -g $DOCKER_GID www-data fi +# Ensure our Magento directory exists +mkdir -p $MAGENTO_ROOT +chown www-data:www-data $MAGENTO_ROOT + + + # Configure Sendmail if required if [ "$ENABLE_SENDMAIL" == "true" ]; then /etc/init.d/sendmail start fi -# Configure PHP +# Substitute in php.ini values [ ! -z "${PHP_MEMORY_LIMIT}" ] && sed -i "s/!PHP_MEMORY_LIMIT!/${PHP_MEMORY_LIMIT}/" /usr/local/etc/php/conf.d/zz-magento.ini [ ! -z "${UPLOAD_MAX_FILESIZE}" ] && sed -i "s/!UPLOAD_MAX_FILESIZE!/${UPLOAD_MAX_FILESIZE}/" /usr/local/etc/php/conf.d/zz-magento.ini @@ -40,7 +46,10 @@ fi docker-php-ext-enable xdebug && \ echo "Xdebug is enabled" + # Configure PHP-FPM [ ! -z "${MAGENTO_RUN_MODE}" ] && sed -i "s/!MAGENTO_RUN_MODE!/${MAGENTO_RUN_MODE}/" /usr/local/etc/php-fpm.conf + exec "$@" + diff --git a/7.0-fpm/etc/php.ini b/7.0-fpm/etc/php.ini index 4b0f0ea..0a1cf51 100644 --- a/7.0-fpm/etc/php.ini +++ b/7.0-fpm/etc/php.ini @@ -1,6 +1,3 @@ ; This file is created automatically by the docker build memory_limit = !PHP_MEMORY_LIMIT! ; Variable: PHP_MEMORY_LIMIT -upload_max_filesize = !UPLOAD_MAX_FILESIZE! ; Variable: UPLOAD_MAX_FILESIZE -post_max_size = !UPLOAD_MAX_FILESIZE! ; Variable: UPLOAD_MAX_FILESIZE - diff --git a/7.1-cli/Dockerfile b/7.1-cli/Dockerfile index 3167d85..daa0d28 100644 --- a/7.1-cli/Dockerfile +++ b/7.1-cli/Dockerfile @@ -1,33 +1,35 @@ # -# Command line, PHP 7.1, Magento 2 compatible container. -# -# Credit to Mark Shust for the basis of this -# Dockerfile in the https://github.com/mageinferno/docker-magento2-php project. +# This file is automatically generated. Do not edit directly. # FROM php:7.1-cli -MAINTAINER Adam Paterson +MAINTAINER Nick Jones # Install dependencies RUN apt-get update \ - && apt-get install -y \ - cron \ - libfreetype6-dev \ - libicu-dev \ - libjpeg62-turbo-dev \ - libmcrypt-dev \ - libpng12-dev \ - libxslt1-dev \ - sendmail-bin \ - sendmail + && apt-get install -y \ + libfreetype6-dev \ + libicu-dev \ + libjpeg62-turbo-dev \ + libmcrypt-dev \ + libpng12-dev \ + libxslt1-dev \ + sendmail-bin \ + sendmail \ + sudo \ + cron \ + rsyslog \ + mysql-client \ + git # Configure the gd library RUN docker-php-ext-configure \ - gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include + gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ # Install required PHP extensions RUN docker-php-ext-install \ + dom \ gd \ intl \ mbstring \ @@ -40,20 +42,48 @@ RUN docker-php-ext-install \ # Install the 2.4 version of xdebug that's compatible with php7 RUN pecl install -o -f xdebug-2.4.0 +ENV PHP_MEMORY_LIMIT 2G +ENV PHP_ENABLE_XDEBUG false +ENV MAGENTO_ROOT /var/www/magento + +ENV DEBUG false +ENV UPDATE_UID_GID false + +ADD docker-entrypoint.sh /docker-entrypoint.sh + +RUN ["chmod", "+x", "/docker-entrypoint.sh"] + +ENTRYPOINT ["/docker-entrypoint.sh"] + +ENV COMPOSER_ALLOW_SUPERUSER 1 +ENV COMPOSER_GITHUB_TOKEN "" +ENV COMPOSER_MAGENTO_USERNAME "" +ENV COMPOSER_MAGENTO_PASSWORD "" +ENV COMPOSER_BITBUCKET_KEY "" +ENV COMPOSER_BITBUCKET_SECRET "" + VOLUME /root/.composer/cache +# Get composer installed to /usr/local/bin/composer +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +# Install n98-magerun2.phar and move to /usr/local/bin/ +RUN curl -O https://files.magerun.net/n98-magerun2.phar && chmod +x ./n98-magerun2.phar && mv ./n98-magerun2.phar /usr/local/bin/ + +# Install magedbm2.phar and move to /usr/local/bin +RUN curl -LO https://s3.eu-west-2.amazonaws.com/magedbm2-releases/magedbm2.phar && chmod +x ./magedbm2.phar && mv ./magedbm2.phar /usr/local/bin + +# Install mageconfigsync and move to /usr/local/bin +RUN curl -L https://github.com/punkstar/mageconfigsync/releases/download/0.5.0-beta.1/mageconfigsync-0.5.0-beta.1.phar > mageconfigsync.phar && chmod +x ./mageconfigsync.phar && mv ./mageconfigsync.phar /usr/local/bin + ADD bin/* /usr/local/bin/ ADD etc/php.ini /usr/local/etc/php/conf.d/zz-magento.ini -ADD etc/mail.ini /usr/local/etc/php/conf.d/zz-mail.ini ADD etc/php-xdebug.ini /usr/local/etc/php/conf.d/zz-xdebug-settings.ini -ADD etc/php-fpm.conf /usr/local/etc/ +ADD etc/mail.ini /usr/local/etc/php/conf.d/zz-mail.ini -ENV PHP_MEMORY_LIMIT 2G -ENV PHP_ENABLE_XDEBUG false -ENV MAGENTO_ROOT /var/www/magento -ENV MAGENTO_RUN_MODE developer -ENV DEBUG false -ENV UPDATE_UID_GID false +RUN ["chmod", "+x", "/usr/local/bin/magento-installer"] +RUN ["chmod", "+x", "/usr/local/bin/magento-command"] +RUN ["chmod", "+x", "/usr/local/bin/magerun2"] +RUN ["chmod", "+x", "/usr/local/bin/run-cron"] -ENTRYPOINT ["/usr/local/bin/docker-environment"] -CMD ["php-fpm", "-F"] +CMD ["bash"] diff --git a/7.1-cli/docker-entrypoint.sh b/7.1-cli/docker-entrypoint.sh new file mode 100755 index 0000000..12c5f54 --- /dev/null +++ b/7.1-cli/docker-entrypoint.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +[ "$DEBUG" = "true" ] && set -x + +# If asked, we'll ensure that the www-data is set to the same uid/gid as the +# mounted volume. This works around permission issues with virtualbox shared +# folders. +if [[ "$UPDATE_UID_GID" = "true" ]]; then + echo "Updating www-data uid and gid" + + DOCKER_UID=`stat -c "%u" $MAGENTO_ROOT` + DOCKER_GID=`stat -c "%g" $MAGENTO_ROOT` + + INCUMBENT_USER=`getent passwd $DOCKER_UID | cut -d: -f1` + INCUMBENT_GROUP=`getent group $DOCKER_GID | cut -d: -f1` + + echo "Docker: uid = $DOCKER_UID, gid = $DOCKER_GID" + echo "Incumbent: user = $INCUMBENT_USER, group = $INCUMBENT_GROUP" + + # Once we've established the ids and incumbent ids then we need to free them + # up (if necessary) and then make the change to www-data. + + [ ! -z "${INCUMBENT_USER}" ] && usermod -u 99$DOCKER_UID $INCUMBENT_USER + usermod -u $DOCKER_UID www-data + + [ ! -z "${INCUMBENT_GROUP}" ] && groupmod -g 99$DOCKER_GID $INCUMBENT_GROUP + groupmod -g $DOCKER_GID www-data +fi + +# Ensure our Magento directory exists +mkdir -p $MAGENTO_ROOT +chown www-data:www-data $MAGENTO_ROOT + + +CRON_LOG=/var/log/cron.log + +# Setup Magento cron +echo "* * * * * www-data /usr/local/bin/php ${MAGENTO_ROOT}/bin/magento cron:run | grep -v \"Ran jobs by schedule\" >> ${MAGENTO_ROOT}/var/log/magento.cron.log" > /etc/cron.d/magento +echo "* * * * * www-data /usr/local/bin/php ${MAGENTO_ROOT}/update/cron.php >> ${MAGENTO_ROOT}/var/log/update.cron.log" >> /etc/cron.d/magento +echo "* * * * * www-data /usr/local/bin/php ${MAGENTO_ROOT}/bin/magento setup:cron:run >> ${MAGENTO_ROOT}/var/log/setup.cron.log" >> /etc/cron.d/magento + +# Get rsyslog running for cron output +touch $CRON_LOG +echo "cron.* $CRON_LOG" > /etc/rsyslog.d/cron.conf +service rsyslog start + + + +# Configure Sendmail if required +if [ "$ENABLE_SENDMAIL" == "true" ]; then + /etc/init.d/sendmail start +fi + +# Substitute in php.ini values +[ ! -z "${PHP_MEMORY_LIMIT}" ] && sed -i "s/!PHP_MEMORY_LIMIT!/${PHP_MEMORY_LIMIT}/" /usr/local/etc/php/conf.d/zz-magento.ini +[ ! -z "${UPLOAD_MAX_FILESIZE}" ] && sed -i "s/!UPLOAD_MAX_FILESIZE!/${UPLOAD_MAX_FILESIZE}/" /usr/local/etc/php/conf.d/zz-magento.ini + +[ "$PHP_ENABLE_XDEBUG" = "true" ] && \ + docker-php-ext-enable xdebug && \ + echo "Xdebug is enabled" + + +# Configure composer +[ ! -z "${COMPOSER_GITHUB_TOKEN}" ] && \ + composer config --global github-oauth.github.com $COMPOSER_GITHUB_TOKEN + +[ ! -z "${COMPOSER_MAGENTO_USERNAME}" ] && \ + composer config --global http-basic.repo.magento.com \ + $COMPOSER_MAGENTO_USERNAME $COMPOSER_MAGENTO_PASSWORD + +[ ! -z "${COMPOSER_BITBUCKET_KEY}" ] && [ ! -z "${COMPOSER_BITBUCKET_SECRET}" ] && \ + composer config --global bitbucket-oauth.bitbucket.org $COMPOSER_BITBUCKET_KEY $COMPOSER_BITBUCKET_SECRET + + +exec "$@" + diff --git a/7.1-fpm/Dockerfile b/7.1-fpm/Dockerfile index 6d131a8..a7f41f4 100644 --- a/7.1-fpm/Dockerfile +++ b/7.1-fpm/Dockerfile @@ -1,33 +1,31 @@ # -# FPM, PHP 7.1, Magento 2 compatible container. -# -# Credit to Mark Shust for the basis of this -# Dockerfile in the https://github.com/mageinferno/docker-magento2-php project. +# This file is automatically generated. Do not edit directly. # FROM php:7.1-fpm -MAINTAINER Adam Paterson +MAINTAINER Nick Jones # Install dependencies RUN apt-get update \ - && apt-get install -y \ - cron \ - libfreetype6-dev \ - libicu-dev \ - libjpeg62-turbo-dev \ - libmcrypt-dev \ - libpng12-dev \ - libxslt1-dev \ - sendmail-bin \ - sendmail + && apt-get install -y \ + libfreetype6-dev \ + libicu-dev \ + libjpeg62-turbo-dev \ + libmcrypt-dev \ + libpng12-dev \ + libxslt1-dev \ + sendmail-bin \ + sendmail \ + sudo # Configure the gd library RUN docker-php-ext-configure \ - gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include + gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ # Install required PHP extensions RUN docker-php-ext-install \ + dom \ gd \ intl \ mbstring \ @@ -40,20 +38,20 @@ RUN docker-php-ext-install \ # Install the 2.4 version of xdebug that's compatible with php7 RUN pecl install -o -f xdebug-2.4.0 -VOLUME /root/.composer/cache - -ADD bin/* /usr/local/bin/ -ADD etc/php.ini /usr/local/etc/php/conf.d/zz-magento.ini -ADD etc/mail.ini /usr/local/etc/php/conf.d/zz-mail.ini -ADD etc/php-xdebug.ini /usr/local/etc/php/conf.d/zz-xdebug-settings.ini -ADD etc/php-fpm.conf /usr/local/etc/ - ENV PHP_MEMORY_LIMIT 2G ENV PHP_ENABLE_XDEBUG false ENV MAGENTO_ROOT /var/www/magento -ENV MAGENTO_RUN_MODE developer + ENV DEBUG false ENV UPDATE_UID_GID false -ENTRYPOINT ["/usr/local/bin/docker-environment"] +ADD docker-entrypoint.sh /docker-entrypoint.sh + +RUN ["chmod", "+x", "/docker-entrypoint.sh"] + +ENTRYPOINT ["/docker-entrypoint.sh"] + +ENV MAGENTO_RUN_MODE developer +ENV UPLOAD_MAX_FILESIZE 64M + CMD ["php-fpm", "-F"] diff --git a/7.1-fpm/bin/docker-environment b/7.1-fpm/bin/docker-environment deleted file mode 100755 index ee48557..0000000 --- a/7.1-fpm/bin/docker-environment +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -[ "$DEBUG" = "true" ] && set -x - -# If asked, we'll ensure that the www-data is set to the same uid/gid as the -# mounted volume. This works around permission issues with virtualbox shared -# folders. -if [[ "$UPDATE_UID_GID" = "true" ]]; then - echo "Updating www-data uid and gid" - - DOCKER_UID=`stat -c "%u" $MAGENTO_ROOT` - DOCKER_GID=`stat -c "%g" $MAGENTO_ROOT` - - INCUMBENT_USER=`getent passwd $DOCKER_UID | cut -d: -f1` - INCUMBENT_GROUP=`getent group $DOCKER_GID | cut -d: -f1` - - echo "Docker: uid = $DOCKER_UID, gid = $DOCKER_GID" - echo "Incumbent: user = $INCUMBENT_USER, group = $INCUMBENT_GROUP" - - # Once we've established the ids and incumbent ids then we need to free them - # up (if necessary) and then make the change to www-data. - - [ ! -z "${INCUMBENT_USER}" ] && usermod -u 99$DOCKER_UID $INCUMBENT_USER - usermod -u $DOCKER_UID www-data - - [ ! -z "${INCUMBENT_GROUP}" ] && groupmod -g 99$DOCKER_GID $INCUMBENT_GROUP - groupmod -g $DOCKER_GID www-data -fi - -# Configure Sendmail if required -if [ "$ENABLE_SENDMAIL" == "true" ]; then - /etc/init.d/sendmail start -fi - -# Configure PHP -[ ! -z "${PHP_MEMORY_LIMIT}" ] && sed -i "s/!PHP_MEMORY_LIMIT!/${PHP_MEMORY_LIMIT}/" /usr/local/etc/php/conf.d/zz-magento.ini - -[ "$PHP_ENABLE_XDEBUG" = "true" ] && \ - docker-php-ext-enable xdebug && \ - echo "Xdebug is enabled" - -# Configure PHP-FPM -[ ! -z "${MAGENTO_RUN_MODE}" ] && sed -i "s/!MAGENTO_RUN_MODE!/${MAGENTO_RUN_MODE}/" /usr/local/etc/php-fpm.conf - -exec "$@" diff --git a/7.1-cli/bin/docker-environment b/7.1-fpm/docker-entrypoint.sh similarity index 84% rename from 7.1-cli/bin/docker-environment rename to 7.1-fpm/docker-entrypoint.sh index ee48557..25fd692 100755 --- a/7.1-cli/bin/docker-environment +++ b/7.1-fpm/docker-entrypoint.sh @@ -27,19 +27,29 @@ if [[ "$UPDATE_UID_GID" = "true" ]]; then groupmod -g $DOCKER_GID www-data fi +# Ensure our Magento directory exists +mkdir -p $MAGENTO_ROOT +chown www-data:www-data $MAGENTO_ROOT + + + # Configure Sendmail if required if [ "$ENABLE_SENDMAIL" == "true" ]; then /etc/init.d/sendmail start fi -# Configure PHP +# Substitute in php.ini values [ ! -z "${PHP_MEMORY_LIMIT}" ] && sed -i "s/!PHP_MEMORY_LIMIT!/${PHP_MEMORY_LIMIT}/" /usr/local/etc/php/conf.d/zz-magento.ini +[ ! -z "${UPLOAD_MAX_FILESIZE}" ] && sed -i "s/!UPLOAD_MAX_FILESIZE!/${UPLOAD_MAX_FILESIZE}/" /usr/local/etc/php/conf.d/zz-magento.ini [ "$PHP_ENABLE_XDEBUG" = "true" ] && \ docker-php-ext-enable xdebug && \ echo "Xdebug is enabled" + # Configure PHP-FPM [ ! -z "${MAGENTO_RUN_MODE}" ] && sed -i "s/!MAGENTO_RUN_MODE!/${MAGENTO_RUN_MODE}/" /usr/local/etc/php-fpm.conf + exec "$@" + diff --git a/README.md b/README.md index df4a4b3..18796a5 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,35 @@ To clear varnish, you can use the `cli` containers `magento-command` to clear th If you need to add your own VCL, then it needs to be mounted to: `/data/varnish.vcl`. -## Credits +## Building -Thanks to [Mark Shust](https://twitter.com/markshust) for his work on [docker-magento2-php](https://github.com/mageinferno/docker-magento2-php) that was used as a basis for this implementation. You solved a lot of the problems so I didn't need to! +A lot of the configuration for each image is the same, with the difference being the base image that they're extending from. For this reason we use `php` to build the `Dockerfile` from a set of templates in `src/`. The `Dockerfile` should still be published to the repository due to Docker Hub needing a `Dockerfile` to build from. + +To build all `Dockerfile`s, run the `builder.php` script in the `php:7` Docker image: + + docker run --rm -it -v $(pwd):/src php:7 php /src/builder.php + +### Adding new images to the build config + +The build configuration is controlled by the `config.json` file. Yeah element in the top level hash is a new build target, using the following syntax: + + "": { + "version": "", + "flavour": "", + "files": { + "": { + "": "", + ... + }, + } + +The target files will be rendered in the `-/` directory. + +The source template for each target file is selected from the `src/` directory using the following fallback order: + +1. `--` +2. `-` +3. `-` +4. `` + +Individual templates may include other templates as partials. \ No newline at end of file diff --git a/builder.php b/builder.php new file mode 100644 index 0000000..b4eab84 --- /dev/null +++ b/builder.php @@ -0,0 +1,275 @@ +template_dir = $options["template_dir"] ?? static::DEFAULT_TEMPLATE_DIR; + $this->destination_dir = $options["destination_dir"] ?? static::DEFAULT_DESTINATION_DIR; + $this->executable_permissions = $options["executable_file_permissions"] ?? static::DEFAULT_EXECUTABLE_PERMISSIONS; + $this->verbose_level = $options["verbose"] ?? static::DEFAULT_VERBOSE_LEVEL; + + $this->loadConfig($options["config_file"] ?? static::DEFAULT_CONFIG_FILE); + } + + /** + * Build the files described in the loaded config. + */ + public function run() + { + foreach ($this->build_config as $name => $config) { + $this->verbose(sprintf("Building '%s'...", $name), 1); + foreach ($config["files"] as $file_name => $variables) { + $destination_file = $this->getDestinationFile($file_name, $config); + $contents = ""; + + if ($template_file = $this->getTemplateFile($file_name, $config)) { + // Merge global variables to the template variables + $variables["version"] = $config["version"]; + $variables["flavour"] = $config["flavour"]; + + // Determine whether we should load with the template renderer, or whether we should straight up + // just load the file from disk. + if ($variables['_disable_variables'] ?? false) { + $contents = file_get_contents($template_file); + } else { + $contents = $this->renderTemplate($template_file, $variables); + } + + $contents = str_replace('{{generated_by_builder}}', 'This file is automatically generated. Do not edit directly.', $contents); + } + + $this->verbose(sprintf("\tWriting '%s'...", $destination_file), 2); + $this->writeFile($destination_file, $contents); + + if ($variables["executable"] ?? false) { + $this->verbose(sprintf("\tUpdating permissions on '%s' to '%o'...", $destination_file, $this->executable_permissions), 2); + $this->setFilePermissions($destination_file, $this->executable_permissions); + } + } + } + } + + /** + * Load the build configuration from the given file. + * + * @param string $file + * + * @return $this + * @throws Exception + */ + protected function loadConfig($file) + { + $config = json_decode(file_get_contents($file), true); + + if (!is_array($config)) { + throw new Exception(sprintf("Invalid configuration in %s!", $file)); + } + + $this->build_config = $config; + + return $this; + } + + /** + * Return the template file name for the given file. + * + * @param string $filename + * @param array $config + * + * @return null|string + */ + protected function getTemplateFile($filename, $config) + { + $potential_file_names = [ + sprintf("%s-%s-%s", $filename, $config["version"], $config["flavour"]), + sprintf("%s-%s", $filename, $config["version"]), + sprintf("%s-%s", $filename, $config["flavour"]), + $filename, + ]; + + foreach ($potential_file_names as $potential_file_name) { + $path = $this->template_dir . DIRECTORY_SEPARATOR . $potential_file_name; + + if (file_exists($path) && is_readable($path)) { + return $path; + } + } + + return null; + } + + /** + * Get the destination for the given file. + * + * @param string $file_name + * @param array $config + * + * @return string + */ + protected function getDestinationFile($file_name, $config) + { + return implode(DIRECTORY_SEPARATOR, [ + $this->destination_dir, + $config["version"] . '-' . $config["flavour"], + $file_name, + ]); + } + + /** + * Render the given template file using the provided variables and return the resulting output. + * + * @param string $template_file + * @param array $variables + * + * @return string + */ + protected function renderTemplate($template_file, $variables) + { + extract($variables, EXTR_OVERWRITE); + ob_start(); + + include $template_file; + + $output = ob_get_clean(); + + return $output ?: ""; + } + + /** + * Write the contents to the given file. + * + * @param string $file_name + * @param string $contents + * + * @return $this + * @throws Exception + */ + protected function writeFile($file_name, $contents) + { + $directory = dirname($file_name); + + // If the directory doesn't created then try to create the directory. + if (!is_dir($directory)) { + // Create the directory, preventing race conditions if another process creates the directory for us. + if (!@mkdir($directory, 0755, true) && !is_dir($directory)) { + throw new Exception(sprintf("Unable to create directory %s!", $directory)); + } + } + + if (file_put_contents($file_name, $contents) === false) { + throw new Exception(sprintf("Failed to write %s!", $file_name)); + } + + return $this; + } + + /** + * Update the permissions on the given file. + * + * @param string $file_name + * @param int $permissions + * + * @return $this + */ + protected function setFilePermissions($file_name, $permissions = 0644) + { + chmod($file_name, $permissions); + + return $this; + } + + /** + * Print an informational message to the command line. + * + * @param string $message + * @param int $level + * @param bool $newline + * + * @return $this + */ + protected function verbose($message, $level = 1, $newline = true) + { + if ($level <= $this->verbose_level) { + printf("%s%s", $message, $newline ? PHP_EOL : ""); + } + + return $this; + } +} + +/** + * __MAIN__ + */ + +$args = getopt("hvq"); +$options = []; + +if (isset($args["h"])) { + echo <<run(); \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..ebba66f --- /dev/null +++ b/config.json @@ -0,0 +1,100 @@ +{ + "7.0-cli": { + "version": "7.0", + "flavour": "cli", + "files": { + "Dockerfile": {}, + "docker-entrypoint.sh": { + "executable": true + }, + "bin/mageconfigsync": { + "executable": true + }, + "bin/magedbm2": { + "executable": true + }, + "bin/magento-command": { + "executable": true + }, + "bin/magento-extension-installer": { + "_disable_variables": true, + "executable": true + }, + "bin/magento-installer": { + "executable": true + }, + "bin/magerun2": { + "executable": true + }, + "bin/run-cron": { + "executable": true + }, + "etc/mail.ini": {}, + "etc/php.ini": {}, + "etc/php-xdebug.ini": {} + } + }, + "7.0-fpm": { + "version": "7.0", + "flavour": "fpm", + "files": { + "Dockerfile": {}, + "docker-entrypoint.sh": { + "executable": true + }, + "etc/mail.ini": {}, + "etc/php.ini": {}, + "etc/php-xdebug.ini": {}, + "etc/php-fpm.conf": {} + } + }, + "7.1-cli": { + "version": "7.1", + "flavour": "cli", + "files": { + "Dockerfile": {}, + "docker-entrypoint.sh": { + "executable": true + }, + "bin/mageconfigsync": { + "executable": true + }, + "bin/magedbm2": { + "executable": true + }, + "bin/magento-command": { + "executable": true + }, + "bin/magento-extension-installer": { + "_disable_variables": true, + "executable": true + }, + "bin/magento-installer": { + "executable": true + }, + "bin/magerun2": { + "executable": true + }, + "bin/run-cron": { + "executable": true + }, + "etc/mail.ini": {}, + "etc/php.ini": {}, + "etc/php-xdebug.ini": {} + } + }, + "7.1-fpm": { + "version": "7.1", + "flavour": "fpm", + "files": { + "Dockerfile": {}, + "docker-entrypoint.sh": { + "executable": true + }, + "etc/mail.ini": {}, + "etc/php.ini": {}, + "etc/php-xdebug.ini": {}, + "etc/php-fpm.conf": {} + } + } +} \ No newline at end of file diff --git a/docker-compose-build.yml b/docker-compose-build.yml index 18bce8d..188b495 100644 --- a/docker-compose-build.yml +++ b/docker-compose-build.yml @@ -32,7 +32,7 @@ services: fpm: hostname: fpm.magento2.docker build: - context: 7.1-fpm/ + context: 7.0-fpm/ ports: - 9000 links: @@ -57,7 +57,7 @@ services: cli: hostname: cli.magento2.docker build: - context: 7.1-cli/ + context: 7.0-cli/ links: - db volumes: @@ -86,7 +86,7 @@ services: cron: build: - context: 7.1-cli/ + context: 7.0-cli/ hostname: magento2-cron.docker command: run-cron environment: diff --git a/docker-compose.yml b/docker-compose.yml index 3c8a265..503d16b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,7 +29,7 @@ services: fpm: hostname: fpm.magento2.docker - image: meanbee/magento2-php:7.1-fpm + image: meanbee/magento2-php:7.0-fpm ports: - 9000 links: @@ -54,7 +54,7 @@ services: cli: hostname: cli.magento2.docker - image: meanbee/magento2-php:7.1-cli + image: meanbee/magento2-php:7.0-cli links: - db volumes: @@ -82,7 +82,7 @@ services: # - M2SETUP_USE_SAMPLE_DATA=true cron: - image: meanbee/magento2-php:7.1-cli + image: meanbee/magento2-php:7.0-cli hostname: magento2-cron.docker command: run-cron env_file: diff --git a/src/Dockerfile b/src/Dockerfile new file mode 100644 index 0000000..0f71f6c --- /dev/null +++ b/src/Dockerfile @@ -0,0 +1,58 @@ +# +# {{generated_by_builder}} +# + +FROM + +MAINTAINER Nick Jones + + +# Install dependencies +RUN apt-get update \ + && apt-get install -y \ + + + +# Configure the gd library +RUN docker-php-ext-configure \ + gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ + +# Install required PHP extensions +RUN docker-php-ext-install \ + dom \ + gd \ + intl \ + mbstring \ + mcrypt \ + pdo_mysql \ + xsl \ + zip \ + soap + +# Install the 2.4 version of xdebug that's compatible with php7 +RUN pecl install -o -f xdebug-2.4.0 + +ENV PHP_MEMORY_LIMIT 2G +ENV PHP_ENABLE_XDEBUG false +ENV MAGENTO_ROOT /var/www/magento + +ENV DEBUG false +ENV UPDATE_UID_GID false + +ADD docker-entrypoint.sh /docker-entrypoint.sh + +RUN ["chmod", "+x", "/docker-entrypoint.sh"] + +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/src/Dockerfile-cli b/src/Dockerfile-cli new file mode 100644 index 0000000..1918483 --- /dev/null +++ b/src/Dockerfile-cli @@ -0,0 +1,43 @@ + + +ENV COMPOSER_ALLOW_SUPERUSER 1 +ENV COMPOSER_GITHUB_TOKEN "" +ENV COMPOSER_MAGENTO_USERNAME "" +ENV COMPOSER_MAGENTO_PASSWORD "" +ENV COMPOSER_BITBUCKET_KEY "" +ENV COMPOSER_BITBUCKET_SECRET "" + +VOLUME /root/.composer/cache + +# Get composer installed to /usr/local/bin/composer +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +# Install n98-magerun2.phar and move to /usr/local/bin/ +RUN curl -O https://files.magerun.net/n98-magerun2.phar && chmod +x ./n98-magerun2.phar && mv ./n98-magerun2.phar /usr/local/bin/ + +# Install magedbm2.phar and move to /usr/local/bin +RUN curl -LO https://s3.eu-west-2.amazonaws.com/magedbm2-releases/magedbm2.phar && chmod +x ./magedbm2.phar && mv ./magedbm2.phar /usr/local/bin + +# Install mageconfigsync and move to /usr/local/bin +RUN curl -L https://github.com/punkstar/mageconfigsync/releases/download/0.5.0-beta.1/mageconfigsync-0.5.0-beta.1.phar > mageconfigsync.phar && chmod +x ./mageconfigsync.phar && mv ./mageconfigsync.phar /usr/local/bin + +ADD bin/* /usr/local/bin/ +ADD etc/php.ini /usr/local/etc/php/conf.d/zz-magento.ini +ADD etc/php-xdebug.ini /usr/local/etc/php/conf.d/zz-xdebug-settings.ini +ADD etc/mail.ini /usr/local/etc/php/conf.d/zz-mail.ini + +RUN ["chmod", "+x", "/usr/local/bin/magento-installer"] +RUN ["chmod", "+x", "/usr/local/bin/magento-command"] +RUN ["chmod", "+x", "/usr/local/bin/magerun2"] +RUN ["chmod", "+x", "/usr/local/bin/run-cron"] + +CMD ["bash"] diff --git a/src/Dockerfile-fpm b/src/Dockerfile-fpm new file mode 100644 index 0000000..68214eb --- /dev/null +++ b/src/Dockerfile-fpm @@ -0,0 +1,6 @@ + + +ENV MAGENTO_RUN_MODE developer +ENV UPLOAD_MAX_FILESIZE 64M + +CMD ["php-fpm", "-F"] diff --git a/src/bin/mageconfigsync b/src/bin/mageconfigsync new file mode 100755 index 0000000..876b5ff --- /dev/null +++ b/src/bin/mageconfigsync @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +[ "$DEBUG" = "true" ] && set -x + +exec sudo -u www-data -- mageconfigsync.phar --magento-root=$MAGENTO_ROOT "$@" diff --git a/src/bin/magedbm2 b/src/bin/magedbm2 new file mode 100755 index 0000000..ac328b4 --- /dev/null +++ b/src/bin/magedbm2 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +[ "$DEBUG" = "true" ] && set -x + +exec sudo -u www-data -- magedbm2.phar --root-dir=$MAGENTO_ROOT "$@" diff --git a/src/bin/magento-command b/src/bin/magento-command new file mode 100755 index 0000000..269bdc4 --- /dev/null +++ b/src/bin/magento-command @@ -0,0 +1,9 @@ +#!/bin/bash + +[ "$DEBUG" = "true" ] && set -x + +MAGENTO_COMMAND="$MAGENTO_ROOT/bin/magento" + +chmod +x $MAGENTO_COMMAND + +exec sudo -u www-data -- $MAGENTO_COMMAND "$@" diff --git a/src/bin/magento-extension-installer b/src/bin/magento-extension-installer new file mode 100755 index 0000000..92f6a08 --- /dev/null +++ b/src/bin/magento-extension-installer @@ -0,0 +1,425 @@ +#!/usr/bin/env php +configure(); + } catch (\Exception $e) { + if ($this->display_help) { + $this->printUsage(); + + return static::RETURN_CODE_SUCCESS; + } else { + $this->error($e->getMessage() . PHP_EOL); + $this->printUsage(); + + return static::RETURN_CODE_ARGUMENT_ERROR; + } + } + + // Validate Magento 2 installation + if (!$this->isMagentoInstalled($this->magento_dir)) { + $this->info("Magento 2 not detected in %s, installing...", $this->magento_dir); + + if (!$this->magentoInstaller()) { + $this->error("Magento 2 installation failed!"); + + return static::RETURN_CODE_MAGENTO_INSTALLER_ERROR; + } + } + + // Install extension with Composer + $this->info("Installing %s with Composer...", $this->package_name); + + if (!$this->installComposerPackage($this->package_name, $this->magento_dir, $this->source_dir)) { + $this->error("Failed to install package!"); + + return static::RETURN_CODE_COMPOSER_ERROR; + } + + // Create a symlink in Magento's root folder to allow access to templates + + try { + $symlink_exists = $this->checkSymlink($this->symlink); + } catch (Exception $e) { + $this->printSymlinkMessage(); + $this->error($e->getMessage()); + return static::RETURN_CODE_SYMLINK_ERROR; + } + + if (!$symlink_exists) { + $this->printSymlinkMessage(); + $this->info("Creating a symlink %s...", $this->symlink); + + if (!$this->createSymlink($this->extensions_dir, $this->symlink)) { + $this->error("Failed to create a symlink!"); + return static::RETURN_CODE_SYMLINK_ERROR; + } + } + + // Configure the installed extension + $this->info("Configuring %s with Magento...", $this->extension_name); + if (!$this->configureModule($this->extension_name)) { + $this->error("Magento 2 cli commands failed!"); + return static::RETURN_CODE_MAGENTO_COMMAND_ERROR; + } + + $this->info("Extension %s installed.", $this->extension_name); + + return static::RETURN_CODE_SUCCESS; + } + + /** + * Parse the command line options and arguments provided and configure the installer. + */ + protected function configure() + { + $options = getopt( + "h", + [ + "help", + "package-name:", + ] + ); + + $arguments = $GLOBALS["argv"]; + + foreach ($options as $option => $value) { + switch ($option) { + case "h": + case "help": + $this->display_help = true; + throw new \Exception("Help option specified, stopping further configuration."); + break; + case "package-name": + $this->package_name = $value; + break; + } + + // Remove options from arguments + if ($opt_ind = array_search("--" . $option, $arguments) ?: array_search("-" . $option, $arguments)) { + unset($arguments[$opt_ind]); + + if ($value !== false && isset($arguments[$opt_ind + 1]) && $value == $arguments[$opt_ind + 1]) { + unset($arguments[$opt_ind + 1]); + } + } else if ($opt_ind = array_search("--" . $option . "=" . $value, $arguments)) { + unset($arguments[$opt_ind]); + } + } + + $arguments = array_values(array_filter(array_slice($arguments, 1), function ($value) { + return $value !== "--"; + })); + + if (count($arguments) > 1) { + throw new \Exception("Too many arguments!"); + } + + if (count($arguments) < 1) { + throw new \Exception("Must specify the name of the extension to install!"); + } + + $this->extensions_dir = implode(DIRECTORY_SEPARATOR, ["", static::EXTENSIONS_DIR]); + + $this->extension_name = $arguments[0]; + $this->source_dir = implode(DIRECTORY_SEPARATOR, [$this->extensions_dir, $this->extension_name]); + + if (!$this->package_name) { + $this->package_name = $this->getComposerPackageName($this->source_dir); + } + + $this->magento_dir = getenv("MAGENTO_ROOT"); + + if (!$this->magento_dir) { + throw new \Exception("This script requires the \$MAGENTO_ROOT environment variable to be defined!"); + } + + $this->symlink = implode(DIRECTORY_SEPARATOR, [$this->magento_dir, static::EXTENSIONS_DIR]); + } + + /** + * Read the Composer package located at the given directory, verify that it + * is a Magento 2 extension and return the Composer package name. + * + * @param string $package_dir + * + * @return string + * @throws Exception + */ + protected function getComposerPackageName($package_dir) + { + if (!file_exists($package_dir) || !is_dir($package_dir) || !is_readable($package_dir)) { + throw new \Exception(sprintf("Unable to read package directory %s!", $package_dir)); + } + + $manifest_file = $package_dir . DIRECTORY_SEPARATOR . "composer.json"; + + if (!file_exists($manifest_file) || !is_file($manifest_file) || !is_readable($manifest_file)) { + throw new \Exception(sprintf("Composer package not found in %s!", $package_dir)); + } + + $manifest = json_decode(file_get_contents($manifest_file), true); + + if (!is_array($manifest) || !isset($manifest["type"]) || $manifest["type"] !== "magento2-module") { + throw new \Exception(sprintf("The Composer package in %s does not appear to be a Magento 2 module!", $package_dir)); + } + + if (!isset($manifest["name"]) || !$manifest["name"]) { + throw new \Exception(sprintf("Unable to determine the Composer package name in %s!", $package_dir)); + } + + return $manifest["name"]; + } + + /** + * Check if Magento 2 is installed in the given directory. + * + * @param string $directory + * + * @return bool + */ + protected function isMagentoInstalled($directory) + { + $it = new \FilesystemIterator($directory); + $env_file = implode(DIRECTORY_SEPARATOR, [$directory, "app", "etc", "env.php"]); + + return $it->valid() && file_exists($env_file); + } + + /** + * Install a package with Composer. + * + * Installs in to the current directory, unless the destination directory + * is specified. + * + * If the package source directory is specified, will add it as a symlinked + * repository to the project. + * + * @param string $package_name + * @param string|null $destination_dir The destination Composer project. + * @param string|null $source_dir The source directory for the package. + * + * @return bool + */ + protected function installComposerPackage($package_name, $destination_dir = null, $source_dir = null) + { + if ($source_dir) { + $repo_config = json_encode([ + "type" => "path", + "url" => $source_dir, + "options" => [ + "symlink" => true, + ] + ]); + + if (!$this->composer("config repositories.$package_name '$repo_config'", $destination_dir)) { + return false; + } + } + + return $this->composer("require $package_name @dev", $destination_dir); + } + + /** + * Check if the given symlink file exists. + * + * @param string $symlink + * + * @return bool + * @throws Exception + */ + protected function checkSymlink($symlink) + { + if (file_exists($symlink) && !is_link($symlink)) { + throw new \Exception(sprintf("File %s exists, but is not a symlink!", $symlink)); + } + + return file_exists($symlink); + } + + /** + * Create a symlink. + * + * @param string $target + * @param string $link + * + * @return bool + */ + protected function createSymlink($target, $link) + { + @mkdir(dirname($link), 0755, true); + return symlink($target, $link); + } + + /** + * Run Magento 2 cli commands to enable and configure the given module. + * + * @param string $name + * + * @return bool + */ + protected function configureModule($name) + { + return $this->magentoCommand("module:enable $name") + && $this->magentoCommand("setup:upgrade") + && $this->magentoCommand("setup:di:compile") + && $this->magentoCommand("setup:static-content:deploy") + && $this->magentoCommand("cache:flush"); + } + + /** + * Run the Magento 2 installer. + * + * @return bool + */ + protected function magentoInstaller() + { + passthru("magento-installer", $status); + + return $status === 0; + } + + /** + * Run a Magento 2 CLI command. + * + * @param string $command + * + * @return bool + */ + protected function magentoCommand($command) + { + $cmd = [ + "magento-command", + $command + ]; + + passthru(implode(" ", $cmd), $status); + + return $status === 0; + } + + /** + * Run a Composer command. + * + * @param string $command + * @param string $working_dir Set the working directory. + * + * @return bool + */ + protected function composer($command, $working_dir = null) + { + $cmd = ["composer"]; + + if ($working_dir) { + $cmd[] = "--working-dir=$working_dir"; + } + + $cmd[] = $command; + + passthru(implode(" ", $cmd), $status); + + return $status === 0; + } + + /** + * Output the usage message. + */ + protected function printUsage() + { + $usage = /** @lang text */ + <<] + +Arguments: + extension_name - the name of the Magento 2 extension to install + +Options: + --package-name The composer package name to require. If not specified, + the installer will attempt to determine the package name + from the composer.json file in the extension directory. + --help, -h Print this help message + +Description: + Installs a Magento 2 extension from /extensions// directory + into a Magento 2 installation defined by the \$MAGENTO_ROOT environment + variable. Expects the extension to contain a Composer package. + + If the destination directory is empty, runs the Magento 2 installer first. + +USAGE; + + $this->info($usage); + } + + protected function printSymlinkMessage() + { + $message = /** @lang text */ + <<info($message); + } + + /** + * Output an informational message. Any additional parameters will be + * passed into a sprintf() along with the message before outputing it. + * + * @param string $message + * @param array ...$parameters + */ + protected function info($message, ...$parameters) + { + fwrite(STDOUT, sprintf($message, ...$parameters) . PHP_EOL); + } + + /** + * Output an error message. Any additional parameters will be passed into a + * sprintf() along with the message before outputing it. + * + * @param string $message + * @param array ...$parameters + */ + protected function error($message, ...$parameters) + { + fwrite(STDERR, sprintf($message, ...$parameters) . PHP_EOL); + } +} + +$installer = new Magento_Extension_Installer(); + +exit($installer->run()); diff --git a/src/bin/magento-installer b/src/bin/magento-installer new file mode 100755 index 0000000..a725841 --- /dev/null +++ b/src/bin/magento-installer @@ -0,0 +1,94 @@ +#!/bin/bash + +[ "$DEBUG" = "true" ] && set -x + +AUTH_JSON_FILE="$(composer -g config data-dir 2>/dev/null)/auth.json" + +if [ -f "$AUTH_JSON_FILE" ]; then + # Get composer auth information into an environment variable to avoid "you need + # to be using an interactive terminal to authenticate". + COMPOSER_AUTH=`cat $AUTH_JSON_FILE` +fi + +MAGENTO_COMMAND="magento-command" + +if [ ! -f "$MAGENTO_ROOT/composer.json" ]; then + echo "Creating Magento ($M2SETUP_VERSION) project from composer" + + composer create-project \ + --repository-url=https://repo.magento.com/ \ + magento/project-community-edition=$M2SETUP_VERSION \ + --no-interaction \ + $MAGENTO_ROOT + + # Magento forces Composer to use $MAGENTO_ROOT/var/composer_home as the home directory + # when running any Composer commands through Magento, e.g. sampledata:deploy, so copy the + # credentials over to it to prevent Composer from asking for them again + if [ -f "$AUTH_JSON_FILE" ]; then + mkdir -p $MAGENTO_ROOT/var/composer_home + cp $AUTH_JSON_FILE $MAGENTO_ROOT/var/composer_home/auth.json + fi +else + echo "Magento installation found in $MAGENTO_ROOT, installing composer dependencies" + composer --working-dir=$MAGENTO_ROOT install +fi + +chown -R www-data:www-data $MAGENTO_ROOT + +if [ ! "$M2SETUP_INSTALL_DB" = "false" ]; then + + echo "Install Magento" + + INSTALL_COMMAND="$MAGENTO_COMMAND setup:install \ + --db-host=$M2SETUP_DB_HOST \ + --db-name=$M2SETUP_DB_NAME \ + --db-user=$M2SETUP_DB_USER \ + --db-password=$M2SETUP_DB_PASSWORD \ + --base-url=$M2SETUP_BASE_URL \ + --admin-firstname=$M2SETUP_ADMIN_FIRSTNAME \ + --admin-lastname=$M2SETUP_ADMIN_LASTNAME \ + --admin-email=$M2SETUP_ADMIN_EMAIL \ + --admin-user=$M2SETUP_ADMIN_USER \ + --admin-password=$M2SETUP_ADMIN_PASSWORD" + + # Use a separate value for secure base URL, if the variable is set + if [ -n "$M2SETUP_SECURE_BASE_URL" ]; then + INSTALL_COMMAND="$INSTALL_COMMAND --base-url-secure=$M2SETUP_SECURE_BASE_URL" + fi + + # Only define a backend-frontname if the variable is set, or not empty. + if [ -n "$M2SETUP_BACKEND_FRONTNAME" ]; then + INSTALL_COMMAND="$INSTALL_COMMAND --backend-frontname=$M2SETUP_BACKEND_FRONTNAME" + fi + + if [ "$M2SETUP_USE_SAMPLE_DATA" = "true" ]; then + + $MAGENTO_COMMAND sampledata:deploy + composer --working-dir=$MAGENTO_ROOT update + + INSTALL_COMMAND="$INSTALL_COMMAND --use-sample-data" + fi + + $INSTALL_COMMAND + $MAGENTO_COMMAND index:reindex + $MAGENTO_COMMAND setup:static-content:deploy + +else + echo "Skipping DB installation" +fi + +echo "Fixing file permissions.." + +[ -f "$MAGENTO_ROOT/vendor/magento/framework/Filesystem/DriverInterface.php" ] \ + && sed -i 's/0770/0775/g' $MAGENTO_ROOT/vendor/magento/framework/Filesystem/DriverInterface.php + +[ -f "$MAGENTO_ROOT/vendor/magento/framework/Filesystem/DriverInterface.php" ] \ + && sed -i 's/0660/0664/g' $MAGENTO_ROOT/vendor/magento/framework/Filesystem/DriverInterface.php + +find $MAGENTO_ROOT/pub -type f -exec chmod 664 {} \; +find $MAGENTO_ROOT/pub -type d -exec chmod 775 {} \; +find $MAGENTO_ROOT/var/generation -type d -exec chmod g+s {} \; + +chown -R www-data:www-data $MAGENTO_ROOT + +echo "Installation complete" diff --git a/src/bin/magerun2 b/src/bin/magerun2 new file mode 100755 index 0000000..476c55b --- /dev/null +++ b/src/bin/magerun2 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +[ "$DEBUG" = "true" ] && set -x + +su www-data -s /bin/bash -c "n98-magerun2.phar --root-dir=$MAGENTO_ROOT $*" diff --git a/src/bin/run-cron b/src/bin/run-cron new file mode 100755 index 0000000..8f6a393 --- /dev/null +++ b/src/bin/run-cron @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +cron && \ +tail -f -n0 /var/log/cron.log diff --git a/src/docker-entrypoint.sh b/src/docker-entrypoint.sh new file mode 100644 index 0000000..49339f4 --- /dev/null +++ b/src/docker-entrypoint.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +[ "$DEBUG" = "true" ] && set -x + +# If asked, we'll ensure that the www-data is set to the same uid/gid as the +# mounted volume. This works around permission issues with virtualbox shared +# folders. +if [[ "$UPDATE_UID_GID" = "true" ]]; then + echo "Updating www-data uid and gid" + + DOCKER_UID=`stat -c "%u" $MAGENTO_ROOT` + DOCKER_GID=`stat -c "%g" $MAGENTO_ROOT` + + INCUMBENT_USER=`getent passwd $DOCKER_UID | cut -d: -f1` + INCUMBENT_GROUP=`getent group $DOCKER_GID | cut -d: -f1` + + echo "Docker: uid = $DOCKER_UID, gid = $DOCKER_GID" + echo "Incumbent: user = $INCUMBENT_USER, group = $INCUMBENT_GROUP" + + # Once we've established the ids and incumbent ids then we need to free them + # up (if necessary) and then make the change to www-data. + + [ ! -z "${INCUMBENT_USER}" ] && usermod -u 99$DOCKER_UID $INCUMBENT_USER + usermod -u $DOCKER_UID www-data + + [ ! -z "${INCUMBENT_GROUP}" ] && groupmod -g 99$DOCKER_GID $INCUMBENT_GROUP + groupmod -g $DOCKER_GID www-data +fi + +# Ensure our Magento directory exists +mkdir -p $MAGENTO_ROOT +chown www-data:www-data $MAGENTO_ROOT + + + +CRON_LOG=/var/log/cron.log + +# Setup Magento cron +echo "* * * * * www-data /usr/local/bin/php ${MAGENTO_ROOT}/bin/magento cron:run | grep -v \"Ran jobs by schedule\" >> ${MAGENTO_ROOT}/var/log/magento.cron.log" > /etc/cron.d/magento +echo "* * * * * www-data /usr/local/bin/php ${MAGENTO_ROOT}/update/cron.php >> ${MAGENTO_ROOT}/var/log/update.cron.log" >> /etc/cron.d/magento +echo "* * * * * www-data /usr/local/bin/php ${MAGENTO_ROOT}/bin/magento setup:cron:run >> ${MAGENTO_ROOT}/var/log/setup.cron.log" >> /etc/cron.d/magento + +# Get rsyslog running for cron output +touch $CRON_LOG +echo "cron.* $CRON_LOG" > /etc/rsyslog.d/cron.conf +service rsyslog start + + + + +# Configure Sendmail if required +if [ "$ENABLE_SENDMAIL" == "true" ]; then + /etc/init.d/sendmail start +fi + +# Substitute in php.ini values +[ ! -z "${PHP_MEMORY_LIMIT}" ] && sed -i "s/!PHP_MEMORY_LIMIT!/${PHP_MEMORY_LIMIT}/" /usr/local/etc/php/conf.d/zz-magento.ini +[ ! -z "${UPLOAD_MAX_FILESIZE}" ] && sed -i "s/!UPLOAD_MAX_FILESIZE!/${UPLOAD_MAX_FILESIZE}/" /usr/local/etc/php/conf.d/zz-magento.ini + +[ "$PHP_ENABLE_XDEBUG" = "true" ] && \ + docker-php-ext-enable xdebug && \ + echo "Xdebug is enabled" + + + +# Configure composer +[ ! -z "${COMPOSER_GITHUB_TOKEN}" ] && \ + composer config --global github-oauth.github.com $COMPOSER_GITHUB_TOKEN + +[ ! -z "${COMPOSER_MAGENTO_USERNAME}" ] && \ + composer config --global http-basic.repo.magento.com \ + $COMPOSER_MAGENTO_USERNAME $COMPOSER_MAGENTO_PASSWORD + +[ ! -z "${COMPOSER_BITBUCKET_KEY}" ] && [ ! -z "${COMPOSER_BITBUCKET_SECRET}" ] && \ + composer config --global bitbucket-oauth.bitbucket.org $COMPOSER_BITBUCKET_KEY $COMPOSER_BITBUCKET_SECRET + + + +# Configure PHP-FPM +[ ! -z "${MAGENTO_RUN_MODE}" ] && sed -i "s/!MAGENTO_RUN_MODE!/${MAGENTO_RUN_MODE}/" /usr/local/etc/php-fpm.conf + + + +exec "$@" + diff --git a/src/etc/mail.ini b/src/etc/mail.ini new file mode 100644 index 0000000..d6dc40b --- /dev/null +++ b/src/etc/mail.ini @@ -0,0 +1,2 @@ +; Sendmail +sendmail_path=/usr/sbin/sendmail -t -i diff --git a/7.1-cli/etc/php-fpm.conf b/src/etc/php-fpm.conf similarity index 100% rename from 7.1-cli/etc/php-fpm.conf rename to src/etc/php-fpm.conf diff --git a/src/etc/php-xdebug.ini b/src/etc/php-xdebug.ini new file mode 100644 index 0000000..a95a842 --- /dev/null +++ b/src/etc/php-xdebug.ini @@ -0,0 +1,12 @@ +; This file is created automatically by the docker build + +; Xdebug settings will only kick in if the Xdebug module is loaded + +xdebug.remote_enable = 1 +xdebug.remote_connect_back = 1 +xdebug.remote_port = 9000 + +xdebug.scream = 0 +xdebug.show_local_vars = 1 + +xdebug.idekey = PHPSTORM diff --git a/src/etc/php.ini b/src/etc/php.ini new file mode 100644 index 0000000..0a1cf51 --- /dev/null +++ b/src/etc/php.ini @@ -0,0 +1,3 @@ +; This file is created automatically by the docker build + +memory_limit = !PHP_MEMORY_LIMIT! ; Variable: PHP_MEMORY_LIMIT