commit 10b5cbec9979aab10ecdd0461e0d7982cc1d398d Author: Peter Surda Date: Thu Feb 6 19:56:37 2025 +0800 Initial commit diff --git a/file-preprocessor.sh b/file-preprocessor.sh new file mode 100644 index 0000000..5c57bb9 --- /dev/null +++ b/file-preprocessor.sh @@ -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 diff --git a/nginx-ingress/docker-compose.yml b/nginx-ingress/docker-compose.yml new file mode 100644 index 0000000..5c4a6e5 --- /dev/null +++ b/nginx-ingress/docker-compose.yml @@ -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 }} diff --git a/using-config.yaml.example b/using-config.yaml.example new file mode 100644 index 0000000..4d6bbde --- /dev/null +++ b/using-config.yaml.example @@ -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 diff --git a/variable-handler.sh b/variable-handler.sh new file mode 100755 index 0000000..78fc82b --- /dev/null +++ b/variable-handler.sh @@ -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