Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,47 @@ release:

dockers:
- image_templates:
- "streamnative/snmcp:{{ .Tag }}"
- "streamnative/snmcp:latest"
- "streamnative/snmcp:{{ .Tag }}-amd64"
- "streamnative/snmcp:latest-amd64"
dockerfile: Dockerfile.goreleaser
goos: linux
goarch: amd64
- image_templates:
- "streamnative/snmcp:{{ .Tag }}-arm64"
- "streamnative/snmcp:latest-arm64"
dockerfile: Dockerfile.goreleaser
goos: linux
goarch: arm64
- image_templates:
- "streamnative/mcp-server:{{ .Tag }}-amd64"
- "streamnative/mcp-server:latest-amd64"
dockerfile: Dockerfile.goreleaser
goos: linux
goarch: amd64
- image_templates:
- "streamnative/mcp-server:{{ .Tag }}-arm64"
- "streamnative/mcp-server:latest-arm64"
dockerfile: Dockerfile.goreleaser
goos: linux
goarch: arm64

docker_manifests:
- name_template: "streamnative/snmcp:{{ .Tag }}"
image_templates:
- "streamnative/snmcp:{{ .Tag }}-amd64"
- "streamnative/snmcp:{{ .Tag }}-arm64"
- name_template: "streamnative/snmcp:latest"
image_templates:
- "streamnative/snmcp:latest-amd64"
- "streamnative/snmcp:latest-arm64"
- name_template: "streamnative/mcp-server:{{ .Tag }}"
image_templates:
- "streamnative/mcp-server:{{ .Tag }}-amd64"
- "streamnative/mcp-server:{{ .Tag }}-arm64"
- name_template: "streamnative/mcp-server:latest"
image_templates:
- "streamnative/mcp-server:latest-amd64"
- "streamnative/mcp-server:latest-arm64"

brews:
- name: snmcp
Expand Down
165 changes: 165 additions & 0 deletions DOCKER_BUILD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Building Multi-Platform Docker Images

This document explains how to build Docker images that work on both Linux and Mac (including M1/M2/M3 Macs).

## Prerequisites

- Docker 19.03 or newer with buildx support
- Docker buildx plugin enabled

## Quick Start

### Build for Local Platform

To build a Docker image for your current platform:

```bash
make docker-build
```

This creates images with both names for backward compatibility:
- `docker.io/streamnative/mcp-server:latest`
- `docker.io/streamnative/mcp-server:<git-version>`
- `docker.io/streamnative/snmcp:latest` (legacy name)
- `docker.io/streamnative/snmcp:<git-version>` (legacy name)

### Build Multi-Platform Images

To build images for both Linux (amd64) and Mac (arm64):

```bash
make docker-build-multiplatform
```

### Build and Push to Registry

To build multi-platform images and push them to a registry:

```bash
make docker-build-push
```

## Customization

You can customize the build using environment variables:

```bash
# Use custom registry
DOCKER_REGISTRY=myregistry.io make docker-build-push

# Use custom image names
DOCKER_IMAGE=my-mcp-server DOCKER_IMAGE_LEGACY=my-snmcp make docker-build

# Build for specific platforms
DOCKER_PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7" make docker-build-multiplatform
```

## Platform Support

By default, images are built for:
- `linux/amd64` - Intel/AMD 64-bit processors (most Linux servers and older Macs)
- `linux/arm64` - ARM 64-bit processors (Apple Silicon Macs, ARM-based servers)

## Running the Image

You can use either `mcp-server` or `snmcp` image names - they are identical:

### On Linux (amd64/x86_64)

```bash
# Using the new name
docker run --rm -it docker.io/streamnative/mcp-server:latest

# Using the legacy name (backward compatibility)
docker run --rm -it docker.io/streamnative/snmcp:latest
```

### On Mac (Intel)

```bash
# Using the new name
docker run --rm -it docker.io/streamnative/mcp-server:latest

# Using the legacy name (backward compatibility)
docker run --rm -it docker.io/streamnative/snmcp:latest
```

### On Mac (Apple Silicon M1/M2/M3)

```bash
# Using the new name
docker run --rm -it --platform linux/arm64 docker.io/streamnative/mcp-server:latest

# Using the legacy name (backward compatibility)
docker run --rm -it --platform linux/arm64 docker.io/streamnative/snmcp:latest
```

## Image Names

For backward compatibility, all builds create images with two names:
- `streamnative/mcp-server` - The new, preferred name
- `streamnative/snmcp` - The legacy name for backward compatibility

Both names point to the exact same image and can be used interchangeably.

## Troubleshooting

### Enable Docker Buildx

If buildx is not available, enable it:

```bash
# Check if buildx is available
docker buildx version

# Create and use a new builder
docker buildx create --use
```

### Clean Build Environment

If you encounter issues, clean the buildx environment:

```bash
make docker-buildx-clean
make docker-buildx-setup
```

## Build Arguments

The Dockerfile accepts the following build arguments:
- `VERSION` - Version string for the binary
- `COMMIT` - Git commit hash
- `BUILD_DATE` - Build timestamp

These are automatically set by the Makefile based on git information.

## Security

The Docker image:
- Runs as a non-root user (uid: 1000, gid: 1000)
- Uses minimal Alpine Linux base image
- Includes only necessary CA certificates for HTTPS connections
- Has a read-only root filesystem (can be enforced with `--read-only` flag)

## Example: Complete Build and Run

