From 064f9fbec8c4cb567f6883926ee19ea1ec69bd9b Mon Sep 17 00:00:00 2001 From: David Cole Date: Thu, 26 Mar 2020 10:18:39 +0000 Subject: [PATCH] publish 'wordpress' harness --- _twig/docker-compose.yml/application.yml.twig | 75 +++++ _twig/docker-compose.yml/environment.yml.twig | 0 .../service/chrome.yml.twig | 7 + .../docker-compose.yml/service/cron.yml.twig | 18 ++ .../service/elasticsearch.yml.twig | 12 + .../service/memcached.yml.twig | 6 + .../docker-compose.yml/service/mysql.yml.twig | 17 ++ .../service/php-fpm-exporter.yml.twig | 10 + .../service/postgres.yml.twig | 10 + .../service/redis-session.yml.twig | 8 + .../docker-compose.yml/service/redis.yml.twig | 8 + application/overlay/.dockerignore.twig | 8 + application/overlay/Jenkinsfile.twig | 62 ++++ .../overlay/_twig/.dockerignore/dynamic.twig | 2 + .../overlay/_twig/.dockerignore/static.twig | 1 + application/overlay/auth.json.twig | 15 + application/skeleton/README.md.twig | 137 +++++++++ docker-compose.yml.twig | 24 ++ docker-sync.yml.twig | 16 ++ docker/image/console/.dockerignore | 1 + docker/image/console/Dockerfile.twig | 33 +++ docker/image/console/root/app/.gitkeep | 0 docker/image/console/root/bin/app | 19 ++ .../image/console/root/entrypoint.dynamic.sh | 52 ++++ docker/image/console/root/entrypoint.sh | 26 ++ .../console/root/home/build/.my.cnf.twig | 4 + docker/image/console/root/lib/functions.sh | 21 ++ docker/image/console/root/lib/sidekick.sh | 81 ++++++ .../console/root/lib/task/assets/apply.sh | 36 +++ .../console/root/lib/task/assets/dump.sh | 19 ++ docker/image/console/root/lib/task/build.sh | 13 + .../root/lib/task/build/backend.sh.twig | 15 + .../root/lib/task/build/frontend.sh.twig | 15 + .../console/root/lib/task/composer/install.sh | 6 + .../root/lib/task/database/available.sh | 31 ++ .../root/lib/task/database/import.sh.twig | 10 + .../image/console/root/lib/task/init.sh.twig | 18 ++ .../console/root/lib/task/install.sh.twig | 11 + .../console/root/lib/task/migrate.sh.twig | 10 + .../console/root/lib/task/overlay/apply.sh | 6 + .../console/root/lib/task/skeleton/apply.sh | 6 + docker/image/console/root/lib/task/state.sh | 8 + docker/image/console/root/lib/task/welcome.sh | 13 + .../php/conf.d/docker-php-ext-xdebug.ini.twig | 8 + .../root/usr/local/etc/php/php.ini.twig | 10 + docker/image/cron/Dockerfile.twig | 29 ++ docker/image/cron/root/cron-run-with-env.sh | 5 + docker/image/cron/root/crontab.twig | 3 + docker/image/cron/root/entrypoint.sh | 8 + docker/image/nginx/Dockerfile.twig | 17 ++ .../docker-entrypoint.d/config_render.sh.twig | 14 + .../root/etc/nginx/conf.d/0-nginx.conf.twig | 3 + .../root/etc/nginx/snippets/certificate.conf | 2 + .../root/etc/nginx/snippets/ssl-params.conf | 17 ++ .../nginx/root/etc/ssl/certs/app.crt.twig | 1 + .../nginx/root/etc/ssl/private/app.key.twig | 1 + docker/image/php-fpm/.dockerignore | 1 + docker/image/php-fpm/Dockerfile.twig | 24 ++ docker/image/php-fpm/root/app/.gitkeep | 0 .../image/php-fpm/root/entrypoint.dynamic.sh | 67 +++++ docker/image/php-fpm/root/entrypoint.sh.twig | 16 ++ .../etc/supervisor/conf.d/container-cmd.conf | 9 + .../root/etc/supervisor/supervisord.conf | 18 ++ .../php-fpm/root/fix_app_permissions.sh.twig | 55 ++++ .../php/conf.d/docker-php-ext-xdebug.ini.twig | 8 + .../root/usr/local/etc/php/php.ini.twig | 10 + docs/.gitkeep | 0 harness/attributes/common.yml | 267 ++++++++++++++++++ harness/attributes/docker-base.yml | 92 ++++++ harness/attributes/environment/local.yml | 6 + harness/attributes/environment/pipeline.yml | 8 + harness/config/commands.yml | 217 ++++++++++++++ harness/config/docker-sync.yml | 8 + harness/config/events.yml | 10 + harness/config/functions.yml | 69 +++++ harness/config/mutagen.yml | 34 +++ harness/config/pipeline.yml | 94 ++++++ harness/scripts/destroy.sh | 17 ++ harness/scripts/disable.sh | 9 + harness/scripts/docker_sync.sh | 84 ++++++ harness/scripts/enable.sh.twig | 64 +++++ harness/scripts/latest-mutagen-release.php | 33 +++ harness/scripts/mutagen.sh | 93 ++++++ helm/app/Chart.yaml.twig | 5 + .../_twig/values.yaml/environment.yml.twig | 1 + helm/app/_twig/values.yaml/resources.yml.twig | 16 ++ helm/app/templates/_base_helper.tpl | 20 ++ helm/app/templates/application/app-init.yaml | 65 +++++ .../templates/application/app-migrate.yaml | 65 +++++ .../application/console/deployment.yaml | 75 +++++ .../application/cron/deployment.yaml | 87 ++++++ .../templates/application/docker-config.yaml | 7 + .../application/webapp/deployment.yaml | 153 ++++++++++ .../application/webapp/ingress-istio.yaml | 25 ++ .../templates/application/webapp/ingress.yaml | 19 ++ .../application/webapp/podmonitor.yaml | 19 ++ .../templates/application/webapp/service.yaml | 15 + .../service/elasticsearch/deployment.yaml | 52 ++++ .../templates/service/elasticsearch/pvc.yaml | 31 ++ .../service/elasticsearch/service.yaml | 17 ++ .../templates/service/mysql/deployment.yaml | 55 ++++ helm/app/templates/service/mysql/pvc.yaml | 31 ++ helm/app/templates/service/mysql/service.yaml | 17 ++ .../service/postgres/deployment.yaml | 52 ++++ helm/app/templates/service/postgres/pvc.yaml | 31 ++ .../templates/service/postgres/service.yaml | 17 ++ .../service/redis-session/deployment.yaml | 51 ++++ .../service/redis-session/service.yaml | 17 ++ .../templates/service/redis/deployment.yaml | 63 +++++ helm/app/templates/service/redis/pvc.yaml | 31 ++ helm/app/templates/service/redis/service.yaml | 17 ++ helm/app/values-preview.yaml.twig | 14 + helm/app/values-production.yaml.twig | 26 ++ helm/app/values.yaml.twig | 41 +++ helm/qa/Chart.yaml.twig | 5 + helm/qa/requirements.yaml.twig | 4 + helm/qa/values.yaml.twig | 11 + mutagen.yml.twig | 30 ++ 118 files changed, 3506 insertions(+) create mode 100644 _twig/docker-compose.yml/application.yml.twig create mode 100644 _twig/docker-compose.yml/environment.yml.twig create mode 100644 _twig/docker-compose.yml/service/chrome.yml.twig create mode 100644 _twig/docker-compose.yml/service/cron.yml.twig create mode 100644 _twig/docker-compose.yml/service/elasticsearch.yml.twig create mode 100644 _twig/docker-compose.yml/service/memcached.yml.twig create mode 100644 _twig/docker-compose.yml/service/mysql.yml.twig create mode 100644 _twig/docker-compose.yml/service/php-fpm-exporter.yml.twig create mode 100644 _twig/docker-compose.yml/service/postgres.yml.twig create mode 100644 _twig/docker-compose.yml/service/redis-session.yml.twig create mode 100644 _twig/docker-compose.yml/service/redis.yml.twig create mode 100644 application/overlay/.dockerignore.twig create mode 100644 application/overlay/Jenkinsfile.twig create mode 100644 application/overlay/_twig/.dockerignore/dynamic.twig create mode 100644 application/overlay/_twig/.dockerignore/static.twig create mode 100644 application/overlay/auth.json.twig create mode 100644 application/skeleton/README.md.twig create mode 100644 docker-compose.yml.twig create mode 100644 docker-sync.yml.twig create mode 100644 docker/image/console/.dockerignore create mode 100644 docker/image/console/Dockerfile.twig create mode 100644 docker/image/console/root/app/.gitkeep create mode 100755 docker/image/console/root/bin/app create mode 100755 docker/image/console/root/entrypoint.dynamic.sh create mode 100755 docker/image/console/root/entrypoint.sh create mode 100644 docker/image/console/root/home/build/.my.cnf.twig create mode 100644 docker/image/console/root/lib/functions.sh create mode 100644 docker/image/console/root/lib/sidekick.sh create mode 100644 docker/image/console/root/lib/task/assets/apply.sh create mode 100644 docker/image/console/root/lib/task/assets/dump.sh create mode 100644 docker/image/console/root/lib/task/build.sh create mode 100644 docker/image/console/root/lib/task/build/backend.sh.twig create mode 100644 docker/image/console/root/lib/task/build/frontend.sh.twig create mode 100644 docker/image/console/root/lib/task/composer/install.sh create mode 100644 docker/image/console/root/lib/task/database/available.sh create mode 100644 docker/image/console/root/lib/task/database/import.sh.twig create mode 100644 docker/image/console/root/lib/task/init.sh.twig create mode 100644 docker/image/console/root/lib/task/install.sh.twig create mode 100644 docker/image/console/root/lib/task/migrate.sh.twig create mode 100644 docker/image/console/root/lib/task/overlay/apply.sh create mode 100644 docker/image/console/root/lib/task/skeleton/apply.sh create mode 100644 docker/image/console/root/lib/task/state.sh create mode 100644 docker/image/console/root/lib/task/welcome.sh create mode 100644 docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig create mode 100644 docker/image/console/root/usr/local/etc/php/php.ini.twig create mode 100644 docker/image/cron/Dockerfile.twig create mode 100755 docker/image/cron/root/cron-run-with-env.sh create mode 100644 docker/image/cron/root/crontab.twig create mode 100644 docker/image/cron/root/entrypoint.sh create mode 100644 docker/image/nginx/Dockerfile.twig create mode 100644 docker/image/nginx/root/docker-entrypoint.d/config_render.sh.twig create mode 100644 docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig create mode 100644 docker/image/nginx/root/etc/nginx/snippets/certificate.conf create mode 100644 docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf create mode 100644 docker/image/nginx/root/etc/ssl/certs/app.crt.twig create mode 100644 docker/image/nginx/root/etc/ssl/private/app.key.twig create mode 100644 docker/image/php-fpm/.dockerignore create mode 100644 docker/image/php-fpm/Dockerfile.twig create mode 100644 docker/image/php-fpm/root/app/.gitkeep create mode 100755 docker/image/php-fpm/root/entrypoint.dynamic.sh create mode 100755 docker/image/php-fpm/root/entrypoint.sh.twig create mode 100644 docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf create mode 100644 docker/image/php-fpm/root/etc/supervisor/supervisord.conf create mode 100755 docker/image/php-fpm/root/fix_app_permissions.sh.twig create mode 100644 docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig create mode 100644 docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig create mode 100644 docs/.gitkeep create mode 100644 harness/attributes/common.yml create mode 100644 harness/attributes/docker-base.yml create mode 100644 harness/attributes/environment/local.yml create mode 100644 harness/attributes/environment/pipeline.yml create mode 100644 harness/config/commands.yml create mode 100644 harness/config/docker-sync.yml create mode 100644 harness/config/events.yml create mode 100644 harness/config/functions.yml create mode 100644 harness/config/mutagen.yml create mode 100644 harness/config/pipeline.yml create mode 100755 harness/scripts/destroy.sh create mode 100755 harness/scripts/disable.sh create mode 100644 harness/scripts/docker_sync.sh create mode 100755 harness/scripts/enable.sh.twig create mode 100644 harness/scripts/latest-mutagen-release.php create mode 100644 harness/scripts/mutagen.sh create mode 100644 helm/app/Chart.yaml.twig create mode 100644 helm/app/_twig/values.yaml/environment.yml.twig create mode 100644 helm/app/_twig/values.yaml/resources.yml.twig create mode 100644 helm/app/templates/_base_helper.tpl create mode 100644 helm/app/templates/application/app-init.yaml create mode 100644 helm/app/templates/application/app-migrate.yaml create mode 100644 helm/app/templates/application/console/deployment.yaml create mode 100644 helm/app/templates/application/cron/deployment.yaml create mode 100644 helm/app/templates/application/docker-config.yaml create mode 100644 helm/app/templates/application/webapp/deployment.yaml create mode 100644 helm/app/templates/application/webapp/ingress-istio.yaml create mode 100644 helm/app/templates/application/webapp/ingress.yaml create mode 100644 helm/app/templates/application/webapp/podmonitor.yaml create mode 100644 helm/app/templates/application/webapp/service.yaml create mode 100644 helm/app/templates/service/elasticsearch/deployment.yaml create mode 100644 helm/app/templates/service/elasticsearch/pvc.yaml create mode 100644 helm/app/templates/service/elasticsearch/service.yaml create mode 100644 helm/app/templates/service/mysql/deployment.yaml create mode 100644 helm/app/templates/service/mysql/pvc.yaml create mode 100644 helm/app/templates/service/mysql/service.yaml create mode 100644 helm/app/templates/service/postgres/deployment.yaml create mode 100644 helm/app/templates/service/postgres/pvc.yaml create mode 100644 helm/app/templates/service/postgres/service.yaml create mode 100644 helm/app/templates/service/redis-session/deployment.yaml create mode 100644 helm/app/templates/service/redis-session/service.yaml create mode 100644 helm/app/templates/service/redis/deployment.yaml create mode 100644 helm/app/templates/service/redis/pvc.yaml create mode 100644 helm/app/templates/service/redis/service.yaml create mode 100644 helm/app/values-preview.yaml.twig create mode 100644 helm/app/values-production.yaml.twig create mode 100644 helm/app/values.yaml.twig create mode 100644 helm/qa/Chart.yaml.twig create mode 100644 helm/qa/requirements.yaml.twig create mode 100644 helm/qa/values.yaml.twig create mode 100644 mutagen.yml.twig diff --git a/_twig/docker-compose.yml/application.yml.twig b/_twig/docker-compose.yml/application.yml.twig new file mode 100644 index 0000000..0111f76 --- /dev/null +++ b/_twig/docker-compose.yml/application.yml.twig @@ -0,0 +1,75 @@ +{% set blocks = '_twig/docker-compose.yml/' %} +{% set syncvolume = false %} +{% if @('host.os') == 'darwin' and @('docker-sync') == 'yes' %} +{% set syncvolume = true %} +{% elseif @('host.os') == 'darwin' and @('mutagen') == 'yes' %} +{% set syncvolume = true %} +{% endif %} + + console: +{% if @('app.build') == 'dynamic' %} + build: + context: ./ + dockerfile: .my127ws/docker/image/console/Dockerfile + entrypoint: [/entrypoint.dynamic.sh] + command: [sleep, infinity] + volumes: + - {{ (syncvolume) ? @('workspace.name') ~ '-sync:/app:nocopy' : './:/app:delegated' }} + - ./.my127ws/application:/home/build/application + - ./.my127ws/docker/image/console/root/lib/task:/lib/task + - ./.my127ws:/.my127ws +{% else %} + image: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-console' }} +{% endif %} + labels: + - traefik.enable=false + environment: +{{ deep_merge_to_yaml([@('services.php-base.environment'), @('services.console.environment')], 2, 6) | raw }} +{% include blocks ~ 'environment.yml.twig' %} + networks: + - private + + nginx: +{% if @('app.build') == 'dynamic' %} + build: .my127ws/docker/image/nginx + volumes: + - {{ (syncvolume) ? @('workspace.name') ~ '-sync:/app:nocopy' : './:/app:delegated' }} +{% else %} + image: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-nginx' }} +{% endif %} + labels: + - traefik.backend={{ @('workspace.name') }} + - traefik.frontend.rule=Host:{{ @('hostname') }} + - traefik.docker.network=my127ws + - traefik.port=80 +{% if @('services.nginx.environment') %} + environment: +{{ to_nice_yaml(@('services.nginx.environment'), 2, 6) | raw }} +{% endif %} + links: + - php-fpm:php-fpm + networks: + private: + aliases: + - {{ @('hostname') }} + shared: {} + + php-fpm: +{% if @('app.build') == 'dynamic' %} + build: .my127ws/docker/image/php-fpm +{% if ("cron" in @('app.services')) %} + image: {{ @('workspace.name') ~ '-php-fpm:dev' }} +{% endif %} + volumes: + - {{ (syncvolume) ? @('workspace.name') ~ '-sync:/app:nocopy' : './:/app:delegated' }} + - ./.my127ws:/.my127ws +{% else %} + image: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-php-fpm' }} +{% endif %} + labels: + - traefik.enable=false + networks: + - private + environment: +{{ deep_merge_to_yaml([@('services.php-base.environment'), @('services.php-fpm.environment')], 2, 6) | raw }} +{% include blocks ~ 'environment.yml.twig' %} diff --git a/_twig/docker-compose.yml/environment.yml.twig b/_twig/docker-compose.yml/environment.yml.twig new file mode 100644 index 0000000..e69de29 diff --git a/_twig/docker-compose.yml/service/chrome.yml.twig b/_twig/docker-compose.yml/service/chrome.yml.twig new file mode 100644 index 0000000..c8a1c81 --- /dev/null +++ b/_twig/docker-compose.yml/service/chrome.yml.twig @@ -0,0 +1,7 @@ + chrome: + image: yukinying/chrome-headless-browser:latest + command: ["--no-sandbox", "--disable-gpu", "--headless", "--disable-dev-shm-usage", "--remote-debugging-address=0.0.0.0", "--remote-debugging-port=9222", "--user-data-dir=/data"] + labels: + - traefik.enable=false + networks: + - private diff --git a/_twig/docker-compose.yml/service/cron.yml.twig b/_twig/docker-compose.yml/service/cron.yml.twig new file mode 100644 index 0000000..a148960 --- /dev/null +++ b/_twig/docker-compose.yml/service/cron.yml.twig @@ -0,0 +1,18 @@ + cron: +{% if @('app.build') == 'dynamic' %} + build: + context: ./ + dockerfile: .my127ws/docker/image/cron/Dockerfile + volumes: + - {{ (syncvolume) ? @('workspace.name') ~ '-sync:/app:nocopy' : './:/app:delegated' }} + - ./.my127ws/application:/home/build/application +{% else %} + image: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-cron' }} +{% endif %} + environment: +{{ deep_merge_to_yaml([@('services.php-base.environment'),@('services.cron.environment')], 2, 6) | raw }} +{% include blocks ~ 'environment.yml.twig' %} + networks: + - private + labels: + - traefik.enable=false diff --git a/_twig/docker-compose.yml/service/elasticsearch.yml.twig b/_twig/docker-compose.yml/service/elasticsearch.yml.twig new file mode 100644 index 0000000..b3eee55 --- /dev/null +++ b/_twig/docker-compose.yml/service/elasticsearch.yml.twig @@ -0,0 +1,12 @@ + elasticsearch: + image: {{ @('elasticsearch.image') }}:{{ @('elasticsearch.tag') }} + labels: + - traefik.enable=false + environment: + ES_JAVA_OPTS: -Xms512m -Xmx512m + discovery.type: single-node + networks: + - private + ports: + - 9200 + - 9300 diff --git a/_twig/docker-compose.yml/service/memcached.yml.twig b/_twig/docker-compose.yml/service/memcached.yml.twig new file mode 100644 index 0000000..f4116b0 --- /dev/null +++ b/_twig/docker-compose.yml/service/memcached.yml.twig @@ -0,0 +1,6 @@ + memcached: + image: memcached:1-alpine + labels: + - traefik.enable=false + networks: + - private diff --git a/_twig/docker-compose.yml/service/mysql.yml.twig b/_twig/docker-compose.yml/service/mysql.yml.twig new file mode 100644 index 0000000..c73ee98 --- /dev/null +++ b/_twig/docker-compose.yml/service/mysql.yml.twig @@ -0,0 +1,17 @@ +{% set command = [] %} +{% for var,value in @('database.var') -%} + {% set command = command|merge(['--' ~ var ~ '=' ~ value]) %} +{% endfor %} + mysql: + image: mysql:5.7 + labels: + - traefik.enable=false +{% if command|length %} + command: {{ command|join(' ') }} +{% endif %} + environment: +{{ to_nice_yaml(@('services.mysql.environment'), 2, 6) | raw }} + networks: + - private + ports: + - 3306 diff --git a/_twig/docker-compose.yml/service/php-fpm-exporter.yml.twig b/_twig/docker-compose.yml/service/php-fpm-exporter.yml.twig new file mode 100644 index 0000000..12864e7 --- /dev/null +++ b/_twig/docker-compose.yml/service/php-fpm-exporter.yml.twig @@ -0,0 +1,10 @@ + php-fpm-exporter: + image: hipages/php-fpm_exporter + environment: +{{ to_nice_yaml(@('services.php-fpm-exporter.environment'), 2, 6) | raw }} + labels: + - traefik.enable=false + depends_on: + - php-fpm + networks: + - private diff --git a/_twig/docker-compose.yml/service/postgres.yml.twig b/_twig/docker-compose.yml/service/postgres.yml.twig new file mode 100644 index 0000000..25e2bbe --- /dev/null +++ b/_twig/docker-compose.yml/service/postgres.yml.twig @@ -0,0 +1,10 @@ + postgres: + image: postgres:9.6 + labels: + - traefik.enable=false + environment: +{{ to_nice_yaml(@('services.postgres.environment'), 2, 6) | raw }} + networks: + - private + ports: + - 5432 diff --git a/_twig/docker-compose.yml/service/redis-session.yml.twig b/_twig/docker-compose.yml/service/redis-session.yml.twig new file mode 100644 index 0000000..44c6072 --- /dev/null +++ b/_twig/docker-compose.yml/service/redis-session.yml.twig @@ -0,0 +1,8 @@ + redis-session: + image: redis:4-alpine + # 1GB; evict key that would expire soonest + command: redis-server --maxmemory 1073742000 --maxmemory-policy volatile-ttl --save 3600 1 --save 300 100 --save 60 10000 + labels: + - traefik.enable=false + networks: + - private diff --git a/_twig/docker-compose.yml/service/redis.yml.twig b/_twig/docker-compose.yml/service/redis.yml.twig new file mode 100644 index 0000000..978a77f --- /dev/null +++ b/_twig/docker-compose.yml/service/redis.yml.twig @@ -0,0 +1,8 @@ + redis: + image: redis:4-alpine + # 1GB; evict any least recently used key even if they don't have a TTL + command: redis-server --maxmemory 1073742000 --maxmemory-policy allkeys-lru --save 3600 1 --save 300 100 --save 60 10000 + labels: + - traefik.enable=false + networks: + - private diff --git a/application/overlay/.dockerignore.twig b/application/overlay/.dockerignore.twig new file mode 100644 index 0000000..96c90ad --- /dev/null +++ b/application/overlay/.dockerignore.twig @@ -0,0 +1,8 @@ +{% set build = @('app.build') %} +{% set blocks = 'application/overlay/_twig/.dockerignore/' %} + +{% if build == 'dynamic' %} +{% include blocks ~ 'dynamic.twig' %} +{% else %} +{% include blocks ~ 'static.twig' %} +{% endif %} diff --git a/application/overlay/Jenkinsfile.twig b/application/overlay/Jenkinsfile.twig new file mode 100644 index 0000000..2aa5292 --- /dev/null +++ b/application/overlay/Jenkinsfile.twig @@ -0,0 +1,62 @@ +pipeline { + agent { label "my127ws" } + environment { + MY127WS_KEY = credentials('{{ @('jenkins.credentials.my127ws_key') }}') + MY127WS_ENV = "pipeline" + } + triggers { cron(env.BRANCH_NAME == '{{ @('git.main_branch') }}' ? 'H H(0-6) * * *' : '') } + stages { + stage('Build') { + steps { + sh 'ws install' + milestone(10) + } + } + stage('Test') { + parallel { + stage('quality') { steps { sh 'ws exec composer test-quality' } } + stage('unit') { steps { sh 'ws exec composer test-unit' } } + stage('acceptance') { steps { sh 'ws exec composer test-acceptance' } } + stage('helm kubeval qa') { steps { sh 'ws helm kubeval qa' } } + } + } +{% if @('pipeline.publish.enabled') == 'yes' %} + stage('Publish') { + when { not { triggeredBy 'TimerTrigger' } } + steps { + milestone(50) + sh 'ws app publish' +{% if @('pipeline.publish.chart.enabled') %} + sh 'ws app publish chart "${GIT_BRANCH}" "{{ @('workspace.name') }} build artifact ${GIT_COMMIT}"' +{% endif %} + } + } +{% endif %} +{% if @('pipeline.qa.enabled') == 'yes' %} + stage('Deploy (QA)') { + environment { +{% for key, value in @('pipeline.qa.environment') %} + {{ key }} = {{ value|raw }} +{% endfor %} + } + when { + not { triggeredBy 'TimerTrigger' } + branch '{{ @('pipeline.qa.branch') }}' + } + steps { + milestone(100) + lock(resource: '{{ @('workspace.name') }}-qa-deploy', inversePrecedence: true) { + milestone(101) + sh 'ws app deploy qa' + } + } + } +{% endif %} + } + post { + always { + sh 'ws destroy' + cleanWs() + } + } +} diff --git a/application/overlay/_twig/.dockerignore/dynamic.twig b/application/overlay/_twig/.dockerignore/dynamic.twig new file mode 100644 index 0000000..4ebb7d2 --- /dev/null +++ b/application/overlay/_twig/.dockerignore/dynamic.twig @@ -0,0 +1,2 @@ +* +!.my127ws diff --git a/application/overlay/_twig/.dockerignore/static.twig b/application/overlay/_twig/.dockerignore/static.twig new file mode 100644 index 0000000..c007eac --- /dev/null +++ b/application/overlay/_twig/.dockerignore/static.twig @@ -0,0 +1 @@ +# no need for exclusions for now diff --git a/application/overlay/auth.json.twig b/application/overlay/auth.json.twig new file mode 100644 index 0000000..0731d87 --- /dev/null +++ b/application/overlay/auth.json.twig @@ -0,0 +1,15 @@ +{ + "http-basic": { + {% for repo in @('composer.auth.basic') %} + "{{ repo.path }}": { + "username": "{{ repo.username }}", + "password": "{{ repo.password }}" + }{% if not loop.last %},{% endif %} + {% endfor %} + }, + "github-oauth": { + {% if @('composer.auth.github') %} + "github.com": "{{ @('composer.auth.github') }}" + {% endif %} + } +} diff --git a/application/skeleton/README.md.twig b/application/skeleton/README.md.twig new file mode 100644 index 0000000..0bc8bdc --- /dev/null +++ b/application/skeleton/README.md.twig @@ -0,0 +1,137 @@ +# {{ @('workspace.name') }} + +Please follow the below steps to get started, if you encounter any issues installing the dependencies or provisioning the development environment, please check the [Common Issues](#common-issues) section first. + +## Development Environment + +### Getting Started + +#### Prerequisites + +##### General + +- Access to LastPass folders + - `Shared-{{ @('workspace.name') }}-Servers` and `Shared-{{ @('workspace.name') }}-Accounts` + +##### Docker + +- A working Docker setup + - On MacOS, use [Docker for Mac](https://docs.docker.com/docker-for-mac/install/). + - On Linux, add the official Docker repository and install the "docker-ce" package. + You will also need to have a recent [docker-compose](https://docs.docker.com/compose/install/) version - at least `1.24.0`. + +#### Setup + +1. Install [workspace](https://github.com/my127/workspace) +2. Copy the LastPass entry "{{ @('workspace.name') }}: Development Environment Key" to a new blank file named `workspace.override.yml` in the project root. +3. Run `ws install` + +Once installed, the site should be available at [https://{{ @('hostname') }}](https://{{ @('hostname') }}). + +### Development environment cleanup + +To stop the development environment, run `ws disable`. + +To start the development environment again, run `ws enable`. + +To remove the development environment, run `ws destroy`. + +### Frontend + +The frontend build should be automatically done as part of bringing up the environment. + +To trigger a rebuild, run `ws frontend build`. + +To watch for changes, run `ws frontend watch`. + +To gain access to the `console` container where the builds happen: `ws frontend console`. + +### Xdebug + +Xdebug is turned off by default as it drastically slows down requests for all developers. + +To enable, run `ws feature xdebug on`. To turn off again, `ws feature xdebug off`. + +To enable on CLI in `ws console`, run `ws feature xdebug cli on`. To turn off again, `ws feature xdebug cli off`. + +Xdebug is set up to listen to your computer's 9000 port once enabled, so all you would need to do in your IDE is: +1. Create a mapping from the project root to `/app` for name `workspace`, hostname `localhost` and port 80. +2. Listen for connections. + +[Here's a good guide for PhpStorm](https://www.jetbrains.com/help/phpstorm/zero-configuration-debugging.html). + +If you have trouble with triggered requests not starting connections to your IDE, check that +`sudo lsof -i :9000 | grep LISTEN` on your host shows process from your IDE. +If it doesn't, stop the indicated process (e.g. `php-fpm`) and toggle the Xdebug listen button off and on again in PhpStorm. + +### Performance on MacOS + +Page load times with Docker for Mac can vary considerably. This is especially so when there is a large +quantity of small files, such as with a large composer vendor folder. + +{% if @('docker-sync') == 'yes' %} +[docker-sync](https://github.com/EugenMayer/docker-sync/) is enabled on this workspace environment to +try to overcome this. +It enables production-like performance at the cost of having to synchronise files with an intermediate +"data" container. +{% else %} +If it takes over 2 seconds to load a page, you can consider enabling +[docker-sync](https://github.com/EugenMayer/docker-sync/) which should enable production-like performance +at the cost of having to synchronise files with an intermediate "data" container. + +You can enable docker-sync with `ws feature docker-sync on` - it takes a while to initially sync. +{% endif %} + +If you don't like the tradeoff of having to synchronise files, you can turn docker-sync off +with `ws feature docker-sync off`. + +{% if @('docker-sync') == 'yes' %} +If your page loads too slowly, you can turn docker-sync back on again with `ws feature docker-sync on` +{% endif %} + +#### Mutagen file sync + +[Mutagen](https://mutagen.io/documentation/transports/docker) is another tool to synchronize files between host machine +and docker containers, just like docker-sync. We have integrated mutagen for synchronizing files as an option of docker-sync. +This tool is still in beta phase, but you can try it yourself if you are not happy with docker-sync. +Following are some useful commands regarding Mutagen. + +```bash +# To switch to Mutagen file sync +ws switch mutagen +# To switch back to docker-sync +ws switch docker-sync +# To check the Mutagen sync status (sync is ready when status is "Watching for changes") +mutagen monitor +# To debug an errored sync +mutagen list +``` + +### Common Issues + +As setup issues are encountered please detail with step by step fix instructions, and where possible update the project or the upstream workspace harness itself to provide a more permanent fix. + +* If you use docker-sync and notice that your changes aren't synchronising to the environment: + * Check if your file exists with your changes in `ws console` + * If your file in `ws console` has changed okay, check your project for any caching that + would prevent changes to source code appearing immediately. + * If the file changes do not appear in `ws console` reasonably quickly, it might be that + Docker for Mac is overwhelmed with file change events. + * Restarting Docker for Mac using the system tray icon's menu and then running `ws enable` again + will fix it. + +# License + +Copyright 2019, Inviqa + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/docker-compose.yml.twig b/docker-compose.yml.twig new file mode 100644 index 0000000..f40af77 --- /dev/null +++ b/docker-compose.yml.twig @@ -0,0 +1,24 @@ +{% set blocks = '_twig/docker-compose.yml/' %} +{% set syncvolume = false %} +{% if @('host.os') == 'darwin' and @('docker-sync') == 'yes' %} +{% set syncvolume = true %} +{% elseif @('host.os') == 'darwin' and @('mutagen') == 'yes' %} +{% set syncvolume = true %} +{% endif %} +version: '{{ @('docker.compose.file_version') }}' +services: +{% include blocks ~ 'application.yml.twig' %} +{% for service in @('app.services') %} +{% include blocks ~ 'service/' ~ service ~ '.yml.twig' %} +{% endfor %} +networks: + private: + external: false + shared: + external: + name: my127ws +{% if syncvolume %} +volumes: + {{ @('workspace.name') }}-sync: + external: true +{% endif %} diff --git a/docker-sync.yml.twig b/docker-sync.yml.twig new file mode 100644 index 0000000..9510ee5 --- /dev/null +++ b/docker-sync.yml.twig @@ -0,0 +1,16 @@ +version: '2' +options: + compose-file-path: + - docker-compose.yml + project_root: config_path +syncs: + {{ @('workspace.name') }}-sync: + src: ./ + sync_userid: '1000' + sync_excludes_type: BelowPath + sync_excludes: &IGNORE + - .docker-sync + - .idea + - .git + - var + watch_excludes: *IGNORE diff --git a/docker/image/console/.dockerignore b/docker/image/console/.dockerignore new file mode 100644 index 0000000..cf49d54 --- /dev/null +++ b/docker/image/console/.dockerignore @@ -0,0 +1 @@ +**/*.twig diff --git a/docker/image/console/Dockerfile.twig b/docker/image/console/Dockerfile.twig new file mode 100644 index 0000000..22bfde6 --- /dev/null +++ b/docker/image/console/Dockerfile.twig @@ -0,0 +1,33 @@ +FROM {{ @('docker.image.console') }} + +COPY .my127ws/docker/image/console/root / +RUN chown -R build:build /home/build + +ENV APP_MODE={{ @('app.mode') }} \ + APP_BUILD={{ @('app.build') }} \ + ASSETS_DIR={{ @('assets.local') }} + +{% if @('node.version') is not null %} +USER build +RUN . /home/build/.nvm/nvm.sh \ + && nvm install {{ @('node.version') }} \ + && nvm use {{ @('node.version') }} \ + && nvm alias default {{ @('node.version') }} \ + && npm install -g yarn +USER root +{% endif %} + +{% if @('app.build') == 'static' %} +RUN chown build:build /app +COPY --chown=build:build .my127ws/application /home/build/application +COPY --chown=build:build ./ /app +USER build +RUN app build +USER root +{% else %} +VOLUME /app +VOLUME /home/build/application +{% endif %} + +ENTRYPOINT ["/entrypoint.sh"] +CMD ["sleep", "infinity"] diff --git a/docker/image/console/root/app/.gitkeep b/docker/image/console/root/app/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker/image/console/root/bin/app b/docker/image/console/root/bin/app new file mode 100755 index 0000000..73a8661 --- /dev/null +++ b/docker/image/console/root/bin/app @@ -0,0 +1,19 @@ +#!/bin/bash +set -e + +main() +{ + task "$@" +} + +bootstrap() +{ + export NVM_DIR="$HOME/.nvm" + # shellcheck source=/home/build/nvm.sh + [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" + . /lib/sidekick.sh + . /lib/functions.sh +} + +bootstrap +main "$@" diff --git a/docker/image/console/root/entrypoint.dynamic.sh b/docker/image/console/root/entrypoint.dynamic.sh new file mode 100755 index 0000000..940b229 --- /dev/null +++ b/docker/image/console/root/entrypoint.dynamic.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +setup_app_volume_permissions() +{ + case "$STRATEGY" in + "host-linux-normal") + usermod -u "$(stat -c '%u' /app)" build + groupmod -g "$(stat -c '%g' /app)" build + ;; + "host-osx-normal") + usermod -u 1000 build + groupmod -g 1000 build + ;; + "host-osx-dockersync") + usermod -u 1000 build + groupmod -g 1000 build + ;; + *) + exit 1 + esac + + chown build:build /app +} + +resolve_volume_mount_strategy() +{ + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + STRATEGY="host-linux-normal" + elif [ "${HOST_OS_FAMILY}" = "darwin" ]; then + if (mount | grep "/app type fuse.osxfs") > /dev/null 2>&1; then + STRATEGY="host-osx-normal" + elif (mount | grep "/app type ext4") > /dev/null 2>&1; then + STRATEGY="host-osx-dockersync" + elif (mount | grep "/app type btrfs") > /dev/null 2>&1; then + STRATEGY="host-linux-normal" + else + exit 1 + fi + else + exit 1 + fi +} + +bootstrap() +{ + resolve_volume_mount_strategy + setup_app_volume_permissions +} + +bootstrap + +source /entrypoint.sh "$@" diff --git a/docker/image/console/root/entrypoint.sh b/docker/image/console/root/entrypoint.sh new file mode 100755 index 0000000..d8e0568 --- /dev/null +++ b/docker/image/console/root/entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +setup_app_networking() +{ + # make linux consistent with docker-for-mac + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + DOCKER_INTERNAL_HOST="host.docker.internal" + if ! grep $DOCKER_INTERNAL_HOST /etc/hosts > /dev/null ; then + DOCKER_INTERNAL_IP=$(/sbin/ip route|awk '/default/ { print $3 }') + echo -e "$DOCKER_INTERNAL_IP $DOCKER_INTERNAL_HOST" | tee -a /etc/hosts > /dev/null + fi + fi +} + +bootstrap() +{ + setup_app_networking +} + +bootstrap + +if [ "${1:-}" == "sleep" ]; then + "$@" +else + exec "$@" +fi diff --git a/docker/image/console/root/home/build/.my.cnf.twig b/docker/image/console/root/home/build/.my.cnf.twig new file mode 100644 index 0000000..ef83bda --- /dev/null +++ b/docker/image/console/root/home/build/.my.cnf.twig @@ -0,0 +1,4 @@ +[client] +host=mysql +user=root +password={{ @('database.root_pass') }} diff --git a/docker/image/console/root/lib/functions.sh b/docker/image/console/root/lib/functions.sh new file mode 100644 index 0000000..4b7b401 --- /dev/null +++ b/docker/image/console/root/lib/functions.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +function db_hasSchema() +{ + if [ "${DB_PLATFORM}" == "mysql" ]; then + SQL="SELECT IF (COUNT(*) = 0, 'no', 'yes') FROM information_schema.tables WHERE table_schema = '$DB_NAME';" + IS_DATABASE_APPLIED="$(mysql -ss -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" -e "$SQL")" + elif [ "${DB_PLATFORM}" == "postgres" ]; then + SQL="SELECT CASE WHEN COUNT(*) = 0 THEN 'no' ELSE 'yes' END FROM information_schema.tables WHERE table_catalog = '$DB_NAME' and table_schema='public';" + IS_DATABASE_APPLIED="$(PGPASSWORD="$DB_PASS" psql -qtAX -h "$DB_HOST" -U "$DB_USER" -c "$SQL")" + elif [ -n "${DB_PLATFORM}" ]; then + (>&2 echo "invalid database type") + exit 1 + fi + + if [ -n "${DB_PLATFORM}" ] && [ "$IS_DATABASE_APPLIED" = "no" ]; then + return 1 + fi + + return 0 +} diff --git a/docker/image/console/root/lib/sidekick.sh b/docker/image/console/root/lib/sidekick.sh new file mode 100644 index 0000000..a5df7c9 --- /dev/null +++ b/docker/image/console/root/lib/sidekick.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +VERBOSE="no" + +RUN_CWD="" + +INDICATOR_RUNNING="34m" +INDICATOR_SUCCESS="32m" +INDICATOR_ERROR="31m" +INDICATOR_PASSTHRU="37m" + +TASKS="/lib/task" + +task() +{ + local task_file="${TASKS}/${1//:/\/}.sh" + local task_name="task_${1//:/_}" + + # shellcheck source=/dev/null + declare -F "$task_name" &>/dev/null || source "$task_file" + + shift + + $task_name "$@" +} + +prompt() +{ + if [ "${RUN_CWD}" != "$(pwd)" ]; then + RUN_CWD="$(pwd)" + echo -e "\\033[1m[\\033[0mdocker(console):$(pwd)\\033[1m]:\\033[0m" + fi +} + +run() +{ + local COMMAND="$*" + if [ "$VERBOSE" = "no" ]; then + prompt + + echo " > ${COMMAND[*]}" + setCommandIndicator $INDICATOR_RUNNING + + if ! bash -c "${COMMAND[@]}" > /tmp/my127ws-stdout.txt 2> /tmp/my127ws-stderr.txt; then + setCommandIndicator $INDICATOR_ERROR + + cat /tmp/my127ws-stderr.txt + + echo "----------------------------------" + echo "Full Logs :-" + echo " stdout: /tmp/my127ws-stdout.txt" + echo " stdout: /tmp/my127ws-stderr.txt" + + exit 1 + else + setCommandIndicator $INDICATOR_SUCCESS + fi + else + passthru "${COMMAND[@]}" + fi +} + +passthru() +{ + prompt + + echo -e "\\033[${INDICATOR_PASSTHRU}■\\033[0m > $*" + + if ! bash -c "$@"; then + exit 1 + fi +} + +setCommandIndicator() +{ + echo -ne "\\033[1A"; + echo -ne "\\033[$1" + echo -n "■" + echo -ne "\\033[0m" + echo -ne "\\033[1E"; +} diff --git a/docker/image/console/root/lib/task/assets/apply.sh b/docker/image/console/root/lib/task/assets/apply.sh new file mode 100644 index 0000000..09f55f8 --- /dev/null +++ b/docker/image/console/root/lib/task/assets/apply.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +function task_assets_apply() +{ + local ASSETS_DIR="${ASSETS_DIR:-tools/assets/development}" + local IMPORT_COMMAND="" + + if [ "${DB_PLATFORM}" == "mysql" ]; then + IMPORT_COMMAND="mysql -h $DB_HOST -u ${DB_ADMIN_USER:-$DB_USER} -p${DB_ROOT_PASS:-${DB_ADMIN_PASS:-$DB_PASS}} $DB_NAME" + elif [ "${DB_PLATFORM}" == "postgres" ]; then + IMPORT_COMMAND="PGPASSWORD=$DB_PASS psql -h $DB_HOST -U $DB_USER $DB_NAME" + elif [ -n "${DB_PLATFORM}" ]; then + (>&2 echo "invalid database type") + exit 1 + fi + + if ! db_hasSchema; then + + local DATABASE_FILE="/app/${ASSETS_DIR}/${DB_NAME}.sql.gz" + + if [ ! -f "$DATABASE_FILE" ]; then + DATABASE_FILE="$(find "/app/${ASSETS_DIR}/" -maxdepth 1 -name "${DB_NAME}*.sql.gz" -print | head -n1)" + fi + + if [ -f "$DATABASE_FILE" ]; then + passthru "pv --force $DATABASE_FILE | zcat - | $IMPORT_COMMAND" + else + task "install" + fi + fi + + for file in "/app/${ASSETS_DIR}/"*.files.{tgz,tar.gz}; do + [ -f "$file" ] || continue + run "tar -xvf ${file} -C /app" + done +} diff --git a/docker/image/console/root/lib/task/assets/dump.sh b/docker/image/console/root/lib/task/assets/dump.sh new file mode 100644 index 0000000..d6a78d9 --- /dev/null +++ b/docker/image/console/root/lib/task/assets/dump.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +function task_assets_dump() +{ + local ASSETS_DIR="${ASSETS_DIR:-tools/assets/development}" + + if [ ! -d "/app/${ASSETS_DIR}" ]; then + run "mkdir -p /app/${ASSETS_DIR}" + fi + + if [ "${DB_PLATFORM}" == "mysql" ]; then + run "mysqldump -h ${DB_HOST} -u ${DB_USER} -p${DB_PASS} ${DB_NAME} | gzip > /app/${ASSETS_DIR}/${DB_NAME}.sql.gz" + elif [ "${DB_PLATFORM}" == "postgres" ]; then + run "PGPASSWORD=$DB_PASS pg_dump -h ${DB_HOST} -U ${DB_USER} ${DB_NAME} | gzip > /app/${ASSETS_DIR}/${DB_NAME}.sql.gz" + elif [ -n "${DB_PLATFORM}" ]; then + (>&2 echo "invalid database type") + exit 1 + fi +} diff --git a/docker/image/console/root/lib/task/build.sh b/docker/image/console/root/lib/task/build.sh new file mode 100644 index 0000000..73b0962 --- /dev/null +++ b/docker/image/console/root/lib/task/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +function task_build() +{ + if [ ! -f /app/composer.json ]; then + task "skeleton:apply" + fi + + task "overlay:apply" + + task "build:backend" + task "build:frontend" +} diff --git a/docker/image/console/root/lib/task/build/backend.sh.twig b/docker/image/console/root/lib/task/build/backend.sh.twig new file mode 100644 index 0000000..418fa62 --- /dev/null +++ b/docker/image/console/root/lib/task/build/backend.sh.twig @@ -0,0 +1,15 @@ +#!/bin/bash + +function task_build_backend() +{( + cd {{ @('backend.path') }} + + if [ ! {{ @('backend.build.when')|raw }} ]; then + return 0; + fi + + {% for step in @('backend.build.steps') -%} + {{ step|raw }} + {% endfor %} + +)} diff --git a/docker/image/console/root/lib/task/build/frontend.sh.twig b/docker/image/console/root/lib/task/build/frontend.sh.twig new file mode 100644 index 0000000..deff49a --- /dev/null +++ b/docker/image/console/root/lib/task/build/frontend.sh.twig @@ -0,0 +1,15 @@ +#!/bin/bash + +function task_build_frontend() +{( + cd {{ @('frontend.path') }} + + if [ ! {{ @('frontend.build.when')|raw }} ]; then + return 0; + fi + + {% for step in @('frontend.build.steps') -%} + {{ step|raw }} + {% endfor %} + +)} diff --git a/docker/image/console/root/lib/task/composer/install.sh b/docker/image/console/root/lib/task/composer/install.sh new file mode 100644 index 0000000..119ad13 --- /dev/null +++ b/docker/image/console/root/lib/task/composer/install.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +function task_composer_install() +{ + passthru "composer install --no-interaction" +} diff --git a/docker/image/console/root/lib/task/database/available.sh b/docker/image/console/root/lib/task/database/available.sh new file mode 100644 index 0000000..c39b848 --- /dev/null +++ b/docker/image/console/root/lib/task/database/available.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +function task_database_available() +{ + local command="" + + if [ "${DB_PLATFORM}" == "mysql" ]; then + command="mysqladmin -h $DB_HOST -u ${DB_ADMIN_USER:-$DB_USER} -p${DB_ROOT_PASS:-${DB_ADMIN_PASS:-$DB_PASS}} ping --connect_timeout=10" + elif [ "${DB_PLATFORM}" == "postgres" ]; then + command="pg_isready -h $DB_HOST" + elif [ "${DB_PLATFORM}" == "" ]; then + # no database is used + return + else + (>&2 echo "invalid database type") + exit 1 + fi + + local counter=0 + + while ! $command &> /dev/null; do + + if (( counter > 300 )); then + (>&2 echo "timeout while waiting on ${DB_PLATFORM} to become available") + exit 1 + fi + + sleep 2 + ((++counter)) + done +} diff --git a/docker/image/console/root/lib/task/database/import.sh.twig b/docker/image/console/root/lib/task/database/import.sh.twig new file mode 100644 index 0000000..d0742b9 --- /dev/null +++ b/docker/image/console/root/lib/task/database/import.sh.twig @@ -0,0 +1,10 @@ +#!/bin/bash + +function task_database_import() +{ + + {% for step in @('database.import.steps') -%} + {{ step|raw }} + {% endfor %} + +} diff --git a/docker/image/console/root/lib/task/init.sh.twig b/docker/image/console/root/lib/task/init.sh.twig new file mode 100644 index 0000000..75d4642 --- /dev/null +++ b/docker/image/console/root/lib/task/init.sh.twig @@ -0,0 +1,18 @@ +#!/bin/bash + +function task_init() +{ + task "database:available" + + if ! db_hasSchema; then + + task "assets:apply" + + {% for step in @('backend.init.steps') -%} + {{ step|raw }} + {% endfor %} + + task "welcome" + + fi +} diff --git a/docker/image/console/root/lib/task/install.sh.twig b/docker/image/console/root/lib/task/install.sh.twig new file mode 100644 index 0000000..4389d61 --- /dev/null +++ b/docker/image/console/root/lib/task/install.sh.twig @@ -0,0 +1,11 @@ +#!/bin/bash + +function task_install() +{ + task "database:available" + + {% for step in @('backend.install.steps') -%} + {{ step|raw }} + {% endfor %} + +} diff --git a/docker/image/console/root/lib/task/migrate.sh.twig b/docker/image/console/root/lib/task/migrate.sh.twig new file mode 100644 index 0000000..a778b3e --- /dev/null +++ b/docker/image/console/root/lib/task/migrate.sh.twig @@ -0,0 +1,10 @@ +#!/bin/bash + +function task_migrate() +{ + task "database:available" + + {% for step in @('backend.migrate.steps') -%} + {{ step|raw }} + {% endfor %} +} diff --git a/docker/image/console/root/lib/task/overlay/apply.sh b/docker/image/console/root/lib/task/overlay/apply.sh new file mode 100644 index 0000000..8dc3638 --- /dev/null +++ b/docker/image/console/root/lib/task/overlay/apply.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +function task_overlay_apply() +{ + run "rsync --exclude='*.twig' --exclude='_twig' -a /home/build/application/overlay/ /app/" +} diff --git a/docker/image/console/root/lib/task/skeleton/apply.sh b/docker/image/console/root/lib/task/skeleton/apply.sh new file mode 100644 index 0000000..c256f9e --- /dev/null +++ b/docker/image/console/root/lib/task/skeleton/apply.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +function task_skeleton_apply() +{ + run "rsync --exclude='*.twig' --exclude='_twig' -a /home/build/application/skeleton/ /app/" +} diff --git a/docker/image/console/root/lib/task/state.sh b/docker/image/console/root/lib/task/state.sh new file mode 100644 index 0000000..bdd6b68 --- /dev/null +++ b/docker/image/console/root/lib/task/state.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +function task_state() +{ + task "database:available" + + echo "Ready!" +} diff --git a/docker/image/console/root/lib/task/welcome.sh b/docker/image/console/root/lib/task/welcome.sh new file mode 100644 index 0000000..17e3188 --- /dev/null +++ b/docker/image/console/root/lib/task/welcome.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +function task_welcome() +{ + echo "" + echo "Welcome!" + echo "--------" + echo "URL: https://${APP_HOST}" + echo "Admin: /admin" + echo " Username: admin" + echo " Password: admin123" + echo "" +} diff --git a/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig new file mode 100644 index 0000000..858a33a --- /dev/null +++ b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig @@ -0,0 +1,8 @@ +{% set xdebug = @('php.ext-xdebug') %} + +{% if xdebug.cli.enable == 'yes' %} + zend_extension=xdebug.so + {% for key, value in xdebug.config -%} + xdebug.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/console/root/usr/local/etc/php/php.ini.twig b/docker/image/console/root/usr/local/etc/php/php.ini.twig new file mode 100644 index 0000000..b76369c --- /dev/null +++ b/docker/image/console/root/usr/local/etc/php/php.ini.twig @@ -0,0 +1,10 @@ +{% for name, value in @('php.ini') %} +{{ name }} = {{ value }} +{% endfor %} +{% for name, value in @('php.cli.ini') %} +{{ name }} = {{ value }} +{% endfor %} + +; UTC for consistent logging that doesn't vary for Daylight Savings +; If you need to change it, configure your application to display dates offset from UTC. +date.timezone = UTC diff --git a/docker/image/cron/Dockerfile.twig b/docker/image/cron/Dockerfile.twig new file mode 100644 index 0000000..4a58ebe --- /dev/null +++ b/docker/image/cron/Dockerfile.twig @@ -0,0 +1,29 @@ +{% if @('app.build') == 'static' %} +FROM {{ @('docker.repository') ~ ':' ~ @('app.version') }}-php-fpm +{% else %} +FROM {{ @('workspace.name') ~ '-php-fpm:dev' }} +{% endif %} + +# install cron +RUN apt update +RUN apt install -y cron sudo + +WORKDIR /app +COPY .my127ws/docker/image/cron/root / +RUN chmod +x /cron-run-with-env.sh + +{% if @('app.build') == 'static' %} +RUN bash /fix_app_permissions.sh +{% else %} +VOLUME /app +{% endif %} +ENV APP_MODE {{ @('app.mode') }} + +{% if @('app.build') == 'static' %} +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["sleep", "infinity"] +{% else %} +ENTRYPOINT ["/entrypoint.dynamic.sh"] +CMD ["sleep", "infinity"] +{% endif %} diff --git a/docker/image/cron/root/cron-run-with-env.sh b/docker/image/cron/root/cron-run-with-env.sh new file mode 100755 index 0000000..f3af2db --- /dev/null +++ b/docker/image/cron/root/cron-run-with-env.sh @@ -0,0 +1,5 @@ +#!/bin/bash +script_args="$*" +IFS=$'\n' +env_vars="$(cat /app/env.sh)" +/usr/bin/env - "$env_vars" su -s /bin/bash -p -c "$script_args" www-data > /proc/1/fd/1 2> /proc/1/fd/2 diff --git a/docker/image/cron/root/crontab.twig b/docker/image/cron/root/crontab.twig new file mode 100644 index 0000000..71a84dc --- /dev/null +++ b/docker/image/cron/root/crontab.twig @@ -0,0 +1,3 @@ +{% for cronjob in @('backend.cron.jobs') -%} +{{ cronjob|raw }} +{% endfor %} \ No newline at end of file diff --git a/docker/image/cron/root/entrypoint.sh b/docker/image/cron/root/entrypoint.sh new file mode 100644 index 0000000..82a7630 --- /dev/null +++ b/docker/image/cron/root/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# this is used to load env vars in crontab commands +env > /app/env.sh + +# run +crontab /crontab +exec cron -f -L 15 \ No newline at end of file diff --git a/docker/image/nginx/Dockerfile.twig b/docker/image/nginx/Dockerfile.twig new file mode 100644 index 0000000..de93565 --- /dev/null +++ b/docker/image/nginx/Dockerfile.twig @@ -0,0 +1,17 @@ +{% if @('app.build') == 'static' %} +FROM {{ @('docker.repository') ~ ':' ~ @('app.version') }}-console as console +{% endif %} + +FROM nginx:1.17-alpine +COPY root / + +{% if @('app.build') == 'static' %} +{% for copy_directory in @('nginx.copy_directories') %} +COPY --from=console {{ copy_directory }} {{ copy_directory }} +{% endfor %} +{% else %} +VOLUME /app +{% endif %} + +ENTRYPOINT ["sh", "/docker-entrypoint.d/config_render.sh"] +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker/image/nginx/root/docker-entrypoint.d/config_render.sh.twig b/docker/image/nginx/root/docker-entrypoint.d/config_render.sh.twig new file mode 100644 index 0000000..e45dd61 --- /dev/null +++ b/docker/image/nginx/root/docker-entrypoint.d/config_render.sh.twig @@ -0,0 +1,14 @@ +#!/bin/sh + +function render_configuration() +{ + local vars='$FPM_HOST' + + for file in /etc/nginx/conf.d/*.template; do + envsubst "$vars" < $file > ${file%.template}; + done +} + +render_configuration + +exec "$@" diff --git a/docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig b/docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig new file mode 100644 index 0000000..c9efff8 --- /dev/null +++ b/docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig @@ -0,0 +1,3 @@ +{% for name, value in @('nginx.global.conf') %} + {{ name }} {{ value }}; +{% endfor %} diff --git a/docker/image/nginx/root/etc/nginx/snippets/certificate.conf b/docker/image/nginx/root/etc/nginx/snippets/certificate.conf new file mode 100644 index 0000000..80e7be3 --- /dev/null +++ b/docker/image/nginx/root/etc/nginx/snippets/certificate.conf @@ -0,0 +1,2 @@ +ssl_certificate /etc/ssl/certs/app.crt; +ssl_certificate_key /etc/ssl/private/app.key; diff --git a/docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf b/docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf new file mode 100644 index 0000000..9b37b60 --- /dev/null +++ b/docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf @@ -0,0 +1,17 @@ +# from https://cipherli.st/ +# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + +ssl_protocols TLSv1.1 TLSv1.2; +ssl_prefer_server_ciphers on; +ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; +ssl_ecdh_curve secp384r1; +ssl_session_cache shared:SSL:10m; +ssl_session_tickets off; +ssl_stapling on; +ssl_stapling_verify on; + +resolver 1.1.1.1 8.8.8.8 valid=300s; +resolver_timeout 5s; + +add_header Strict-Transport-Security "max-age=63072000; includeSubdomains"; +add_header X-Content-Type-Options nosniff; diff --git a/docker/image/nginx/root/etc/ssl/certs/app.crt.twig b/docker/image/nginx/root/etc/ssl/certs/app.crt.twig new file mode 100644 index 0000000..0d94581 --- /dev/null +++ b/docker/image/nginx/root/etc/ssl/certs/app.crt.twig @@ -0,0 +1 @@ +{{ @('tls.crt') }} \ No newline at end of file diff --git a/docker/image/nginx/root/etc/ssl/private/app.key.twig b/docker/image/nginx/root/etc/ssl/private/app.key.twig new file mode 100644 index 0000000..6bb8bcb --- /dev/null +++ b/docker/image/nginx/root/etc/ssl/private/app.key.twig @@ -0,0 +1 @@ +{{ @('tls.key') }} \ No newline at end of file diff --git a/docker/image/php-fpm/.dockerignore b/docker/image/php-fpm/.dockerignore new file mode 100644 index 0000000..cf49d54 --- /dev/null +++ b/docker/image/php-fpm/.dockerignore @@ -0,0 +1 @@ +**/*.twig diff --git a/docker/image/php-fpm/Dockerfile.twig b/docker/image/php-fpm/Dockerfile.twig new file mode 100644 index 0000000..2735053 --- /dev/null +++ b/docker/image/php-fpm/Dockerfile.twig @@ -0,0 +1,24 @@ +{% if @('app.build') == 'static' %} +FROM {{ @('docker.repository') ~ ':' ~ @('app.version') }}-console as console +{% endif %} + +FROM {{ @('docker.image.php-fpm') }} +WORKDIR /app +COPY root / + +{% if @('app.build') == 'static' %} +COPY --from=console --chown=root:root /app /app +RUN bash /fix_app_permissions.sh +{% else %} +VOLUME /app +{% endif %} +ENV APP_MODE {{ @('app.mode') }} + +{% if @('app.build') == 'static' %} +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["sleep", "infinity"] +{% else %} +ENTRYPOINT ["/entrypoint.dynamic.sh"] +CMD ["sleep", "infinity"] +{% endif %} diff --git a/docker/image/php-fpm/root/app/.gitkeep b/docker/image/php-fpm/root/app/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker/image/php-fpm/root/entrypoint.dynamic.sh b/docker/image/php-fpm/root/entrypoint.dynamic.sh new file mode 100755 index 0000000..06d8b0d --- /dev/null +++ b/docker/image/php-fpm/root/entrypoint.dynamic.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +main() +{ + source /entrypoint.sh +} + +setup_app_networking() +{ + # make linux consistent with docker-for-mac + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + DOCKER_INTERNAL_HOST="host.docker.internal" + if ! grep $DOCKER_INTERNAL_HOST /etc/hosts > /dev/null ; then + DOCKER_INTERNAL_IP=$(/sbin/ip route|awk '/default/ { print $3 }') + echo -e "$DOCKER_INTERNAL_IP $DOCKER_INTERNAL_HOST" | tee -a /etc/hosts > /dev/null + fi + fi +} + +setup_app_volume_permissions() +{ + case "$STRATEGY" in + "host-linux-normal") + usermod -u "$(stat -c '%u' /app)" www-data + groupmod -g "$(stat -c '%g' /app)" www-data + ;; + "host-osx-normal") + usermod -u 1000 www-data + groupmod -g 1000 www-data + ;; + "host-osx-dockersync") + usermod -u 1000 www-data + groupmod -g 1000 www-data + ;; + *) + exit 1 + esac +} + +resolve_volume_mount_strategy() +{ + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + STRATEGY="host-linux-normal" + elif [ "${HOST_OS_FAMILY}" = "darwin" ]; then + if (mount | grep "/app type fuse.osxfs") > /dev/null 2>&1; then + STRATEGY="host-osx-normal" + elif (mount | grep "/app type ext4") > /dev/null 2>&1; then + STRATEGY="host-osx-dockersync" + elif (mount | grep "/app type btrfs") > /dev/null 2>&1; then + STRATEGY="host-linux-normal" + else + exit 1 + fi + else + exit 1 + fi +} + +bootstrap() +{ + resolve_volume_mount_strategy + setup_app_volume_permissions + setup_app_networking +} + +bootstrap +main diff --git a/docker/image/php-fpm/root/entrypoint.sh.twig b/docker/image/php-fpm/root/entrypoint.sh.twig new file mode 100755 index 0000000..b6dc51e --- /dev/null +++ b/docker/image/php-fpm/root/entrypoint.sh.twig @@ -0,0 +1,16 @@ +#!/bin/bash + +run_steps() +{ + echo "pm.status_path = /status" >> /usr/local/etc/php-fpm.d/www.conf + + # run any command required to be executed at docker startup + {% for step in @('php-fpm.entrypoint.steps') -%} + {{ step|raw }} + {% endfor %} +} + +run_steps + +# run +exec supervisord -c /etc/supervisor/supervisord.conf -n diff --git a/docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf b/docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf new file mode 100644 index 0000000..a96f50e --- /dev/null +++ b/docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf @@ -0,0 +1,9 @@ +[program:php-fpm] +command=docker-php-entrypoint php-fpm +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +user = root +autostart = %(ENV_AUTOSTART_PHP_FPM)s +autorestart = true diff --git a/docker/image/php-fpm/root/etc/supervisor/supervisord.conf b/docker/image/php-fpm/root/etc/supervisor/supervisord.conf new file mode 100644 index 0000000..6cfe17a --- /dev/null +++ b/docker/image/php-fpm/root/etc/supervisor/supervisord.conf @@ -0,0 +1,18 @@ +[supervisord] +nodaemon = true +logfile=/dev/stdout +logfile_maxbytes=0 +pidfile = /var/run/supervisord.pid + +[include] +files = /etc/supervisor/conf.d/*.conf + +[supervisorctl] +serverurl = unix:///var/run/supervisor.sock + +[unix_http_server] +file = /var/run/supervisor.sock +chmod = 0700 + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface diff --git a/docker/image/php-fpm/root/fix_app_permissions.sh.twig b/docker/image/php-fpm/root/fix_app_permissions.sh.twig new file mode 100755 index 0000000..c211659 --- /dev/null +++ b/docker/image/php-fpm/root/fix_app_permissions.sh.twig @@ -0,0 +1,55 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + + +main() +{ + app_permissions_fix +} + + +function app_permissions_fix() +{ + local APP_OWNER="{{ @('app.web_owner') }}" + local APP_GROUP="{{ @('app.web_group') }}" + DIRS=("{{ @('app.web_writable_dirs') | join('" "') | raw }}") + FILES=("{{ @('app.web_writable_files') | join('" "') | raw }}") + + for DIR in "${DIRS[@]}" + do + if [ -n "${DIR}" ]; then + if [ ! -d "${DIR}" ]; then + echo "${DIR} does not exist. Creating ${DIR}..." + mkdir -p "${DIR}" + fi + chown -R "${APP_OWNER}":"${APP_GROUP}" "${DIR}" + chmod -R ug+rw,o-w "${DIR}" + chmod -R a+r "${DIR}" + echo "fixed permissions for ${DIR}" + else + echo "No directory was specified for permissions fixing." + fi + done + + for FILE in "${FILES[@]}" + do + if [ -n "${FILE}" ]; then + if [ ! -f "${FILE}" ]; then + echo "${FILE} does not exist. Creating ${FILE}..." + touch "${FILE}" + fi + chown "${APP_OWNER}":"${APP_GROUP}" "${FILE}" + chmod ug+rw,o-w "${FILE}" + chmod a+r "${FILE}" + echo "fixed permissions for ${FILE}" + else + echo "No file was specified for permissions fixing." + fi + done + +} + +main diff --git a/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig new file mode 100644 index 0000000..1c319da --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig @@ -0,0 +1,8 @@ +{% set xdebug = @('php.ext-xdebug') %} + +{% if xdebug.enable == 'yes' %} + zend_extension=xdebug.so + {% for key, value in xdebug.config -%} + xdebug.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig b/docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig new file mode 100644 index 0000000..90f4ad6 --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig @@ -0,0 +1,10 @@ +{% for name, value in @('php.ini') %} +{{ name }} = {{ value }} +{% endfor %} +{% for name, value in @('php.fpm.ini') %} +{{ name }} = {{ value }} +{% endfor %} + +; UTC for consistent logging that doesn't vary for Daylight Savings +; If you need to change it, configure your application to display dates offset from UTC. +date.timezone = UTC diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/harness/attributes/common.yml b/harness/attributes/common.yml new file mode 100644 index 0000000..e1ed785 --- /dev/null +++ b/harness/attributes/common.yml @@ -0,0 +1,267 @@ + + +attributes.default: + + app: + # build - static|dynamic + # dynamic - volumes are mounted and the build step is run once the containers have started + # static - app is copied into console, built, then the resulting build is copied into the web image + build: dynamic + + # mode - development|production + # development - additional tooling is made available and application is run in development mode + # production - leaner images with less tooling and application is run in production mode + mode: development + + services: [mysql] + web_owner: www-data + web_group: www-data + web_writable_dirs: [] + web_writable_files: [] + + web_directory: /app/public + vendor_directory: /app/vendor + + docker-sync: yes + mutagen: no + + jenkins: + credentials: + my127ws_key: = @('workspace.name') ~ '-my127ws-key' + + pipeline: + base: + persistence: = @('persistence') + resourcePrefix: ~ + hostname: = @('pipeline.preview.hostname') + publish: + enabled: no + # when enabled the application helm chart will be published + # to the given git repository. + chart: + enabled: no + git: + # private key with write access to the repository + key: ~ + # eg. git@github.com:organisation/project.git + repository: ~ + # path within the repository to place the chart, no leading or trailing slashes + # note: an additional directory with the branch name will be created + path: = 'build-artifacts/' ~ @('workspace.name') + # sets the git user.email before pushing the commit + email: name@example.com + preview: + enabled: no + environment: ~ + cluster: + name: null + namespace: = @('workspace.name') ~ '-' ~ slugify(branch()) + hostname: = @('pipeline.preview.namespace') ~ '.example.com' + qa: + enabled: no + environment: ~ + branch: develop + cluster: + name: null + namespace: = @('workspace.name') ~ '-' ~ 'qa' + hostname: = @('pipeline.qa.namespace') ~ '.example.com' + resourcePrefix: ~ + persistence: ~ + + docker: + repository: = @("workspace.name") + compose: + file_version: '3' + config: null + image: + console: = 'my127/php:' ~ @('php.version') ~ '-fpm-stretch-console' + php-fpm: = 'my127/php:' ~ @('php.version') ~ '-fpm-stretch' + + composer: + auth: + basic: ~ + github: ~ + + backend: + path: /app + build: + when: -f "composer.json" + steps: + - task "composer:install" + install: + steps: [] + init: + steps: [] + migrate: + steps: [] + cron: + jobs: [] + + frontend: + path: /app + watch: npm watch + build: + when: -f "package.json" + steps: + - run "npm install" + + git: + main_branch: develop + + nginx: + # used to set site specific configurations under server directive + site: + conf: [] + # used to set nginx global configurations under http directive + global: + conf: [] + # used to limit what is copied into an Nginx static-built image + # vendor directory needed for vendor/*/*/*/public/ resources (images etc.) + copy_directories: + - = @('app.web_directory') + - = @('app.vendor_directory') + + node: + # only set this attribute if you wish to override the supplied node version, by default + # the supplied version will be the current LTS. + version: null + + php: + version: 7.3 + cli: + ini: + memory_limit: -1 + fpm: + ini: + memory_limit: 1024M + ini: ~ + ext-xdebug: + enable: no + cli: + enable: no + config: + remote_enable: 1 + remote_autostart: 1 + remote_port: 9000 + remote_host: host.docker.internal + + assets: + remote: ="s3://"~@("aws.bucket")~"/development" + local: tools/assets/development + + database: + # possible platforms are mysql, postgres or ~ for none + platform: mysql + host: mysql + user: app + pass: app + name: app + root_pass: DV6RdNY3QcFsBk7V + var: + max_allowed_packet: 4M + import: + steps: [] + + elasticsearch: + image: elasticsearch + tag: 7.1.1 + + domain: my127.site + hostname: = @('namespace') ~ '.' ~ @('domain') + + helm: + timeout: 300 + + php-fpm: + entrypoint: + steps: [] + + resources: + cpu: + requests: [] + limits: [] + memory: + app_init: "1024Mi" + app_migrate: "1024Mi" + console: "2048Mi" + cron: "1024Mi" + elasticsearch: "1024Mi" + mysql: "512Mi" + nginx: "100Mi" + php_fpm: "1024Mi" + php_fpm_exporter: "100Mi" + postgres: "512Mi" + redis: "256Mi" + redis_session: "1024Mi" + + persistence: + enabled: false + mountVolumesOnConsole: true # possible to disable, but may lead to unexpected concequences with app init/migrate + + elasticsearch: + enabled: true + accessMode: ReadWriteOnce + size: 2Gi + mysql: + enabled: true + accessMode: ReadWriteOnce + size: 4Gi + postgres: + enabled: true + accessMode: ReadWriteOnce + size: 4Gi + redis: + enabled: false + accessMode: ReadWriteOnce + size: 2Gi + + tls: + key: | + -----BEGIN PRIVATE KEY----- + MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC9q3EMGDtDNKAt + CHyM1MfWUaIGsv5Zka7pfjIOKL/KvrSIVpZyyJ3lSALeRyyDDRZeYwkbkNdDJgir + FmD0vJkYifYWfGdIJmbjdm62LGyzDf79Ve8aQF0lLcedMhoCfu7+qciIYnjHdvkx + Y6Fo9CTZP7m+oSNmUjHdJD3scX4l3vodBK67Hpk+W2eEhwAxG5aFsspDnPi4L9ha + KlMps+eSn1hLLGYrmthtP2assckvdyL10hS7+OOZFmj5vxGNbQn2F4whiu06JmXL + oO8T9yd8XNN383FjREYKjrQcyJo3izvawEgrRi9mNKM9DhWuBdbYNe/cSgGfwBK6 + Kc9e8zCLAgMBAAECggEAVL6fOgoxoGuJDdX24G3KBCZhQKEFKDwBbO4nq0/lsc7X + lvspKYwdkG5Gac5fQwa78dxKG3jx1VzPDrJnC7KgrOgnfhCDjScrXYJzIQ5kWvRr + 9AFLXe1YMN5ti/zwxiC05DA0G0v0LxsnaDvdyKkdNbxVX6lbycH76ZTh3h0vgfeD + Wc8MMlRTa+ORWKoIZsm+qnNLhWQhhbmoA8LNkZqtJIOBZuyAu8vyXzrEFIhKqVzU + Jdz0S+xtgYUkoXCTgdYiqoFjlKhaIIV2Fc0vbc68ziIiu3ZtaVch7wNyftoXyjBr + hjI1GT1dr7NsQpPZ6xtqjGhIvUuVSeCSBZeeXkymAQKBgQDsxFb916gIxl3QQYPV + NiKPi3rZD5iuMTjy0937dhHWGGYlWW2GEE0XjWrmLUnGyLuxwA5kFgS0eMubbhTg + aeewHamHeN/pcJIF6HndJbqXLB148E8ux6grpQrHKpTb2RLOPkd6bAgn1SjPllCL + a/vVanevaJs8U27sKEfGND0aCwKBgQDNE7IzvD1JAUrzqzG9Lxg+NhaHQTQfW45W + cuHvESiyhc93kdufvcCTrrRRXSZOqDN26+64Ni62O/ulduq4qZmhG/lxqSz5mnpr + 2oV2Kg1C1EUC4V2B9WQoMOhvOa0esTVSm9hC4oX0kYIzl6HbVAUGe8JMXOoKTJkV + 3sAz0FbTgQKBgQC1CX+2wvIiG4NaHO4v1h/hAHajiDBnaQ2xZtzCTMpgmPFpt5Ju + QwKfcqt9ar2RuKUDyeV3E/ru/7o3k5l06qWUXWnmQz96oG+XAuZDeXjN5JZ4hc8V + 5uYo0R6HoYCHBdlCSA6hhf9Kbcuxxq65nIzH54uyXNrt6qHTAw22ePULdwKBgQCK + vp+a1ukToldGQfV1zA330Pou6dNMv9Gt9S2cY5yII3W4rKrNCUDn6ZO/VGkdYDjp + ZTft02KJEk3vpWOqKbxxvo5l8pImEPhwTbhruImeRCSojTaJPS9U7bnjvj68/CFa + UWvf3IfKbkOLijQMQmzf9Q0AQwBolWgg3sJki7iigQKBgQCf82eve3W/s/pZzKGi + WWACcZLmDTHeH2AU3ZDfFaEAKObe/cdHMgk8MGewf1IF6QDQXtaxHlM5/FKQ1ohu + uoe7Xo1R+KlrVRxKAlNQ5lfzhAAgDNaOhpgkH4cehfPrIIh9rwNMSkHDRS0DELvY + DPyRumPy7zTg5YPzzl7tM1/OPA== + -----END PRIVATE KEY----- + + crt: | + -----BEGIN CERTIFICATE----- + MIIC6zCCAdOgAwIBAgIJAI4syJyPEWAMMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNV + BAMMASowHhcNMTgwNzI0MTE1MjQ0WhcNMTkwNzI0MTE1MjQ0WjAMMQowCAYDVQQD + DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvatxDBg7QzSgLQh8 + jNTH1lGiBrL+WZGu6X4yDii/yr60iFaWcsid5UgC3kcsgw0WXmMJG5DXQyYIqxZg + 9LyZGIn2FnxnSCZm43Zutixssw3+/VXvGkBdJS3HnTIaAn7u/qnIiGJ4x3b5MWOh + aPQk2T+5vqEjZlIx3SQ97HF+Jd76HQSuux6ZPltnhIcAMRuWhbLKQ5z4uC/YWipT + KbPnkp9YSyxmK5rYbT9mrLHJL3ci9dIUu/jjmRZo+b8RjW0J9heMIYrtOiZly6Dv + E/cnfFzTd/NxY0RGCo60HMiaN4s72sBIK0YvZjSjPQ4VrgXW2DXv3EoBn8ASuinP + XvMwiwIDAQABo1AwTjAdBgNVHQ4EFgQUK4SXDSeyVYbCWr31rz2K6GLRFoYwHwYD + VR0jBBgwFoAUK4SXDSeyVYbCWr31rz2K6GLRFoYwDAYDVR0TBAUwAwEB/zANBgkq + hkiG9w0BAQUFAAOCAQEAjz2PUbdi2S+h4UB3P2UBLdgDClkiSPF+gAqfw4D82faf + M8hpMuCcd3148dejU4tFPUdLx1MASK8ucCk7rcwVtafWPYU4nMDlmZ9Zj9F2Y8KY + dVfHfTIOblTSYc90g+nTFsTchkEFOH0nRZAKhCT3HphXNTZFNIQWoqe63SJZ8LTs + 8RBO/zcoh5E31+Rm0WxKlYH4QElLp9dXAtKueWGTafh2E8Re96IS+Uig+yC3RIYJ + MWLcATwR3lSnqN2ifByic5VGWbRKkGNsh3wAWlejL2FGv8mLU1q8nLK36UcU/HzZ + ziLtpidJOJHDpyDSAxDSxcP9fJ6gssMQln92DJ/SUQ== + -----END CERTIFICATE----- diff --git a/harness/attributes/docker-base.yml b/harness/attributes/docker-base.yml new file mode 100644 index 0000000..503ff0d --- /dev/null +++ b/harness/attributes/docker-base.yml @@ -0,0 +1,92 @@ +attributes: + services: + php-base: + environment: + HOST_OS_FAMILY: = @('host.os') + APP_NAME: = @('workspace.name') + APP_HOST: = @('hostname') + DB_PLATFORM: = @('database.platform') + DB_HOST: = @('database.host') + DB_USER: = @('database.user') + DB_PASS: = @('database.pass') + DB_NAME: = @('database.name') + PHP_IDE_CONFIG: "serverName=workspace" + nginx: + environment: + FPM_HOST: php-fpm + console: + enabled: true + environment: + DB_ADMIN_USER: root + DB_ADMIN_PASS: = @('database.root_pass') + php-fpm: + environment: + AUTOSTART_PHP_FPM: "true" + php-fpm-exporter: + environment: + PHP_FPM_SCRAPE_URI: tcp://php-fpm:9000/status + mysql: + environment: + MYSQL_DATABASE: = @('database.name') + MYSQL_PASSWORD: = @('database.pass') + MYSQL_ROOT_PASSWORD: = @('database.root_pass') + MYSQL_USER: = @('database.user') + postgres: + environment: + POSTGRES_DB: = @('database.name') + POSTGRES_PASSWORD: = @('database.pass') + POSTGRES_USER: = @('database.user') + PGDATA: /var/lib/postgresql/data/pgdata + cron: + environment: [] + pipeline: + base: + prometheus: + podMonitoring: false + services: + php-base: + environment: + ES_HOST: "{{ if .Values.service.elasticsearch }}{{ .Values.resourcePrefix }}elasticsearch:9200{{ end }}" + DB_HOST: = '{{ .Values.resourcePrefix }}' ~ @('database.host') + APP_HOST: = @('pipeline.base.hostname') + PHP_IDE_CONFIG: = '' + nginx: + environment: + FPM_HOST: localhost + metricsEnabled: false + metricsEndpoints: + - port: http + php-fpm-exporter: + environment: + PHP_FPM_SCRAPE_URI: tcp://127.0.0.1:9000/status + metricsEnabled: true + metricsEndpoints: + - port: php-fpm-metrics + istio: + gateways: + - "istio-system/{{ .Release.Namespace }}-gateway" + additionalGateways: [] + production: {} + qa: + services: + php-base: + environment: + APP_HOST: = @('pipeline.qa.hostname') + preview: + resources: + memory: + app_init: "1024Mi" + app_migrate: "1024Mi" + console: "1024Mi" + cron: "1024Mi" + elasticsearch: "1024Mi" + mysql: "512Mi" + nginx: "64Mi" + php_fpm: "1024Mi" + php_fpm_exporter: "32Mi" + postgres: "512Mi" + redis: "64Mi" + redis_session: "64Mi" + services: + console: + enabled: false diff --git a/harness/attributes/environment/local.yml b/harness/attributes/environment/local.yml new file mode 100644 index 0000000..41505a5 --- /dev/null +++ b/harness/attributes/environment/local.yml @@ -0,0 +1,6 @@ + +attributes: + app: + build: dynamic + mode: development + version: develop \ No newline at end of file diff --git a/harness/attributes/environment/pipeline.yml b/harness/attributes/environment/pipeline.yml new file mode 100644 index 0000000..cbec666 --- /dev/null +++ b/harness/attributes/environment/pipeline.yml @@ -0,0 +1,8 @@ + +attributes: + namespace: =exec("git log -n 1 --pretty=format:'%H'") + hostname: =@('workspace.name') ~ '.' ~ @('domain') + app: + build: static + version: =exec("git log -n 1 --pretty=format:'%H'") + mode: production diff --git a/harness/config/commands.yml b/harness/config/commands.yml new file mode 100644 index 0000000..c0c2ff1 --- /dev/null +++ b/harness/config/commands.yml @@ -0,0 +1,217 @@ + +command('enable'): + env: + USE_DOCKER_SYNC: = @('host.os') == 'darwin' and @('docker-sync') == 'yes' ? 'yes':'no' + USE_MUTAGEN: = @('host.os') == 'darwin' and @('mutagen') == 'yes' ? 'yes':'no' + APP_BUILD: = @('app.build') + APP_MODE: = @('app.mode') + NAMESPACE: = @('namespace') + HAS_ASSETS: = @('aws.bucket') !== null ? 'yes':'no' + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/enable.sh + +command('disable'): + env: + USE_DOCKER_SYNC: = (@('host.os') == 'darwin' and @('docker-sync') == 'yes') ? 'yes':'no' + USE_MUTAGEN: = @('host.os') == 'darwin' and @('mutagen') == 'yes' ? 'yes':'no' + NAMESPACE: = @('namespace') + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/disable.sh + +command('destroy'): + env: + NAMESPACE: = @('namespace') + APP_BUILD: = @('app.build') + APP_VERSION: = @('app.version') + DOCKER_REPOSITORY: = @('docker.repository') + USE_DOCKER_SYNC: = (@('host.os') == 'darwin' and @('docker-sync') == 'yes') ? 'yes':'no' + USE_MUTAGEN: = @('host.os') == 'darwin' and @('mutagen') == 'yes' ? 'yes':'no' + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + source .my127ws/harness/scripts/destroy.sh + +command('networks external'): + env: + NETWORKS: = get_docker_external_networks() + exec: | + #!bash(workspace:/) + for NETWORK in ${NETWORKS}; do + if ! docker network inspect "${NETWORK}" >/dev/null 2>&1; then + passthru docker network create "${NETWORK}" + fi + done + +command('exec %'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|= + if [ -t 1 ] ; then + docker-compose exec -u build console ={ input.argument('%') } + else + docker-compose exec -T -u build console ={ input.argument('%') } + fi + +command('logs %'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(harness:/)|= + docker-compose logs ={input.argument('%')} + +command('ps'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + docker-compose ps + +command('console'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru docker-compose exec -u build console bash + +command('db-console'): | + #!bash + ws db console + +command('db console'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru "docker-compose exec console bash -c 'mysql -h\"\$DB_HOST\" -u\"\$DB_USER\" -p\"\$DB_PASS\" \"\$DB_NAME\"'" + +command('assets download'): + env: + AWS_ID: =@('aws.id') + AWS_KEY: =@('aws.key') + exec: | + #!bash(workspace:/)|@ + passthru ws.aws s3 sync @('assets.remote') @('assets.local') + +command('assets upload'): + env: + AWS_ID: =@('aws.id') + AWS_KEY: =@('aws.key') + exec: | + #!bash(workspace:/)|@ + passthru ws.aws s3 sync @('assets.local') @('assets.remote') + +command('feature docker-sync (on|off)'): + env: + ATTR_KEY: 'docker-sync' + ATTR_VAL: = input.command(3) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating docker-compose.yml' + run ws install --step=prepare + echo 'Bringing up the environment with the new setting' + if [[ "$ATTR_VAL" = "yes" ]]; then + passthru ws docker-sync start + fi + passthru ws enable + if [[ "$ATTR_VAL" = "no" ]]; then + passthru ws docker-sync stop + passthru ws docker-sync clean + fi + echo 'Done' + +command('frontend build'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru "docker-compose exec -u build console bash -i -c 'app build:frontend'" + +command('frontend watch'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru "docker-compose exec -u build console bash -i -c 'cd @('frontend.path'); @('frontend.watch')'" + +command('frontend console'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru "docker-compose exec -u build console bash -i -c 'cd @('frontend.path'); bash'" + +command('port '): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|= + passthru docker port $(docker-compose ps -q ={input.argument('service')}) + +command('service php-fpm restart'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru ws install --step=prepare + passthru "docker-compose exec console bash -c 'cp -r /.my127ws/docker/image/console/root/usr/local/etc/php/conf.d/* /usr/local/etc/php/conf.d/'" + passthru "docker-compose exec php-fpm bash -c 'cp -r /.my127ws/docker/image/php-fpm/root/usr/local/etc/php/conf.d/* /usr/local/etc/php/conf.d/'" + passthru docker-compose exec php-fpm supervisorctl restart php-fpm + +command('set '): + env: + ATTR_KEY: = input.argument('attribute') + ATTR_VAL: = input.argument('value') + exec: | + #!bash(workspace:/)|= + if [ ! -f workspace.override.yml ]; then + touch workspace.override.yml + fi + if grep -q "attribute('${ATTR_KEY}'):" workspace.override.yml; then + echo "Removing old '${ATTR_KEY}' setting from workspace.override.yml" + sed "/^attribute('${ATTR_KEY}'): .*$/d" workspace.override.yml > workspace.override.yml.tmp && mv workspace.override.yml.tmp workspace.override.yml + fi + if grep -q "attribute('${ATTR_KEY}'):" workspace.override.yml; then + echo 'Could not remove line from workspace.override.yml, failing' + exit 1 + fi + echo "Setting '${ATTR_KEY}' setting to '${ATTR_VAL}' in workspace.override.yml" + echo "attribute('${ATTR_KEY}'): ${ATTR_VAL}" >> workspace.override.yml + +command('feature xdebug (on|off)'): + env: + ATTR_KEY: 'php.ext-xdebug.enable' + ATTR_VAL: = input.command(3) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up php-fpm with the new setting' + run ws service php-fpm restart + echo 'Done' + +command('feature xdebug cli (on|off)'): + env: + ATTR_KEY: 'php.ext-xdebug.cli.enable' + ATTR_VAL: = input.command(4) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up console with the new setting' + run ws service php-fpm restart + echo 'Done' + +command('db import '): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|= + passthru "docker-compose exec -u build console bash -i -c 'app database:import ={input.argument('database_file')}'" diff --git a/harness/config/docker-sync.yml b/harness/config/docker-sync.yml new file mode 100644 index 0000000..accbfab --- /dev/null +++ b/harness/config/docker-sync.yml @@ -0,0 +1,8 @@ +command('docker-sync (start|stop|clean)'): + env: + NAMESPACE: = @('namespace') + COMMAND: = input.command(2) + PATH: "$PATH:./.my127ws/" + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/docker_sync.sh "$COMMAND" diff --git a/harness/config/events.yml b/harness/config/events.yml new file mode 100644 index 0000000..6139a17 --- /dev/null +++ b/harness/config/events.yml @@ -0,0 +1,10 @@ + +after('harness.install'): | + #!bash + ws enable + +after('harness.refresh'): | + #!bash(harness:/)|@ + run docker-compose -p @('namespace') stop + run docker-compose -p @('namespace') pull + run docker-compose -p @('namespace') up -d --build diff --git a/harness/config/functions.yml b/harness/config/functions.yml new file mode 100644 index 0000000..d983d60 --- /dev/null +++ b/harness/config/functions.yml @@ -0,0 +1,69 @@ +function('to_yaml', [text]): | + #!php + = preg_replace('/^/m', ' ', \Symfony\Component\Yaml\Yaml::dump($text, 100, 2)); + +function('to_nice_yaml', [text, indentation, nesting]): | + #!php + = preg_replace('/^/m', str_repeat(' ', $nesting ?: 2), \Symfony\Component\Yaml\Yaml::dump($text, 100, $indentation ?: 2)); + +function('deep_merge_to_yaml', [arrays, indentation, nesting]): | + #!php + // source https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_array_merge_deep_array/7.x + $deepMerge = function ($arrays) use (&$deepMerge) { + $result = array(); + foreach ($arrays as $array) { + if ($array === null) { continue; } + foreach ($array as $key => $value) { + // Renumber integer keys as array_merge_recursive() does. Note that PHP + // automatically converts array keys that are integer strings (e.g., '1') + // to integers. + if (is_integer($key)) { + $result[] = $value; + } + elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) { + $result[$key] = $deepMerge(array( + $result[$key], + $value, + )); + } + else { + $result[$key] = $value; + } + } + } + return $result; + }; + $text = $deepMerge($arrays); + = preg_replace('/^/m', str_repeat(' ', $nesting ?: 2), \Symfony\Component\Yaml\Yaml::dump($text, 100, $indentation ?: 2)); + +function('get_docker_external_networks'): | + #!php + $configRaw = shell_exec('docker-compose config'); + $config = \Symfony\Component\Yaml\Yaml::parse($configRaw); + $externalNetworks = []; + if (isset($config['networks'])) { + foreach ($config['networks'] as $network) { + if (isset($network['external'])) { + if (is_array($network['external'])) { + $externalNetworks[] = $network['external']['name']; + } else if ($network['external'] === true) { + $externalNetworks[] = $network['name']; + } + } + } + } + = join(" ", $externalNetworks); + +function('branch'): | + #!bash(workspace:/) + =$(git branch | grep \* | cut -d ' ' -f2) + +function('slugify', [text]): | + #!php + $text = preg_replace('~[^\pL\d]+~u', '-', $text); + $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text); + $text = preg_replace('~[^-\w]+~', '', $text); + $text = trim($text, '-'); + $text = preg_replace('~-+~', '-', $text); + $text = strtolower($text); + = $text; diff --git a/harness/config/mutagen.yml b/harness/config/mutagen.yml new file mode 100644 index 0000000..9cf5327 --- /dev/null +++ b/harness/config/mutagen.yml @@ -0,0 +1,34 @@ +command('mutagen (start|stop|pause|resume)'): + env: + NAMESPACE: = @('namespace') + COMMAND: = input.command(2) + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/mutagen.sh "$COMMAND" + +command('switch (mutagen|docker-sync)'): + env: + SYNC: = input.command(2) + NAMESPACE: = @('namespace') + exec: | + #!bash(workspace:/)|= + run ws disable + if [[ "$SYNC" = "mutagen" ]]; then + ws set mutagen yes + ws set docker-sync no + else + ws set mutagen no + ws set docker-sync yes + fi + run ws harness prepare + echo 'Bringing up the environment with the new setting' + if [[ "$SYNC" = "mutagen" ]]; then + if command -v docker-sync >/dev/null 2>&1 && [ -f docker-sync.yml ]; then + passthru ws docker-sync clean + fi + passthru ws mutagen start + else + passthru ws mutagen stop + fi + passthru ws enable + echo 'Done' diff --git a/harness/config/pipeline.yml b/harness/config/pipeline.yml new file mode 100644 index 0000000..8f614a8 --- /dev/null +++ b/harness/config/pipeline.yml @@ -0,0 +1,94 @@ + +command('app build'): | + #!bash(workspace:/)|@ + ws app build console + ws app build php-fpm + ws app build nginx + +command('app build console'): | + #!bash(workspace:/)|@ + passthru docker build --pull -t @('docker.repository'):@('app.version')-console -f .my127ws/docker/image/console/Dockerfile . + +command('app build cron'): | + #!bash(workspace:/)|@ + passthru docker build -t @('docker.repository'):@('app.version')-cron -f .my127ws/docker/image/cron/Dockerfile . + +command('app build php-fpm'): | + #!bash(harness:/docker/image/php-fpm)|@ + passthru docker build -t @('docker.repository'):@('app.version')-php-fpm . + +command('app build nginx'): | + #!bash(harness:/docker/image/nginx)|@ + passthru docker build -t @('docker.repository'):@('app.version')-nginx . + +command('app publish'): | + #!bash(workspace:/)|@ + echo "@('docker.password')" | run docker login --username="@('docker.username')" --password-stdin @('docker.repository') + run docker push @('docker.repository'):@('app.version')-console + run docker push @('docker.repository'):@('app.version')-php-fpm + run docker push @('docker.repository'):@('app.version')-nginx + run docker logout @('docker.repository') + +command('app publish chart '): + env: + SSH_KEY: = @('pipeline.publish.chart.git.key') + REPOSITORY: = @('pipeline.publish.chart.git.repository') + ARTIFACTS: = "./build-artifacts-repository/" ~ @('pipeline.publish.chart.git.path') ~ "/" ~ input.argument('release') + MESSAGE: = input.argument('message') + USER_EMAIL: = @('pipeline.publish.chart.git.email') + exec: | + #!bash(workspace:/)|@ + + run rm -rf build-artifacts-repository + echo "${SSH_KEY}" | base64 -d > id_rsa + chmod 0600 id_rsa + + export GIT_SSH_COMMAND='ssh -i ./id_rsa -o "IdentitiesOnly yes" -F /dev/null -o StrictHostKeyChecking=no' + + run git clone $REPOSITORY ./build-artifacts-repository + run git -C ./build-artifacts-repository config user.email \"${USER_EMAIL}\" + + run mkdir -p $ARTIFACTS + run rsync --exclude='*.twig' --exclude='_twig' --delete -a .my127ws/helm/app/ ${ARTIFACTS}/ + + export GIT_SSH_COMMAND='ssh -i ../id_rsa -o "IdentitiesOnly yes" -F /dev/null -o StrictHostKeyChecking=no' + run git -C ./build-artifacts-repository add . + run git -C ./build-artifacts-repository commit --allow-empty -m \"${MESSAGE}\" + run git -C ./build-artifacts-repository push origin master + +command('app deploy '): + env: + ENVIRONMENT: = input.argument('environment') + NAMESPACE: = @('pipeline.' ~ input.argument('environment') ~ '.namespace') + CLUSTER: = @('pipeline.' ~ input.argument('environment') ~ '.cluster.name') + TIMEOUT: = @('helm.timeout') + exec: | + #!bash(harness:/helm)|= + cd "${ENVIRONMENT}" + doctl -t $DO_ACCESS_TOKEN kubernetes cluster kubeconfig show $CLUSTER > kubectl.config.yaml + passthru helm init --client-only + passthru helm dependency build + passthru helm --kubeconfig=$PWD/kubectl.config.yaml upgrade --wait --atomic --install --timeout "${TIMEOUT}" --namespace "${NAMESPACE}" "${NAMESPACE}" ./ + +command('helm template '): + env: + CHART_PATH: = input.argument('chart-path') + NAMESPACE: = @('pipeline.' ~ input.argument('environment') ~ '.namespace') + exec: | + #!bash(harness:/helm)|= + cd "${CHART_PATH}" + passthru helm init --client-only + passthru helm dependency build + passthru helm template . + +command('helm kubeval '): + env: + CHART_PATH: = input.argument('chart-path') + NAMESPACE: = @('pipeline.' ~ input.argument('environment') ~ '.namespace') + exec: | + #!bash(harness:/helm)|= + cd "${CHART_PATH}" + passthru helm init --client-only + passthru helm dependency build + passthru helm plugin install https://github.com/instrumenta/helm-kubeval || true + passthru helm kubeval . diff --git a/harness/scripts/destroy.sh b/harness/scripts/destroy.sh new file mode 100755 index 0000000..2d4672f --- /dev/null +++ b/harness/scripts/destroy.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +run docker-compose down --rmi local --volumes --remove-orphans + +if [[ "$USE_DOCKER_SYNC" = "yes" ]] && [ -f docker-sync.yml ]; then + run ws docker-sync clean + run docker volume rm "${NAMESPACE}-sync" +elif [[ "$USE_MUTAGEN" = "yes" ]]; then + run ws mutagen stop + run docker volume rm "${NAMESPACE}-sync" +fi + +if [[ "$APP_BUILD" = "static" ]]; then + run "docker images --filter=reference='${DOCKER_REPOSITORY}:${APP_VERSION}-*' -q | xargs --no-run-if-empty docker image rm --force" +fi + +run rm -f .my127ws/.flag-built diff --git a/harness/scripts/disable.sh b/harness/scripts/disable.sh new file mode 100755 index 0000000..632d029 --- /dev/null +++ b/harness/scripts/disable.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +if [[ "$USE_DOCKER_SYNC" = "yes" ]] && [ -f docker-sync.yml ]; then + run ws docker-sync stop +elif [[ "$USE_MUTAGEN" = "yes" ]]; then + run ws mutagen pause +fi + +run docker-compose stop diff --git a/harness/scripts/docker_sync.sh b/harness/scripts/docker_sync.sh new file mode 100644 index 0000000..2a0cb13 --- /dev/null +++ b/harness/scripts/docker_sync.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +if [ "$#" -ne 1 ]; then + echo "This script supports only one parameter" + exit 1 +fi + +COMMAND="$1" +PATH="$PATH:./.my127ws/utilities/rbenv/bin/" + +install_rbenv() +( + if command -v rbenv > /dev/null 2>&1; then + return 0 + fi + + if command -v sw_vers > /dev/null 2>&1 && sw_vers | grep -q Mac && command -v brew > /dev/null 2>&1; then + passthru brew install rbenv + else + mkdir -p .my127ws/utilities/ + if [ ! -d .my127ws/utilities/rbenv ]; then + git clone https://github.com/rbenv/rbenv.git .my127ws/utilities/rbenv + fi + mkdir -p "$(rbenv root)"/plugins + git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build + fi + + passthru rbenv install --skip-existing 2.7.0 + run rbenv local 2.7.0 + init_rbenv +) + +init_rbenv() +{ + eval "$(rbenv init -)" +} + +install_docker_sync() +( + if command -v docker-sync > /dev/null 2>&1; then + return 0 + fi + + install_rbenv + passthru gem install docker-sync --no-document +) + +start() +{ + install_docker_sync + init_rbenv + passthru docker-sync start +} + +stop() +{ + init_rbenv + passthru docker-sync stop +} + +clean() +{ + init_rbenv + run docker-sync stop + run docker rm "${NAMESPACE}-sync" +} + +case "$COMMAND" in + start) + start + ;; + stop) + stop + ;; + clean) + clean + ;; + *) + echo "Command not supported" + exit 1 + ;; +esac diff --git a/harness/scripts/enable.sh.twig b/harness/scripts/enable.sh.twig new file mode 100755 index 0000000..c1fd691 --- /dev/null +++ b/harness/scripts/enable.sh.twig @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +main() +{ + passthru ws networks external + if [ ! -f .my127ws/.flag-built ]; then + + passthru docker-compose down + + if [[ "$HAS_ASSETS" = "yes" ]]; then + ws assets download + fi + + $APP_BUILD + touch .my127ws/.flag-built + + else + passthru docker-compose up -d + passthru docker-compose exec -T -u build console app welcome + fi + + if [[ "$APP_BUILD" = "dynamic" && "$USE_DOCKER_SYNC" = "yes" ]]; then + passthru ws docker-sync start + elif [[ "$APP_BUILD" = "dynamic" && "$USE_MUTAGEN" = "yes" ]]; then + passthru ws mutagen resume + fi +} + +dynamic() +{ + # we synchronise then stop docker-sync as leaving it running during the build + # will often cause it to crash. + + if [[ "$USE_DOCKER_SYNC" = "yes" ]]; then + passthru ws docker-sync start + passthru ws docker-sync stop + elif [[ "$USE_MUTAGEN" = "yes" ]]; then + passthru ws mutagen start + passthru ws mutagen pause + fi + + {% if ("cron" in @('app.services')) %} + passthru "docker-compose config --services | grep -v php-fpm | xargs docker-compose pull" + passthru "docker-compose config --services | grep -v cron | xargs docker-compose build --pull" + passthru docker-compose build cron + {% else %} + passthru docker-compose pull + passthru docker-compose build --pull + passthru docker-compose up -d + {% endif %} + + passthru docker-compose exec -T -u build console app build + passthru docker-compose exec -T -u build console app init +} + +static() +{ + ws app build + + passthru docker-compose up -d + passthru docker-compose exec -T -u build console app init +} + +main diff --git a/harness/scripts/latest-mutagen-release.php b/harness/scripts/latest-mutagen-release.php new file mode 100644 index 0000000..b5ace9c --- /dev/null +++ b/harness/scripts/latest-mutagen-release.php @@ -0,0 +1,33 @@ + [ + 'header' => "User-Agent: inviqa/harness-base-php\r\n", + ], +]); +$releases = file_get_contents('https://api.github.com/repos/mutagen-io/mutagen/releases', false, $fetchOptions); +if (!$releases) { + throw new Exception('Could not fetch releases. Response from GitHub: ' . $releases); +} + +$jsonReleases = json_decode($releases, true); +if (!$jsonReleases) { + throw new Exception('Could not decode releases. Response from GitHub: ' . $releases); +} + +$stableReleases = array_filter($jsonReleases, function ($release) { + return !$release['prerelease'] && !$release['draft']; +}); +$latestStableRelease = reset($stableReleases); +if (!$latestStableRelease) { + throw new Exception('Could not find latest stable release.'); +} + +$osFamily = strtolower(PHP_OS_FAMILY); +$releaseAssets = array_filter($latestStableRelease['assets'], function ($asset) use ($osFamily) { + return preg_match("/^mutagen_.*${osFamily}.*amd64.*/", $asset['name']) > 0; +}); +$releaseAsset = reset($releaseAssets); +if (!$releaseAsset) { + throw new Exception('Could not find latest stable release asset for your OS Platform: ' . $osFamily); +} +echo $releaseAsset['browser_download_url']; diff --git a/harness/scripts/mutagen.sh b/harness/scripts/mutagen.sh new file mode 100644 index 0000000..017d5d5 --- /dev/null +++ b/harness/scripts/mutagen.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +if [ "$#" -ne 1 ]; then + echo "This script supports only one parameter" + exit 1 +fi + +COMMAND="$1" +PATH="$PATH:./.my127ws/utilities/mutagen/" + +install_mutagen() +{ + if command -v mutagen > /dev/null 2>&1; then + return 0 + fi + + if command -v sw_vers > /dev/null 2>&1 && sw_vers | grep -q Mac && command -v brew > /dev/null 2>&1; then + passthru brew install mutagen-io/mutagen/mutagen + return "$?" + fi + mkdir -p .my127ws/utilities/mutagen/ + local download_url="" + download_url="$(php .my127ws/harness/scripts/latest-mutagen-release.php)" + if [ -z "$download_url" ]; then + echo "Failed to get mutagen download link. Please install mutagen globally." + return 1 + fi + + run curl -L -q -sS -f "$download_url" -o .my127ws/utilities/mutagen/mutagen.tar.gz + run "cd .my127ws/utilities/mutagen/ && tar -xf mutagen.tar.gz" +} + +setup_sync_container() +{ + if [[ "$(docker ps -a -f "name=${NAMESPACE}-sync" --format '{{.Names}}')" == "${NAMESPACE}-sync" ]]; then + passthru docker rm -f "${NAMESPACE}-sync" + fi + passthru docker run -d --name "${NAMESPACE}-sync" -v "${NAMESPACE}-sync":/app alpine:latest tail -f /dev/null +} + +start_mutagen_daemon() +{ + passthru mutagen daemon start +} + +start() +{ + install_mutagen + setup_sync_container + start_mutagen_daemon + + mutagen project list > /dev/null 2>&1 && passthru mutagen project terminate + passthru mutagen project start + passthru mutagen project flush +} + +stop() +{ + passthru mutagen project terminate + passthru docker rm -f "${NAMESPACE}-sync" +} + +pause() +{ + passthru mutagen project pause + passthru docker stop "${NAMESPACE}-sync" +} + +resume() +{ + start_mutagen_daemon + passthru docker start "${NAMESPACE}-sync" + passthru mutagen project resume +} + +case "$COMMAND" in + start) + start + ;; + stop) + stop + ;; + pause) + pause + ;; + resume) + resume + ;; + *) + echo "Command not supported" + exit 1 + ;; +esac diff --git a/helm/app/Chart.yaml.twig b/helm/app/Chart.yaml.twig new file mode 100644 index 0000000..ee356e3 --- /dev/null +++ b/helm/app/Chart.yaml.twig @@ -0,0 +1,5 @@ +name: {{ @('workspace.name') }} +description: Base helm chart for {{ @('workspace.name') }} +version: 0.0.1 +sources: +home: diff --git a/helm/app/_twig/values.yaml/environment.yml.twig b/helm/app/_twig/values.yaml/environment.yml.twig new file mode 100644 index 0000000..69bb373 --- /dev/null +++ b/helm/app/_twig/values.yaml/environment.yml.twig @@ -0,0 +1 @@ +# environment: is deprecated, this has moved to harness/attributes/docker*.yml diff --git a/helm/app/_twig/values.yaml/resources.yml.twig b/helm/app/_twig/values.yaml/resources.yml.twig new file mode 100644 index 0000000..572db8a --- /dev/null +++ b/helm/app/_twig/values.yaml/resources.yml.twig @@ -0,0 +1,16 @@ + cpu: + requests: + limits: + memory: + app_init: {{ @('resources.memory.app_init') }} + app_migrate: {{ @('resources.memory.app_migrate') }} + console: {{ @('resources.memory.console') }} + cron: {{ @('resources.memory.cron') }} + elasticsearch: {{ @('resources.memory.elasticsearch') }} + mysql: {{ @('resources.memory.mysql') }} + nginx: {{ @('resources.memory.nginx') }} + php_fpm: {{ @('resources.memory.php_fpm') }} + php_fpm_exporter: {{ @('resources.memory.php_fpm_exporter') }} + postgres: {{ @('resources.memory.postgres') }} + redis: {{ @('resources.memory.redis') }} + redis_session: {{ @('resources.memory.redis_session') }} diff --git a/helm/app/templates/_base_helper.tpl b/helm/app/templates/_base_helper.tpl new file mode 100644 index 0000000..176c4d0 --- /dev/null +++ b/helm/app/templates/_base_helper.tpl @@ -0,0 +1,20 @@ +{{- define "application.volumes.backend" }}{{ end }} +{{- define "application.volumeMounts.backend" }}{{ end }} + +{{- define "application.volumes.all" }}{{ end }} +{{- define "application.volumeMounts.all" }}{{ end }} + +{{- define "application.volumes.wwwDataPaths" }}{{ end }} + +{{- define "application.volumes.console" -}} +{{- if .Values.persistence.mountVolumesOnConsole -}} +{{- template "application.volumes.backend" . -}} +{{- template "application.volumes.all" . -}} +{{- end -}} +{{- end }} +{{- define "application.volumeMounts.console" -}} +{{- if .Values.persistence.mountVolumesOnConsole -}} +{{- template "application.volumeMounts.backend" . -}} +{{- template "application.volumeMounts.all" . -}} +{{- end -}} +{{- end }} diff --git a/helm/app/templates/application/app-init.yaml b/helm/app/templates/application/app-init.yaml new file mode 100644 index 0000000..a4b983a --- /dev/null +++ b/helm/app/templates/application/app-init.yaml @@ -0,0 +1,65 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Values.resourcePrefix }}app-init + annotations: + helm.sh/hook: "post-install" + helm.sh/hook-delete-policy: "before-hook-creation" + argocd.argoproj.io/hook: "Sync" + argocd.argoproj.io/hook-delete-policy: "BeforeHookCreation" + argocd.argoproj.io/sync-wave: "5" +spec: + template: + spec: + containers: + - env: + {{- range $key, $value := index .Values.docker.services "php-base" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.docker.services.console.environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + image: {{ .Values.docker.image.console }} + imagePullPolicy: Always + name: app-init +{{ if eq .Values.ingress "istio" }} + command: ["/bin/sh"] + args: ["-c", "app init ; code=$? ; curl -vv -XPOST http://127.0.0.1:15020/quitquitquit ; exit $code"] +{{ else }} + command: ["app", "init"] +{{ end }} + resources: + limits: + memory: {{ .Values.resources.memory.app_init }} + requests: + memory: {{ .Values.resources.memory.app_init }} + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.console" .)) }} + {{- include "application.volumeMounts.console" . | indent 8 }} + {{- else }} [] + {{- end }} + imagePullSecrets: + - name: {{ .Values.resourcePrefix }}docker-config + restartPolicy: Never + enableServiceLinks: false + volumes: + {{- if not (eq "" (include "application.volumes.console" .)) }} + {{- include "application.volumes.console" . | indent 6 }} + {{- else }} [] + {{- end }} diff --git a/helm/app/templates/application/app-migrate.yaml b/helm/app/templates/application/app-migrate.yaml new file mode 100644 index 0000000..c873665 --- /dev/null +++ b/helm/app/templates/application/app-migrate.yaml @@ -0,0 +1,65 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Values.resourcePrefix }}app-migrate + annotations: + helm.sh/hook: "pre-upgrade" + helm.sh/hook-delete-policy: "before-hook-creation" + argocd.argoproj.io/hook: "Sync" + argocd.argoproj.io/hook-delete-policy: "BeforeHookCreation" + argocd.argoproj.io/sync-wave: "10" +spec: + template: + spec: + containers: + - env: + {{- range $key, $value := index .Values.docker.services "php-base" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.docker.services.console.environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + image: {{ .Values.docker.image.console }} + imagePullPolicy: Always + name: app-migrate +{{ if eq .Values.ingress "istio" }} + command: ["/bin/sh"] + args: ["-c", "app migrate ; code=$? ; curl -vv -XPOST http://127.0.0.1:15020/quitquitquit ; exit $code"] +{{ else }} + command: ["app", "migrate"] +{{ end }} + resources: + limits: + memory: {{ .Values.resources.memory.app_migrate }} + requests: + memory: {{ .Values.resources.memory.app_migrate }} + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.console" .)) }} + {{- include "application.volumeMounts.console" . | indent 8 }} + {{- else }} [] + {{- end }} + imagePullSecrets: + - name: {{ .Values.resourcePrefix }}docker-config + restartPolicy: Never + enableServiceLinks: false + volumes: + {{- if not (eq "" (include "application.volumes.console" .)) }} + {{- include "application.volumes.console" . | indent 6 }} + {{- else }} [] + {{- end }} diff --git a/helm/app/templates/application/console/deployment.yaml b/helm/app/templates/application/console/deployment.yaml new file mode 100644 index 0000000..2d205fe --- /dev/null +++ b/helm/app/templates/application/console/deployment.yaml @@ -0,0 +1,75 @@ +{{ if .Values.docker.services.console.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}console + labels: + app.service: {{ .Values.resourcePrefix }}console + annotations: + argocd.argoproj.io/sync-wave: "15" +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}console + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}console + spec: + containers: + - env: + {{- range $key, $value := index .Values.docker.services "php-base" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.docker.services.console.environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + image: {{ .Values.docker.image.console }} + imagePullPolicy: Always + name: console + resources: + limits: + memory: {{ .Values.resources.memory.console }} + requests: + memory: {{ .Values.resources.memory.console }} + readinessProbe: + exec: + command: + - app + - state + initialDelaySeconds: 20 + periodSeconds: 10 + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.console" .)) }} + {{- include "application.volumeMounts.console" . | indent 8 }} + {{- else }} [] + {{- end }} + imagePullSecrets: + - name: {{ .Values.resourcePrefix }}docker-config + restartPolicy: Always + enableServiceLinks: false + volumes: + {{- if not (eq "" (include "application.volumes.console" .)) }} + {{- include "application.volumes.console" . | indent 6 }} + {{- else }} [] + {{- end }} +status: {} +{{ end }} diff --git a/helm/app/templates/application/cron/deployment.yaml b/helm/app/templates/application/cron/deployment.yaml new file mode 100644 index 0000000..4d9cab8 --- /dev/null +++ b/helm/app/templates/application/cron/deployment.yaml @@ -0,0 +1,87 @@ +{{ if .Values.service.cron }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}cron + labels: + app.service: {{ .Values.resourcePrefix }}cron + annotations: + argocd.argoproj.io/sync-wave: "15" +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}cron + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}cron + spec: + {{- if not (eq "" (include "application.volumes.wwwDataPaths" .)) }} + initContainers: + - name: cron-volume-permissions + image: busybox + command: + - "/bin/chown" + - "-R" + - "www-data" + {{- include "application.volumes.wwwDataPaths" . | indent 8 }} + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" .)) (eq "" (include "application.volumeMounts.all" .)) ) }} + {{- include "application.volumeMounts.backend" . | indent 8 }} + {{- include "application.volumeMounts.all" . | indent 8 }} + {{- else }} [] + {{- end }} + {{- end }} + containers: + - name: cron + env: + {{- range $key, $value := index .Values.docker.services "php-base" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := index .Values.docker.services "cron" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + image: {{ .Values.docker.image.cron }} + imagePullPolicy: Always + resources: + limits: + memory: {{ .Values.resources.memory.cron }} + requests: + memory: {{ .Values.resources.memory.cron }} + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" .)) (eq "" (include "application.volumeMounts.all" .)) ) }} + {{- include "application.volumeMounts.backend" . | indent 8 }} + {{- include "application.volumeMounts.all" . | indent 8 }} + {{- else }} [] + {{- end }} + + imagePullSecrets: + - name: {{ .Values.resourcePrefix }}docker-config + restartPolicy: Always + enableServiceLinks: false + volumes: + {{- if not (and (eq "" (include "application.volumes.backend" .)) (eq "" (include "application.volumes.all" .)) ) }} + {{- include "application.volumes.backend" . | indent 6 }} + {{- include "application.volumes.all" . | indent 6 }} + {{- else }} [] + {{- end }} +status: {} +{{ end }} diff --git a/helm/app/templates/application/docker-config.yaml b/helm/app/templates/application/docker-config.yaml new file mode 100644 index 0000000..6b3bc18 --- /dev/null +++ b/helm/app/templates/application/docker-config.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.resourcePrefix }}docker-config +data: + .dockerconfigjson: {{ .Values.docker.config }} +type: kubernetes.io/dockerconfigjson diff --git a/helm/app/templates/application/webapp/deployment.yaml b/helm/app/templates/application/webapp/deployment.yaml new file mode 100644 index 0000000..f6089f6 --- /dev/null +++ b/helm/app/templates/application/webapp/deployment.yaml @@ -0,0 +1,153 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}webapp + labels: + app.service: {{ .Values.resourcePrefix }}webapp + annotations: + argocd.argoproj.io/sync-wave: "15" +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}webapp + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}webapp + spec: + {{- if not (eq "" (include "application.volumes.wwwDataPaths" .)) }} + initContainers: + - name: webapp-volume-permissions + image: busybox + command: + - "/bin/chown" + - "-R" + - "www-data" + {{- include "application.volumes.wwwDataPaths" . | indent 8 }} + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" .)) (eq "" (include "application.volumeMounts.all" .)) ) }} + {{- include "application.volumeMounts.backend" . | indent 8 }} + {{- include "application.volumeMounts.all" . | indent 8 }} + {{- else }} [] + {{- end }} + {{- end }} + containers: + - name: nginx + env: + {{- range $key, $value := .Values.docker.services.nginx.environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + image: {{ .Values.docker.image.nginx }} + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + resources: + limits: + memory: {{ .Values.resources.memory.nginx }} + requests: + memory: {{ .Values.resources.memory.nginx }} + readinessProbe: + tcpSocket: + port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.all" .)) }} + {{- include "application.volumeMounts.all" . | indent 8 }} + {{- else }} [] + {{- end }} + + - name: php-fpm + env: + {{- range $key, $value := index .Values.docker.services "php-base" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := index .Values.docker.services "php-fpm" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + image: {{ .Values.docker.image.fpm }} + imagePullPolicy: Always + ports: + - containerPort: 9000 + resources: + limits: + memory: {{ .Values.resources.memory.php_fpm }} + requests: + memory: {{ .Values.resources.memory.php_fpm }} + readinessProbe: + tcpSocket: + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" .)) (eq "" (include "application.volumeMounts.all" .)) ) }} + {{- include "application.volumeMounts.backend" . | indent 8 }} + {{- include "application.volumeMounts.all" . | indent 8 }} + {{- else }} [] + {{- end }} + + {{ if .Values.service.php_fpm_exporter }} + - name: php-fpm-exporter + env: + {{- range $key, $value := index .Values.docker.services "php-fpm-exporter" "environment" }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + image: hipages/php-fpm_exporter + imagePullPolicy: Always + ports: + - name: php-fpm-metrics + containerPort: 9253 + resources: + limits: + memory: {{ .Values.resources.memory.php_fpm_exporter }} + requests: + memory: {{ .Values.resources.memory.php_fpm_exporter }} + readinessProbe: + tcpSocket: + port: 9253 + initialDelaySeconds: 5 + periodSeconds: 10 + {{ end }} + + imagePullSecrets: + - name: {{ .Values.resourcePrefix }}docker-config + restartPolicy: Always + enableServiceLinks: false + volumes: + {{- if not (and (eq "" (include "application.volumes.backend" .)) (eq "" (include "application.volumes.all" .)) ) }} + {{- include "application.volumes.backend" . | indent 6 }} + {{- include "application.volumes.all" . | indent 6 }} + {{- else }} [] + {{- end }} +status: {} diff --git a/helm/app/templates/application/webapp/ingress-istio.yaml b/helm/app/templates/application/webapp/ingress-istio.yaml new file mode 100644 index 0000000..3d605ab --- /dev/null +++ b/helm/app/templates/application/webapp/ingress-istio.yaml @@ -0,0 +1,25 @@ +{{ if eq .Values.ingress "istio" }} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ .Release.Namespace }}-{{ .Values.resourcePrefix }}webapp-virtualservice + labels: + app: {{ .Values.resourcePrefix }}webapp + app.service: {{ .Values.resourcePrefix }}webapp +spec: + hosts: + - {{ index .Values.docker.services "php-base" "environment" "APP_HOST" }} + gateways: +{{- range $key, $value := .Values.istio.gateways }} + - {{ tpl $value $ | quote }} +{{- end }} +{{- range $key, $value := .Values.istio.additionalGateways }} + - {{ $value | quote }} +{{- end }} + http: + - route: + - destination: + host: {{ .Values.resourcePrefix }}webapp + port: + number: 80 +{{ end }} diff --git a/helm/app/templates/application/webapp/ingress.yaml b/helm/app/templates/application/webapp/ingress.yaml new file mode 100644 index 0000000..a008d62 --- /dev/null +++ b/helm/app/templates/application/webapp/ingress.yaml @@ -0,0 +1,19 @@ +{{ if eq .Values.ingress "standard" }} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + creationTimestamp: null + labels: + app.service: {{ .Values.resourcePrefix }}webapp + name: {{ .Values.resourcePrefix }}webapp +spec: + rules: + - host: {{ index .Values.docker.services "php-base" "environment" "APP_HOST" }} + http: + paths: + - backend: + serviceName: {{ .Values.resourcePrefix }}webapp + servicePort: 80 +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/application/webapp/podmonitor.yaml b/helm/app/templates/application/webapp/podmonitor.yaml new file mode 100644 index 0000000..6d650e6 --- /dev/null +++ b/helm/app/templates/application/webapp/podmonitor.yaml @@ -0,0 +1,19 @@ +{{- if .Values.prometheus.podMonitoring -}} +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ .Values.resourcePrefix }}webapp + labels: + app.service: {{ .Values.resourcePrefix }}webapp +spec: + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}webapp + podMetricsEndpoints: +{{- if .Values.docker.services.nginx.metricsEnabled -}} +{{ .Values.docker.services.nginx.metricsEndpoints | toYaml | nindent 6 -}} +{{- end -}} +{{- if and .Values.service.php_fpm_exporter (index .Values.docker.services "php-fpm-exporter" "metricsEnabled") -}} +{{ index .Values.docker.services "php-fpm-exporter" "metricsEndpoints" | toYaml | nindent 6 -}} +{{- end -}} +{{- end -}} diff --git a/helm/app/templates/application/webapp/service.yaml b/helm/app/templates/application/webapp/service.yaml new file mode 100644 index 0000000..5760135 --- /dev/null +++ b/helm/app/templates/application/webapp/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}webapp + name: {{ .Values.resourcePrefix }}webapp +spec: + ports: + - name: http-80 + port: 80 + targetPort: 80 + selector: + app.service: {{ .Values.resourcePrefix }}webapp +status: + loadBalancer: {} diff --git a/helm/app/templates/service/elasticsearch/deployment.yaml b/helm/app/templates/service/elasticsearch/deployment.yaml new file mode 100644 index 0000000..da0a694 --- /dev/null +++ b/helm/app/templates/service/elasticsearch/deployment.yaml @@ -0,0 +1,52 @@ +{{ if .Values.service.elasticsearch }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}elasticsearch + labels: + app.service: {{ .Values.resourcePrefix }}elasticsearch +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}elasticsearch + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}elasticsearch + spec: + containers: + - env: + - name: ES_JAVA_OPTS + value: -Xmx512m -Xms512m + - name: discovery.type + value: single-node + image: {{ .Values.docker.image.elasticsearch }} + imagePullPolicy: Always + name: elasticsearch + ports: + - containerPort: 9200 + resources: + limits: + memory: {{ .Values.resources.memory.elasticsearch }} + requests: + memory: {{ .Values.resources.memory.elasticsearch }} + readinessProbe: + tcpSocket: + port: 9200 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ .Values.resourcePrefix }}elasticsearch-persistent-storage + mountPath: /usr/share/elasticsearch/data + restartPolicy: Always + volumes: + - name: {{ .Values.resourcePrefix }}elasticsearch-persistent-storage +{{- if .Values.persistence.elasticsearch.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.resourcePrefix }}elasticsearch-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{ end }} diff --git a/helm/app/templates/service/elasticsearch/pvc.yaml b/helm/app/templates/service/elasticsearch/pvc.yaml new file mode 100644 index 0000000..823f0f2 --- /dev/null +++ b/helm/app/templates/service/elasticsearch/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.service.elasticsearch .Values.persistence.elasticsearch.enabled -}} + +{{- with .Values.persistence.elasticsearch -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}elasticsearch-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}elasticsearch +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/elasticsearch/service.yaml b/helm/app/templates/service/elasticsearch/service.yaml new file mode 100644 index 0000000..6f550dd --- /dev/null +++ b/helm/app/templates/service/elasticsearch/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.elasticsearch }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}elasticsearch + name: {{ .Values.resourcePrefix }}elasticsearch +spec: + ports: + - name: "9200" + port: 9200 + targetPort: 9200 + selector: + app.service: {{ .Values.resourcePrefix }}elasticsearch +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/mysql/deployment.yaml b/helm/app/templates/service/mysql/deployment.yaml new file mode 100644 index 0000000..97e0917 --- /dev/null +++ b/helm/app/templates/service/mysql/deployment.yaml @@ -0,0 +1,55 @@ +{{ if .Values.service.mysql }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}mysql + labels: + app.service: {{ .Values.resourcePrefix }}mysql +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}mysql + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}mysql + spec: + containers: + - env: + {{- range $key, $value := .Values.docker.services.mysql.environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + image: mysql:5.7 + imagePullPolicy: Always + name: mysql + args: + - --ignore-db-dir + - lost+found + ports: + - containerPort: 3306 + resources: + limits: + memory: {{ .Values.resources.memory.mysql }} + requests: + memory: {{ .Values.resources.memory.mysql }} + readinessProbe: + tcpSocket: + port: 3306 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ .Values.resourcePrefix }}mysql-persistent-storage + mountPath: /var/lib/mysql + restartPolicy: Always + volumes: + - name: {{ .Values.resourcePrefix }}mysql-persistent-storage +{{- if .Values.persistence.mysql.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.resourcePrefix }}mysql-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{ end }} diff --git a/helm/app/templates/service/mysql/pvc.yaml b/helm/app/templates/service/mysql/pvc.yaml new file mode 100644 index 0000000..155c55a --- /dev/null +++ b/helm/app/templates/service/mysql/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.service.mysql .Values.persistence.mysql.enabled -}} + +{{- with .Values.persistence.mysql -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}mysql-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}mysql +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/mysql/service.yaml b/helm/app/templates/service/mysql/service.yaml new file mode 100644 index 0000000..26e8f09 --- /dev/null +++ b/helm/app/templates/service/mysql/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.mysql }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}mysql + name: {{ .Values.resourcePrefix }}mysql +spec: + ports: + - name: "3306" + port: 3306 + targetPort: 3306 + selector: + app.service: {{ .Values.resourcePrefix }}mysql +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/postgres/deployment.yaml b/helm/app/templates/service/postgres/deployment.yaml new file mode 100644 index 0000000..7f082b1 --- /dev/null +++ b/helm/app/templates/service/postgres/deployment.yaml @@ -0,0 +1,52 @@ +{{ if .Values.service.postgres }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}postgres + labels: + app.service: {{ .Values.resourcePrefix }}postgres +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}postgres + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}postgres + spec: + containers: + - env: + {{- range $key, $value := .Values.docker.services.postgres.environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + image: postgres:9.6 + imagePullPolicy: Always + name: postgres + ports: + - containerPort: 5432 + resources: + limits: + memory: {{ .Values.resources.memory.postgres }} + requests: + memory: {{ .Values.resources.memory.postgres }} + readinessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ .Values.resourcePrefix }}postgres-persistent-storage + mountPath: /var/lib/postgresql/data + restartPolicy: Always + volumes: + - name: {{ .Values.resourcePrefix }}postgres-persistent-storage +{{- if .Values.persistence.postgres.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.resourcePrefix }}postgres-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{ end }} diff --git a/helm/app/templates/service/postgres/pvc.yaml b/helm/app/templates/service/postgres/pvc.yaml new file mode 100644 index 0000000..6e69a50 --- /dev/null +++ b/helm/app/templates/service/postgres/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.service.postgres .Values.persistence.postgres.enabled -}} + +{{- with .Values.persistence.postgres -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}postgres-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}postgres +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/postgres/service.yaml b/helm/app/templates/service/postgres/service.yaml new file mode 100644 index 0000000..ee08424 --- /dev/null +++ b/helm/app/templates/service/postgres/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.postgres }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}postgres + name: {{ .Values.resourcePrefix }}postgres +spec: + ports: + - name: "5432" + port: 5432 + targetPort: 5432 + selector: + app.service: {{ .Values.resourcePrefix }}postgres +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/redis-session/deployment.yaml b/helm/app/templates/service/redis-session/deployment.yaml new file mode 100644 index 0000000..1a7b97a --- /dev/null +++ b/helm/app/templates/service/redis-session/deployment.yaml @@ -0,0 +1,51 @@ +{{ if .Values.service.redis_session }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}redis-session + labels: + app.service: {{ .Values.resourcePrefix }}redis-session +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}redis-session + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}redis-session + spec: + containers: + - args: + - redis-server + - --maxmemory + - "1073742000" + - --maxmemory-policy + - volatile-ttl + - --save + - "3600" + - "1" + - --save + - "300" + - "100" + - --save + - "60" + - "10000" + image: redis:4-alpine + imagePullPolicy: Always + name: redis-session + ports: + - containerPort: 6379 + resources: + limits: + memory: {{ .Values.resources.memory.redis_session }} + requests: + memory: {{ .Values.resources.memory.redis_session }} + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 5 + periodSeconds: 10 + restartPolicy: Always +status: {} +{{ end }} diff --git a/helm/app/templates/service/redis-session/service.yaml b/helm/app/templates/service/redis-session/service.yaml new file mode 100644 index 0000000..2c4256d --- /dev/null +++ b/helm/app/templates/service/redis-session/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.redis_session }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}redis-session + name: {{ .Values.resourcePrefix }}redis-session +spec: + ports: + - name: "6379" + port: 6379 + targetPort: 6379 + selector: + app.service: {{ .Values.resourcePrefix }}redis-session +status: + loadBalancer: {} +{{ end }} \ No newline at end of file diff --git a/helm/app/templates/service/redis/deployment.yaml b/helm/app/templates/service/redis/deployment.yaml new file mode 100644 index 0000000..fba48c5 --- /dev/null +++ b/helm/app/templates/service/redis/deployment.yaml @@ -0,0 +1,63 @@ +{{ if .Values.service.redis }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}redis + labels: + app.service: {{ .Values.resourcePrefix }}redis +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}redis + template: + metadata: + creationTimestamp: null + labels: + app.service: {{ .Values.resourcePrefix }}redis + spec: + containers: + - args: + - redis-server + - --maxmemory + - "1073742000" + - --maxmemory-policy + - allkeys-lru + - --save + - "3600" + - "1" + - --save + - "300" + - "100" + - --save + - "60" + - "10000" + image: redis:4-alpine + imagePullPolicy: Always + name: redis + ports: + - containerPort: 6379 + resources: + limits: + memory: {{ .Values.resources.memory.redis }} + requests: + memory: {{ .Values.resources.memory.redis }} + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ .Values.resourcePrefix }}redis-persistent-storage + mountPath: /data + restartPolicy: Always + volumes: + - name: {{ .Values.resourcePrefix }}redis-persistent-storage +{{- if .Values.persistence.redis.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.resourcePrefix }}redis-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{ end }} diff --git a/helm/app/templates/service/redis/pvc.yaml b/helm/app/templates/service/redis/pvc.yaml new file mode 100644 index 0000000..fbf7b11 --- /dev/null +++ b/helm/app/templates/service/redis/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.service.redis .Values.persistence.redis.enabled -}} + +{{- with .Values.persistence.redis -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}redis-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}redis +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/redis/service.yaml b/helm/app/templates/service/redis/service.yaml new file mode 100644 index 0000000..722bc2b --- /dev/null +++ b/helm/app/templates/service/redis/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.redis }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}redis + name: {{ .Values.resourcePrefix }}redis +spec: + ports: + - name: "6379" + port: 6379 + targetPort: 6379 + selector: + app.service: {{ .Values.resourcePrefix }}redis +status: + loadBalancer: {} +{{ end }} \ No newline at end of file diff --git a/helm/app/values-preview.yaml.twig b/helm/app/values-preview.yaml.twig new file mode 100644 index 0000000..ef85d52 --- /dev/null +++ b/helm/app/values-preview.yaml.twig @@ -0,0 +1,14 @@ +{% if @('pipeline.preview.services') %} +docker: + services: +{{ to_nice_yaml(@('pipeline.preview.services'), 2, 4) | raw }} +{% endif %} +{% if @('pipeline.preview.persistence') %} +persistence: +{{ to_nice_yaml(@('pipeline.preview.persistence'), 2, 2) | raw }} +{% endif %} + +{% if @('pipeline.preview.resources') %} +resources: +{{ to_nice_yaml(@('pipeline.preview.resources'), 2, 2) | raw }} +{% endif %} diff --git a/helm/app/values-production.yaml.twig b/helm/app/values-production.yaml.twig new file mode 100644 index 0000000..1ff70c5 --- /dev/null +++ b/helm/app/values-production.yaml.twig @@ -0,0 +1,26 @@ + +# assumption is that in a production style environment these would be +# managed services outside of the applications control + +service: + elasticsearch: false + memcached: false + mysql: false + postgres: false + redis: false + redis_session: false + +{% if @('pipeline.production.services') %} +docker: + services: +{{ to_nice_yaml(@('pipeline.production.services'), 2, 4) | raw }} +{% endif %} +{% if @('pipeline.production.persistence') %} +persistence: +{{ to_nice_yaml(@('pipeline.production.persistence'), 2, 2) | raw }} +{% endif %} + + {% if @('pipeline.production.resources') %} +resources: +{{ to_nice_yaml(@('pipeline.production.resources'), 2, 2) | raw }} +{% endif %} diff --git a/helm/app/values.yaml.twig b/helm/app/values.yaml.twig new file mode 100644 index 0000000..dbb4d15 --- /dev/null +++ b/helm/app/values.yaml.twig @@ -0,0 +1,41 @@ +{% set blocks = 'helm/app/_twig/values.yaml/' %} + +environment: +{% include blocks ~ 'environment.yml.twig' %} + +docker: + config: {{ @('docker.config') }} + image: + console: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-console' }} + fpm: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-php-fpm' }} + nginx: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-nginx' }} + elasticsearch: {{ @('elasticsearch.image') ~ ':' ~ @('elasticsearch.tag') }} + cron: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-cron' }} + php_fpm_exporter: {{ @('docker.repository') ~ ':' ~ @('app.version') ~ '-php-fpm-exporter' }} + services: +{{ deep_merge_to_yaml([@('services'), @('pipeline.base.services')], 2, 4) | raw }} + +service: + elasticsearch: {{ ("elasticsearch" in @('app.services')) ? 'true' : 'false' }} + memcached: {{ ("memcached" in @('app.services')) ? 'true' : 'false' }} + mysql: {{ ("mysql" in @('app.services')) ? 'true' : 'false' }} + postgres: {{ ("postgres" in @('app.services')) ? 'true' : 'false' }} + redis: {{ ("redis" in @('app.services')) ? 'true' : 'false' }} + redis_session: {{ ("redis-session" in @('app.services')) ? 'true' : 'false' }} + cron: {{ ("cron" in @('app.services')) ? 'true' : 'false' }} + php_fpm_exporter: {{ ("php-fpm-exporter" in @('app.services')) ? 'true' : 'false' }} + +resources: +{% include blocks ~ 'resources.yml.twig' %} + +persistence: +{{ to_nice_yaml(@('pipeline.base.persistence'), 2, 2) | raw }} + +prometheus: +{{ to_nice_yaml(@('pipeline.base.prometheus'), 2, 2) | raw }} + +resourcePrefix: {{ @('pipeline.base.resourcePrefix') | json_encode | raw }} + +ingress: "standard" # standard or istio +istio: +{{ to_nice_yaml(@('pipeline.base.istio'), 2, 2) | raw }} diff --git a/helm/qa/Chart.yaml.twig b/helm/qa/Chart.yaml.twig new file mode 100644 index 0000000..2afdc86 --- /dev/null +++ b/helm/qa/Chart.yaml.twig @@ -0,0 +1,5 @@ +name: {{ @('workspace.name') }}-qa +description: Base helm chart for the {{ @('workspace.name') }}-qa environment +version: 0.0.1 +sources: +home: diff --git a/helm/qa/requirements.yaml.twig b/helm/qa/requirements.yaml.twig new file mode 100644 index 0000000..16b0aa8 --- /dev/null +++ b/helm/qa/requirements.yaml.twig @@ -0,0 +1,4 @@ +dependencies: +- name: {{ @('workspace.name') }} + version: 0.0.1 + repository: "file://../app" diff --git a/helm/qa/values.yaml.twig b/helm/qa/values.yaml.twig new file mode 100644 index 0000000..e73cd1f --- /dev/null +++ b/helm/qa/values.yaml.twig @@ -0,0 +1,11 @@ +{{ @('workspace.name') }}: + resourcePrefix: {{ @('pipeline.qa.resourcePrefix') | json_encode | raw }} +{% if @('pipeline.qa.services') %} + docker: + services: +{{ to_nice_yaml(@('pipeline.qa.services'), 2, 6) | raw }} +{% endif %} +{% if @('pipeline.qa.persistence') %} + persistence: +{{ to_nice_yaml(@('pipeline.qa.persistence'), 2, 4) | raw }} +{% endif %} diff --git a/mutagen.yml.twig b/mutagen.yml.twig new file mode 100644 index 0000000..d09a48d --- /dev/null +++ b/mutagen.yml.twig @@ -0,0 +1,30 @@ +forward: + {{ @('workspace.name') }}: + source: "tcp:localhost:6060" + destination: "docker://{{ @('workspace.name') }}-sync:tcp:localhost:6060" + +sync: + {{ @('workspace.name') }}: + alpha: "." + beta: "docker://{{ @('workspace.name') }}-sync/app" + mode: "two-way-resolved" + # Configuration for host file system as configured above for "alpha" key + configurationAlpha: + permissions: + defaultFileMode: 0644 + defaultDirectoryMode: 0755 + # Configuration for docker file system as configured above for "beta" key + configurationBeta: + permissions: + defaultOwner: "id:1000" + defaultGroup: "id:1000" + defaultFileMode: 0644 + defaultDirectoryMode: 0755 + symlink: + mode: posix-raw + ignore: + paths: + - /.docker-sync + - /.idea + - /.git + - /var