{"id":13446658,"url":"https://github.com/safe-waters/docker-lock","last_synced_at":"2025-03-21T16:32:38.145Z","repository":{"id":38845784,"uuid":"198267526","full_name":"safe-waters/docker-lock","owner":"safe-waters","description":"Automatically manage image digests in Dockerfiles, docker-compose files, and Kubernetes manifests by tracking them in a separate Lockfile","archived":false,"fork":false,"pushed_at":"2024-01-31T22:47:13.000Z","size":9641,"stargazers_count":429,"open_issues_count":10,"forks_count":18,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-08-01T05:20:06.649Z","etag":null,"topics":["cli","container-registry","docker","golang","kubernetes"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/safe-waters.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2019-07-22T16:59:16.000Z","updated_at":"2024-07-29T17:36:19.000Z","dependencies_parsed_at":"2024-06-18T21:52:42.759Z","dependency_job_id":null,"html_url":"https://github.com/safe-waters/docker-lock","commit_stats":null,"previous_names":["michaelperel/docker-lock"],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/safe-waters%2Fdocker-lock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/safe-waters%2Fdocker-lock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/safe-waters%2Fdocker-lock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/safe-waters%2Fdocker-lock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/safe-waters","download_url":"https://codeload.github.com/safe-waters/docker-lock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221817134,"owners_count":16885468,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["cli","container-registry","docker","golang","kubernetes"],"created_at":"2024-07-31T05:00:55.765Z","updated_at":"2024-10-28T10:30:12.742Z","avatar_url":"https://github.com/safe-waters.png","language":"Go","readme":"![Docker-Lock-Banner](./docs/assets/readme-banner.png)\n# About\n![ci](https://github.com/safe-waters/docker-lock/workflows/ci/badge.svg)\n![cd-master](https://github.com/safe-waters/docker-lock/workflows/cd-master/badge.svg)\n![cd-tag](https://github.com/safe-waters/docker-lock/workflows/cd-tag/badge.svg)\n[![Go Report Card](https://goreportcard.com/badge/github.com/safe-waters/docker-lock)](https://goreportcard.com/report/github.com/safe-waters/docker-lock)\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/safe-waters/docker-lock)](https://pkg.go.dev/github.com/safe-waters/docker-lock)\n\n`docker-lock` is a cli tool that automates managing image digests by tracking\nthem in a separate Lockfile (think package-lock.json or Pipfile.lock). With\n`docker-lock`, you can refer to images in **Dockerfiles**,\n**docker-compose V3 files**, and **Kubernetes manifests** by\nmutable tags (as in `python:3.6`) yet receive the same \nbenefits as if you had specified immutable digests (as in `python:3.6@sha256:25a189a536ae4d7c77dd5d0929da73057b85555d6b6f8a66bfbcc1a7a7de094b`).\n\n\u003e Note: If you are unsure about the differences between tags and digests,\nrefer to this [quick summary](./docs/tutorials/tags-vs-digests.md).\n\n`docker-lock` ships with 3 commands that take you from development \nto production:\n\n* `docker lock generate` finds images in your `Dockerfiles`,\n`docker-compose` files, and `Kubernetes` manifests and generates\na Lockfile containing digests that correspond to their tags.\n* `docker lock verify` lets you know if there are more recent digests \nthan those last recorded in the Lockfile.\n* `docker lock rewrite` rewrites `Dockerfiles`, `docker-compose` files,\nand `Kubernetes` manifests to include digests.\n\n`docker-lock` is most commonly used as a\n[cli-plugin](https://github.com/docker/cli/issues/1534) for `docker` so `lock`\ncan be used as subcommand of `docker` as in `docker lock`. However,\n`docker-lock` does not require `docker` at all. Instead, it can be called\nmanually as a standalone executable as in `docker-lock lock`. \nThis is especially convenient if the proper version of `docker` is unavailable\nor you would prefer to use another container technology such as\n[podman](https://podman.io/).\n\n# Demo\nConsider a project with a multi-stage build `Dockerfile` at its root:\n```Dockerfile\nFROM ubuntu AS base\n# ...\nFROM mperel/log:v1\n# ...\nFROM python:3.6\n# ...\n```\nRunning `docker lock generate` from the root queries each images' \nregistry to produce a Lockfile, `docker-lock.json`.\n\n![Generate GIF](./docs/assets/generate.gif)\n\nNote that the Lockfile records image digests so you do not have to \nmanually specify them.\n\nRunning `docker lock verify` ensures that the image digests are the \nsame as those on the registry for the same tags.\n\n![Verify Success GIF](./docs/assets/verify_success.gif)\n\nNow, assume that a change to `mperel/log:v1` has been pushed to the registry.\n\nRunning `docker lock verify` shows that the image digest in the Lockfile \nis out-of-date because it differs from the newer image's digest on the registry.\n\n![Verify Fail GIF](./docs/assets/verify_fail.gif)\n\nWhile developing, it can be useful to generate a Lockfile, commit it to \nsource control, and verify it periodically (for instance on PR merges). In \nthis way, developers can be notified when images change, and if a bug related \nto a change in an image crops up, it will be easy to identify.\n\nFinally, lets assume the `Dockerfile` is ready to be built and shared.\n\nRunning `docker lock rewrite` will add digests from the Lockfile \nto all of the images.\n\n![Rewrite GIF](./docs/assets/rewrite.gif)\n\nAt this point, the `Dockerfile` will contain all of the digest information \nfrom the Lockfile, so it will always maintain the same, known behavior \nin the future.\n\n# Install\n`docker-lock` can be run as a\n* [cli-plugin](https://github.com/docker/cli/issues/1534) for `docker`\n* standalone executable without `docker`\n* prebuilt [image from Dockerhub](https://hub.docker.com/repository/docker/safewaters/docker-lock)\n\n## Cli-plugin\nEnsure `docker` cli version \u003e= 19.03 is installed by running `docker --version`.\n\n### Linux / Mac\n```bash\n$ mkdir -p \"${HOME}/.docker/cli-plugins\"\n$ curl -fsSL \"https://github.com/safe-waters/docker-lock/releases/download/v${VERSION}/docker-lock_${VERSION}_${OS}_${ARCH}.tar.gz\" | tar -xz -C \"${HOME}/.docker/cli-plugins\" \"docker-lock\"\n$ chmod +x \"${HOME}/.docker/cli-plugins/docker-lock\"\n```\n\n### Windows\n* Create the folder `%USERPROFILE%\\.docker\\cli-plugins`\n* Download the Windows release from the releases page.\n* Unzip the release.\n* Move `docker-lock.exe` into `%USERPROFILE%\\.docker\\cli-plugins`\n\n## Standalone tool\n* Follow the same instructions as in the\n[cli-plugin section](#cli-plugin) except place the `docker-lock` executable in\nyour `PATH`.\n* To use `docker-lock`, replace any `docker` command such as `docker lock` with\nthe name of the executable, `docker-lock`, as in `docker-lock lock`.\n* To verify that `docker-lock` was installed, run:\n```bash\n$ docker-lock lock --help\n```\n\n## Docker image\n`docker-lock` can be run in a `docker` container, as below. If you leave off\nthe `${VERSION}` tag, you will use the latest, nightly build from the master branch.\n\n\u003e Note: If your host machine uses a credential helper such as `osxkeychain`,\n\u003e `wincred`, or `pass`, the credentials will not be available to the container even\n\u003e if you pass in your `docker` config.\n\n### Linux / Mac\n* Without your `docker` config:\n```bash\n$ docker run -v \"${PWD}\":/run safewaters/docker-lock:${VERSION} [commands]\n```\n* With your `docker` config:\n```bash\n$ docker run -v \"${HOME}/.docker/config.json\":/.docker/config.json:ro -v \"${PWD}\":/run safewaters/docker-lock:${VERSION} [commands]\n```\n### Windows\n* Without your `docker` config:\n```bash\n$ docker run -v \"%cd%\":/run safewaters/docker-lock:${VERSION} [commands]\n```\n* With your `docker` config:\n```bash\n$ docker run -v \"%USERPROFILE%\\.docker\\config.json\":/.docker/config.json:ro -v \"%cd%\":/run safewaters/docker-lock:${VERSION} [commands]\n```\n\n### Available tags\n* By default, images are built from `scratch`. These images only contain\nthe `docker-lock` executable and are tagged as follows:\n    * `safewaters/docker-lock:${VERSION}`\n    * `safewaters/docker-lock`\n* If you need a shell alongside the executable (as is required by some CI/CD\nproviders such as Gitlab), images built from `alpine` are provided. They\nare tagged as follows:\n    * `safewaters/docker-lock:${VERSION}-alpine`\n    * `safewaters/docker-lock:alpine`\n\n# Use\n## Registries\n`docker-lock` supports public and private registries. If necessary, login to\ndocker before using `docker-lock`.\n\n## How to specify configuration options\n`docker-lock` supports options via cli flags or a configuration file,\n`.docker-lock.yml`.\nThe root of this repo has an example,\n[.docker-lock.yml.example](./.docker-lock.example.yml).\n\nTo see available options, run commands with `--help`. For instance:\n\n```bash\n$ docker lock --help\n$ docker lock generate --help\n$ docker lock verify --help\n$ docker lock rewrite --help\n$ docker lock version --help\n```\n\n\u003e Note: You can mix and match cli flags to get the output that you want.\n\n## Generate\n### Commands for Dockerfiles, docker-compose files, and Kubernetes manifests\n* `docker lock generate` will collect all default files (`Dockerfile`,\n`compose.yml`, `compose.yaml`, `docker-compose.yaml`, `docker-compose.yml`,\n`pod.yml`, `pod.yaml`, `deployment.yml`, `deployment.yaml`, `job.yml`,\nand `job.yaml` in the default base directory, the directory from which\nthe command is run) and generate a Lockfile.\n\n* `docker lock generate --lockfile-name=[file name]` will generate a Lockfile with the\nfile name as the output, instead of the default `docker-lock.json`.\n\n* `docker lock generate --update-existing-digests` will generate a Lockfile,\nquerying for all digests, even those that are hardcoded in the files. Normally,\nif a digest is hardcoded, it would be used in the Lockfile.\n\n* `docker lock generate --ignore-missing-digests` will generate a Lockfile,\nrecording images for which a digest could not be found as not having a digest.\nNormally, if a digest cannot be found, `docker-lock` would print an error.\n\n* `docker lock generate --base-dir=[sub directory]` will collect all default\nfiles in a sub directory and generate a Lockfile.\n\n### Commands for Dockerfiles\n* `docker lock generate --dockerfiles=[file1,file2,file3]` will collect all\nfiles from a comma separated list (\"file1,file2,file3\") as well as default\ndocker-compose files and Kubernetes manifests and generate a Lockfile.\n\n* `docker lock generate --exclude-all-dockerfiles` will generate a Lockfile,\nexcluding all Dockerfiles.\n\n* `docker lock generate --dockerfile-recursive` will collect all default\nDockerfiles (`Dockerfile`) in subdirectories from the base directory as well\nas default docker-compose files and Kubernetes manifests in the base directory\nand generate a Lockfile.\n\n* `docker lock generate --dockerfile-globs='[glob pattern]'` will collect all\nDockerfiles that match the glob pattern relative to the base directory as well\nas default docker-compose files and Kubernetes manifests in the base directory\nand generate a Lockfile. Use '**' to recursively search directories.\nRemember to quote using single quotes so that the glob is not expanded\nbefore `docker-lock` uses it.\n\n### Commands for docker-compose files\n* `docker lock generate --composefiles=[file1,file2,file3]` will collect all\nfiles from a comma separated list (\"file1,file2,file3\") as well as default\nDockerfiles files and Kubernetes manifests and generate a Lockfile.\n\n* `docker lock generate --exclude-all-composefiles` will generate a Lockfile,\nexcluding all docker-compose files.\n\n* `docker lock generate --composefile-recursive` will collect all default\ndocker-compose files (`compose.yml`, `compose.yaml`,\n`docker-compose.yaml`, `docker-compose.yml`) in subdirectories from the\nbase directory as well as default Dockerfiles and Kubernetes manifests in\nthe base directory and generate a Lockfile.\n\n* `docker lock generate --composefile-globs='[glob pattern]'` will collect all\ndocker-compose files that match the glob pattern relative to the base directory as well\nas default Dockerfiles and Kubernetes manifests in the base directory\nand generate a Lockfile. Use '**' to recursively search directories.\nRemember to quote using single quotes so that the glob is not expanded\nbefore `docker-lock` uses it.\n\n### Commands for Kubernetes manifests\n* `docker lock generate --kubernetesfiles=[file1,file2,file3]` will collect all\nfiles from a comma separated list (\"file1,file2,file3\") as well as default\nDockerfiles files and docker-compose files and generate a Lockfile.\n\n* `docker lock generate --exclude-all-kubernetesfiles` will generate a Lockfile,\nexcluding all Kubernetes manifests.\n\n* `docker lock generate --kubernetesfile-recursive` will collect all default\nKubernetes manifests (`pod.yaml`, `pod.yml`) in\nsubdirectories from the base directory as well as default Dockerfiles\nand docker-compose files in the base directory and generate a Lockfile.\n\n* `docker lock generate --kubernetesfile-globs='[glob pattern]'` will collect all\nKubernetes manifests that match the glob pattern relative to the base directory as well\nas default Dockerfiles and docker-compose files in the base directory\nand generate a Lockfile. Use '**' to recursively search directories.\nRemember to quote using single quotes so that the glob is not expanded\nbefore `docker-lock` uses it.\n\n## Verify\n* `docker lock verify` will take an existing Lockfile, with the default name,\n`docker-lock.json`, generate a new Lockfile and report differences between\nthe new and existing Lockfiles.\n\n* `docker lock verify --lockfile-name=[file name]` will use another file, instead\nof the default `docker-lock.json`, as the Lockfile.\n\n* `docker lock verify --exclude-tags` will check for differences between a newly\ngenerated Lockfile and the existing Lockfile, ignoring if tags are different.\n\n* `docker lock verify --ignore-missing-digests` will verify, but when generating\nthe new Lockfile to compare against, will assume that digests that cannot be\nfound are empty. Normally, if a digest could not be found, an error would be\nreported.\n\n* `docker lock verify --update-existing-digests` will verify, but when generating\nthe new Lockfile to compare against, will query for digests even if they are hardcoded.\nNormally, the new Lockfile would use the hardcoded digests, instead of querying\nfor the most recent one.\n\n## Rewrite\n* `docker lock rewrite` will write the image names, tags, and digests\nfrom the Lockfile into the referenced Dockerfiles, docker-compose files,\nand Kubernetes manifests.\n\n* `docker lock rewrite --lockfile-name=[file name]` will use another file, instead\nof the default `docker-lock.json`, as the Lockfile.\n\n* `docker lock rewrite --exclude-tags` will write image names and digests,\nbut not the tags, from the Lockfile into the referenced Dockerfiles,\ndocker-compose files, and Kubernetes manifests.\n\n* `docker lock rewrite --tempdir=[directory]` will create a temporary directory in the `[directory]` and\nwrite all files into it. Afterwards, the files are renamed to the appropriate\nlocation and the temporary directory is deleted. Normally, this occurs in the\ncurrent directory. In general, this 2 step process happens to ensure that\neither all rewrites succeed, or none of them do. There are also other rollback\nmeasures in `docker-lock` to ensure this transaction happens and you are not\nleft with some files rewritten if a failure occurs.\n\n# Suggested workflow\n* Locally run `docker lock generate` to create a Lockfile, `docker-lock.json`,\nand commit it.\n* Continue developing normally, as if the Lockfile does not exist.\n* When merging a code change/releasing, run `docker-lock` in a CI/CD\npipeline. Specifically:\n    * In the pipeline, run `docker lock verify` to make sure that the\n    Lockfile is up-to-date. If `docker lock verify` fails, the developer can\n    locally rerun `docker lock generate` to update the Lockfile. This has\n    the benefit that digest changes will be explicitly tracked in git.\n    * Once the `docker lock verify` step in the pipeline passes, the pipeline\n    should run `docker lock rewrite` so all files have correct digests\n    hardcoded in them.\n    * The pipeline should run tests that use the rewritten images.\n    * If the tests pass, merge the code change/push the images to\n    the registry, etc.\n\n# Contributing\n## Development environment\nA development container based on `ubuntu:bionic` has been provided,\nso ensure `docker` is installed and the `docker` daemon is running.\n\n* Open the project in [VSCode](https://code.visualstudio.com/).\n* Install VSCode's [Remote Development Extension - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack).\n* In the command palette (ctrl+shift+p on Windows/Linux,\ncommand+shift+p on Mac), type \"Reopen in Container\".\n* In the command palette type: \"Go: Install/Update Tools\" and select all.\n* When all tools are finished installing, in the command palette type:\n\"Developer: Reload Window\".\n* The `docker` daemon is mapped from the host into the dev container,\nso you can use `docker` and `docker-compose` commands from within the container\nas if they were run on the host.\n\n## Build from source\nTo build and install `docker-lock` in `docker`'s cli-plugins directory,\nfrom the root of the project, run:\n\n```bash\n$ make install\n```\n\n## Code quality and correctness\nTo clean, format, lint, install, generate a new Lockfile, and run unit tests:\n```bash\nmake\n```\n\nThe CI pipeline will additionally run integration tests on pull requests.\n\nYou can run any step individually.\n\n* To uninstall: `make clean`\n* To install into `docker`'s cli-plugins directory: `make install`\n* To generate a new Lockfile: `make lock`\n* To format Go code: `make format`\n* To lint all code: `make lint`\n* To run unit tests: `make unittest`\n\nTo view the coverage report after running unit tests, open `coverage.html` in\nyour browser.\n\n\u003eNote: While there exists a target in the Makefile for integration tests, these\ncannot run locally because they require credentials that are only available in\nthe CI pipeline.\n\n# Tutorials\n* [Tags Vs. Digests](./docs/tutorials/tags-vs-digests.md)\n","funding_links":[],"categories":["Container Operations","Go"],"sub_categories":["Security"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsafe-waters%2Fdocker-lock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsafe-waters%2Fdocker-lock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsafe-waters%2Fdocker-lock/lists"}