devto 2026-06-18 원문 보기 ↗
Every time someone starts self-hosting - a homelab, a few internal services for a small team - they tend to fall down the same rabbit hole: should I run K8s? And if I run K8s, do I need ArgoCD or Flux for GitOps? Two weeks later they've read a pile of Helm charts and CRDs and still haven't deployed a single service.
Let me say the quiet part out loud: for a single host, or three-to-five machines, you do not need ArgoCD. The part of GitOps you actually want - "the git repo is the source of truth, changes deploy themselves, I can roll back, and there's a record" - you can get 90% of it with git + docker compose and about twenty lines of script, with no control plane to babysit.
GitOps boils down to two things:
docker-compose.yml).On one docker host, the minimal version looks like this: a webhook (or a 60-second git fetch) notices the tracked branch moved, and runs:
git pull --ff-only
docker compose pull
docker compose up -d --remove-orphans
--remove-orphans matters: services you delete from the compose file actually get stopped, instead of lingering forever. That's it - you now have a working GitOps loop: edit compose -> push -> the machine reconciles itself.
The good-enough version runs, but there are two traps anyone who's done this knows:
Plain docker compose up -d recreates the container - old one stops, new one starts, with a few seconds of gap in between. Fine for background jobs, but for anything user-facing those few seconds are a 502.
compose up --wait (v2.17+) at least waits for the healthcheck before calling the deploy a success, which catches the "starts then crashes" case;Don't expect compose to do graceful rolling updates for you. It doesn't.
This is the one most people skip and the one that hurts most. If your image tag is :latest, then "rollback" means "edit the file and pray" - you have no idea which version last worked.
The fix: pin image tags to the git commit SHA (myapp:9f8322f, not myapp:latest), and record which SHA is currently live. Now rollback degrades to "re-deploy the previous SHA" - deterministic and repeatable. Without it, your GitOps quietly turns into "git pull and hope".
The boundary is clear:
But note: that threshold is much later than most people assume. For the vast majority of self-hosting, you're still on the "twenty-line script is fine" side.
I understood all of the above, and still got tired of re-typing the webhook + pull + compose + SHA-pinning + rollback-record dance every time I set up a new machine. So I bundled it - along with the CI build step before it, agentless multi-host SSH deploys, and container management - into a single Go binary called Pipewright: scp one file to a server, run it, open the browser, and you get a visual pipeline + one-click deploy + a container panel, with no other runtime dependencies (the Vue frontend is compiled into the binary via embed.FS, SQLite by default).
It's basically the "good-enough GitOps" above, productized, with the zero-downtime and SHA-based rollback gaps filled in. MIT licensed, aimed at solo devs and small teams - not trying to replace GitLab for a 200-engineer org.
Repo: https://github.com/huangchengsir/pipewright
But even if you never touch it, the takeaway stands: for self-hosted GitOps, you probably don't need ArgoCD. Start with git + compose, and only add weight when you actually hit the wall.
Issues and pushback welcome.