diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 82286ec3..16f25bf5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -24,6 +24,12 @@ jobs: with: go-version-file: go.mod + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GHCR uses: docker/login-action@v3 with: @@ -40,21 +46,14 @@ jobs: echo "version=main" >> "$GITHUB_OUTPUT" fi - - name: Build images - env: - VERSION: ${{ steps.version.outputs.version }} - run: make image VERSION="$VERSION" - - - name: Push images + - name: Build and push images env: VERSION: ${{ steps.version.outputs.version }} - run: make push VERSION="$VERSION" + run: make image-multiarch VERSION="$VERSION" - name: Push latest tags for releases if: startsWith(github.ref, 'refs/tags/v') - run: | - make image VERSION=latest - make push VERSION=latest + run: make image-multiarch VERSION=latest - name: Build CLI binaries if: startsWith(github.ref, 'refs/tags/v') diff --git a/Makefile b/Makefile index 19a60ac1..df68540a 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ REGISTRY ?= ghcr.io/kelos-dev VERSION ?= latest IMAGE_DIRS ?= cmd/kelos-controller cmd/kelos-spawner cmd/kelos-token-refresher claude-code codex gemini opencode cursor +LOCAL_ARCH ?= $(shell go env GOARCH) # Version injection for the kelos CLI – only set ldflags when an explicit # version is given so that dev builds fall through to runtime/debug info. @@ -80,13 +81,16 @@ run: ## Run a controller from your host. go run ./cmd/kelos-controller .PHONY: image -image: ## Build docker images (use WHAT to build specific image). +image: ## Build docker images for the local platform (use WHAT to build specific image). @for dir in $(filter cmd/%,$(or $(WHAT),$(IMAGE_DIRS))); do \ - GOOS=linux GOARCH=amd64 $(MAKE) build WHAT=$$dir; \ + name=$$(basename $$dir); \ + GOOS=linux GOARCH=$(LOCAL_ARCH) $(MAKE) build WHAT=$$dir; \ + cp bin/$$name bin/$${name}-linux-$(LOCAL_ARCH); \ done - @GOOS=linux GOARCH=amd64 $(MAKE) build WHAT=cmd/kelos-capture + @GOOS=linux GOARCH=$(LOCAL_ARCH) $(MAKE) build WHAT=cmd/kelos-capture + @cp bin/kelos-capture bin/kelos-capture-linux-$(LOCAL_ARCH) @for dir in $(or $(WHAT),$(IMAGE_DIRS)); do \ - docker build -t $(REGISTRY)/$$(basename $$dir):$(VERSION) -f $$dir/Dockerfile .; \ + docker build -t $(REGISTRY)/$$(basename $$dir):$(VERSION) -f $$dir/Dockerfile . --build-arg TARGETARCH=$(LOCAL_ARCH); \ done .PHONY: push @@ -95,6 +99,28 @@ push: ## Push docker images (use WHAT to push specific image). docker push $(REGISTRY)/$$(basename $$dir):$(VERSION); \ done +IMAGE_PLATFORMS ?= linux/amd64,linux/arm64 +IMAGE_ARCHES = $(shell echo "$(IMAGE_PLATFORMS)" | tr ',' '\n' | cut -d'/' -f2 | tr '\n' ' ') + +.PHONY: image-multiarch +image-multiarch: ## Build and push multi-platform docker images via buildx (use WHAT to build specific image). + @for dir in $(filter cmd/%,$(or $(WHAT),$(IMAGE_DIRS))); do \ + name=$$(basename $$dir); \ + for arch in $(IMAGE_ARCHES); do \ + GOOS=linux GOARCH=$$arch $(MAKE) build WHAT=$$dir; \ + mv bin/$$name bin/$${name}-linux-$$arch; \ + done; \ + done + @for arch in $(IMAGE_ARCHES); do \ + GOOS=linux GOARCH=$$arch $(MAKE) build WHAT=cmd/kelos-capture; \ + mv bin/kelos-capture bin/kelos-capture-linux-$$arch; \ + done + @for dir in $(or $(WHAT),$(IMAGE_DIRS)); do \ + docker buildx build --platform $(IMAGE_PLATFORMS) \ + -t $(REGISTRY)/$$(basename $$dir):$(VERSION) \ + -f $$dir/Dockerfile . --push; \ + done + RELEASE_PLATFORMS ?= linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 .PHONY: release-binaries diff --git a/claude-code/Dockerfile b/claude-code/Dockerfile index 6e3352ef..de507c2c 100644 --- a/claude-code/Dockerfile +++ b/claude-code/Dockerfile @@ -33,7 +33,8 @@ RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION} COPY claude-code/kelos_entrypoint.sh /kelos_entrypoint.sh RUN chmod +x /kelos_entrypoint.sh -COPY bin/kelos-capture /kelos/kelos-capture +ARG TARGETARCH +COPY bin/kelos-capture-linux-${TARGETARCH} /kelos/kelos-capture RUN useradd -u 61100 -m -s /bin/bash claude RUN mkdir -p /home/claude/.claude && chown -R claude:claude /home/claude diff --git a/cmd/kelos-controller/Dockerfile b/cmd/kelos-controller/Dockerfile index bbe8cb11..2cefe1d5 100644 --- a/cmd/kelos-controller/Dockerfile +++ b/cmd/kelos-controller/Dockerfile @@ -1,5 +1,6 @@ FROM gcr.io/distroless/static:nonroot +ARG TARGETARCH WORKDIR / -COPY bin/kelos-controller . +COPY bin/kelos-controller-linux-${TARGETARCH} kelos-controller USER 65532:65532 ENTRYPOINT ["/kelos-controller"] diff --git a/cmd/kelos-spawner/Dockerfile b/cmd/kelos-spawner/Dockerfile index a1851bc0..7c9bcdd8 100644 --- a/cmd/kelos-spawner/Dockerfile +++ b/cmd/kelos-spawner/Dockerfile @@ -1,5 +1,6 @@ FROM gcr.io/distroless/static:nonroot +ARG TARGETARCH WORKDIR / -COPY bin/kelos-spawner . +COPY bin/kelos-spawner-linux-${TARGETARCH} kelos-spawner USER 65532:65532 ENTRYPOINT ["/kelos-spawner"] diff --git a/codex/Dockerfile b/codex/Dockerfile index 397dd250..cb6636dc 100644 --- a/codex/Dockerfile +++ b/codex/Dockerfile @@ -33,7 +33,8 @@ RUN npm install -g @openai/codex@${CODEX_VERSION} COPY codex/kelos_entrypoint.sh /kelos_entrypoint.sh RUN chmod +x /kelos_entrypoint.sh -COPY bin/kelos-capture /kelos/kelos-capture +ARG TARGETARCH +COPY bin/kelos-capture-linux-${TARGETARCH} /kelos/kelos-capture RUN useradd -u 61100 -m -s /bin/bash agent RUN mkdir -p /home/agent/.codex && chown -R agent:agent /home/agent diff --git a/cursor/Dockerfile b/cursor/Dockerfile index 4bd0f8ae..08b8b665 100644 --- a/cursor/Dockerfile +++ b/cursor/Dockerfile @@ -30,7 +30,8 @@ ENV PATH="/usr/local/go/bin:${PATH}" COPY cursor/kelos_entrypoint.sh /kelos_entrypoint.sh RUN chmod +x /kelos_entrypoint.sh -COPY bin/kelos-capture /kelos/kelos-capture +ARG TARGETARCH +COPY bin/kelos-capture-linux-${TARGETARCH} /kelos/kelos-capture RUN useradd -u 61100 -m -s /bin/bash agent RUN mkdir -p /home/agent/.cursor && chown -R agent:agent /home/agent diff --git a/gemini/Dockerfile b/gemini/Dockerfile index 5e7380f3..78b44b75 100644 --- a/gemini/Dockerfile +++ b/gemini/Dockerfile @@ -33,7 +33,8 @@ RUN npm install -g @google/gemini-cli@${GEMINI_CLI_VERSION} COPY gemini/kelos_entrypoint.sh /kelos_entrypoint.sh RUN chmod +x /kelos_entrypoint.sh -COPY bin/kelos-capture /kelos/kelos-capture +ARG TARGETARCH +COPY bin/kelos-capture-linux-${TARGETARCH} /kelos/kelos-capture RUN useradd -u 61100 -m -s /bin/bash agent RUN mkdir -p /home/agent/.gemini && chown -R agent:agent /home/agent diff --git a/opencode/Dockerfile b/opencode/Dockerfile index f102c18a..14e41b2b 100644 --- a/opencode/Dockerfile +++ b/opencode/Dockerfile @@ -33,7 +33,8 @@ RUN npm install -g opencode-ai@${OPENCODE_VERSION} COPY opencode/kelos_entrypoint.sh /kelos_entrypoint.sh RUN chmod +x /kelos_entrypoint.sh -COPY bin/kelos-capture /kelos/kelos-capture +ARG TARGETARCH +COPY bin/kelos-capture-linux-${TARGETARCH} /kelos/kelos-capture RUN useradd -u 61100 -m -s /bin/bash agent RUN mkdir -p /home/agent/.opencode && chown -R agent:agent /home/agent