{"id":21698617,"url":"https://github.com/theohbrothers/generate-dockerimagevariants","last_synced_at":"2026-02-28T11:03:07.493Z","repository":{"id":46027325,"uuid":"180047067","full_name":"theohbrothers/Generate-DockerImageVariants","owner":"theohbrothers","description":"Easily generate a repository populated with Docker image variants. 🐳","archived":false,"fork":false,"pushed_at":"2025-02-13T11:22:11.000Z","size":244,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-03T19:50:25.330Z","etag":null,"topics":["continuous-deployment","continuous-integration","docker","docker-image","generate-dockerimagevariants","generator","module","powershell","pwsh","repository","template","template-engine","variants"],"latest_commit_sha":null,"homepage":"","language":"PowerShell","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/theohbrothers.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,"zenodo":null}},"created_at":"2019-04-08T01:29:52.000Z","updated_at":"2025-02-13T11:22:15.000Z","dependencies_parsed_at":"2024-06-16T18:35:56.586Z","dependency_job_id":"52aab8ea-3d42-4395-9121-2a8e1843b458","html_url":"https://github.com/theohbrothers/Generate-DockerImageVariants","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/theohbrothers/Generate-DockerImageVariants","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theohbrothers%2FGenerate-DockerImageVariants","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theohbrothers%2FGenerate-DockerImageVariants/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theohbrothers%2FGenerate-DockerImageVariants/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theohbrothers%2FGenerate-DockerImageVariants/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theohbrothers","download_url":"https://codeload.github.com/theohbrothers/Generate-DockerImageVariants/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theohbrothers%2FGenerate-DockerImageVariants/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266510687,"owners_count":23940696,"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","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"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":["continuous-deployment","continuous-integration","docker","docker-image","generate-dockerimagevariants","generator","module","powershell","pwsh","repository","template","template-engine","variants"],"created_at":"2024-11-25T19:35:33.251Z","updated_at":"2026-02-28T11:03:02.463Z","avatar_url":"https://github.com/theohbrothers.png","language":"PowerShell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Generate-DockerImageVariants\n\n[![github-actions](https://github.com/theohbrothers/Generate-DockerImageVariants/actions/workflows/ci-master-pr.yml/badge.svg?branch=master)](https://github.com/theohbrothers/Generate-DockerImageVariants/actions/workflows/ci-master-pr.yml)\n[![github-release](https://img.shields.io/github/v/release/theohbrothers/Generate-DockerImageVariants?style=flat-square)](https://github.com/theohbrothers/Generate-DockerImageVariants/releases/)\n[![powershell-gallery-release](https://img.shields.io/powershellgallery/v/Generate-DockerImageVariants?logo=powershell\u0026logoColor=white\u0026label=PSGallery\u0026labelColor=\u0026style=flat-square)](https://www.powershellgallery.com/packages/Generate-DockerImageVariants/)\n\nEasily generate a repository populated with Docker image variants.\n\n## Agenda\n\nIt is very common to need to have multiple variants of a docker image. This module solves this problem by creating a simple templating framework to generate a full repository:\n\n- `Dockerfile` build contexts for variants\n- `README.md` containing the variants' image tags\n- Optional: Continuous integration (CI) configuration files to build and push variants' images to a docker registry\n\nHere are some real repositories generated by using this module:\n\n- https://github.com/theohbrothers/docker-alpine\n- https://github.com/theohbrothers/docker-ansible\n- https://github.com/theohbrothers/docker-certbot-dns-cron\n- https://github.com/theohbrothers/docker-chrony\n- https://github.com/theohbrothers/docker-code-server\n- https://github.com/theohbrothers/docker-easyrsa\n- https://github.com/theohbrothers/docker-imap-backup\n- https://github.com/theohbrothers/docker-isync\n- https://github.com/theohbrothers/docker-kubectl\n- https://github.com/theohbrothers/docker-openvpn\n- https://github.com/theohbrothers/docker-packer\n- https://github.com/theohbrothers/docker-powershell\n- https://github.com/theohbrothers/docker-php\n- https://github.com/theohbrothers/docker-socat\n- https://github.com/theohbrothers/docker-terraform\n- https://github.com/theohbrothers/docker-varnish-agent\n- https://github.com/theohbrothers/docker-webhook\n\n## Install\n\nOpen [`powershell`](https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/install/installing-windows-powershell?view=powershell-5.1) or [`pwsh`](https://github.com/powershell/powershell#-powershell) and type:\n\n```powershell\nInstall-Module -Name Generate-DockerImageVariants -Repository PSGallery -Scope CurrentUser -Verbose\n```\n\nIf prompted to trust the repository, hit `Y` and `enter`.\n\n## Usage\n\n1. Initialize your repository\n\n    ```sh\n    mkdir -p /path/to/my-project\n    cd /path/to/my-project\n    ```\n\n1. Initialize the `./generate` folder\n\n    ```powershell\n    Import-Module Generate-DockerImageVariants\n    Generate-DockerImageVariants . -Init\n    ```\n\n   Definition and template files are generated in the `./generate` folder.\n\n    ```sh\n    ├── generate\n    │   ├── definitions\n    │   │   ├── FILES.ps1\n    │   │   └── VARIANTS.ps1\n    │   ├── functions\n    │   │   └── Download-Binary.ps1\n    │   └── templates\n    │       ├── Dockerfile.ps1\n    │       └── README.md.ps1\n    ```\n\n1. Edit the definitions and template files in `./generate` (as needed)\n\n1. Generate the variants:\n\n    ```powershell\n    Generate-DockerImageVariants .\n    ```\n\n   Build contexts of variants are generated in `./variants`.\n\n   The repository tree now looks like:\n\n    ```sh\n    ├── README.md\n    ├── generate\n    │   ├── definitions\n    │   │   ├── FILES.ps1\n    │   │   └── VARIANTS.ps1\n    │   ├── functions\n    │   │   └── Download-Binary.ps1\n    │   └── templates\n    │       ├── Dockerfile.ps1\n    │       └── README.md.ps1\n    └── variants\n        └── curl\n            └── Dockerfile\n    ```\n\n## Directory structure\n\nA single folder named `./generate` at the base of the repository will hold all the definition and template files:\n\n```sh\n├── generate\n│   ├── definitions             # Definitions folder\n│   │   ├── FILES.ps1           # An optional definition file for generation of repository files\n│   │   └── VARIANTS.ps1        # Variant definition file for generation of variant build context\n│   ├── functions               # Functions folder (optional). Useful for Dockerfile templating\n│   │   └── Some-Function.ps1   # A function to use in your templates\n│   │   └── Another-Function.ps1   # A function to use in your templates\n│   └── templates               # Templates folder\n│       ├── Dockerfile.ps1      # Dockerfile template (shared among variants across all distros)\n│       └── README.md.ps1       # README.md template\n```\n\n## Generation of a variant\n\nAt minimum, the `./generate/definitions/VARIANTS.ps1` definition file should contain the `$VARIANTS` definition like this:\n\n```powershell\n$VARIANTS = @(\n    @{\n        tag = 'sometag'\n        buildContextFiles = @{\n            templates = @{\n                'Dockerfile' = @{\n                    common = $true\n                    passes = @(\n                        @{\n                            variables = @{}\n                        }\n                    )\n                }\n            }\n        }\n    }\n)\n```\n\nThe `FILES.ps1` definition file is optional, but if used, at minimum it should look like:\n\n```powershell\n$FILES = @(\n    # Paths are relative to the base of the project\n    'README.md'\n)\n```\n\nUpon generation, the `sometag` variant's build context is generated in `./variants/sometag` with a file `Dockerfile`, as well as a file `./README.md`, both relative to the base of the project.\n\n```sh\n├── README.md\n└── variants\n|   └── sometag\n|       └── Dockerfile\n```\n\nSee [this](docs/examples/basic) basic example.\n\n## Using custom functions\n\nTo add a custom function, add a `.ps1` file in the `./generate/functions`. They will be dot-sourced and available in your templates. For instance, to add two functions `Some-Function` and `Another-Function`:\n\n```sh\n├── generate\n│   ├── functions               # Functions is optional. Useful for Dockerfile templating\n│   │   └── Some-Function.ps1   # A function to use in your templates\n│   │   └── Another-Function.ps1   # A function to use in your templates\n```\n\nThen simply call them in your templates.\n\nSee [this](docs/examples/basic-functions) basic example with function called `Download-Binary` and `Download-Binary2`.\n\n## Generation of multiple variants\n\nSuppose we want to generate two variants tagged `curl` and `git`:\n\n```powershell\n$VARIANTS = @(\n    @{\n        tag = 'curl'\n    }\n    @{\n        tag = 'git'\n    }\n)\n\n# This is a optional variable that sets a common buildContextFiles for all variants\n# Individual variant buildContextsFiles overrides this\n$VARIANTS_SHARED = @{\n    buildContextFiles = @{\n        templates = @{\n            'Dockerfile' = @{\n                common = $true\n                passes = @(\n                    @{\n                        variables = @{}\n                    }\n                )\n            }\n        }\n    }\n}\n```\n\nUpon generation, the `curl` and `git` variants' build contexts are generated:\n\n```sh\n└── variants\n|   └── curl\n|       └── Dockerfile\n|   └── git\n|       └── Dockerfile\n```\n\nSee [this](docs/examples/basic-multiple-variants) example.\n\n## Generation of a variant through file copying\n\nPopulating a build context might not always involve processing templates. Sometimes we simply want to copy a file into the build context.\n\nTo copy a file, simply use the property `copies` in `buildContextFiles`:\n\n```powershell\n$VARIANTS = @(\n    @{\n        tag = 'curl'\n        buildContextFiles = @{\n            copies = @(\n                '/app'\n            )\n        }\n    }\n)\n```\n\nThis will recursively copy all descending files/folders of the `./app` folder located relative to the *base* of the parent repository into the to-be-generated `curl` variant's build directory `./variants/curl` as `./variants/curl/app`.\n\nSee [this](docs/examples/basic-copies) example.\n\n## Generation of a variant through multiple template passes\n\n```powershell\n$VARIANTS = @(\n    @{\n        tag = 'curl'\n        buildContextFiles = @{\n            templates = @{\n                'Dockerfile' = @{\n                    common = $false\n                    passes = @(\n                        # The first pass will generate 'Dockerfile'\n                        @{\n                            variables = @{\n                                'foo' = 'bar'\n                            }\n                        }\n                        # The second pass will generate 'Dockerfile.dev'\n                        @{\n                            variables = @{\n                                'foo2' = 'bar2'\n                            }\n                            generatedFileNameOverride = 'Dockerfile.dev'\n                        }\n                    )\n                }\n            }\n        }\n    }\n)\n```\n\nDuring generation, in addition to the `$VARIANT` object, a `$PASS_VARIABLES` hashtable will be in the scope of the processed `Dockerfile.ps1` template. In the first pass, the value of `$PASS_VARIABLES['foo']` will be `bar`, and the file `Dockerfile` will be generated in the variant's build context. In the second pass, the value of `$PASS_VARIABLES['foo2']` will be `bar2`, and the file `Dockerfile.dev` will be generated in the same build context.\n\nSee [this](docs/examples/basic-variables) example for using multiple passes with variables.\n\n## Generation of a single variant's build context file(s) using Component-chaining\n\nWhen a variant's `tag` contains words delimited by `-`, it is known as **Component-chaining**. The final generated file will be a concatanation of the product of processing the template of each component specified in this chain.\n\nFor instance, suppose you want a variant `Dockerfile` that installs `curl` and `git`:\n\n```powershell\n$VARIANTS = @(\n    @{\n        tag = 'curl-git'\n        buildContextFiles = @{\n            templates = @{\n                'Dockerfile' = @{\n                    common = $true\n                    passes = @(\n                        @{\n                            variables = @{}\n                        }\n                    )\n                }\n            }\n        }\n    }\n)\n```\n\nThe template pass to generate the variant's build context `Dockerfile` proceeds as such:\n\n1. The template `./generate/templates/Dockerfile.ps1` is processed\n1. The build context: `./variants/curl-git` is generated with the file `./variants/curl-git/Dockerfile`\n\nSee [this](docs/examples/basic-component-chaining) example.\n\n## Generation of multiple variants' build context file(s) using Component-chaining\n\n```powershell\n$VARIANTS = @(\n    @{\n        tag = 'curl-git'\n    }\n    @{\n        tag = 'curl'\n    }\n    @{\n        tag = 'git'\n    }\n)\n\n# This is a special optional variable that sets a common buildContextFiles definition for all variants\n$VARIANTS_SHARED = @{\n    buildContextFiles = @{\n        templates = @{\n            'Dockerfile' = @{\n                common = $false\n                passes = @(\n                    @{\n                        variables = @{}\n                    }\n                )\n            }\n        }\n    }\n}\n```\n\nUpon generation, **three** variants build contexts for variants `curl-git`, `curl`, and `git` are generated:\n\n```sh\n└── variants\n|   └── curl-git\n|       └── Dockerfile\n|   └── curl\n|       └── Dockerfile\n|   └── git\n|       └── Dockerfile\n```\n\nSee [this](docs/examples/basic-component-chaining) example.\n\nTo specify that only certain components be processed, independent of the `tag` property, ensure to define the `components` property. See these examples:\n\n- [`/docs/examples/basic-custom-components`](docs/examples/basic-custom-components) example.\n- [`/docs/examples/basic-custom-components-distro`](docs/examples/basic-custom-components-distro) example.\n\nNote if using [`distro`](#appendix):\n\n\u003e If [`distro`](#appendix) is non-empty, and if the variant's `tag` consist of a word that matches the variant's `distro`, `distro` will not be among the `components`.** For instance, in the above example, if the `tag` is `curl-git-alpine` and the distro is `alpine`, there will still only be two components `curl` and `git`. `alpine` will not be considered a component.\n\n## Optional: Generate other repository files\n\nTo generate files other than variant build contexts in `./variants`, define them in `FILES.ps1`.\n\nSuppose we want to generate `README.md`:\n\n```powershell\n$FILES = @(\n    'README.md'\n)\n```\n\nThen, create their templates in the `./generate/templates` directory:\n\n```sh\n├── generate\n│   └── templates\n│       └── README.md.ps1       # README.md template\n```\n\nUpon generation, `README.md` is now generated:\n\n```sh\n└── README.md\n```\n\nThe variables `$VARIANTS` will be available during the processing of the template files.\n\nSee [this](docs/examples/basic-copies) example.\n\n## Appendix\n\n### Variant object properties\n\nA `$VARIANT` definition will contain these properties.\n\nThe `buildContextFiles` property of the `$VARIANT` object can be used to customize the template processing:\n\n- `common` - (Optional, defaults to `$false`) Specifies whether this file is shared by all distros. If value is `$true`, template has to be present in `./generate/templates/\u003cfile\u003e.ps1`. If value is `$false`, and if a variant `distro` is defined, template has to be present in `./generate/templates/\u003cfile\u003e/\u003cdistro\u003e/`, or if a variant `distro` is omitted, template has to be present in `./generate/templates/\u003cfile\u003e/\u003cfile\u003e.ps1`.\n- `includeHeader` - (Optional, defaults to `$false`) Specifies to process a template `\u003cfile\u003e.header.ps1`. Template path determined by `common`\n- `includeFooter` - (Optional, defaults to `$false`) Specifies to process a template `\u003cfile\u003e.footer.ps1`. Template path determined by `common`\n- `passes` - (Mandatory) An array of pass definitions that the template will undergo. Each pass will generate a single file.\n\nEach template pass processes a template file `\u003cfile\u003e.ps1` template and generates a single file named `\u003cfile\u003e` in the variant's build context.\n\nA pass can be configured with the `variables` and `generatedFileNameOverride` properties.\n\n```powershell\n$VARIANT = @{\n    # Specifies the docker image tag\n    # When the tag contains words delimited by '-', it known as component-chaining.\n    tag = 'some-cool-tag'\n\n    # Specifies a distro (optional). If you dont define a distro, templates will be sourced from ./generate/templates/\u003cfile\u003e folder\n    # In contrast, if a distro is specified, templates will be sourced from ./generate/templates/\u003cfile\u003e/\u003cdistro\u003e folder\n    distro = 'somedistro'\n\n    # Specifies that this variant should be tagged ':latest'. This property will be useful in generation of content in README.md or ci files. Automatically populated as $false if unspecified\n    tag_as_latest = $false\n\n    # Automatically populated\n    tag_without_distro = 'somecomponent1-somecomponent2'\n\n    # Specifies an list of components, independent of the `tag` property\n    # If unspecified, this is automatically populated based on the components in the tag\n    # If specified, the components override those specified in the tag\n    components = @(\n        'somecomponent1'\n        'somecomponent2'\n    )\n\n    # Automatically populated\n    build_dir_rel = './variants/distro/\u003ctag_without_distro\u003e'\n\n    # Automatically populated\n    build_dir = '/full/path/to/variants/distro/\u003ctag_without_distro\u003e'\n\n    # Build context template definition\n    buildContextFiles = @{\n        templates = @{\n            'Dockerfile' = @{\n                # Specifies whether the template is common (shared) across distros\n                common = $false\n\n                # Specifies whether the template \u003cfile\u003e.header.ps1 will be processed. Useful for Dockerfiles\n                includeHeader = $true\n\n                # Specifies whether the template \u003cfile\u003e.footer.ps1 will be processed. Useful for Dockerfiles\n                includeFooter = $true\n\n                # Specifies a list of passes the template will be undergo, where each pass generates a file\n                passes = @(\n                    # This first pass generates the file called 'Dockerfile'\n                    @{\n                        # These variables will be available in $PASS_VARIABLES hashtable when this template is processed\n                        variables = @{\n                            foo = 'bar'\n                        }\n\n                        # If this is uncommented, the pass will generate the file named 'Dockerfile.dev' instead\n                        # generatedFileNameOverride = 'Dockerfile.dev'\n                    }\n                )\n            }\n        }\n        # Specifies the paths, relative to the root of the repository, to recursively copy into each variant's build context\n        copies = @(\n            '/app'\n        )\n    }\n}\n```\n\n### Debugging\n\nUse the `-Verbose` switch. This gives a detail trace of:\n\n- Validation of `$VARIANTS` definition\n- Validation of `$FILES` definition\n- Template files or to-be-copied repository files for the build context generation\n- Template files for repository files generation\n\nThis is particularly useful when the module is throwing errors about definitions, or about missing template or to-be-copied files.\n\n#### Validation of `$VARIANTS` and `$FILES` definitions\n\nFor instance, if a variant was defined with an incorrect type (expected to be `hashtable`):\n\n```powershell\n$VARIANTS = @(\n    1\n    @{\n        tag = 'curl'\n        distro = 'alpine'\n    }\n)\n```\n\nExample of a validation trace:\n\n```powershell\nPS \u003e cd /path/to/my-repo\nPS \u003e Generate-DockerImageVariants . -Verbose\nVERBOSE: Validating $VARIANTS definition\nVERBOSE: Validating TargetObject '1 System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable' of type 'Object[]' and basetype 'array'       against Prototype 'System.Collections.Hashtable' of type 'Object[]' and basetype 'array'\nVERBOSE:        Validating TargetObject '1' of type 'Int32' and basetype 'System.ValueType'             against Prototype 'System.Collections.Hashtable' of type 'Hashtable' and basetype 'System.Object'\nWARNING: Failed with errors. Exception: Type System.Int32 is invalid! It should be of type 'System.Collections.Hashtable'.\n```\n\nThis demonstrates that a variant definition has to be of type `hashtable`. The value `1` is of type `int32`, and hence is invalid.\n\n#### Validation of template files or to-be-copied files\n\nExample of a validation trace:\n\n```powershell\nPS \u003e cd /path/to/my-repo\nPS \u003e Generate-DockerImageVariants . -Init\nPS \u003e Generate-DockerImageVariants . -Verbose\nVERBOSE: Validating $VARIANTS definition\n...\nVERBOSE: Validating $FILES definition\n...\nGenerating build context of variant 'curl': /path/to/my-repo/variants/curl\nVERBOSE: Generating build context file: /path/to/my-repo/variants/curl/Dockerfile\nVERBOSE: Processing template file: /path/to/my-repo/generate/templates/Dockerfile.ps1\nGenerating build context of variant 'curl-git': /path/to/my-repo/variants/curl-git\nVERBOSE: Generating build context file: /path/to/my-repo/variants/curl-git/Dockerfile\nVERBOSE: Processing template file: /path/to/my-repo/generate/templates/Dockerfile.ps1\nGenerating build context of variant 'my-cool-variant': /path/to/my-repo/variants/my-cool-variant\nVERBOSE: Generating build context file: /path/to/my-repo/variants/my-cool-variant/Dockerfile\nVERBOSE: Processing template file: /path/to/my-repo/generate/templates/Dockerfile.ps1\nGenerating repository file: /path/to/my-repo/README.md\nVERBOSE: Processing template file: /path/to/my-repo/generate/templates/README.md.ps1\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheohbrothers%2Fgenerate-dockerimagevariants","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheohbrothers%2Fgenerate-dockerimagevariants","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheohbrothers%2Fgenerate-dockerimagevariants/lists"}