This commit is contained in:
Vadim 2025-05-17 18:16:46 +00:00
commit 0d81bb5791
5 changed files with 516 additions and 0 deletions

32
Dockerfile Normal file
View File

@ -0,0 +1,32 @@
FROM gcr.io/kaniko-project/executor:v1.23.0-debug
SHELL ["/busybox/sh", "-c"]
# Download crane
RUN set -eux; \
case "$(arch)" in \
'x86_64') \
url='https://github.com/google/go-containerregistry/releases/download/v0.19.1/go-containerregistry_Linux_x86_64.tar.gz'; \
sha256='5f2b43c32a901adaaabaa78755d56cea71183954de7547cb4c4bc64b9ac6b2ff'; \
;; \
'aarch64') \
url='https://github.com/google/go-containerregistry/releases/download/v0.19.1/go-containerregistry_Linux_arm64.tar.gz'; \
sha256='9118c29cdf2197441c4a934cf517df76c021ba12a70edc14ee9dc4dc08226680'; \
;; \
*) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \
esac; \
\
cd /workspace; \
wget -O crane.tar.gz "$url"; \
echo "$sha256 crane.tar.gz" | sha256sum -c -; \
tar -xzf crane.tar.gz; \
mv crane /kaniko; \
rm *; \
mkdir /kaniko/build;
COPY entrypoint.sh /kaniko/entrypoint.sh
ENTRYPOINT ["/kaniko/entrypoint.sh"]
LABEL repository="https://code.thetadev.de/ThetaDev/action-kaniko" \
maintainer="ThetaDev <thetadev@magenta.de>"

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) 2024 ThetaDev
MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

233
README.md Normal file
View File

