Language: English · Русский
Status: Go implementation (draft specification in this file).
CLI binary: the dq executable in this repository; the Bash/Python wrapper has been removed.
Full product name: Docker Quick-ops (binary: dq).
- The previous stack based on Bash, rsync/ssh/scp, and Python for YAML led to drift between environments.
A single statically linkable dq binary that:
- reads configuration from
**docker-ops.yaml**or**docker-ops.yml**only at the project root (no alternate paths such asscripts/); - keeps secrets and sensitive values in a separate
**dq.env**file (listed in**.gitignore**), merged into settings; - exposes a CLI built with spf13/cobra;
- generates shell completions (bash/zsh/fish as needed) and man pages from Cobra metadata (or related tooling);
- transfers files over SSH from Go without requiring
rsync/scpon the user machine; - supports cross-compilation for major OS/arch combinations (linux/windows/darwin, amd64/arm64, etc.).
- Runtime self-sufficiency: no Python and no mandatory
rsyncon the client. - Predictable behaviour and clear error messages.
- Versioned releases (tags, changelog — as decided).
| Term | Meaning |
|---|---|
| Project root | Directory from which the user runs dq (current cwd). |
| Local mode | No remote host configured, or remote explicitly disabled (--local / config flag / environment variable). |
| Remote mode | Host and server path are set; commands run over SSH on the remote machine (dq is not installed on the server). |
source deploy mode |
Sync project tree to the server + remote reup (build on server). |
artifacts deploy mode |
Server receives image-only compose, optional app config if set, image via registry or save/load. |
- Full name: Docker Quick-ops.
- Executable:
dq. - Use Docker Quick-ops (
dq) indq version, manNAME, and documentation.
- Go (version pinned in go.mod, LTS branch).
- Cobra — root command
dq, subcommands instead of “first argv = command”. - Packages (roughly):
config,compose(CLI and API if needed),remote/ssh, tree mirroring,deploy,internal/version.
- Main file: only
./docker-ops.yamlor./docker-ops.ymlat the project root (relative to cwd). No other standard paths (includingscripts/). - Secrets: separate
**dq.env**at project root (dotenv / shell-assignments), must be in.gitignore; values merge into config (precedence vs YAML fields — defined in code; env file usually wins). - Validation on startup; clear errors when required fields for a command are missing.
- Key-based auth (path from config / ssh-agent / OpenSSH defaults).
- Directory sync without
rsyncon the client: SFTP + size/mtime comparison; no repo size cap for now (may add later). - Image stream
docker save | … | docker load: over SSH via stdin or temp file on server — implementation-specific (disk and safety).
- Current: only
docker compose(Compose V2 plugin for Docker CLI). Standalonedocker-compose(V1) is not supported — if the plugin is missing,dqprints install hints (see Docker docs). Same locally and on the remote host over SSH (remote shell runs commands;dqis not installed on the server). - Extensions: may use
**docker.sock**(local Docker API). - Planned: HTTP Docker API (including remote hosts). Access on the server via SSH to the Docker socket (
/var/run/docker.sockon the remote host): forward/tunnel in the SSH session (local Unix socket or TCP proxy on the client), without exposing the Docker API on the network. Transport details — in implementation (see §14.2).
- Subcommands such as
up,logs,deployin remote mode use one SSH session / remote shell running**docker compose …**inremote_path. - In
artifactsmode, deploy files are delivered (image compose, optional app config, etc.), not thedqbinary.
dq completion bash|zsh|fish|powershell.dq man [subcommand…]— man page from Cobra metadata, viewed withman -l(man-db / groff). Ifmanis not inPATH, troff source goes to stdout.- Static generation into
man/man1/:make gen-man(go run ./tools/genman); install:make install-man(MANPREFIX, default/usr/local/share/man). - Single source of truth: Cobra →
--help, completion, and man.
- Project root: current working directory; optional
--project-dir/**DQ_PROJECT_ROOT**. - Load
docker-ops.yaml|docker-ops.yml+dq.envwhen present. - Setting precedence: §14.1.
Minimal set (snake_case in YAML):
| Area | Fields |
|---|---|
| Compose | compose_project_name, compose_file, compose_service |
| Remote | remote_ssh, remote_path, ssh_identity |
| Sync | exclude list (global); options equivalent to legacy rsync_extra map to internal sync |
| Deploy | deploy_mode (source or artifacts), deploy_image (single built image), optional deploy_images (YAML map: service name → image ref for multiple build: services), optional deploy_build_remote (artifacts: docker build / docker push on the server after mirroring the tree), deploy_push, deploy_use_registry, deploy_save_load, deploy_save_compress. Env: DEPLOY_IMAGE, and DEPLOY_IMAGES=svc=ref,svc2=ref2 in dq.env or process env (same format; overrides YAML deploy_images when set — §14.1). |
| Extra paths | deploy_include — relative to project root |
| Application | **app_config** (or equivalent): optional path to app config for copying in artifacts and for config-check; if unset — check/copy not required (often no file exists) |
| UX | help_show_effective and others as needed |
| Command | Locally | Remotely |
|---|---|---|
help / --help |
yes | yes |
man |
man from Cobra (man -l) |
yes |
env (config template) |
local only | do not proxy |
config-check |
if app_config set — verify file; else no-op or info |
same over SSH |
build, pull, up, down, reup, ps, restart |
docker compose … |
SSH + docker compose … in remote_path |
status |
ps + log tail | same over SSH |
logs, logs-tail, exec |
follow / tail / exec -it in terminal |
SSH; PTY for follow and interactive exec |
deploy |
source: SFTP mirror. artifacts: by default local docker (build) + upload; with deploy_build_remote: SFTP mirror, then docker build (and push if not save/load) on the server — no local Docker required for the image build. Needs configured remote. |
source or artifacts |
deploy:
source: directory on server, tree sync with exclude, copy app_config when configured and file exists, then remotereup.artifacts: whendeploy_push: trueordq deploy --build, images are built withdocker build— by default on this machine, then save/load or registry as configured. Withdeploy_build_remote: true(only withdeploy_mode: artifacts, e.g.DEPLOY_BUILD_REMOTE=1) the tree is mirrored over SFTP (likesource, honoringexclude) anddocker build/ registrydocker push(when not save/load) run on the server; local Docker is not required for the build. The same image tags apply:deploy_image, ordeploy_imagesin YAML, orDEPLOY_IMAGES=…in env — including when resolving whichdocker build -t …and push commands run (locally or on the server). Registry vs save/load; deliverdocker-compose.image.yml, app_config if set,deploy_include; on the server:config-check(if applicable) →uporpull+up. Thedqbinary is not copied to the server. Draftdocker-compose.image.yml:dq gen-image-compose. For several built services,deploy_images/DEPLOY_IMAGESanddq gen-image-compose --all-built; if no multi-image config, the single-deploy_image(orDEPLOY_IMAGE) flow applies.- Data on server (
artifacts): by default the wholeremote_pathproject tree is not fully mirrored (only the compose, image delivery, and configured paths) — extra dirs (e.g.db-data) are not removed unless indeploy_include. If you usedeploy_build_remote, a full mirror toremote_pathruns for the build (seeexclude). In all cases, ensuredocker-compose.image.ymluses the same volume path for DB data, etc.sourcecan delete server-only extras during sync — riskier for a live DB inside the project tree.
- Print
docker-ops.yamltemplate to stdout or--outputwith--force. --anonymize: do not substitute realremote_ssh/remote_pathfrom config/env.
- Linux — primary target.
- Windows initially: WSL2 is enough (full native Windows not required in v1).
- Go module:
github.com/SomniSom/docker-ops(repo: https://github.com/SomniSom/docker-ops). Install from source:go install github.com/SomniSom/docker-ops/cmd/dq@latest. dq versionand the product number: a release build (GitHub Releases asset, or your owngo build/makewith-ldflags) setsv1.1.0,v1.1.2, etc. — a single line likeDocker Quick-ops v1.1.2 (a1b2c3d). A plaingo install ...@latest(or@v1.1.2) embeds the Go module pseudo-version (e.g.v1.0.1-0.20260407201612-08053888e894), which comes from the module graph, not the human marketing tag. That is expected;dq versionmay print a second Note line in that case. To align the string with a git tag, use:make build VERSION=$(git describe --tags --always)or a prebuilt archive from Releases (GoReleaser sets-X .../version.Version={{.Version}}tov1.1.2for that tag build).go build/make build/make install— see Makefile (VERSION,GIT_COMMIT, ldflags →internal/version).- OS/arch matrix: GitHub Actions (
.github/workflows/ci.yml) — tests on Linux / macOS / Windows and cross-buildlinux|darwin|windows×amd64|arm64. - GoReleaser (
.goreleaser.yaml): same targets, archives (tar.gz/zipon Windows),checksums.txt, injects release semver into the binary. Locally:make goreleaser-check, snapshot:make goreleaser-snapshot(goreleaser required). Pushing a git tagv*runs.github/workflows/release.ymland publishes a GitHub release; that is the usual way to get a binary whosedq versionshows exactly the tag. - man —
make gen-man/make install-man(§4.6).
- UI language (messages, subcommand help, errors): English by default.
- If the system locale is Russian (
LANGUAGE,LC_ALL,LC_MESSAGES,LANG—ruprefix) — use Russian (internal/locale). - Explicit:
DQ_LANG=en|ru|auto(overrides auto) or globaldq --lang en|ru|auto(persistent flag; e.g.dq up --lang ruallowed). - Product name in
dq versionand root help: Docker Quick-ops (not translated).
- SSH host key behaviour like accept-new for known_hosts (analogous to
StrictHostKeyChecking=accept-newin OpenSSH).
- Project license: Apache License 2.0 (
**LICENSE**in repo root). Fork and use per license terms. - Binary signing (cosign, etc.) not required in v1.
- Old names (
**docker-ops.remote.yaml**,**docker-ops.remote.env**, etc.) are not supported: only**docker-ops.yaml/docker-ops.yml**+**dq.env**. Migrate manually per docs.
- Mapping old
docker-ops.remote.*/ env vars →docker-ops.yaml+dq.env— document in roadmap table. - No automatic migration (optional tool separately).
- Bash/Python scripts removed from the repo; use
dqonly.
- All commands from §5.3 in local mode on Linux with Docker installed.
- Remote mode without
dqon server: e2edeploy(sourceandartifactswith save/load) over SSH. - No Python or mandatory
rsyncon client; sync via SFTP + size/mtime. - Config only at root:
docker-ops.yaml|docker-ops.yml; secrets indq.env; merge order §14.1. dq completion bash|zshand man per §4.6.- Localization: en default, ru for Russian locale /
DQ_LANG/--lang(§8). - WSL2 user scenario documented and verified where possible.
For each parameter (YAML key, logical env var name), order is weaker → stronger (stronger overrides):
**docker-ops.yaml/docker-ops.yml**— base values from file at project root.**dq.env**— secrets file; overrides matching parameters from YAML (same key in either file; if both exist,dq.envwins).- Process environment (CI/CD,
export, systemd) — highest; overrides YAML anddq.env.
Parameters only in YAML and absent from dq.env and process env come from YAML. Empty or missing lines in dq.env should not wipe YAML without an explicit rule in code (recommendation: treat empty as “unset” and do not override YAML). DEPLOY_IMAGES=app=ghcr.io/ns/a:1,worker=ghcr.io/ns/w:1 in dq.env or the process environment replaces the deploy_images map from YAML when non-empty (same as other DEPLOY_* overrides; see list in internal/config/overlay.go).
Future Docker API access on remote hosts: via SSH to the Docker socket on the server (typically Unix socket /var/run/docker.sock). dq should establish an SSH tunnel (or library equivalent) so the user machine gets a local endpoint (Unix socket or 127.0.0.1:port) pointing at remote Docker; API client talks to that endpoint. No need to expose the Docker daemon on the internet.
Apache License, Version 2.0; full text in LICENSE at repo root.
- Sources:
cmd/dq,internal/config,internal/cli,internal/compose,internal/deploy,internal/sshexec,internal/remote,internal/version,tools/genman. - No Bash/Python scripts in the repo (formerly
scripts/). - Build:
make build→bin/dq;make installviago install. - Tests:
make test/make test-unit(-race);make test-integration—-tags=integration(Docker with Compose V2 plugin required). - Detailed status — Roadmap below.
Legend: [x] done · [ ] not done / planned.
-
docker-ops.yaml/docker-ops.ymlonly at project root -
dq.envand merge order §14.1 (YAML → dq.env → process env) - Defaults
compose_project_name(directory name),compose_file,compose_service -
dq validate(YAML,deploy_mode,app_configon disk,deploy_build_remoterequiresdeploy_mode: artifacts,dq.envsyntax) - Clear errors on YAML syntax (line context, indentation hints)
-
dq env(--output,--force,--anonymize) - Deeper semantic validation (e.g. all deploy fields,
ssh_identityexists)
-
build,pull,up,down,reup,ps,restart,exec,status,logs,logs-tail - Check
app_configbeforeup/reupwhen path set - Integration test with Docker (
-tags=integration) - Compose V2 required (
docker compose); nodocker-composeV1 fallback — missing plugin shows install hint
- Compose commands over SSH in
remote_path(internal/sshexec,internal/remote) —build,pull,up,down,reup,ps,restart,exec,status,logs,logs-tail - Auth:
ssh_identity(path,~allowed) and/or ssh-agent (SSH_AUTH_SOCK) - New host keys: append to
~/.ssh/known_hosts(accept-new); key change — refuse - TTY / PTY for
logs -fwith interactive terminal - Disable remote:
DOCKER_OPS_USE_REMOTE=0oruse_remote: falsein YAML
-
deployinsourcemode: SFTP tree sync, exclude list,deploy_include, optionalapp_config, remotereup -
deployinartifactsmode:docker build(local or withdeploy_build_remoteon the server), registry vssave/load, deliverdocker-compose.image.ymland files, remotepull+uporup - Map
rsync_extra→ internal sync options (if still in spec)
- Local docker.sock / API (§4.4)
- Remote Docker API via SSH tunnel to socket (§14.2)
- Cobra,
dq completion(bash / zsh / fish / powershell) -
dq version+ Makefile ldflags - Man pages:
dq man,make gen-man/make install-man(§4.6) - GoReleaser + CI OS/arch matrix, archives, checksums (§7,
.goreleaser.yaml,.github/workflows/)
- Messages and help: en default, ru for Russian locale (§8), package
internal/locale -
--lang,DQ_LANG
- Artifact signing (cosign, etc.) — not required in v1 (§10)
May move to docs/spec-dq.md; this readme.md is the living English spec. Russian: readme.ru.md.