Initial commit
All checks were successful
buildbot/travis_bionic Build done.
buildbot/multibuild_parent Build done.

This commit is contained in:
Peter Šurda 2025-02-06 19:56:37 +08:00
commit 10b5cbec99
Signed by: PeterSurda
GPG Key ID: 3E47497CF67ABB95
4 changed files with 289 additions and 0 deletions

22
file-preprocessor.sh Normal file
View File

@ -0,0 +1,22 @@
#!/bin/bash
SUBDIR=files
[ -d $SUBDIR ] || exit
# TODO init variables:
# - secrets
datafile=$(mktemp)
for f in "$SUBDIR/*"; do
# TODO how about symlinks?
[ -f "$f" ] || continue
target="${f%.*}" # strip extension
case "${f##*.}" in
"j2")
j2 "$f" $datafile -o "$target"
;;
esac
done
rm -f $datafile

View File

@ -0,0 +1,116 @@
services:
provision:
deploy:
placement:
constraints:
- node.role == manager
mode: replicated-job
replicas: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- check the extent of provisioning and
- provision basic certbot config and secrets
- letsencrypt account key
- 2 private SSL keys, an old and a new, the old is possibly never used
- functionality to rotate both of these private keys
certbot:
depends_on:
nginx:
condition: service_healthy
deploy:
placement:
constraints:
- node.role == manager
volumes:
- /var/run/docker.sock:/var/run/docker.sock
secrets:
- source: certbot_key
target: /etc/certbot/priv.key
uid: "0"
gid: "0"
mode: 0400
- source: ssl_key_old
target: /etc/certbot/ssl/old.key
uid: "0"
gid: "0"
mode: 0400
- source: ssl_key_new
target: /etc/certbot/ssl/new.key
uid: "0"
gid: "0"
mode: 0400
- populate its own filesystem from live config
- all the SSL certs and corresponding renewal configs
- detect missing certs and request them
- maybe this can be also from a docker config, since the config is
readable, it wouldn't require a restart of the container
- then call certbot in a loop or something like that
- should point to new SSL key
- post-install and post-renewal script should refresh
nginx:
image: nginx:stable-alpine
depends_on:
provision:
condition: service_completed_successfully
deploy:
mode: replicated
endpoint_mode: vip
replicas: 1
placement:
constraints:
- node.role == manager
rollback_config:
order: start-first
update_config:
order: start-first
failure_action: rollback
configs:
- source: nginx_plain_conf
target: /etc/nginx/nginx.conf
uid: "0"
gid: "0"
mode: 0444
nginx_ssl:
image: nginx:stable-alpine
depends_on:
certbot:
condition: service_healthy
deploy:
mode: global
endpoint_mode: dnsrr
placement:
constraints:
- node.labels.org.sysdeploy.env == live
rollback_config:
parallelism: 2
delay: 20s
order: start-first
update_config:
parallelism: 2
delay: 20s
failure_action: rollback
order: start-first
configs:
- source: nginx_ssl_conf
target: /etc/nginx/nginx.conf
uid: "0"
gid: "0"
mode: 0444
networks:
configs:
nginx_plain_conf:
external: true
name: {{ NGINX_PLAIN_CONF }}
nginx_ssl_conf:
external: true
name: {{ NGINX_SSL_CONF }}
secrets:
certbot_key:
external: true
name: {{ CERTBOT_KEY }}
ssl_key_old:
external: true
name: {{ SSL_KEY_OLD }}
ssl_key_new:
external: true
name: {{ SSL_KEY_NEW }}

18
using-config.yaml.example Normal file
View File

@ -0,0 +1,18 @@
# example
# services:
# test:
# configs:
# - source: hello_conf # this would match the filename in the repo
# target: /etc/hello.conf # this would be used for labeling
# uid: "0"
# gid: "user"
# mode: 0440
# # this section below should be created by the templater and then
# # appended during `deploy`
# # templater does need to parse the compose file to extract the "target"
# # for labeling the config, but the name is automatic as that's based on
# # the filesystem
# configs:
# hello_conf:
# external: true
# name: templater_will_auto_fill_this

133
variable-handler.sh Executable file
View File

@ -0,0 +1,133 @@
#!/bin/bash
PROJECT_NAME=${1:?Project name missing}
shift
SERVICE_NAME=${1:?Service name missing}
shift
FILE_NAME=${1:?File name missing}
shift
VARIABLE_TYPE=${1:?Variable type missing (config or secret)}
shift
ITERATOR_TYPE=${1:?Iterator missing (version or hash)}
shift
case "$VARIABLE_TYPE" in
"config"|"secret")
;;
*)
echo "Invalid variable type"
exit 1
esac
LOCAL_FNAME=${PROJECT_NAME}/files/${SERVICE_NAME}/${FILE_NAME}
function get_variable {
# find latest
if [ "$ITERATOR_TYPE" = "version" ]; then
RETVAL=$(docker $VARIABLE_TYPE ls \
--filter label=org.sysdeploy.project=${PROJECT_NAME} \
--filter label=org.sysdeploy.service=${SERVICE_NAME} \
--filter label=org.sysdeploy.file=${FILE_NAME} \
--format '{{.Label "org.sysdeploy.version"}} {{.Name}}' \
| sort -rn | head -1)
ITERATOR=$(echo "$RETVAL" | cut -d\ -f1)
OBJECT_NAME=$(echo "$RETVAL" | cut -d\ -f2-)
elif [ "$ITERATOR_TYPE" = "hash" ]; then
if [ ! -f "$LOCAL_FNAME" ]; then
echo "Can't find $LOCAL_FNAME"
exit 1
fi
NEW_HASH=$(git log -n 1 --format='format:%H' -- "$LOCAL_FNAME")
ITERATOR="$NEW_HASH"
OBJECT_NAME=$(docker $VARIABLE_TYPE ls \
--filter label=org.sysdeploy.project=${PROJECT_NAME} \
--filter label=org.sysdeploy.service=${SERVICE_NAME} \
--filter label=org.sysdeploy.file=${FILE_NAME} \
--filter label=org.sysdeploy.hash=${ITERATOR} \
--format '{{.Name}}' \
| head -1)
fi
}
function get_content {
local OBJECT_NAME="$1"
shift
docker config inspect "$OBJECT_NAME" |jq -r \
'.[0].Spec.Data'|base64 --decode
}
function set_variable {
NEW_NAME=$(uuidgen)
if [ "$ITERATOR_TYPE" = "version" ]; then
((ITERATOR++))
docker $VARIABLE_TYPE create \
--label=org.sysdeploy.project=${PROJECT_NAME} \
--label=org.sysdeploy.service=${SERVICE_NAME} \
--label=org.sysdeploy.file=${FILE_NAME} \
--label=org.sysdeploy.version=${ITERATOR} \
"$NEW_NAME" "$LOCAL_FNAME"
elif [ "$ITERATOR_TYPE" = "hash" ]; then
docker $VARIABLE_TYPE create \
--label=org.sysdeploy.project=${PROJECT_NAME} \
--label=org.sysdeploy.service=${SERVICE_NAME} \
--label=org.sysdeploy.file=${FILE_NAME} \
--label=org.sysdeploy.hash=${ITERATOR} \
"$NEW_NAME" "$LOCAL_FNAME"
fi
}
get_variable
if [ -n "$OBJECT_NAME" ]; then
echo "Name: $OBJECT_NAME"
echo "Version/hash: $ITERATOR"
else
echo "Can't find any such $VARIABLE_TYPE"
fi
# set
if [ -n "$1" ]; then
set_variable
echo "New name: $NEW_NAME, $ITERATOR_TYPE: $ITERATOR"
fi
# docker config ls \
# --filter label=org.sysdeploy.file=/etc/collectd/collectd.conf.d/thresholds.conf \
# --format '{{.Label "org.sysdeploy.version"}} {{.ID}}'|sort -rn
# Create or rotate
#
# get current
# optional compare
# create a new one
# update references if needed
#
# create a config:
# docker config create \
# --label org.sysdeploy.project=monitoring \
# --label org.sysdeploy.file=/etc/collectd/collectd.conf.d/thresholds.conf \
# --label org.sysdeploy.service=collectd \
# --label org.sysdeploy.version=11 \
# $(uuidgen) thresholds.conf
#
# retrieving config label:
# docker config inspect \
# -f '{{index .Spec.Labels "org.sysdeploy.file"}}' \
# 6fe6qfmjjg606h138nxkbzjyw
#
# finding configs by label matching and reverse order by version
# docker config ls \
# --filter label=org.sysdeploy.file=/etc/collectd/collectd.conf.d/thresholds.conf \
# --format '{{.Label "org.sysdeploy.version"}} {{.ID}}'|sort -rn
#
# labels:
# org.sysdeploy.file = filename inside the container
# org.sysdeploy.version = if versioning incrementally, version is stored
# here
# org.sysdeploy.commit = if versioning by commit, commit is stored here
# org.sysdeploy.service = compose/stack service, not sure this is needed
# org.sysdeploy.project = $COMPOSE_PROJECT_NAME
#
# find the last commit a file was changed:
# git log -n 1 --format='format:%H' -- monitoring/docker-compose.yml