{"id":34572723,"url":"https://github.com/evolutics/kerek","last_synced_at":"2026-03-13T08:31:24.249Z","repository":{"id":65545693,"uuid":"591609987","full_name":"evolutics/kerek","owner":"evolutics","description":"Light continuous delivery for Docker Compose","archived":false,"fork":false,"pushed_at":"2025-09-14T07:39:16.000Z","size":778,"stargazers_count":32,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-25T21:07:27.322Z","etag":null,"topics":["compose","delivery","deployment","docker","podman"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evolutics.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-21T09:16:54.000Z","updated_at":"2025-09-14T07:39:20.000Z","dependencies_parsed_at":"2024-05-18T16:22:32.468Z","dependency_job_id":"dc571c78-9c2f-4ec8-a730-984fd2180f97","html_url":"https://github.com/evolutics/kerek","commit_stats":null,"previous_names":["evolutics/kerek","evolutics/wheelsticks"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/evolutics/kerek","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolutics%2Fkerek","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolutics%2Fkerek/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolutics%2Fkerek/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolutics%2Fkerek/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evolutics","download_url":"https://codeload.github.com/evolutics/kerek/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evolutics%2Fkerek/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30462230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T06:34:02.089Z","status":"ssl_error","status_checked_at":"2026-03-13T06:33:49.182Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compose","delivery","deployment","docker","podman"],"created_at":"2025-12-24T09:44:17.285Z","updated_at":"2026-03-13T08:31:24.234Z","avatar_url":"https://github.com/evolutics.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kerek: Light Continuous Delivery for Docker Compose\n\nKerek is a CLI that adds features to Docker for people who like to keep\ncontinuous delivery light and not deal with Kubernetes or a container registry.\n\n![Kerek logo](logo.svg)\n\n## Features\n\n- Zero-downtime deployments for Docker Compose.\n- Distributing images over SSH instead of a registry.\n- Custom SSH config files supported for remote Docker instances.\n- Compatible with Docker and Podman.\n\n## Setup\n\n### Prerequisites\n\n- Docker or Podman\n- Docker Compose\n\n### Installation\n\nDownload a pre-built executable from the\n[latest release](https://github.com/evolutics/kerek/releases/latest). If you see\nan error with glibc (\"version … not found\"), try the musl executable instead.\n\nAlternatively, build from source with\n\n```bash\ncargo install --git https://github.com/evolutics/kerek\n```\n\n## Usage\n\n### CLI overview\n\n```\nUsage: kerek [OPTIONS] \u003cCOMMAND\u003e\n\nCommands:\n  deploy           Create or update Docker Compose services\n  provision        Install container engine on host, making system-wide changes\n  transfer-images  Copy images from default to specified Docker host\n  tunnel-ssh       Forward local Unix domain socket to remote Docker host over\n                   SSH\n  help             Print this message or the help of the given subcommand(s)\n```\n\nSee the [CLI reference](#command-line-arguments-reference) (also available via\n`kerek \u003cCOMMAND\u003e --help`) for many quick **examples**.\n\nThe following explains common CI/CD scenarios.\n\n### Service update order\n\nWhen updating services with `docker compose up`, the old container of a service\nis stopped before a new container of the service is started, causing a service\ninterruption (**`stop-first`** case):\n\n```\n_______________________.\nOld container           Stop\n                                    ._______________________\n                                    Start      New container\n```\n\nImagine we could make the container lifetimes overlap instead (**`start-first`**\ncase):\n\n```\n___________________________________.\nOld container                       Stop\n                        .___________________________________\n                        Start                  New container\n```\n\nKerek supports both of these cases.\n\nFor services where a new container should be started before the old container is\nstopped, configure this in your Compose file:\n\n```diff\n# compose.yaml\nservices:\n  my-service:\n    image: my-image\n+   deploy:\n+     update_config:\n+       order: start-first\n```\n\nNow just run `kerek deploy` in place of `docker compose up`. No need to change\nany other Docker Compose workflows.\n\nNote that above config is an official (but optional) part of the\n[Compose specification](https://github.com/compose-spec/compose-spec/blob/main/deploy.md).\nHowever, vanilla Docker Compose always updates services in `stop-first` order,\neven if your Compose file says otherwise.\n\n### Zero-downtime deployments\n\nTo switch over traffic from old to new version of an application during an\nupdate, it is common to use a reverse proxy.\n\nSee this [demo](examples/zero_downtime_deployment/compose.yaml) with an example\n`greet` service, which is behind a `reverse-proxy` service (Caddy) for this\npurpose:\n\n```mermaid\nflowchart LR\n    localhost:8080 --\u003e|:8181| reverse-proxy --\u003e|:8282| greet\n```\n\nAs `greet` is configured in `start-first` update order, the `reverse-proxy` can\nseamlessly switch over traffic from old to new container during their overlap.\n\nTry it yourself:\n\n```bash\ncd examples/zero_downtime_deployment\n\nGREET_VERSION=A kerek deploy --wait\ncurl localhost:8080 # … prints \"Hi from A\"\n\nGREET_VERSION=B kerek deploy --wait\ncurl localhost:8080 # … prints \"Hi from B\"\n\ndocker compose down\n```\n\nTo see above deployments in action, use a separate shell session to run\n\n```bash\nwhile true; do curl --fail --max-time 0.2 localhost:8080; sleep 0.01s; done\n```\n\n### Continuous delivery via SSH\n\nThere is an [example](examples/ssh_delivery/test.sh) of a pipeline that delivers\na Compose application to a staging environment via SSH. Summary of the whole\nprocess:\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant Pipeline\n    participant SSH tunnel\n    participant Staging VM\n\n    Pipeline-\u003e\u003eStaging VM: Provision Vagrant VM with Podman\n    Pipeline-\u003e\u003ePipeline: Build/pull container images\n    Pipeline-\u003e\u003eSSH tunnel: Tunnel SSH to Podman service on staging\n    activate SSH tunnel\n    Pipeline-\u003e\u003eStaging VM: Transfer container images\n    Pipeline-\u003e\u003eStaging VM: Deploy Compose application\n    Pipeline-xSSH tunnel: Terminate tunnel\n    deactivate SSH tunnel\n    Pipeline-\u003e\u003eStaging VM: Smoke test application\n```\n\n### Support for Podman and other container engines\n\nPass `--container-engine podman` or set the environment variable\n`CONTAINER_ENGINE=podman` to use Podman instead of Docker. Kerek is\nengine-agnostic so you may use any other container engine with a compatible CLI.\n\nPodman Compose is not supported as it currently lacks some needed features like\nthe calculation of service config hashes (`docker compose config --hash \\*`).\n\n### Docker CLI plugin\n\nKerek may be set up as a Docker CLI plugin. With that, calls to subcommands like\n`kerek deploy` can be replaced by `docker deploy`, which some people prefer.\nExample [setup](https://github.com/docker/cli/issues/1534):\n\n```bash\nmkdir --parents ~/.docker/cli-plugins\nln --symbolic \"$(which kerek)\" ~/.docker/cli-plugins/docker-deploy\ndocker deploy --help\n```\n\n## Alternatives\n\nOther light options for continuous delivery of containerized applications:\n\n- [Docker without Compose](https://github.com/evolutics/zero-downtime-deployments-with-podman-docker-or-docker-compose)\n- [`docker rollout`](https://github.com/Wowu/docker-rollout)\n- [Docker Swarm mode](https://docs.docker.com/engine/swarm/)\n- [K3s](https://docs.k3s.io)\n- PaaS like [CapRover](https://caprover.com), [Dokku](https://dokku.com), etc.\n- [`podman kube play`](https://docs.podman.io/en/latest/markdown/podman-kube-play.1.html)\n\n## Command-line arguments reference\n\n### `kerek --help`\n\n```\nLight continuous delivery for Docker Compose\n\nUsage: kerek [OPTIONS] \u003cCOMMAND\u003e\n\nCommands:\n  deploy           Create or update Docker Compose services\n  provision        Install container engine on host, making system-wide changes\n  transfer-images  Copy images from default to specified Docker host\n  tunnel-ssh       Forward local Unix domain socket to remote Docker host over\n                   SSH\n  help             Print this message or the help of the given subcommand(s)\n\nOptions:\n      --container-engine \u003cCONTAINER_ENGINE\u003e\n          Container engine program to use\n\n          [env: CONTAINER_ENGINE=]\n          [default: docker]\n\n      --dry-run\n          Do not apply changes, only show what would be done\n\n      --config \u003cCONFIG\u003e\n          Location of client config files\n\n  -c, --context \u003cCONTEXT\u003e\n          Name of the context to use to connect to the daemon (overrides\n          DOCKER_HOST env var and default context set with `docker context use`)\n\n  -D, --debug\n          Enable debug mode\n\n  -H, --host \u003cHOST\u003e\n          Daemon socket to connect to\n\n  -l, --log-level \u003cLOG_LEVEL\u003e\n          Set the logging level\n\n          [possible values: debug, info, warn, error, fatal]\n\n      --tls\n          Use TLS; implied by --tlsverify\n\n      --tlscacert \u003cTLSCACERT\u003e\n          Trust certs signed only by this CA\n\n      --tlscert \u003cTLSCERT\u003e\n          Path to TLS certificate file\n\n      --tlskey \u003cTLSKEY\u003e\n          Path to TLS key file\n\n      --tlsverify\n          Use TLS and verify the remote\n\n  -h, --help\n          Print help\n\n  -V, --version\n          Print version\n```\n\n### `kerek deploy --help`\n\n```\nCreate or update Docker Compose services\n\nBuilds, (re)creates, and starts containers for a Docker Compose service.\n\nIf service names are given as command-line operands, this command does not\nautomatically start any of their linked services.\n\nThe containers are always run in the background (detached mode).\n\nIf there are existing containers for a service whose service config has changed\nsince the containers' creation, the changes are applied by recreating the\ncontainers (preserving mounted volumes).\n\nMore precisely, a service is updated only if its service config hash changes\n(details in https://github.com/docker/compose/blob/main/pkg/compose/hash.go).\nNote that the service config hash does not depend on the container image\ncontents but only the `image` field. Thus, reusing an image tag like `latest`\ndoes not trigger an update per se.\n\nTo force updating services regardless of config hash changes, use the\n`--force-recreate` flag.\n\nWhether the old containers are stopped before or after the new containers are\nstarted is controlled via `services.*.deploy.update_config.order` in a Compose\nfile. The options are `stop-first` and `start-first`, respectively.\n\nServices are updated in lexicographical order (by Unicode code point),\nregardless of dependencies. For each service, containers are stopped then\nstarted (`stop-first`, default) or started then stopped (`start-first`),\nrespectively, and this is repeated for replicas:\n\n- `stop-first` case:\n  1. Stop old replica 1\n  2. Start new replica 1\n  3. Stop old replica 2\n  4. Start new replica 2\n  5. …\n- `start-first` case:\n  1. Start new replica 1\n  2. Stop old replica 1\n  3. Start new replica 2\n  4. Stop old replica 2\n  5. …\n\nExamples:\n\n- Update services whose config hash has changed:\n    $ kerek deploy\n- Update service `my-service` if its config hash has changed:\n    $ kerek deploy my-service\n- Always update all services:\n    $ kerek deploy --force-recreate\n- Always update service `my-service`:\n    $ kerek deploy --force-recreate my-service\n\n- Only show what would be changed:\n    $ kerek --dry-run deploy\n- Show service config hashes:\n    $ docker compose config --hash \\*\n\nUsage: kerek deploy [OPTIONS] [SERVICE_NAMES]...\n\nArguments:\n  [SERVICE_NAMES]...\n          Services to consider\n\nOptions:\n      --all-resources\n          Include all resources, even those not used by services\n\n      --ansi \u003cANSI\u003e\n          Control when to print ANSI control characters\n\n          [possible values: never, always, auto]\n\n      --compatibility\n          Run compose in backward compatibility mode\n\n      --env-file \u003cENV_FILE\u003e\n          Specify an alternate environment file\n\n  -f, --file \u003cFILE\u003e\n          Compose configuration files\n\n      --parallel \u003cPARALLEL\u003e\n          Control max parallelism, -1 for unlimited\n\n      --profile \u003cPROFILE\u003e\n          Specify a profile to enable\n\n      --progress \u003cPROGRESS\u003e\n          Set type of progress output\n\n          [possible values: auto, tty, plain, json, quiet]\n\n      --project-directory \u003cPROJECT_DIRECTORY\u003e\n          Specify an alternate working directory (default: the path of the,\n          first specified, Compose file)\n\n  -p, --project-name \u003cPROJECT_NAME\u003e\n          Project name\n\n      --build\n          Build images before starting containers\n\n      --force-recreate\n          Recreate containers even if their configuration and image haven't\n          changed\n\n      --no-build\n          Don't build an image, even if it's policy\n\n      --no-deps\n          Don't start linked services\n\n      --no-start\n          Don't start the services after creating them\n\n      --pull \u003cPULL\u003e\n          Pull image before running\n\n          [possible values: always, missing, never]\n\n      --quiet-pull\n          Pull without printing progress information\n\n      --remove-orphans\n          Remove containers for services not defined in the Compose file\n\n  -V, --renew-anon-volumes\n          Recreate anonymous volumes instead of retrieving data from the\n          previous containers\n\n  -t, --timeout \u003cTIMEOUT\u003e\n          Use this timeout in seconds for container shutdown when containers are\n          already running\n\n      --wait\n          Wait for services to be running|healthy\n\n      --wait-timeout \u003cWAIT_TIMEOUT\u003e\n          Maximum duration to wait for the project to be running|healthy\n\n  -h, --help\n          Print help (see a summary with '-h')\n```\n\n### `kerek provision --help`\n\n```\nInstall container engine on host, making system-wide changes\n\nThis targets a host via SSH, unless host `localhost` and no SSH config file are\npassed as arguments, in which case the current machine is targeted.\n\nExamples:\n\n- Provision Podman on SSH host:\n    $ kerek --container-engine podman provision my-ssh-host\n- Provision Podman on localhost:\n    $ kerek --container-engine podman provision localhost\n\nUsage: kerek provision [OPTIONS] \u003cHOST\u003e\n\nArguments:\n  \u003cHOST\u003e\n          Reference like `localhost` or `[ssh://][\u003cuser\u003e@]\u003chostname\u003e[:\u003cport\u003e]`\n\nOptions:\n      --force\n          Go ahead without prompting user to confirm\n\n  -F, --ssh-config \u003cSSH_CONFIG\u003e\n          Path to SSH config file\n\n  -h, --help\n          Print help (see a summary with '-h')\n```\n\n### `kerek transfer-images --help`\n\n```\nCopy images from default to specified Docker host\n\nBy default, only images not present on the destination host are transferred. An\nimage is considered present if the provided name matches one of these forms:\n\n- `\u003cnamespace\u003e:\u003ctag\u003e`\n- `\u003cnamespace\u003e@\u003cdigest\u003e`\n- `\u003cnamespace\u003e:\u003ctag\u003e@\u003cdigest\u003e`\n\nExamples:\n\n- Transfer image `img:tag` from default Docker host to 192.0.2.1 over SSH:\n    $ kerek --host ssh://192.0.2.1 transfer-images img:tag\n- Transfer image from Docker host `ssh://src` to `ssh://dest`:\n    $ DOCKER_HOST=ssh://src kerek --host ssh://dest transfer-images img:tag\n- Transfer image from Docker context `src` to `dest`:\n    $ DOCKER_CONTEXT=src kerek --context dest transfer-images img:tag\n\n- Always transfer image, even if already present under same name `img:tag`:\n    $ kerek --host … transfer-images --force img:tag\n- Transfer images of Compose file:\n    $ docker compose config --images | kerek --host … transfer-images -\n- Transfer image, compressing it in transit with Zstandard:\n    $ kerek --host … transfer-images --compress zstd img:tag\n\nUsage: kerek transfer-images [OPTIONS] [IMAGES]...\n\nArguments:\n  [IMAGES]...\n          Images to copy; use `-` to pass image names as stdin lines\n\nOptions:\n      --compress \u003cCOMPRESS\u003e\n          Compression command to use (`bzip2`, `gzip`, `xz`, `zstd`, etc.)\n\n      --force\n          Copy images without checking if the destination already has such\n          images; useful for replacing images with `latest` tag\n\n  -h, --help\n          Print help (see a summary with '-h')\n```\n\n### `kerek tunnel-ssh --help`\n\n```\nForward local Unix domain socket to remote Docker host over SSH\n\nThis runs an SSH tunnel in the background. Meanwhile, you can connect to the\nremote Docker host using `DOCKER_HOST=unix:///path/to/kerek.sock` locally. Note\nthat a custom SSH config file can be specified, unlike with vanilla Docker.\n\nExamples:\n\n- Use temporary SSH tunnel to show containers running on SSH host:\n    $ kerek tunnel-ssh my-ssh-host\n    $ DOCKER_HOST=\"unix://${PWD}/kerek.sock\" docker ps\n    $ fuser --kill -TERM kerek.sock\n- Tunnel to SSH host of custom SSH config file:\n    $ kerek tunnel-ssh --ssh-config my_ssh_config my-ssh-host\n\nUsage: kerek tunnel-ssh [OPTIONS] \u003cSSH_HOST\u003e\n\nArguments:\n  \u003cSSH_HOST\u003e\n          Reference like `[ssh://][\u003cuser\u003e@]\u003chostname\u003e[:\u003cport\u003e]`\n\nOptions:\n      --local-socket \u003cLOCAL_SOCKET\u003e\n          Path to Unix domain socket on localhost to be forwarded\n\n          [default: kerek.sock]\n\n      --remote-socket \u003cREMOTE_SOCKET\u003e\n          Path to Unix domain socket of Docker host on remote\n\n  -F, --ssh-config \u003cSSH_CONFIG\u003e\n          Path to SSH config file\n\n  -h, --help\n          Print help (see a summary with '-h')\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevolutics%2Fkerek","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevolutics%2Fkerek","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevolutics%2Fkerek/lists"}