From 49d612daa1c9993f494b6233a07bf47b93311ec4 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 10 Jul 2018 20:02:19 +0300 Subject: [PATCH] Replace debian-based image with alpine-based. Remove supervisor usage. Cron now runs as separate service. CI for backend now performs without Docker. --- .gitlab-ci.yml | 45 ++++-------- Dockerfile | 119 ++++++++++++++++++++------------ Dockerfile-dev | 52 -------------- composer.json | 2 +- composer.lock | 4 +- docker-compose.dev.yml | 33 +++++---- docker-compose.prod.yml | 9 +++ docker/php/bootstrap.sh | 41 ----------- docker/php/docker-entrypoint.sh | 62 +++++++++++++++++ docker/php/php.dev.ini | 5 ++ docker/php/php.prod.ini | 14 ++++ docker/{ => php}/wait-for-it.sh | 0 12 files changed, 201 insertions(+), 185 deletions(-) delete mode 100644 Dockerfile-dev delete mode 100755 docker/php/bootstrap.sh create mode 100755 docker/php/docker-entrypoint.sh create mode 100644 docker/php/php.dev.ini create mode 100644 docker/php/php.prod.ini rename docker/{ => php}/wait-for-it.sh (100%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8deb81b..3a5aacb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,50 +6,31 @@ stages: variables: CONTAINER_IMAGE: "registry.ely.by/elyby/accounts" -test:backend: - image: docker:18.02 +check backend codestyle: + image: edbizarro/gitlab-ci-pipeline-php:7.2-alpine + stage: test + script: + - vendor/bin/php-cs-fixer fix -v --dry-run + +test backend: + image: edbizarro/gitlab-ci-pipeline-php:7.2-alpine services: - mariadb:10.2.11 - redis:3.0-alpine variables: + # app config + YII_ENV: "test" + YII_DEBUG: "true" # mariadb config MYSQL_RANDOM_ROOT_PASSWORD: "true" MYSQL_DATABASE: "ely_accounts_test" MYSQL_USER: "ely_accounts_tester" MYSQL_PASSWORD: "ely_accounts_tester_password" stage: test - before_script: - - docker login -u gitlab-ci -p $CI_BUILD_TOKEN registry.ely.by - - echo "$SSH_PRIVATE_KEY" > id_rsa script: - - export TEMP_DEV_IMAGE="${CONTAINER_IMAGE}:ci-${CI_BUILD_ID}" - - docker build --pull -f Dockerfile-dev -t $TEMP_DEV_IMAGE . - - > - docker run --rm - $TEMP_DEV_IMAGE - bash -c " - rm /usr/local/etc/php/conf.d/xdebug.ini && - cp -r /var/www/vendor /var/www/html/vendor && - vendor/bin/php-cs-fixer fix -v --dry-run - " - - > - docker run --rm - --add-host=mariadb:`getent hosts mariadb | awk '{ print $1 ; exit }'` - --add-host=redis:`getent hosts redis | awk '{ print $1 ; exit }'` - -e YII_DEBUG="true" - -e YII_ENV="test" - -e DB_HOST="mariadb" - -e DB_DATABASE="ely_accounts_test" - -e DB_USER="ely_accounts_tester" - -e DB_PASSWORD="ely_accounts_tester_password" - -e REDIS_HOST="redis" - $TEMP_DEV_IMAGE - bash -c " - rm /usr/local/etc/php/conf.d/xdebug.ini && - docker-entrypoint.sh php vendor/bin/codecept run -c tests - " + - docker-entrypoint.sh vendor/bin/codecept run -c tests -test:frontend: +test frontend: image: node:9.2.1-alpine stage: test cache: diff --git a/Dockerfile b/Dockerfile index 54d8000..652ab21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,55 +1,86 @@ -FROM registry.ely.by/elyby/accounts-php:1.8.0 +FROM node:9.11.2-alpine as frontend -# bootstrap скрипт для проекта -COPY docker/php/bootstrap.sh /bootstrap.sh -# Вносим конфигурации для крона и воркеров -COPY docker/cron/* /etc/cron.d/ -COPY docker/supervisor/* /etc/supervisor/conf.d/ +WORKDIR /app -COPY id_rsa /root/.ssh/id_rsa +COPY ./frontend/package.json ./ +COPY ./frontend/scripts ./scripts +COPY ./frontend/webpack-utils ./webpack-utils +COPY ./frontend/yarn.lock ./ +RUN yarn build:install -# Включаем поддержку ssh -RUN chmod 400 ~/.ssh/id_rsa \ - && eval $(ssh-agent -s) \ - && ssh-add /root/.ssh/id_rsa \ - && touch /root/.ssh/known_hosts \ - && ssh-keyscan github.com gitlab.ely.by >> /root/.ssh/known_hosts +COPY ./frontend . +RUN yarn build:quiet -# Копируем списки зависимостей composer в родительскую директорию, которая не будет синкаться -# с хостом через volume на dev окружении. В entrypoint эта папка будет скопирована обратно -COPY ./composer.json /var/www/composer.json -COPY ./composer.lock /var/www/composer.lock -# Устанавливаем зависимости PHP -RUN cd .. \ - && composer install --no-interaction --no-suggest --no-dev --optimize-autoloader \ - && cd - +FROM php:7.2.7-fpm-alpine3.7 -# Устанавливаем зависимости для Node.js -# Делаем это отдельно, чтобы можно было воспользоваться кэшем, если от предыдущего билда -# ничего не менялось в зависимостях -RUN mkdir -p /var/www/frontend +# bash needed to support wait-for-it script +RUN apk add --update --no-cache \ + git \ + bash \ + openssh \ + dcron \ + zlib-dev \ + icu-dev \ + libintl \ + imagemagick-dev \ + imagemagick \ + && docker-php-ext-install \ + zip \ + pdo_mysql \ + intl \ + pcntl \ + opcache \ + && apk add --no-cache --virtual ".phpize-deps" $PHPIZE_DEPS \ + && yes | pecl install xdebug-2.6.0 \ + && yes | pecl install imagick \ + && docker-php-ext-enable imagick \ + && apk del ".phpize-deps" \ + && rm -rf /usr/share/man \ + && rm -rf /tmp/* \ + && mkdir /etc/cron.d -COPY ./frontend/package.json /var/www/frontend/ -COPY ./frontend/yarn.lock /var/www/frontend/ -COPY ./frontend/scripts /var/www/frontend/scripts -COPY ./frontend/webpack-utils /var/www/frontend/webpack-utils +COPY --from=composer:1.6.5 /usr/bin/composer /usr/bin/composer +COPY --from=node:9.11.2-alpine /usr/local/bin/node /usr/bin/ +COPY --from=node:9.11.2-alpine /usr/lib/libgcc* /usr/lib/libstdc* /usr/lib/* /usr/lib/ -RUN cd /var/www/frontend \ - && yarn run build:install \ - && cd - +# ENV variables for composer +ENV COMPOSER_NO_INTERACTION 1 +ENV COMPOSER_ALLOW_SUPERUSER 1 -# Удаляем ключи из production контейнера на всякий случай -RUN rm -rf /root/.ssh +RUN mkdir /root/.composer \ + && echo '{"github-oauth": {"github.com": "***REMOVED***"}}' > ~/.composer/auth.json \ + && composer global require --no-progress "hirak/prestissimo:^0.3.7" \ + && composer clear-cache -# Наконец переносим все сорцы внутрь контейнера -COPY . /var/www/html +COPY ./docker/php/wait-for-it.sh /usr/local/bin/wait-for-it -# Билдим фронт -RUN cd frontend \ - && ln -s /var/www/frontend/node_modules $PWD/node_modules \ - && yarn run build:quiet \ - && rm node_modules \ - # Копируем билд наружу, чтобы его не затёрло volume в dev режиме - && cp -r ./dist /var/www/dist \ - && cd - +COPY ./composer.* /var/www/html/ + +ARG build_env=prod +ENV YII_ENV=$build_env + +RUN if [ "$build_env" = "prod" ] ; then \ + composer install --no-interaction --no-suggest --no-dev --optimize-autoloader; \ + else \ + composer install --no-interaction --no-suggest; \ + fi \ + && composer clear-cache + +COPY ./docker/php/*.ini /usr/local/etc/php/conf.d/ +COPY ./docker/php/docker-entrypoint.sh /usr/local/bin/ +COPY ./docker/cron/* /etc/cron.d/ + +COPY --from=frontend /app/dist /var/www/html/frontend/dist + +COPY ./api /var/www/html/api/ +COPY ./common /var/www/html/common/ +COPY ./console /var/www/html/console/ +COPY ./yii /var/www/html/yii + +# Expose everything under /var/www/html to share it with nginx +VOLUME ["/var/www/html"] + +WORKDIR /var/www/html +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["php-fpm"] diff --git a/Dockerfile-dev b/Dockerfile-dev deleted file mode 100644 index dec0312..0000000 --- a/Dockerfile-dev +++ /dev/null @@ -1,52 +0,0 @@ -FROM registry.ely.by/elyby/accounts-php:1.8.0-dev - -# bootstrap скрипт для проекта -COPY docker/php/bootstrap.sh /bootstrap.sh -# Вносим конфигурации для крона и воркеров -COPY docker/cron/* /etc/cron.d/ -COPY docker/supervisor/* /etc/supervisor/conf.d/ - -COPY id_rsa /root/.ssh/id_rsa - -# Включаем поддержку ssh -RUN chmod 400 ~/.ssh/id_rsa \ - && eval $(ssh-agent -s) \ - && ssh-add /root/.ssh/id_rsa \ - && touch /root/.ssh/known_hosts \ - && ssh-keyscan github.com gitlab.ely.by >> /root/.ssh/known_hosts - -# Копируем списки зависимостей composer в родительскую директорию, которая не будет синкаться -# с хостом через volume на dev окружении. В entrypoint эта папка будет скопирована обратно -COPY ./composer.json /var/www/composer.json -COPY ./composer.lock /var/www/composer.lock - -# Устанавливаем зависимости PHP -RUN cd .. \ - && composer install --no-interaction --no-suggest \ - && cd - - -# Устанавливаем зависимости для Node.js -# Делаем это отдельно, чтобы можно было воспользоваться кэшем, если от предыдущего билда -# ничего не менялось в зависимостях -RUN mkdir -p /var/www/frontend - -COPY ./frontend/package.json /var/www/frontend/ -COPY ./frontend/yarn.lock /var/www/frontend/ -COPY ./frontend/scripts /var/www/frontend/scripts -COPY ./frontend/webpack-utils /var/www/frontend/webpack-utils - -RUN cd /var/www/frontend \ - && yarn run build:install \ - && cd - - -# Наконец переносим все сорцы внутрь контейнера -COPY . /var/www/html - -# Билдим фронт -RUN cd frontend \ - && ln -s /var/www/frontend/node_modules $PWD/node_modules \ - && yarn run build:quiet \ - && rm node_modules \ - # Копируем билд наружу, чтобы его не затёрло volume в dev режиме - && cp -r ./dist /var/www/dist \ - && cd - diff --git a/composer.json b/composer.json index 9bf9e12..d6448ff 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ }, { "type": "git", - "url": "git@gitlab.ely.by:elyby/email-renderer.git" + "url": "https://gitlab+deploy-token-1:FDGgmcnLdykcsyJJ_8Uv@gitlab.ely.by/elyby/email-renderer.git" } ], "autoload": { diff --git a/composer.lock b/composer.lock index 60f1fee..cba9321 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4334ca4dd8b377a9c40afd844527a850", + "content-hash": "7368afb90e5f3ed26a7b6d98551da170", "packages": [ { "name": "bacon/bacon-qr-code", @@ -615,7 +615,7 @@ "version": "dev-master", "source": { "type": "git", - "url": "git@gitlab.ely.by:elyby/email-renderer.git", + "url": "https://gitlab+deploy-token-1:FDGgmcnLdykcsyJJ_8Uv@gitlab.ely.by/elyby/email-renderer.git", "reference": "8aa2e71c5b3b8e4a726c3c090b2997030ba29f73" }, "require": { diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 7082ef4..7854586 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,9 +1,11 @@ version: '2' services: app: + image: registry.ely.by/elyby/accounts:dev build: - dockerfile: Dockerfile-dev context: . + args: + build_env: dev depends_on: - db - redis @@ -12,9 +14,11 @@ services: env_file: .env worker: + image: registry.ely.by/elyby/accounts:dev build: - dockerfile: Dockerfile-dev context: . + args: + build_env: dev command: ['php', 'yii', 'queue/listen', '-v'] depends_on: - db @@ -23,6 +27,20 @@ services: - ./:/var/www/html/ env_file: .env + cron: + image: registry.ely.by/elyby/accounts:dev + build: + context: . + args: + build_env: dev + command: ['crond', '-s', '/etc/cron.d', '-f', '-L', '/var/log/cron.log'] + depends_on: + - db + - redis + volumes: + - ./:/var/www/html/ + env_file: .env + web: image: registry.ely.by/elyby/accounts-nginx:latest volumes_from: @@ -58,17 +76,6 @@ services: - default - nginx-proxy - # Эта штука работает дико медленно, грузит процессор и т.д. и т.п. - # Раскоментировать только в случае лютой надобности - #node-dev-server: - # build: ./frontend - # ports: - # - "8080:8080" - # volumes: - # - ./frontend/:/usr/src/app/ - # environment: - # DOCKERIZED: "true" - networks: nginx-proxy: external: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 539c878..687baab 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -17,6 +17,15 @@ services: - redis env_file: .env + worker: + image: registry.ely.by/elyby/accounts:latest + restart: always + command: ['crond', '-s', '/etc/cron.d', '-f', '-L', '/var/log/cron.log'] + depends_on: + - db + - redis + env_file: .env + web: image: registry.ely.by/elyby/accounts-nginx:1.0.3 restart: always diff --git a/docker/php/bootstrap.sh b/docker/php/bootstrap.sh deleted file mode 100755 index 65617dd..0000000 --- a/docker/php/bootstrap.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -mkdir -p api/runtime api/web/assets console/runtime -chown www-data:www-data api/runtime api/web/assets console/runtime - -if [ "$YII_ENV" = "test" ] -then - YII_EXEC="/var/www/html/tests/codeception/bin/yii" -else - YII_EXEC="/var/www/html/yii" -fi - -if ! cmp -s ./../vendor/autoload.php ./vendor/autoload.php -then - echo "Vendor have diffs" - echo "Removing not bundled vendor..." - rm -rf ./vendor - echo "Copying new one..." - cp -r ./../vendor ./vendor -fi - -# Переносим dist, если его нету или он изменился (или затёрся силами volume) -if ! cmp -s ./../dist/index.html ./frontend/dist/index.html -then - echo "Frontend dist have diffs" - echo "Removing not bundled dist..." - rm -rf ./frontend/dist - echo "Copying new one..." - cp -r ./../dist ./frontend/dist -fi - -# Генерируем правила RBAC -echo "Generating RBAC rules" -php $YII_EXEC rbac/generate - -if [ "$YII_ENV" != "test" ] -then - wait-for-it "${DB_HOST:-db}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" -else - wait-for-it "${DB_HOST:-testdb}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" -fi diff --git a/docker/php/docker-entrypoint.sh b/docker/php/docker-entrypoint.sh new file mode 100755 index 0000000..c34f9fa --- /dev/null +++ b/docker/php/docker-entrypoint.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -e + +XDEBUG_EXTENSION_FILE="/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini" +PHP_PROD_INI="/usr/local/etc/php/conf.d/php.prod.ini" +PHP_DEV_INI="/usr/local/etc/php/conf.d/php.dev.ini" + +if [ "$YII_DEBUG" = "true" ] || [ "$YII_DEBUG" = "1" ] ; then + echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > $XDEBUG_EXTENSION_FILE + mv ${PHP_PROD_INI}{,.disabled} 2> /dev/null || true + mv ${PHP_DEV_INI}{.disabled,} 2> /dev/null || true +else + rm -f $XDEBUG_EXTENSION_FILE + mv ${PHP_DEV_INI}{,.disabled} 2> /dev/null || true + mv ${PHP_PROD_INI}{.disabled,} 2> /dev/null || true +fi + +cd /var/www/html + +# Create all necessary folders +mkdir -p api/runtime api/web/assets console/runtime +chown -R www-data:www-data api/runtime api/web/assets console/runtime + +if [ "$YII_ENV" = "test" ] +then + YII_EXEC="/var/www/html/tests/codeception/bin/yii" +else + YII_EXEC="/var/www/html/yii" +fi + +# Fix permissions for cron tasks +chmod 644 /etc/cron.d/* + +if [ "$1" = "crond" ] ; then + # see: https://github.com/dubiousjim/dcron/issues/13 + # ignore using `exec` for `dcron` to get another pid instead of `1` + # exec "$@" + "$@" +fi + +if [ "$1" = "yii" ] ; then + shift + php $YII_EXEC "$@" + exit 0 +fi + +if [ "$1" = "sh" ] || [ "$1" = "bash" ] || [ "$1" = "composer" ] || [ "$1" = "php" ] ; then + exec "$@" + exit 0 +fi + +echo "Generating RBAC rules" +php $YII_EXEC rbac/generate + +if [ "$YII_ENV" != "test" ] +then + wait-for-it "${DB_HOST:-db}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" +else + wait-for-it "${DB_HOST:-testdb}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" +fi + +exec "$@" diff --git a/docker/php/php.dev.ini b/docker/php/php.dev.ini new file mode 100644 index 0000000..7114082 --- /dev/null +++ b/docker/php/php.dev.ini @@ -0,0 +1,5 @@ +error_reporting = E_ALL; +display_errors = On; + +# Disable Opcache caching +opcache.validate_timestamps = 1; diff --git a/docker/php/php.prod.ini b/docker/php/php.prod.ini new file mode 100644 index 0000000..f0cc3e5 --- /dev/null +++ b/docker/php/php.prod.ini @@ -0,0 +1,14 @@ +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT +display_errors = Off +display_startup_errors = Off +log_errors = On +html_errors = Off +expose_php = Off + +# Opcache tuning +opcache.revalidate_freq = 0 +opcache.validate_timestamps = 0 +opcache.max_accelerated_files = 7963 +opcache.memory_consumption = 192 +opcache.interned_strings_buffer = 16 +opcache.fast_shutdown = 1 diff --git a/docker/wait-for-it.sh b/docker/php/wait-for-it.sh similarity index 100% rename from docker/wait-for-it.sh rename to docker/php/wait-for-it.sh