Skip to content

About

Manage a Docker Compose stand over SSH from GitLab CI: diff-based auto-deploy, dynamic child pipelines, full stand backups. No agents on the host.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

GitLab CI — Docker stand manager

English | Русский

A single gitlab-ci.yml that turns a GitLab pipeline into a remote control panel for a stand — a server running a set of Docker Compose services — over SSH. No agents on the target host: everything is plain ssh + rsync + docker compose from a CI runner.

To use it, drop the file into your project as .gitlab-ci.yml and set two CI/CD variables (see Configuration).

Repository layout it expects

.
├── .gitlab-ci.yml   # this pipeline
├── services/        # services/<name>/docker-compose.yml — one directory per service
├── scripts/         # helper shell scripts, mirrored to the stand
└── backups/         # optional seed content for the stand's backups directory

Jobs

service_management (deploy & observe)

Job Mode What it does
auto_deploy_services automatic on push git-diff based sync: rsync new and changed services, restart the changed ones, down + remove the deleted ones, then a final status report per service
auto_deploy_scripts automatic on push mirror scripts/ to the stand, including file deletions
start_all_services / stop_all_services / restart_all_services manual iterate BASE_PATH, docker compose up/down/restart in every directory with a compose file
status_all_services manual per-service status, ps and last 30 log lines for stopped ones, plus disk / memory / container table

stand_management (heavy operations)

Job What it does
push_services_only full stand reinstall: stop and remove all containers and images, recreate BASE_PATH, rsync services/, pull and start everything, then verify status
push_scripts_only / push_backups_only replace the stand's scripts/ / backups/ directory with the repo copy
delete_docker_containers / delete_docker_images / delete_docker_volumes targeted host cleanup: containers / images / named volumes
delete_services_dir wipe and recreate BASE_PATH
DROP_FULL_STAND all of the above in one button
backup_full_stand full backup: tar archives of every service and of scripts/, docker save of every running container's image, named-volume dumps — each with a .sha256 checksum and a jq-generated backup_manifest.json

component_management (dynamic child pipelines)

Each generator job inspects the stand and produces a child pipeline (artifact → trigger:), so buttons appear per discovered service/script:

Pair Result
generate_logs_pipeline → trigger_logs_pipeline a "logs" button per service: last 100 lines + live follow
generate_services_pipeline → trigger_services_pipeline a manual deploy button per service
generate_scripts_pipeline → trigger_scripts_pipeline a run button per *.sh script found on the stand (executed with sudo)

How change detection works

auto_deploy_* jobs compute a diff against a BASE_REF:

  1. merge request pipeline → origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME};
  2. push with a valid CI_COMMIT_BEFORE_SHA → that SHA;
  3. fallback → HEAD~1 if it exists;
  4. otherwise the diff is skipped with a warning (new/deleted service sync still runs — it doesn't depend on the diff).

GIT_DEPTH: 0 is set so the MR target branch is always fetchable.

Configuration

Pipeline variables (defaults in the file, override per environment/branch):

Variable Default Purpose
STAND stand stand name: SSH host and deploy subdirectory
SSH_HOST $STAND host to connect to
BASE_PATH /opt/apps/${STAND} services root; each subdirectory is one compose service
SCRIPTS_PATH /opt/scripts helper scripts directory on the stand
BACKUPS_ROOT /opt/backups backups root on the stand
REPO_SERVICES_PATH / REPO_SCRIPTS_PATH / REPO_BACKUPS_PATH services / scripts / backups repository directories to sync
RSYNC_EXCLUDES .git, CI files, .md exclusions applied to every rsync

Required project CI/CD variables (Settings → CI/CD → Variables, masked where possible):

Variable Purpose
DEPLOY_USER SSH user on the stand
SSH_PRIVATE_KEY private key allowed to log in to the stand

Runner image

The default image must contain openssh-client, rsync and jq. The file ships with a placeholder ubuntu:24.04 — replace it with an image from your registry (the same image name is embedded in the generated child pipelines).

Security notes

  • The destructive jobs (DROP_FULL_STAND, delete_*, push_services_only) operate on the whole host — they stop/remove all containers, images and volumes, not just "own" ones. They are when: manual buttons by design; protect your branches and restrict who can press them.
  • Host keys are accepted via ssh-keyscan (TOFU) and rsync uses StrictHostKeyChecking=no. Acceptable for an internal lab stand; for anything stricter, pre-seed known_hosts.
  • The model assumes passwordless sudo for the deploy user on the stand.

Requirements

  • GitLab with CI and a runner with the Docker executor
  • Network access from the runner to the stand over SSH (port 22)

About

Manage a Docker Compose stand over SSH from GitLab CI: diff-based auto-deploy, dynamic child pipelines, full stand backups. No agents on the host.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors