├── tests ├── .docksal │ ├── docksal.yml │ ├── etc │ │ └── php │ │ │ ├── preload.php │ │ │ ├── php.ini │ │ │ └── php-fpm.conf │ ├── services │ │ └── cli │ │ │ ├── crontab │ │ │ └── startup.sh │ └── docksal.env ├── docroot │ ├── test.php │ ├── phpinfo.php │ └── php-fpm.sh ├── env_make └── test.bats ├── 8.1 ├── config │ ├── php │ │ ├── xhprof.ini │ │ ├── opcache.ini │ │ ├── zz-php.ini │ │ ├── zz-php-fpm.conf │ │ └── xdebug.ini │ ├── .ssh │ │ ├── id_rsa.tmpl │ │ └── config │ ├── .terminus │ │ └── config.yml │ ├── supervisor │ │ ├── supervisord-sshd.conf │ │ ├── supervisord-php-fpm.conf │ │ ├── supervisord-crond.conf │ │ ├── supervisord-code-server.conf.tmpl │ │ └── supervisord.conf │ └── code-server │ │ ├── config.yaml.tmpl │ │ └── User │ │ └── settings.json ├── .dockerignore ├── ping-web.sh ├── healthcheck.sh ├── tests │ ├── essential-binaries.sh │ └── php-modules.sh ├── Makefile ├── startup.sh └── Dockerfile ├── 8.2 ├── config │ ├── php │ │ ├── xhprof.ini │ │ ├── opcache.ini │ │ ├── zz-php.ini │ │ ├── zz-php-fpm.conf │ │ └── xdebug.ini │ ├── .ssh │ │ ├── id_rsa.tmpl │ │ └── config │ ├── .terminus │ │ └── config.yml │ ├── supervisor │ │ ├── supervisord-sshd.conf │ │ ├── supervisord-php-fpm.conf │ │ ├── supervisord-crond.conf │ │ ├── supervisord-code-server.conf.tmpl │ │ └── supervisord.conf │ └── code-server │ │ ├── config.yaml.tmpl │ │ └── User │ │ └── settings.json ├── .dockerignore ├── ping-web.sh ├── healthcheck.sh ├── tests │ ├── essential-binaries.sh │ └── php-modules.sh ├── Makefile ├── startup.sh └── Dockerfile ├── 8.3 ├── config │ ├── php │ │ ├── xhprof.ini │ │ ├── opcache.ini │ │ ├── zz-php.ini │ │ ├── zz-php-fpm.conf │ │ └── xdebug.ini │ ├── .ssh │ │ ├── id_rsa.tmpl │ │ └── config │ ├── .terminus │ │ └── config.yml │ ├── supervisor │ │ ├── supervisord-sshd.conf │ │ ├── supervisord-php-fpm.conf │ │ ├── supervisord-crond.conf │ │ ├── supervisord-code-server.conf.tmpl │ │ └── supervisord.conf │ └── code-server │ │ ├── config.yaml.tmpl │ │ └── User │ │ └── settings.json ├── .dockerignore ├── ping-web.sh ├── healthcheck.sh ├── tests │ ├── essential-binaries.sh │ └── php-modules.sh ├── Makefile ├── startup.sh └── Dockerfile ├── 8.4 ├── config │ ├── php │ │ ├── xhprof.ini │ │ ├── opcache.ini │ │ ├── zz-php.ini │ │ ├── zz-php-fpm.conf │ │ └── xdebug.ini │ ├── .ssh │ │ ├── id_rsa.tmpl │ │ └── config │ ├── .terminus │ │ └── config.yml │ ├── supervisor │ │ ├── supervisord-sshd.conf │ │ ├── supervisord-php-fpm.conf │ │ ├── supervisord-crond.conf │ │ ├── supervisord-code-server.conf.tmpl │ │ └── supervisord.conf │ └── code-server │ │ ├── config.yaml.tmpl │ │ └── User │ │ └── settings.json ├── .dockerignore ├── ping-web.sh ├── healthcheck.sh ├── tests │ ├── essential-binaries.sh │ └── php-modules.sh ├── Makefile ├── startup.sh └── Dockerfile ├── LICENSE ├── .github ├── scripts │ ├── docker-tag-delete.sh │ └── docker-tags.sh └── workflows │ └── default.yaml └── README.md /tests/.docksal/docksal.yml: -------------------------------------------------------------------------------- 1 | version: "2.1" 2 | -------------------------------------------------------------------------------- /tests/.docksal/etc/php/preload.php: -------------------------------------------------------------------------------- 1 | /tmp/date.txt 2 | -------------------------------------------------------------------------------- /tests/.docksal/services/cli/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "I ran properly" > /tmp/test-startup.txt 4 | -------------------------------------------------------------------------------- /8.1/config/php/opcache.ini: -------------------------------------------------------------------------------- 1 | ; Extention settings 2 | [opcache] 3 | opcache.preload=/var/www/.docksal/etc/php/preload.php 4 | -------------------------------------------------------------------------------- /8.2/config/php/opcache.ini: -------------------------------------------------------------------------------- 1 | ; Extention settings 2 | [opcache] 3 | opcache.preload=/var/www/.docksal/etc/php/preload.php 4 | -------------------------------------------------------------------------------- /8.3/config/php/opcache.ini: -------------------------------------------------------------------------------- 1 | ; Extention settings 2 | [opcache] 3 | opcache.preload=/var/www/.docksal/etc/php/preload.php 4 | -------------------------------------------------------------------------------- /8.4/config/php/opcache.ini: -------------------------------------------------------------------------------- 1 | ; Extention settings 2 | [opcache] 3 | opcache.preload=/var/www/.docksal/etc/php/preload.php 4 | -------------------------------------------------------------------------------- /tests/.docksal/etc/php/php.ini: -------------------------------------------------------------------------------- 1 | ; Global PHP settings 2 | [php] 3 | ; Maximum amount of memory a script may consume 4 | memory_limit = 128M 5 | -------------------------------------------------------------------------------- /tests/env_make: -------------------------------------------------------------------------------- 1 | ENV = \ 2 | -e XDEBUG_ENABLED \ 3 | -e SECRET_SSH_PRIVATE_KEY \ 4 | -e SECRET_PLATFORMSH_CLI_TOKEN \ 5 | -e SECRET_TERMINUS_TOKEN 6 | -------------------------------------------------------------------------------- /tests/.docksal/etc/php/php-fpm.conf: -------------------------------------------------------------------------------- 1 | ; PHP FPM settings 2 | [www] 3 | ; Maximum amount of memory a script may consume 4 | php_admin_value[memory_limit] = 512M 5 | -------------------------------------------------------------------------------- /8.1/config/.ssh/config: -------------------------------------------------------------------------------- 1 | # Disable remote host key checking and warnings 2 | Host * 3 | StrictHostKeyChecking no 4 | UserKnownHostsFile /dev/null 5 | LogLevel ERROR 6 | -------------------------------------------------------------------------------- /8.2/config/.ssh/config: -------------------------------------------------------------------------------- 1 | # Disable remote host key checking and warnings 2 | Host * 3 | StrictHostKeyChecking no 4 | UserKnownHostsFile /dev/null 5 | LogLevel ERROR 6 | -------------------------------------------------------------------------------- /8.3/config/.ssh/config: -------------------------------------------------------------------------------- 1 | # Disable remote host key checking and warnings 2 | Host * 3 | StrictHostKeyChecking no 4 | UserKnownHostsFile /dev/null 5 | LogLevel ERROR 6 | -------------------------------------------------------------------------------- /8.4/config/.ssh/config: -------------------------------------------------------------------------------- 1 | # Disable remote host key checking and warnings 2 | Host * 3 | StrictHostKeyChecking no 4 | UserKnownHostsFile /dev/null 5 | LogLevel ERROR 6 | -------------------------------------------------------------------------------- /8.1/config/supervisor/supervisord-sshd.conf: -------------------------------------------------------------------------------- 1 | [program:sshd] 2 | command = /usr/sbin/sshd -D 3 | stdout_logfile = /var/log/supervisor/sshd-stdout 4 | stderr_logfile = /var/log/supervisor/sshd-stderr 5 | -------------------------------------------------------------------------------- /8.2/config/supervisor/supervisord-sshd.conf: -------------------------------------------------------------------------------- 1 | [program:sshd] 2 | command = /usr/sbin/sshd -D 3 | stdout_logfile = /var/log/supervisor/sshd-stdout 4 | stderr_logfile = /var/log/supervisor/sshd-stderr 5 | -------------------------------------------------------------------------------- /8.3/config/supervisor/supervisord-sshd.conf: -------------------------------------------------------------------------------- 1 | [program:sshd] 2 | command = /usr/sbin/sshd -D 3 | stdout_logfile = /var/log/supervisor/sshd-stdout 4 | stderr_logfile = /var/log/supervisor/sshd-stderr 5 | -------------------------------------------------------------------------------- /8.4/config/supervisor/supervisord-sshd.conf: -------------------------------------------------------------------------------- 1 | [program:sshd] 2 | command = /usr/sbin/sshd -D 3 | stdout_logfile = /var/log/supervisor/sshd-stdout 4 | stderr_logfile = /var/log/supervisor/sshd-stderr 5 | -------------------------------------------------------------------------------- /8.1/config/supervisor/supervisord-php-fpm.conf: -------------------------------------------------------------------------------- 1 | [program:php-fpm] 2 | command = /usr/local/sbin/php-fpm 3 | stdout_logfile = /var/log/supervisor/php-fpm-stdout 4 | stderr_logfile = /var/log/supervisor/php-fpm-stderr 5 | -------------------------------------------------------------------------------- /8.2/config/supervisor/supervisord-php-fpm.conf: -------------------------------------------------------------------------------- 1 | [program:php-fpm] 2 | command = /usr/local/sbin/php-fpm 3 | stdout_logfile = /var/log/supervisor/php-fpm-stdout 4 | stderr_logfile = /var/log/supervisor/php-fpm-stderr 5 | -------------------------------------------------------------------------------- /8.3/config/supervisor/supervisord-php-fpm.conf: -------------------------------------------------------------------------------- 1 | [program:php-fpm] 2 | command = /usr/local/sbin/php-fpm 3 | stdout_logfile = /var/log/supervisor/php-fpm-stdout 4 | stderr_logfile = /var/log/supervisor/php-fpm-stderr 5 | -------------------------------------------------------------------------------- /8.4/config/supervisor/supervisord-php-fpm.conf: -------------------------------------------------------------------------------- 1 | [program:php-fpm] 2 | command = /usr/local/sbin/php-fpm 3 | stdout_logfile = /var/log/supervisor/php-fpm-stdout 4 | stderr_logfile = /var/log/supervisor/php-fpm-stderr 5 | -------------------------------------------------------------------------------- /8.1/config/supervisor/supervisord-crond.conf: -------------------------------------------------------------------------------- 1 | [program:cron] 2 | # Cron will only log to syslog and nothing else... 3 | command = /usr/sbin/cron -f 4 | stdout_logfile = /var/log/supervisor/cron-stdout 5 | stderr_logfile = /var/log/supervisor/cron-stderr 6 | -------------------------------------------------------------------------------- /8.2/config/supervisor/supervisord-crond.conf: -------------------------------------------------------------------------------- 1 | [program:cron] 2 | # Cron will only log to syslog and nothing else... 3 | command = /usr/sbin/cron -f 4 | stdout_logfile = /var/log/supervisor/cron-stdout 5 | stderr_logfile = /var/log/supervisor/cron-stderr 6 | -------------------------------------------------------------------------------- /8.3/config/supervisor/supervisord-crond.conf: -------------------------------------------------------------------------------- 1 | [program:cron] 2 | # Cron will only log to syslog and nothing else... 3 | command = /usr/sbin/cron -f 4 | stdout_logfile = /var/log/supervisor/cron-stdout 5 | stderr_logfile = /var/log/supervisor/cron-stderr 6 | -------------------------------------------------------------------------------- /8.4/config/supervisor/supervisord-crond.conf: -------------------------------------------------------------------------------- 1 | [program:cron] 2 | # Cron will only log to syslog and nothing else... 3 | command = /usr/sbin/cron -f 4 | stdout_logfile = /var/log/supervisor/cron-stdout 5 | stderr_logfile = /var/log/supervisor/cron-stderr 6 | -------------------------------------------------------------------------------- /8.1/config/code-server/config.yaml.tmpl: -------------------------------------------------------------------------------- 1 | user-data-dir: {{ getenv "VSCODE_HOME" }} 2 | bind-addr: 0.0.0.0:8080 3 | cert: false 4 | {{ if (getenv "IDE_PASSWORD") }} 5 | auth: password 6 | password: {{ getenv "IDE_PASSWORD" }} 7 | {{ else }} 8 | auth: none 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /8.2/config/code-server/config.yaml.tmpl: -------------------------------------------------------------------------------- 1 | user-data-dir: {{ getenv "VSCODE_HOME" }} 2 | bind-addr: 0.0.0.0:8080 3 | cert: false 4 | {{ if (getenv "IDE_PASSWORD") }} 5 | auth: password 6 | password: {{ getenv "IDE_PASSWORD" }} 7 | {{ else }} 8 | auth: none 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /8.3/config/code-server/config.yaml.tmpl: -------------------------------------------------------------------------------- 1 | user-data-dir: {{ getenv "VSCODE_HOME" }} 2 | bind-addr: 0.0.0.0:8080 3 | cert: false 4 | {{ if (getenv "IDE_PASSWORD") }} 5 | auth: password 6 | password: {{ getenv "IDE_PASSWORD" }} 7 | {{ else }} 8 | auth: none 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /8.4/config/code-server/config.yaml.tmpl: -------------------------------------------------------------------------------- 1 | user-data-dir: {{ getenv "VSCODE_HOME" }} 2 | bind-addr: 0.0.0.0:8080 3 | cert: false 4 | {{ if (getenv "IDE_PASSWORD") }} 5 | auth: password 6 | password: {{ getenv "IDE_PASSWORD" }} 7 | {{ else }} 8 | auth: none 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /8.1/ping-web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Notify web container about started fin exec 4 | if [[ "${WEB_KEEPALIVE}" != "0" ]] && [[ "${VIRTUAL_HOST}" != "" ]] 5 | then 6 | while true 7 | do 8 | curl -s -m 1 ${VIRTUAL_HOST}/exec_in_progress_inside_cli >/dev/null 2>&1 9 | sleep ${WEB_KEEPALIVE} 10 | done 11 | fi 12 | -------------------------------------------------------------------------------- /8.2/ping-web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Notify web container about started fin exec 4 | if [[ "${WEB_KEEPALIVE}" != "0" ]] && [[ "${VIRTUAL_HOST}" != "" ]] 5 | then 6 | while true 7 | do 8 | curl -s -m 1 ${VIRTUAL_HOST}/exec_in_progress_inside_cli >/dev/null 2>&1 9 | sleep ${WEB_KEEPALIVE} 10 | done 11 | fi 12 | -------------------------------------------------------------------------------- /8.3/ping-web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Notify web container about started fin exec 4 | if [[ "${WEB_KEEPALIVE}" != "0" ]] && [[ "${VIRTUAL_HOST}" != "" ]] 5 | then 6 | while true 7 | do 8 | curl -s -m 1 ${VIRTUAL_HOST}/exec_in_progress_inside_cli >/dev/null 2>&1 9 | sleep ${WEB_KEEPALIVE} 10 | done 11 | fi 12 | -------------------------------------------------------------------------------- /8.4/ping-web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Notify web container about started fin exec 4 | if [[ "${WEB_KEEPALIVE}" != "0" ]] && [[ "${VIRTUAL_HOST}" != "" ]] 5 | then 6 | while true 7 | do 8 | curl -s -m 1 ${VIRTUAL_HOST}/exec_in_progress_inside_cli >/dev/null 2>&1 9 | sleep ${WEB_KEEPALIVE} 10 | done 11 | fi 12 | -------------------------------------------------------------------------------- /tests/.docksal/docksal.env: -------------------------------------------------------------------------------- 1 | DOCKSAL_STACK=node 2 | 3 | # Project secrets 4 | SECRET_SSH_PRIVATE_KEY="LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1xNHg2MVF0aVVpcnJsTjlBcWxwbmlvZndTVXI2NzRGaFpvSEdNc20yYkRvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFS0xmcG8zbG4ra2VaYXQvSFlJRytnMEgvTHQvK2owRVVFTkh5R084cTJ5cXUwMmw4MzNHOApsMlhSSlQ1a3hORlJhM1lHUjBKbzFLbnp5ZXk4d0ZPT293PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=" 5 | -------------------------------------------------------------------------------- /8.1/config/supervisor/supervisord-code-server.conf.tmpl: -------------------------------------------------------------------------------- 1 | # VS Code Server web IDE 2 | [program:code-server] 3 | # Using bash -lc here to load docker user profile (necessary for nvn/node to initialize) 4 | command = gosu docker bash -lc '/usr/bin/code-server --config=${VSCODE_HOME}/config.yaml /var/www' 5 | stdout_logfile = /var/log/supervisor/code-server-stdout 6 | stderr_logfile = /var/log/supervisor/code-server-stderr 7 | -------------------------------------------------------------------------------- /8.2/config/supervisor/supervisord-code-server.conf.tmpl: -------------------------------------------------------------------------------- 1 | # VS Code Server web IDE 2 | [program:code-server] 3 | # Using bash -lc here to load docker user profile (necessary for nvn/node to initialize) 4 | command = gosu docker bash -lc '/usr/bin/code-server --config=${VSCODE_HOME}/config.yaml /var/www' 5 | stdout_logfile = /var/log/supervisor/code-server-stdout 6 | stderr_logfile = /var/log/supervisor/code-server-stderr 7 | -------------------------------------------------------------------------------- /8.3/config/supervisor/supervisord-code-server.conf.tmpl: -------------------------------------------------------------------------------- 1 | # VS Code Server web IDE 2 | [program:code-server] 3 | # Using bash -lc here to load docker user profile (necessary for nvn/node to initialize) 4 | command = gosu docker bash -lc '/usr/bin/code-server --config=${VSCODE_HOME}/config.yaml /var/www' 5 | stdout_logfile = /var/log/supervisor/code-server-stdout 6 | stderr_logfile = /var/log/supervisor/code-server-stderr 7 | -------------------------------------------------------------------------------- /8.4/config/supervisor/supervisord-code-server.conf.tmpl: -------------------------------------------------------------------------------- 1 | # VS Code Server web IDE 2 | [program:code-server] 3 | # Using bash -lc here to load docker user profile (necessary for nvn/node to initialize) 4 | command = gosu docker bash -lc '/usr/bin/code-server --config=${VSCODE_HOME}/config.yaml /var/www' 5 | stdout_logfile = /var/log/supervisor/code-server-stdout 6 | stderr_logfile = /var/log/supervisor/code-server-stderr 7 | -------------------------------------------------------------------------------- /8.1/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Initialization phase in startup.sh is complete 4 | [[ -f /var/run/cli ]] || exit 1 5 | 6 | # supervisor services are running 7 | if [[ -f /run/supervisord.pid ]]; then 8 | if [[ "${IDE_ENABLED}" == "1" ]]; then 9 | # IDE mode 10 | ps aux | grep code-server >/dev/null || exit 1 11 | else 12 | # php-fpm/cli mode 13 | [[ -f /run/php-fpm.pid ]] || exit 1 14 | [[ -f /run/sshd.pid ]] || exit 1 15 | fi 16 | fi 17 | -------------------------------------------------------------------------------- /8.2/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Initialization phase in startup.sh is complete 4 | [[ -f /var/run/cli ]] || exit 1 5 | 6 | # supervisor services are running 7 | if [[ -f /run/supervisord.pid ]]; then 8 | if [[ "${IDE_ENABLED}" == "1" ]]; then 9 | # IDE mode 10 | ps aux | grep code-server >/dev/null || exit 1 11 | else 12 | # php-fpm/cli mode 13 | [[ -f /run/php-fpm.pid ]] || exit 1 14 | [[ -f /run/sshd.pid ]] || exit 1 15 | fi 16 | fi 17 | -------------------------------------------------------------------------------- /8.3/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Initialization phase in startup.sh is complete 4 | [[ -f /var/run/cli ]] || exit 1 5 | 6 | # supervisor services are running 7 | if [[ -f /run/supervisord.pid ]]; then 8 | if [[ "${IDE_ENABLED}" == "1" ]]; then 9 | # IDE mode 10 | ps aux | grep code-server >/dev/null || exit 1 11 | else 12 | # php-fpm/cli mode 13 | [[ -f /run/php-fpm.pid ]] || exit 1 14 | [[ -f /run/sshd.pid ]] || exit 1 15 | fi 16 | fi 17 | -------------------------------------------------------------------------------- /8.4/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Initialization phase in startup.sh is complete 4 | [[ -f /var/run/cli ]] || exit 1 5 | 6 | # supervisor services are running 7 | if [[ -f /run/supervisord.pid ]]; then 8 | if [[ "${IDE_ENABLED}" == "1" ]]; then 9 | # IDE mode 10 | ps aux | grep code-server >/dev/null || exit 1 11 | else 12 | # php-fpm/cli mode 13 | [[ -f /run/php-fpm.pid ]] || exit 1 14 | [[ -f /run/sshd.pid ]] || exit 1 15 | fi 16 | fi 17 | -------------------------------------------------------------------------------- /8.1/config/php/zz-php.ini: -------------------------------------------------------------------------------- 1 | ; PHP global (CLI and FPM) settings 2 | ; To override settings for FPM use zz-php-fpm.conf 3 | [php] 4 | memory_limit = -1 5 | max_execution_time = 600 6 | date.timezone = UTC 7 | display_errors = On 8 | display_startup_errors = On 9 | 10 | [mail] 11 | ; Enable Mailhog integration by default 12 | sendmail_path = '/usr/bin/msmtp -t --host=mail --port=1025 --from=docker@cli' 13 | 14 | ; Extention settings 15 | [opcache] 16 | opcache.memory_consumption = 128 17 | -------------------------------------------------------------------------------- /8.2/config/php/zz-php.ini: -------------------------------------------------------------------------------- 1 | ; PHP global (CLI and FPM) settings 2 | ; To override settings for FPM use zz-php-fpm.conf 3 | [php] 4 | memory_limit = -1 5 | max_execution_time = 600 6 | date.timezone = UTC 7 | display_errors = On 8 | display_startup_errors = On 9 | 10 | [mail] 11 | ; Enable Mailhog integration by default 12 | sendmail_path = '/usr/bin/msmtp -t --host=mail --port=1025 --from=docker@cli' 13 | 14 | ; Extention settings 15 | [opcache] 16 | opcache.memory_consumption = 128 17 | -------------------------------------------------------------------------------- /8.3/config/php/zz-php.ini: -------------------------------------------------------------------------------- 1 | ; PHP global (CLI and FPM) settings 2 | ; To override settings for FPM use zz-php-fpm.conf 3 | [php] 4 | memory_limit = -1 5 | max_execution_time = 600 6 | date.timezone = UTC 7 | display_errors = On 8 | display_startup_errors = On 9 | 10 | [mail] 11 | ; Enable Mailhog integration by default 12 | sendmail_path = '/usr/bin/msmtp -t --host=mail --port=1025 --from=docker@cli' 13 | 14 | ; Extention settings 15 | [opcache] 16 | opcache.memory_consumption = 128 17 | -------------------------------------------------------------------------------- /8.4/config/php/zz-php.ini: -------------------------------------------------------------------------------- 1 | ; PHP global (CLI and FPM) settings 2 | ; To override settings for FPM use zz-php-fpm.conf 3 | [php] 4 | memory_limit = -1 5 | max_execution_time = 600 6 | date.timezone = UTC 7 | display_errors = On 8 | display_startup_errors = On 9 | 10 | [mail] 11 | ; Enable Mailhog integration by default 12 | sendmail_path = '/usr/bin/msmtp -t --host=mail --port=1025 --from=docker@cli' 13 | 14 | ; Extention settings 15 | [opcache] 16 | opcache.memory_consumption = 128 17 | -------------------------------------------------------------------------------- /8.1/config/supervisor/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon = true 3 | # debug prints output from all services to stdout/stderr. 4 | # This way logs can be reviewed with docker logs. 5 | # Additionalluy, logs from specific services are forwarded to individual files on disk. 6 | loglevel = debug 7 | # Mute the "CRIT Supervisor is running as root" warning in logs. 8 | user=root 9 | # Mute the "CRIT Server 'unix_http_server' running without any HTTP authentication checking" warning in logs 10 | [unix_http_server] 11 | username = dummy 12 | password = dummy 13 | -------------------------------------------------------------------------------- /8.2/config/supervisor/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon = true 3 | # debug prints output from all services to stdout/stderr. 4 | # This way logs can be reviewed with docker logs. 5 | # Additionalluy, logs from specific services are forwarded to individual files on disk. 6 | loglevel = debug 7 | # Mute the "CRIT Supervisor is running as root" warning in logs. 8 | user=root 9 | # Mute the "CRIT Server 'unix_http_server' running without any HTTP authentication checking" warning in logs 10 | [unix_http_server] 11 | username = dummy 12 | password = dummy 13 | -------------------------------------------------------------------------------- /8.3/config/supervisor/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon = true 3 | # debug prints output from all services to stdout/stderr. 4 | # This way logs can be reviewed with docker logs. 5 | # Additionalluy, logs from specific services are forwarded to individual files on disk. 6 | loglevel = debug 7 | # Mute the "CRIT Supervisor is running as root" warning in logs. 8 | user=root 9 | # Mute the "CRIT Server 'unix_http_server' running without any HTTP authentication checking" warning in logs 10 | [unix_http_server] 11 | username = dummy 12 | password = dummy 13 | -------------------------------------------------------------------------------- /8.4/config/supervisor/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon = true 3 | # debug prints output from all services to stdout/stderr. 4 | # This way logs can be reviewed with docker logs. 5 | # Additionalluy, logs from specific services are forwarded to individual files on disk. 6 | loglevel = debug 7 | # Mute the "CRIT Supervisor is running as root" warning in logs. 8 | user=root 9 | # Mute the "CRIT Server 'unix_http_server' running without any HTTP authentication checking" warning in logs 10 | [unix_http_server] 11 | username = dummy 12 | password = dummy 13 | -------------------------------------------------------------------------------- /8.1/config/php/zz-php-fpm.conf: -------------------------------------------------------------------------------- 1 | ; PHP-FPM settings 2 | 3 | [global] 4 | ; This pid file is used for Docker healthcheck 5 | pid = /run/php-fpm.pid 6 | ; Reduce noise in logs 7 | log_level = error 8 | 9 | [www] 10 | user = docker 11 | catch_workers_output = yes 12 | listen = 0.0.0.0:9000 13 | clear_env = no 14 | ; Do not log php-fpm accesses (see web container for http access) 15 | access.log = /dev/null 16 | 17 | ; PHP (FPM) settings 18 | ; See zz-php.ini for global (CLI and FPM) PHP settings 19 | php_value[memory_limit] = 256M 20 | php_value[max_execution_time] = 300 21 | php_value[upload_max_filesize] = 500M 22 | php_value[post_max_size] = 500M 23 | php_value[max_input_vars] = 2000 24 | -------------------------------------------------------------------------------- /8.2/config/php/zz-php-fpm.conf: -------------------------------------------------------------------------------- 1 | ; PHP-FPM settings 2 | 3 | [global] 4 | ; This pid file is used for Docker healthcheck 5 | pid = /run/php-fpm.pid 6 | ; Reduce noise in logs 7 | log_level = error 8 | 9 | [www] 10 | user = docker 11 | catch_workers_output = yes 12 | listen = 0.0.0.0:9000 13 | clear_env = no 14 | ; Do not log php-fpm accesses (see web container for http access) 15 | access.log = /dev/null 16 | 17 | ; PHP (FPM) settings 18 | ; See zz-php.ini for global (CLI and FPM) PHP settings 19 | php_value[memory_limit] = 256M 20 | php_value[max_execution_time] = 300 21 | php_value[upload_max_filesize] = 500M 22 | php_value[post_max_size] = 500M 23 | php_value[max_input_vars] = 2000 24 | -------------------------------------------------------------------------------- /8.3/config/php/zz-php-fpm.conf: -------------------------------------------------------------------------------- 1 | ; PHP-FPM settings 2 | 3 | [global] 4 | ; This pid file is used for Docker healthcheck 5 | pid = /run/php-fpm.pid 6 | ; Reduce noise in logs 7 | log_level = error 8 | 9 | [www] 10 | user = docker 11 | catch_workers_output = yes 12 | listen = 0.0.0.0:9000 13 | clear_env = no 14 | ; Do not log php-fpm accesses (see web container for http access) 15 | access.log = /dev/null 16 | 17 | ; PHP (FPM) settings 18 | ; See zz-php.ini for global (CLI and FPM) PHP settings 19 | php_value[memory_limit] = 256M 20 | php_value[max_execution_time] = 300 21 | php_value[upload_max_filesize] = 500M 22 | php_value[post_max_size] = 500M 23 | php_value[max_input_vars] = 2000 24 | -------------------------------------------------------------------------------- /8.4/config/php/zz-php-fpm.conf: -------------------------------------------------------------------------------- 1 | ; PHP-FPM settings 2 | 3 | [global] 4 | ; This pid file is used for Docker healthcheck 5 | pid = /run/php-fpm.pid 6 | ; Reduce noise in logs 7 | log_level = error 8 | 9 | [www] 10 | user = docker 11 | catch_workers_output = yes 12 | listen = 0.0.0.0:9000 13 | clear_env = no 14 | ; Do not log php-fpm accesses (see web container for http access) 15 | access.log = /dev/null 16 | 17 | ; PHP (FPM) settings 18 | ; See zz-php.ini for global (CLI and FPM) PHP settings 19 | php_value[memory_limit] = 256M 20 | php_value[max_execution_time] = 300 21 | php_value[upload_max_filesize] = 500M 22 | php_value[post_max_size] = 500M 23 | php_value[max_input_vars] = 2000 24 | -------------------------------------------------------------------------------- /8.1/config/php/xdebug.ini: -------------------------------------------------------------------------------- 1 | [xdebug] 2 | zend_extension=xdebug.so 3 | ; See https://xdebug.org/docs/all_settings#mode 4 | xdebug.mode=debug 5 | ; xdebug.xdebug.client_host defaults to "localhost", which works with VS Code Server web IDE running locally 6 | ; For debugging from a "remote" host, xdebug.xdebug.client_host is set to ${DOCKSAL_HOST_IP} at runtime 7 | ; xdebug.xdebug.client_port defaults to "9003" in Xdebug 3. We use 9000 instead for backward compatibility with Xdebug 2. 8 | xdebug.client_port=9000 9 | ; TODO: Why do we have to set this? 10 | xdebug.idekey=xdebug_session 11 | ; Increase max_nesting_level to support complex Drupal pages (default is 100) 12 | xdebug.max_nesting_level=256 13 | -------------------------------------------------------------------------------- /8.2/config/php/xdebug.ini: -------------------------------------------------------------------------------- 1 | [xdebug] 2 | zend_extension=xdebug.so 3 | ; See https://xdebug.org/docs/all_settings#mode 4 | xdebug.mode=debug 5 | ; xdebug.xdebug.client_host defaults to "localhost", which works with VS Code Server web IDE running locally 6 | ; For debugging from a "remote" host, xdebug.xdebug.client_host is set to ${DOCKSAL_HOST_IP} at runtime 7 | ; xdebug.xdebug.client_port defaults to "9003" in Xdebug 3. We use 9000 instead for backward compatibility with Xdebug 2. 8 | xdebug.client_port=9000 9 | ; TODO: Why do we have to set this? 10 | xdebug.idekey=xdebug_session 11 | ; Increase max_nesting_level to support complex Drupal pages (default is 100) 12 | xdebug.max_nesting_level=256 13 | -------------------------------------------------------------------------------- /8.3/config/php/xdebug.ini: -------------------------------------------------------------------------------- 1 | [xdebug] 2 | zend_extension=xdebug.so 3 | ; See https://xdebug.org/docs/all_settings#mode 4 | xdebug.mode=debug 5 | ; xdebug.xdebug.client_host defaults to "localhost", which works with VS Code Server web IDE running locally 6 | ; For debugging from a "remote" host, xdebug.xdebug.client_host is set to ${DOCKSAL_HOST_IP} at runtime 7 | ; xdebug.xdebug.client_port defaults to "9003" in Xdebug 3. We use 9000 instead for backward compatibility with Xdebug 2. 8 | xdebug.client_port=9000 9 | ; TODO: Why do we have to set this? 10 | xdebug.idekey=xdebug_session 11 | ; Increase max_nesting_level to support complex Drupal pages (default is 100) 12 | xdebug.max_nesting_level=256 13 | -------------------------------------------------------------------------------- /8.4/config/php/xdebug.ini: -------------------------------------------------------------------------------- 1 | [xdebug] 2 | zend_extension=xdebug.so 3 | ; See https://xdebug.org/docs/all_settings#mode 4 | xdebug.mode=debug 5 | ; xdebug.xdebug.client_host defaults to "localhost", which works with VS Code Server web IDE running locally 6 | ; For debugging from a "remote" host, xdebug.xdebug.client_host is set to ${DOCKSAL_HOST_IP} at runtime 7 | ; xdebug.xdebug.client_port defaults to "9003" in Xdebug 3. We use 9000 instead for backward compatibility with Xdebug 2. 8 | xdebug.client_port=9000 9 | ; TODO: Why do we have to set this? 10 | xdebug.idekey=xdebug_session 11 | ; Increase max_nesting_level to support complex Drupal pages (default is 100) 12 | xdebug.max_nesting_level=256 13 | -------------------------------------------------------------------------------- /tests/docroot/php-fpm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export SCRIPT_FILENAME="/var/www/docroot/${1}" 4 | export REQUEST_URI=/ 5 | export QUERY_STRING= 6 | export REQUEST_METHOD=GET 7 | 8 | # "sed 's/\xC2\xA0/ /g'" - replaces non-breaking spaces ( ) with regular spaces. 9 | # This can be a nightmare to debug, since nbsp's are identical to spaces in a text editor. 10 | # Note: this sed does NOT work on Mac, so make sure it's only run inside a container. 11 | # See https://superuser.com/questions/517847/use-sed-to-replace-nbsp-160-hex-00a0-octal-240-non-breaking-space 12 | # "-width 1024" prevents text wrapping for long values (e.g. sendmail_path) 13 | cgi-fcgi -bind -connect 127.0.0.1:9000 | html2text -width 1024 | sed 's/\xC2\xA0/ /g' 14 | -------------------------------------------------------------------------------- /8.1/config/code-server/User/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // XDebug Launch Configuration settings 3 | "launch": { 4 | "version": "0.2.0", 5 | "configurations": [ 6 | // Listener mode (recommended for most cases) 7 | // Can be used to debug both: web and cli PHP sessions. 8 | { 9 | "name": "XDebug (listener)", 10 | "type": "php", 11 | "request": "launch", 12 | "port": 9000 13 | }, 14 | // Current script mode 15 | // Note: IDE launches the script inside of the ide container and not the cli container. 16 | { 17 | "name": "XDebug (currently open script)", 18 | "type": "php", 19 | "request": "launch", 20 | "program": "${file}", 21 | "cwd": "${fileDirname}", 22 | "port": 9000 23 | } 24 | ] 25 | }, 26 | // File associations 27 | "files.associations": { 28 | "*.inc": "php", 29 | "*.module": "php", 30 | "*.install": "php", 31 | "*.theme": "php", 32 | "*.tpl.php": "php", 33 | "*.test": "php", 34 | "*.php": "php" 35 | }, 36 | "workbench.colorTheme": "Default Dark+" 37 | } 38 | -------------------------------------------------------------------------------- /8.2/config/code-server/User/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // XDebug Launch Configuration settings 3 | "launch": { 4 | "version": "0.2.0", 5 | "configurations": [ 6 | // Listener mode (recommended for most cases) 7 | // Can be used to debug both: web and cli PHP sessions. 8 | { 9 | "name": "XDebug (listener)", 10 | "type": "php", 11 | "request": "launch", 12 | "port": 9000 13 | }, 14 | // Current script mode 15 | // Note: IDE launches the script inside of the ide container and not the cli container. 16 | { 17 | "name": "XDebug (currently open script)", 18 | "type": "php", 19 | "request": "launch", 20 | "program": "${file}", 21 | "cwd": "${fileDirname}", 22 | "port": 9000 23 | } 24 | ] 25 | }, 26 | // File associations 27 | "files.associations": { 28 | "*.inc": "php", 29 | "*.module": "php", 30 | "*.install": "php", 31 | "*.theme": "php", 32 | "*.tpl.php": "php", 33 | "*.test": "php", 34 | "*.php": "php" 35 | }, 36 | "workbench.colorTheme": "Default Dark+" 37 | } 38 | -------------------------------------------------------------------------------- /8.3/config/code-server/User/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // XDebug Launch Configuration settings 3 | "launch": { 4 | "version": "0.2.0", 5 | "configurations": [ 6 | // Listener mode (recommended for most cases) 7 | // Can be used to debug both: web and cli PHP sessions. 8 | { 9 | "name": "XDebug (listener)", 10 | "type": "php", 11 | "request": "launch", 12 | "port": 9000 13 | }, 14 | // Current script mode 15 | // Note: IDE launches the script inside of the ide container and not the cli container. 16 | { 17 | "name": "XDebug (currently open script)", 18 | "type": "php", 19 | "request": "launch", 20 | "program": "${file}", 21 | "cwd": "${fileDirname}", 22 | "port": 9000 23 | } 24 | ] 25 | }, 26 | // File associations 27 | "files.associations": { 28 | "*.inc": "php", 29 | "*.module": "php", 30 | "*.install": "php", 31 | "*.theme": "php", 32 | "*.tpl.php": "php", 33 | "*.test": "php", 34 | "*.php": "php" 35 | }, 36 | "workbench.colorTheme": "Default Dark+" 37 | } 38 | -------------------------------------------------------------------------------- /8.4/config/code-server/User/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // XDebug Launch Configuration settings 3 | "launch": { 4 | "version": "0.2.0", 5 | "configurations": [ 6 | // Listener mode (recommended for most cases) 7 | // Can be used to debug both: web and cli PHP sessions. 8 | { 9 | "name": "XDebug (listener)", 10 | "type": "php", 11 | "request": "launch", 12 | "port": 9000 13 | }, 14 | // Current script mode 15 | // Note: IDE launches the script inside of the ide container and not the cli container. 16 | { 17 | "name": "XDebug (currently open script)", 18 | "type": "php", 19 | "request": "launch", 20 | "program": "${file}", 21 | "cwd": "${fileDirname}", 22 | "port": 9000 23 | } 24 | ] 25 | }, 26 | // File associations 27 | "files.associations": { 28 | "*.inc": "php", 29 | "*.module": "php", 30 | "*.install": "php", 31 | "*.theme": "php", 32 | "*.tpl.php": "php", 33 | "*.test": "php", 34 | "*.php": "php" 35 | }, 36 | "workbench.colorTheme": "Default Dark+" 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2025 Docksal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /8.1/tests/essential-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | binaries_amd64=\ 4 | 'bundler 5 | cat 6 | convert 7 | curl 8 | dig 9 | g++ 10 | ghostscript 11 | git 12 | git-lfs 13 | gcc 14 | jq 15 | html2text 16 | less 17 | make 18 | mc 19 | more 20 | mysql 21 | nano 22 | node 23 | nvm 24 | nslookup 25 | php 26 | ping 27 | pip 28 | psql 29 | pv 30 | python3 31 | rsync 32 | ruby 33 | sudo 34 | unzip 35 | wget 36 | yq 37 | zip' 38 | 39 | binaries_arm64=\ 40 | 'bundler 41 | cat 42 | convert 43 | curl 44 | dig 45 | g++ 46 | ghostscript 47 | git 48 | git-lfs 49 | gcc 50 | jq 51 | html2text 52 | less 53 | make 54 | mc 55 | more 56 | mysql 57 | nano 58 | node 59 | nvm 60 | nslookup 61 | php 62 | ping 63 | psql 64 | pv 65 | python3 66 | rsync 67 | ruby 68 | sudo 69 | unzip 70 | wget 71 | yq 72 | zip' 73 | 74 | # Use the docker reported architecture and not the hosts (uname -m). 75 | # docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). 76 | case "$(docker info -f '{{ .Architecture }}')" in 77 | x86_64) echo "${binaries_amd64}" ;; 78 | amd64) echo "${binaries_amd64}" ;; 79 | aarch64) echo "${binaries_arm64}" ;; 80 | arm64) echo "${binaries_arm64}" ;; 81 | * ) false;; 82 | esac 83 | -------------------------------------------------------------------------------- /8.2/tests/essential-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | binaries_amd64=\ 4 | 'bundler 5 | cat 6 | convert 7 | curl 8 | dig 9 | g++ 10 | ghostscript 11 | git 12 | git-lfs 13 | gcc 14 | jq 15 | html2text 16 | less 17 | make 18 | mc 19 | more 20 | mysql 21 | nano 22 | node 23 | nvm 24 | nslookup 25 | php 26 | ping 27 | pip 28 | psql 29 | pv 30 | python3 31 | rsync 32 | ruby 33 | sudo 34 | unzip 35 | wget 36 | yq 37 | zip' 38 | 39 | binaries_arm64=\ 40 | 'bundler 41 | cat 42 | convert 43 | curl 44 | dig 45 | g++ 46 | ghostscript 47 | git 48 | git-lfs 49 | gcc 50 | jq 51 | html2text 52 | less 53 | make 54 | mc 55 | more 56 | mysql 57 | nano 58 | node 59 | nvm 60 | nslookup 61 | php 62 | ping 63 | psql 64 | pv 65 | python3 66 | rsync 67 | ruby 68 | sudo 69 | unzip 70 | wget 71 | yq 72 | zip' 73 | 74 | # Use the docker reported architecture and not the hosts (uname -m). 75 | # docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). 76 | case "$(docker info -f '{{ .Architecture }}')" in 77 | x86_64) echo "${binaries_amd64}" ;; 78 | amd64) echo "${binaries_amd64}" ;; 79 | aarch64) echo "${binaries_arm64}" ;; 80 | arm64) echo "${binaries_arm64}" ;; 81 | * ) false;; 82 | esac 83 | -------------------------------------------------------------------------------- /8.3/tests/essential-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | binaries_amd64=\ 4 | 'bundler 5 | cat 6 | convert 7 | curl 8 | dig 9 | g++ 10 | ghostscript 11 | git 12 | git-lfs 13 | gcc 14 | jq 15 | html2text 16 | less 17 | make 18 | mc 19 | more 20 | mysql 21 | nano 22 | node 23 | nvm 24 | nslookup 25 | php 26 | ping 27 | pip 28 | psql 29 | pv 30 | python3 31 | rsync 32 | ruby 33 | sudo 34 | unzip 35 | wget 36 | yq 37 | zip' 38 | 39 | binaries_arm64=\ 40 | 'bundler 41 | cat 42 | convert 43 | curl 44 | dig 45 | g++ 46 | ghostscript 47 | git 48 | git-lfs 49 | gcc 50 | jq 51 | html2text 52 | less 53 | make 54 | mc 55 | more 56 | mysql 57 | nano 58 | node 59 | nvm 60 | nslookup 61 | php 62 | ping 63 | psql 64 | pv 65 | python3 66 | rsync 67 | ruby 68 | sudo 69 | unzip 70 | wget 71 | yq 72 | zip' 73 | 74 | # Use the docker reported architecture and not the hosts (uname -m). 75 | # docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). 76 | case "$(docker info -f '{{ .Architecture }}')" in 77 | x86_64) echo "${binaries_amd64}" ;; 78 | amd64) echo "${binaries_amd64}" ;; 79 | aarch64) echo "${binaries_arm64}" ;; 80 | arm64) echo "${binaries_arm64}" ;; 81 | * ) false;; 82 | esac 83 | -------------------------------------------------------------------------------- /8.4/tests/essential-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | binaries_amd64=\ 4 | 'bundler 5 | cat 6 | convert 7 | curl 8 | dig 9 | g++ 10 | ghostscript 11 | git 12 | git-lfs 13 | gcc 14 | jq 15 | html2text 16 | less 17 | make 18 | mc 19 | more 20 | mysql 21 | nano 22 | node 23 | nvm 24 | nslookup 25 | php 26 | ping 27 | pip 28 | psql 29 | pv 30 | python3 31 | rsync 32 | ruby 33 | sudo 34 | unzip 35 | wget 36 | yq 37 | zip' 38 | 39 | binaries_arm64=\ 40 | 'bundler 41 | cat 42 | convert 43 | curl 44 | dig 45 | g++ 46 | ghostscript 47 | git 48 | git-lfs 49 | gcc 50 | jq 51 | html2text 52 | less 53 | make 54 | mc 55 | more 56 | mysql 57 | nano 58 | node 59 | nvm 60 | nslookup 61 | php 62 | ping 63 | psql 64 | pv 65 | python3 66 | rsync 67 | ruby 68 | sudo 69 | unzip 70 | wget 71 | yq 72 | zip' 73 | 74 | # Use the docker reported architecture and not the hosts (uname -m). 75 | # docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). 76 | case "$(docker info -f '{{ .Architecture }}')" in 77 | x86_64) echo "${binaries_amd64}" ;; 78 | amd64) echo "${binaries_amd64}" ;; 79 | aarch64) echo "${binaries_arm64}" ;; 80 | arm64) echo "${binaries_arm64}" ;; 81 | * ) false;; 82 | esac 83 | -------------------------------------------------------------------------------- /.github/scripts/docker-tag-delete.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Deletes an image tag from Docker Hub 4 | # 5 | # Expects USER, PASSWORD 6 | # Expects IMAGE:TAG as argument. 7 | # 8 | # Example: docker-tag-delete.sh docksal/cli:php7.3-build-01c92a2-amd64 9 | 10 | # Credit: 11 | # https://devopsheaven.com/docker/dockerhub/2018/04/09/delete-docker-image-tag-dockerhub.html 12 | 13 | set -euo pipefail 14 | 15 | # Get IMAGE and TAG from first argument 16 | if [[ "${1}" == "" ]]; then 17 | echo "Usage: ${0} image:tag" 18 | exit 1 19 | else 20 | # Split image:tag 21 | IFS=$':' read IMAGE TAG <<< "${1}"; 22 | # Remove registry prefix from image if present 23 | IMAGE=${IMAGE#"docker.io/"} 24 | fi 25 | 26 | login_data() { 27 | cat </dev/null 2>&1 || true 74 | 75 | tags: 76 | @../.github/scripts/docker-tags.sh 77 | -------------------------------------------------------------------------------- /8.2/Makefile: -------------------------------------------------------------------------------- 1 | -include ../tests/env_make 2 | -include env_make 3 | 4 | IMAGE ?= docksal/cli 5 | VERSION_PREFIX ?= php 6 | VERSION ?= 8.2 7 | BUILD_IMAGE_TAG ?= $(IMAGE):$(VERSION_PREFIX)$(VERSION)-build 8 | NAME = docksal-cli-$(VERSION)-$(GIT_SHA7) 9 | CWD = $(shell pwd) 10 | 11 | # Improve write performance for /home/docker by turning it into a volume 12 | VOLUMES = -v /home/docker 13 | 14 | .EXPORT_ALL_VARIABLES: 15 | 16 | .PHONY: build exec test push shell run start stop logs clean release 17 | 18 | default: build 19 | 20 | build: 21 | docker build -t $(BUILD_IMAGE_TAG) . 22 | 23 | # See https://docs.docker.com/buildx/working-with-buildx/ 24 | # See https://github.com/docker/buildx 25 | buildx: 26 | docker buildx build --tag $(BUILD_IMAGE_TAG) . 27 | buildx-with-cache: 28 | docker buildx build --cache-from=type=registry,ref=$(BUILD_IMAGE_TAG) --cache-to=type=inline --tag=$(BUILD_IMAGE_TAG) . 29 | 30 | test: 31 | NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats 32 | 33 | push: 34 | docker push $(BUILD_IMAGE_TAG) 35 | 36 | run: clean 37 | docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 38 | 39 | # Copy files into container instead of mounting from the host at runtime. 40 | # This allows running tests on a remote docker instance. 41 | start: clean 42 | docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 43 | docker cp ../tests/. $(NAME):/var/www/ 44 | docker start $(NAME) 45 | 46 | # Only copy docroot (not config overrides) 47 | start-bare: clean 48 | docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 49 | docker cp ../tests/docroot/. $(NAME):/var/www/docroot/ 50 | docker start $(NAME) 51 | 52 | # Non-interactive and non-tty docker exec (uses LF instead of CRLF line endings) 53 | exec: 54 | @docker exec -u docker $(NAME) bash -lc "$(CMD)" 55 | 56 | # Interactive docker exec 57 | exec-it: 58 | @docker exec -u docker -it $(NAME) bash -ilc "$(CMD)" 59 | 60 | shell: 61 | @docker exec -u docker -it $(NAME) bash -il 62 | 63 | stop: 64 | docker stop $(NAME) 65 | 66 | logs: 67 | docker logs $(NAME) 68 | 69 | logs-follow: 70 | docker logs -f $(NAME) 71 | 72 | clean: 73 | docker rm -vf $(NAME) >/dev/null 2>&1 || true 74 | 75 | tags: 76 | @../.github/scripts/docker-tags.sh 77 | -------------------------------------------------------------------------------- /8.3/Makefile: -------------------------------------------------------------------------------- 1 | -include ../tests/env_make 2 | -include env_make 3 | 4 | IMAGE ?= docksal/cli 5 | VERSION_PREFIX ?= php 6 | VERSION ?= 8.3 7 | BUILD_IMAGE_TAG ?= $(IMAGE):$(VERSION_PREFIX)$(VERSION)-build 8 | NAME = docksal-cli-$(VERSION)-$(GIT_SHA7) 9 | CWD = $(shell pwd) 10 | 11 | # Improve write performance for /home/docker by turning it into a volume 12 | VOLUMES = -v /home/docker 13 | 14 | .EXPORT_ALL_VARIABLES: 15 | 16 | .PHONY: build exec test push shell run start stop logs clean release 17 | 18 | default: build 19 | 20 | build: 21 | docker build -t $(BUILD_IMAGE_TAG) . 22 | 23 | # See https://docs.docker.com/buildx/working-with-buildx/ 24 | # See https://github.com/docker/buildx 25 | buildx: 26 | docker buildx build --tag $(BUILD_IMAGE_TAG) . 27 | buildx-with-cache: 28 | docker buildx build --cache-from=type=registry,ref=$(BUILD_IMAGE_TAG) --cache-to=type=inline --tag=$(BUILD_IMAGE_TAG) . 29 | 30 | test: 31 | NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats 32 | 33 | push: 34 | docker push $(BUILD_IMAGE_TAG) 35 | 36 | run: clean 37 | docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 38 | 39 | # Copy files into container instead of mounting from the host at runtime. 40 | # This allows running tests on a remote docker instance. 41 | start: clean 42 | docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 43 | docker cp ../tests/. $(NAME):/var/www/ 44 | docker start $(NAME) 45 | 46 | # Only copy docroot (not config overrides) 47 | start-bare: clean 48 | docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 49 | docker cp ../tests/docroot/. $(NAME):/var/www/docroot/ 50 | docker start $(NAME) 51 | 52 | # Non-interactive and non-tty docker exec (uses LF instead of CRLF line endings) 53 | exec: 54 | @docker exec -u docker $(NAME) bash -lc "$(CMD)" 55 | 56 | # Interactive docker exec 57 | exec-it: 58 | @docker exec -u docker -it $(NAME) bash -ilc "$(CMD)" 59 | 60 | shell: 61 | @docker exec -u docker -it $(NAME) bash -il 62 | 63 | stop: 64 | docker stop $(NAME) 65 | 66 | logs: 67 | docker logs $(NAME) 68 | 69 | logs-follow: 70 | docker logs -f $(NAME) 71 | 72 | clean: 73 | docker rm -vf $(NAME) >/dev/null 2>&1 || true 74 | 75 | tags: 76 | @../.github/scripts/docker-tags.sh 77 | -------------------------------------------------------------------------------- /8.4/Makefile: -------------------------------------------------------------------------------- 1 | -include ../tests/env_make 2 | -include env_make 3 | 4 | IMAGE ?= docksal/cli 5 | VERSION_PREFIX ?= php 6 | VERSION ?= 8.4 7 | BUILD_IMAGE_TAG ?= $(IMAGE):$(VERSION_PREFIX)$(VERSION)-build 8 | NAME = docksal-cli-$(VERSION)-$(GIT_SHA7) 9 | CWD = $(shell pwd) 10 | 11 | # Improve write performance for /home/docker by turning it into a volume 12 | VOLUMES = -v /home/docker 13 | 14 | .EXPORT_ALL_VARIABLES: 15 | 16 | .PHONY: build exec test push shell run start stop logs clean release 17 | 18 | default: build 19 | 20 | build: 21 | docker build -t $(BUILD_IMAGE_TAG) . 22 | 23 | # See https://docs.docker.com/buildx/working-with-buildx/ 24 | # See https://github.com/docker/buildx 25 | buildx: 26 | docker buildx build --tag $(BUILD_IMAGE_TAG) . 27 | buildx-with-cache: 28 | docker buildx build --cache-from=type=registry,ref=$(BUILD_IMAGE_TAG) --cache-to=type=inline --tag=$(BUILD_IMAGE_TAG) . 29 | 30 | test: 31 | NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats 32 | 33 | push: 34 | docker push $(BUILD_IMAGE_TAG) 35 | 36 | run: clean 37 | docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 38 | 39 | # Copy files into container instead of mounting from the host at runtime. 40 | # This allows running tests on a remote docker instance. 41 | start: clean 42 | docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 43 | docker cp ../tests/. $(NAME):/var/www/ 44 | docker start $(NAME) 45 | 46 | # Only copy docroot (not config overrides) 47 | start-bare: clean 48 | docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) 49 | docker cp ../tests/docroot/. $(NAME):/var/www/docroot/ 50 | docker start $(NAME) 51 | 52 | # Non-interactive and non-tty docker exec (uses LF instead of CRLF line endings) 53 | exec: 54 | @docker exec -u docker $(NAME) bash -lc "$(CMD)" 55 | 56 | # Interactive docker exec 57 | exec-it: 58 | @docker exec -u docker -it $(NAME) bash -ilc "$(CMD)" 59 | 60 | shell: 61 | @docker exec -u docker -it $(NAME) bash -il 62 | 63 | stop: 64 | docker stop $(NAME) 65 | 66 | logs: 67 | docker logs $(NAME) 68 | 69 | logs-follow: 70 | docker logs -f $(NAME) 71 | 72 | clean: 73 | docker rm -vf $(NAME) >/dev/null 2>&1 || true 74 | 75 | tags: 76 | @../.github/scripts/docker-tags.sh 77 | -------------------------------------------------------------------------------- /.github/scripts/docker-tags.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Generates docker images tags for the docker/build-push-action@v2 action depending on the branch/tag. 4 | # Image tag format: 5 | # develop => image:[version_prefix][version-]edge[-version_suffix] 6 | # master => image:[version_prefix][version][-][version_suffix] 7 | # semver tag => image:[version_prefix][version-]major.minor[-version_suffix] 8 | 9 | # Declare expected variables 10 | IMAGE=${IMAGE} # docksal/cli 11 | VERSION_PREFIX=${VERSION_PREFIX} # php 12 | VERSION=${VERSION} # 8.1 13 | VERSION_SUFFIX=${VERSION_SUFFIX} # ide 14 | REGISTRY="${REGISTRY}" # ghcr.io 15 | GITHUB_REF=${GITHUB_REF} # refs/heads/develop, refs/heads/master, refs/tags/v1.0.0 16 | 17 | # Join arguments with hyphen (-) as a delimiter 18 | # Usage: join [] 19 | join() { 20 | local IFS='-' # join delimiter 21 | echo "$*" 22 | } 23 | 24 | # Prints resulting image tags and sets output variable 25 | set_output() { 26 | local -n inputArr=${1} 27 | 28 | declare -a outputArr 29 | for imageTag in ${inputArr[@]}; do 30 | # Prepend registry to imageTag if provided 31 | [[ "${REGISTRY}" != "" ]] && imageTag="${REGISTRY}/${imageTag}" 32 | outputArr+=("${imageTag}") 33 | done 34 | 35 | # Print with new lines for output in build logs 36 | (IFS=$'\n'; echo "${outputArr[*]}") 37 | # Using newlines in output variables does not seem to work, so we'll use comas 38 | (IFS=$','; echo tags="${outputArr[*]}" | tee -a ${GITHUB_OUTPUT}) 39 | } 40 | 41 | # Image tags 42 | declare -a imageTagArr 43 | 44 | ## On every build => build / build-sha7 45 | ## Latest build tag (used with cache-from) 46 | #imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX} build)") 47 | ## Specific build tag - SHA7 (first 7 characters of commit SHA) 48 | #imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX} build ${GITHUB_SHA:0:7})") 49 | 50 | # develop => version-edge 51 | if [[ "${GITHUB_REF}" == "refs/heads/develop" ]]; then 52 | imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} edge ${VERSION_SUFFIX})") 53 | fi 54 | 55 | # master => version 56 | if [[ "${GITHUB_REF}" == "refs/heads/master" ]]; then 57 | imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX})") 58 | fi 59 | 60 | # tags/v1.0.0 => 1.0 61 | if [[ "${GITHUB_REF}" =~ "refs/tags/" ]]; then 62 | # Extract version parts from release tag 63 | IFS='.' read -a release_arr <<< "${GITHUB_REF#refs/tags/}" 64 | releaseMajor=${release_arr[0]#v*} # 2.7.0 => "2" 65 | releaseMinor=${release_arr[1]} # "2.7.0" => "7" 66 | imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX})") 67 | imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${releaseMajor} ${VERSION_SUFFIX})") 68 | imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${releaseMajor}.${releaseMinor} ${VERSION_SUFFIX})") 69 | fi 70 | 71 | # Note: imageTagArr is passed as variable name ("reference") and then expanded inside the called function 72 | # See https://stackoverflow.com/questions/16461656/how-to-pass-array-as-an-argument-to-a-function-in-bash/26443029#26443029 73 | # DockerHub tags 74 | set_output imageTagArr 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CLI Docker image for Docksal 2 | 3 | This image focuses on console tools necessary to develop LAMP stack (and other web) applications. 4 | 5 | This image(s) is part of the [Docksal](https://docksal.io) image library. 6 | 7 | ## Features 8 | 9 | - Based on the official php-fpm Debian 12 (bookworm) images 10 | - php/php-fpm (w/ xdebug), nodejs (via nvm), python, ruby 11 | - Framework specific tools for Drupal and Wordpress 12 | - Miscellaneous cli tools for day to day web development 13 | - Hosting provider cli tools (Acquia, Pantheon, Platform.sh) 14 | - Cron job scheduling 15 | - Custom startup script support 16 | - [VS Code Server](https://github.com/cdr/code-server) (VS Code in the browser) 17 | - Multi-platform images (amd64/arm64) starting with v3.0.0 18 | 19 | ## Versions and image tag naming convention 20 | 21 | - Stable image versions 22 | - `docksal/cli:php8.1-3.10`, `docksal/cli:php8.1` - PHP 8.1 23 | - `docksal/cli:php8.2-3.10`, `docksal/cli:php8.2` - PHP 8.2 24 | - `docksal/cli:php8.3-3.10`, `docksal/cli:php8.3` - PHP 8.3 25 | - `docksal/cli:php8.4-3.10`, `docksal/cli:php8.4`, `docksal/cli:latest` - PHP 8.4 26 | - Development image versions 27 | - `docksal/cli:php8.1-edge` - PHP 8.1 28 | - `docksal/cli:php8.2-edge` - PHP 8.2 29 | - `docksal/cli:php8.3-edge` - PHP 8.3 30 | - `docksal/cli:php8.3-edge` - PHP 8.3 31 | 32 | ## PHP 33 | 34 | - php-fpm && php-cli 35 | - xdebug v3 36 | - composer v1 & v2 37 | - drush (Drupal) 38 | - coder-8.x + phpcs 39 | - drupal console launcher (Drupal) 40 | - wp-cli (Wordpress) 41 | 42 | This image uses the official `php-fpm` images from [Docker Hub](https://hub.docker.com/_/php/) as the base. 43 | 44 | Additional PHP extensions can be installed via the `install-php-extensions` tool ([mlocati/docker-php-extension-installer](https://github.com/mlocati/docker-php-extension-installer)). 45 | 46 | ### Available PHP database drivers 47 | 48 | - SQLite - via `sqlite3`, `pdo_sqlite` 49 | - MySQL - via `mysqli`, `mysqlnd`, `pdo_mysql` 50 | - PostgreSQL - via `pgsql`, `pdo_pgsql` 51 | - MSSQL - via `sqlsrv` and `pdo_sqlsrv` 52 | 53 | ### Using PHP Xdebug 54 | 55 | Xdebug is disabled by default. 56 | 57 | To enable it, run the image with `XDEBUG_ENABLED=1`: 58 | 59 | ```yml 60 | cli 61 | ... 62 | environment: 63 | ... 64 | - XDEBUG_ENABLED=1 65 | ... 66 | ``` 67 | 68 | [See docs](https://docs.docksal.io/tools/xdebug/) on using Xdebug for web and cli PHP debugging. 69 | 70 | ## NodeJS 71 | 72 | - nvm 73 | - node v22.20.0 LTS (following NodeJS LTS release cycle) 74 | - yarn (classic v1) 75 | 76 | NodeJS is installed via `nvm` in the `docker` user's profile inside the image (`/home/docker/.nvm`). 77 | 78 | If you need a different version of node, use `nvm` to install it, e.g., `nvm install 23.11.0`. 79 | Then, use `nvm use 23.11.0` to use it in the current session or `nvm alias default 23.11.0` to use it by default. 80 | 81 | ## Python 82 | 83 | This image comes with a system level installed Python v3.9.x from upstream Debian 11. 84 | 85 | ## Ruby 86 | 87 | This image comes with a system level installed Ruby v2.7.x from upstream Debian 11. 88 | 89 | ## Notable console tools 90 | 91 | - git with git-lfs 92 | - curl, wget 93 | - zip, unzip 94 | - jq, yq 95 | - mysql, pgsql, and sqlsrv cli clients 96 | - imagemagick, ghostscript 97 | - mc, nano, rsync 98 | - cron 99 | 100 | ## Hosting provider tools 101 | 102 | - `acli` for Acquia Cloud APIv2 ([Acquia](https://docs.acquia.com/acquia-cloud-platform/add-ons/acquia-cli/docs)) 103 | - `terminus` ([Pantheon](https://pantheon.io/platform/command-line-interface-cli)) 104 | - `platform` ([Platform.sh](https://docs.platform.sh/administration/cli.html)) 105 | 106 | Also, see the [Secrets](#secrets) section below for more information on managing and using your hosting provider keys. 107 | 108 | ## Customizing startup 109 | 110 | To run a custom startup script anytime the `cli` container has started, create a `startup.sh` file within the 111 | `.docksal/services/cli` directory. Additionally, make sure that the file is executable as well so that the container 112 | does not run into issues when attempting to execute the file. 113 | 114 | ## Scheduling cron jobs 115 | 116 | Cron can be configured by making sure there is a `crontab` file located within `.docksal/services/cli`. The file should 117 | follow the [standard crontab format](http://www.nncron.ru/help/EN/working/cron-format.htm). 118 | 119 | 120 | 121 | ## Secrets and integrations 122 | 123 | `cli` can read secrets from environment variables and configure the respective integrations automatically at start. 124 | 125 | The recommended place store secrets in Docksal is the global `$HOME/.docksal/docksal.env` file on the host. From there, 126 | secrets are injected into the `cli` container's environment. 127 | 128 | Below is the list of secrets currently supported. 129 | 130 | `SECRET_SSH_PRIVATE_KEY` 131 | 132 | Use to pass a private SSH key. The key will be stored in `/home/docker/.ssh/id_rsa` inside `cli` and will be considered 133 | by the SSH client **in addition** to the keys loaded in `docksal-ssh-agent` when establishing a SSH connection 134 | from within `cli`. 135 | 136 | This is useful when you need a project stack to inherit a private SSH key that is not shared with other project stacks 137 | on the same host (e.g., in shared CI environments). 138 | 139 | The value must be base64 encoded, i.e.: 140 | 141 | ```bash 142 | cat /path/to/some_key_rsa | base64 143 | ``` 144 | 145 | `SECRET_ACQUIA_CLI_KEY` and `SECRET_ACQUIA_CLI_SECRET` 146 | 147 | Credentials used to authenticate [Acquia CLI](https://github.com/acquia/cli) with Acquia Cloud APIv2. 148 | Stored as `ACQUIA_CLI_KEY` and `ACQUIA_CLI_SECRET` environment variables inside `cli`. 149 | 150 | Acquia CLI is installed and available globally in `cli` as `acli`. 151 | 152 | `SECRET_TERMINUS_TOKEN` 153 | 154 | Credentials used to authenticate [Terminus](https://pantheon.io/docs/terminus) with Pantheon. 155 | Stored in `/home/docker/.terminus/` inside `cli`. 156 | 157 | Terminus is installed and available globally in `cli` as `terminus`. 158 | 159 | `SECRET_PLATFORMSH_CLI_TOKEN` 160 | 161 | Credentials used to authenticate with the [Platform.sh CLI](https://github.com/platformsh/platformsh-cli) tool. 162 | Stored in `/home/docker/.platform` inside `cli`. 163 | 164 | Platform CLI is installed and available globally in `cli` as `platform`. 165 | 166 | `WEB_KEEPALIVE` 167 | 168 | Sets the delay in seconds between pings of the web container during execution `fin exec`. Setting this variable to non zero value prevents the project from stopping in cases of long `fin exec` and web container inactivity. Disabled by default (set to 0). 169 | 170 | ## Git configuration 171 | 172 | When working with git from within the image, it will ask for the `user.email` and `user.name` set before you can commit. 173 | These can be passed as environment variables and will be applied at the container startup. 174 | 175 | ``` 176 | GIT_USER_EMAIL="git@example.com" 177 | GIT_USER_NAME="Docksal CLI" 178 | ``` 179 | 180 | 181 | ## Coder (Visual Studio Code web IDE) 182 | 183 | [Coder](https://coder.com/) is a free, open-source web IDE. 184 | 185 | VS Code Server is pre-installed along with GitLens and PHP Xdebug extensions. 186 | 187 | ### Configuration 188 | 189 | `IDE_ENABLED` (default: 0) 190 | 191 | Set to `1` to start the image in IDE mode. VS Code web UI will is listening on port `8080`. 192 | 193 | `IDE_PASSWORD` (default: '') 194 | 195 | Store your preferred password in this variable if you need to password protect the IDE environment. 196 | 197 | [See docs](https://docs.docksal.io/tools/ide/) for instructions on using Coder in Docksal. 198 | 199 | ## Composer 200 | 201 | Composer v1 and v2 are both installed in the container. v2 is set as the default version, but while not all 202 | projects may be able to work with v2 quite yet, v1 is available by setting the `COMPOSER_DEFAULT_VERSION` variable to `1`. 203 | 204 | Example: 205 | 206 | ``` 207 | services: 208 | cli: 209 | environment: 210 | - COMPOSER_DEFAULT_VERSION=1 211 | ``` 212 | 213 | The following Composer optimization packages are no longer relevant/compatible with Composer v2 and have been dropped: 214 | 215 | - [hirak/prestissimo](https://github.com/hirak/prestissimo) 216 | - [zaporylie/composer-drupal-optimizations](https://github.com/zaporylie/composer-drupal-optimizations) 217 | 218 | To benefit from these optimizations with Composer v1, you would need to pin the image to an older version. 219 | See Docksal [documentation](https://docs.docksal.io/service/cli/settings#composer) for more details. 220 | -------------------------------------------------------------------------------- /8.1/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is running as root by default. 4 | # Switching to the docker user can be done via "gosu docker ". 5 | 6 | HOME_DIR='/home/docker' 7 | 8 | DEBUG=${DEBUG:-0} 9 | # Turn debugging ON when cli is started in the service mode 10 | [[ "$1" == "supervisord" ]] && DEBUG=1 11 | echo-debug () 12 | { 13 | [[ "$DEBUG" != 0 ]] && echo "$(date +"%F %H:%M:%S") | $@" 14 | } 15 | 16 | uid_gid_reset () 17 | { 18 | if [[ "$HOST_UID" != "$(id -u docker)" ]] || [[ "$HOST_GID" != "$(id -g docker)" ]]; then 19 | echo-debug "Updating docker user uid/gid to $HOST_UID/$HOST_GID to match the host user uid/gid..." 20 | usermod -u "$HOST_UID" -o docker 21 | groupmod -g "$HOST_GID" -o "$(id -gn docker)" 22 | fi 23 | } 24 | 25 | xdebug_enable () 26 | { 27 | echo-debug "Enabling xdebug..." 28 | ln -s /opt/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/ 29 | } 30 | 31 | xhprof_enable () 32 | { 33 | echo-debug "Enabling xhprof..." 34 | cp /opt/docker-php-ext-xhprof.ini /usr/local/etc/php/conf.d/ 35 | # Output directory to the ini file 36 | echo "xhprof.output_dir = ${XHPROF_OUTPUT_DIR}" >> /usr/local/etc/php/conf.d/docker-php-ext-xhprof.ini 37 | # Try to create directory if it doesn't exist 38 | mkdir ${XHPROF_OUTPUT_DIR} || true 39 | # Change owner of directory 40 | chown docker:docker ${XHPROF_OUTPUT_DIR} 41 | } 42 | 43 | opcache_preload_enable() 44 | { 45 | echo-debug "Enabling opcache preload..." 46 | ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ 47 | } 48 | 49 | ide_mode_enable () 50 | { 51 | echo-debug "Enabling web IDE..." 52 | # Enabled only code-server service (disabled all other services) 53 | # TODO: split IDE/cli and php-fpm entirely 54 | rm -f /etc/supervisor/conf.d/supervisord-*.conf 55 | render_tmpl "/etc/supervisor/conf.d/supervisord-code-server.conf" 56 | render_tmpl "${VSCODE_HOME}/config.yaml" 57 | } 58 | 59 | # Creates symlinks to project level overrides if they exist 60 | php_settings () 61 | { 62 | php_ini=/var/www/.docksal/etc/php/php.ini 63 | if [[ -f ${php_ini} ]]; then 64 | echo-debug "Found project level overrides for PHP. Including:" 65 | echo-debug "${php_ini}" 66 | ln -s /var/www/.docksal/etc/php/php.ini /usr/local/etc/php/conf.d/zzz-php.ini 67 | fi 68 | 69 | php_fpm_conf=/var/www/.docksal/etc/php/php-fpm.conf 70 | if [[ -f ${php_fpm_conf} ]]; then 71 | echo-debug "Found project level overrides for PHP-FPM. Including:" 72 | echo-debug "${php_fpm_conf}" 73 | ln -s ${php_fpm_conf} /usr/local/etc/php-fpm.d/zzz-php-fpm.conf 74 | fi 75 | } 76 | 77 | add_ssh_key () 78 | { 79 | echo-debug "Adding a private SSH key from SECRET_SSH_PRIVATE_KEY..." 80 | render_tmpl "$HOME_DIR/.ssh/id_rsa" 81 | chmod 0600 "$HOME_DIR/.ssh/id_rsa" 82 | } 83 | 84 | # Helper function to render configs from go templates using gomplate 85 | render_tmpl () 86 | { 87 | local file="${1}" 88 | local tmpl="${1}.tmpl" 89 | 90 | if [[ -f "${tmpl}" ]]; then 91 | echo-debug "Rendering template: ${tmpl}..." 92 | # gomplate started throwing an empty line into stderr in v3.7.0, so we have to mute it below 93 | gomplate --file "${tmpl}" --out "${file}" &>/dev/null 94 | else 95 | echo-debug "Error: Template file not found: ${tmpl}" 96 | return 1 97 | fi 98 | } 99 | 100 | # Helper function to loop through all environment variables prefixed with SECRET_ and 101 | # convert to the equivalent variable without SECRET. 102 | # Example: SECRET_TERMINUS_TOKEN => TERMINUS_TOKEN. 103 | convert_secrets () 104 | { 105 | eval 'secrets=(${!SECRET_@})' 106 | for secret_key in "${secrets[@]}"; do 107 | key=${secret_key#SECRET_} 108 | secret_value=${!secret_key} 109 | 110 | # Write new variables to /etc/profile.d/secrets.sh to make them available for all users/sessions 111 | echo "export ${key}=\"${secret_value}\"" | tee -a "/etc/profile.d/secrets.sh" >/dev/null 112 | 113 | # Also export new variables here 114 | # This makes them available in the server/php-fpm environment 115 | eval "export ${key}=${secret_value}" 116 | done 117 | } 118 | 119 | # Pantheon (terminus) login 120 | terminus_login () 121 | { 122 | echo-debug "Authenticating with Pantheon..." 123 | # This has to be done using the docker user via su to load the user environment 124 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 125 | local command="terminus auth:login --no-interaction --machine-token='${TERMINUS_TOKEN}'" 126 | local output=$(su -l docker -c "${command}") 127 | if [[ $? != 0 ]]; then 128 | echo-debug "ERROR: Pantheon authentication failed." 129 | echo 130 | echo "$output" 131 | echo 132 | fi 133 | } 134 | 135 | # Acquia CLI login 136 | acli_login () 137 | { 138 | echo-debug "Authenticating with Acquia..." 139 | # This has to be done using the docker user via su to load the user environment 140 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 141 | local command="acli auth:login --key='${ACQUIA_CLI_KEY}' --secret='${ACQUIA_CLI_SECRET}' --no-interaction" 142 | local output=$(su -l docker -c "${command}" 2>&1) 143 | if [[ $? != 0 ]]; then 144 | echo-debug "ERROR: Acquia authentication failed." 145 | echo 146 | echo "$output" 147 | echo 148 | fi 149 | } 150 | 151 | # Git settings 152 | git_settings () 153 | { 154 | # These must be run as the docker user 155 | echo-debug "Configuring git..." 156 | # Set default git settings if none have been passed 157 | # See https://github.com/docksal/service-cli/issues/124 158 | gosu docker git config --global user.email "${GIT_USER_EMAIL:-cli@docksal.io}" 159 | gosu docker git config --global user.name "${GIT_USER_NAME:-Docksal CLI}" 160 | } 161 | 162 | # Inject a private SSH key if provided 163 | [[ "$SECRET_SSH_PRIVATE_KEY" != "" ]] && add_ssh_key 164 | 165 | # Set Composer Version 166 | [[ "${COMPOSER_DEFAULT_VERSION}" != "" ]] && [[ -f /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} ]] && ln -sf /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer 167 | 168 | # Convert all Environment Variables Prefixed with SECRET_ 169 | convert_secrets 170 | 171 | # Docker user uid/gid mapping to the host user uid/gid 172 | [[ "$HOST_UID" != "" ]] && [[ "$HOST_GID" != "" ]] && uid_gid_reset 173 | 174 | # Enable xdebug 175 | [[ "$XDEBUG_ENABLED" != "" ]] && [[ "$XDEBUG_ENABLED" != "0" ]] && xdebug_enable 176 | 177 | # Enable xdebug 178 | [[ "$XHPROF_ENABLED" != "" ]] && [[ "$XHPROF_ENABLED" != "0" ]] && xhprof_enable 179 | 180 | # Enable opcache preload 181 | [[ -f "/var/www/.docksal/etc/php/preload.php" ]] && opcache_preload_enable 182 | 183 | # Enable web IDE 184 | [[ "$IDE_ENABLED" != "" ]] && [[ "$IDE_ENABLED" != "0" ]] && ide_mode_enable 185 | 186 | # Include project level PHP settings if found 187 | php_settings 188 | 189 | # Make sure permissions are correct (after uid/gid change and COPY operations in Dockerfile) 190 | # To not bloat the image size, permissions on the home folder are reset at runtime. 191 | echo-debug "Resetting permissions on $HOME_DIR and /var/www..." 192 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" -R "$HOME_DIR" 193 | # Docker resets the project root folder permissions to 0:0 when cli is recreated (e.g. an env variable updated). 194 | # We apply a fix/workaround for this at startup (non-recursive). 195 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" /var/www 196 | 197 | # These have to happen after the home directory permissions are reset, 198 | # otherwise the docker user may not have write access to /home/docker, where the auth session data is stored. 199 | # Automatically authenticate with Pantheon if Terminus token is present 200 | [[ "$TERMINUS_TOKEN" != "" ]] && terminus_login 201 | 202 | # Authenticate to Acquia CLI 203 | [[ "$ACQUIA_CLI_KEY" != "" ]] && [[ "$ACQUIA_CLI_SECRET" != "" ]] && acli_login 204 | 205 | # If crontab file is found within project add contents to user crontab file. 206 | if [[ -f ${PROJECT_ROOT}/.docksal/services/cli/crontab ]]; then 207 | echo-debug "Loading crontab..." 208 | cat ${PROJECT_ROOT}/.docksal/services/cli/crontab | crontab -u docker - 209 | fi 210 | 211 | # Apply git settings 212 | [[ "$GIT_USER_EMAIL" != "" ]] && [[ "$GIT_USER_NAME" != "" ]] && git_settings 213 | 214 | # Initialization steps completed. Create a pid file to mark the container as healthy 215 | echo-debug "Preliminary initialization completed." 216 | touch /var/run/cli 217 | 218 | # Execute a custom startup script if present 219 | if [[ -x ${PROJECT_ROOT}/.docksal/services/cli/startup.sh ]]; then 220 | echo-debug "Running custom startup script..." 221 | # TODO: should we source the script instead? 222 | su -l docker -c "${PROJECT_ROOT}/.docksal/services/cli/startup.sh" 223 | if [[ $? == 0 ]]; then 224 | echo-debug "Custom startup script executed successfully." 225 | else 226 | echo-debug "ERROR: Custom startup script execution failed." 227 | fi 228 | fi 229 | 230 | # Execute passed CMD arguments 231 | echo-debug "Passing execution to: $*" 232 | # Service mode (run as root) 233 | if [[ "$1" == "supervisord" ]]; then 234 | exec gosu root supervisord -c /etc/supervisor/supervisord.conf 235 | # Command mode (run as docker user) 236 | else 237 | exec gosu docker "$@" 238 | fi 239 | -------------------------------------------------------------------------------- /8.2/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is running as root by default. 4 | # Switching to the docker user can be done via "gosu docker ". 5 | 6 | HOME_DIR='/home/docker' 7 | 8 | DEBUG=${DEBUG:-0} 9 | # Turn debugging ON when cli is started in the service mode 10 | [[ "$1" == "supervisord" ]] && DEBUG=1 11 | echo-debug () 12 | { 13 | [[ "$DEBUG" != 0 ]] && echo "$(date +"%F %H:%M:%S") | $@" 14 | } 15 | 16 | uid_gid_reset () 17 | { 18 | if [[ "$HOST_UID" != "$(id -u docker)" ]] || [[ "$HOST_GID" != "$(id -g docker)" ]]; then 19 | echo-debug "Updating docker user uid/gid to $HOST_UID/$HOST_GID to match the host user uid/gid..." 20 | usermod -u "$HOST_UID" -o docker 21 | groupmod -g "$HOST_GID" -o "$(id -gn docker)" 22 | fi 23 | } 24 | 25 | xdebug_enable () 26 | { 27 | echo-debug "Enabling xdebug..." 28 | ln -s /opt/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/ 29 | } 30 | 31 | xhprof_enable () 32 | { 33 | echo-debug "Enabling xhprof..." 34 | cp /opt/docker-php-ext-xhprof.ini /usr/local/etc/php/conf.d/ 35 | # Output directory to the ini file 36 | echo "xhprof.output_dir = ${XHPROF_OUTPUT_DIR}" >> /usr/local/etc/php/conf.d/docker-php-ext-xhprof.ini 37 | # Try to create directory if it doesn't exist 38 | mkdir ${XHPROF_OUTPUT_DIR} || true 39 | # Change owner of directory 40 | chown docker:docker ${XHPROF_OUTPUT_DIR} 41 | } 42 | 43 | opcache_preload_enable() 44 | { 45 | echo-debug "Enabling opcache preload..." 46 | ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ 47 | } 48 | 49 | ide_mode_enable () 50 | { 51 | echo-debug "Enabling web IDE..." 52 | # Enabled only code-server service (disabled all other services) 53 | # TODO: split IDE/cli and php-fpm entirely 54 | rm -f /etc/supervisor/conf.d/supervisord-*.conf 55 | render_tmpl "/etc/supervisor/conf.d/supervisord-code-server.conf" 56 | render_tmpl "${VSCODE_HOME}/config.yaml" 57 | } 58 | 59 | # Creates symlinks to project level overrides if they exist 60 | php_settings () 61 | { 62 | php_ini=/var/www/.docksal/etc/php/php.ini 63 | if [[ -f ${php_ini} ]]; then 64 | echo-debug "Found project level overrides for PHP. Including:" 65 | echo-debug "${php_ini}" 66 | ln -s /var/www/.docksal/etc/php/php.ini /usr/local/etc/php/conf.d/zzz-php.ini 67 | fi 68 | 69 | php_fpm_conf=/var/www/.docksal/etc/php/php-fpm.conf 70 | if [[ -f ${php_fpm_conf} ]]; then 71 | echo-debug "Found project level overrides for PHP-FPM. Including:" 72 | echo-debug "${php_fpm_conf}" 73 | ln -s ${php_fpm_conf} /usr/local/etc/php-fpm.d/zzz-php-fpm.conf 74 | fi 75 | } 76 | 77 | add_ssh_key () 78 | { 79 | echo-debug "Adding a private SSH key from SECRET_SSH_PRIVATE_KEY..." 80 | render_tmpl "$HOME_DIR/.ssh/id_rsa" 81 | chmod 0600 "$HOME_DIR/.ssh/id_rsa" 82 | } 83 | 84 | # Helper function to render configs from go templates using gomplate 85 | render_tmpl () 86 | { 87 | local file="${1}" 88 | local tmpl="${1}.tmpl" 89 | 90 | if [[ -f "${tmpl}" ]]; then 91 | echo-debug "Rendering template: ${tmpl}..." 92 | # gomplate started throwing an empty line into stderr in v3.7.0, so we have to mute it below 93 | gomplate --file "${tmpl}" --out "${file}" &>/dev/null 94 | else 95 | echo-debug "Error: Template file not found: ${tmpl}" 96 | return 1 97 | fi 98 | } 99 | 100 | # Helper function to loop through all environment variables prefixed with SECRET_ and 101 | # convert to the equivalent variable without SECRET. 102 | # Example: SECRET_TERMINUS_TOKEN => TERMINUS_TOKEN. 103 | convert_secrets () 104 | { 105 | eval 'secrets=(${!SECRET_@})' 106 | for secret_key in "${secrets[@]}"; do 107 | key=${secret_key#SECRET_} 108 | secret_value=${!secret_key} 109 | 110 | # Write new variables to /etc/profile.d/secrets.sh to make them available for all users/sessions 111 | echo "export ${key}=\"${secret_value}\"" | tee -a "/etc/profile.d/secrets.sh" >/dev/null 112 | 113 | # Also export new variables here 114 | # This makes them available in the server/php-fpm environment 115 | eval "export ${key}=${secret_value}" 116 | done 117 | } 118 | 119 | # Pantheon (terminus) login 120 | terminus_login () 121 | { 122 | echo-debug "Authenticating with Pantheon..." 123 | # This has to be done using the docker user via su to load the user environment 124 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 125 | local command="terminus auth:login --no-interaction --machine-token='${TERMINUS_TOKEN}'" 126 | local output=$(su -l docker -c "${command}") 127 | if [[ $? != 0 ]]; then 128 | echo-debug "ERROR: Pantheon authentication failed." 129 | echo 130 | echo "$output" 131 | echo 132 | fi 133 | } 134 | 135 | # Acquia CLI login 136 | acli_login () 137 | { 138 | echo-debug "Authenticating with Acquia..." 139 | # This has to be done using the docker user via su to load the user environment 140 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 141 | local command="acli auth:login --key='${ACQUIA_CLI_KEY}' --secret='${ACQUIA_CLI_SECRET}' --no-interaction" 142 | local output=$(su -l docker -c "${command}" 2>&1) 143 | if [[ $? != 0 ]]; then 144 | echo-debug "ERROR: Acquia authentication failed." 145 | echo 146 | echo "$output" 147 | echo 148 | fi 149 | } 150 | 151 | # Git settings 152 | git_settings () 153 | { 154 | # These must be run as the docker user 155 | echo-debug "Configuring git..." 156 | # Set default git settings if none have been passed 157 | # See https://github.com/docksal/service-cli/issues/124 158 | gosu docker git config --global user.email "${GIT_USER_EMAIL:-cli@docksal.io}" 159 | gosu docker git config --global user.name "${GIT_USER_NAME:-Docksal CLI}" 160 | } 161 | 162 | # Inject a private SSH key if provided 163 | [[ "$SECRET_SSH_PRIVATE_KEY" != "" ]] && add_ssh_key 164 | 165 | # Set Composer Version 166 | [[ "${COMPOSER_DEFAULT_VERSION}" != "" ]] && [[ -f /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} ]] && ln -sf /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer 167 | 168 | # Convert all Environment Variables Prefixed with SECRET_ 169 | convert_secrets 170 | 171 | # Docker user uid/gid mapping to the host user uid/gid 172 | [[ "$HOST_UID" != "" ]] && [[ "$HOST_GID" != "" ]] && uid_gid_reset 173 | 174 | # Enable xdebug 175 | [[ "$XDEBUG_ENABLED" != "" ]] && [[ "$XDEBUG_ENABLED" != "0" ]] && xdebug_enable 176 | 177 | # Enable xdebug 178 | [[ "$XHPROF_ENABLED" != "" ]] && [[ "$XHPROF_ENABLED" != "0" ]] && xhprof_enable 179 | 180 | # Enable opcache preload 181 | [[ -f "/var/www/.docksal/etc/php/preload.php" ]] && opcache_preload_enable 182 | 183 | # Enable web IDE 184 | [[ "$IDE_ENABLED" != "" ]] && [[ "$IDE_ENABLED" != "0" ]] && ide_mode_enable 185 | 186 | # Include project level PHP settings if found 187 | php_settings 188 | 189 | # Make sure permissions are correct (after uid/gid change and COPY operations in Dockerfile) 190 | # To not bloat the image size, permissions on the home folder are reset at runtime. 191 | echo-debug "Resetting permissions on $HOME_DIR and /var/www..." 192 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" -R "$HOME_DIR" 193 | # Docker resets the project root folder permissions to 0:0 when cli is recreated (e.g. an env variable updated). 194 | # We apply a fix/workaround for this at startup (non-recursive). 195 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" /var/www 196 | 197 | # These have to happen after the home directory permissions are reset, 198 | # otherwise the docker user may not have write access to /home/docker, where the auth session data is stored. 199 | # Automatically authenticate with Pantheon if Terminus token is present 200 | [[ "$TERMINUS_TOKEN" != "" ]] && terminus_login 201 | 202 | # Authenticate to Acquia CLI 203 | [[ "$ACQUIA_CLI_KEY" != "" ]] && [[ "$ACQUIA_CLI_SECRET" != "" ]] && acli_login 204 | 205 | # If crontab file is found within project add contents to user crontab file. 206 | if [[ -f ${PROJECT_ROOT}/.docksal/services/cli/crontab ]]; then 207 | echo-debug "Loading crontab..." 208 | cat ${PROJECT_ROOT}/.docksal/services/cli/crontab | crontab -u docker - 209 | fi 210 | 211 | # Apply git settings 212 | [[ "$GIT_USER_EMAIL" != "" ]] && [[ "$GIT_USER_NAME" != "" ]] && git_settings 213 | 214 | # Initialization steps completed. Create a pid file to mark the container as healthy 215 | echo-debug "Preliminary initialization completed." 216 | touch /var/run/cli 217 | 218 | # Execute a custom startup script if present 219 | if [[ -x ${PROJECT_ROOT}/.docksal/services/cli/startup.sh ]]; then 220 | echo-debug "Running custom startup script..." 221 | # TODO: should we source the script instead? 222 | su -l docker -c "${PROJECT_ROOT}/.docksal/services/cli/startup.sh" 223 | if [[ $? == 0 ]]; then 224 | echo-debug "Custom startup script executed successfully." 225 | else 226 | echo-debug "ERROR: Custom startup script execution failed." 227 | fi 228 | fi 229 | 230 | # Execute passed CMD arguments 231 | echo-debug "Passing execution to: $*" 232 | # Service mode (run as root) 233 | if [[ "$1" == "supervisord" ]]; then 234 | exec gosu root supervisord -c /etc/supervisor/supervisord.conf 235 | # Command mode (run as docker user) 236 | else 237 | exec gosu docker "$@" 238 | fi 239 | -------------------------------------------------------------------------------- /8.3/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is running as root by default. 4 | # Switching to the docker user can be done via "gosu docker ". 5 | 6 | HOME_DIR='/home/docker' 7 | 8 | DEBUG=${DEBUG:-0} 9 | # Turn debugging ON when cli is started in the service mode 10 | [[ "$1" == "supervisord" ]] && DEBUG=1 11 | echo-debug () 12 | { 13 | [[ "$DEBUG" != 0 ]] && echo "$(date +"%F %H:%M:%S") | $@" 14 | } 15 | 16 | uid_gid_reset () 17 | { 18 | if [[ "$HOST_UID" != "$(id -u docker)" ]] || [[ "$HOST_GID" != "$(id -g docker)" ]]; then 19 | echo-debug "Updating docker user uid/gid to $HOST_UID/$HOST_GID to match the host user uid/gid..." 20 | usermod -u "$HOST_UID" -o docker 21 | groupmod -g "$HOST_GID" -o "$(id -gn docker)" 22 | fi 23 | } 24 | 25 | xdebug_enable () 26 | { 27 | echo-debug "Enabling xdebug..." 28 | ln -s /opt/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/ 29 | } 30 | 31 | xhprof_enable () 32 | { 33 | echo-debug "Enabling xhprof..." 34 | cp /opt/docker-php-ext-xhprof.ini /usr/local/etc/php/conf.d/ 35 | # Output directory to the ini file 36 | echo "xhprof.output_dir = ${XHPROF_OUTPUT_DIR}" >> /usr/local/etc/php/conf.d/docker-php-ext-xhprof.ini 37 | # Try to create directory if it doesn't exist 38 | mkdir ${XHPROF_OUTPUT_DIR} || true 39 | # Change owner of directory 40 | chown docker:docker ${XHPROF_OUTPUT_DIR} 41 | } 42 | 43 | opcache_preload_enable() 44 | { 45 | echo-debug "Enabling opcache preload..." 46 | ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ 47 | } 48 | 49 | ide_mode_enable () 50 | { 51 | echo-debug "Enabling web IDE..." 52 | # Enabled only code-server service (disabled all other services) 53 | # TODO: split IDE/cli and php-fpm entirely 54 | rm -f /etc/supervisor/conf.d/supervisord-*.conf 55 | render_tmpl "/etc/supervisor/conf.d/supervisord-code-server.conf" 56 | render_tmpl "${VSCODE_HOME}/config.yaml" 57 | } 58 | 59 | # Creates symlinks to project level overrides if they exist 60 | php_settings () 61 | { 62 | php_ini=/var/www/.docksal/etc/php/php.ini 63 | if [[ -f ${php_ini} ]]; then 64 | echo-debug "Found project level overrides for PHP. Including:" 65 | echo-debug "${php_ini}" 66 | ln -s /var/www/.docksal/etc/php/php.ini /usr/local/etc/php/conf.d/zzz-php.ini 67 | fi 68 | 69 | php_fpm_conf=/var/www/.docksal/etc/php/php-fpm.conf 70 | if [[ -f ${php_fpm_conf} ]]; then 71 | echo-debug "Found project level overrides for PHP-FPM. Including:" 72 | echo-debug "${php_fpm_conf}" 73 | ln -s ${php_fpm_conf} /usr/local/etc/php-fpm.d/zzz-php-fpm.conf 74 | fi 75 | } 76 | 77 | add_ssh_key () 78 | { 79 | echo-debug "Adding a private SSH key from SECRET_SSH_PRIVATE_KEY..." 80 | render_tmpl "$HOME_DIR/.ssh/id_rsa" 81 | chmod 0600 "$HOME_DIR/.ssh/id_rsa" 82 | } 83 | 84 | # Helper function to render configs from go templates using gomplate 85 | render_tmpl () 86 | { 87 | local file="${1}" 88 | local tmpl="${1}.tmpl" 89 | 90 | if [[ -f "${tmpl}" ]]; then 91 | echo-debug "Rendering template: ${tmpl}..." 92 | # gomplate started throwing an empty line into stderr in v3.7.0, so we have to mute it below 93 | gomplate --file "${tmpl}" --out "${file}" &>/dev/null 94 | else 95 | echo-debug "Error: Template file not found: ${tmpl}" 96 | return 1 97 | fi 98 | } 99 | 100 | # Helper function to loop through all environment variables prefixed with SECRET_ and 101 | # convert to the equivalent variable without SECRET. 102 | # Example: SECRET_TERMINUS_TOKEN => TERMINUS_TOKEN. 103 | convert_secrets () 104 | { 105 | eval 'secrets=(${!SECRET_@})' 106 | for secret_key in "${secrets[@]}"; do 107 | key=${secret_key#SECRET_} 108 | secret_value=${!secret_key} 109 | 110 | # Write new variables to /etc/profile.d/secrets.sh to make them available for all users/sessions 111 | echo "export ${key}=\"${secret_value}\"" | tee -a "/etc/profile.d/secrets.sh" >/dev/null 112 | 113 | # Also export new variables here 114 | # This makes them available in the server/php-fpm environment 115 | eval "export ${key}=${secret_value}" 116 | done 117 | } 118 | 119 | # Pantheon (terminus) login 120 | terminus_login () 121 | { 122 | echo-debug "Authenticating with Pantheon..." 123 | # This has to be done using the docker user via su to load the user environment 124 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 125 | local command="terminus auth:login --no-interaction --machine-token='${TERMINUS_TOKEN}'" 126 | local output=$(su -l docker -c "${command}") 127 | if [[ $? != 0 ]]; then 128 | echo-debug "ERROR: Pantheon authentication failed." 129 | echo 130 | echo "$output" 131 | echo 132 | fi 133 | } 134 | 135 | # Acquia CLI login 136 | acli_login () 137 | { 138 | echo-debug "Authenticating with Acquia..." 139 | # This has to be done using the docker user via su to load the user environment 140 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 141 | local command="acli auth:login --key='${ACQUIA_CLI_KEY}' --secret='${ACQUIA_CLI_SECRET}' --no-interaction" 142 | local output=$(su -l docker -c "${command}" 2>&1) 143 | if [[ $? != 0 ]]; then 144 | echo-debug "ERROR: Acquia authentication failed." 145 | echo 146 | echo "$output" 147 | echo 148 | fi 149 | } 150 | 151 | # Git settings 152 | git_settings () 153 | { 154 | # These must be run as the docker user 155 | echo-debug "Configuring git..." 156 | # Set default git settings if none have been passed 157 | # See https://github.com/docksal/service-cli/issues/124 158 | gosu docker git config --global user.email "${GIT_USER_EMAIL:-cli@docksal.io}" 159 | gosu docker git config --global user.name "${GIT_USER_NAME:-Docksal CLI}" 160 | } 161 | 162 | # Inject a private SSH key if provided 163 | [[ "$SECRET_SSH_PRIVATE_KEY" != "" ]] && add_ssh_key 164 | 165 | # Set Composer Version 166 | [[ "${COMPOSER_DEFAULT_VERSION}" != "" ]] && [[ -f /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} ]] && ln -sf /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer 167 | 168 | # Convert all Environment Variables Prefixed with SECRET_ 169 | convert_secrets 170 | 171 | # Docker user uid/gid mapping to the host user uid/gid 172 | [[ "$HOST_UID" != "" ]] && [[ "$HOST_GID" != "" ]] && uid_gid_reset 173 | 174 | # Enable xdebug 175 | [[ "$XDEBUG_ENABLED" != "" ]] && [[ "$XDEBUG_ENABLED" != "0" ]] && xdebug_enable 176 | 177 | # Enable xdebug 178 | [[ "$XHPROF_ENABLED" != "" ]] && [[ "$XHPROF_ENABLED" != "0" ]] && xhprof_enable 179 | 180 | # Enable opcache preload 181 | [[ -f "/var/www/.docksal/etc/php/preload.php" ]] && opcache_preload_enable 182 | 183 | # Enable web IDE 184 | [[ "$IDE_ENABLED" != "" ]] && [[ "$IDE_ENABLED" != "0" ]] && ide_mode_enable 185 | 186 | # Include project level PHP settings if found 187 | php_settings 188 | 189 | # Make sure permissions are correct (after uid/gid change and COPY operations in Dockerfile) 190 | # To not bloat the image size, permissions on the home folder are reset at runtime. 191 | echo-debug "Resetting permissions on $HOME_DIR and /var/www..." 192 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" -R "$HOME_DIR" 193 | # Docker resets the project root folder permissions to 0:0 when cli is recreated (e.g. an env variable updated). 194 | # We apply a fix/workaround for this at startup (non-recursive). 195 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" /var/www 196 | 197 | # These have to happen after the home directory permissions are reset, 198 | # otherwise the docker user may not have write access to /home/docker, where the auth session data is stored. 199 | # Automatically authenticate with Pantheon if Terminus token is present 200 | [[ "$TERMINUS_TOKEN" != "" ]] && terminus_login 201 | 202 | # Authenticate to Acquia CLI 203 | [[ "$ACQUIA_CLI_KEY" != "" ]] && [[ "$ACQUIA_CLI_SECRET" != "" ]] && acli_login 204 | 205 | # If crontab file is found within project add contents to user crontab file. 206 | if [[ -f ${PROJECT_ROOT}/.docksal/services/cli/crontab ]]; then 207 | echo-debug "Loading crontab..." 208 | cat ${PROJECT_ROOT}/.docksal/services/cli/crontab | crontab -u docker - 209 | fi 210 | 211 | # Apply git settings 212 | [[ "$GIT_USER_EMAIL" != "" ]] && [[ "$GIT_USER_NAME" != "" ]] && git_settings 213 | 214 | # Initialization steps completed. Create a pid file to mark the container as healthy 215 | echo-debug "Preliminary initialization completed." 216 | touch /var/run/cli 217 | 218 | # Execute a custom startup script if present 219 | if [[ -x ${PROJECT_ROOT}/.docksal/services/cli/startup.sh ]]; then 220 | echo-debug "Running custom startup script..." 221 | # TODO: should we source the script instead? 222 | su -l docker -c "${PROJECT_ROOT}/.docksal/services/cli/startup.sh" 223 | if [[ $? == 0 ]]; then 224 | echo-debug "Custom startup script executed successfully." 225 | else 226 | echo-debug "ERROR: Custom startup script execution failed." 227 | fi 228 | fi 229 | 230 | # Execute passed CMD arguments 231 | echo-debug "Passing execution to: $*" 232 | # Service mode (run as root) 233 | if [[ "$1" == "supervisord" ]]; then 234 | exec gosu root supervisord -c /etc/supervisor/supervisord.conf 235 | # Command mode (run as docker user) 236 | else 237 | exec gosu docker "$@" 238 | fi 239 | -------------------------------------------------------------------------------- /8.4/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is running as root by default. 4 | # Switching to the docker user can be done via "gosu docker ". 5 | 6 | HOME_DIR='/home/docker' 7 | 8 | DEBUG=${DEBUG:-0} 9 | # Turn debugging ON when cli is started in the service mode 10 | [[ "$1" == "supervisord" ]] && DEBUG=1 11 | echo-debug () 12 | { 13 | [[ "$DEBUG" != 0 ]] && echo "$(date +"%F %H:%M:%S") | $@" 14 | } 15 | 16 | uid_gid_reset () 17 | { 18 | if [[ "$HOST_UID" != "$(id -u docker)" ]] || [[ "$HOST_GID" != "$(id -g docker)" ]]; then 19 | echo-debug "Updating docker user uid/gid to $HOST_UID/$HOST_GID to match the host user uid/gid..." 20 | usermod -u "$HOST_UID" -o docker 21 | groupmod -g "$HOST_GID" -o "$(id -gn docker)" 22 | fi 23 | } 24 | 25 | xdebug_enable () 26 | { 27 | echo-debug "Enabling xdebug..." 28 | ln -s /opt/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/ 29 | } 30 | 31 | xhprof_enable () 32 | { 33 | echo-debug "Enabling xhprof..." 34 | cp /opt/docker-php-ext-xhprof.ini /usr/local/etc/php/conf.d/ 35 | # Output directory to the ini file 36 | echo "xhprof.output_dir = ${XHPROF_OUTPUT_DIR}" >> /usr/local/etc/php/conf.d/docker-php-ext-xhprof.ini 37 | # Try to create directory if it doesn't exist 38 | mkdir ${XHPROF_OUTPUT_DIR} || true 39 | # Change owner of directory 40 | chown docker:docker ${XHPROF_OUTPUT_DIR} 41 | } 42 | 43 | opcache_preload_enable() 44 | { 45 | echo-debug "Enabling opcache preload..." 46 | ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ 47 | } 48 | 49 | ide_mode_enable () 50 | { 51 | echo-debug "Enabling web IDE..." 52 | # Enabled only code-server service (disabled all other services) 53 | # TODO: split IDE/cli and php-fpm entirely 54 | rm -f /etc/supervisor/conf.d/supervisord-*.conf 55 | render_tmpl "/etc/supervisor/conf.d/supervisord-code-server.conf" 56 | render_tmpl "${VSCODE_HOME}/config.yaml" 57 | } 58 | 59 | # Creates symlinks to project level overrides if they exist 60 | php_settings () 61 | { 62 | php_ini=/var/www/.docksal/etc/php/php.ini 63 | if [[ -f ${php_ini} ]]; then 64 | echo-debug "Found project level overrides for PHP. Including:" 65 | echo-debug "${php_ini}" 66 | ln -s /var/www/.docksal/etc/php/php.ini /usr/local/etc/php/conf.d/zzz-php.ini 67 | fi 68 | 69 | php_fpm_conf=/var/www/.docksal/etc/php/php-fpm.conf 70 | if [[ -f ${php_fpm_conf} ]]; then 71 | echo-debug "Found project level overrides for PHP-FPM. Including:" 72 | echo-debug "${php_fpm_conf}" 73 | ln -s ${php_fpm_conf} /usr/local/etc/php-fpm.d/zzz-php-fpm.conf 74 | fi 75 | } 76 | 77 | add_ssh_key () 78 | { 79 | echo-debug "Adding a private SSH key from SECRET_SSH_PRIVATE_KEY..." 80 | render_tmpl "$HOME_DIR/.ssh/id_rsa" 81 | chmod 0600 "$HOME_DIR/.ssh/id_rsa" 82 | } 83 | 84 | # Helper function to render configs from go templates using gomplate 85 | render_tmpl () 86 | { 87 | local file="${1}" 88 | local tmpl="${1}.tmpl" 89 | 90 | if [[ -f "${tmpl}" ]]; then 91 | echo-debug "Rendering template: ${tmpl}..." 92 | # gomplate started throwing an empty line into stderr in v3.7.0, so we have to mute it below 93 | gomplate --file "${tmpl}" --out "${file}" &>/dev/null 94 | else 95 | echo-debug "Error: Template file not found: ${tmpl}" 96 | return 1 97 | fi 98 | } 99 | 100 | # Helper function to loop through all environment variables prefixed with SECRET_ and 101 | # convert to the equivalent variable without SECRET. 102 | # Example: SECRET_TERMINUS_TOKEN => TERMINUS_TOKEN. 103 | convert_secrets () 104 | { 105 | eval 'secrets=(${!SECRET_@})' 106 | for secret_key in "${secrets[@]}"; do 107 | key=${secret_key#SECRET_} 108 | secret_value=${!secret_key} 109 | 110 | # Write new variables to /etc/profile.d/secrets.sh to make them available for all users/sessions 111 | echo "export ${key}=\"${secret_value}\"" | tee -a "/etc/profile.d/secrets.sh" >/dev/null 112 | 113 | # Also export new variables here 114 | # This makes them available in the server/php-fpm environment 115 | eval "export ${key}=${secret_value}" 116 | done 117 | } 118 | 119 | # Pantheon (terminus) login 120 | terminus_login () 121 | { 122 | echo-debug "Authenticating with Pantheon..." 123 | # This has to be done using the docker user via su to load the user environment 124 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 125 | local command="terminus auth:login --no-interaction --machine-token='${TERMINUS_TOKEN}'" 126 | local output=$(su -l docker -c "${command}") 127 | if [[ $? != 0 ]]; then 128 | echo-debug "ERROR: Pantheon authentication failed." 129 | echo 130 | echo "$output" 131 | echo 132 | fi 133 | } 134 | 135 | # Acquia CLI login 136 | acli_login () 137 | { 138 | echo-debug "Authenticating with Acquia..." 139 | # This has to be done using the docker user via su to load the user environment 140 | # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user 141 | local command="acli auth:login --key='${ACQUIA_CLI_KEY}' --secret='${ACQUIA_CLI_SECRET}' --no-interaction" 142 | local output=$(su -l docker -c "${command}" 2>&1) 143 | if [[ $? != 0 ]]; then 144 | echo-debug "ERROR: Acquia authentication failed." 145 | echo 146 | echo "$output" 147 | echo 148 | fi 149 | } 150 | 151 | # Git settings 152 | git_settings () 153 | { 154 | # These must be run as the docker user 155 | echo-debug "Configuring git..." 156 | # Set default git settings if none have been passed 157 | # See https://github.com/docksal/service-cli/issues/124 158 | gosu docker git config --global user.email "${GIT_USER_EMAIL:-cli@docksal.io}" 159 | gosu docker git config --global user.name "${GIT_USER_NAME:-Docksal CLI}" 160 | } 161 | 162 | # Inject a private SSH key if provided 163 | [[ "$SECRET_SSH_PRIVATE_KEY" != "" ]] && add_ssh_key 164 | 165 | # Set Composer Version 166 | [[ "${COMPOSER_DEFAULT_VERSION}" != "" ]] && [[ -f /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} ]] && ln -sf /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer 167 | 168 | # Convert all Environment Variables Prefixed with SECRET_ 169 | convert_secrets 170 | 171 | # Docker user uid/gid mapping to the host user uid/gid 172 | [[ "$HOST_UID" != "" ]] && [[ "$HOST_GID" != "" ]] && uid_gid_reset 173 | 174 | # Enable xdebug 175 | [[ "$XDEBUG_ENABLED" != "" ]] && [[ "$XDEBUG_ENABLED" != "0" ]] && xdebug_enable 176 | 177 | # Enable xdebug 178 | [[ "$XHPROF_ENABLED" != "" ]] && [[ "$XHPROF_ENABLED" != "0" ]] && xhprof_enable 179 | 180 | # Enable opcache preload 181 | [[ -f "/var/www/.docksal/etc/php/preload.php" ]] && opcache_preload_enable 182 | 183 | # Enable web IDE 184 | [[ "$IDE_ENABLED" != "" ]] && [[ "$IDE_ENABLED" != "0" ]] && ide_mode_enable 185 | 186 | # Include project level PHP settings if found 187 | php_settings 188 | 189 | # Make sure permissions are correct (after uid/gid change and COPY operations in Dockerfile) 190 | # To not bloat the image size, permissions on the home folder are reset at runtime. 191 | echo-debug "Resetting permissions on $HOME_DIR and /var/www..." 192 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" -R "$HOME_DIR" 193 | # Docker resets the project root folder permissions to 0:0 when cli is recreated (e.g. an env variable updated). 194 | # We apply a fix/workaround for this at startup (non-recursive). 195 | chown "${HOST_UID:-1000}:${HOST_GID:-1000}" /var/www 196 | 197 | # These have to happen after the home directory permissions are reset, 198 | # otherwise the docker user may not have write access to /home/docker, where the auth session data is stored. 199 | # Automatically authenticate with Pantheon if Terminus token is present 200 | [[ "$TERMINUS_TOKEN" != "" ]] && terminus_login 201 | 202 | # Authenticate to Acquia CLI 203 | [[ "$ACQUIA_CLI_KEY" != "" ]] && [[ "$ACQUIA_CLI_SECRET" != "" ]] && acli_login 204 | 205 | # If crontab file is found within project add contents to user crontab file. 206 | if [[ -f ${PROJECT_ROOT}/.docksal/services/cli/crontab ]]; then 207 | echo-debug "Loading crontab..." 208 | cat ${PROJECT_ROOT}/.docksal/services/cli/crontab | crontab -u docker - 209 | fi 210 | 211 | # Apply git settings 212 | [[ "$GIT_USER_EMAIL" != "" ]] && [[ "$GIT_USER_NAME" != "" ]] && git_settings 213 | 214 | # Initialization steps completed. Create a pid file to mark the container as healthy 215 | echo-debug "Preliminary initialization completed." 216 | touch /var/run/cli 217 | 218 | # Execute a custom startup script if present 219 | if [[ -x ${PROJECT_ROOT}/.docksal/services/cli/startup.sh ]]; then 220 | echo-debug "Running custom startup script..." 221 | # TODO: should we source the script instead? 222 | su -l docker -c "${PROJECT_ROOT}/.docksal/services/cli/startup.sh" 223 | if [[ $? == 0 ]]; then 224 | echo-debug "Custom startup script executed successfully." 225 | else 226 | echo-debug "ERROR: Custom startup script execution failed." 227 | fi 228 | fi 229 | 230 | # Execute passed CMD arguments 231 | echo-debug "Passing execution to: $*" 232 | # Service mode (run as root) 233 | if [[ "$1" == "supervisord" ]]; then 234 | exec gosu root supervisord -c /etc/supervisor/supervisord.conf 235 | # Command mode (run as docker user) 236 | else 237 | exec gosu docker "$@" 238 | fi 239 | -------------------------------------------------------------------------------- /.github/workflows/default.yaml: -------------------------------------------------------------------------------- 1 | name: Build, Test, Push 2 | 3 | on: 4 | schedule: 5 | - cron: "0 10 * * 0" # Every Sunday at 10AM 6 | push: 7 | branches: 8 | - master 9 | - develop 10 | - feature/* 11 | tags: 12 | - "v*.*.*" 13 | workflow_dispatch: # Allow manually triggering a build 14 | 15 | defaults: 16 | run: 17 | shell: bash 18 | 19 | env: 20 | IMAGE: docksal/cli 21 | UPSTREAM_IMAGE: debian 22 | LATEST_VERSION: "8.4" 23 | DOCKSAL_VERSION: develop 24 | 25 | jobs: 26 | build: 27 | name: "Build: ${{ matrix.version }}/${{ matrix.arch }}" 28 | runs-on: ${{ matrix.runner }} 29 | 30 | strategy: 31 | fail-fast: false # Don't cancel other jobs if one fails 32 | matrix: 33 | include: 34 | - 35 | platform: linux/amd64 36 | arch: amd64 37 | version: "8.1" 38 | runner: ubuntu-24.04 39 | - 40 | platform: linux/amd64 41 | arch: amd64 42 | version: "8.2" 43 | runner: ubuntu-24.04 44 | - 45 | platform: linux/amd64 46 | arch: amd64 47 | version: "8.3" 48 | runner: ubuntu-24.04 49 | - 50 | platform: linux/amd64 51 | arch: amd64 52 | version: "8.4" 53 | runner: ubuntu-24.04 54 | - 55 | platform: linux/arm64 56 | arch: arm64 57 | version: "8.1" 58 | runner: ubuntu-24.04-arm 59 | - 60 | platform: linux/arm64 61 | arch: arm64 62 | version: "8.2" 63 | runner: ubuntu-24.04-arm 64 | - 65 | platform: linux/arm64 66 | arch: arm64 67 | version: "8.3" 68 | runner: ubuntu-24.04-arm 69 | - 70 | platform: linux/arm64 71 | arch: arm64 72 | version: "8.4" 73 | runner: ubuntu-24.04-arm 74 | 75 | env: 76 | ARCH: ${{ matrix.arch }} 77 | VERSION_PREFIX: php 78 | VERSION: ${{ matrix.version }} 79 | 80 | steps: 81 | - 82 | name: Checkout 83 | uses: actions/checkout@v4 84 | - 85 | name: Environment variables 86 | run: | 87 | # Export variables for further steps 88 | echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV} 89 | echo BUILD_DIR="${VERSION:-.}" | tee -a ${GITHUB_ENV} 90 | echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV} 91 | - 92 | name: Check Docker 93 | run: | 94 | docker version 95 | docker info 96 | - 97 | name: Login to Docker Hub 98 | uses: docker/login-action@v3 99 | with: 100 | username: ${{ secrets.DOCKERHUB_USERNAME }} 101 | password: ${{ secrets.DOCKERHUB_TOKEN }} 102 | - 103 | # Build and cache image in the registry 104 | name: Build image 105 | uses: docker/build-push-action@v6 106 | with: 107 | context: ${{ env.BUILD_DIR }} 108 | file: ${{ env.BUILD_DIR }}/Dockerfile 109 | build-args: VERSION=${{ env.VERSION }} 110 | # Push intermediate arch-specific build tag to repo 111 | tags: ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }} 112 | push: ${{ github.event_name != 'pull_request' }} # Don't push for PRs 113 | # BUILD_IMAGE_TAG - persistent multi-arch tag, updated at the end of the build (success or failure) 114 | cache-from: type=registry,ref=${{ env.BUILD_IMAGE_TAG }} 115 | cache-to: type=inline # Write the cache metadata into the image configuration 116 | 117 | test: 118 | name: "Test: ${{ matrix.version }}/${{ matrix.arch }}" 119 | runs-on: ${{ matrix.runner }} 120 | needs: build 121 | 122 | strategy: 123 | fail-fast: false # Don't cancel other jobs if one fails 124 | matrix: 125 | include: 126 | - 127 | platform: linux/amd64 128 | arch: amd64 129 | version: "8.1" 130 | runner: ubuntu-24.04 131 | - 132 | platform: linux/amd64 133 | arch: amd64 134 | version: "8.2" 135 | runner: ubuntu-24.04 136 | - 137 | platform: linux/amd64 138 | arch: amd64 139 | version: "8.3" 140 | runner: ubuntu-24.04 141 | - 142 | platform: linux/amd64 143 | arch: amd64 144 | version: "8.4" 145 | runner: ubuntu-24.04 146 | - 147 | platform: linux/arm64 148 | arch: arm64 149 | version: "8.1" 150 | runner: ubuntu-24.04-arm 151 | - 152 | platform: linux/arm64 153 | arch: arm64 154 | version: "8.2" 155 | runner: ubuntu-24.04-arm 156 | - 157 | platform: linux/arm64 158 | arch: arm64 159 | version: "8.3" 160 | runner: ubuntu-24.04-arm 161 | - 162 | platform: linux/arm64 163 | arch: arm64 164 | version: "8.4" 165 | runner: ubuntu-24.04-arm 166 | 167 | env: 168 | ARCH: ${{ matrix.arch }} 169 | VERSION_PREFIX: php 170 | VERSION: ${{ matrix.version }} 171 | 172 | steps: 173 | - 174 | name: Setup Bats 175 | uses: bats-core/bats-action@3.0.1 176 | - 177 | name: Checkout 178 | uses: actions/checkout@v4 179 | - 180 | name: Environment variables 181 | run: | 182 | # Export variables for further steps 183 | echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV} 184 | echo BUILD_DIR="${VERSION:-.}" | tee -a ${GITHUB_ENV} 185 | echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV} 186 | - 187 | name: Check Docker 188 | run: | 189 | docker version 190 | docker info 191 | - 192 | # Run tests 193 | name: Test 194 | id: tests 195 | working-directory: ${{ env.BUILD_DIR }} 196 | env: 197 | BUILD_IMAGE_TAG: ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }} 198 | SECRET_PLATFORMSH_CLI_TOKEN: ${{ secrets.SECRET_PLATFORMSH_CLI_TOKEN }} 199 | SECRET_TERMINUS_TOKEN: ${{ secrets.SECRET_TERMINUS_TOKEN }} 200 | run: | 201 | make test 202 | ([[ $? == 0 ]] && echo "pass" || echo "fail") | tee ${{ github.workspace }}/test-results-${VERSION_PREFIX}${VERSION}-${ARCH}.txt 203 | # Store tests results as an artifact (used by downstream jobs) 204 | # Note: Cannot use "::set-output name=var_name::var_value" as var_name would need to be dynamic here. 205 | # Dynamic variable names cannot be used when mapping step outputs to job outputs. 206 | # Step outputs cannot be accessed directly from other jobs. Dead end. 207 | - name: Store test results 208 | uses: actions/upload-artifact@v4 209 | with: 210 | name: test-results-${{ env.GIT_SHA7 }}-${{ env.VERSION_PREFIX }}${{ env.VERSION }}-${{ env.ARCH }} 211 | path: ${{ github.workspace }}/test-results-*.txt 212 | if-no-files-found: error 213 | overwrite: true 214 | 215 | push: 216 | name: "Push: ${{ matrix.version }}/multi" 217 | runs-on: ubuntu-24.04 218 | 219 | # Wait for test to either succeed or fail 220 | needs: test 221 | if: always() 222 | 223 | strategy: 224 | matrix: 225 | version: 226 | - "8.1" 227 | - "8.2" 228 | - "8.3" 229 | - "8.4" 230 | 231 | env: 232 | VERSION_PREFIX: php 233 | VERSION: ${{ matrix.version }} 234 | 235 | steps: 236 | - 237 | name: Checkout 238 | uses: actions/checkout@v4 239 | - 240 | name: Environment variables 241 | run: | 242 | # Export variables for further steps 243 | echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV} 244 | echo BUILD_DIR="${VERSION:-.}" | tee -a ${GITHUB_ENV} 245 | echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV} 246 | - 247 | # Login to Docker Hub 248 | name: Login to Docker Hub 249 | uses: docker/login-action@v3 250 | with: 251 | username: ${{ secrets.DOCKERHUB_USERNAME }} 252 | password: ${{ secrets.DOCKERHUB_TOKEN }} 253 | - 254 | name: Retrieve test results 255 | uses: actions/download-artifact@v4 256 | with: 257 | pattern: test-results-${{ env.GIT_SHA7 }}-* 258 | merge-multiple: true 259 | - 260 | # Generate persistent tags (edge, stable, release) 261 | name: Docker image tags 262 | id: docker_tags 263 | # Don't push broken builds to persistent tags (both amd64 and arm64 tests must pass) 264 | run: | 265 | amd64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-amd64.txt) 266 | arm64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-arm64.txt) 267 | if [[ "${amd64_tests}" == "pass" ]] && [[ "${arm64_tests}" == "pass" ]]; then 268 | .github/scripts/docker-tags.sh 269 | fi 270 | - 271 | # Create and push multi-arch image manifests 272 | name: Push multi-arch images 273 | env: 274 | # build tags are always pushed (build caching, debugging needs) 275 | # edge, stage, release are only pushed if tests were successful (see docker_tags step) 276 | TAGS: | 277 | ${{ env.BUILD_IMAGE_TAG }} 278 | ${{ steps.docker_tags.outputs.tags }} 279 | DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} # Needed for docker-tag-delete.sh 280 | DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} # Needed for docker-tag-delete.sh 281 | run: | 282 | set -xeuo pipefail 283 | IFS="${IFS}," # Also split strings by comma (in case list of tag is comma-separated) 284 | for tag in ${TAGS}; do 285 | if [[ "${tag}" == "" ]]; then continue; fi 286 | docker manifest create --amend ${tag} \ 287 | ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64 \ 288 | ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64 289 | docker manifest inspect ${tag} 290 | docker manifest push ${tag} 291 | done 292 | # Clean up intermediate arch-specific image tags (DockerHub only) 293 | # TODO: DISABLED. DOES NOT WORK RELIABLY. 294 | #.github/scripts/docker-tag-delete.sh "${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64" 295 | #.github/scripts/docker-tag-delete.sh "${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64" 296 | -------------------------------------------------------------------------------- /8.2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2.29-fpm-bookworm AS cli 2 | 3 | ARG TARGETARCH 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 6 | 7 | # Prevent services autoload (http://jpetazzo.github.io/2013/10/06/policy-rc-d-do-not-start-services-automatically/) 8 | RUN set -xe; \ 9 | echo '#!/bin/sh\nexit 101' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d 10 | 11 | # Install basic packages 12 | RUN set -xe; \ 13 | apt-get update >/dev/null; \ 14 | apt-get -y --no-install-recommends install >/dev/null \ 15 | apt-transport-https \ 16 | # ca-certificates and curl come from upstream 17 | #ca-certificates \ 18 | #curl \ 19 | gnupg \ 20 | locales \ 21 | wget \ 22 | ;\ 23 | # Cleanup 24 | apt-get clean; rm -rf /var/lib/apt/lists/* 25 | 26 | # Set en_US.UTF-8 as the default locale 27 | RUN set -xe; \ 28 | echo "en_US.UTF-8 UTF-8" | tee -a /etc/locale.gen; \ 29 | locale-gen en_US.UTF-8; \ 30 | update-locale LANG=en_US.UTF-8 31 | ENV LC_ALL=en_US.UTF-8 32 | 33 | # Additional packages 34 | RUN set -xe; \ 35 | # Create man direcotries, otherwise some packages may not install (e.g. postgresql-client) 36 | # This should be a temporary workaround until fixed upstream: https://github.com/debuerreotype/debuerreotype/issues/10 37 | mkdir -p /usr/share/man/man1 /usr/share/man/man7; \ 38 | apt-get update >/dev/null; \ 39 | apt-get -y --no-install-recommends install >/dev/null \ 40 | cron \ 41 | dnsutils \ 42 | git \ 43 | git-lfs \ 44 | ghostscript \ 45 | # html2text binary - used for self-testing (php-fpm) 46 | html2text \ 47 | imagemagick \ 48 | iputils-ping \ 49 | less \ 50 | # cgi-fcgi binary - used for self-testing (php-fpm) 51 | libfcgi-bin \ 52 | mc \ 53 | msmtp \ 54 | # Debian ships with MariaDB instead of MySQL 55 | mariadb-client \ 56 | nano \ 57 | openssh-client \ 58 | openssh-server \ 59 | postgresql-client \ 60 | procps \ 61 | pv \ 62 | rsync \ 63 | sudo \ 64 | supervisor \ 65 | unzip \ 66 | webp \ 67 | zip \ 68 | ;\ 69 | # Cleanup 70 | apt-get clean; rm -rf /var/lib/apt/lists/* 71 | 72 | RUN set -xe; \ 73 | # Create a regular user/group "docker" (uid = 1000, gid = 1000 ) 74 | useradd -m -s /bin/bash -u 1000 -U -p docker docker; \ 75 | # Give the docker user sudo access 76 | usermod -a -G sudo docker; \ 77 | echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 78 | 79 | # gosu v1.14+ discorages using it as a non-root user (https://github.com/tianon/gosu/issues/11), which we rely on here. 80 | # See https://github.com/tianon/gosu/pull/89/commits/8afd3dec5fb4fe0356e4fb5d358fe235f7311181 81 | # We'll stick with v1.13 for the time being. 82 | # TODO: Replace gosu with sudo/su in startup.sh 83 | ENV \ 84 | GOSU_VERSION=1.13 \ 85 | GOMPLATE_VERSION=3.11.3 86 | RUN set -xe; \ 87 | # Install gosu and give access to the docker user primary group to use it. 88 | # gosu is used instead of sudo to start the main container process (pid 1) in a docker friendly way. 89 | # https://github.com/tianon/gosu 90 | curl -fsSL https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${TARGETARCH} -o /usr/local/bin/gosu; \ 91 | chown root:$(id -gn docker) /usr/local/bin/gosu; \ 92 | chmod +sx /usr/local/bin/gosu; \ 93 | # gomplate (to process configuration templates in startup.sh) 94 | curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-${TARGETARCH} -o /usr/local/bin/gomplate; \ 95 | chmod +x /usr/local/bin/gomplate 96 | 97 | # Configure sshd (for use PHPStorm's remote interpreters and tools integrations) 98 | # http://docs.docker.com/examples/running_ssh_service/ 99 | RUN set -xe; \ 100 | mkdir /var/run/sshd; \ 101 | echo 'docker:docker' | chpasswd; \ 102 | sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config; \ 103 | # SSH login fix. Otherwise user is kicked off after login 104 | sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd; \ 105 | echo "export VISIBLE=now" >> /etc/profile 106 | ENV NOTVISIBLE="in users profile" 107 | 108 | # PHP 109 | RUN set -xe; \ 110 | # Note: essential build tools (g++, gcc, make, etc) are included upstream as persistent packages. 111 | # Docker PHP Extension Installer 112 | curl -sSLf "https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions" -o /usr/local/bin/install-php-extensions \ 113 | && chmod +x /usr/local/bin/install-php-extensions; \ 114 | # Instal/enable all PHP extensions via mlocati/docker-php-extension-installer 115 | install-php-extensions \ 116 | # Stock extensions from upstream image 117 | bcmath \ 118 | bz2 \ 119 | calendar\ 120 | exif \ 121 | ftp \ 122 | gd \ 123 | gettext \ 124 | imap \ 125 | intl \ 126 | ldap \ 127 | mysqli \ 128 | opcache \ 129 | pcntl \ 130 | pdo_mysql \ 131 | pdo_pgsql \ 132 | pgsql \ 133 | soap \ 134 | sockets \ 135 | xsl \ 136 | zip \ 137 | sysvsem \ 138 | # Pecl extensions 139 | apcu \ 140 | gnupg \ 141 | imagick \ 142 | memcached \ 143 | redis \ 144 | ssh2 \ 145 | xdebug \ 146 | xhprof \ 147 | # MSSQL PHP client 148 | pdo_sqlsrv \ 149 | sqlsrv \ 150 | ;\ 151 | # Disable xdebug and xhprof by default to avoid performance impact 152 | # They can be enabled via environment variables at runtime (XDEBUG_ENABLED=1 and XHPROF_ENABLED=1) 153 | # There is no native "docker-php-ext-disable", so we remove the ini files manually 154 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"; \ 155 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xhprof.ini" 156 | 157 | # PHP tools (installed globally) 158 | ENV \ 159 | COMPOSER_DEFAULT_VERSION=2 \ 160 | COMPOSER_VERSION=1.10.27 \ 161 | COMPOSER2_VERSION=2.8.12 \ 162 | DRUSH_VERSION=8.4.12 \ 163 | DRUPAL_CONSOLE_LAUNCHER_VERSION=1.9.7 \ 164 | WPCLI_VERSION=2.12.0 \ 165 | PLATFORMSH_CLI_VERSION=5.6.0 \ 166 | ACQUIA_CLI_VERSION=2.49.0 \ 167 | TERMINUS_VERSION=4.1.0 \ 168 | JQ_VERSION=1.8.1 \ 169 | YQ_VERSION=4.48.1 170 | RUN set -xe; \ 171 | # Composer 1.x 172 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar" -o /usr/local/bin/composer1; \ 173 | # Composer 2.x 174 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER2_VERSION}/composer.phar" -o /usr/local/bin/composer2; \ 175 | # Drush 8 (global fallback) 176 | curl -fsSL "https://github.com/drush-ops/drush/releases/download/${DRUSH_VERSION}/drush.phar" -o /usr/local/bin/drush8; \ 177 | # Drupal Console Launcher 178 | curl -fsSL "https://github.com/hechoendrupal/drupal-console-launcher/releases/download/${DRUPAL_CONSOLE_LAUNCHER_VERSION}/drupal.phar" -o /usr/local/bin/drupal; \ 179 | # Wordpress CLI 180 | curl -fsSL "https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar" -o /usr/local/bin/wp; \ 181 | # Platform.sh CLI 182 | curl -fsSL "https://github.com/platformsh/cli/releases/download/${PLATFORMSH_CLI_VERSION}/platform_${PLATFORMSH_CLI_VERSION}_linux_${TARGETARCH}.tar.gz" -o /tmp/platform.tar.gz; \ 183 | tar -xzf /tmp/platform.tar.gz -C /tmp && mv /tmp/platform /usr/local/bin/platform; rm -rf /tmp/*; \ 184 | # Acquia CLI 185 | curl -fsSL "https://github.com/acquia/cli/releases/download/${ACQUIA_CLI_VERSION}/acli.phar" -o /usr/local/bin/acli; \ 186 | # Pantheon Terminus 187 | curl -fsSL "https://github.com/pantheon-systems/terminus/releases/download/${TERMINUS_VERSION}/terminus.phar" -o /usr/local/bin/terminus; \ 188 | # jq 189 | curl -fsSL "https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}/jq-linux-${TARGETARCH}" -o /usr/local/bin/jq; \ 190 | # yq 191 | curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq; \ 192 | # Set Default Composer Version 193 | ln -s /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer; \ 194 | # Make all downloaded binaries executable in one shot 195 | (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drupal wp platform acli terminus jq yq); 196 | 197 | # Install Python 3 + pip from Debian repos 198 | RUN set -xe; \ 199 | apt-get update >/dev/null; \ 200 | apt-get -y --no-install-recommends install >/dev/null \ 201 | python3 \ 202 | python3-pip \ 203 | ;\ 204 | # Cleanup 205 | apt-get clean; rm -rf /var/lib/apt/lists/* 206 | 207 | # Install Ruby from Debian repos 208 | RUN set -xe; \ 209 | apt-get update >/dev/null; \ 210 | apt-get -y --no-install-recommends install >/dev/null \ 211 | ruby-full \ 212 | ;\ 213 | # Cleanup 214 | apt-get clean; rm -rf /var/lib/apt/lists/* 215 | 216 | # Install a newer SQLite version from Debian Trixie (testing) repo 217 | # Debian Bookworm (main) ships with sqlite v3.40. Drupal 11 requires SQLite v3.45+. 218 | # @see https://www.drupal.org/project/drupal/issues/3346338 219 | RUN set -xe; \ 220 | echo "deb https://deb.debian.org/debian testing main" | tee /etc/apt/sources.list.d/testing.list; \ 221 | apt-get update >/dev/null; \ 222 | apt-get install -y -t testing sqlite3;\ 223 | # Cleanup 224 | apt-get clean; rm -rf /var/lib/apt/lists/*; rm -f /etc/apt/sources.list.d/testing.list 225 | 226 | # All further RUN commands will run as the "docker" user 227 | USER docker 228 | SHELL ["/bin/bash", "-c"] 229 | 230 | # Don't use -x here, as the output may be excessive 231 | RUN set -e; \ 232 | \ 233 | # Composer based dependencies 234 | # Add composer bin project level and global directories to PATH 235 | # Project level comes first and thus takes precedence over the global one 236 | echo -e "\n"'export PATH="$PATH:${PROJECT_ROOT:-/var/www}/vendor/bin"' >> $HOME/.profile; \ 237 | echo -e "\n"'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> $HOME/.profile; \ 238 | # Reload updated PATH from profile to make composer/etc. visible below 239 | . $HOME/.profile; \ 240 | # Drupal Coder & WP Coding Standards w/ a matching version of PHP_CodeSniffer 241 | # Set allow-plugins. See https://getcomposer.org/allow-plugins 242 | composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true; \ 243 | composer global require drupal/coder wp-coding-standards/wpcs phpcompatibility/phpcompatibility-wp; \ 244 | # Don't fix the indentation or installed_paths will not be set correctly 245 | phpcs --config-set installed_paths \ 246 | $HOME/.composer/vendor/drupal/coder/coder_sniffer/,\ 247 | $HOME/.composer/vendor/wp-coding-standards/wpcs/,\ 248 | $HOME/.composer/vendor/phpcompatibility/php-compatibility/PHPCompatibility/,\ 249 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp/PHPCompatibilityWP,\ 250 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie/PHPCompatibilityParagonieRandomCompat; \ 251 | # Cleanup 252 | composer clear-cache 253 | 254 | # Node.js (installed as user) 255 | ENV \ 256 | NVM_VERSION=0.40.3 \ 257 | NODE_VERSION=22.20.0 \ 258 | # Yarn (Classic v1) 259 | # https://github.com/yarnpkg/yarn/releases 260 | YARN_VERSION=1.22.22 261 | # Don't use -x here, as the output may be excessive 262 | RUN set -e; \ 263 | # NVM and a defaut Node.js version 264 | export PROFILE="$HOME/.profile"; \ 265 | curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash >/dev/null; \ 266 | # Reload profile to load nvm (needed by Yarn installation below) 267 | . $HOME/.profile; \ 268 | # Yarn (Classic v1) 269 | # Installing via npm to allow fore override with never versions via corepack 270 | npm install -g yarn@${YARN_VERSION}; \ 271 | # Enable corepack (allows installing project level yarn v2+ via yarn) 272 | corepack enable 273 | 274 | ## Ruby bundler 275 | ## Don't use -x here, as the output may be excessive 276 | RUN set -e; \ 277 | # Export ruby gem bin path 278 | echo 'export PATH=$PATH:$(ruby -r rubygems -e "puts Gem.user_dir")/bin' >> $HOME/.profile; \ 279 | . $HOME/.profile; \ 280 | gem install --user-install bundler; \ 281 | # Have bundler install gems in the current directory (./.bundle) by default 282 | echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile 283 | 284 | # Notify web container about started fin exec 285 | RUN echo '(/opt/ping-web.sh &)' >> $HOME/.profile 286 | 287 | USER root 288 | SHELL ["/bin/sh", "-c"] 289 | 290 | # Copy configs and scripts 291 | COPY --chown=docker:docker config/.terminus /home/docker/.terminus 292 | COPY --chown=docker:docker config/.ssh /home/docker/.ssh 293 | COPY config/supervisor /etc/supervisor/conf.d 294 | COPY startup.sh /opt/startup.sh 295 | COPY healthcheck.sh /opt/healthcheck.sh 296 | COPY ping-web.sh /opt/ping-web.sh 297 | # PHP default settings, global overrides and fpm overrides 298 | RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" 299 | COPY config/php/zz-php.ini /usr/local/etc/php/conf.d/zz-php.ini 300 | COPY config/php/xdebug.ini /opt/docker-php-ext-xdebug.ini 301 | COPY config/php/xhprof.ini /opt/docker-php-ext-xhprof.ini 302 | COPY config/php/opcache.ini /opt/docker-php-ext-opcache.ini 303 | COPY config/php/zz-php-fpm.conf /usr/local/etc/php-fpm.d/zz-php-fpm.conf 304 | 305 | ENV \ 306 | # ssh-agent proxy socket (requires docksal/ssh-agent) 307 | SSH_AUTH_SOCK=/.ssh-agent/proxy-socket \ 308 | # Set TERM so text editors/etc. can be used 309 | TERM=xterm \ 310 | # Allow PROJECT_ROOT to be universally used in fin custom commands (inside and outside cli) 311 | PROJECT_ROOT=/var/www \ 312 | # Default values for HOST_UID and HOST_GUI to match the default Ubuntu user. These are used in startup.sh 313 | HOST_UID=1000 \ 314 | HOST_GID=1000 \ 315 | # Delay in seconds between pings web from cli, while running fin exec. 0 - disabled 316 | WEB_KEEPALIVE=0 \ 317 | # xdebug disabled by default 318 | XDEBUG_ENABLED=0 \ 319 | XHPROF_ENABLED=0 \ 320 | XHPROF_OUTPUT_DIR=/tmp/xhprof 321 | 322 | # TODO: [v3] remove and set these via docker-compose 323 | EXPOSE 9000 324 | EXPOSE 22 325 | EXPOSE 3000 326 | 327 | WORKDIR /var/www 328 | 329 | # Starter script 330 | ENTRYPOINT ["/opt/startup.sh"] 331 | 332 | # By default, launch supervisord to keep the container running. 333 | CMD ["supervisord"] 334 | 335 | # Health check script 336 | HEALTHCHECK --interval=5s --timeout=1s --retries=12 CMD ["/opt/healthcheck.sh"] 337 | 338 | 339 | # Visual Studio Code Server flavor 340 | FROM cli AS code-server 341 | 342 | # Run as docker, so we don't have to fix permissions 343 | USER docker 344 | 345 | ARG HOME=/home/docker 346 | 347 | ENV \ 348 | CODE_SERVER_VERSION=4.104.3 \ 349 | VSCODE_GITLENS_VERSION=17.6.1 \ 350 | VSCODE_XDEBUG_VERSION=1.37.0 \ 351 | VSCODE_HOME="${HOME}/code-server" 352 | 353 | # Install code-server 354 | RUN set -xe; \ 355 | curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${TARGETARCH}.deb" -o /tmp/code-server_${TARGETARCH}.deb; \ 356 | sudo dpkg -i /tmp/code-server_${TARGETARCH}.deb; \ 357 | rm -rf /tmp/*.* 358 | 359 | # Settings 360 | COPY --chown=docker:docker config/code-server ${VSCODE_HOME} 361 | 362 | # Install extensions 363 | # Note: Have to use --user-data-dir with --install-extension instead of --config 364 | RUN set -xe; \ 365 | code-server --user-data-dir=${VSCODE_HOME} --install-extension eamodio.gitlens@${VSCODE_GITLENS_VERSION}; \ 366 | code-server --user-data-dir=${VSCODE_HOME} --install-extension xdebug.php-debug@${VSCODE_XDEBUG_VERSION} 367 | 368 | # Switch back to root (IMPORTANT!) 369 | USER root 370 | -------------------------------------------------------------------------------- /8.3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.3.26-fpm-bookworm AS cli 2 | 3 | ARG TARGETARCH 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 6 | 7 | # Prevent services autoload (http://jpetazzo.github.io/2013/10/06/policy-rc-d-do-not-start-services-automatically/) 8 | RUN set -xe; \ 9 | echo '#!/bin/sh\nexit 101' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d 10 | 11 | # Install basic packages 12 | RUN set -xe; \ 13 | apt-get update >/dev/null; \ 14 | apt-get -y --no-install-recommends install >/dev/null \ 15 | apt-transport-https \ 16 | # ca-certificates and curl come from upstream 17 | #ca-certificates \ 18 | #curl \ 19 | gnupg \ 20 | locales \ 21 | wget \ 22 | ;\ 23 | # Cleanup 24 | apt-get clean; rm -rf /var/lib/apt/lists/* 25 | 26 | # Set en_US.UTF-8 as the default locale 27 | RUN set -xe; \ 28 | echo "en_US.UTF-8 UTF-8" | tee -a /etc/locale.gen; \ 29 | locale-gen en_US.UTF-8; \ 30 | update-locale LANG=en_US.UTF-8 31 | ENV LC_ALL=en_US.UTF-8 32 | 33 | # Additional packages 34 | RUN set -xe; \ 35 | # Create man direcotries, otherwise some packages may not install (e.g. postgresql-client) 36 | # This should be a temporary workaround until fixed upstream: https://github.com/debuerreotype/debuerreotype/issues/10 37 | mkdir -p /usr/share/man/man1 /usr/share/man/man7; \ 38 | apt-get update >/dev/null; \ 39 | apt-get -y --no-install-recommends install >/dev/null \ 40 | cron \ 41 | dnsutils \ 42 | git \ 43 | git-lfs \ 44 | ghostscript \ 45 | # html2text binary - used for self-testing (php-fpm) 46 | html2text \ 47 | imagemagick \ 48 | iputils-ping \ 49 | less \ 50 | # cgi-fcgi binary - used for self-testing (php-fpm) 51 | libfcgi-bin \ 52 | mc \ 53 | msmtp \ 54 | # Debian ships with MariaDB instead of MySQL 55 | mariadb-client \ 56 | nano \ 57 | openssh-client \ 58 | openssh-server \ 59 | postgresql-client \ 60 | procps \ 61 | pv \ 62 | rsync \ 63 | sudo \ 64 | supervisor \ 65 | unzip \ 66 | webp \ 67 | zip \ 68 | ;\ 69 | # Cleanup 70 | apt-get clean; rm -rf /var/lib/apt/lists/* 71 | 72 | RUN set -xe; \ 73 | # Create a regular user/group "docker" (uid = 1000, gid = 1000 ) 74 | useradd -m -s /bin/bash -u 1000 -U -p docker docker; \ 75 | # Give the docker user sudo access 76 | usermod -a -G sudo docker; \ 77 | echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 78 | 79 | # gosu v1.14+ discorages using it as a non-root user (https://github.com/tianon/gosu/issues/11), which we rely on here. 80 | # See https://github.com/tianon/gosu/pull/89/commits/8afd3dec5fb4fe0356e4fb5d358fe235f7311181 81 | # We'll stick with v1.13 for the time being. 82 | # TODO: Replace gosu with sudo/su in startup.sh 83 | ENV \ 84 | GOSU_VERSION=1.13 \ 85 | GOMPLATE_VERSION=3.11.3 86 | RUN set -xe; \ 87 | # Install gosu and give access to the docker user primary group to use it. 88 | # gosu is used instead of sudo to start the main container process (pid 1) in a docker friendly way. 89 | # https://github.com/tianon/gosu 90 | curl -fsSL https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${TARGETARCH} -o /usr/local/bin/gosu; \ 91 | chown root:$(id -gn docker) /usr/local/bin/gosu; \ 92 | chmod +sx /usr/local/bin/gosu; \ 93 | # gomplate (to process configuration templates in startup.sh) 94 | curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-${TARGETARCH} -o /usr/local/bin/gomplate; \ 95 | chmod +x /usr/local/bin/gomplate 96 | 97 | # Configure sshd (for use PHPStorm's remote interpreters and tools integrations) 98 | # http://docs.docker.com/examples/running_ssh_service/ 99 | RUN set -xe; \ 100 | mkdir /var/run/sshd; \ 101 | echo 'docker:docker' | chpasswd; \ 102 | sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config; \ 103 | # SSH login fix. Otherwise user is kicked off after login 104 | sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd; \ 105 | echo "export VISIBLE=now" >> /etc/profile 106 | ENV NOTVISIBLE="in users profile" 107 | 108 | # PHP 109 | RUN set -xe; \ 110 | # Note: essential build tools (g++, gcc, make, etc) are included upstream as persistent packages. 111 | # Docker PHP Extension Installer 112 | curl -sSLf "https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions" -o /usr/local/bin/install-php-extensions \ 113 | && chmod +x /usr/local/bin/install-php-extensions; \ 114 | # Instal/enable all PHP extensions via mlocati/docker-php-extension-installer 115 | install-php-extensions \ 116 | # Stock extensions from upstream image 117 | bcmath \ 118 | bz2 \ 119 | calendar\ 120 | exif \ 121 | ftp \ 122 | gd \ 123 | gettext \ 124 | imap \ 125 | intl \ 126 | ldap \ 127 | mysqli \ 128 | opcache \ 129 | pcntl \ 130 | pdo_mysql \ 131 | pdo_pgsql \ 132 | pgsql \ 133 | soap \ 134 | sockets \ 135 | xsl \ 136 | zip \ 137 | sysvsem \ 138 | # Pecl extensions 139 | apcu \ 140 | gnupg \ 141 | imagick \ 142 | memcached \ 143 | redis \ 144 | ssh2 \ 145 | xdebug \ 146 | xhprof \ 147 | # MSSQL PHP client 148 | pdo_sqlsrv \ 149 | sqlsrv \ 150 | ;\ 151 | # Disable xdebug and xhprof by default to avoid performance impact 152 | # They can be enabled via environment variables at runtime (XDEBUG_ENABLED=1 and XHPROF_ENABLED=1) 153 | # There is no native "docker-php-ext-disable", so we remove the ini files manually 154 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"; \ 155 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xhprof.ini" 156 | 157 | # PHP tools (installed globally) 158 | ENV \ 159 | COMPOSER_DEFAULT_VERSION=2 \ 160 | COMPOSER_VERSION=1.10.27 \ 161 | COMPOSER2_VERSION=2.8.12 \ 162 | DRUSH_VERSION=8.4.12 \ 163 | DRUPAL_CONSOLE_LAUNCHER_VERSION=1.9.7 \ 164 | WPCLI_VERSION=2.12.0 \ 165 | PLATFORMSH_CLI_VERSION=5.6.0 \ 166 | ACQUIA_CLI_VERSION=2.49.0 \ 167 | TERMINUS_VERSION=4.1.0 \ 168 | JQ_VERSION=1.8.1 \ 169 | YQ_VERSION=4.48.1 170 | RUN set -xe; \ 171 | # Composer 1.x 172 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar" -o /usr/local/bin/composer1; \ 173 | # Composer 2.x 174 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER2_VERSION}/composer.phar" -o /usr/local/bin/composer2; \ 175 | # Drush 8 (global fallback) 176 | curl -fsSL "https://github.com/drush-ops/drush/releases/download/${DRUSH_VERSION}/drush.phar" -o /usr/local/bin/drush8; \ 177 | # Drupal Console Launcher 178 | curl -fsSL "https://github.com/hechoendrupal/drupal-console-launcher/releases/download/${DRUPAL_CONSOLE_LAUNCHER_VERSION}/drupal.phar" -o /usr/local/bin/drupal; \ 179 | # Wordpress CLI 180 | curl -fsSL "https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar" -o /usr/local/bin/wp; \ 181 | # Platform.sh CLI 182 | curl -fsSL "https://github.com/platformsh/cli/releases/download/${PLATFORMSH_CLI_VERSION}/platform_${PLATFORMSH_CLI_VERSION}_linux_${TARGETARCH}.tar.gz" -o /tmp/platform.tar.gz; \ 183 | tar -xzf /tmp/platform.tar.gz -C /tmp && mv /tmp/platform /usr/local/bin/platform; rm -rf /tmp/*; \ 184 | # Acquia CLI 185 | curl -fsSL "https://github.com/acquia/cli/releases/download/${ACQUIA_CLI_VERSION}/acli.phar" -o /usr/local/bin/acli; \ 186 | # Pantheon Terminus 187 | curl -fsSL "https://github.com/pantheon-systems/terminus/releases/download/${TERMINUS_VERSION}/terminus.phar" -o /usr/local/bin/terminus; \ 188 | # jq 189 | curl -fsSL "https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}/jq-linux-${TARGETARCH}" -o /usr/local/bin/jq; \ 190 | # yq 191 | curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq; \ 192 | # Set Default Composer Version 193 | ln -s /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer; \ 194 | # Make all downloaded binaries executable in one shot 195 | (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drupal wp platform acli terminus jq yq); 196 | 197 | # Install Python 3 + pip from Debian repos 198 | RUN set -xe; \ 199 | apt-get update >/dev/null; \ 200 | apt-get -y --no-install-recommends install >/dev/null \ 201 | python3 \ 202 | python3-pip \ 203 | ;\ 204 | # Cleanup 205 | apt-get clean; rm -rf /var/lib/apt/lists/* 206 | 207 | # Install Ruby from Debian repos 208 | RUN set -xe; \ 209 | apt-get update >/dev/null; \ 210 | apt-get -y --no-install-recommends install >/dev/null \ 211 | ruby-full \ 212 | ;\ 213 | # Cleanup 214 | apt-get clean; rm -rf /var/lib/apt/lists/* 215 | 216 | # Install a newer SQLite version from Debian Trixie (testing) repo 217 | # Debian Bookworm (main) ships with sqlite v3.40. Drupal 11 requires SQLite v3.45+. 218 | # @see https://www.drupal.org/project/drupal/issues/3346338 219 | RUN set -xe; \ 220 | echo "deb https://deb.debian.org/debian testing main" | tee /etc/apt/sources.list.d/testing.list; \ 221 | apt-get update >/dev/null; \ 222 | apt-get install -y -t testing sqlite3;\ 223 | # Cleanup 224 | apt-get clean; rm -rf /var/lib/apt/lists/*; rm -f /etc/apt/sources.list.d/testing.list 225 | 226 | # All further RUN commands will run as the "docker" user 227 | USER docker 228 | SHELL ["/bin/bash", "-c"] 229 | 230 | # Don't use -x here, as the output may be excessive 231 | RUN set -e; \ 232 | \ 233 | # Composer based dependencies 234 | # Add composer bin project level and global directories to PATH 235 | # Project level comes first and thus takes precedence over the global one 236 | echo -e "\n"'export PATH="$PATH:${PROJECT_ROOT:-/var/www}/vendor/bin"' >> $HOME/.profile; \ 237 | echo -e "\n"'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> $HOME/.profile; \ 238 | # Reload updated PATH from profile to make composer/etc. visible below 239 | . $HOME/.profile; \ 240 | # Drupal Coder & WP Coding Standards w/ a matching version of PHP_CodeSniffer 241 | # Set allow-plugins. See https://getcomposer.org/allow-plugins 242 | composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true; \ 243 | composer global require drupal/coder wp-coding-standards/wpcs phpcompatibility/phpcompatibility-wp; \ 244 | # Don't fix the indentation or installed_paths will not be set correctly 245 | phpcs --config-set installed_paths \ 246 | $HOME/.composer/vendor/drupal/coder/coder_sniffer/,\ 247 | $HOME/.composer/vendor/wp-coding-standards/wpcs/,\ 248 | $HOME/.composer/vendor/phpcompatibility/php-compatibility/PHPCompatibility/,\ 249 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp/PHPCompatibilityWP,\ 250 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie/PHPCompatibilityParagonieRandomCompat; \ 251 | # Cleanup 252 | composer clear-cache 253 | 254 | # Node.js (installed as user) 255 | ENV \ 256 | NVM_VERSION=0.40.3 \ 257 | NODE_VERSION=22.20.0 \ 258 | # Yarn (Classic v1) 259 | # https://github.com/yarnpkg/yarn/releases 260 | YARN_VERSION=1.22.22 261 | # Don't use -x here, as the output may be excessive 262 | RUN set -e; \ 263 | # NVM and a defaut Node.js version 264 | export PROFILE="$HOME/.profile"; \ 265 | curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash >/dev/null; \ 266 | # Reload profile to load nvm (needed by Yarn installation below) 267 | . $HOME/.profile; \ 268 | # Yarn (Classic v1) 269 | # Installing via npm to allow fore override with never versions via corepack 270 | npm install -g yarn@${YARN_VERSION}; \ 271 | # Enable corepack (allows installing project level yarn v2+ via yarn) 272 | corepack enable 273 | 274 | ## Ruby bundler 275 | ## Don't use -x here, as the output may be excessive 276 | RUN set -e; \ 277 | # Export ruby gem bin path 278 | echo 'export PATH=$PATH:$(ruby -r rubygems -e "puts Gem.user_dir")/bin' >> $HOME/.profile; \ 279 | . $HOME/.profile; \ 280 | gem install --user-install bundler; \ 281 | # Have bundler install gems in the current directory (./.bundle) by default 282 | echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile 283 | 284 | # Notify web container about started fin exec 285 | RUN echo '(/opt/ping-web.sh &)' >> $HOME/.profile 286 | 287 | USER root 288 | SHELL ["/bin/sh", "-c"] 289 | 290 | # Copy configs and scripts 291 | COPY --chown=docker:docker config/.terminus /home/docker/.terminus 292 | COPY --chown=docker:docker config/.ssh /home/docker/.ssh 293 | COPY config/supervisor /etc/supervisor/conf.d 294 | COPY startup.sh /opt/startup.sh 295 | COPY healthcheck.sh /opt/healthcheck.sh 296 | COPY ping-web.sh /opt/ping-web.sh 297 | # PHP default settings, global overrides and fpm overrides 298 | RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" 299 | COPY config/php/zz-php.ini /usr/local/etc/php/conf.d/zz-php.ini 300 | COPY config/php/xdebug.ini /opt/docker-php-ext-xdebug.ini 301 | COPY config/php/xhprof.ini /opt/docker-php-ext-xhprof.ini 302 | COPY config/php/opcache.ini /opt/docker-php-ext-opcache.ini 303 | COPY config/php/zz-php-fpm.conf /usr/local/etc/php-fpm.d/zz-php-fpm.conf 304 | 305 | ENV \ 306 | # ssh-agent proxy socket (requires docksal/ssh-agent) 307 | SSH_AUTH_SOCK=/.ssh-agent/proxy-socket \ 308 | # Set TERM so text editors/etc. can be used 309 | TERM=xterm \ 310 | # Allow PROJECT_ROOT to be universally used in fin custom commands (inside and outside cli) 311 | PROJECT_ROOT=/var/www \ 312 | # Default values for HOST_UID and HOST_GUI to match the default Ubuntu user. These are used in startup.sh 313 | HOST_UID=1000 \ 314 | HOST_GID=1000 \ 315 | # Delay in seconds between pings web from cli, while running fin exec. 0 - disabled 316 | WEB_KEEPALIVE=0 \ 317 | # xdebug disabled by default 318 | XDEBUG_ENABLED=0 \ 319 | XHPROF_ENABLED=0 \ 320 | XHPROF_OUTPUT_DIR=/tmp/xhprof 321 | 322 | # TODO: [v3] remove and set these via docker-compose 323 | EXPOSE 9000 324 | EXPOSE 22 325 | EXPOSE 3000 326 | 327 | WORKDIR /var/www 328 | 329 | # Starter script 330 | ENTRYPOINT ["/opt/startup.sh"] 331 | 332 | # By default, launch supervisord to keep the container running. 333 | CMD ["supervisord"] 334 | 335 | # Health check script 336 | HEALTHCHECK --interval=5s --timeout=1s --retries=12 CMD ["/opt/healthcheck.sh"] 337 | 338 | 339 | # Visual Studio Code Server flavor 340 | FROM cli AS code-server 341 | 342 | # Run as docker, so we don't have to fix permissions 343 | USER docker 344 | 345 | ARG HOME=/home/docker 346 | 347 | ENV \ 348 | CODE_SERVER_VERSION=4.104.3 \ 349 | VSCODE_GITLENS_VERSION=17.6.1 \ 350 | VSCODE_XDEBUG_VERSION=1.37.0 \ 351 | VSCODE_HOME="${HOME}/code-server" 352 | 353 | # Install code-server 354 | RUN set -xe; \ 355 | curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${TARGETARCH}.deb" -o /tmp/code-server_${TARGETARCH}.deb; \ 356 | sudo dpkg -i /tmp/code-server_${TARGETARCH}.deb; \ 357 | rm -rf /tmp/*.* 358 | 359 | # Settings 360 | COPY --chown=docker:docker config/code-server ${VSCODE_HOME} 361 | 362 | # Install extensions 363 | # Note: Have to use --user-data-dir with --install-extension instead of --config 364 | RUN set -xe; \ 365 | code-server --user-data-dir=${VSCODE_HOME} --install-extension eamodio.gitlens@${VSCODE_GITLENS_VERSION}; \ 366 | code-server --user-data-dir=${VSCODE_HOME} --install-extension xdebug.php-debug@${VSCODE_XDEBUG_VERSION} 367 | 368 | # Switch back to root (IMPORTANT!) 369 | USER root 370 | -------------------------------------------------------------------------------- /8.4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.4.13-fpm-bookworm AS cli 2 | 3 | ARG TARGETARCH 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 6 | 7 | # Prevent services autoload (http://jpetazzo.github.io/2013/10/06/policy-rc-d-do-not-start-services-automatically/) 8 | RUN set -xe; \ 9 | echo '#!/bin/sh\nexit 101' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d 10 | 11 | # Install basic packages 12 | RUN set -xe; \ 13 | apt-get update >/dev/null; \ 14 | apt-get -y --no-install-recommends install >/dev/null \ 15 | apt-transport-https \ 16 | # ca-certificates and curl come from upstream 17 | #ca-certificates \ 18 | #curl \ 19 | gnupg \ 20 | locales \ 21 | wget \ 22 | ;\ 23 | # Cleanup 24 | apt-get clean; rm -rf /var/lib/apt/lists/* 25 | 26 | # Set en_US.UTF-8 as the default locale 27 | RUN set -xe; \ 28 | echo "en_US.UTF-8 UTF-8" | tee -a /etc/locale.gen; \ 29 | locale-gen en_US.UTF-8; \ 30 | update-locale LANG=en_US.UTF-8 31 | ENV LC_ALL=en_US.UTF-8 32 | 33 | # Additional packages 34 | RUN set -xe; \ 35 | # Create man direcotries, otherwise some packages may not install (e.g. postgresql-client) 36 | # This should be a temporary workaround until fixed upstream: https://github.com/debuerreotype/debuerreotype/issues/10 37 | mkdir -p /usr/share/man/man1 /usr/share/man/man7; \ 38 | apt-get update >/dev/null; \ 39 | apt-get -y --no-install-recommends install >/dev/null \ 40 | cron \ 41 | dnsutils \ 42 | git \ 43 | git-lfs \ 44 | ghostscript \ 45 | # html2text binary - used for self-testing (php-fpm) 46 | html2text \ 47 | imagemagick \ 48 | iputils-ping \ 49 | less \ 50 | # cgi-fcgi binary - used for self-testing (php-fpm) 51 | libfcgi-bin \ 52 | mc \ 53 | msmtp \ 54 | # Debian ships with MariaDB instead of MySQL 55 | mariadb-client \ 56 | nano \ 57 | openssh-client \ 58 | openssh-server \ 59 | postgresql-client \ 60 | procps \ 61 | pv \ 62 | rsync \ 63 | sudo \ 64 | supervisor \ 65 | unzip \ 66 | webp \ 67 | zip \ 68 | ;\ 69 | # Cleanup 70 | apt-get clean; rm -rf /var/lib/apt/lists/* 71 | 72 | RUN set -xe; \ 73 | # Create a regular user/group "docker" (uid = 1000, gid = 1000 ) 74 | useradd -m -s /bin/bash -u 1000 -U -p docker docker; \ 75 | # Give the docker user sudo access 76 | usermod -a -G sudo docker; \ 77 | echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 78 | 79 | # gosu v1.14+ discorages using it as a non-root user (https://github.com/tianon/gosu/issues/11), which we rely on here. 80 | # See https://github.com/tianon/gosu/pull/89/commits/8afd3dec5fb4fe0356e4fb5d358fe235f7311181 81 | # We'll stick with v1.13 for the time being. 82 | # TODO: Replace gosu with sudo/su in startup.sh 83 | ENV \ 84 | GOSU_VERSION=1.13 \ 85 | GOMPLATE_VERSION=3.11.3 86 | RUN set -xe; \ 87 | # Install gosu and give access to the docker user primary group to use it. 88 | # gosu is used instead of sudo to start the main container process (pid 1) in a docker friendly way. 89 | # https://github.com/tianon/gosu 90 | curl -fsSL https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${TARGETARCH} -o /usr/local/bin/gosu; \ 91 | chown root:$(id -gn docker) /usr/local/bin/gosu; \ 92 | chmod +sx /usr/local/bin/gosu; \ 93 | # gomplate (to process configuration templates in startup.sh) 94 | curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-${TARGETARCH} -o /usr/local/bin/gomplate; \ 95 | chmod +x /usr/local/bin/gomplate 96 | 97 | # Configure sshd (for use PHPStorm's remote interpreters and tools integrations) 98 | # http://docs.docker.com/examples/running_ssh_service/ 99 | RUN set -xe; \ 100 | mkdir /var/run/sshd; \ 101 | echo 'docker:docker' | chpasswd; \ 102 | sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config; \ 103 | # SSH login fix. Otherwise user is kicked off after login 104 | sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd; \ 105 | echo "export VISIBLE=now" >> /etc/profile 106 | ENV NOTVISIBLE="in users profile" 107 | 108 | # PHP 109 | RUN set -xe; \ 110 | # Note: essential build tools (g++, gcc, make, etc) are included upstream as persistent packages. 111 | # Docker PHP Extension Installer 112 | curl -sSLf "https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions" -o /usr/local/bin/install-php-extensions \ 113 | && chmod +x /usr/local/bin/install-php-extensions; \ 114 | # Instal/enable all PHP extensions via mlocati/docker-php-extension-installer 115 | install-php-extensions \ 116 | # Stock extensions from upstream image 117 | bcmath \ 118 | bz2 \ 119 | calendar\ 120 | exif \ 121 | ftp \ 122 | gd \ 123 | gettext \ 124 | imap \ 125 | intl \ 126 | ldap \ 127 | mysqli \ 128 | opcache \ 129 | pcntl \ 130 | pdo_mysql \ 131 | pdo_pgsql \ 132 | pgsql \ 133 | soap \ 134 | sockets \ 135 | xsl \ 136 | zip \ 137 | sysvsem \ 138 | # Pecl extensions 139 | apcu \ 140 | gnupg \ 141 | imagick \ 142 | memcached \ 143 | redis \ 144 | ssh2 \ 145 | xdebug \ 146 | xhprof \ 147 | # MSSQL PHP client 148 | pdo_sqlsrv \ 149 | sqlsrv \ 150 | ;\ 151 | # Disable xdebug and xhprof by default to avoid performance impact 152 | # They can be enabled via environment variables at runtime (XDEBUG_ENABLED=1 and XHPROF_ENABLED=1) 153 | # There is no native "docker-php-ext-disable", so we remove the ini files manually 154 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"; \ 155 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xhprof.ini" 156 | 157 | # PHP tools (installed globally) 158 | ENV \ 159 | COMPOSER_DEFAULT_VERSION=2 \ 160 | COMPOSER_VERSION=1.10.27 \ 161 | COMPOSER2_VERSION=2.8.12 \ 162 | DRUSH_VERSION=8.4.12 \ 163 | DRUPAL_CONSOLE_LAUNCHER_VERSION=1.9.7 \ 164 | WPCLI_VERSION=2.12.0 \ 165 | PLATFORMSH_CLI_VERSION=5.6.0 \ 166 | ACQUIA_CLI_VERSION=2.49.0 \ 167 | TERMINUS_VERSION=4.1.0 \ 168 | JQ_VERSION=1.8.1 \ 169 | YQ_VERSION=4.48.1 170 | RUN set -xe; \ 171 | # Composer 1.x 172 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar" -o /usr/local/bin/composer1; \ 173 | # Composer 2.x 174 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER2_VERSION}/composer.phar" -o /usr/local/bin/composer2; \ 175 | # Drush 8 (global fallback) 176 | curl -fsSL "https://github.com/drush-ops/drush/releases/download/${DRUSH_VERSION}/drush.phar" -o /usr/local/bin/drush8; \ 177 | # Drupal Console Launcher 178 | curl -fsSL "https://github.com/hechoendrupal/drupal-console-launcher/releases/download/${DRUPAL_CONSOLE_LAUNCHER_VERSION}/drupal.phar" -o /usr/local/bin/drupal; \ 179 | # Wordpress CLI 180 | curl -fsSL "https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar" -o /usr/local/bin/wp; \ 181 | # Platform.sh CLI 182 | curl -fsSL "https://github.com/platformsh/cli/releases/download/${PLATFORMSH_CLI_VERSION}/platform_${PLATFORMSH_CLI_VERSION}_linux_${TARGETARCH}.tar.gz" -o /tmp/platform.tar.gz; \ 183 | tar -xzf /tmp/platform.tar.gz -C /tmp && mv /tmp/platform /usr/local/bin/platform; rm -rf /tmp/*; \ 184 | # Acquia CLI 185 | curl -fsSL "https://github.com/acquia/cli/releases/download/${ACQUIA_CLI_VERSION}/acli.phar" -o /usr/local/bin/acli; \ 186 | # Pantheon Terminus 187 | curl -fsSL "https://github.com/pantheon-systems/terminus/releases/download/${TERMINUS_VERSION}/terminus.phar" -o /usr/local/bin/terminus; \ 188 | # jq 189 | curl -fsSL "https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}/jq-linux-${TARGETARCH}" -o /usr/local/bin/jq; \ 190 | # yq 191 | curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq; \ 192 | # Set Default Composer Version 193 | ln -s /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer; \ 194 | # Make all downloaded binaries executable in one shot 195 | (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drupal wp platform acli terminus jq yq); 196 | 197 | # Install Python 3 + pip from Debian repos 198 | RUN set -xe; \ 199 | apt-get update >/dev/null; \ 200 | apt-get -y --no-install-recommends install >/dev/null \ 201 | python3 \ 202 | python3-pip \ 203 | ;\ 204 | # Cleanup 205 | apt-get clean; rm -rf /var/lib/apt/lists/* 206 | 207 | # Install Ruby from Debian repos 208 | RUN set -xe; \ 209 | apt-get update >/dev/null; \ 210 | apt-get -y --no-install-recommends install >/dev/null \ 211 | ruby-full \ 212 | ;\ 213 | # Cleanup 214 | apt-get clean; rm -rf /var/lib/apt/lists/* 215 | 216 | # Install a newer SQLite version from Debian Trixie (testing) repo 217 | # Debian Bookworm (main) ships with sqlite v3.40. Drupal 11 requires SQLite v3.45+. 218 | # @see https://www.drupal.org/project/drupal/issues/3346338 219 | RUN set -xe; \ 220 | echo "deb https://deb.debian.org/debian testing main" | tee /etc/apt/sources.list.d/testing.list; \ 221 | apt-get update >/dev/null; \ 222 | apt-get install -y -t testing sqlite3;\ 223 | # Cleanup 224 | apt-get clean; rm -rf /var/lib/apt/lists/*; rm -f /etc/apt/sources.list.d/testing.list 225 | 226 | # All further RUN commands will run as the "docker" user 227 | USER docker 228 | SHELL ["/bin/bash", "-c"] 229 | 230 | # Don't use -x here, as the output may be excessive 231 | RUN set -e; \ 232 | \ 233 | # Composer based dependencies 234 | # Add composer bin project level and global directories to PATH 235 | # Project level comes first and thus takes precedence over the global one 236 | echo -e "\n"'export PATH="$PATH:${PROJECT_ROOT:-/var/www}/vendor/bin"' >> $HOME/.profile; \ 237 | echo -e "\n"'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> $HOME/.profile; \ 238 | # Reload updated PATH from profile to make composer/etc. visible below 239 | . $HOME/.profile; \ 240 | # Drupal Coder & WP Coding Standards w/ a matching version of PHP_CodeSniffer 241 | # Set allow-plugins. See https://getcomposer.org/allow-plugins 242 | composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true; \ 243 | composer global require drupal/coder wp-coding-standards/wpcs phpcompatibility/phpcompatibility-wp; \ 244 | # Don't fix the indentation or installed_paths will not be set correctly 245 | phpcs --config-set installed_paths \ 246 | $HOME/.composer/vendor/drupal/coder/coder_sniffer/,\ 247 | $HOME/.composer/vendor/wp-coding-standards/wpcs/,\ 248 | $HOME/.composer/vendor/phpcompatibility/php-compatibility/PHPCompatibility/,\ 249 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp/PHPCompatibilityWP,\ 250 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie/PHPCompatibilityParagonieRandomCompat; \ 251 | # Cleanup 252 | composer clear-cache 253 | 254 | # Node.js (installed as user) 255 | ENV \ 256 | NVM_VERSION=0.40.3 \ 257 | NODE_VERSION=22.20.0 \ 258 | # Yarn (Classic v1) 259 | # https://github.com/yarnpkg/yarn/releases 260 | YARN_VERSION=1.22.22 261 | # Don't use -x here, as the output may be excessive 262 | RUN set -e; \ 263 | # NVM and a defaut Node.js version 264 | export PROFILE="$HOME/.profile"; \ 265 | curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash >/dev/null; \ 266 | # Reload profile to load nvm (needed by Yarn installation below) 267 | . $HOME/.profile; \ 268 | # Yarn (Classic v1) 269 | # Installing via npm to allow fore override with never versions via corepack 270 | npm install -g yarn@${YARN_VERSION}; \ 271 | # Enable corepack (allows installing project level yarn v2+ via yarn) 272 | corepack enable 273 | 274 | ## Ruby bundler 275 | ## Don't use -x here, as the output may be excessive 276 | RUN set -e; \ 277 | # Export ruby gem bin path 278 | echo 'export PATH=$PATH:$(ruby -r rubygems -e "puts Gem.user_dir")/bin' >> $HOME/.profile; \ 279 | . $HOME/.profile; \ 280 | gem install --user-install bundler; \ 281 | # Have bundler install gems in the current directory (./.bundle) by default 282 | echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile 283 | 284 | # Notify web container about started fin exec 285 | RUN echo '(/opt/ping-web.sh &)' >> $HOME/.profile 286 | 287 | USER root 288 | SHELL ["/bin/sh", "-c"] 289 | 290 | # Copy configs and scripts 291 | COPY --chown=docker:docker config/.terminus /home/docker/.terminus 292 | COPY --chown=docker:docker config/.ssh /home/docker/.ssh 293 | COPY config/supervisor /etc/supervisor/conf.d 294 | COPY startup.sh /opt/startup.sh 295 | COPY healthcheck.sh /opt/healthcheck.sh 296 | COPY ping-web.sh /opt/ping-web.sh 297 | # PHP default settings, global overrides and fpm overrides 298 | RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" 299 | COPY config/php/zz-php.ini /usr/local/etc/php/conf.d/zz-php.ini 300 | COPY config/php/xdebug.ini /opt/docker-php-ext-xdebug.ini 301 | COPY config/php/xhprof.ini /opt/docker-php-ext-xhprof.ini 302 | COPY config/php/opcache.ini /opt/docker-php-ext-opcache.ini 303 | COPY config/php/zz-php-fpm.conf /usr/local/etc/php-fpm.d/zz-php-fpm.conf 304 | 305 | ENV \ 306 | # ssh-agent proxy socket (requires docksal/ssh-agent) 307 | SSH_AUTH_SOCK=/.ssh-agent/proxy-socket \ 308 | # Set TERM so text editors/etc. can be used 309 | TERM=xterm \ 310 | # Allow PROJECT_ROOT to be universally used in fin custom commands (inside and outside cli) 311 | PROJECT_ROOT=/var/www \ 312 | # Default values for HOST_UID and HOST_GUI to match the default Ubuntu user. These are used in startup.sh 313 | HOST_UID=1000 \ 314 | HOST_GID=1000 \ 315 | # Delay in seconds between pings web from cli, while running fin exec. 0 - disabled 316 | WEB_KEEPALIVE=0 \ 317 | # xdebug disabled by default 318 | XDEBUG_ENABLED=0 \ 319 | XHPROF_ENABLED=0 \ 320 | XHPROF_OUTPUT_DIR=/tmp/xhprof 321 | 322 | # TODO: [v3] remove and set these via docker-compose 323 | EXPOSE 9000 324 | EXPOSE 22 325 | EXPOSE 3000 326 | 327 | WORKDIR /var/www 328 | 329 | # Starter script 330 | ENTRYPOINT ["/opt/startup.sh"] 331 | 332 | # By default, launch supervisord to keep the container running. 333 | CMD ["supervisord"] 334 | 335 | # Health check script 336 | HEALTHCHECK --interval=5s --timeout=1s --retries=12 CMD ["/opt/healthcheck.sh"] 337 | 338 | 339 | # Visual Studio Code Server flavor 340 | FROM cli AS code-server 341 | 342 | # Run as docker, so we don't have to fix permissions 343 | USER docker 344 | 345 | ARG HOME=/home/docker 346 | 347 | ENV \ 348 | CODE_SERVER_VERSION=4.104.3 \ 349 | VSCODE_GITLENS_VERSION=17.6.1 \ 350 | VSCODE_XDEBUG_VERSION=1.37.0 \ 351 | VSCODE_HOME="${HOME}/code-server" 352 | 353 | # Install code-server 354 | RUN set -xe; \ 355 | curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${TARGETARCH}.deb" -o /tmp/code-server_${TARGETARCH}.deb; \ 356 | sudo dpkg -i /tmp/code-server_${TARGETARCH}.deb; \ 357 | rm -rf /tmp/*.* 358 | 359 | # Settings 360 | COPY --chown=docker:docker config/code-server ${VSCODE_HOME} 361 | 362 | # Install extensions 363 | # Note: Have to use --user-data-dir with --install-extension instead of --config 364 | RUN set -xe; \ 365 | code-server --user-data-dir=${VSCODE_HOME} --install-extension eamodio.gitlens@${VSCODE_GITLENS_VERSION}; \ 366 | code-server --user-data-dir=${VSCODE_HOME} --install-extension xdebug.php-debug@${VSCODE_XDEBUG_VERSION} 367 | 368 | # Switch back to root (IMPORTANT!) 369 | USER root 370 | -------------------------------------------------------------------------------- /8.1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.1.33-fpm-bookworm AS cli 2 | 3 | ARG TARGETARCH 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 6 | 7 | # Prevent services autoload (http://jpetazzo.github.io/2013/10/06/policy-rc-d-do-not-start-services-automatically/) 8 | RUN set -xe; \ 9 | echo '#!/bin/sh\nexit 101' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d 10 | 11 | # Install basic packages 12 | RUN set -xe; \ 13 | apt-get update >/dev/null; \ 14 | apt-get -y --no-install-recommends install >/dev/null \ 15 | apt-transport-https \ 16 | # ca-certificates and curl come from upstream 17 | #ca-certificates \ 18 | #curl \ 19 | gnupg \ 20 | locales \ 21 | wget \ 22 | ;\ 23 | # Cleanup 24 | apt-get clean; rm -rf /var/lib/apt/lists/* 25 | 26 | # Set en_US.UTF-8 as the default locale 27 | RUN set -xe; \ 28 | echo "en_US.UTF-8 UTF-8" | tee -a /etc/locale.gen; \ 29 | locale-gen en_US.UTF-8; \ 30 | update-locale LANG=en_US.UTF-8 31 | ENV LC_ALL=en_US.UTF-8 32 | 33 | # Additional packages 34 | RUN set -xe; \ 35 | # Create man direcotries, otherwise some packages may not install (e.g. postgresql-client) 36 | # This should be a temporary workaround until fixed upstream: https://github.com/debuerreotype/debuerreotype/issues/10 37 | mkdir -p /usr/share/man/man1 /usr/share/man/man7; \ 38 | apt-get update >/dev/null; \ 39 | apt-get -y --no-install-recommends install >/dev/null \ 40 | cron \ 41 | dnsutils \ 42 | git \ 43 | git-lfs \ 44 | ghostscript \ 45 | # html2text binary - used for self-testing (php-fpm) 46 | html2text \ 47 | imagemagick \ 48 | iputils-ping \ 49 | less \ 50 | # cgi-fcgi binary - used for self-testing (php-fpm) 51 | libfcgi-bin \ 52 | mc \ 53 | msmtp \ 54 | # Debian ships with MariaDB instead of MySQL 55 | mariadb-client \ 56 | nano \ 57 | openssh-client \ 58 | openssh-server \ 59 | postgresql-client \ 60 | procps \ 61 | pv \ 62 | rsync \ 63 | sudo \ 64 | supervisor \ 65 | unzip \ 66 | webp \ 67 | zip \ 68 | ;\ 69 | # Cleanup 70 | apt-get clean; rm -rf /var/lib/apt/lists/* 71 | 72 | RUN set -xe; \ 73 | # Create a regular user/group "docker" (uid = 1000, gid = 1000 ) 74 | useradd -m -s /bin/bash -u 1000 -U -p docker docker; \ 75 | # Give the docker user sudo access 76 | usermod -a -G sudo docker; \ 77 | echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 78 | 79 | # gosu v1.14+ discorages using it as a non-root user (https://github.com/tianon/gosu/issues/11), which we rely on here. 80 | # See https://github.com/tianon/gosu/pull/89/commits/8afd3dec5fb4fe0356e4fb5d358fe235f7311181 81 | # We'll stick with v1.13 for the time being. 82 | # TODO: Replace gosu with sudo/su in startup.sh 83 | ENV \ 84 | GOSU_VERSION=1.13 \ 85 | GOMPLATE_VERSION=3.11.3 86 | RUN set -xe; \ 87 | # Install gosu and give access to the docker user primary group to use it. 88 | # gosu is used instead of sudo to start the main container process (pid 1) in a docker friendly way. 89 | # https://github.com/tianon/gosu 90 | curl -fsSL https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${TARGETARCH} -o /usr/local/bin/gosu; \ 91 | chown root:$(id -gn docker) /usr/local/bin/gosu; \ 92 | chmod +sx /usr/local/bin/gosu; \ 93 | # gomplate (to process configuration templates in startup.sh) 94 | curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-${TARGETARCH} -o /usr/local/bin/gomplate; \ 95 | chmod +x /usr/local/bin/gomplate 96 | 97 | # Configure sshd (for use PHPStorm's remote interpreters and tools integrations) 98 | # http://docs.docker.com/examples/running_ssh_service/ 99 | RUN set -xe; \ 100 | mkdir /var/run/sshd; \ 101 | echo 'docker:docker' | chpasswd; \ 102 | sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config; \ 103 | # SSH login fix. Otherwise user is kicked off after login 104 | sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd; \ 105 | echo "export VISIBLE=now" >> /etc/profile 106 | ENV NOTVISIBLE="in users profile" 107 | 108 | # PHP 109 | RUN set -xe; \ 110 | # Note: essential build tools (g++, gcc, make, etc) are included upstream as persistent packages. 111 | # Docker PHP Extension Installer 112 | curl -sSLf "https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions" -o /usr/local/bin/install-php-extensions \ 113 | && chmod +x /usr/local/bin/install-php-extensions; \ 114 | # Instal/enable all PHP extensions via mlocati/docker-php-extension-installer 115 | install-php-extensions \ 116 | # Stock extensions from upstream image 117 | bcmath \ 118 | bz2 \ 119 | calendar\ 120 | exif \ 121 | gd \ 122 | gettext \ 123 | imap \ 124 | intl \ 125 | ldap \ 126 | mysqli \ 127 | opcache \ 128 | pcntl \ 129 | pdo_mysql \ 130 | pdo_pgsql \ 131 | pgsql \ 132 | soap \ 133 | sockets \ 134 | xsl \ 135 | zip \ 136 | sysvsem \ 137 | # Pecl extensions 138 | apcu \ 139 | gnupg \ 140 | imagick \ 141 | memcached \ 142 | redis \ 143 | ssh2 \ 144 | xdebug \ 145 | xhprof \ 146 | # MSSQL PHP client 147 | pdo_sqlsrv \ 148 | sqlsrv \ 149 | ;\ 150 | # Disable xdebug and xhprof by default to avoid performance impact 151 | # They can be enabled via environment variables at runtime (XDEBUG_ENABLED=1 and XHPROF_ENABLED=1) 152 | # There is no native "docker-php-ext-disable", so we remove the ini files manually 153 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"; \ 154 | rm -f "$PHP_INI_DIR/conf.d/docker-php-ext-xhprof.ini" 155 | 156 | # PHP tools (installed globally) 157 | ENV \ 158 | COMPOSER_DEFAULT_VERSION=2 \ 159 | COMPOSER_VERSION=1.10.27 \ 160 | COMPOSER2_VERSION=2.8.12 \ 161 | DRUSH_VERSION=8.4.12 \ 162 | DRUPAL_CONSOLE_LAUNCHER_VERSION=1.9.7 \ 163 | WPCLI_VERSION=2.12.0 \ 164 | PLATFORMSH_CLI_VERSION=5.6.0 \ 165 | ACQUIA_CLI_VERSION=2.49.0 \ 166 | # Pin Terminus 3.6.2 for PHP 8.1 167 | TERMINUS_VERSION=3.6.2 \ 168 | JQ_VERSION=1.8.1 \ 169 | YQ_VERSION=4.48.1 170 | RUN set -xe; \ 171 | # Composer 1.x 172 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar" -o /usr/local/bin/composer1; \ 173 | # Composer 2.x 174 | curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER2_VERSION}/composer.phar" -o /usr/local/bin/composer2; \ 175 | # Drush 8 (global fallback) 176 | curl -fsSL "https://github.com/drush-ops/drush/releases/download/${DRUSH_VERSION}/drush.phar" -o /usr/local/bin/drush8; \ 177 | # Drupal Console Launcher 178 | curl -fsSL "https://github.com/hechoendrupal/drupal-console-launcher/releases/download/${DRUPAL_CONSOLE_LAUNCHER_VERSION}/drupal.phar" -o /usr/local/bin/drupal; \ 179 | # Wordpress CLI 180 | curl -fsSL "https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar" -o /usr/local/bin/wp; \ 181 | # Platform.sh CLI 182 | curl -fsSL "https://github.com/platformsh/cli/releases/download/${PLATFORMSH_CLI_VERSION}/platform_${PLATFORMSH_CLI_VERSION}_linux_${TARGETARCH}.tar.gz" -o /tmp/platform.tar.gz; \ 183 | tar -xzf /tmp/platform.tar.gz -C /tmp && mv /tmp/platform /usr/local/bin/platform; rm -rf /tmp/*; \ 184 | # Acquia CLI 185 | curl -fsSL "https://github.com/acquia/cli/releases/download/${ACQUIA_CLI_VERSION}/acli.phar" -o /usr/local/bin/acli; \ 186 | # Pantheon Terminus 187 | curl -fsSL "https://github.com/pantheon-systems/terminus/releases/download/${TERMINUS_VERSION}/terminus.phar" -o /usr/local/bin/terminus; \ 188 | # jq 189 | curl -fsSL "https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}/jq-linux-${TARGETARCH}" -o /usr/local/bin/jq; \ 190 | # yq 191 | curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq; \ 192 | # Set Default Composer Version 193 | ln -s /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer; \ 194 | # Make all downloaded binaries executable in one shot 195 | (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drupal wp platform acli terminus jq yq); 196 | 197 | # Install Python 3 + pip from Debian repos 198 | RUN set -xe; \ 199 | apt-get update >/dev/null; \ 200 | apt-get -y --no-install-recommends install >/dev/null \ 201 | python3 \ 202 | python3-pip \ 203 | ;\ 204 | # Cleanup 205 | apt-get clean; rm -rf /var/lib/apt/lists/* 206 | 207 | # Install Ruby from Debian repos 208 | RUN set -xe; \ 209 | apt-get update >/dev/null; \ 210 | apt-get -y --no-install-recommends install >/dev/null \ 211 | ruby-full \ 212 | ;\ 213 | # Cleanup 214 | apt-get clean; rm -rf /var/lib/apt/lists/* 215 | 216 | # Install a newer SQLite version from Debian Trixie (testing) repo 217 | # Debian Bookworm (main) ships with sqlite v3.40. Drupal 11 requires SQLite v3.45+. 218 | # @see https://www.drupal.org/project/drupal/issues/3346338 219 | RUN set -xe; \ 220 | echo "deb https://deb.debian.org/debian testing main" | tee /etc/apt/sources.list.d/testing.list; \ 221 | apt-get update >/dev/null; \ 222 | apt-get install -y -t testing sqlite3;\ 223 | # Cleanup 224 | apt-get clean; rm -rf /var/lib/apt/lists/*; rm -f /etc/apt/sources.list.d/testing.list 225 | 226 | # All further RUN commands will run as the "docker" user 227 | USER docker 228 | SHELL ["/bin/bash", "-c"] 229 | 230 | # Don't use -x here, as the output may be excessive 231 | RUN set -e; \ 232 | \ 233 | # Composer based dependencies 234 | # Add composer bin project level and global directories to PATH 235 | # Project level comes first and thus takes precedence over the global one 236 | echo -e "\n"'export PATH="$PATH:${PROJECT_ROOT:-/var/www}/vendor/bin"' >> $HOME/.profile; \ 237 | echo -e "\n"'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> $HOME/.profile; \ 238 | # Reload updated PATH from profile to make composer/etc. visible below 239 | . $HOME/.profile; \ 240 | # Drupal Coder & WP Coding Standards w/ a matching version of PHP_CodeSniffer 241 | # Set allow-plugins. See https://getcomposer.org/allow-plugins 242 | composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true; \ 243 | composer global require drupal/coder wp-coding-standards/wpcs phpcompatibility/phpcompatibility-wp; \ 244 | # Don't fix the indentation or installed_paths will not be set correctly 245 | phpcs --config-set installed_paths \ 246 | $HOME/.composer/vendor/drupal/coder/coder_sniffer/,\ 247 | $HOME/.composer/vendor/wp-coding-standards/wpcs/,\ 248 | $HOME/.composer/vendor/phpcompatibility/php-compatibility/PHPCompatibility/,\ 249 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp/PHPCompatibilityWP,\ 250 | $HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie/PHPCompatibilityParagonieRandomCompat; \ 251 | # Cleanup 252 | composer clear-cache 253 | 254 | # Node.js (installed as user) 255 | ENV \ 256 | NVM_VERSION=0.40.3 \ 257 | NODE_VERSION=22.20.0 \ 258 | # Yarn (Classic v1) 259 | # https://github.com/yarnpkg/yarn/releases 260 | YARN_VERSION=1.22.22 261 | # Don't use -x here, as the output may be excessive 262 | RUN set -e; \ 263 | # NVM and a defaut Node.js version 264 | export PROFILE="$HOME/.profile"; \ 265 | curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash >/dev/null; \ 266 | # Reload profile to load nvm (needed by Yarn installation below) 267 | . $HOME/.profile; \ 268 | # Yarn (Classic v1) 269 | # Installing via npm to allow fore override with never versions via corepack 270 | npm install -g yarn@${YARN_VERSION}; \ 271 | # Enable corepack (allows installing project level yarn v2+ via yarn) 272 | corepack enable 273 | 274 | ## Ruby bundler 275 | ## Don't use -x here, as the output may be excessive 276 | RUN set -e; \ 277 | # Export ruby gem bin path 278 | echo 'export PATH=$PATH:$(ruby -r rubygems -e "puts Gem.user_dir")/bin' >> $HOME/.profile; \ 279 | . $HOME/.profile; \ 280 | gem install --user-install bundler; \ 281 | # Have bundler install gems in the current directory (./.bundle) by default 282 | echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile 283 | 284 | # Notify web container about started fin exec 285 | RUN echo '(/opt/ping-web.sh &)' >> $HOME/.profile 286 | 287 | USER root 288 | SHELL ["/bin/sh", "-c"] 289 | 290 | # Copy configs and scripts 291 | COPY --chown=docker:docker config/.terminus /home/docker/.terminus 292 | COPY --chown=docker:docker config/.ssh /home/docker/.ssh 293 | COPY config/supervisor /etc/supervisor/conf.d 294 | COPY startup.sh /opt/startup.sh 295 | COPY healthcheck.sh /opt/healthcheck.sh 296 | COPY ping-web.sh /opt/ping-web.sh 297 | # PHP default settings, global overrides and fpm overrides 298 | RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" 299 | COPY config/php/zz-php.ini /usr/local/etc/php/conf.d/zz-php.ini 300 | COPY config/php/xdebug.ini /opt/docker-php-ext-xdebug.ini 301 | COPY config/php/xhprof.ini /opt/docker-php-ext-xhprof.ini 302 | COPY config/php/opcache.ini /opt/docker-php-ext-opcache.ini 303 | COPY config/php/zz-php-fpm.conf /usr/local/etc/php-fpm.d/zz-php-fpm.conf 304 | 305 | ENV \ 306 | # ssh-agent proxy socket (requires docksal/ssh-agent) 307 | SSH_AUTH_SOCK=/.ssh-agent/proxy-socket \ 308 | # Set TERM so text editors/etc. can be used 309 | TERM=xterm \ 310 | # Allow PROJECT_ROOT to be universally used in fin custom commands (inside and outside cli) 311 | PROJECT_ROOT=/var/www \ 312 | # Default values for HOST_UID and HOST_GUI to match the default Ubuntu user. These are used in startup.sh 313 | HOST_UID=1000 \ 314 | HOST_GID=1000 \ 315 | # Delay in seconds between pings web from cli, while running fin exec. 0 - disabled 316 | WEB_KEEPALIVE=0 \ 317 | # xdebug disabled by default 318 | XDEBUG_ENABLED=0 \ 319 | XHPROF_ENABLED=0 \ 320 | XHPROF_OUTPUT_DIR=/tmp/xhprof 321 | 322 | # TODO: [v3] remove and set these via docker-compose 323 | EXPOSE 9000 324 | EXPOSE 22 325 | EXPOSE 3000 326 | 327 | WORKDIR /var/www 328 | 329 | # Starter script 330 | ENTRYPOINT ["/opt/startup.sh"] 331 | 332 | # By default, launch supervisord to keep the container running. 333 | CMD ["supervisord"] 334 | 335 | # Health check script 336 | HEALTHCHECK --interval=5s --timeout=1s --retries=12 CMD ["/opt/healthcheck.sh"] 337 | 338 | 339 | # Visual Studio Code Server flavor 340 | FROM cli AS code-server 341 | 342 | # Run as docker, so we don't have to fix permissions 343 | USER docker 344 | 345 | ARG HOME=/home/docker 346 | 347 | ENV \ 348 | CODE_SERVER_VERSION=4.104.3 \ 349 | VSCODE_GITLENS_VERSION=17.6.1 \ 350 | VSCODE_XDEBUG_VERSION=1.37.0 \ 351 | VSCODE_HOME="${HOME}/code-server" 352 | 353 | # Install code-server 354 | RUN set -xe; \ 355 | curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${TARGETARCH}.deb" -o /tmp/code-server_${TARGETARCH}.deb; \ 356 | sudo dpkg -i /tmp/code-server_${TARGETARCH}.deb; \ 357 | rm -rf /tmp/*.* 358 | 359 | # Settings 360 | COPY --chown=docker:docker config/code-server ${VSCODE_HOME} 361 | 362 | # Install extensions 363 | # Note: Have to use --user-data-dir with --install-extension instead of --config 364 | RUN set -xe; \ 365 | code-server --user-data-dir=${VSCODE_HOME} --install-extension eamodio.gitlens@${VSCODE_GITLENS_VERSION}; \ 366 | code-server --user-data-dir=${VSCODE_HOME} --install-extension xdebug.php-debug@${VSCODE_XDEBUG_VERSION} 367 | 368 | # Switch back to root (IMPORTANT!) 369 | USER root 370 | -------------------------------------------------------------------------------- /tests/test.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # Debugging 4 | teardown() { 5 | echo 6 | # TODO: figure out how to deal with this (output from previous run commands showing up along with the error message) 7 | echo "Note: ignore the lines between \"...failed\" above and here" 8 | echo 9 | echo "Status: ${status}" 10 | echo "Output:" 11 | echo "================================================================" 12 | echo "${output}" 13 | echo "================================================================" 14 | } 15 | 16 | # Checks container health status (if available) 17 | # Relies on healchecks introduced in docksal/cli v1.3.0+, uses `sleep` as a fallback 18 | # @param $1 container id/name 19 | _healthcheck () 20 | { 21 | local health_status 22 | health_status=$(docker inspect --format='{{json .State.Health.Status}}' "$1" 2>/dev/null) 23 | 24 | # Wait for 5s then exit with 0 if a container does not have a health status property 25 | # Necessary for backward compatibility with images that do not support health checks 26 | if [[ $? != 0 ]]; then 27 | echo "Waiting 10s for container to start..." 28 | sleep 10 29 | return 0 30 | fi 31 | 32 | # If it does, check the status 33 | echo ${health_status} | grep '"healthy"' >/dev/null 2>&1 34 | } 35 | 36 | # Waits for containers to become healthy 37 | _healthcheck_wait () 38 | { 39 | # Wait for cli to become ready by watching its health status 40 | local container_name="${NAME}" 41 | local delay=5 42 | local timeout=30 43 | local elapsed=0 44 | 45 | until _healthcheck "$container_name"; do 46 | echo "Waiting for $container_name to become ready..." 47 | sleep ${delay}; 48 | 49 | # Give the container 30s to become ready 50 | elapsed=$((elapsed + delay)) 51 | if ((elapsed > timeout)); then 52 | echo "$container_name healthcheck failed" 53 | exit 1 54 | fi 55 | done 56 | 57 | return 0 58 | } 59 | 60 | # To work on a specific test: 61 | # run `export SKIP=1` locally, then comment skip in the test you want to debug 62 | 63 | @test "Essential binaries" { 64 | [[ $SKIP == 1 ]] && skip 65 | 66 | ### Setup ### 67 | make start-bare 68 | 69 | run _healthcheck_wait 70 | unset output 71 | 72 | ### Tests ### 73 | 74 | # List of binaries to check 75 | binaries=$(./tests/essential-binaries.sh) 76 | 77 | # Check all binaries in a single shot 78 | run make exec -e CMD="type $(echo ${binaries} | xargs)" 79 | [ "$status" -eq 0 ] 80 | unset output 81 | 82 | ### Cleanup ### 83 | make clean 84 | } 85 | 86 | @test "Bare service" { 87 | [[ $SKIP == 1 ]] && skip 88 | 89 | ### Setup ### 90 | make start-bare 91 | 92 | run _healthcheck_wait 93 | unset output 94 | 95 | ### Tests ### 96 | 97 | # Check PHP FPM and settings 98 | # "sed -E 's/[[:space:]]{2,}/ => /g'" - makes the HTML phpinfo output easier to parse. It will transforms 99 | # "memory_limit 256M 256M" 100 | # into "memory_limit => 256M => 256M", which is much easier to parse 101 | phpInfo=$(docker exec -u docker "$NAME" bash -c "/var/www/docroot/php-fpm.sh phpinfo.php | sed -E 's/[[:space:]]{2,}/ => /g'") 102 | 103 | output=$(echo "$phpInfo" | grep "memory_limit") 104 | echo "$output" | grep "256M => 256M" 105 | unset output 106 | 107 | output=$(echo "$phpInfo" | grep "sendmail_path") 108 | echo "$output" | grep '/usr/bin/msmtp -t --host=mail --port=1025 --from=docker@cli' 109 | unset output 110 | 111 | run docker exec -u docker "$NAME" /var/www/docroot/php-fpm.sh nonsense.php 112 | echo "$output" | grep "Status: 404 Not Found" 113 | unset output 114 | 115 | # Check PHP CLI and settings 116 | phpInfo=$(docker exec -u docker "$NAME" php -i) 117 | 118 | output=$(echo "$phpInfo" | grep "PHP Version") 119 | echo "$output" | grep "${VERSION}" 120 | unset output 121 | 122 | # Confirm WebP support enabled for GD 123 | output=$(echo "$phpInfo" | grep "WebP Support") 124 | echo "$output" | grep "enabled" 125 | unset output 126 | 127 | output=$(echo "$phpInfo" | grep "memory_limit") 128 | # grep expression cannot start with "-", so prepending the expression with "memory_limit" here. 129 | # Another option is to do "grep -- '-...'". 130 | echo "$output" | grep "memory_limit => -1 => -1" 131 | unset output 132 | 133 | output=$(echo "$phpInfo" | grep "sendmail_path") 134 | echo "$output" | grep '/usr/bin/msmtp -t --host=mail --port=1025 --from=docker@cli' 135 | unset output 136 | 137 | # Check PHP modules 138 | output=$(docker exec -u docker "$NAME" php -m | diff <(./tests/php-modules.sh) -) 139 | [[ ${output} == "" ]] 140 | unset output 141 | 142 | ### Cleanup ### 143 | make clean 144 | } 145 | 146 | # Examples of using Makefile commands 147 | # make start, make exec, make clean 148 | @test "Configuration overrides" { 149 | [[ $SKIP == 1 ]] && skip 150 | 151 | ### Setup ### 152 | make start -e ENV='-e XDEBUG_ENABLED=1 -e XHPROF_ENABLED=1' 153 | 154 | run _healthcheck_wait 155 | unset output 156 | 157 | ### Tests ### 158 | 159 | # Check PHP FPM settings overrides 160 | run make exec -e CMD='/var/www/docroot/php-fpm.sh phpinfo.php' 161 | echo "$output" | grep "memory_limit" | grep "512M" 162 | unset output 163 | 164 | # Check xdebug was enabled 165 | run make exec -e CMD='php -m' 166 | echo "$output" | grep -e "^xdebug$" 167 | unset output 168 | 169 | # Check xdebug was enabled 170 | run make exec -e CMD='php -m' 171 | echo "$output" | grep -e "^xhprof$" 172 | unset output 173 | 174 | # Check PHP CLI overrides 175 | run make exec -e CMD='php -i' 176 | echo "$output" | grep "memory_limit => 128M => 128M" 177 | unset output 178 | 179 | ### Cleanup ### 180 | make clean 181 | } 182 | 183 | @test "Check PHP tools and versions" { 184 | [[ $SKIP == 1 ]] && skip 185 | 186 | ### Setup ### 187 | make start 188 | 189 | run _healthcheck_wait 190 | unset output 191 | 192 | ### Tests ### 193 | 194 | # Check Composer v1 version (legacy) 195 | run docker exec -u docker "$NAME" bash -lc 'set -x; composer1 --version | grep "${COMPOSER_VERSION}"' 196 | [ "$status" -eq 0 ] 197 | unset output 198 | 199 | # Check Composer v2 version (default) 200 | run docker exec -u docker "$NAME" bash -lc 'set -x; composer --version | grep "${COMPOSER2_VERSION}"' 201 | [ "$status" -eq 0 ] 202 | unset output 203 | 204 | # Check Drush 8 version (legacy) 205 | run docker exec -u docker "$NAME" bash -lc 'set -x; drush8 --version | grep "${DRUSH_VERSION}"' 206 | [ "$status" -eq 0 ] 207 | unset output 208 | 209 | # Check Drupal Console version 210 | run docker exec -u docker "$NAME" bash -lc 'set -x; drupal --version | grep "${DRUPAL_CONSOLE_LAUNCHER_VERSION}"' 211 | [ "$status" -eq 0 ] 212 | unset output 213 | 214 | # Check Wordpress CLI version 215 | run docker exec -u docker "$NAME" bash -lc 'set -x; wp --version | grep "${WPCLI_VERSION}"' 216 | [ "$status" -eq 0 ] 217 | unset output 218 | 219 | # Check Terminus version 220 | run docker exec -u docker "$NAME" bash -lc 'set -x; terminus --version | grep "${TERMINUS_VERSION}"' 221 | [ "$status" -eq 0 ] 222 | unset output 223 | 224 | # Check Platform CLI version 225 | run docker exec -u docker "$NAME" bash -lc 'set -x; platform --version | grep "${PLATFORMSH_CLI_VERSION}"' 226 | [ "$status" -eq 0 ] 227 | unset output 228 | 229 | # Check Acquia CLI version 230 | run docker exec -u docker "$NAME" bash -lc 'set -x; acli --version | grep "${ACQUIA_CLI_VERSION}"' 231 | [ "$status" -eq 0 ] 232 | unset output 233 | 234 | ### Cleanup ### 235 | make clean 236 | } 237 | 238 | @test "Check misc tools and versions" { 239 | [[ $SKIP == 1 ]] && skip 240 | 241 | ### Setup ### 242 | make start 243 | 244 | run _healthcheck_wait 245 | unset output 246 | 247 | ### Tests ### 248 | 249 | # nvm 250 | run docker exec -u docker "$NAME" bash -lc 'nvm --version | grep "${NVM_VERSION}"' 251 | [ "$status" -eq 0 ] 252 | unset output 253 | 254 | # nodejs 255 | run docker exec -u docker "$NAME" bash -lc 'node --version | grep "${NODE_VERSION}"' 256 | [ "$status" -eq 0 ] 257 | unset output 258 | 259 | # yarn 260 | run docker exec -u docker "$NAME" bash -lc 'yarn --version | grep "${YARN_VERSION}"' 261 | [ "$status" -eq 0 ] 262 | unset output 263 | 264 | # Stock Ruby version in Debian 12 is 3.1.x 265 | run docker exec -u docker "$NAME" bash -lc 'ruby --version | grep "ruby 3.1"' 266 | [ "$status" -eq 0 ] 267 | unset output 268 | 269 | # Stock Python version in Debian 12 is 3.11.x 270 | run docker exec -u docker "$NAME" bash -lc 'python3 --version 2>&1 | grep "Python 3.11"' 271 | [ "$status" -eq 0 ] 272 | unset output 273 | 274 | # Check msmtp 275 | run docker exec -u docker "$NAME" which msmtp 276 | echo "$output" | grep "/usr/bin/msmtp" 277 | unset output 278 | 279 | ### Cleanup ### 280 | make clean 281 | } 282 | 283 | @test "Check config templates" { 284 | [[ $SKIP == 1 ]] && skip 285 | 286 | # Source and allexport (set -a) variables from docksal.env 287 | set -a; source $(pwd)/../tests/.docksal/docksal.env; set +a 288 | 289 | # Config variables were loaded 290 | [[ "${SECRET_SSH_PRIVATE_KEY}" != "" ]] 291 | 292 | ### Setup ### 293 | make start -e ENV="-e SECRET_SSH_PRIVATE_KEY" 294 | 295 | run _healthcheck_wait 296 | unset output 297 | 298 | ### Tests ### 299 | 300 | # Check private SSH key 301 | run make exec -e CMD='echo ${SECRET_SSH_PRIVATE_KEY}' 302 | [[ "${output}" != "" ]] 303 | unset output 304 | # TODO: figure out how to properly use 'make exec' here (escape quotes) 305 | run docker exec -u docker "${NAME}" bash -lc 'echo "${SECRET_SSH_PRIVATE_KEY}" | base64 -d | diff ${HOME}/.ssh/id_rsa -' 306 | [ "$status" -eq 0 ] 307 | unset output 308 | 309 | ### Cleanup ### 310 | make clean 311 | } 312 | 313 | # Disabled for now as this test keeps failing sporadically. 314 | @test "Check custom startup script" { 315 | skip # Disabled 316 | 317 | [[ $SKIP == 1 ]] && skip 318 | 319 | make start 320 | 321 | run _healthcheck_wait 322 | unset output 323 | 324 | # docksal/cli container healthcheck completes right before a customer startup scripts is executed 325 | # Give the custom startup script a little time to complete, otherwise this test will be randomly failing. 326 | sleep 2 327 | 328 | run docker exec -u docker "${NAME}" cat /tmp/test-startup.txt 329 | [ "$status" -eq 0 ] 330 | [[ "${output}" =~ "I ran properly" ]] 331 | 332 | ### Cleanup ### 333 | make clean 334 | } 335 | 336 | @test "Check Platform.sh integration" { 337 | [[ $SKIP == 1 ]] && skip 338 | 339 | # Confirm secret is not empty 340 | [[ "${SECRET_PLATFORMSH_CLI_TOKEN}" != "" ]] 341 | 342 | ### Setup ### 343 | make start -e ENV='-e SECRET_PLATFORMSH_CLI_TOKEN' 344 | 345 | run _healthcheck_wait 346 | unset output 347 | 348 | ### Tests ### 349 | 350 | # Confirm token was passed to the container 351 | run docker exec -u docker "${NAME}" bash -lc 'echo SECRET_PLATFORMSH_CLI_TOKEN: ${SECRET_PLATFORMSH_CLI_TOKEN}' 352 | [[ "${output}" == "SECRET_PLATFORMSH_CLI_TOKEN: ${SECRET_PLATFORMSH_CLI_TOKEN}" ]] 353 | unset output 354 | 355 | # Confirm the SECRET_ prefix was stripped 356 | run docker exec -u docker "${NAME}" bash -lc 'echo PLATFORMSH_CLI_TOKEN: ${SECRET_PLATFORMSH_CLI_TOKEN}' 357 | [[ "${output}" == "PLATFORMSH_CLI_TOKEN: ${SECRET_PLATFORMSH_CLI_TOKEN}" ]] 358 | unset output 359 | 360 | # Confirm authentication works 361 | run docker exec -u docker "${NAME}" bash -lc 'platform auth:info --no-interaction' 362 | [ "$status" -eq 0 ] 363 | [[ ! "${output}" =~ "Invalid API token" ]] 364 | [[ "${output}" =~ "developer@docksal.io" ]] 365 | unset output 366 | 367 | ### Cleanup ### 368 | make clean 369 | } 370 | 371 | @test "Check Pantheon integration" { 372 | [[ $SKIP == 1 ]] && skip 373 | 374 | # Disabled for the time being 375 | # TODO: Figure out why these tests fail sporadically, then re-enable 376 | skip 377 | 378 | # Terminus v3 is not yet fully compatible with PHP 8.1 379 | # TODO: Re-enable tests for Terminus v3 on PHP 8.1 once stable. 380 | # See: https://github.com/pantheon-systems/terminus/issues/2256 381 | [[ "${VERSION}" == "8.1" ]] && skip 382 | 383 | # Confirm secret is not empty 384 | [[ "${SECRET_TERMINUS_TOKEN}" != "" ]] 385 | 386 | ### Setup ### 387 | make start -e ENV='-e SECRET_TERMINUS_TOKEN' 388 | 389 | run _healthcheck_wait 390 | unset output 391 | 392 | ### Tests ### 393 | 394 | # Confirm token was passed to the container 395 | run docker exec -u docker "${NAME}" bash -lc 'echo SECRET_TERMINUS_TOKEN: ${SECRET_TERMINUS_TOKEN}' 396 | [[ "${output}" == "SECRET_TERMINUS_TOKEN: ${SECRET_TERMINUS_TOKEN}" ]] 397 | unset output 398 | 399 | # Confirm the SECRET_ prefix was stripped 400 | run docker exec -u docker "${NAME}" bash -lc 'echo TERMINUS_TOKEN: ${TERMINUS_TOKEN}' 401 | [[ "${output}" == "TERMINUS_TOKEN: ${SECRET_TERMINUS_TOKEN}" ]] 402 | unset output 403 | 404 | # Confirm we are logged in with the expected user 405 | run docker exec -u docker "${NAME}" bash -lc 'terminus site:list' 406 | [ "$status" -eq 0 ] 407 | [[ ! "${output}" =~ "You are not logged in." ]] 408 | unset output 409 | 410 | # Confirm we are logged in with the expected user 411 | # terminus auth:whoami is finicky/buggy and needs another command to run to create a session first. 412 | # See https://github.com/docksal/service-cli/issues/258 413 | run docker exec -u docker "${NAME}" bash -lc 'terminus auth:whoami' 414 | [ "$status" -eq 0 ] 415 | [[ ! "${output}" =~ "You are not logged in." ]] 416 | [[ "${output}" =~ "developer@docksal.io" ]] 417 | unset output 418 | 419 | ### Cleanup ### 420 | make clean 421 | } 422 | 423 | @test "Check cron" { 424 | [[ $SKIP == 1 ]] && skip 425 | 426 | ### Setup ### 427 | make start 428 | 429 | run _healthcheck_wait 430 | unset output 431 | 432 | ### Tests ### 433 | 434 | # Wait for cron to run. 435 | # This test keeps failing randomly... 436 | # Worst case, the wait would need to be 120s (double the 60s minimal interval possible with cron). 437 | sleep 90 438 | # Confirm cron has run and file contents has changed 439 | run docker exec -u docker "$NAME" bash -lc 'tail -1 /tmp/date.txt' 440 | [[ "${output}" =~ "The current date is " ]] 441 | unset output 442 | 443 | ### Cleanup ### 444 | make clean 445 | } 446 | 447 | @test "Git settings" { 448 | [[ $SKIP == 1 ]] && skip 449 | 450 | ### Setup ### 451 | make start -e ENV='-e GIT_USER_EMAIL=git@example.com -e GIT_USER_NAME="Docksal CLI"' 452 | 453 | run _healthcheck_wait 454 | unset output 455 | 456 | ### Tests ### 457 | 458 | # Check git settings were applied 459 | run docker exec -u docker "$NAME" bash -lc 'git config --get --global user.email' 460 | [[ "${output}" == "git@example.com" ]] 461 | unset output 462 | 463 | run docker exec -u docker "$NAME" bash -lc 'git config --get --global user.name' 464 | [[ "${output}" == "Docksal CLI" ]] 465 | unset output 466 | 467 | ### Cleanup ### 468 | make clean 469 | } 470 | 471 | @test "PHPCS Coding standards check" { 472 | [[ $SKIP == 1 ]] && skip 473 | 474 | ### Setup ### 475 | make start 476 | 477 | run _healthcheck_wait 478 | unset output 479 | 480 | ### Tests ### 481 | 482 | # Check PHPCS libraries loaded 483 | # Normalize the output from phpcs -i so it's easier to do matches 484 | run docker exec -u docker "$NAME" bash -lc "phpcs -i | sed 's/,//g'" 485 | # The trailing space below allows comparing all values the same way: " " (needed for the last value to match). 486 | output="${output} " 487 | [[ "${output}" =~ " Drupal " ]] 488 | [[ "${output}" =~ " DrupalPractice " ]] 489 | [[ "${output}" =~ " WordPress " ]] # Includes WordPress-Core, WordPress-Docs and WordPress-Extra 490 | [[ "${output}" =~ " PHPCompatibility " ]] 491 | [[ "${output}" =~ " PHPCompatibilityWP " ]] 492 | [[ "${output}" =~ " PHPCompatibilityParagonieRandomCompat " ]] 493 | unset output 494 | 495 | ### Cleanup ### 496 | make clean 497 | } 498 | 499 | @test "VS Code Server" { 500 | [[ $SKIP == 1 ]] && skip 501 | 502 | ### Setup ### 503 | make start -e ENV='-e IDE_ENABLED=1' 504 | 505 | run _healthcheck_wait 506 | unset output 507 | 508 | ### Tests ### 509 | 510 | run make logs 511 | echo "$output" | grep 'HTTP server listening on http://0\.0\.0\.0:8080' 512 | unset output 513 | 514 | ### Cleanup ### 515 | make clean 516 | } 517 | --------------------------------------------------------------------------------