@ -0,0 +1,233 @@
# Kaniko image builder
Gitea/Github action for building docker images using Kaniko. Kaniko is an image builder
that runs the build steps on the host system without a container runtime. Therefore it
runs without issues in an unprivileged container.
The action script supports building containers for multiple architectures. This requires
the installation of `qemu-user-static` on the runner machine.
This project is based on [action-kaniko](https://github.com/aevea/action-kaniko) by Alex
Viscreanu.
## Usage
```yaml
steps:
- name: Build docker image
uses: https://code.thetadev.de/actions/kaniko@v1
with:
image: thetadev256/test-actions-helloworld2
username: thetadev256
password: ${{ secrets.DOCKER_TOKEN }}
platforms: "linux/amd64,linux/arm64"
```
## Required Arguments
This action aims to be as flexible as possible, so it tries to define the defaults as
for what I thought of being the most used values. So, technically there is a single
required argument
| variable | description | required | default |
| -------- | ---------------------------------------- | -------- | ------- |
| image | Name of the image you would like to push | true | |
## Optional Arguments
| variable | description | required | default |
| ---------------- | -------------------------------------------------------- | -------- | ------------- |
| registry | Docker registry where the image will be pushed | false | docker.io |
| username | Username used for authentication to the Docker registry | false | $GITHUB_ACTOR |
| password | Password used for authentication to the Docker registry | false | |
| tag | Image tag | false | latest |
| cache | Enables build cache | false | false |
| cache_ttl | How long the cache should be considered valid | false | |
| cache_registry | Docker registry meant to be used as cache | false | |
| cache_directory | Filesystem path meant to be used as cache | false | |
| build_file | Dockerfile filename | false | Dockerfile |
| extra_args | Additional arguments to be passed to the kaniko executor | false | |
| strip_tag_prefix | Prefix to be stripped from the tag | false | |
| platforms | Target platforms to build (separated by comma) | false | |
| path | Path to the build context. Defaults to `.` | false | . |
| tag_with_latest | Tags the built image with additional latest tag | false | |
| target | Sets the target stage to build | false | |
| debug | Enables trace for entrypoint.sh | false | |
**Here is where it gets specific, as the optional arguments become required depending on
the registry targeted**
### [docker.io](https://hub.docker.com/)
This is the default, and implicit docker registry, in the same way as with using the
docker CLI In this case, the authentication credentials need to be passed via GitHub
Action secrets
```yaml
with:
image: aevea/kaniko
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
```
> NOTE: Dockerhub doesn't support more than one level deep of docker images, so Kaniko's
> default approach of pushing the cache to `$image/cache` doesn't work. If you want to
> use caching with Dockerhub, create a `cache` repository, and specify it in the action
> options.
```yaml
with:
image: aevea/kaniko
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
cache: true
cache_registry: aevea/cache
```
### [ghcr.io](https://github.com/features/packages)
GitHub's docker registry is a bit special. It doesn't allow top-level images, so this
action will prefix any image with the GitHub namespace. If you want to push your image
like `aevea/action-kaniko/kaniko`, you'll only need to pass `kaniko` to this action.
The authentication is automatically done using the `GITHUB_ACTOR` and `GITHUB_TOKEN`
provided from GitHub itself. But as `GITHUB_TOKEN` is not passed by default, it will
have to be explicitly set up.
```yaml
with:
registry: ghcr.io
password: ${{ secrets.GITHUB_TOKEN }}
image: kaniko
```
> NOTE: GitHub's docker registry is structured a bit differently, but it has the same
> drawback as Dockerhub, and that's that it's not possible to "namespace" images for
> cache. In order to use registry cache, just specify the image meant to be used as
> cache, and Kaniko will push the cache layers to that image instead
```yaml
with:
registry: ghcr.io
password: ${{ secrets.GITHUB_TOKEN }}
image: kaniko
cache: true
cache_registry: cache
```
### [registry.gitlab.com](https://docs.gitlab.com/ee/user/packages/container_registry)
GitLab's registry is quite flexible, it allows easy image namespacing, so a project's
docker registry can hold up to three levels of image repository names.
```
registry.gitlab.com/group/project:some-tag
registry.gitlab.com/group/project/image:latest
registry.gitlab.com/group/project/my/image:rc1
```
To authenticate to it, a username and personal access token must be supplied via GitHub
Action Secrets.
```yaml
with:
registry: registry.gitlab.com
username: ${{ secrets.GL_REGISTRY_USERNAME }}
password: ${{ secrets.GL_REGISTRY_PASSWORD }}
image: aevea/kaniko
```
> NOTE: As GitLab's registry does support namespacing, Kaniko can natively push cached
> layers to it, so only `cache: true` is necessary to be specified in order to use it.
```yaml
with:
registry: registry.gitlab.com
username: ${{ secrets.GL_REGISTRY_USERNAME }}
password: ${{ secrets.GL_REGISTRY_PASSWORD }}
image: aevea/kaniko
cache: true
```
### Other registries
If you would like to publish the image to other registries, these actions might be
helpful
| Registry | Action |
| --------------------------------------------------- | --------------------------------------------- |
| Amazon Webservices Elastic Container Registry (ECR) | https://github.com/elgohr/ecr-login-action |
| Google Cloud Container Registry | https://github.com/elgohr/gcloud-login-action |
### Other arguments details
#### tag
The `tag` argument, **unless overridden**, is automatically guessed based on the branch
name. If the branch is `master` or `main` then the tag will be `latest`, otherwise it
will keep the branch name, but replacing any forward slash (/) with a hyphen (-).
If the `v` prefix that it's usually added to the GitHub releases is not desired when
pushed to dockerhub, the `strip_tag_prefix` allows to specify which part of the tag
should be removed.
Example:
```yaml
with:
registry: ghcr.io
password: ${{ secrets.GITHUB_TOKEN }}
image: kaniko
strip_tag_prefix: pre-
```
for the tag `pre-0.1` will push `kaniko:0.1`, as the `pre-` part will be stripped from
the tag name.
#### platforms
By default, the script will build a single image for the build platform. If you want to
create images for multiple platforms (for example x86 and ARM) you can specify these
using the `platforms` option.
[Here](https://github.com/docker-library/official-images#architectures-other-than-amd64)
is a list of supported docker architectures.
**Note:** Kaniko does not do any emulation by itself. If you are running binaries for a
different architecture during the build process, you need to setup
[`qemu-user-static`](https://wiki.debian.org/QemuUserEmulation) on the build machine.
The script will build the images in the specified order. If all images built
successfully, they will be pushed to the registry and a multi-arch manifest is created.
## Outputs
### `image`
Full reference to the built image with registry and tag.
Example: `thetadev256/test-actions-helloworld2:main`
### `digest`
Full reference to the built image with registry and tag.
Example: `thetadev256/test-actions-helloworld2:main`
### `image-tag-digest`
Full reference to the built image with registry and tag.
Example: `thetadev256/test-actions-helloworld2:main`
## Dockerfile build arguments
Action-Kaniko automatically sets build arguments to allow for different dockerfile actions
depending on the OS and architecture the image is build for.
The supported arguments are:
- `TARGETPLATFORM` (example: linux/amd64)
- `TARGETOS` (example: linux)
- `TARGETARCH` (example: amd64)
- `TARGETARCH_ALT` (alternative architecture name, x86_64 for amd64, otherwise the same as TARGETARCH)
- `TARGETVARIANT` (third docker platform parameter like ARM version)

66
action.yml Normal file
View File

@ -0,0 +1,66 @@
name: "Kaniko builder"
description: "Build and push docker images using Kaniko"
author: <vshulkin@gmail.com>
inputs:
path:
description: Path to the build context
required: false
default: "."
registry:
description: "Docker registry where the image will be pushed"
required: false
username:
description: "Username used for authentication to the Docker registry"
required: false
password:
description: "Password used for authentication to the Docker registry"
required: false
image:
description: "Image name"
required: true
tag:
description: "Image tag"
required: false
cache:
description: "Enables build cache"
required: false
cache_ttl:
description: "How long the cache should be considered valid"
required: false
cache_registry:
description: "Docker registry meant to be used as cache"
required: false
cache_directory:
description: "Filesystem path meant to be used as cache"
required: false
build_file:
description: "Dockerfile filename"
required: false
strip_tag_prefix:
description: "Prefix to be stripped from the tag"
required: false
platforms:
description: "Target platforms to build (separated by comma); Example: linux/amd64,linux/arm64"
required: false
extra_args:
description: "Additional arguments to be passed to the kaniko executor"
required: false
tag_with_latest:
description: "Tags the built image with additional latest tag"
required: false
target:
description: Sets the target stage to build
required: false
debug:
description: Enables trace for entrypoint.sh
required: false
outputs:
image:
description: "Full reference to the built image with registry and tag"
digest:
description: "Checksum of the build image; Example: sha256:65335ed73cf17abdbcbe90354b75da0f22173486e6b92ab2f0f3d9ff9d928898"
image-tag-digest:
description: "Reference to the build image with registry and checksum; Example: index.docker.io/vshulkin/test-actions-helloworld@sha256:65335ed73cf17abdbcbe90354b75da0f22173486e6b92ab2f0f3d9ff9d928898"
runs:
using: "docker"
image: "Dockerfile"

164
entrypoint.sh Executable file
View File

@ -0,0 +1,164 @@
#!/busybox/sh
set -e pipefail
if [ "$INPUT_DEBUG" = "true" ]; then
set -x
fi
OLDIFS=$IFS
REGISTRY="${INPUT_REGISTRY:-"docker.io"}"
IMAGE="$INPUT_IMAGE"
BRANCH=$(echo "$GITHUB_REF" | sed -E "s/refs\/(heads|tags)\///g" | sed -e "s/\//-/g")
TAG=${INPUT_TAG:-$({ [ "$BRANCH" = "master" ] || [ "$BRANCH" = "main" ]; } && echo latest || echo "$BRANCH")}
TAG="${TAG:-"latest"}"
TAG="${TAG#$INPUT_STRIP_TAG_PREFIX}"
USERNAME="${INPUT_USERNAME:-$GITHUB_ACTOR}"
PASSWORD="${INPUT_PASSWORD:-$GITHUB_TOKEN}"
REPOSITORY="$IMAGE"
IMAGE="${IMAGE}:${TAG}"
CONTEXT_PATH="$INPUT_PATH"
if [ "$INPUT_TAG_WITH_LATEST" = "true" ]; then
IMAGE_LATEST="${REPOSITORY}:latest"
fi
ensure() {
if [ -z "${1}" ]; then
echo >&2 "Unable to find the ${2} variable. Did you set with.${2}?"
exit 1
fi
}
ensure "${REGISTRY}" "registry"
ensure "${USERNAME}" "username"
ensure "${PASSWORD}" "password"
ensure "${IMAGE}" "image"
ensure "${TAG}" "tag"
ensure "${CONTEXT_PATH}" "path"
if [ "$REGISTRY" = "ghcr.io" ]; then
IMAGE_NAMESPACE="$(echo "$GITHUB_REPOSITORY" | tr '[:upper:]' '[:lower:]')"
# Set `/` separator, unless image is pre-fixed with dash or slash
[ -n "$REPOSITORY" ] && expr "$REPOSITORY" : "^[-/]" > /dev/null && SEPARATOR="/"
IMAGE="$IMAGE_NAMESPACE$SEPARATOR$IMAGE"
REPOSITORY="$IMAGE_NAMESPACE$SEPARATOR$REPOSITORY"
if [ -n "$IMAGE_LATEST" ]; then
IMAGE_LATEST="${IMAGE_NAMESPACE}/${IMAGE_LATEST}"
fi
if [ -n "$INPUT_CACHE_REGISTRY" ]; then
INPUT_CACHE_REGISTRY="${REGISTRY}/${IMAGE_NAMESPACE}/${INPUT_CACHE_REGISTRY}"
fi
fi
if [ "$REGISTRY" != "docker.io" ]; then
IMAGE="${REGISTRY}/${IMAGE}"
if [ -n "$IMAGE_LATEST" ]; then
IMAGE_LATEST="${REGISTRY}/${IMAGE_LATEST}"
fi
fi
CACHE="${INPUT_CACHE:+"--cache=true"}"
CACHE="$CACHE"${INPUT_CACHE_TTL:+" --cache-ttl=$INPUT_CACHE_TTL"}
CACHE="$CACHE"${INPUT_CACHE_REGISTRY:+" --cache-repo=$INPUT_CACHE_REGISTRY"}
CACHE="$CACHE"${INPUT_CACHE_DIRECTORY:+" --cache-dir=$INPUT_CACHE_DIRECTORY"}
CONTEXT="--context $GITHUB_WORKSPACE/$CONTEXT_PATH"
DOCKERFILE="--dockerfile $CONTEXT_PATH/${INPUT_BUILD_FILE:-Dockerfile}"
TARGET=${INPUT_TARGET:+"--target=$INPUT_TARGET"}
ARGS="$CACHE $CONTEXT $DOCKERFILE $TARGET $INPUT_EXTRA_ARGS"
crane auth login "$REGISTRY" -u "$USERNAME" -p "$PASSWORD"
runKaniko() {
# https://github.com/GoogleContainerTools/kaniko/issues/1803
# https://github.com/GoogleContainerTools/kaniko/issues/1349
IFS=''
kaniko_cmd="executor ${1} --reproducible --force --cleanup"
echo "Running kaniko command: ${kaniko_cmd}"
eval "${kaniko_cmd}"
IFS=$OLDIFS
}
if [ -n "$INPUT_PLATFORMS" ]; then
# Build image for all platforms, then push the manifest
platformArray=$(echo "$INPUT_PLATFORMS" | sed 's/,/ /g' )
echo "⚒️ Building image $IMAGE for the following platforms: $platformArray"
for platform in $platformArray; do
echo; echo "📦 Building image for $platform"
platformFn=$(echo "$platform" | sed 's#/#-#g')
DESTINATION="--no-push --tarPath /kaniko/build/${platformFn}.tar --destination $IMAGE"
DIGEST="--image-name-tag-with-digest-file=/kaniko/build/${platformFn}_image-tag-digest"
targetos=$(echo "$platform" | cut -d/ -f1)
targetarch=$(echo "$platform" | cut -d/ -f2)
targetvariant=$(echo "$platform" | cut -d/ -f3)
case "$targetarch" in
'amd64') targetarchAlt="x86_64" ;;
'arm64') targetarchAlt="aarch64" ;;
'i386') targetarchAlt="i686" ;;
'386') targetarchAlt="i686" ;;
'ppc64le') targetarchAlt="powerpc64le" ;;
'arm')
case "$targetvariant" in
'v5') targetarchAlt="armv5te" ;;
'v7') targetarchAlt="armv7" ;;
*) targetarchAlt="arm" ;;
esac
;;
*) targetarchAlt="$targetarch" ;;
esac
runKaniko "${ARGS} --custom-platform=${platform} --build-arg TARGETPLATFORM='${platform}' --build-arg TARGETOS='${targetos}' --build-arg TARGETARCH='${targetarch}' --build-arg TARGETARCH_ALT='${targetarchAlt}' --build-arg TARGETVARIANT='${targetvariant}' $DESTINATION $DIGEST"
echo "$platform image built: $(head -n 1 "/kaniko/build/${platformFn}_image-tag-digest")"
done
echo; echo "🚀 Pushing images"
DIGESTS=""
for platform in $platformArray; do
platformFn=$(echo "$platform" | sed 's#/#-#g')
digest=$(head -n 1 "/kaniko/build/${platformFn}_image-tag-digest")
echo "Pushing $platform img $digest"
crane push "/kaniko/build/${platformFn}.tar" "$digest"
DIGESTS="$DIGESTS -m $digest"
done
manifest_cmd="crane index append -t $IMAGE $DIGESTS"
echo "Building manifest: $manifest_cmd"
IMAGE_TAG_DIGEST=$(eval "$manifest_cmd")
if [ -n "$IMAGE_LATEST" ]; then
crane tag "$IMAGE" latest
fi
else
# Build and push image for the default platform
echo "⚒️ Building image $IMAGE"
DESTINATION="--destination $IMAGE"
if [ -n "$IMAGE_LATEST" ]; then
DESTINATION="$DESTINATION --destination $IMAGE_LATEST"
fi
DIGEST="--image-name-tag-with-digest-file=/kaniko/build/image-tag-digest"
runKaniko "${ARGS} $DESTINATION $DIGEST"
IMAGE_TAG_DIGEST=$(head -n 1 /kaniko/build/image-tag-digest)
fi
DIGEST=$(echo "$IMAGE_TAG_DIGEST" | cut -f2 -d '@')
echo "image=$IMAGE" >> "$GITHUB_OUTPUT"
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
echo "image-tag-digest=$IMAGE_TAG_DIGEST" >> "$GITHUB_OUTPUT"
echo "🎉 Successfully deployed $IMAGE"
echo "Digest: $DIGEST"