diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index a733345..cf1202d 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -6,6 +6,8 @@ jobs: runs-on: ubuntu-latest name: Verify commit messages steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Run commitsar - uses: docker://aevea/commitsar + uses: docker://aevea/commitsar@sha256:e4aed72de9a00b990a53c678ad51fbe9bd04e127a617d10beab0ef0204b1dfa0 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 3260341..fc0bb44 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -11,7 +11,7 @@ jobs: - name: GitHub Package Registry uses: aevea/action-kaniko@master with: - registry: docker.pkg.github.com + registry: ghcr.io password: ${{ secrets.GITHUB_TOKEN }} image: kaniko cache: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ea8e3c0..4dbe99b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,17 +10,22 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v1 + uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Release Notary Action - uses: docker://aevea/release-notary + uses: docker://aevea/release-notary@sha256:690915bf87458fd8eb1e1ff0be34b33377f920eda3f38b96c62ecbf897c831f4 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + entrypoint: release-notary + args: publish - name: GitHub Package Registry uses: aevea/action-kaniko@master with: - registry: docker.pkg.github.com + registry: ghcr.io password: ${{ secrets.GITHUB_TOKEN }} image: kaniko cache: true diff --git a/Dockerfile b/Dockerfile index 024c21c..2c0fd25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,16 +2,20 @@ FROM alpine as certs RUN apk --update add ca-certificates -FROM gcr.io/kaniko-project/executor:debug +FROM gcr.io/kaniko-project/executor:v1.23.2-debug SHELL ["/busybox/sh", "-c"] RUN wget -O /kaniko/jq \ - https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 && \ + https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux64 && \ chmod +x /kaniko/jq && \ wget -O /kaniko/reg \ https://github.com/genuinetools/reg/releases/download/v0.16.1/reg-linux-386 && \ - chmod +x /kaniko/reg + chmod +x /kaniko/reg && \ + wget -O /crane.tar.gz \ + https://github.com/google/go-containerregistry/releases/download/v0.17.0/go-containerregistry_Linux_x86_64.tar.gz && \ + tar -xvzf /crane.tar.gz crane -C /kaniko && \ + rm /crane.tar.gz COPY entrypoint.sh / COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt diff --git a/README.md b/README.md index a09a7ca..56d6940 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Kaniko image builder +> [!WARNING] +> The kaniko project no longer seems to [have maintainers](https://github.com/GoogleContainerTools/kaniko/issues/3348). Keep this in mind before deciding to use kaniko as your image builder. + This Action uses the [kaniko](https://github.com/GoogleContainerTools/kaniko) executor instead of the docker daemon. Kaniko builds the image by extracting the filesystem of the base image, making the changes in the user space, snapshotting any change and appending it to the base image filesystem. @@ -56,6 +59,7 @@ the most used values. So, technically there is a single required argument | 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** @@ -83,7 +87,7 @@ with: cache_registry: aevea/cache ``` -### [docker.pkg.github.com](https://github.com/features/packages) +### [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. @@ -93,7 +97,7 @@ passed by default, it will have to be explicitly set up. ```yaml with: - registry: docker.pkg.github.com + registry: ghcr.io password: ${{ secrets.GITHUB_TOKEN }} image: kaniko ``` @@ -104,7 +108,7 @@ cache layers to that image instead ```yaml with: - registry: docker.pkg.github.com + registry: ghcr.io password: ${{ secrets.GITHUB_TOKEN }} image: kaniko cache: true @@ -167,10 +171,16 @@ Example: ```yaml with: - registry: docker.pkg.github.com + 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. + +## Outputs + +### `image` + +Full reference to the built image with registry and tag. diff --git a/action.yml b/action.yml index bc41cfb..7c51772 100644 --- a/action.yml +++ b/action.yml @@ -54,6 +54,12 @@ inputs: 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" runs: using: "docker" image: "Dockerfile" diff --git a/entrypoint.sh b/entrypoint.sh index c744ff4..8a29b69 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,20 +1,26 @@ #!/busybox/sh set -e pipefail +if [ "$INPUT_DEBUG" = "true" ]; then + set -o xtrace +fi -export REGISTRY=${INPUT_REGISTRY:-"docker.io"} -export IMAGE=${INPUT_IMAGE} -export BRANCH=$(echo ${GITHUB_REF} | sed -E "s/refs\/(heads|tags)\///g" | sed -e "s/\//-/g") -export TAG=${INPUT_TAG:-$([ "$BRANCH" == "master" ] && echo latest || echo $BRANCH)} -export TAG=${TAG:-"latest"} -export TAG=${TAG#$INPUT_STRIP_TAG_PREFIX} -export USERNAME=${INPUT_USERNAME:-$GITHUB_ACTOR} -export PASSWORD=${INPUT_PASSWORD:-$GITHUB_TOKEN} -export REPOSITORY=$IMAGE -export IMAGE_LATEST=${INPUT_TAG_WITH_LATEST:+"$IMAGE:latest"} -export IMAGE=$IMAGE:$TAG -export CONTEXT_PATH=${INPUT_PATH} +export REGISTRY="${INPUT_REGISTRY:-"docker.io"}" +export IMAGE="$INPUT_IMAGE" +export BRANCH=$(echo "$GITHUB_REF" | sed -E "s/refs\/(heads|tags)\///g" | sed -e "s/\//-/g") +export TAG=${INPUT_TAG:-$([ "$BRANCH" = "master" ] && echo latest || echo "$BRANCH")} +export TAG="${TAG:-"latest"}" +export TAG="${TAG#$INPUT_STRIP_TAG_PREFIX}" +export USERNAME="${INPUT_USERNAME:-$GITHUB_ACTOR}" +export PASSWORD="${INPUT_PASSWORD:-$GITHUB_TOKEN}" +export REPOSITORY="$IMAGE" +export IMAGE="${IMAGE}:${TAG}" +export CONTEXT_PATH="$INPUT_PATH" -function ensure() { +if [ "$INPUT_TAG_WITH_LATEST" = "true" ]; then + export 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 @@ -28,48 +34,51 @@ ensure "${IMAGE}" "image" ensure "${TAG}" "tag" ensure "${CONTEXT_PATH}" "path" -if [ "$REGISTRY" == "docker.pkg.github.com" ]; then +if [ "$REGISTRY" = "ghcr.io" ]; then IMAGE_NAMESPACE="$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')" - export IMAGE="$IMAGE_NAMESPACE/$IMAGE" - export REPOSITORY="$IMAGE_NAMESPACE/$REPOSITORY" + # Set `/` separator, unless image is pre-fixed with dash or slash + [ -n "$REPOSITORY" ] && [[ ! "$REPOSITORY" =~ ^[-/] ]] && SEPARATOR="/" + export IMAGE="$IMAGE_NAMESPACE$SEPARATOR$IMAGE" + export REPOSITORY="$IMAGE_NAMESPACE$SEPARATOR$REPOSITORY" - if [ ! -z $IMAGE_LATEST ]; then - export IMAGE_LATEST="$IMAGE_NAMESPACE/$IMAGE_LATEST" + if [ -n "$IMAGE_LATEST" ]; then + export IMAGE_LATEST="${IMAGE_NAMESPACE}/${IMAGE_LATEST}" fi - if [ ! -z $INPUT_CACHE_REGISTRY ]; then - export INPUT_CACHE_REGISTRY="$REGISTRY/$IMAGE_NAMESPACE/$INPUT_CACHE_REGISTRY" + if [ -n "$INPUT_CACHE_REGISTRY" ]; then + export INPUT_CACHE_REGISTRY="${REGISTRY}/${IMAGE_NAMESPACE}/${INPUT_CACHE_REGISTRY}" fi fi -if [ "$REGISTRY" == "docker.io" ]; then +if [ "$REGISTRY" = "docker.io" ]; then export REGISTRY="index.${REGISTRY}/v1/" else - export IMAGE="$REGISTRY/$IMAGE" + export IMAGE="${REGISTRY}/${IMAGE}" - if [ ! -z $IMAGE_LATEST ]; then - export IMAGE_LATEST="$REGISTRY/$IMAGE_LATEST" + if [ -n "$IMAGE_LATEST" ]; then + export IMAGE_LATEST="${REGISTRY}/${IMAGE_LATEST}" fi fi -export CACHE=${INPUT_CACHE:+"--cache=true"} -export CACHE=$CACHE${INPUT_CACHE_TTL:+" --cache-ttl=$INPUT_CACHE_TTL"} -export CACHE=$CACHE${INPUT_CACHE_REGISTRY:+" --cache-repo=$INPUT_CACHE_REGISTRY"} -export CACHE=$CACHE${INPUT_CACHE_DIRECTORY:+" --cache-dir=$INPUT_CACHE_DIRECTORY"} +export CACHE="${INPUT_CACHE:+"--cache=true"}" +export CACHE="$CACHE"${INPUT_CACHE_TTL:+" --cache-ttl=$INPUT_CACHE_TTL"} +export CACHE="$CACHE"${INPUT_CACHE_REGISTRY:+" --cache-repo=$INPUT_CACHE_REGISTRY"} +export CACHE="$CACHE"${INPUT_CACHE_DIRECTORY:+" --cache-dir=$INPUT_CACHE_DIRECTORY"} export CONTEXT="--context $GITHUB_WORKSPACE/$CONTEXT_PATH" export DOCKERFILE="--dockerfile $CONTEXT_PATH/${INPUT_BUILD_FILE:-Dockerfile}" export TARGET=${INPUT_TARGET:+"--target=$INPUT_TARGET"} +export DIGEST="--digest-file /kaniko/digest --image-name-tag-with-digest-file=/kaniko/image-tag-digest" -if [ ! -z $INPUT_SKIP_UNCHANGED_DIGEST ]; then - export DESTINATION="--no-push --digest-file digest" +if [ -n "$INPUT_SKIP_UNCHANGED_DIGEST" ]; then + export DESTINATION="--no-push --tarPath image.tar --destination $IMAGE" else export DESTINATION="--destination $IMAGE" - if [ ! -z $IMAGE_LATEST ]; then - export DESTINATION="$DESTINATION --destination $IMAGE_LATEST" + if [ -n "$IMAGE_LATEST" ]; then + export DESTINATION="$DESTINATION --destination $IMAGE_LATEST" fi fi -export ARGS="$CACHE $CONTEXT $DOCKERFILE $TARGET $DESTINATION $INPUT_EXTRA_ARGS" +export ARGS="$CACHE $CONTEXT $DOCKERFILE $TARGET $DIGEST $DESTINATION $INPUT_EXTRA_ARGS" cat </kaniko/.docker/config.json { @@ -82,35 +91,45 @@ cat </kaniko/.docker/config.json } EOF +# https://github.com/GoogleContainerTools/kaniko/issues/1803 # https://github.com/GoogleContainerTools/kaniko/issues/1349 -/kaniko/executor --reproducible --force $ARGS +export IFS='' +# Removes a trailing new line +ARGS=$(echo "${ARGS}" | sed 's/\n*$//') +kaniko_cmd="/kaniko/executor ${ARGS} --reproducible --force" +echo "Running kaniko command ${kaniko_cmd}" +eval "${kaniko_cmd}" -if [ ! -z $INPUT_SKIP_UNCHANGED_DIGEST ]; then - export DIGEST=$(cat digest) +echo "image=$IMAGE" >> "$GITHUB_OUTPUT" +echo "digest=$(cat /kaniko/digest)" >> "$GITHUB_OUTPUT" +echo "image-tag-digest<>"$GITHUB_OUTPUT" +echo "$(cat /kaniko/image-tag-digest)" >>"$GITHUB_OUTPUT" +echo 'EOF' >>"$GITHUB_OUTPUT" - if [ "$REGISTRY" == "docker.pkg.github.com" ]; then - wget -q -O manifest --header "Authorization: Basic $(echo -n $USERNAME:$PASSWORD | base64)" https://docker.pkg.github.com/v2/$REPOSITORY/manifests/latest || true - export REMOTE="sha256:$(cat manifest | sha256sum | awk '{ print $1 }')" - else - export REMOTE=$(reg digest -u $USERNAME -p $PASSWORD $REGISTRY/$REPOSITORY | tail -1) - fi - if [ "$DIGEST" == "$REMOTE" ]; then +if [ -n "$INPUT_SKIP_UNCHANGED_DIGEST" ]; then + export DIGEST="$(cat /kaniko/digest)" + + /kaniko/crane auth login "$REGISTRY" -u "$USERNAME" -p "$PASSWORD" + + export REMOTE=$(crane digest "${REGISTRY}/${REPOSITORY}:latest") + + if [ "$DIGEST" = "$REMOTE" ]; then + echo "refreshed=false" >> "$GITHUB_OUTPUT" echo "Digest hasn't changed, skipping, $DIGEST" echo "Done 🎉️" exit 0 fi - export DESTINATION="--destination $IMAGE" - if [ ! -z $IMAGE_LATEST ]; then - export DESTINATION="$DESTINATION --destination $IMAGE_LATEST" - fi - - export ARGS="$CACHE $CONTEXT $DOCKERFILE $TARGET $DESTINATION $INPUT_EXTRA_ARGS" - echo "Pushing image..." - /kaniko/executor --reproducible $ARGS >/dev/null 2>&1 + /kaniko/crane push image.tar "$IMAGE" + if [ -n "$IMAGE_LATEST" ]; then + echo "Tagging latest..." + /kaniko/crane tag "$IMAGE" latest + fi + + echo "refreshed=false" >> "$GITHUB_OUTPUT" echo "Done 🎉️" fi