From 9da47101af18a92ea73709ee3115a62cfea67d76 Mon Sep 17 00:00:00 2001 From: Tasuku Yamashita Date: Tue, 14 Apr 2026 14:33:48 +0900 Subject: [PATCH 1/2] Use native-only push with manifest integration The previous Makefile cross-built both amd64 and arm64 via QEMU in the push target, which caused py3compile segfaults due to QEMU bugs (actions/runner-images#11542). Switch to native-only push per runner, with manifest:push to merge arch-specific tags into a multi-arch manifest. This matches the CI workflow's intended design (separate push jobs + manifest job). - Dockerfile.arm64: convert from symlink to real file (triggers manifest job) - Makefile: push uses native PLATFORM only, add manifest:push/succeed-message - goss: add aws --version test Ref: https://github.com/chatwork/dockerfiles/actions/runs/24380489874/job/71208405664 Co-Authored-By: Claude Opus 4.6 (1M context) --- claude-code/Dockerfile.arm64 | 45 +++++++++++++++++++++++++++++++++++- claude-code/Makefile | 43 ++++++++++++++++++++++++++++------ claude-code/goss/goss.yaml | 2 ++ 3 files changed, 82 insertions(+), 8 deletions(-) mode change 120000 => 100644 claude-code/Dockerfile.arm64 diff --git a/claude-code/Dockerfile.arm64 b/claude-code/Dockerfile.arm64 deleted file mode 120000 index 1d1fe94df..000000000 --- a/claude-code/Dockerfile.arm64 +++ /dev/null @@ -1 +0,0 @@ -Dockerfile \ No newline at end of file diff --git a/claude-code/Dockerfile.arm64 b/claude-code/Dockerfile.arm64 new file mode 100644 index 000000000..373427537 --- /dev/null +++ b/claude-code/Dockerfile.arm64 @@ -0,0 +1,44 @@ +FROM debian:bookworm-slim + +ARG CLAUDE_CODE_VERSION=2.1.105 + +LABEL version="${CLAUDE_CODE_VERSION}" + +# Common dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + git \ + jq \ + unzip \ + python3 \ + awscli \ + gpg \ + openssh-client \ + bash \ + less \ + && rm -rf /var/lib/apt/lists/* + +# yq (latest) +RUN curl -fsSL "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_$(dpkg --print-architecture)" \ + -o /usr/local/bin/yq \ + && chmod +x /usr/local/bin/yq + +# GitHub CLI +RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + -o /usr/share/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ + > /etc/apt/sources.list.d/github-cli.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends gh \ + && rm -rf /var/lib/apt/lists/* + +# Non-root user +RUN useradd -m -s /bin/bash claude +USER claude +ENV HOME=/home/claude +ENV PATH="/home/claude/.local/bin:${PATH}" +WORKDIR /home/claude + +# Claude Code CLI (Native Install) +RUN curl -fsSL https://claude.ai/install.sh | bash -s "${CLAUDE_CODE_VERSION}" diff --git a/claude-code/Makefile b/claude-code/Makefile index 5f5b1b4f1..fc64825b8 100644 --- a/claude-code/Makefile +++ b/claude-code/Makefile @@ -1,29 +1,58 @@ ARCH:=$(shell uname -m) +TAG:=$(shell case "$(ARCH)" in \ + ("arm64"|"aarch64") echo "arm64" ;; \ + ("x86_64") echo "x86_64" ;; \ + (*) echo $(ARCH) ;; \ +esac) PLATFORM:=$(shell case "$(ARCH)" in \ ("arm64"|"aarch64") echo "arm64" ;; \ ("x86_64") echo "amd64" ;; \ (*) echo $(ARCH) ;; \ esac) +IMAGE_NAME:=claude-code .PHONY: build build: - @docker buildx build -t chatwork/`basename $$PWD`:latest --platform linux/${PLATFORM} -f Dockerfile --load .; \ - version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/`basename $$PWD`:latest); \ + @docker buildx build -t chatwork/${IMAGE_NAME}:latest --platform linux/${PLATFORM} -f Dockerfile --load .; \ + version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ if [ -n "$$version" ]; then \ - docker tag chatwork/`basename $$PWD`:latest chatwork/`basename $$PWD`:$$version; \ + docker tag chatwork/${IMAGE_NAME}:latest chatwork/${IMAGE_NAME}:$$version; \ fi .PHONY: test test: build docker-compose -f docker-compose.test.yml up --no-start sut - docker cp $(shell pwd)/goss `basename $$PWD`:/goss + docker cp $(shell pwd)/goss ${IMAGE_NAME}:/goss docker-compose -f docker-compose.test.yml up --no-recreate --exit-code-from sut sut .PHONY: push push: - @version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/`basename $$PWD`:latest); \ - if docker inspect --format='{{index .RepoDigests 0}}' chatwork/$$(basename $$PWD):$$version >/dev/null 2>&1; then \ + @version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ + if docker inspect --format='{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version-$(TAG) >/dev/null 2>&1; then \ + echo "no changes"; \ + else \ + docker buildx build -t chatwork/${IMAGE_NAME}:$$version-$(TAG) --platform linux/${PLATFORM} -f Dockerfile --push .; \ + fi + +.PHONY: manifest\:push +manifest\:push: + @version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ + if docker inspect --format='{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version >/dev/null 2>&1; then \ echo "no changes"; \ else \ - docker buildx build -t chatwork/`basename $$PWD`:$$version -t chatwork/`basename $$PWD`:latest --platform linux/amd64,linux/arm64 -f Dockerfile --push .; \ + docker pull chatwork/${IMAGE_NAME}:$$version-aarch64; \ + docker pull chatwork/${IMAGE_NAME}:$$version-x86_64; \ + arm64_digest=$$(docker inspect -f '{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version-aarch64); \ + amd64_digest=$$(docker inspect -f '{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version-x86_64); \ + docker buildx imagetools create -t chatwork/${IMAGE_NAME}:$$version $$arm64_digest $$amd64_digest; \ + docker buildx imagetools create -t chatwork/${IMAGE_NAME}:latest $$arm64_digest $$amd64_digest; \ + hub-tool tag rm chatwork/${IMAGE_NAME}:$$version-aarch64 -f; \ + hub-tool tag rm chatwork/${IMAGE_NAME}:$$version-x86_64 -f; \ fi + +.PHONY: manifest\:succeed-message +manifest\:succeed-message: + @version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ + echo "Released new tags."; \ + echo "- chatwork/${IMAGE_NAME}:$$version"; \ + echo "- chatwork/${IMAGE_NAME}:latest" diff --git a/claude-code/goss/goss.yaml b/claude-code/goss/goss.yaml index 71db1504f..49b3904da 100644 --- a/claude-code/goss/goss.yaml +++ b/claude-code/goss/goss.yaml @@ -18,3 +18,5 @@ command: exit-status: 0 gpg --version: exit-status: 0 + aws --version: + exit-status: 0 From 9bb5c5557168bb605b50e8e9ec5bade8a6dd7b51 Mon Sep 17 00:00:00 2001 From: Tasuku Yamashita Date: Tue, 21 Apr 2026 13:27:40 +0900 Subject: [PATCH 2/2] Fix arch suffix mismatch between push and manifest:push push used $(TAG) (arm64/x86_64) while manifest:push pulled aarch64/x86_64, causing a mismatch on ARM builds. Introduce an image_ref function and shared arch suffix variables so both targets construct references through a single source of truth. Co-Authored-By: Claude Opus 4.7 (1M context) --- claude-code/Makefile | 57 ++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/claude-code/Makefile b/claude-code/Makefile index fc64825b8..3edd4f0a4 100644 --- a/claude-code/Makefile +++ b/claude-code/Makefile @@ -1,58 +1,63 @@ ARCH:=$(shell uname -m) -TAG:=$(shell case "$(ARCH)" in \ - ("arm64"|"aarch64") echo "arm64" ;; \ - ("x86_64") echo "x86_64" ;; \ - (*) echo $(ARCH) ;; \ -esac) PLATFORM:=$(shell case "$(ARCH)" in \ ("arm64"|"aarch64") echo "arm64" ;; \ ("x86_64") echo "amd64" ;; \ (*) echo $(ARCH) ;; \ esac) -IMAGE_NAME:=claude-code + +ARM64_SUFFIX:=aarch64 +AMD64_SUFFIX:=x86_64 +SUFFIX:=$(shell case "$(ARCH)" in \ + ("arm64"|"aarch64") echo "$(ARM64_SUFFIX)" ;; \ + ("x86_64") echo "$(AMD64_SUFFIX)" ;; \ + (*) echo $(ARCH) ;; \ +esac) + +# $(call image_ref,version,suffix) -> chatwork/claude-code:[-] +image_ref=chatwork/claude-code:$(1)$(if $(2),-$(2)) .PHONY: build build: - @docker buildx build -t chatwork/${IMAGE_NAME}:latest --platform linux/${PLATFORM} -f Dockerfile --load .; \ - version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ + @docker buildx build -t $(call image_ref,latest) --platform linux/${PLATFORM} -f Dockerfile --load .; \ + version=$$(docker inspect -f {{.Config.Labels.version}} $(call image_ref,latest)); \ if [ -n "$$version" ]; then \ - docker tag chatwork/${IMAGE_NAME}:latest chatwork/${IMAGE_NAME}:$$version; \ + docker tag $(call image_ref,latest) $(call image_ref,$$version); \ fi .PHONY: test test: build docker-compose -f docker-compose.test.yml up --no-start sut - docker cp $(shell pwd)/goss ${IMAGE_NAME}:/goss + docker cp $(shell pwd)/goss claude-code:/goss docker-compose -f docker-compose.test.yml up --no-recreate --exit-code-from sut sut .PHONY: push push: - @version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ - if docker inspect --format='{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version-$(TAG) >/dev/null 2>&1; then \ + @version=$$(docker inspect -f {{.Config.Labels.version}} $(call image_ref,latest)); \ + if docker inspect --format='{{index .RepoDigests 0}}' $(call image_ref,$$version,$(SUFFIX)) >/dev/null 2>&1; then \ echo "no changes"; \ else \ - docker buildx build -t chatwork/${IMAGE_NAME}:$$version-$(TAG) --platform linux/${PLATFORM} -f Dockerfile --push .; \ + docker buildx build -t $(call image_ref,$$version,$(SUFFIX)) --platform linux/${PLATFORM} -f Dockerfile --push .; \ fi .PHONY: manifest\:push manifest\:push: - @version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ - if docker inspect --format='{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version >/dev/null 2>&1; then \ + @version=$$(docker inspect -f {{.Config.Labels.version}} $(call image_ref,latest)); \ + if docker inspect --format='{{index .RepoDigests 0}}' $(call image_ref,$$version) >/dev/null 2>&1; then \ echo "no changes"; \ else \ - docker pull chatwork/${IMAGE_NAME}:$$version-aarch64; \ - docker pull chatwork/${IMAGE_NAME}:$$version-x86_64; \ - arm64_digest=$$(docker inspect -f '{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version-aarch64); \ - amd64_digest=$$(docker inspect -f '{{index .RepoDigests 0}}' chatwork/${IMAGE_NAME}:$$version-x86_64); \ - docker buildx imagetools create -t chatwork/${IMAGE_NAME}:$$version $$arm64_digest $$amd64_digest; \ - docker buildx imagetools create -t chatwork/${IMAGE_NAME}:latest $$arm64_digest $$amd64_digest; \ - hub-tool tag rm chatwork/${IMAGE_NAME}:$$version-aarch64 -f; \ - hub-tool tag rm chatwork/${IMAGE_NAME}:$$version-x86_64 -f; \ + docker pull $(call image_ref,$$version,$(ARM64_SUFFIX)); \ + docker pull $(call image_ref,$$version,$(AMD64_SUFFIX)); \ + arm64_digest=$$(docker inspect -f '{{index .RepoDigests 0}}' $(call image_ref,$$version,$(ARM64_SUFFIX))); \ + amd64_digest=$$(docker inspect -f '{{index .RepoDigests 0}}' $(call image_ref,$$version,$(AMD64_SUFFIX))); \ + docker buildx imagetools create -t $(call image_ref,$$version) $$arm64_digest $$amd64_digest; \ + docker buildx imagetools create -t $(call image_ref,latest) $$arm64_digest $$amd64_digest; \ + hub-tool tag rm $(call image_ref,$$version,$(ARM64_SUFFIX)) -f; \ + hub-tool tag rm $(call image_ref,$$version,$(AMD64_SUFFIX)) -f; \ fi .PHONY: manifest\:succeed-message manifest\:succeed-message: - @version=$$(docker inspect -f {{.Config.Labels.version}} chatwork/${IMAGE_NAME}:latest); \ + @version=$$(docker inspect -f {{.Config.Labels.version}} $(call image_ref,latest)); \ echo "Released new tags."; \ - echo "- chatwork/${IMAGE_NAME}:$$version"; \ - echo "- chatwork/${IMAGE_NAME}:latest" + echo "- $(call image_ref,$$version)"; \ + echo "- $(call image_ref,latest)"