a9a758d332
- Add slcompose.sh: Central orchestrator for managing all Docker services * Boot all services at startup with automated Infisical secret injection * Commands: up, down, restart, logs, logs-tail, env, env-all * Colored environment variable output (blue names, green values) - Add slcompose.service: Systemd service file for auto-boot on startup * Type=oneshot with RemainAfterExit=yes * Waits for Docker service before starting * Runs on multi-user.target - Add orchestration.md: Comprehensive documentation * Architecture and installation guide * Usage examples for all commands * Secret injection flow and troubleshooting * Performance and security notes - Update README.md and AI_CONTEXT.md * Document service orchestration architecture * Explain slcompose functionality and commands * Reference new orchestration documentation
289 lines
6.5 KiB
Bash
289 lines
6.5 KiB
Bash
#!/bin/bash
|
|
set -e
|
|
|
|
BASE_DIR="/srv/docker"
|
|
INFISICAL_TOKEN_FILE="/etc/infisical/token"
|
|
INFISICAL_DOMAIN_FILE="/etc/infisical/domain"
|
|
|
|
function load_infisical() {
|
|
if [ ! -f "$INFISICAL_TOKEN_FILE" ]; then
|
|
echo "ERROR: Missing Infisical token at $INFISICAL_TOKEN_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
export INFISICAL_TOKEN=$(cat "$INFISICAL_TOKEN_FILE")
|
|
|
|
if [ -f "$INFISICAL_DOMAIN_FILE" ]; then
|
|
export INFISICAL_DOMAIN=$(cat "$INFISICAL_DOMAIN_FILE")
|
|
fi
|
|
}
|
|
|
|
function exec_with_infisical() {
|
|
local service_name="$1"
|
|
shift
|
|
|
|
infisical run \
|
|
--token "$INFISICAL_TOKEN" \
|
|
--env prod \
|
|
--path="/$service_name" \
|
|
--recursive \
|
|
-- "$@"
|
|
}
|
|
|
|
function run_service() {
|
|
SERVICE_DIR="$1"
|
|
shift
|
|
|
|
SERVICE_NAME=$(basename "$SERVICE_DIR")
|
|
|
|
cd "$SERVICE_DIR"
|
|
|
|
echo "-----------------------------------"
|
|
echo "Booting: $SERVICE_DIR"
|
|
|
|
until docker info >/dev/null 2>&1; do
|
|
echo "Waiting for Docker..."
|
|
sleep 2
|
|
done
|
|
|
|
load_infisical
|
|
|
|
echo "Using Infisical path: /$SERVICE_NAME"
|
|
|
|
exec_with_infisical "$SERVICE_NAME" docker compose "$@"
|
|
}
|
|
|
|
function list_services() {
|
|
echo "Available services:"
|
|
echo "===================="
|
|
for dir in "$BASE_DIR"/*; do
|
|
if [ -f "$dir/docker-compose.yml" ]; then
|
|
SERVICE_NAME=$(basename "$dir")
|
|
echo " - $SERVICE_NAME"
|
|
fi
|
|
done
|
|
}
|
|
|
|
function boot_all() {
|
|
echo "==================================="
|
|
echo "SilverLinux Boot Orchestrator START"
|
|
echo "==================================="
|
|
|
|
load_infisical
|
|
|
|
for dir in "$BASE_DIR"/*; do
|
|
if [ -f "$dir/docker-compose.yml" ]; then
|
|
SERVICE_NAME=$(basename "$dir")
|
|
echo "Booting: $SERVICE_NAME"
|
|
run_service "$dir" up -d || {
|
|
echo "FAILED: $SERVICE_NAME"
|
|
}
|
|
|
|
sleep 2
|
|
fi
|
|
done
|
|
|
|
echo "==================================="
|
|
echo "Boot orchestration finished"
|
|
echo "==================================="
|
|
}
|
|
|
|
function service_up() {
|
|
SERVICE_NAME="$1"
|
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
|
|
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Starting service: $SERVICE_NAME"
|
|
run_service "$SERVICE_DIR" up -d
|
|
}
|
|
|
|
function service_down() {
|
|
SERVICE_NAME="$1"
|
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
|
|
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Stopping service: $SERVICE_NAME"
|
|
run_service "$SERVICE_DIR" down
|
|
}
|
|
|
|
function service_restart() {
|
|
SERVICE_NAME="$1"
|
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
|
|
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Restarting service: $SERVICE_NAME"
|
|
run_service "$SERVICE_DIR" restart
|
|
}
|
|
|
|
function service_logs() {
|
|
SERVICE_NAME="$1"
|
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
|
|
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Tailing logs for: $SERVICE_NAME (Ctrl+C to exit)"
|
|
run_service "$SERVICE_DIR" logs -f
|
|
}
|
|
|
|
function service_logs_tail() {
|
|
SERVICE_NAME="$1"
|
|
NUM_LINES="${2:-200}"
|
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
|
|
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Last $NUM_LINES lines of logs for: $SERVICE_NAME"
|
|
run_service "$SERVICE_DIR" logs --tail "$NUM_LINES"
|
|
}
|
|
|
|
function service_env() {
|
|
SERVICE_NAME="$1"
|
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
|
|
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
load_infisical
|
|
|
|
echo "========================================"
|
|
echo "Environment Variables for: $SERVICE_NAME"
|
|
echo "========================================"
|
|
|
|
exec_with_infisical "$SERVICE_NAME" env | grep -v "^_" | sort | while IFS='=' read -r name value; do
|
|
printf "\033[34m%-50s\033[0m = \033[32m%s\033[0m\n" "$name" "$value"
|
|
done
|
|
}
|
|
|
|
function service_env_all() {
|
|
load_infisical
|
|
|
|
echo "========================================"
|
|
echo "All Services and Their Environment Variables"
|
|
echo "========================================"
|
|
|
|
for dir in "$BASE_DIR"/*; do
|
|
if [ -f "$dir/docker-compose.yml" ]; then
|
|
SERVICE_NAME=$(basename "$dir")
|
|
echo ""
|
|
echo "--- $SERVICE_NAME ---"
|
|
exec_with_infisical "$SERVICE_NAME" env | grep -v "^_" | sort | while IFS='=' read -r name value; do
|
|
printf "\033[34m%-50s\033[0m = \033[32m%s\033[0m\n" "$name" "$value"
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
function show_usage() {
|
|
cat <<EOF
|
|
SilverLinux Service Orchestrator
|
|
|
|
Usage: $0 <command> [service_name] [options]
|
|
|
|
Commands:
|
|
boot Boot all services at startup
|
|
list List all available services
|
|
up <service> Start a service
|
|
down <service> Stop a service
|
|
restart <service> Restart a service
|
|
logs <service> Tail logs for a service (Ctrl+C to exit)
|
|
logs-tail <service> [lines] Show last N lines of logs (default: 200)
|
|
env <service> Show injected environment variables for a service
|
|
env-all Show injected environment variables for all services
|
|
|
|
Examples:
|
|
$0 boot
|
|
$0 list
|
|
$0 up gitea
|
|
$0 down gitea
|
|
$0 restart gitea
|
|
$0 logs gitea
|
|
$0 logs-tail gitea
|
|
$0 logs-tail gitea 500
|
|
$0 env gitea
|
|
$0 env-all
|
|
EOF
|
|
}
|
|
|
|
case "$1" in
|
|
boot)
|
|
boot_all
|
|
;;
|
|
list)
|
|
list_services
|
|
;;
|
|
up)
|
|
if [ -z "$2" ]; then
|
|
echo "ERROR: Service name required"
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
service_up "$2"
|
|
;;
|
|
down)
|
|
if [ -z "$2" ]; then
|
|
echo "ERROR: Service name required"
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
service_down "$2"
|
|
;;
|
|
restart)
|
|
if [ -z "$2" ]; then
|
|
echo "ERROR: Service name required"
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
service_restart "$2"
|
|
;;
|
|
logs)
|
|
if [ -z "$2" ]; then
|
|
echo "ERROR: Service name required"
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
service_logs "$2"
|
|
;;
|
|
logs-tail)
|
|
if [ -z "$2" ]; then
|
|
echo "ERROR: Service name required"
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
service_logs_tail "$2" "$3"
|
|
;;
|
|
env)
|
|
if [ -z "$2" ]; then
|
|
echo "ERROR: Service name required"
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
service_env "$2"
|
|
;;
|
|
env-all)
|
|
service_env_all
|
|
;;
|
|
*)
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac |