feat: add Dockerfile and container image CI#25
Conversation
Signed-off-by: SzymonIwaniuk <szymon.iwaniuk@joinmoxie.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hey @Krishna-kg732, can you take a look at this PR, this will be part of release workflow you are working on right? |
| type=semver,pattern={{major}} | ||
| type=raw,value=latest | ||
|
|
||
| - name: Build and push |
There was a problem hiding this comment.
Thank you @SzymonIwaniuk . should we consider injecting the release version into the image (via build args / OCI labels)? Right now versioning is only at the tag level, which can make runtime debugging harder.
There was a problem hiding this comment.
Yeah, great idea - agree with that
| *.yaml | ||
| *.yml |
|
|
||
| FROM python:3.12-slim AS builder | ||
|
|
||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv |
There was a problem hiding this comment.
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv | |
| COPY --from=ghcr.io/astral-sh/uv:0.11.14/uv /usr/local/bin/uv |
|
|
||
| USER 65532:65532 | ||
|
|
||
| ENTRYPOINT ["kubeflow-mcp", "serve", "--transport", "http"] |
There was a problem hiding this comment.
| ENTRYPOINT ["kubeflow-mcp", "serve", "--transport", "http"] | |
| ENTRYPOINT ["sh", "-c", "exec kubeflow-mcp serve --transport ${MCP_TRANSPORT}"] |
|
Hey @SzymonIwaniuk , few nits , rest looks good cc: @abhijeet-dhumal |
|
Hey @Krishna-kg732, appreciate suggestions and feedback, thanks - gonna apply them 🚀 |
Signed-off-by: SzymonIwaniuk <szymon.iwaniuk@joinmoxie.com>
There was a problem hiding this comment.
Pull request overview
Adds a production container image build plus an automated GitHub Actions pipeline to publish multi-arch images to GHCR, along with Docker run documentation to support in-cluster HTTP deployments of the Kubeflow MCP Server.
Changes:
- Introduces a multi-stage
Dockerfile(builder + slim runtime) running as a non-root user. - Adds a GH Actions workflow to build/push multi-arch images on semver tags (and manual dispatch) and run a post-push Trivy scan.
- Updates
README.mdwith “Run with Docker” instructions and environment variable reference.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| README.md | Adds Docker usage docs and MCP HTTP client config snippet. |
| Dockerfile | Defines multi-stage build and hardened runtime image defaults/entrypoint. |
| .github/workflows/docker-publish.yaml | Adds CI to build/push multi-arch images to GHCR and scan with Trivy. |
| .dockerignore | Reduces Docker build context by excluding dev/test artifacts and tooling files. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Applied all suggestions, let me know WDYT @Krishna-kg732 One thing Copilot flagged: |
|
lgtm, Let’s keep the config surface simple and align with what the code already expects — I’d go with updating the Dockerfile to use |
Signed-off-by: SzymonIwaniuk <szymon.iwaniuk@joinmoxie.com>
|
Done |
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| FROM python:3.12-slim AS builder |
There was a problem hiding this comment.
it seems python:3.12-slim is floating tag here. can we pin to a patch version so two builds don't silently pull different base images?
| push: | ||
| tags: | ||
| - "v*.*.*" | ||
| workflow_dispatch: |
There was a problem hiding this comment.
Looks like there's no PR build path, so a broken Dockerfile would only surface when a release tag is pushed. Would it make sense to add a pull_request trigger with push: false so we at least validate the build on PRs?
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | ||
| tags: | |
There was a problem hiding this comment.
This will tag a v1.0.0-rc.1 as latest too - is that intentional? We could add an enable condition to only update latest on non-prerelease tags:
type=raw,value=latest,enable=${{ github.ref_type == 'tag' && !contains(github.ref_name, '-') }}
| - name: Scan image for critical CVEs (Trivy) | ||
| uses: aquasecurity/trivy-action@0.30.0 | ||
| with: | ||
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} |
There was a problem hiding this comment.
Minor nit - scanning by tag means there's a small window where another concurrent push could overwrite the tag between the build and the scan. Using the digest directly would be safer, wdyt?
fixes #17
Description
Implements a production-ready container image and CI publish pipeline for in-cluster deployment of the Kubeflow MCP Server.
Dockerfile
builder(uv install) ->runtime(python:3.12-slim)kubeflow-mcp(uid 65532) for hardened security.venvcopied to the final image - no compiler, no uv, no sourcekubeflow-mcp serve --transport httpas the default entrypointKUBEFLOW_MCP_AUTH_TOKENandKUBEFLOW_MCP_LOG_FORMAT=jsonconfigurable via envCI Workflow (
.github/workflows/docker-publish.yaml)v*.*.*release tags andworkflow_dispatchlinux/amd64,linux/arm64) via Docker Buildx + QEMUghcr.io/kubeflow/mcp-serverwith semver tags (1.2.3,1.2,1,latest)GITHUB_TOKENCRITICALCVEs after push - fails the release if any are foundDocumentation
README.mdwithdocker runone-liner, full env var reference table, and MCP client config snippet for HTTP transportChecklist
docker build -t kubeflow-mcp:local .succeedsmake verify)cc: @abhijeet-dhumal