diff --git a/claude-code/Dockerfile b/claude-code/Dockerfile new file mode 100644 index 000000000..373427537 --- /dev/null +++ b/claude-code/Dockerfile @@ -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/Dockerfile.arm64 b/claude-code/Dockerfile.arm64 new file mode 120000 index 000000000..1d1fe94df --- /dev/null +++ b/claude-code/Dockerfile.arm64 @@ -0,0 +1 @@ +Dockerfile \ No newline at end of file diff --git a/claude-code/Makefile b/claude-code/Makefile new file mode 100644 index 000000000..5f5b1b4f1 --- /dev/null +++ b/claude-code/Makefile @@ -0,0 +1,29 @@ +ARCH:=$(shell uname -m) +PLATFORM:=$(shell case "$(ARCH)" in \ + ("arm64"|"aarch64") echo "arm64" ;; \ + ("x86_64") echo "amd64" ;; \ + (*) echo $(ARCH) ;; \ +esac) + +.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); \ + if [ -n "$$version" ]; then \ + docker tag chatwork/`basename $$PWD`:latest chatwork/`basename $$PWD`:$$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-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 \ + 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 .; \ + fi diff --git a/claude-code/README.md b/claude-code/README.md new file mode 100644 index 000000000..75a823c59 --- /dev/null +++ b/claude-code/README.md @@ -0,0 +1,49 @@ +# claude-code + +A base Docker image for running [Claude Code](https://claude.ai/code) in containers. Provides the Claude Code CLI and common dependencies pre-installed. + +This image is designed to be used as a base (`FROM chatwork/claude-code`) by teams building their own plugin marketplace runner images, or directly in Kubernetes CronJobs. + +## Usage + +### As a base image + +```dockerfile +FROM chatwork/claude-code:latest + +# Copy your marketplace plugins +COPY . /marketplace +RUN claude plugin marketplace add /marketplace +``` + +### In a Kubernetes CronJob + +```yaml +containers: + - name: task + image: chatwork/claude-code:latest + command: ["/bin/bash", "-lc"] + args: + - | + set -euo pipefail + claude --print "Generate weekly report" +``` + +### Standalone + +``` +$ docker run --rm chatwork/claude-code claude --version +``` + +## Included + +| Category | Tools | +|---|---| +| Core | Claude Code CLI, curl, ca-certificates, git, bash, less | +| Data processing | jq, yq, unzip | +| Cloud / CI | awscli, gh (GitHub CLI), python3 | +| Security | gpg, openssh-client | + +## Version management + +Claude Code CLI version is pinned and automatically updated via [variant mod](https://github.com/variantdev/mod). See `variant.mod` and `variant.lock` for details. diff --git a/claude-code/docker-compose.test.yml b/claude-code/docker-compose.test.yml new file mode 100644 index 000000000..5cfeb3454 --- /dev/null +++ b/claude-code/docker-compose.test.yml @@ -0,0 +1,18 @@ +version: '3' +services: + claude-code: + build: + context: . + image: chatwork/claude-code + sut: + image: chatwork/dgoss:latest + environment: + GOSS_FILES_PATH: /goss + GOSS_FILES_STRATEGY: cp + entrypoint: "" + command: /usr/local/bin/dgoss run --entrypoint '' chatwork/claude-code tail -f /dev/null + container_name: claude-code + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - claude-code diff --git a/claude-code/goss/goss.yaml b/claude-code/goss/goss.yaml new file mode 100644 index 000000000..71db1504f --- /dev/null +++ b/claude-code/goss/goss.yaml @@ -0,0 +1,20 @@ +file: + /home/claude/.local/bin/claude: + exists: true +command: + claude --version: + exit-status: 0 + stdout: + - 2.1.105 + git --version: + exit-status: 0 + jq --version: + exit-status: 0 + python3 --version: + exit-status: 0 + yq --version: + exit-status: 0 + gh --version: + exit-status: 0 + gpg --version: + exit-status: 0 diff --git a/claude-code/hooks/test b/claude-code/hooks/test new file mode 100755 index 000000000..3f97d1157 --- /dev/null +++ b/claude-code/hooks/test @@ -0,0 +1,3 @@ +#!/bin/bash + +make test \ No newline at end of file diff --git a/claude-code/variant.lock b/claude-code/variant.lock new file mode 100644 index 000000000..f16d7610d --- /dev/null +++ b/claude-code/variant.lock @@ -0,0 +1,7 @@ +dependencies: + claude_code: + version: 2.1.105 + previousVersion: 2.1.100 + versions: + - 2.1.100 + - 2.1.105 diff --git a/claude-code/variant.mod b/claude-code/variant.mod new file mode 100644 index 000000000..9f7d5aad3 --- /dev/null +++ b/claude-code/variant.mod @@ -0,0 +1,18 @@ +provisioners: + textReplace: + Dockerfile: + from: "ARG CLAUDE_CODE_VERSION={{ .claude_code.previousVersion }}" + to: "ARG CLAUDE_CODE_VERSION={{ .claude_code.version }}" + goss/goss.yaml: + from: "- {{ .claude_code.previousVersion }}" + to: "- {{ .claude_code.version }}" + +dependencies: + claude_code: + releasesFrom: + exec: + command: bash + args: + - -c + - "curl -s https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest" + version: "> 2.0"