From 5cdcdc08203b15a81e9757ea884a9adf1a1a0ffd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 21:45:38 +0000 Subject: [PATCH 01/11] Bump the go-minor group with 4 updates Bumps the go-minor group with 4 updates: [golang.org/x/sync](https://github.com/golang/sync), [golang.org/x/sys](https://github.com/golang/sys), [golang.org/x/term](https://github.com/golang/term) and [golang.org/x/text](https://github.com/golang/text). Updates `golang.org/x/sync` from 0.12.0 to 0.13.0 - [Commits](https://github.com/golang/sync/compare/v0.12.0...v0.13.0) Updates `golang.org/x/sys` from 0.31.0 to 0.32.0 - [Commits](https://github.com/golang/sys/compare/v0.31.0...v0.32.0) Updates `golang.org/x/term` from 0.30.0 to 0.31.0 - [Commits](https://github.com/golang/term/compare/v0.30.0...v0.31.0) Updates `golang.org/x/text` from 0.23.0 to 0.24.0 - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.23.0...v0.24.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-version: 0.13.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-minor - dependency-name: golang.org/x/sys dependency-version: 0.32.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-minor - dependency-name: golang.org/x/term dependency-version: 0.31.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-minor - dependency-name: golang.org/x/text dependency-version: 0.24.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-minor ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index a55e4081..975b814d 100644 --- a/go.mod +++ b/go.mod @@ -13,10 +13,10 @@ require ( github.com/stretchr/testify v1.10.0 github.com/vbauerster/mpb/v8 v8.9.3 golang.org/x/mod v0.24.0 - golang.org/x/sync v0.12.0 - golang.org/x/sys v0.31.0 - golang.org/x/term v0.30.0 - golang.org/x/text v0.23.0 + golang.org/x/sync v0.13.0 + golang.org/x/sys v0.32.0 + golang.org/x/term v0.31.0 + golang.org/x/text v0.24.0 gopkg.in/yaml.v3 v3.0.1 oras.land/oras-go/v2 v2.5.0 ) diff --git a/go.sum b/go.sum index 28335e92..8e007612 100644 --- a/go.sum +++ b/go.sum @@ -35,14 +35,14 @@ github.com/vbauerster/mpb/v8 v8.9.3 h1:PnMeF+sMvYv9u23l6DO6Q3+Mdj408mjLRXIzmUmU2 github.com/vbauerster/mpb/v8 v8.9.3/go.mod h1:hxS8Hz4C6ijnppDSIX6LjG8FYJSoPo9iIOcE53Zik0c= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From a96b9cec9e1eda1a5c0fa7d5e5afe766802e402c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 20:31:18 +0000 Subject: [PATCH 02/11] Bump goreleaser/goreleaser-action in the actions-minor group Bumps the actions-minor group with 1 update: [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action). Updates `goreleaser/goreleaser-action` from 6.2.1 to 6.3.0 - [Release notes](https://github.com/goreleaser/goreleaser-action/releases) - [Commits](https://github.com/goreleaser/goreleaser-action/compare/90a3faa9d0182683851fbfa97ca1a2cb983bfca3...9c156ee8a17a598857849441385a2041ef570552) --- updated-dependencies: - dependency-name: goreleaser/goreleaser-action dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/platform-release.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/platform-release.yaml b/.github/workflows/platform-release.yaml index b71b4d8d..91ffa75b 100644 --- a/.github/workflows/platform-release.yaml +++ b/.github/workflows/platform-release.yaml @@ -59,7 +59,7 @@ jobs: p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - name: Run GoReleaser - uses: goreleaser/goreleaser-action@90a3faa9d0182683851fbfa97ca1a2cb983bfca3 #v6.2.1 + uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 #v6.3.0 with: version: latest distribution: goreleaser @@ -104,7 +104,7 @@ jobs: go-version-file: 'go.mod' - name: Run GoReleaser - uses: goreleaser/goreleaser-action@90a3faa9d0182683851fbfa97ca1a2cb983bfca3 #v6.2.1 + uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 #v6.3.0 with: version: latest distribution: goreleaser @@ -132,7 +132,7 @@ jobs: go-version-file: 'go.mod' - name: Run GoReleaser - uses: goreleaser/goreleaser-action@90a3faa9d0182683851fbfa97ca1a2cb983bfca3 #v6.2.1 + uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 #v6.3.0 with: version: latest distribution: goreleaser From 3125698361e9c47ad1e498e9be186797084110ca Mon Sep 17 00:00:00 2001 From: amisevsk <16168279+amisevsk@users.noreply.github.com> Date: Tue, 1 Apr 2025 11:21:42 +0000 Subject: [PATCH 03/11] docs: update CLI documentation for v1.3.0 Signed-off-by: Angel Misevski --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index f2d7e425..979f45eb 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,5 +1,5 @@ { - "version": "v1.2.2", + "version": "v1.3.0", "peerDependencies": { "vue": "^3.4" }, From f2397f06a7a404eddf08bc7bdff27a8f9df38d79 Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Tue, 8 Apr 2025 12:53:16 -0400 Subject: [PATCH 04/11] Fix ghcr.io package references after move to kitops-ml org At some point, the base kit package in ghcr changed from kit to kitops so some references were out of date. Signed-off-by: Angel Misevski --- build/dockerfiles/KServe/Dockerfile | 2 +- build/dockerfiles/KServe/README.md | 6 +++--- build/dockerfiles/README.md | 2 +- build/dockerfiles/init/README.md | 6 +++--- docs/src/docs/deploy.md | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build/dockerfiles/KServe/Dockerfile b/build/dockerfiles/KServe/Dockerfile index c420c0b6..d21ee61e 100644 --- a/build/dockerfiles/KServe/Dockerfile +++ b/build/dockerfiles/KServe/Dockerfile @@ -1,4 +1,4 @@ -ARG KIT_BASE_IMAGE=ghcr.io/kitops-ml/kit:next +ARG KIT_BASE_IMAGE=ghcr.io/kitops-ml/kitops:next FROM $KIT_BASE_IMAGE COPY entrypoint.sh /usr/local/bin/entrypoint.sh diff --git a/build/dockerfiles/KServe/README.md b/build/dockerfiles/KServe/README.md index 69255ec9..6bec0206 100644 --- a/build/dockerfiles/KServe/README.md +++ b/build/dockerfiles/KServe/README.md @@ -8,10 +8,10 @@ To build the image, `docker` or `podman` is required. From the root of this repo docker build -t $KIT_KSERVE_IMAGE . ``` -By default, the image will be built using `ghcr.io/kitops-ml/kit:next` as a base. This can be overridden (to build using a specific version of Kit, for example) by using the build arg `KIT_BASE_IMAGE`: +By default, the image will be built using `ghcr.io/kitops-ml/kitops:next` as a base. This can be overridden (to build using a specific version of Kit, for example) by using the build arg `KIT_BASE_IMAGE`: ```shell -# Build the image based on Kit v0.3.2 instead of 'next' -docker build -t kit-init-container:latest --build-arg KIT_BASE_IMAGE=ghcr.io/kitops-ml/kit:v0.3.2 . +# Build the image based on Kit v1.3.0 instead of 'next' +docker build -t kit-init-container:latest --build-arg KIT_BASE_IMAGE=ghcr.io/kitops-ml/kitops:v1.3.0 . ``` ## Installing diff --git a/build/dockerfiles/README.md b/build/dockerfiles/README.md index e648fce0..8ad9a62b 100644 --- a/build/dockerfiles/README.md +++ b/build/dockerfiles/README.md @@ -3,7 +3,7 @@ The Dockerfiles in this directory can be used for building a containerized version of the Kit CLI. The default entrypoint for these image is invoking the `kit` CLI, allowing for quickly running Kit commands without needing to install the CLI: ``` -docker run --rm ghcr.io/kitops-ml/kit:latest version +docker run --rm ghcr.io/kitops-ml/kitops:latest version ``` ## Release build diff --git a/build/dockerfiles/init/README.md b/build/dockerfiles/init/README.md index b56b0a17..421e1b81 100644 --- a/build/dockerfiles/init/README.md +++ b/build/dockerfiles/init/README.md @@ -70,9 +70,9 @@ Building the image requires docker or podman. To build the image, run the follow docker build -t kit-init-container:latest . ``` -By default, the image will be built using `ghcr.io/kitops-ml/kit:next` as a base. This can be overridden (to build using a specific version of Kit, for example) by using the build arg `KIT_BASE_IMAGE`: +By default, the image will be built using `ghcr.io/kitops-ml/kitops:next` as a base. This can be overridden (to build using a specific version of Kit, for example) by using the build arg `KIT_BASE_IMAGE`: ```shell -# Build the image based on Kit v0.3.2 instead of 'next' -docker build -t kit-init-container:latest --build-arg KIT_BASE_IMAGE=ghcr.io/kitops-ml/kit:v0.3.2 . +# Build the image based on Kit v1.3.0 instead of 'next' +docker build -t kit-init-container:latest --build-arg KIT_BASE_IMAGE=ghcr.io/kitops-ml/kitops:v1.3.0 . ``` diff --git a/docs/src/docs/deploy.md b/docs/src/docs/deploy.md index 0358a416..d9e1c361 100644 --- a/docs/src/docs/deploy.md +++ b/docs/src/docs/deploy.md @@ -69,7 +69,7 @@ This container runs `kit` as its entrypoint, accepting Kit CLI arguments. So you Docker run example: -`docker run ghcr.io/kitops-ml/kit:latest pull jozu.ml/jozu/llama3-8b:8B-instruct-q5_0` +`docker run ghcr.io/kitops-ml/kitops:latest pull jozu.ml/jozu/llama3-8b:8B-instruct-q5_0` Kubernetes example: @@ -81,7 +81,7 @@ Kubernetes example: spec: containers: - name: me-using-kit - image: ghcr.io/kitops-ml/kit:latest + image: ghcr.io/kitops-ml/kitops:latest args: # You can put whatever you want; args is an array - pull - jozu.ml/jozu/llama3-8b:8B-instruct-q5_0 @@ -95,7 +95,7 @@ Example `dockerfile` for a custom container that has `my-modelkit` built into it ``` # Staged build to grab the ModelKit so we can use it later - FROM ghcr.io/kitops-ml/kit:latest AS modelkit-download + FROM ghcr.io/kitops-ml/kitops:latest AS modelkit-download # Download your ModelKit into the container RUN kit unpack my-modelkit /tmp/my-modelkit From 5bd91f17a994cdf7a5fa70e47163d1cec433d1a4 Mon Sep 17 00:00:00 2001 From: Gorkem Ercan Date: Wed, 9 Apr 2025 10:02:03 -0400 Subject: [PATCH 05/11] Introduce KServe image builds Also fixes the documentation for the ClusterContainerStorage Signed-off-by: Gorkem Ercan --- .github/workflows/next-container-build.yaml | 32 ++++++------ .github/workflows/platform-release.yaml | 28 ++++++++++- build/dockerfiles/KServe/README.md | 56 ++++++++++++++------- 3 files changed, 82 insertions(+), 34 deletions(-) diff --git a/.github/workflows/next-container-build.yaml b/.github/workflows/next-container-build.yaml index 8f4c982f..f546bc8a 100644 --- a/.github/workflows/next-container-build.yaml +++ b/.github/workflows/next-container-build.yaml @@ -11,6 +11,7 @@ env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} INIT_IMAGE_NAME: ${{ github.repository }}-init + KIT_SERVE_IMAGE: ${{ github.repository }}-kserve NEXT_TAG: next permissions: @@ -72,17 +73,20 @@ jobs: index:org.opencontainers.image.description=Kit CLI init container index:org.opencontainers.image.source=https://github.com/kitops-ml/kitops index:org.opencontainers.image.licenses=Apache-2.0 - - # - name: Generate artifact attestation for base container - # uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 - # with: - # subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - # subject-digest: ${{ steps.build-kit-container.outputs.digest }} - # push-to-registry: true - - # - name: Generate artifact attestation for base container - # uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 - # with: - # subject-name: ${{ env.REGISTRY }}/${{ env.INIT_IMAGE_NAME }} - # subject-digest: ${{ steps.build-kit-init-container.outputs.digest }} - # push-to-registry: true + + - name: Build and push Kit KServe container + id: build-kit-serve-container + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + with: + platforms: linux/amd64,linux/arm64 + push: true + context: build/dockerfiles/KServe + file: build/dockerfiles/KServe/Dockerfile + build-args: | + KIT_BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-kit-container.outputs.digest }} + tags: | + ${{ env.REGISTRY }}/${{ env.KIT_SERVE_IMAGE }}:${{ env.NEXT_TAG }} + annotations: | + index:org.opencontainers.image.description=KitOps KServe container + index:org.opencontainers.image.source=https://github.com/kitops-ml/kitops + index:org.opencontainers.image.licenses=Apache-2.0 diff --git a/.github/workflows/platform-release.yaml b/.github/workflows/platform-release.yaml index 91ffa75b..218d3e10 100644 --- a/.github/workflows/platform-release.yaml +++ b/.github/workflows/platform-release.yaml @@ -20,6 +20,7 @@ env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} INIT_IMAGE_NAME: ${{ github.repository }}-init + KIT_SERVE_IMAGE: ${{ github.repository }}-kserve permissions: contents: write @@ -394,6 +395,24 @@ jobs: index:org.opencontainers.image.source=https://github.com/kitops-ml/kitops index:org.opencontainers.image.licenses=Apache-2.0 + - name: Build and push Kit KServe container + id: build-kit-serve-container + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + with: + platforms: linux/amd64,linux/arm64 + push: true + context: build/dockerfiles/KServe + file: build/dockerfiles/KServe/Dockerfile + build-args: | + KIT_BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-kit-container.outputs.digest }} + tags: | + ${{ env.REGISTRY }}/${{ env.KIT_SERVE_IMAGE }}:latest + ${{ env.REGISTRY }}/${{ env.KIT_SERVE_IMAGE }}:${{ github.ref_name }} + annotations: | + index:org.opencontainers.image.description=Kit KServe container + index:org.opencontainers.image.source=https://github.com/kitops-ml/kitops + index:org.opencontainers.image.licenses=Apache-2.0 + - name: Generate artifact attestation for base container uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 with: @@ -401,9 +420,16 @@ jobs: subject-digest: ${{ steps.build-kit-container.outputs.digest }} push-to-registry: true - - name: Generate artifact attestation for base container + - name: Generate artifact attestation for kit init container uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 with: subject-name: ${{ env.REGISTRY }}/${{ env.INIT_IMAGE_NAME }} subject-digest: ${{ steps.build-kit-init-container.outputs.digest }} push-to-registry: true + + - name: Generate artifact attestation for kit kserve container + uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.KIT_SERVE_IMAGE }} + subject-digest: ${{ steps.build-kit-serve-container.outputs.digest }} + push-to-registry: true diff --git a/build/dockerfiles/KServe/README.md b/build/dockerfiles/KServe/README.md index 6bec0206..8b636206 100644 --- a/build/dockerfiles/KServe/README.md +++ b/build/dockerfiles/KServe/README.md @@ -1,23 +1,13 @@ -# Kitops ClusterStorageContainer image for KServe +# KitOps ClusterStorageContainer image for KServe The Dockerfile in this directory is used to build an image that can run as a ClusterStorageContainer for [KServe](https://kserve.github.io/website/master/). -## Building -To build the image, `docker` or `podman` is required. From the root of this repository, set the `$KIT_KSERVE_IMAGE` to the image tag you want to build and run -```bash -docker build -t $KIT_KSERVE_IMAGE . -``` +## Installing -By default, the image will be built using `ghcr.io/kitops-ml/kitops:next` as a base. This can be overridden (to build using a specific version of Kit, for example) by using the build arg `KIT_BASE_IMAGE`: -```shell -# Build the image based on Kit v1.3.0 instead of 'next' -docker build -t kit-init-container:latest --build-arg KIT_BASE_IMAGE=ghcr.io/kitops-ml/kitops:v1.3.0 . -``` +The following process creates a new ClusterStorageContainer that uses `kit` to support KServe InferenceServices with storage URIs that have the `kit://` prefix. -## Installing -The following process will create a new ClusterStorageContainer that uses `kit` to support KServe InferenceServices with storage URIs that have the `kit://` prefix. +Create the following `ClusterStorageContainer` custom resource in a Kubernetes cluster with KServe installed. Note that the sample below uses the `ghcr.io/kitops-ml/kitops-kserve:next` image, although the repository includes other tags you can use. -Create the following ClusterStorageContainer custom resource in a Kubernetes cluster with KServe installed ```yaml apiVersion: "serving.kserve.io/v1alpha1" kind: ClusterStorageContainer @@ -25,8 +15,8 @@ metadata: name: kitops spec: container: - name: kit-storage-initializer - image: $KIT_KSERVE_IMAGE + name: storage-initializer + image: ghcr.io/kitops-ml/kitops-kserve:next imagePullPolicy: Always env: - name: KIT_UNPACK_FLAGS @@ -41,13 +31,40 @@ spec: - prefix: kit:// ``` -Once this CR is installed, modelkits can be used in InferenceServices by specifying with the `kit://` URI: +Once this custom resource is installed, ModelKits can be used in InferenceServices by specifying the ModelKit URI with the `kit://` prefix in the `storageUri` field: + ```yaml -storageUri: kit:// +apiVersion: "serving.kserve.io/v1beta1" +kind: "InferenceService" +metadata: + name: "iris-model" +spec: + predictor: + model: + modelFormat: + name: sklearn + storageUri: kit:// +``` + +## Building + +To build the image, `docker` or `podman` is required. From the root of this repository, set the `$KIT_KSERVE_IMAGE` environment variable to the image tag you want to build and run + +```bash +docker build -t $KIT_KSERVE_IMAGE . +``` + +By default, the image will be built using `ghcr.io/kitops-ml/kitops:next` as a base. This can be overridden by specifying the build argument `KIT_BASE_IMAGE` to use a specific version of Kit. For example: + +```shell +# Build the image based on Kit v1.3.0 instead of 'next' +docker build -t kitops-kserve:latest --build-arg KIT_BASE_IMAGE=ghcr.io/kitops-ml/kitops:v1.3.0 . ``` ## Configuration -The Kit KServe container supports specifying additional flags as supported by the `kit unpack` command. Additional flags are read from the `KIT_UNPACK_FLAGS` environment variable in the ClusterStorageContainer. For example, the following adds `-v` and `--plain-http` for all unpack commands: + +The Kit KServe container supports specifying additional flags for the `kit unpack` command. These flags are read from the KIT_UNPACK_FLAGS environment variable in the ClusterStorageContainer. For example, the following configuration adds `-v` and `--plain-http` for all unpack commands: + ```yaml env: - name: KIT_UNPACK_FLAGS @@ -55,4 +72,5 @@ The Kit KServe container supports specifying additional flags as supported by th ``` ## Additional links + * [KServe ClusterStorageContainer documentation](https://kserve.github.io/website/master/modelserving/storage/storagecontainers/) From 49ff3e28486aeee8be8d21ea034092797587037b Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Thu, 10 Apr 2025 14:21:41 -0400 Subject: [PATCH 06/11] Allow specifying version when importing huggingface repositories Add flag `--ref` to kit import command to allow importing tagged versions of the repository instead of only 'main' Signed-off-by: Angel Misevski --- pkg/cmd/kitimport/cmd.go | 5 +++++ pkg/cmd/kitimport/hfimport.go | 4 ++-- pkg/lib/hf/download.go | 6 +++--- pkg/lib/hf/list.go | 6 +++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/pkg/cmd/kitimport/cmd.go b/pkg/cmd/kitimport/cmd.go index d28cec98..993a56ea 100644 --- a/pkg/cmd/kitimport/cmd.go +++ b/pkg/cmd/kitimport/cmd.go @@ -58,6 +58,9 @@ REPOSITORY.` example = `# Download repository myorg/myrepo and package it, using the default tag (myorg/myrepo:latest) kit import myorg/myrepo +# Download repository using a different version (tag) than the default and package it +kit import myorg/myrepo --ref v1.0.0 + # Download repository and tag it 'myrepository:mytag' kit import myorg/myrepo --tag myrepository:mytag @@ -68,6 +71,7 @@ kit import myorg/myrepo --file ./path/to/Kitfile` type importOptions struct { configHome string repo string + repoRef string tag string token string kitfilePath string @@ -88,6 +92,7 @@ func ImportCommand() *cobra.Command { Args: cobra.ExactArgs(1), } + cmd.Flags().StringVar(&opts.repoRef, "ref", "main", "Version (tag) of repository to import (default is 'main')") cmd.Flags().StringVar(&opts.token, "token", "", "Token to use for authenticating with repository") cmd.Flags().StringVarP(&opts.tag, "tag", "t", "", "Tag for the ModelKit (default is '[repository]:latest')") cmd.Flags().StringVarP(&opts.kitfilePath, "file", "f", "", "Path to Kitfile to use for packing (use '-' to read from standard input)") diff --git a/pkg/cmd/kitimport/hfimport.go b/pkg/cmd/kitimport/hfimport.go index cfee2f3b..e69783bc 100644 --- a/pkg/cmd/kitimport/hfimport.go +++ b/pkg/cmd/kitimport/hfimport.go @@ -53,7 +53,7 @@ func importUsingHF(ctx context.Context, opts *importOptions) error { } }() - dirListing, err := hf.ListFiles(ctx, repo, opts.token) + dirListing, err := hf.ListFiles(ctx, repo, opts.repoRef, opts.token) if err != nil { return fmt.Errorf("failed to list files from HuggingFace API: %w", err) } @@ -106,7 +106,7 @@ func importUsingHF(ctx context.Context, opts *importOptions) error { if err != nil { return err } - if err := hf.DownloadFiles(ctx, repo, tmpDir, toDownload, opts.token, opts.concurrency); err != nil { + if err := hf.DownloadFiles(ctx, repo, opts.repoRef, tmpDir, toDownload, opts.token, opts.concurrency); err != nil { return fmt.Errorf("error downloading repository: %w", err) } diff --git a/pkg/lib/hf/download.go b/pkg/lib/hf/download.go index 40756fe7..eb68ebc2 100644 --- a/pkg/lib/hf/download.go +++ b/pkg/lib/hf/download.go @@ -34,12 +34,12 @@ import ( ) const ( - resolveURLFmt = "https://huggingface.co/%s/resolve/main/%s" + resolveURLFmt = "https://huggingface.co/%s/resolve/%s/%s" ) func DownloadFiles( ctx context.Context, - modelRepo, destDir string, + modelRepo, repoRef, destDir string, filepaths []string, token string, maxConcurrency int) error { @@ -61,7 +61,7 @@ func DownloadFiles( break } - fileURL := fmt.Sprintf(resolveURLFmt, modelRepo, f) + fileURL := fmt.Sprintf(resolveURLFmt, modelRepo, repoRef, f) destPath := filepath.Join(destDir, f) errs.Go(func() error { defer sem.Release(1) diff --git a/pkg/lib/hf/list.go b/pkg/lib/hf/list.go index 7791a4a2..7bd93146 100644 --- a/pkg/lib/hf/list.go +++ b/pkg/lib/hf/list.go @@ -30,7 +30,7 @@ import ( ) const ( - treeURLFmt = "https://huggingface.co/api/models/%s/tree/main" + treeURLFmt = "https://huggingface.co/api/models/%s/tree/%s" ) type hfTreeResponse []struct { @@ -44,11 +44,11 @@ type hfErrorResponse struct { Error string `json:"error"` } -func ListFiles(ctx context.Context, modelRepo string, token string) (*kfgen.DirectoryListing, error) { +func ListFiles(ctx context.Context, modelRepo, ref string, token string) (*kfgen.DirectoryListing, error) { client := &http.Client{ Timeout: 10 * time.Second, } - baseURL, err := url.Parse(fmt.Sprintf(treeURLFmt, modelRepo)) + baseURL, err := url.Parse(fmt.Sprintf(treeURLFmt, modelRepo, ref)) if err != nil { return nil, fmt.Errorf("failed to parse URL: %w", err) } From 4d7d3ee3431e34676435d920e75c71ad8cc9c515 Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Thu, 10 Apr 2025 14:50:52 -0400 Subject: [PATCH 07/11] Support specifying branch/tag when importing using Git directly Signed-off-by: Angel Misevski --- pkg/cmd/kitimport/cmd.go | 3 ++- pkg/cmd/kitimport/gitimport.go | 6 +++--- pkg/lib/git/clone.go | 11 +++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/kitimport/cmd.go b/pkg/cmd/kitimport/cmd.go index 993a56ea..ea100e92 100644 --- a/pkg/cmd/kitimport/cmd.go +++ b/pkg/cmd/kitimport/cmd.go @@ -24,6 +24,7 @@ import ( "strings" "github.com/kitops-ml/kitops/pkg/lib/constants" + "github.com/kitops-ml/kitops/pkg/lib/git" repoutils "github.com/kitops-ml/kitops/pkg/lib/repo/util" "github.com/kitops-ml/kitops/pkg/output" @@ -92,7 +93,7 @@ func ImportCommand() *cobra.Command { Args: cobra.ExactArgs(1), } - cmd.Flags().StringVar(&opts.repoRef, "ref", "main", "Version (tag) of repository to import (default is 'main')") + cmd.Flags().StringVar(&opts.repoRef, "ref", git.DefaultGitRef, "Version (tag) of repository to import") cmd.Flags().StringVar(&opts.token, "token", "", "Token to use for authenticating with repository") cmd.Flags().StringVarP(&opts.tag, "tag", "t", "", "Tag for the ModelKit (default is '[repository]:latest')") cmd.Flags().StringVarP(&opts.kitfilePath, "file", "f", "", "Path to Kitfile to use for packing (use '-' to read from standard input)") diff --git a/pkg/cmd/kitimport/gitimport.go b/pkg/cmd/kitimport/gitimport.go index edde44e6..a5448cca 100644 --- a/pkg/cmd/kitimport/gitimport.go +++ b/pkg/cmd/kitimport/gitimport.go @@ -47,7 +47,7 @@ func importUsingGit(ctx context.Context, opts *importOptions) error { } }() - if err := cloneRepository(opts.repo, tmpDir, opts.token); err != nil { + if err := cloneRepository(opts.repo, opts.repoRef, tmpDir, opts.token); err != nil { return err } @@ -117,12 +117,12 @@ func importUsingGit(ctx context.Context, opts *importOptions) error { return nil } -func cloneRepository(repo, destDir, token string) error { +func cloneRepository(repo, repoRef, destDir, token string) error { fullRepo := repo if !strings.HasPrefix(fullRepo, "http") { fullRepo = fmt.Sprintf("https://huggingface.co/%s", repo) } - if err := git.CloneRepository(fullRepo, destDir, token); err != nil { + if err := git.CloneRepository(fullRepo, repoRef, destDir, token); err != nil { return err } // Clean up git-related files, since we probably don't want those diff --git a/pkg/lib/git/clone.go b/pkg/lib/git/clone.go index 94280a7a..1323f47a 100644 --- a/pkg/lib/git/clone.go +++ b/pkg/lib/git/clone.go @@ -26,7 +26,9 @@ import ( "github.com/kitops-ml/kitops/pkg/output" ) -func CloneRepository(repo, dest, token string) error { +const DefaultGitRef = "main" + +func CloneRepository(repo, repoRef, dest, token string) error { if err := checkGit(); err != nil { return err } @@ -53,7 +55,12 @@ func CloneRepository(repo, dest, token string) error { } // Clone without LFS enabled to get metadata about repo first - cloneCmd := exec.Command("git", "clone", "--depth", "1", repo, dest) + var cloneCmd *exec.Cmd + if repoRef != DefaultGitRef { + cloneCmd = exec.Command("git", "clone", "--depth", "1", "--branch", repoRef, "-c", "advice.detachedHead=false", repo, dest) + } else { + cloneCmd = exec.Command("git", "clone", "--depth", "1", repo, dest) + } cloneCmd.Env = cloneEnv cloneCmd.Env = append(cloneCmd.Env, "GIT_LFS_SKIP_SMUDGE=1") cloneCmd.Stderr = os.Stderr From ed837a3f67fdc29aa76a5d33803a4cc398378dbd Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Thu, 10 Apr 2025 14:56:55 -0400 Subject: [PATCH 08/11] Handle errors when tag is not found during kit import using huggingface Signed-off-by: Angel Misevski --- pkg/lib/hf/list.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/lib/hf/list.go b/pkg/lib/hf/list.go index 7bd93146..05a360df 100644 --- a/pkg/lib/hf/list.go +++ b/pkg/lib/hf/list.go @@ -23,6 +23,7 @@ import ( "net/http" "net/url" "path" + "strings" "time" kfgen "github.com/kitops-ml/kitops/pkg/lib/kitfile/generate" @@ -115,6 +116,11 @@ func processTreeResponse(resp *http.Response) (*hfTreeResponse, error) { if err := json.NewDecoder(resp.Body).Decode(errResp); err != nil { return nil, fmt.Errorf("failed to parse API error response: %w", err) } + if resp.StatusCode == http.StatusNotFound && strings.HasPrefix(errResp.Error, "Invalid rev id") { + // Handle case where provided reference (tag) is not found to avoid confusing response + ref := errResp.Error[strings.LastIndex(errResp.Error, " ")+1:] + return nil, fmt.Errorf("reference '%s' not found", ref) + } return nil, fmt.Errorf("got error code %d from API: %s", resp.StatusCode, errResp.Error) } From 876a227774f52802a202051693b20964681671c0 Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Wed, 9 Apr 2025 17:41:42 -0400 Subject: [PATCH 09/11] Use monolithic PUT to upload large layers to Amazon ECR Amazon ECR registries return HTTP 201 after the first chunk in a multi-part upload, which is unexpected and causes the upload to fail. To avoid this, we can default to using a monolithic PUT. Signed-off-by: Angel Misevski --- pkg/lib/repo/remote/upload-format.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/lib/repo/remote/upload-format.go b/pkg/lib/repo/remote/upload-format.go index 7479a914..69e8de95 100644 --- a/pkg/lib/repo/remote/upload-format.go +++ b/pkg/lib/repo/remote/upload-format.go @@ -17,8 +17,9 @@ package remote import ( - "github.com/kitops-ml/kitops/pkg/output" "regexp" + + "github.com/kitops-ml/kitops/pkg/output" ) type uploadFormat int @@ -34,8 +35,9 @@ const ( ) var ( - googleArtifactRegistryRegexp = regexp.MustCompile(`.*\.pkg\.dev$`) - googleContainerRegistryRegexp = regexp.MustCompile(`.*\.?gcr.io$`) + googleArtifactRegistryRegexp = regexp.MustCompile(`.*\.pkg\.dev$`) + googleContainerRegistryRegexp = regexp.MustCompile(`.*\.?gcr\.io$`) + amazonElasticContainerRegistryRegexp = regexp.MustCompile(`.*\.?amazonaws\.com(\.cn)?$`) ) func getUploadFormat(registry string, size int64) uploadFormat { @@ -50,6 +52,10 @@ func getUploadFormat(registry string, size int64) uploadFormat { // uploads. // docs: https://cloud.google.com/artifact-registry/docs/docker/pushing-and-pulling#pushing return uploadMonolithicPut + case amazonElasticContainerRegistryRegexp.MatchString(registry): + // Amazon ECR returns an HTTP 201 after the first piece in a multi-part upload, which causes + // uploads to fail. + return uploadMonolithicPut default: // No matches above, use heuristic if size < uploadChunkDefaultSize { From 3e7dca459837fb9d9df46dc05bc6e15666d14a81 Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Thu, 10 Apr 2025 15:20:47 -0400 Subject: [PATCH 10/11] Add test cases for Amazon ECR push format Signed-off-by: Angel Misevski --- pkg/lib/repo/remote/upload-format_test.go | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pkg/lib/repo/remote/upload-format_test.go b/pkg/lib/repo/remote/upload-format_test.go index 81249f31..12acd702 100644 --- a/pkg/lib/repo/remote/upload-format_test.go +++ b/pkg/lib/repo/remote/upload-format_test.go @@ -101,3 +101,30 @@ func TestGetUploadFormatGoogleArtifactRegistry(t *testing.T) { assert.Equal(t, uploadMonolithicPut, uploadFormatLarge, "Large layers should use monolithic put") } } + +func TestGetUploadFormatAmazonECR(t *testing.T) { + testRegistries := []string{ + "123918541723.dkr.ecr.us-east-2.amazonaws.com", + "123918541723.dkr.ecr-fips.us-east-1.amazonaws.com", + "123918541723.dkr.ecr-fips.us-west-2.amazonaws.com", + "123918541723.dkr.ecr.ap-south-1.amazonaws.com", + "123918541723.dkr.ecr.ap-northeast-1.amazonaws.com", + "123918541723.dkr.ecr.ca-central-1.amazonaws.com", + "123918541723.dkr.ecr.cn-north-1.amazonaws.com.cn", + "123918541723.dkr.ecr.cn-northwest-1.amazonaws.com.cn", + "123918541723.dkr.ecr.eu-central-1.amazonaws.com", + "123918541723.dkr.ecr.eu-west-1.amazonaws.com", + "123918541723.dkr.ecr.me-south-1.amazonaws.com", + "123918541723.dkr.ecr.sa-east-1.amazonaws.com", + "123918541723.dkr.ecr-fips.us-gov-east-1.amazonaws.com", + "123918541723.dkr.ecr.us-gov-west-1.amazonaws.com", + "123918541723.dkr.ecr-fips.us-gov-west-1.amazonaws.com", + } + + for _, registry := range testRegistries { + uploadFormatSmall := getUploadFormat(registry, 100) + assert.Equal(t, uploadMonolithicPut, uploadFormatSmall, "Small layers should use monolithic put") + uploadFormatLarge := getUploadFormat(registry, uploadChunkDefaultSize) + assert.Equal(t, uploadMonolithicPut, uploadFormatLarge, "Large layers should use monolithic put") + } +} From 84d6d3d2269552b5b7c449a2e15b2a8eb855747c Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Thu, 10 Apr 2025 15:49:14 -0400 Subject: [PATCH 11/11] Handle mixed case URLs when determining upload format for push Since URLs are case-insensitive Signed-off-by: Angel Misevski --- pkg/lib/repo/remote/upload-format.go | 2 ++ pkg/lib/repo/remote/upload-format_test.go | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/pkg/lib/repo/remote/upload-format.go b/pkg/lib/repo/remote/upload-format.go index 69e8de95..c44799a3 100644 --- a/pkg/lib/repo/remote/upload-format.go +++ b/pkg/lib/repo/remote/upload-format.go @@ -18,6 +18,7 @@ package remote import ( "regexp" + "strings" "github.com/kitops-ml/kitops/pkg/output" ) @@ -42,6 +43,7 @@ var ( func getUploadFormat(registry string, size int64) uploadFormat { output.SafeDebugf("Getting upload format for: %s", registry) + registry = strings.ToLower(registry) switch { case registry == "ghcr.io": // ghcr.io returns 416 is a PATCH has Content-Length greater than 4.0 MiB for some reason diff --git a/pkg/lib/repo/remote/upload-format_test.go b/pkg/lib/repo/remote/upload-format_test.go index 12acd702..2a1f1492 100644 --- a/pkg/lib/repo/remote/upload-format_test.go +++ b/pkg/lib/repo/remote/upload-format_test.go @@ -92,6 +92,8 @@ func TestGetUploadFormatGoogleArtifactRegistry(t *testing.T) { "northamerica-northeast1-docker.pkg.dev", "us-central1-docker.pkg.dev", "us-east1-docker.pkg.dev", + ".PKG.DEV", + ".pkg.DEV", } for _, registry := range testRegistries { @@ -119,6 +121,8 @@ func TestGetUploadFormatAmazonECR(t *testing.T) { "123918541723.dkr.ecr-fips.us-gov-east-1.amazonaws.com", "123918541723.dkr.ecr.us-gov-west-1.amazonaws.com", "123918541723.dkr.ecr-fips.us-gov-west-1.amazonaws.com", + "123918541723.dkr.ecr.us-east-2.AmAzOnAwS.com", + "123918541723.dkr.ecr.us-east-2.AMAZONAWS.COM", } for _, registry := range testRegistries {