SSH host keys, split out swarm-cronjob

This commit is contained in:
3wc 2021-11-10 22:01:57 +02:00
parent 721c393d2d
commit a990dc27c7
6 changed files with 75 additions and 48 deletions

View File

@ -9,8 +9,12 @@ RESTIC_HOST=minio.example.com
CRON_SCHEDULE='*/5 * * * *' CRON_SCHEDULE='*/5 * * * *'
# swarm-cronjob, instead of built-in cron
#COMPOSE_FILE="$COMPOSE_FILE:compose.swarm-cronjob.yml"
# SSH storage # SSH storage
#SECRET_SSH_KEY_VERSION=v1 #SECRET_SSH_KEY_VERSION=v1
#SSH_HOST_KEY="hostname ssh-rsa AAAAB3...
#COMPOSE_FILE="$COMPOSE_FILE:compose.ssh.yml" #COMPOSE_FILE="$COMPOSE_FILE:compose.ssh.yml"
# S3 storage # S3 storage

View File

@ -19,8 +19,8 @@ A first stab:
- [ ] SSH remote storage - [ ] SSH remote storage
- [ ] Add SSH key handling - [ ] Add SSH key handling
- [ ] SSH host key checking - [ ] SSH host key checking
- [ ] S3 remote storage - [x] S3 remote storage
- [ ] Re-add `crond` support - [x] Re-add `crond` support
Future: Future:
- [ ] Continuous linting with shellcheck - [ ] Continuous linting with shellcheck

View File

@ -16,7 +16,18 @@ restic_extra_options=
if [ -n "$ssh_key_file" ] && [ -f "$ssh_key_file" ]; then if [ -n "$ssh_key_file" ] && [ -f "$ssh_key_file" ]; then
restic_repo="sftp:$restic_host:/$server_name" restic_repo="sftp:$restic_host:/$server_name"
restic_extra_options="sftp.command=ssh -i $ssh_key_file $restic_host -s sftp"
# Only check server against provided SSH_HOST_KEY, if set
if [ -n "$SSH_HOST_KEY" ]; then
tmpfile=$(mktemp)
echo "$SSH_HOST_KEY" >> "$tmpfile"
ssh_options="-o 'UserKnownHostsFile $tmpfile'"
elif [ "$SSH_HOST_KEY_DISABLE" = "1" ]; then
ssh_options="-o 'StrictHostKeyChecking=No'"
else
echo "Neither SSH_HOST_KEY nor SSH_HOST_KEY_DISABLE set"
fi
restic_extra_options="sftp.command=ssh $ssh_options -i $ssh_key_file $restic_host -s sftp"
fi fi
if [ -n "$s3_key_file" ] && [ -f "$s3_key_file" ] && [ -n "$AWS_ACCESS_KEY_ID" ]; then if [ -n "$s3_key_file" ] && [ -f "$s3_key_file" ] && [ -n "$AWS_ACCESS_KEY_ID" ]; then
@ -57,45 +68,49 @@ else
mapfile -t services < <(docker service ls --format '{{ .Name }}') mapfile -t services < <(docker service ls --format '{{ .Name }}')
fi fi
for service in "${services[@]}"; do if [[ \ $*\ != *\ --skip-backup\ * ]]; then
echo "service: $service" for service in "${services[@]}"; do
details=$(docker service inspect "$service" --format "{{ json .Spec.Labels }}") echo "service: $service"
if echo "$details" | jq -r '.["backupbot.backup"]' | grep -q 'true'; then details=$(docker service inspect "$service" --format "{{ json .Spec.Labels }}")
pre=$(echo "$details" | jq -r '.["backupbot.backup.pre-hook"]') if echo "$details" | jq -r '.["backupbot.backup"]' | grep -q 'true'; then
post=$(echo "$details" | jq -r '.["backupbot.backup.post-hook"]') pre=$(echo "$details" | jq -r '.["backupbot.backup.pre-hook"]')
path=$(echo "$details" | jq -r '.["backupbot.backup.path"]') post=$(echo "$details" | jq -r '.["backupbot.backup.post-hook"]')
path=$(echo "$details" | jq -r '.["backupbot.backup.path"]')
if [ "$path" = "null" ]; then
echo "ERROR: missing 'path' for $service" if [ "$path" = "null" ]; then
continue # or maybe exit? echo "ERROR: missing 'path' for $service"
fi continue # or maybe exit?
fi
container=$(docker container ls -f "name=$service" --format '{{ .ID }}') container=$(docker container ls -f "name=$service" --format '{{ .ID }}')
echo "backing up $service" echo "backing up $service"
test -d "$backup_path/$service" || mkdir "$backup_path/$service" test -d "$backup_path/$service" || mkdir "$backup_path/$service"
if [ "$pre" != "null" ]; then if [ "$pre" != "null" ]; then
# run the precommand # run the precommand
# shellcheck disable=SC2086 # shellcheck disable=SC2086
docker exec "$container" sh -c "$pre" docker exec "$container" sh -c "$pre"
fi fi
# run the backup # run the backup
docker cp "$container:$path" "$backup_path/$service" docker cp "$container:$path" "$backup_path/$service"
if [ "$post" != "null" ]; then if [ "$post" != "null" ]; then
# run the postcommand # run the postcommand
# shellcheck disable=SC2086 # shellcheck disable=SC2086
docker exec "$container" sh -c "$post" docker exec "$container" sh -c "$post"
fi
fi fi
done
# check if restic repo exists, initialise if not
if [ -z "$(_restic cat config)" ] 2>/dev/null; then
echo "initializing restic repo"
_restic init
fi fi
done
# check if restic repo exists, initialise if not
if [ -z "$(_restic cat config)" ] 2>/dev/null; then
echo "initializing restic repo"
_restic init
fi fi
_restic backup --tag coop-cloud "$backup_path" if [[ \ $*\ != *\ --skip-upload\ * ]]; then
_restic backup --tag coop-cloud "$backup_path"
fi

View File

@ -4,8 +4,11 @@ services:
app: app:
environment: environment:
- SSH_KEY_FILE=/run/secrets/ssh_key - SSH_KEY_FILE=/run/secrets/ssh_key
- SSH_HOST_KEY
secrets: secrets:
- ssh_key - source: ssh_key
mode: 0400
entrypoint: [ "/usr/bin/backup.sh" ]
secrets: secrets:
ssh_key: ssh_key:

View File

@ -0,0 +1,14 @@
---
version: "3.8"
services:
app:
deploy:
mode: replicated
replicas: 0
labels:
- "swarm.cronjob.enable=true"
# Note(3wc): every 5m, testing
- "swarm.cronjob.schedule=*/5 * * * *"
# Note(3wc): blank label to be picked up by `abra recipe sync`
restart_policy:
condition: none

View File

@ -16,18 +16,9 @@ services:
- SERVER_NAME - SERVER_NAME
secrets: secrets:
- restic_password - restic_password
deploy: deploy:
mode: replicated
replicas: 0
labels: labels:
- "swarm.cronjob.enable=true"
# Note(3wc): every 5m, testing
- "swarm.cronjob.schedule=*/5 * * * *"
# Note(3wc): blank label to be picked up by `abra recipe sync`
- coop-cloud.${STACK_NAME}.app.version= - coop-cloud.${STACK_NAME}.app.version=
restart_policy:
condition: none
volumes: volumes:
backups: backups: