Docker Image Compability Matrix: https://github.com/dotsandlines-tech/dal-craft-cli/wiki/Compatibility-Matrix
This image marries 2-3 containers into a locked down Docker-based management cli for craftcms services - accessable via SSH:
- atmoz/sftp
- craftcms/cli
- either witten/borgmatic (the
-borgmaticimage tag variant) - or it simply bakes
kubectl(the-a3cloudimage tag variant)
The idea is to provide a minimal separate management container for craftcms services that allows:
- locked down access via ssh via a set of predefined users,
- direct usage of the
./craftmanagement cli and - backup/snapshoting capabilities either via
borgmaticorkubectl(CSI volume snapshots).
This container may also be interesting for CI deployment steps (syncing craftcms DB / files with CI-built artifacts).
All ENV configuration requirements of atmoz/sftp and craftcms/cli apply as documented here. Please note that we do not lock down to sftp-only access, ssh-access is granted to all configured users as configured by sftp.
Regarding witten/borgmatic, please mount its full configuration at /etc/borgmatic.d/config.yaml.
After successfully setting this it, it should be possible to get a ssh shell into this container on port 22:
ssh <username>@<container-host> -p <ssh-port>
# $MOTD_MESSAGE: Welcome to <container-host>!
# owner: www-data (chown 82:82 <file>)
# app disk: /app
# craft home: /app/current
# backup disk: /mnt/snapshots
# Type "snapshots -h" for help regarding adhoc backups (held for **30 days**).
container:/app$ whoami
# www-data
container:/app$ id
# uid=82(www-data) gid=82(www-data) groups=82(www-data)
# -borgmatic image variant only:
container:/app$ ./snapshots -h
# dal-craft-cli snapshots utility
# Usage:
# snapshots -h Display this help message.
# snapshots print-config Print current config vars.
# snapshots init Initialize '/mnt/snapshots/{.borg, .repo}'.
# snapshots list List available snapshots.
# snapshots info Info about snapshot size.
# snapshots create Create a new snapshot from '/app/current/**' and prune old snapshots.
# snapshots export <snapshot> Export <snapshot> to '/mnt/snapshots/<snapshot>.tar.gz'.
# snapshots restore <snapshot> Restore <snapshot> to '/app/current/**' (hotswap).
# -a3cloud image variant only:
container:/app$ snapshots -h
# dal-craft-cli snapshots utility (a3cloud kubectl csi volume snapshot compatible)
# Usage:
# snapshots -h Display this help message.
# snapshots list|info List available k8s volume snapshots.
# snapshots create Create a new k8s volume snapshot.
# snapshots print-config Prints a3cloud k8s ConfigMap/backup-env
# snapshots init NOOP exit 0
# snapshots export <snapshot> NOT IMPLEMENTED, exit 1
# snapshots restore <snapshot> NOT IMPLEMENTED, exit 1
container:/app$ snapshots create
# A new snapshot is created either via borgmatic or kubectl, see above.
# Feel free to adapt the bash-script under /usr/bin/snapshots to your needs (mount an executable file there to overwrite)
# For samples see files/snapshots-a3cloud or files/snapshots-borgmatic in this repo.
container:/app$ cd current/
container:/app/current$ ./craft off
# The system is now offline.
container:/app/current$ ./craft on
# The system is already online.- We mount the craftcms working directory at
/app/current. -a3cloudspecific: The container simply reused the mounted service account.-borgmaticspecific: A separate backup volume is mounted at/mnt/snapshots, including a temporary/dumpsdirectory (emptydir). The borgmatic config gets mounted at/etc/borgmatic.d/config.yaml.- Regarding
sshaccess:- We set the
ENV-varSFTP_USERS(e.g.<username>:<pass>:82:82:app,snapshots) to a k8s secret to setup our sftp users and keys and additionally mount a common ssh host key at/etc/ssh/ssh_host_ed25519_keyand/etc/ssh/ssh_host_rsa_key. - Furthermore we mount the respective user-specific ssh public keys at
/home/<username>/.ssh/keys/user-ssh-key.pub. - All ssh users get uid/gid
82:82(www-user, as used by the official craftcms images) - We also mount the craftcms working directory at
/home/<username>/app(and-borgmaticspecific: backups at/home/<username>/snapshotsto make them available while usingsftp).
- We set the
- We set a the
ENV-varMOTD_MESSAGEto a nice message. This is displayed to each ssh user connecting via ssh.
We typically mount something like that following at /etc/borgmatic.d/config.yaml:
# https://torsion.org/borgmatic/docs/reference/configuration/
location:
source_directories:
- /app/current
repositories:
- /mnt/snapshots/.repo
# Skip craft temp folder
# exclude_patterns:
# - /app/current/temp
# Path for additional source files used for **temporary** internal state like borgmatic database dumps.
borgmatic_source_directory: /dumps
storage:
compression: lz4
archive_name_format: 'backup-{now}'
borg_base_directory: /mnt/snapshots/.borg
# borg_config_directory: # defaults to $borg_base_directory/.config/borg
# borg_cache_directory: # defaults to $borg_base_directory/.cache/borg
# borg_security_directory: # defaults to $borg_base_directory/.config/borg/security
# borg_keys_directory: # defaults to $borg_base_directory/.config/borg/keys
lock_wait: 30
retention:
keep_within: 30d
prefix: 'backup-'
consistency:
checks:
- repository
- archives
check_last: 3
prefix: 'backup-'
hooks:
before_backup:
- echo "Starting a backup."
before_prune:
- echo "Starting pruning."
before_check:
- echo "Starting checks."
before_extract:
- echo "Starting extracting."
after_backup:
- echo "Finished a backup."
after_prune:
- echo "Finished pruning."
after_check:
- echo "Finished checks."
after_extract:
- echo "Finished extracting."
on_error:
- echo "Error during prune/create/check."
mysql_databases:
- name: all
hostname: <db-host>
port: <db-port>
username: <db-username>
password: <db-password>
# IMPORTANT! do not use --compact with mariadb! https://github.com/arionum/node/issues/13
options: --default-character-set=utf8 --add-drop-database --add-locks --set-charset --create-options --add-drop-table --lock-tablesTo enable TCP forwarding via SSH through this container you need to set the ENV_VAR SSHD_ALLOW_TCP_FORWARDING: "yes". This is for example needed to directly access a mySQL/MariaDB database through a SSH tunnel via this container.
See templates/sshd_config, the following envs will be set and a substituted template written to /etc/ssh/sshd_config.
Default values:
SSHD_HOST_KEY_ED25519="/etc/ssh/ssh_host_ed25519_key"
SSHD_HOST_KEY_RSA="/etc/ssh/ssh_host_rsa_key"
SSHD_USE_DNS="no"
SSHD_ALLOW_TCP_FORWARDING="no"
SSHD_X11_FORWARDING="no"
SSHD_PERMIT_ROOT_LOGIN="no"We inject a snapshots utility that easens the burden to create snapshots/backups for our default stack.
# You may configure the following env vars - here are its default values (a new UUID is generated each time):
./snapshots print-config
Using:
SNAPSHOTS_DIR: "/mnt/snapshots"
SRC_DIR: "/app/current"
TMP_RESTORE_UUID: "cf44881a-4e21-429c-8931-dc653ef96053"
TMP_RESTORED_BASE_DIR: "/tmp/.cf44881a-4e21-429c-8931-dc653ef96053"
TMP_RESTORED_SRC_DIR: "/tmp/.cf44881a-4e21-429c-8931-dc653ef96053/app/current"
HOTSWAP_BASE_DIR: "/app"
HOTSWAP_RESTORED_DIR: "/app/.cf44881a-4e21-429c-8931-dc653ef96053"
HOTSWAP_OLD_DIR: "/app/.cf44881a-4e21-429c-8931-dc653ef96053_old"As users that connect via ssh, don't automatically get the same env as the root user running this container, we explicitly define env vars that are allowed to be shared with each user, see files/create-sftp-user.
Currently expose the following ENV-vars from the root user (that runs the ssh-server within this container) to each created user:
export PATH="${PATH}"
export PHP_VERSION="${PHP_VERSION}"
export PHP_MD5="${PHP_VERSION}"
export PHP_INI_DIR="${PHP_INI_DIR}"
export PHP_LDFLAGS="${PHP_LDFLAGS}"
export PHP_SHA256="${PHP_SHA256}"
export PHPIZE_DEPS="${PHPIZE_DEPS}"
export PHP_URL="${PHP_URL}"
export COMPOSER_VERSION="${COMPOSER_VERSION}"
export PHP_CFLAGS="${PHP_CFLAGS}"
export COMPOSER_HOME="${COMPOSER_HOME}"
export PHP_ASC_URL="${PHP_ASC_URL}"
export PHP_CPPFLAGS="${PHP_CPPFLAGS}"
export KUBERNETES_SERVICE_HOST="${KUBERNETES_SERVICE_HOST}"
export KUBERNETES_SERVICE_PORT="${KUBERNETES_SERVICE_PORT}"
export KUBERNETES_SERVICE_PORT_HTTPS="${KUBERNETES_SERVICE_PORT_HTTPS}"
export KUBERNETES_PORT="${KUBERNETES_PORT}"
export KUBERNETES_PORT_443_TCP="${KUBERNETES_PORT_443_TCP}"
export KUBERNETES_PORT_443_TCP_PROTO="${KUBERNETES_PORT_443_TCP_PROTO}"
export KUBERNETES_PORT_443_TCP_ADDR="${KUBERNETES_PORT_443_TCP_ADDR}"
export KUBERNETES_PORT_443_TCP_PORT="${KUBERNETES_PORT_443_TCP_PORT}"
# all provided BAK_* and BACKUP_JOB_* env vars- Replace the
Stage: cli-a3cloudbase image within theDockerfileto your new variant from craftcms/cli. - Replace the
IMAGE_NAMEwithinbuild.sh. - Push into private working branch and check GitHub Actions build pipeline for errors.
- Push into
mainbranch and check Github Actions build and publish pipeline for errors. - Push as new git tag (e.g.
v1.2.0-php8.2,git tag -a <TAG> -m "<msg>") and check Github Actions build and publish pipeline for errors. This will automatically publish 2 tags:v1.2.0-php8.2-a3cloudandv1.2.0-php8.2-borgmatic - Update the Compatibility Matrix
- Use the published docker image (e.g.
ghcr.io/dotsandlines-tech/dal-craft-cli:v1.2.0-php8.2-a3cloud)
You can run this locally.
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $HOME/Library/Caches:/root/.cache/ aquasec/trivy image --exit-code 1 --severity HIGH,CRITICAL --no-progress --ignore-unfixed ghcr.io/dotsandlines-tech/dal-craft-cli:v1.2.0-php8.2-a3cloud