```bash
# Setup buildx (first time only)
make docker-buildx-setup

# Build multi-platform image (creates both mcp-server and snmcp tags)
make docker-build-multiplatform

# Run on current platform (using new name)
docker run --rm -it docker.io/streamnative/mcp-server:latest

# Run on current platform (using legacy name)
docker run --rm -it docker.io/streamnative/snmcp:latest

# Run with custom configuration
docker run --rm -it \
-v $(pwd)/config.yaml:/server/config.yaml:ro \
docker.io/streamnative/mcp-server:latest \
--config /server/config.yaml
```
56 changes: 55 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,60 @@
# Multi-stage build for multi-platform support
FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder

# Install build dependencies
RUN apk add --no-cache git make

# Set working directory
WORKDIR /build

# Copy go mod files and SDK directories first
COPY go.mod go.sum go.work go.work.sum ./
COPY sdk/ ./sdk/

# Download dependencies
RUN go mod download

# Copy source code
COPY . .

# Build arguments for cross-compilation
ARG TARGETOS
ARG TARGETARCH
ARG VERSION
ARG COMMIT
ARG BUILD_DATE

# Build the binary for the target platform
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -ldflags "\
-X main.version=${VERSION} \
-X main.commit=${COMMIT} \
-X main.date=${BUILD_DATE}" \
-o snmcp cmd/streamnative-mcp-server/main.go

# Final stage - minimal Alpine image
FROM alpine:3.21

# Install CA certificates for HTTPS connections
RUN apk --no-cache add ca-certificates

# Create non-root user
RUN addgroup -g 1000 snmcp && \
adduser -D -u 1000 -G snmcp snmcp

# Set working directory
WORKDIR /server
COPY snmcp /server/snmcp

# Copy binary from builder
COPY --from=builder /build/snmcp /server/snmcp

# Change ownership
RUN chown -R snmcp:snmcp /server

# Switch to non-root user
USER snmcp

# Expose port if needed (adjust based on your application)
# EXPOSE 8080

ENTRYPOINT ["/server/snmcp"]
29 changes: 29 additions & 0 deletions Dockerfile.goreleaser
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Minimal Alpine image for GoReleaser builds
FROM alpine:3.21

# Install CA certificates for HTTPS connections
RUN apk --no-cache add ca-certificates

# Create non-root user
RUN addgroup -g 1000 snmcp && \
adduser -D -u 1000 -G snmcp snmcp

# Set working directory
WORKDIR /server

# Copy pre-built binary from GoReleaser
COPY snmcp /server/snmcp

# Make binary executable
RUN chmod +x /server/snmcp

# Change ownership
RUN chown -R snmcp:snmcp /server

# Switch to non-root user
USER snmcp

# Expose port if needed (adjust based on your application)
# EXPOSE 8080

ENTRYPOINT ["/server/snmcp"]
65 changes: 65 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ GIT_COMMIT=$(shell git rev-parse HEAD)
BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
MKDIR_P = mkdir -p

# Docker configuration
DOCKER_REGISTRY ?= docker.io
DOCKER_IMAGE ?= streamnative/mcp-server
DOCKER_IMAGE_LEGACY ?= streamnative/snmcp
DOCKER_TAG ?= $(GIT_VERSION)
DOCKER_PLATFORMS ?= linux/amd64,linux/arm64

export GOPRIVATE=github.com/streamnative

.PHONY: all
Expand All @@ -19,6 +26,64 @@ build:
-X ${VERSION_PATH}.date=${BUILD_DATE}" \
-o bin/snmcp cmd/streamnative-mcp-server/main.go

# Build Docker image for local platform with both names
.PHONY: docker-build
docker-build:
docker build \
--build-arg VERSION=$(GIT_VERSION) \
--build-arg COMMIT=$(GIT_COMMIT) \
--build-arg BUILD_DATE=$(BUILD_DATE) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE):$(DOCKER_TAG) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE):latest \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_LEGACY):$(DOCKER_TAG) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_LEGACY):latest \
.

# Build multi-platform Docker image and push to registry with both names
.PHONY: docker-build-push
docker-build-push: docker-buildx-setup
docker buildx build \
--platform $(DOCKER_PLATFORMS) \
--build-arg VERSION=$(GIT_VERSION) \
--build-arg COMMIT=$(GIT_COMMIT) \
--build-arg BUILD_DATE=$(BUILD_DATE) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE):$(DOCKER_TAG) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE):latest \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_LEGACY):$(DOCKER_TAG) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_LEGACY):latest \
--push \
.

# Build multi-platform Docker image without pushing (for testing) with both names
.PHONY: docker-build-multiplatform
docker-build-multiplatform: docker-buildx-setup
docker buildx build \
--platform $(DOCKER_PLATFORMS) \
--build-arg VERSION=$(GIT_VERSION) \
--build-arg COMMIT=$(GIT_COMMIT) \
--build-arg BUILD_DATE=$(BUILD_DATE) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE):$(DOCKER_TAG) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE):latest \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_LEGACY):$(DOCKER_TAG) \
-t $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_LEGACY):latest \
--load \
.

# Setup Docker buildx for multi-platform builds
.PHONY: docker-buildx-setup
docker-buildx-setup:
@if ! docker buildx ls | grep -q mcp-builder; then \
docker buildx create --name mcp-builder --use; \
docker buildx inspect --bootstrap; \
else \
docker buildx use mcp-builder; \
fi

# Clean Docker buildx builder
.PHONY: docker-buildx-clean
docker-buildx-clean:
-docker buildx rm mcp-builder

.PHONY: license-check
license-check:
license-eye header check
Expand Down