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
25 changes: 25 additions & 0 deletions .gitlab/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# Runner: docker executor + privileged dind (see [runners.docker] privileged = true).
#
# CI job images from ACR (${ACR_REGISTRY}/opencsg_public/...) to avoid Docker Hub timeouts.
# Dockerfile builder/runtime bases use opencsghq ACR mirrors that preserve the
# upstream multi-arch indexes for linux/amd64 and linux/arm64.
#
# Required CI/CD variables:
# ACR_REGISTRY, ACR_USERNAME, ACR_PASSWORD
Expand Down Expand Up @@ -32,6 +34,7 @@ variables:
DOCKER_BUILDKIT: "1"
BUILDX_NO_DEFAULT_ATTESTATIONS: "1"
DOCKER_PLATFORMS: "linux/amd64,linux/arm64"
RUNTIME_ALPINE_BASE_IMAGE: "opencsg-registry.cn-beijing.cr.aliyuncs.com/opencsghq/alpine:3.23"
BINFMT_IMAGE: "${ACR_REGISTRY}/opencsg_public/binfmt:latest"
BUILDKIT_CI_IMAGE: "${ACR_REGISTRY}/opencsg_public/moby-buildkit:buildx-stable-1"

Expand All @@ -53,6 +56,7 @@ docker-build-push:
- docker/csgclaw-cli/**/*
- docker/csgclaw-cli/*
- docker/Dockerfile
- .gitlab/ci.yml
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
Expand All @@ -76,16 +80,37 @@ docker-build-push:
- docker buildx rm "${BUILDX_BUILDER}" 2>/dev/null || true
- echo "BuildKit image for buildx driver ${BUILDKIT_CI_IMAGE}"
- docker buildx create --name "${BUILDX_BUILDER}" --driver docker-container --driver-opt "image=${BUILDKIT_CI_IMAGE}" --bootstrap --use
- |
set -euo pipefail
echo "Checking runtime base image platforms: ${RUNTIME_ALPINE_BASE_IMAGE}"
docker buildx imagetools inspect "${RUNTIME_ALPINE_BASE_IMAGE}" | tee /tmp/runtime-alpine-manifest.txt
grep -Eq 'Platform:[[:space:]]+linux/amd64' /tmp/runtime-alpine-manifest.txt
grep -Eq 'Platform:[[:space:]]+linux/arm64' /tmp/runtime-alpine-manifest.txt
script:
- |
set -euo pipefail
docker buildx build \
--platform "${DOCKER_PLATFORMS}" \
-f docker/Dockerfile \
--build-arg "RUNTIME_ALPINE_BASE_IMAGE=${RUNTIME_ALPINE_BASE_IMAGE}" \
-t "${DOCKER_IMAGE}:${IMAGE_TAG}" \
--provenance=false \
--sbom=false \
--push \
.
- |
set -euo pipefail
docker buildx imagetools inspect "${DOCKER_IMAGE}:${IMAGE_TAG}"
for entry in "linux/amd64:x86_64" "linux/arm64:aarch64"; do
platform="${entry%%:*}"
expected_arch="${entry##*:}"
echo "Validating ${DOCKER_IMAGE}:${IMAGE_TAG} on ${platform}"
docker run --rm --platform "${platform}" --entrypoint /bin/sh "${DOCKER_IMAGE}:${IMAGE_TAG}" -ec "
test \"\$(uname -m)\" = \"${expected_arch}\"
/sbin/tini --version >/dev/null
/usr/local/bin/picoclaw version >/dev/null
/usr/local/bin/csgclaw-cli --help >/dev/null
"
done
after_script:
- docker buildx rm "picoclaw-mx-${CI_PIPELINE_ID}" 2>/dev/null || true
38 changes: 28 additions & 10 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# Base images mirrored to ACR (opencsg_public) so CI can pull without Docker Hub.
# Host: opencsg-registry.cn-beijing.cr.aliyuncs.com — push local pulls with:
# docker tag golang:1.25-alpine .../opencsg_public/golang:1.25-alpine
# docker tag alpine:3.23 .../opencsg_public/alpine:3.23
# Base images mirrored to ACR (opencsghq) with full upstream multi-arch indexes
# so CI can pull without Docker Hub while preserving linux/amd64 and linux/arm64.
#
ARG RUNTIME_ALPINE_BASE_IMAGE=opencsg-registry.cn-beijing.cr.aliyuncs.com/opencsghq/alpine:3.23

# ============================================================
# Stage 1: Build the picoclaw binary
# ============================================================
FROM opencsg-registry.cn-beijing.cr.aliyuncs.com/opencsg_public/golang:1.25-alpine AS builder
FROM --platform=$BUILDPLATFORM opencsg-registry.cn-beijing.cr.aliyuncs.com/opencsghq/golang:1.25-alpine AS builder
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT

# Alpine apk: use Aliyun mirror instead of dl-cdn (often slow or flaky in mainland CN).
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
Expand All @@ -26,30 +29,45 @@ RUN go mod download

# Copy source and build
COPY . .
RUN make build
RUN set -eux; \
targetos="${TARGETOS:-linux}"; \
targetarch="${TARGETARCH:-$(go env GOARCH)}"; \
case "${targetarch}/${TARGETVARIANT:-}" in \
arm/v*) export GOARM="${TARGETVARIANT#v}" ;; \
esac; \
make build GO="CGO_ENABLED=0 GOOS=${targetos} GOARCH=${targetarch} go" PLATFORM="${targetos}" ARCH="${targetarch}"

# ============================================================
# Stage 1.5: Download platform-specific csgclaw-cli release tarball
# ============================================================
FROM opencsg-registry.cn-beijing.cr.aliyuncs.com/opencsg_public/alpine:3.23 AS csgclaw-cli
FROM --platform=$BUILDPLATFORM opencsg-registry.cn-beijing.cr.aliyuncs.com/opencsghq/alpine:3.23 AS csgclaw-cli
ARG TARGETARCH
# Override to pin a release, e.g. https://csgclaw.opencsg.com/releases/v1.0.0
ARG CSGCLAW_CLI_BASE_URL=https://csgclaw.opencsg.com/releases/latest
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add --no-cache ca-certificates curl \
&& curl -fSL "${CSGCLAW_CLI_BASE_URL}/linux/${TARGETARCH}?package=csgclaw-cli" -o /tmp/csgclaw-cli.tar.gz \
&& set -eu; \
arch="${TARGETARCH:-}"; \
if [ -z "$arch" ]; then \
case "$(uname -m)" in \
x86_64) arch=amd64 ;; \
aarch64) arch=arm64 ;; \
*) echo "unsupported build arch: $(uname -m)" >&2; exit 1 ;; \
esac; \
fi; \
curl -fSL "${CSGCLAW_CLI_BASE_URL}/linux/${arch}?package=csgclaw-cli" -o /tmp/csgclaw-cli.tar.gz \
&& mkdir -p /tmp/extract \
&& tar -xzf /tmp/csgclaw-cli.tar.gz -C /tmp/extract \
&& set -eu; \
bin="$(find /tmp/extract -type f \( -name csgclaw-cli -o -name "csgclaw-cli_linux_${TARGETARCH}" \) | head -n1)"; \
bin="$(find /tmp/extract -type f \( -name csgclaw-cli -o -name "csgclaw-cli_linux_${arch}" \) | head -n1)"; \
if [ -z "$bin" ]; then bin="$(find /tmp/extract -type f -perm -111 | head -n1)"; fi; \
if [ -z "$bin" ]; then echo "csgclaw-cli binary not found in archive"; ls -laR /tmp/extract; exit 1; fi; \
install -m0755 "$bin" /csgclaw-cli

# ============================================================
# Stage 2: Minimal runtime image
# ============================================================
FROM opencsg-registry.cn-beijing.cr.aliyuncs.com/opencsg_public/alpine:3.23
FROM ${RUNTIME_ALPINE_BASE_IMAGE}

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

Expand Down