├── Dockerfile ├── LICENSE ├── README.md ├── action.yml └── entrypoint.sh /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker:20-dind 2 | 3 | COPY entrypoint.sh /entrypoint.sh 4 | 5 | ENTRYPOINT ["/entrypoint.sh"] 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Pavel Alimpiev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action to build and publish Docker Images to GitHub Container registry 2 | 3 | ## Usage examples: 4 | 5 | ### Build and publish Docker Image with the `head` tag for the `develop` branch 6 | 7 | #### Complete workflow example 8 | ```yaml 9 | name: Build and publish 10 | 11 | on: 12 | push: 13 | branches: 14 | - "develop" # Running this workflow only for develop branch 15 | 16 | jobs: 17 | build-and-publish-head: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v2.5.0 # Checking out the repo 22 | 23 | - name: Build and publish "head" Docker image 24 | uses: VaultVulp/gp-docker-action@1.6.0 25 | with: 26 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 27 | image-name: my-cool-service # Provide Docker image name 28 | image-tag: head # Provide Docker image tag 29 | ``` 30 | 31 | ### Build and publish Docker Image with a `latest` tag for the `master` branch with different dockerfile 32 | 33 | #### Complete workflow example 34 | ```yaml 35 | name: Build and publish 36 | 37 | on: 38 | push: 39 | branches: 40 | - "master" # Running this workflow only for master branch 41 | 42 | jobs: 43 | build-and-publish-latest: 44 | runs-on: ubuntu-latest 45 | 46 | steps: 47 | - uses: actions/checkout@v2.5.0 # Checking out the repo 48 | 49 | - name: Build and publish "latest" Docker image 50 | uses: VaultVulp/gp-docker-action@1.6.0 51 | with: 52 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 53 | image-name: my-cool-service # Provide only Docker image name, tag will be automatically set to latest 54 | dockerfile: Alternative.Dockerfile # Provide custom Dockerfile name 55 | ``` 56 | 57 | ### Build and publish Docker Image with a tag equal to a git tag 58 | 59 | #### Complete workflow example 60 | ```yaml 61 | name: Build and publish 62 | 63 | on: 64 | push: 65 | tags: 66 | - "*" # Running this workflow for any tag 67 | 68 | jobs: 69 | build-and-publish-tag: 70 | runs-on: ubuntu-latest 71 | 72 | steps: 73 | - uses: actions/checkout@v2.5.0 # Checking out the repo 74 | 75 | - name: Build and publish Docker image tagged according to a git-tag 76 | uses: VaultVulp/gp-docker-action@1.6.0 77 | with: 78 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 79 | image-name: my-cool-service # Provide only Docker image name 80 | extract-git-tag: true # Provide flag to extract Docker image tag from git reference 81 | ``` 82 | 83 | ### Build and publish Docker Image with a different build context 84 | 85 | #### Complete workflow example 86 | ```yaml 87 | name: Build and publish 88 | 89 | on: push 90 | 91 | jobs: 92 | build-and-publish-context: 93 | runs-on: ubuntu-latest 94 | 95 | steps: 96 | - uses: actions/checkout@v2.5.0 # Checking out the repo 97 | 98 | - name: Build and publish Docker image from a different context 99 | uses: VaultVulp/gp-docker-action@1.6.0 100 | with: 101 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 102 | image-name: my-cool-service # Provide Docker image name 103 | build-context: ./dev # Provide path to the folder with a Dockerfile 104 | ``` 105 | 106 | ### Pulling an image before building it 107 | 108 | #### Complete workflow example 109 | ```yaml 110 | name: Build and publish 111 | 112 | on: push 113 | 114 | jobs: 115 | pull-and-build-and-publish: 116 | runs-on: ubuntu-latest 117 | 118 | steps: 119 | - uses: actions/checkout@v2.5.0 # Checking out the repo 120 | 121 | - name: Pull, build and publish Docker image 122 | uses: VaultVulp/gp-docker-action@1.6.0 123 | with: 124 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 125 | image-name: my-cool-service # Provide Docker image name 126 | pull-image: true # Provide the flag to pull image 127 | ``` 128 | 129 | ### Passing additional image tags 130 | 131 | **NB**, `additional-image-tags` will **not** replace `image-tag` argument - additional tags will be appended to the list. If no `image-tag` was specified, then image will be tagged with the `latest` tag. 132 | 133 | #### Examples 134 | 135 | ##### `image-tag` was specified: 136 | ```yaml 137 | image-name: my-cool-service 138 | image-tags: first 139 | additional-image-tags: second third 140 | ``` 141 | Action will produce one image with three tags: 142 | - `my-cool-service:first` 143 | - `my-cool-service:second` 144 | - `my-cool-service:third` 145 | 146 | ##### No `image-tag` was specified: 147 | 148 | In this case action will use the default `latest` tag. 149 | 150 | ```yaml 151 | image-name: my-cool-service 152 | additional-image-tags: second third 153 | ``` 154 | Action will produce one image with three tags: 155 | - `my-cool-service:latest` 156 | - `my-cool-service:second` 157 | - `my-cool-service:third` 158 | 159 | #### Complete workflow example 160 | ```yaml 161 | name: Build and publish 162 | 163 | on: push 164 | 165 | jobs: 166 | build-with-multiple-tags: 167 | runs-on: ubuntu-latest 168 | 169 | steps: 170 | - uses: actions/checkout@v2.5.0 # Checking out the repo 171 | 172 | - name: Build and publish Docker image with multiple tags 173 | uses: VaultVulp/gp-docker-action@1.6.0 174 | with: 175 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 176 | image-name: my-cool-service # Provide Docker image name 177 | image-tags: first # if ommitted will be replaced with "latest" 178 | additional-image-tags: second third # two additional tags for an image 179 | ``` 180 | 181 | ### Cross-platform builds 182 | 183 | It's possible to leverage `custom-args` to build images for different architectures. 184 | 185 | #### Examples 186 | ##### One architeture 187 | ```yaml 188 | custom-args: --platform=linux/arm64 # target architecture 189 | ``` 190 | ##### Multiple architetures 191 | ```yaml 192 | custom-args: --platform=linux/arm64,linux/amd64 # multiple target architectures 193 | ``` 194 | 195 | #### Complete workflow example 196 | ```yaml 197 | name: Build and publish 198 | 199 | on: push 200 | 201 | jobs: 202 | cross-platform-builds: 203 | runs-on: ubuntu-latest 204 | 205 | steps: 206 | - uses: actions/checkout@v2.5.0 # Checking out the repo 207 | 208 | - name: Build and publish Docker image for ARM64 and AMD64 architectures at the same time 209 | uses: VaultVulp/gp-docker-action@1.6.0 210 | with: 211 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 212 | image-name: my-cool-service # Provide Docker image name 213 | custom-args: --platform=linux/arm64,linux/amd64 # specify target architectures via the `custom-args` agrument 214 | ``` 215 | 216 | ### Passing additional arguments to the docker build command 217 | 218 | **NB**, additional arguments should be passed with the `=` sign istead of a ` `(space) between argument name and values. 219 | 220 | Correct example: 221 | ```yaml 222 | custom-args: --build-arg=some="value" 223 | # ^ this "=" is mandatory 224 | ``` 225 | Incorrect example: 226 | ```yaml 227 | custom-args: --build-arg some="value" 228 | # ^ this space might break the action 229 | ``` 230 | 231 | #### Complete workflow example 232 | ```yaml 233 | name: Build and publish 234 | 235 | on: push 236 | 237 | jobs: 238 | build-with-custom-args: 239 | runs-on: ubuntu-latest 240 | 241 | steps: 242 | - uses: actions/checkout@v2.5.0 # Checking out the repo 243 | 244 | - name: Build and publish Docker image with arbitrary --build-arg(s) 245 | uses: VaultVulp/gp-docker-action@1.6.0 246 | with: 247 | github-token: ${{ secrets.GITHUB_TOKEN }} # Provide GITHUB_TOKEN to login into the GitHub Packages 248 | image-name: my-cool-service # Provide Docker image name 249 | custom-args: --build-arg=some="value" --build-arg=some_other="value" # Pass some additional arguments to the docker build command 250 | ``` 251 | 252 | ## My own repo with examples 253 | 254 | [VaultVulp/test-gp-docker-action](https://github.com/VaultVulp/test-gp-docker-action) 255 | 256 | ## Security considerations 257 | 258 | You will encounter the following log message in your GitHub Actions Pipelines: 259 | 260 | ``` 261 | WARNING! Using --password via the CLI is insecure. Use --password-stdin. 262 | WARNING! Your password will be stored unencrypted in /github/home/.docker/config.json. 263 | Login Succeeded 264 | ``` 265 | 266 | I would like to ensure you, that I do not store your secrets, passwords, token, or any other information. 267 | 268 | This warning informs you about the fact, that this Action passes your GitHub token via the command line argument: 269 | ```bash 270 | docker login -u publisher -p ${DOCKER_TOKEN} ghcr.io 271 | ``` 272 | 273 | In a non-safe environment, this could raise a security issue, but this is not the case. We are passing a temporary authorization token, which will expire once the pipeline is completed. It would also require additional code to extract this token from the environment or `docker` internals, that this Action does not have. 274 | 275 | [This](https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#upgrading-a-workflow-that-accesses-a-registry-using-a-personal-access-token 276 | ) is the detailed explanation about the `${{ secrets.GITHUB_TOKEN }}` and it's relations with the GCR. 277 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Build and publish Docker Images to GitHub Container registry' 2 | description: 'Supports custom Dockerfile name, tags, build context, etc. Could generate Docker tags based on git branches.' 3 | inputs: 4 | github-token: 5 | description: 'GitHub token to push Docker image to GitHub Packages' 6 | required: true 7 | image-name: 8 | description: 'Docker Image name' 9 | required: true 10 | image-tag: 11 | description: 'Docker Image tag' 12 | default: "latest" 13 | required: false 14 | extract-git-tag: 15 | description: 'Extract git-tag from repository' 16 | default: "false" 17 | required: false 18 | dockerfile: 19 | description: 'Dockerfile name' 20 | default: "Dockerfile" 21 | required: false 22 | build-context: 23 | description: 'Path to build context' 24 | default: "." 25 | required: false 26 | pull-image: 27 | description: 'Pull the image before buiding it' 28 | default: "false" 29 | required: false 30 | additional-image-tags: 31 | description: 'Multiple tags that will be attached to a built image' 32 | default: "" 33 | required: false 34 | image-platform: 35 | description: 'Target image platform/platforms' 36 | default: "" 37 | required: false 38 | custom-args: 39 | description: 'Any additional docker build arguments as a string' 40 | default: "" 41 | required: false 42 | runs: 43 | using: 'docker' 44 | image: 'Dockerfile' 45 | args: 46 | - ${{ inputs.github-token }} 47 | - ${{ inputs.image-name }} 48 | - ${{ inputs.image-tag }} 49 | - ${{ inputs.extract-git-tag }} 50 | - ${{ inputs.dockerfile }} 51 | - ${{ inputs.build-context}} 52 | - ${{ inputs.pull-image}} 53 | - ${{ inputs.additional-image-tags}} 54 | - ${{ inputs.image-platform}} 55 | - ${{ inputs.custom-args}} 56 | branding: 57 | icon: 'box' 58 | color: 'blue' 59 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | DOCKER_TOKEN=$1 4 | DOCKER_IMAGE_NAME=$2 5 | DOCKER_IMAGE_TAG=$3 6 | EXTRACT_TAG_FROM_GIT_REF=$4 7 | DOCKERFILE=$5 8 | BUILD_CONTEXT=$6 9 | PULL_IMAGE=$7 10 | DOCKER_IMAGE_TAGS=$8 11 | DOCKER_IMAGE_PLATFORM=$9 12 | CUSTOM_DOCKER_BUILD_ARGS=${10} 13 | 14 | if [ "$(echo ${EXTRACT_TAG_FROM_GIT_REF})" == 'true' ]; then 15 | DOCKER_IMAGE_TAG=$(echo ${GITHUB_REF} | sed -e "s/refs\/tags\///g") 16 | fi 17 | 18 | DOCKER_IMAGE_NAME=$(echo ghcr.io/${GITHUB_REPOSITORY}/${DOCKER_IMAGE_NAME} | tr '[:upper:]' '[:lower:]') 19 | DOCKER_IMAGE_NAME_WITH_TAG=$(echo ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} | tr '[:upper:]' '[:lower:]') 20 | 21 | docker buildx create --use # Creating builder instance to support cross-platform builds 22 | 23 | docker login -u publisher -p ${DOCKER_TOKEN} ghcr.io 24 | 25 | if [ "$(echo ${PULL_IMAGE})" == 'true' ]; then 26 | if [ "$(echo ${DOCKER_IMAGE_PLATFORM})" != '' ]; then 27 | docker pull ${DOCKER_IMAGE_NAME_WITH_TAG} --platform ${DOCKER_IMAGE_PLATFORM} || docker pull ${DOCKER_IMAGE_NAME} --platform ${DOCKER_IMAGE_PLATFORM} || true 28 | else 29 | docker pull ${DOCKER_IMAGE_NAME_WITH_TAG} || docker pull ${DOCKER_IMAGE_NAME} || true 30 | fi 31 | fi 32 | 33 | set -- -t ${DOCKER_IMAGE_NAME_WITH_TAG} 34 | 35 | if [ "$(echo ${DOCKERFILE})" != 'Dockerfile' ]; then 36 | set -- $(echo ${@}) -f ${DOCKERFILE} 37 | fi 38 | 39 | if [ "$(echo ${DOCKER_IMAGE_PLATFORM})" != '' ]; then 40 | set -- $(echo ${@}) --platform ${DOCKER_IMAGE_PLATFORM} 41 | fi 42 | 43 | if [ "$(echo ${CUSTOM_DOCKER_BUILD_ARGS})" != '' ]; then 44 | set -- ${@} ${CUSTOM_DOCKER_BUILD_ARGS} 45 | fi 46 | 47 | set -- ${@} ${BUILD_CONTEXT} 48 | 49 | for tag in ${DOCKER_IMAGE_TAGS} 50 | do 51 | DOCKER_IMAGE_NAME_WITH_TAG=$(echo ${DOCKER_IMAGE_NAME}:${tag} | tr '[:upper:]' '[:lower:]') 52 | set -- -t ${DOCKER_IMAGE_NAME_WITH_TAG} ${@} 53 | done 54 | 55 | docker buildx build --push ${@} 56 | --------------------------------------------------------------------------------