From 6a46b341a3363fb1a7ab5e417f056347df0dfbf5 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Wed, 12 Aug 2026 11:45:40 +0800 Subject: [PATCH 1/2] fix(deploy): publish dependency images consistently Add an AKernel-maintained etcd image whose shell, UID, and data directory match the Helm runtime contract. Use it as the chart and Terraform default while keeping the Traefik internal-stats public BusyBox fallback valid. Generate sibling etcd and BusyBox repositories from deployment profiles and have make push prepare and publish all required images. Reject stale profiles instead of silently pushing dependencies to locations that differ from Terraform, and cover the image contracts in CI and deployment documentation. Signed-off-by: hky1999 <976929993@qq.com> --- .github/workflows/ci.yml | 67 +++++++++++++++++++ AGENTS.md | 16 ++++- Makefile | 2 +- builder/etcd.Dockerfile | 39 +++++++++++ builder/etcd.NOTICE | 4 ++ deploy/README.md | 29 ++++++-- deploy/akernel/charts/core/values.yaml | 2 +- deploy/scripts/common.sh | 4 ++ deploy/scripts/configure.sh | 16 +++++ deploy/scripts/push-image.sh | 64 ++++++++++++++++-- deploy/terraform/aliyun/README.md | 13 ++++ deploy/terraform/aliyun/main.tf | 4 +- .../terraform/aliyun/terraform.tfvars.example | 8 ++- deploy/terraform/aliyun/variables.tf | 4 +- deploy/terraform/huaweicloud/README.md | 8 ++- .../huaweicloud/terraform.tfvars.example | 2 +- deploy/terraform/huaweicloud/variables.tf | 2 +- 17 files changed, 258 insertions(+), 26 deletions(-) create mode 100644 builder/etcd.Dockerfile create mode 100644 builder/etcd.NOTICE diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d219159..6145376 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,51 @@ permissions: contents: read jobs: + etcd-image-smoke: + name: etcd image smoke test + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Build etcd image + run: | + docker build \ + -f builder/etcd.Dockerfile \ + -t akernel-etcd-ci:3.6.8 \ + . + + - name: Verify chart runtime contract + run: | + docker run --rm --entrypoint /bin/sh akernel-etcd-ci:3.6.8 -ec ' + test "$(id -u)" = 1001 + test "$(pwd)" = /etcd + test -w /etcd + command -v etcd + command -v etcdctl + command -v etcdutl + ' + volume="akernel-etcd-smoke-${GITHUB_RUN_ID}" + trap 'docker volume rm -f "${volume}" >/dev/null 2>&1 || true' EXIT + docker volume create "${volume}" >/dev/null + docker run --rm --user 0:0 --entrypoint /bin/sh \ + -v "${volume}:/etcd" akernel-etcd-ci:3.6.8 -ec ' + mkdir -p /etcd + chown -R 1001:1001 /etcd + chmod 0700 /etcd + ' + docker run --rm --entrypoint /bin/sh \ + -v "${volume}:/etcd" akernel-etcd-ci:3.6.8 -ec ' + test "$(id -u)" = 1001 + test "$(stat -c %u:%g /etcd)" = 1001:1001 + test "$(stat -c %a /etcd)" = 700 + touch /etcd/.write-test + rm /etcd/.write-test + ' + docker run --rm akernel-etcd-ci:3.6.8 --version + sdk-unit-tests: name: Python SDK unit tests (${{ matrix.python-version }}) runs-on: ubuntu-latest @@ -63,3 +108,25 @@ jobs: run: | unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY no_proxy NO_PROXY make deploy-script-check + + - name: Reject stale image push profiles + run: | + profile=".akernel/ci-stale-image-profile" + mkdir -p "${profile}" + printf '%s\n' \ + 'IMAGE_REPOSITORY=example.invalid/akernel/all-in-one' \ + 'IMAGE_TAG=test' \ + > "${profile}/config.env" + + set +e + output="$(./deploy/scripts/push-image.sh \ + --vendor aliyun \ + --env ci-stale-image-profile 2>&1)" + status=$? + set -e + + test "${status}" -ne 0 + case "${output}" in + *"missing dependency image settings"*) ;; + *) printf '%s\n' "${output}" >&2; exit 1 ;; + esac diff --git a/AGENTS.md b/AGENTS.md index 0dbedbd..3ec2704 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,7 +31,7 @@ tunnels. The project overview and deployment quick start are in - `src/yuanrong/` - pinned openYuanRong mirror checkout, including its recursive component submodules. - `builder/` - Dockerfiles, service configs, runtime rootfs build, and image - entrypoint scripts for the public all-in-one image. + entrypoint scripts for the public all-in-one and etcd images. - `deploy/` - Helm charts, standalone scripts, Terraform modules, and deployment helper scripts. - `assets/` - static images used by the root README. @@ -108,8 +108,18 @@ make build RUNTIME_PROFILE=python For a build that will be pushed and deployed, set `IMAGE_REPOSITORY` and `IMAGE_TAG` when creating the deployment profile. A one-off `IMAGE_TAG` override on `make build` does not update the profile consumed by `make push`. -The build creates only the selected image reference; it does not add a second -`akernel-all-in-one` alias. `make push` pushes that selected reference directly. +The build creates only the selected all-in-one image reference; it does not add +a second `akernel-all-in-one` alias. `make push` also builds or mirrors the +profile's etcd and Traefik internal-stats BusyBox images, then pushes those +three images. It does not mirror Traefik itself, monitoring, or Dragonfly. + +The bundled Helm chart uses `akerneldev/etcd:3.6.8`, which is built from the +official etcd binaries plus an Alpine runtime layer. The shell and UID 1001 are +part of the chart contract: both the volume-permissions init container and the +etcd container execute `/bin/sh`, and `/etcd` is owned by UID 1001 after the +init container prepares the mounted volume. +`make push` builds this image and pushes it, BusyBox, and the all-in-one image +to the repositories recorded in the deployment profile. The build helper performs two Docker builds. `builder/runtime.Dockerfile` creates `yr-runtime-rootfs.img`; the default `rrt` profile contains the diff --git a/Makefile b/Makefile index cc5cda6..0e11820 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ help: @echo " make build RUNTIME_PROFILE=python Include optional Python runtimes" @echo " make build GVISOR_RELEASE= Override the pinned official gVisor tag" @echo " make versions Show locally selected component versions" - @echo " make push Push the configured all-in-one image" + @echo " make push Push all-in-one, etcd, and BusyBox" @echo " make plan Terraform plan" @echo " make deploy Terraform apply" @echo " make token TTL=24h Generate a local JWT token" diff --git a/builder/etcd.Dockerfile b/builder/etcd.Dockerfile new file mode 100644 index 0000000..5a38e42 --- /dev/null +++ b/builder/etcd.Dockerfile @@ -0,0 +1,39 @@ +# Copyright (c) 2026 Ant Group Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +ARG ETCD_VERSION=3.6.8 + +FROM gcr.io/etcd-development/etcd:v${ETCD_VERSION} AS upstream + +FROM alpine:3.22 + +ARG ETCD_VERSION + +LABEL org.opencontainers.image.title="AKernel etcd" \ + org.opencontainers.image.description="etcd with a POSIX shell for the AKernel Helm chart" \ + org.opencontainers.image.source="https://github.com/etcd-io/etcd" \ + org.opencontainers.image.version="${ETCD_VERSION}" \ + org.opencontainers.image.licenses="Apache-2.0" + +RUN apk add --no-cache ca-certificates \ + && addgroup -S -g 1001 etcd \ + && adduser -S -D -H -u 1001 -G etcd etcd \ + && install -d -o etcd -g etcd /etcd /usr/share/licenses/etcd + +COPY --from=upstream \ + /usr/local/bin/etcd \ + /usr/local/bin/etcdctl \ + /usr/local/bin/etcdutl \ + /usr/local/bin/ +COPY LICENSE /usr/share/licenses/etcd/LICENSE +COPY builder/etcd.NOTICE /usr/share/licenses/etcd/NOTICE + +RUN chmod 0755 /usr/local/bin/etcd /usr/local/bin/etcdctl /usr/local/bin/etcdutl + +USER 1001:1001 +WORKDIR /etcd + +EXPOSE 2379 2378 + +ENTRYPOINT ["/usr/local/bin/etcd"] diff --git a/builder/etcd.NOTICE b/builder/etcd.NOTICE new file mode 100644 index 0000000..2970b79 --- /dev/null +++ b/builder/etcd.NOTICE @@ -0,0 +1,4 @@ +AKernel etcd image + +This image redistributes the etcd binaries from https://github.com/etcd-io/etcd. +etcd is licensed under the Apache License, Version 2.0. diff --git a/deploy/README.md b/deploy/README.md index 17e6fd0..28163bc 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -151,6 +151,12 @@ fsync enabled and uses persistent storage by default. Production environments that require etcd high availability should point AKernel at an externally managed multi-member etcd cluster instead of increasing `etcd.replicas`. +The default `akerneldev/etcd:3.6.8` image copies the official etcd binaries +into an Alpine runtime. This preserves `/bin/sh` for the chart's init and main +container commands and runs etcd as UID 1001, matching the persistent-volume +ownership configured by the chart. The image working directory and the chart's +data directory are both `/etcd`. + The core chart defaults master, frontend, and node to the same all-in-one image: ```yaml @@ -268,10 +274,25 @@ through its own LoadBalancer when `install_monitor=true`. Set `install_dragonfly=true` to install the pinned official Dragonfly chart and inject its seed-client proxy into the node runtime configuration. -Only the AKernel all-in-one image is pushed to the registry selected by -`make config`. etcd, Traefik, Grafana, Prometheus, Loki, Tempo, and BusyBox use -their pinned official public images by default. Set the per-component image -overrides when a private cluster requires mirrored third-party images. +`make push` pushes the all-in-one image plus the etcd and Traefik internal-stats +BusyBox images to the image namespace selected by `make config`. For example, +`registry.example.com/akernel/all-in-one:` produces sibling repositories +`registry.example.com/akernel/etcd:3.6.8` and +`registry.example.com/akernel/busybox:1.37.0-musl`. Monitoring and Dragonfly +images remain separate; set their registry overrides when private mirrors are +required. + +> **Release note.** When `IMAGE_REPOSITORY` points at the public +> `akerneldev/all-in-one` namespace (the default for users who consume AKernel's +> published images instead of mirroring), `make config` writes +> `akerneldev/etcd:3.6.8` and `akerneldev/busybox:1.37.0-musl` into the profile. +> Both are release artifacts: a release that ships a new all-in-one tag must +> also run `make push` so these sibling repositories exist, otherwise etcd or +> the Traefik `/internal-stats` sidecar will fail to pull with +> `ImagePullBackOff`. `make push` pushes the already-built all-in-one first, +> then prepares and pushes the dependency images, so a build-host failure to +> reach `gcr.io`/Docker Hub for the upstream etcd/busybox sources no longer +> blocks the primary image. ## Directory Layout diff --git a/deploy/akernel/charts/core/values.yaml b/deploy/akernel/charts/core/values.yaml index 20d9982..5234e50 100644 --- a/deploy/akernel/charts/core/values.yaml +++ b/deploy/akernel/charts/core/values.yaml @@ -58,7 +58,7 @@ etcd: runAsUser: 0 dataUser: 1001 image: - repository: public.ecr.aws/bitnami/etcd + repository: akerneldev/etcd tag: 3.6.8 pullPolicy: IfNotPresent resources: diff --git a/deploy/scripts/common.sh b/deploy/scripts/common.sh index b5088a1..86f90ed 100644 --- a/deploy/scripts/common.sh +++ b/deploy/scripts/common.sh @@ -17,6 +17,10 @@ info() { echo "==> $*" } +warn() { + echo "WARNING: $*" >&2 +} + require_cmd() { local missing=0 for cmd in "$@"; do diff --git a/deploy/scripts/configure.sh b/deploy/scripts/configure.sh index d8af553..a0f3c82 100755 --- a/deploy/scripts/configure.sh +++ b/deploy/scripts/configure.sh @@ -213,6 +213,13 @@ case "${vendor}" in ;; esac set_or_prompt image_tag "All-in-one image tag" "${default_tag}" "${image_tag_override}" +if [[ "${image_repository}" != */* ]]; then + die "all-in-one image repository must include a namespace: ${image_repository}" +fi +image_namespace="${image_repository%/*}" +etcd_image_repository="${image_namespace}/etcd" +etcd_image_tag="3.6.8" +traefik_internal_stats_image="${image_namespace}/busybox:1.37.0-musl" set_or_prompt install_monitor "Install monitor chart (true/false)" "true" "${install_monitor_override}" set_or_prompt install_dragonfly "Install Dragonfly and dedicated node pools (true/false)" "false" "${install_dragonfly_override}" set_or_prompt grafana_public_access "Expose Grafana LoadBalancer (true/false)" "true" "${grafana_public_access_override}" @@ -313,6 +320,8 @@ master_image_repository = "${image_repository}" master_image_tag = "${image_tag}" node_image_repository = "${image_repository}" node_image_tag = "${image_tag}" +etcd_image_repository = "${etcd_image_repository}" +etcd_image_tag = "${etcd_image_tag}" iam_litebus_data_key = "${iam_seed}" frontend_enabled = true @@ -329,6 +338,7 @@ traefik_web_port = 80 traefik_tls_enabled = false traefik_tls_create_secret = false traefik_internal_stats_enabled = true +traefik_internal_stats_image = "${traefik_internal_stats_image}" install_prereqs = false @@ -367,6 +377,8 @@ master_image_repository = "${image_repository}" master_image_tag = "${image_tag}" node_image_repository = "${image_repository}" node_image_tag = "${image_tag}" +etcd_image_repository = "${etcd_image_repository}" +etcd_image_tag = "${etcd_image_tag}" iam_litebus_data_key = "${iam_seed}" frontend_enabled = true @@ -382,6 +394,7 @@ traefik_web_port = 80 traefik_tls_enabled = false traefik_tls_create_secret = false traefik_internal_stats_enabled = true +traefik_internal_stats_image = "${traefik_internal_stats_image}" install_prereqs = false @@ -409,6 +422,9 @@ GRAFANA_PASSWORD_FILE=${grafana_password_file} KUBECONFIG_PATH=${kubeconfig_file} IMAGE_REPOSITORY=${image_repository} IMAGE_TAG=${image_tag} +ETCD_IMAGE_REPOSITORY=${etcd_image_repository} +ETCD_IMAGE_TAG=${etcd_image_tag} +TRAEFIK_INTERNAL_STATS_IMAGE=${traefik_internal_stats_image} CORE_NAMESPACE=akernel MONITOR_NAMESPACE=akernel-monitor INSTALL_DRAGONFLY=${install_dragonfly} diff --git a/deploy/scripts/push-image.sh b/deploy/scripts/push-image.sh index cebcbbc..be16d8c 100755 --- a/deploy/scripts/push-image.sh +++ b/deploy/scripts/push-image.sh @@ -33,10 +33,64 @@ vendor_dir "${vendor}" >/dev/null load_env_config "${env_name}" require_cmd docker -image="${IMAGE_REPOSITORY}:${IMAGE_TAG}" +missing_profile_vars=() +for var_name in ETCD_IMAGE_REPOSITORY ETCD_IMAGE_TAG TRAEFIK_INTERNAL_STATS_IMAGE; do + if [[ -z "${!var_name:-}" ]]; then + missing_profile_vars+=("${var_name}") + fi +done +if [[ "${#missing_profile_vars[@]}" -gt 0 ]]; then + die "deployment profile ${env_name} is missing dependency image settings (${missing_profile_vars[*]}); rerun make config ENV=${env_name} and review the generated Terraform plan" +fi + +# Pinned dependency image versions. Keep these in sync with the chart defaults +# in deploy/akernel/charts/core/values.yaml (etcd.image.tag and the busybox tag +# under traefik.internalStats.image). configure.sh mirrors the same values into +# the deployment profile, so an override arriving via env vars must match a +# chart that the caller has actually updated accordingly. +readonly etcd_version="3.6.8" +readonly busybox_tag="1.37.0-musl" + +all_in_one_image="${IMAGE_REPOSITORY}:${IMAGE_TAG}" +etcd_source_image="akerneldev/etcd:${etcd_version}" +busybox_source_image="busybox:${busybox_tag}" +etcd_image="${ETCD_IMAGE_REPOSITORY}:${ETCD_IMAGE_TAG}" +busybox_image="${TRAEFIK_INTERNAL_STATS_IMAGE}" + +# Warn if an override disagrees with the chart default, so a stale pin does not +# silently push a tag the bundled chart will not request. +[[ "${ETCD_IMAGE_TAG}" == "${etcd_version}" ]] || \ + warn "ETCD_IMAGE_TAG=${ETCD_IMAGE_TAG} overrides the chart default ${etcd_version}; ensure the chart's etcd.image.tag matches" +[[ "${TRAEFIK_INTERNAL_STATS_IMAGE}" == *":${busybox_tag}" ]] || \ + warn "TRAEFIK_INTERNAL_STATS_IMAGE=${TRAEFIK_INTERNAL_STATS_IMAGE} does not use the chart default tag ${busybox_tag}; ensure the chart's traefik.internalStats.image matches" -docker image inspect "${image}" >/dev/null 2>&1 || \ - die "missing local image ${image}; run make build ENV=${env_name} first" +docker image inspect "${all_in_one_image}" >/dev/null 2>&1 || \ + die "missing local image ${all_in_one_image}; run make build ENV=${env_name} first" -info "pushing ${image}" -docker push "${image}" +# Push the primary artifact first. It is already built locally, so pushing it +# must not depend on pulling etcd/busybox from upstream registries that may be +# unreachable on the build host (e.g. cross-border network restrictions). +info "pushing ${all_in_one_image}" +docker push "${all_in_one_image}" + +info "preparing deployment dependency images (etcd, BusyBox)" +docker build \ + --build-arg "ETCD_VERSION=${etcd_version}" \ + -f "${ROOT}/builder/etcd.Dockerfile" \ + -t "${etcd_source_image}" \ + "${ROOT}" || \ + die "failed to build etcd image; build host may be unable to reach gcr.io for the upstream etcd binaries" +docker pull "${busybox_source_image}" || \ + die "failed to pull ${busybox_source_image}; build host may be unable to reach Docker Hub" + +if [[ "${etcd_source_image}" != "${etcd_image}" ]]; then + docker tag "${etcd_source_image}" "${etcd_image}" +fi +if [[ "${busybox_source_image}" != "${busybox_image}" ]]; then + docker tag "${busybox_source_image}" "${busybox_image}" +fi + +for image in "${etcd_image}" "${busybox_image}"; do + info "pushing ${image}" + docker push "${image}" +done diff --git a/deploy/terraform/aliyun/README.md b/deploy/terraform/aliyun/README.md index 80849cf..19f41ef 100644 --- a/deploy/terraform/aliyun/README.md +++ b/deploy/terraform/aliyun/README.md @@ -144,6 +144,19 @@ export AKERNEL_SERVER_ADDRESS= not required for the `websecure` router on port 443; Traefik serves its default certificate when the variable is `false`. +The module uses `akerneldev/etcd:3.6.8` by default. The image contains the +official etcd binaries and the shell required by the bundled StatefulSet. The +Traefik `/internal-stats` sidecar uses `busybox:1.37.0-musl` by default rather +than deriving an image path from the deployment ACR namespace. Override +`etcd_image_repository`, `etcd_image_tag`, or +`traefik_internal_stats_image` when using a private mirror. + +The guided `make config` flow does configure that private mirror: it derives +sibling `etcd` and `busybox` repositories from `IMAGE_REPOSITORY`, and +`make push` handles the all-in-one, etcd, and internal-stats BusyBox images. +It does not mirror the Traefik, monitoring, or Dragonfly images. Direct +Terraform users retain the public defaults shown above. + To use the legacy single-entrypoint mode, set `traefik_enable_web_entrypoint=false` and configure `traefik_tcp_port`. In that mode SDK clients must include the port explicitly: diff --git a/deploy/terraform/aliyun/main.tf b/deploy/terraform/aliyun/main.tf index 16a5996..28e10bf 100644 --- a/deploy/terraform/aliyun/main.tf +++ b/deploy/terraform/aliyun/main.tf @@ -195,11 +195,11 @@ locals { auths = { for host, cred in var.registry_auths : host => { auth = base64encode("${cred.username}:${cred.password}") } } } - etcd_image_repo = length(var.etcd_image_repository) > 0 ? var.etcd_image_repository : "public.ecr.aws/bitnami/etcd" + etcd_image_repo = length(var.etcd_image_repository) > 0 ? var.etcd_image_repository : "akerneldev/etcd" master_image_repo = length(var.master_image_repository) > 0 ? var.master_image_repository : "${local.acr_registry}/all-in-one" node_image_repo = length(var.node_image_repository) > 0 ? var.node_image_repository : "${local.acr_registry}/all-in-one" traefik_image_repo = length(var.traefik_image_repository) > 0 ? var.traefik_image_repository : "traefik" - traefik_internal_stats_image = length(var.traefik_internal_stats_image) > 0 ? var.traefik_internal_stats_image : "${local.acr_registry}/busybox:1.37.0-musl" + traefik_internal_stats_image = length(var.traefik_internal_stats_image) > 0 ? var.traefik_internal_stats_image : "busybox:1.37.0-musl" core_values = templatefile("${path.module}/values-akernel.yaml.tmpl", { acr_registry = local.acr_registry diff --git a/deploy/terraform/aliyun/terraform.tfvars.example b/deploy/terraform/aliyun/terraform.tfvars.example index 7b71e91..92052cd 100644 --- a/deploy/terraform/aliyun/terraform.tfvars.example +++ b/deploy/terraform/aliyun/terraform.tfvars.example @@ -88,8 +88,10 @@ core_namespace = "akernel" # iam_litebus_data_key = "<64-char-hex-seed>" # --- Component images --- -# Override image repository/tag for each component. Defaults to /. -# etcd_image_repository = "my-registry.com/etcd" +# Override image repository/tag for each component. AKernel components default +# to the configured ACR. The guided make config flow writes sibling etcd and +# BusyBox repositories automatically; direct Terraform can override them here. +# etcd_image_repository = "akerneldev/etcd" # etcd_image_tag = "3.6.8" # master_image_repository = "my-registry.com/akernel/all-in-one" # master_image_tag = "" @@ -158,7 +160,7 @@ traefik_tls_create_secret = false # traefik_tls_cert = "" # traefik_tls_key = "" # traefik_internal_stats_enabled = true -# traefik_internal_stats_image = "registry-vpc.cn-hangzhou.aliyuncs.com/my-namespace/busybox:1.37.0-musl" +# traefik_internal_stats_image = "busybox:1.37.0-musl" # Install prerequisite components (OpenKruise) before AKernel charts. install_prereqs = false diff --git a/deploy/terraform/aliyun/variables.tf b/deploy/terraform/aliyun/variables.tf index 9317654..17a313e 100644 --- a/deploy/terraform/aliyun/variables.tf +++ b/deploy/terraform/aliyun/variables.tf @@ -348,7 +348,7 @@ variable "iam_litebus_data_key" { variable "etcd_image_repository" { type = string - description = "Image repository for etcd." + description = "Image repository for etcd. Empty uses the AKernel-maintained public image." default = "" } @@ -573,7 +573,7 @@ variable "traefik_internal_stats_enabled" { variable "traefik_internal_stats_image" { type = string - description = "Optional BusyBox image for the Traefik /internal-stats sidecar. Empty uses the deployment ACR VPC endpoint." + description = "Optional BusyBox image for the Traefik /internal-stats sidecar. Empty uses the official public image." default = "" } diff --git a/deploy/terraform/huaweicloud/README.md b/deploy/terraform/huaweicloud/README.md index d2fdfcb..d20b378 100644 --- a/deploy/terraform/huaweicloud/README.md +++ b/deploy/terraform/huaweicloud/README.md @@ -76,9 +76,11 @@ are enabled. Its generated administrator password is stored at ## Images Master, frontend, and node use the same configured AKernel all-in-one image. -etcd, Traefik, Grafana, Prometheus, Loki, Tempo, and BusyBox use pinned official -public images by default. Use the component image variables or -`monitor_image_registry` only when the cluster requires private mirrors. +etcd uses the AKernel-maintained `akerneldev/etcd:3.6.8` image. Traefik, +Grafana, Prometheus, Loki, Tempo, and BusyBox use pinned upstream public images +by default. The guided make flow derives sibling etcd and BusyBox mirror +repositories from the all-in-one image repository; direct Terraform users can +set the component image variables or `monitor_image_registry` explicitly. ## Optional components diff --git a/deploy/terraform/huaweicloud/terraform.tfvars.example b/deploy/terraform/huaweicloud/terraform.tfvars.example index 76f3c29..e1581a0 100644 --- a/deploy/terraform/huaweicloud/terraform.tfvars.example +++ b/deploy/terraform/huaweicloud/terraform.tfvars.example @@ -76,7 +76,7 @@ monitor_storage_class = "csi-disk" # --- Component images --- # Override image repository/tag for each component. -# etcd_image_repository = "public.ecr.aws/bitnami/etcd" +# etcd_image_repository = "akerneldev/etcd" # etcd_image_tag = "3.6.8" master_image_repository = "swr.cn-north-4.myhuaweicloud.com/akernel/all-in-one" master_image_tag = "" diff --git a/deploy/terraform/huaweicloud/variables.tf b/deploy/terraform/huaweicloud/variables.tf index b2b9cc3..03fce3a 100644 --- a/deploy/terraform/huaweicloud/variables.tf +++ b/deploy/terraform/huaweicloud/variables.tf @@ -409,7 +409,7 @@ variable "iam_litebus_data_key" { variable "etcd_image_repository" { type = string description = "Image repository for etcd." - default = "public.ecr.aws/bitnami/etcd" + default = "akerneldev/etcd" } variable "etcd_image_tag" { From cc0afc7a02f8c6eb192bfe31c7a085786bc9875e Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Wed, 12 Aug 2026 21:15:51 +0800 Subject: [PATCH 2/2] fix(deploy): run the official etcd image directly Remove the AKernel-specific etcd runtime layer and adapt the Helm StatefulSet to the minimal upstream image. A dedicated BusyBox init container prepares the data volume, while the etcd container runs the official binary directly as UID and GID 1001. Keep private-registry deployments supported by mirroring the pinned upstream etcd and BusyBox images, pass the permissions image through both Terraform modules, and exercise the rendered and runtime contracts in CI. Signed-off-by: hky1999 <976929993@qq.com> --- .github/workflows/ci.yml | 58 ++++++++++--------- AGENTS.md | 22 ++++--- Makefile | 2 +- builder/etcd.Dockerfile | 39 ------------- builder/etcd.NOTICE | 4 -- deploy/README.md | 21 ++++--- .../charts/core/templates/etcd/etcd.yaml | 36 ++++++------ deploy/akernel/charts/core/values.yaml | 6 +- deploy/scripts/configure.sh | 5 +- deploy/scripts/push-image.sh | 22 +++---- deploy/terraform/aliyun/README.md | 19 +++--- deploy/terraform/aliyun/main.tf | 3 +- .../terraform/aliyun/terraform.tfvars.example | 11 ++-- .../terraform/aliyun/values-akernel.yaml.tmpl | 2 + deploy/terraform/aliyun/variables.tf | 10 +++- deploy/terraform/huaweicloud/README.md | 6 +- deploy/terraform/huaweicloud/main.tf | 1 + .../huaweicloud/terraform.tfvars.example | 5 +- .../huaweicloud/values-akernel.yaml.tmpl | 2 + deploy/terraform/huaweicloud/variables.tf | 10 +++- 20 files changed, 130 insertions(+), 154 deletions(-) delete mode 100644 builder/etcd.Dockerfile delete mode 100644 builder/etcd.NOTICE diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6145376..ca28fe9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ permissions: jobs: etcd-image-smoke: - name: etcd image smoke test + name: Official etcd image smoke test runs-on: ubuntu-latest timeout-minutes: 10 @@ -19,41 +19,45 @@ jobs: - name: Check out repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Build etcd image + - name: Render etcd StatefulSet run: | - docker build \ - -f builder/etcd.Dockerfile \ - -t akernel-etcd-ci:3.6.8 \ - . - - - name: Verify chart runtime contract + helm template akernel deploy/akernel \ + --show-only charts/core/templates/etcd/etcd.yaml \ + > /tmp/etcd-statefulset.yaml + grep -F 'image: "busybox:1.37.0-musl"' /tmp/etcd-statefulset.yaml + grep -F 'image: "gcr.io/etcd-development/etcd:v3.6.8"' /tmp/etcd-statefulset.yaml + grep -F -- '- /usr/local/bin/etcd' /tmp/etcd-statefulset.yaml + grep -F -- '- --listen-client-urls=http://$(MY_POD_IP):2379' /tmp/etcd-statefulset.yaml + test "$(grep -cF -- '- /bin/sh' /tmp/etcd-statefulset.yaml)" = 1 + + - name: Verify official image runtime contract run: | - docker run --rm --entrypoint /bin/sh akernel-etcd-ci:3.6.8 -ec ' - test "$(id -u)" = 1001 - test "$(pwd)" = /etcd - test -w /etcd - command -v etcd - command -v etcdctl - command -v etcdutl - ' volume="akernel-etcd-smoke-${GITHUB_RUN_ID}" trap 'docker volume rm -f "${volume}" >/dev/null 2>&1 || true' EXIT docker volume create "${volume}" >/dev/null - docker run --rm --user 0:0 --entrypoint /bin/sh \ - -v "${volume}:/etcd" akernel-etcd-ci:3.6.8 -ec ' + docker run --rm --user 0:0 \ + -v "${volume}:/etcd" busybox:1.37.0-musl sh -ec ' mkdir -p /etcd chown -R 1001:1001 /etcd chmod 0700 /etcd ' - docker run --rm --entrypoint /bin/sh \ - -v "${volume}:/etcd" akernel-etcd-ci:3.6.8 -ec ' - test "$(id -u)" = 1001 - test "$(stat -c %u:%g /etcd)" = 1001:1001 - test "$(stat -c %a /etcd)" = 700 - touch /etcd/.write-test - rm /etcd/.write-test - ' - docker run --rm akernel-etcd-ci:3.6.8 --version + set +e + timeout 5 docker run --rm --user 1001:1001 \ + -v "${volume}:/etcd" \ + gcr.io/etcd-development/etcd:v3.6.8 \ + /usr/local/bin/etcd \ + --name=etcd0 \ + --data-dir=/etcd \ + --listen-client-urls=http://127.0.0.1:2379 \ + --advertise-client-urls=http://127.0.0.1:2379 \ + --listen-peer-urls=http://127.0.0.1:2378 \ + --initial-advertise-peer-urls=http://127.0.0.1:2378 \ + --initial-cluster=etcd0=http://127.0.0.1:2378 + status=$? + set -e + test "${status}" = 124 + docker run --rm -v "${volume}:/etcd" busybox:1.37.0-musl \ + test -s /etcd/member/snap/db sdk-unit-tests: name: Python SDK unit tests (${{ matrix.python-version }}) diff --git a/AGENTS.md b/AGENTS.md index 3ec2704..5459fde 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,7 +31,7 @@ tunnels. The project overview and deployment quick start are in - `src/yuanrong/` - pinned openYuanRong mirror checkout, including its recursive component submodules. - `builder/` - Dockerfiles, service configs, runtime rootfs build, and image - entrypoint scripts for the public all-in-one and etcd images. + entrypoint scripts for the public all-in-one image. - `deploy/` - Helm charts, standalone scripts, Terraform modules, and deployment helper scripts. - `assets/` - static images used by the root README. @@ -109,17 +109,15 @@ For a build that will be pushed and deployed, set `IMAGE_REPOSITORY` and `IMAGE_TAG` when creating the deployment profile. A one-off `IMAGE_TAG` override on `make build` does not update the profile consumed by `make push`. The build creates only the selected all-in-one image reference; it does not add -a second `akernel-all-in-one` alias. `make push` also builds or mirrors the -profile's etcd and Traefik internal-stats BusyBox images, then pushes those -three images. It does not mirror Traefik itself, monitoring, or Dragonfly. - -The bundled Helm chart uses `akerneldev/etcd:3.6.8`, which is built from the -official etcd binaries plus an Alpine runtime layer. The shell and UID 1001 are -part of the chart contract: both the volume-permissions init container and the -etcd container execute `/bin/sh`, and `/etcd` is owned by UID 1001 after the -init container prepares the mounted volume. -`make push` builds this image and pushes it, BusyBox, and the all-in-one image -to the repositories recorded in the deployment profile. +a second `akernel-all-in-one` alias. `make push` also mirrors the official etcd +and BusyBox images to the repositories recorded in the deployment profile. It +does not mirror Traefik itself, monitoring, or Dragonfly. + +The bundled Helm chart runs the official etcd image directly as UID 1001. A +separate BusyBox init container prepares `/etcd` on the mounted volume because +the minimal official etcd image intentionally has no shell. Keep the etcd main +container free of shell commands so the official image remains usable without +an AKernel-specific rebuild. The build helper performs two Docker builds. `builder/runtime.Dockerfile` creates `yr-runtime-rootfs.img`; the default `rrt` profile contains the diff --git a/Makefile b/Makefile index 0e11820..526f5d0 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ help: @echo " make build RUNTIME_PROFILE=python Include optional Python runtimes" @echo " make build GVISOR_RELEASE= Override the pinned official gVisor tag" @echo " make versions Show locally selected component versions" - @echo " make push Push all-in-one, etcd, and BusyBox" + @echo " make push Push all-in-one and mirror etcd/BusyBox" @echo " make plan Terraform plan" @echo " make deploy Terraform apply" @echo " make token TTL=24h Generate a local JWT token" diff --git a/builder/etcd.Dockerfile b/builder/etcd.Dockerfile deleted file mode 100644 index 5a38e42..0000000 --- a/builder/etcd.Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2026 Ant Group Corporation. -# -# SPDX-License-Identifier: Apache-2.0 - -ARG ETCD_VERSION=3.6.8 - -FROM gcr.io/etcd-development/etcd:v${ETCD_VERSION} AS upstream - -FROM alpine:3.22 - -ARG ETCD_VERSION - -LABEL org.opencontainers.image.title="AKernel etcd" \ - org.opencontainers.image.description="etcd with a POSIX shell for the AKernel Helm chart" \ - org.opencontainers.image.source="https://github.com/etcd-io/etcd" \ - org.opencontainers.image.version="${ETCD_VERSION}" \ - org.opencontainers.image.licenses="Apache-2.0" - -RUN apk add --no-cache ca-certificates \ - && addgroup -S -g 1001 etcd \ - && adduser -S -D -H -u 1001 -G etcd etcd \ - && install -d -o etcd -g etcd /etcd /usr/share/licenses/etcd - -COPY --from=upstream \ - /usr/local/bin/etcd \ - /usr/local/bin/etcdctl \ - /usr/local/bin/etcdutl \ - /usr/local/bin/ -COPY LICENSE /usr/share/licenses/etcd/LICENSE -COPY builder/etcd.NOTICE /usr/share/licenses/etcd/NOTICE - -RUN chmod 0755 /usr/local/bin/etcd /usr/local/bin/etcdctl /usr/local/bin/etcdutl - -USER 1001:1001 -WORKDIR /etcd - -EXPOSE 2379 2378 - -ENTRYPOINT ["/usr/local/bin/etcd"] diff --git a/builder/etcd.NOTICE b/builder/etcd.NOTICE deleted file mode 100644 index 2970b79..0000000 --- a/builder/etcd.NOTICE +++ /dev/null @@ -1,4 +0,0 @@ -AKernel etcd image - -This image redistributes the etcd binaries from https://github.com/etcd-io/etcd. -etcd is licensed under the Apache License, Version 2.0. diff --git a/deploy/README.md b/deploy/README.md index 28163bc..64d1a47 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -151,11 +151,10 @@ fsync enabled and uses persistent storage by default. Production environments that require etcd high availability should point AKernel at an externally managed multi-member etcd cluster instead of increasing `etcd.replicas`. -The default `akerneldev/etcd:3.6.8` image copies the official etcd binaries -into an Alpine runtime. This preserves `/bin/sh` for the chart's init and main -container commands and runs etcd as UID 1001, matching the persistent-volume -ownership configured by the chart. The image working directory and the chart's -data directory are both `/etcd`. +The chart runs `gcr.io/etcd-development/etcd:v3.6.8` directly as UID 1001. The +official image intentionally has no shell, so a separate BusyBox init container +prepares ownership and permissions on the mounted `/etcd` volume before the +etcd process starts. The core chart defaults master, frontend, and node to the same all-in-one image: @@ -274,10 +273,10 @@ through its own LoadBalancer when `install_monitor=true`. Set `install_dragonfly=true` to install the pinned official Dragonfly chart and inject its seed-client proxy into the node runtime configuration. -`make push` pushes the all-in-one image plus the etcd and Traefik internal-stats +`make push` pushes the all-in-one image and mirrors the official etcd and BusyBox images to the image namespace selected by `make config`. For example, `registry.example.com/akernel/all-in-one:` produces sibling repositories -`registry.example.com/akernel/etcd:3.6.8` and +`registry.example.com/akernel/etcd:v3.6.8` and `registry.example.com/akernel/busybox:1.37.0-musl`. Monitoring and Dragonfly images remain separate; set their registry overrides when private mirrors are required. @@ -285,10 +284,10 @@ required. > **Release note.** When `IMAGE_REPOSITORY` points at the public > `akerneldev/all-in-one` namespace (the default for users who consume AKernel's > published images instead of mirroring), `make config` writes -> `akerneldev/etcd:3.6.8` and `akerneldev/busybox:1.37.0-musl` into the profile. -> Both are release artifacts: a release that ships a new all-in-one tag must -> also run `make push` so these sibling repositories exist, otherwise etcd or -> the Traefik `/internal-stats` sidecar will fail to pull with +> `akerneldev/etcd:v3.6.8` and `akerneldev/busybox:1.37.0-musl` into the profile. +> These are mirrors of the pinned upstream images. A release that uses this +> profile must run `make push` so the sibling repositories exist, otherwise +> etcd, its permissions init container, or `/internal-stats` will fail with > `ImagePullBackOff`. `make push` pushes the already-built all-in-one first, > then prepares and pushes the dependency images, so a build-host failure to > reach `gcr.io`/Docker Hub for the upstream etcd/busybox sources no longer diff --git a/deploy/akernel/charts/core/templates/etcd/etcd.yaml b/deploy/akernel/charts/core/templates/etcd/etcd.yaml index 4acbd6a..f2b1d09 100644 --- a/deploy/akernel/charts/core/templates/etcd/etcd.yaml +++ b/deploy/akernel/charts/core/templates/etcd/etcd.yaml @@ -40,8 +40,8 @@ spec: {{- if .Values.etcd.volumePermissions.enabled }} initContainers: - name: init-etcd-permissions - image: "{{ .Values.etcd.image.repository }}:{{ .Values.etcd.image.tag }}" - imagePullPolicy: {{ .Values.etcd.image.pullPolicy }} + image: "{{ .Values.etcd.volumePermissions.image }}" + imagePullPolicy: {{ .Values.etcd.volumePermissions.pullPolicy }} command: - /bin/sh - -ec @@ -60,21 +60,23 @@ spec: image: "{{ .Values.etcd.image.repository }}:{{ .Values.etcd.image.tag }}" imagePullPolicy: {{ .Values.etcd.image.pullPolicy }} command: - - /bin/sh - - -ec - - | - mkdir -p {{ .Values.etcd.dataDir }} - exec etcd --name=etcd0 \ - --data-dir={{ .Values.etcd.dataDir }} \ - --auto-compaction-mode=revision \ - --auto-compaction-retention={{ .Values.etcd.args.autoCompactionRetention }} \ - --quota-backend-bytes={{ .Values.etcd.args.quotaBackendBytes }} \ - --listen-client-urls=http://${MY_POD_IP}:2379 \ - --advertise-client-urls=http://${MY_POD_IP}:2379 \ - --listen-peer-urls=http://${MY_POD_IP}:2378 \ - --initial-advertise-peer-urls=http://${MY_POD_IP}:2378 \ - --initial-cluster=etcd0=http://${MY_POD_IP}:2378 \ - --initial-cluster-state=new + - /usr/local/bin/etcd + args: + - --name=etcd0 + - --data-dir={{ .Values.etcd.dataDir }} + - --auto-compaction-mode=revision + - --auto-compaction-retention={{ .Values.etcd.args.autoCompactionRetention }} + - --quota-backend-bytes={{ .Values.etcd.args.quotaBackendBytes }} + - --listen-client-urls=http://$(MY_POD_IP):2379 + - --advertise-client-urls=http://$(MY_POD_IP):2379 + - --listen-peer-urls=http://$(MY_POD_IP):2378 + - --initial-advertise-peer-urls=http://$(MY_POD_IP):2378 + - --initial-cluster=etcd0=http://$(MY_POD_IP):2378 + - --initial-cluster-state=new + securityContext: + runAsNonRoot: true + runAsUser: {{ .Values.etcd.volumePermissions.dataUser }} + runAsGroup: {{ .Values.etcd.volumePermissions.dataUser }} env: - name: MY_POD_IP valueFrom: diff --git a/deploy/akernel/charts/core/values.yaml b/deploy/akernel/charts/core/values.yaml index 5234e50..a81fd2b 100644 --- a/deploy/akernel/charts/core/values.yaml +++ b/deploy/akernel/charts/core/values.yaml @@ -57,9 +57,11 @@ etcd: enabled: true runAsUser: 0 dataUser: 1001 + image: busybox:1.37.0-musl + pullPolicy: IfNotPresent image: - repository: akerneldev/etcd - tag: 3.6.8 + repository: gcr.io/etcd-development/etcd + tag: v3.6.8 pullPolicy: IfNotPresent resources: limits: diff --git a/deploy/scripts/configure.sh b/deploy/scripts/configure.sh index a0f3c82..39153ce 100755 --- a/deploy/scripts/configure.sh +++ b/deploy/scripts/configure.sh @@ -218,8 +218,9 @@ if [[ "${image_repository}" != */* ]]; then fi image_namespace="${image_repository%/*}" etcd_image_repository="${image_namespace}/etcd" -etcd_image_tag="3.6.8" +etcd_image_tag="v3.6.8" traefik_internal_stats_image="${image_namespace}/busybox:1.37.0-musl" +etcd_volume_permissions_image="${traefik_internal_stats_image}" set_or_prompt install_monitor "Install monitor chart (true/false)" "true" "${install_monitor_override}" set_or_prompt install_dragonfly "Install Dragonfly and dedicated node pools (true/false)" "false" "${install_dragonfly_override}" set_or_prompt grafana_public_access "Expose Grafana LoadBalancer (true/false)" "true" "${grafana_public_access_override}" @@ -322,6 +323,7 @@ node_image_repository = "${image_repository}" node_image_tag = "${image_tag}" etcd_image_repository = "${etcd_image_repository}" etcd_image_tag = "${etcd_image_tag}" +etcd_volume_permissions_image = "${etcd_volume_permissions_image}" iam_litebus_data_key = "${iam_seed}" frontend_enabled = true @@ -379,6 +381,7 @@ node_image_repository = "${image_repository}" node_image_tag = "${image_tag}" etcd_image_repository = "${etcd_image_repository}" etcd_image_tag = "${etcd_image_tag}" +etcd_volume_permissions_image = "${etcd_volume_permissions_image}" iam_litebus_data_key = "${iam_seed}" frontend_enabled = true diff --git a/deploy/scripts/push-image.sh b/deploy/scripts/push-image.sh index be16d8c..f7c70f7 100755 --- a/deploy/scripts/push-image.sh +++ b/deploy/scripts/push-image.sh @@ -43,24 +43,20 @@ if [[ "${#missing_profile_vars[@]}" -gt 0 ]]; then die "deployment profile ${env_name} is missing dependency image settings (${missing_profile_vars[*]}); rerun make config ENV=${env_name} and review the generated Terraform plan" fi -# Pinned dependency image versions. Keep these in sync with the chart defaults -# in deploy/akernel/charts/core/values.yaml (etcd.image.tag and the busybox tag -# under traefik.internalStats.image). configure.sh mirrors the same values into -# the deployment profile, so an override arriving via env vars must match a -# chart that the caller has actually updated accordingly. +# Pinned dependency image versions. Keep these in sync with the chart defaults. readonly etcd_version="3.6.8" readonly busybox_tag="1.37.0-musl" all_in_one_image="${IMAGE_REPOSITORY}:${IMAGE_TAG}" -etcd_source_image="akerneldev/etcd:${etcd_version}" +etcd_source_image="gcr.io/etcd-development/etcd:v${etcd_version}" busybox_source_image="busybox:${busybox_tag}" etcd_image="${ETCD_IMAGE_REPOSITORY}:${ETCD_IMAGE_TAG}" busybox_image="${TRAEFIK_INTERNAL_STATS_IMAGE}" # Warn if an override disagrees with the chart default, so a stale pin does not # silently push a tag the bundled chart will not request. -[[ "${ETCD_IMAGE_TAG}" == "${etcd_version}" ]] || \ - warn "ETCD_IMAGE_TAG=${ETCD_IMAGE_TAG} overrides the chart default ${etcd_version}; ensure the chart's etcd.image.tag matches" +[[ "${ETCD_IMAGE_TAG}" == "v${etcd_version}" ]] || \ + warn "ETCD_IMAGE_TAG=${ETCD_IMAGE_TAG} overrides the chart default v${etcd_version}; ensure the chart's etcd.image.tag matches" [[ "${TRAEFIK_INTERNAL_STATS_IMAGE}" == *":${busybox_tag}" ]] || \ warn "TRAEFIK_INTERNAL_STATS_IMAGE=${TRAEFIK_INTERNAL_STATS_IMAGE} does not use the chart default tag ${busybox_tag}; ensure the chart's traefik.internalStats.image matches" @@ -74,14 +70,10 @@ info "pushing ${all_in_one_image}" docker push "${all_in_one_image}" info "preparing deployment dependency images (etcd, BusyBox)" -docker build \ - --build-arg "ETCD_VERSION=${etcd_version}" \ - -f "${ROOT}/builder/etcd.Dockerfile" \ - -t "${etcd_source_image}" \ - "${ROOT}" || \ - die "failed to build etcd image; build host may be unable to reach gcr.io for the upstream etcd binaries" +docker pull "${etcd_source_image}" || \ + die "failed to pull ${etcd_source_image}" docker pull "${busybox_source_image}" || \ - die "failed to pull ${busybox_source_image}; build host may be unable to reach Docker Hub" + die "failed to pull ${busybox_source_image}" if [[ "${etcd_source_image}" != "${etcd_image}" ]]; then docker tag "${etcd_source_image}" "${etcd_image}" diff --git a/deploy/terraform/aliyun/README.md b/deploy/terraform/aliyun/README.md index 19f41ef..aab5324 100644 --- a/deploy/terraform/aliyun/README.md +++ b/deploy/terraform/aliyun/README.md @@ -144,16 +144,15 @@ export AKERNEL_SERVER_ADDRESS= not required for the `websecure` router on port 443; Traefik serves its default certificate when the variable is `false`. -The module uses `akerneldev/etcd:3.6.8` by default. The image contains the -official etcd binaries and the shell required by the bundled StatefulSet. The -Traefik `/internal-stats` sidecar uses `busybox:1.37.0-musl` by default rather -than deriving an image path from the deployment ACR namespace. Override -`etcd_image_repository`, `etcd_image_tag`, or -`traefik_internal_stats_image` when using a private mirror. - -The guided `make config` flow does configure that private mirror: it derives -sibling `etcd` and `busybox` repositories from `IMAGE_REPOSITORY`, and -`make push` handles the all-in-one, etcd, and internal-stats BusyBox images. +The module uses the official `gcr.io/etcd-development/etcd:v3.6.8` image by +default. A BusyBox init container prepares the etcd volume because the official +image has no shell; it uses the same pinned BusyBox image as Traefik's +`/internal-stats` sidecar. Override the component image variables when using a +private mirror. + +The guided `make config` flow configures that private mirror: it derives sibling +`etcd` and `busybox` repositories from `IMAGE_REPOSITORY`, and `make push` +mirrors the official etcd and BusyBox images alongside the all-in-one image. It does not mirror the Traefik, monitoring, or Dragonfly images. Direct Terraform users retain the public defaults shown above. diff --git a/deploy/terraform/aliyun/main.tf b/deploy/terraform/aliyun/main.tf index 28e10bf..c206960 100644 --- a/deploy/terraform/aliyun/main.tf +++ b/deploy/terraform/aliyun/main.tf @@ -195,7 +195,7 @@ locals { auths = { for host, cred in var.registry_auths : host => { auth = base64encode("${cred.username}:${cred.password}") } } } - etcd_image_repo = length(var.etcd_image_repository) > 0 ? var.etcd_image_repository : "akerneldev/etcd" + etcd_image_repo = length(var.etcd_image_repository) > 0 ? var.etcd_image_repository : "gcr.io/etcd-development/etcd" master_image_repo = length(var.master_image_repository) > 0 ? var.master_image_repository : "${local.acr_registry}/all-in-one" node_image_repo = length(var.node_image_repository) > 0 ? var.node_image_repository : "${local.acr_registry}/all-in-one" traefik_image_repo = length(var.traefik_image_repository) > 0 ? var.traefik_image_repository : "traefik" @@ -209,6 +209,7 @@ locals { acr_password = var.acr_password etcd_image_repository = local.etcd_image_repo etcd_image_tag = var.etcd_image_tag + etcd_volume_permissions_image = var.etcd_volume_permissions_image master_image_repository = local.master_image_repo master_image_tag = var.master_image_tag node_image_repository = local.node_image_repo diff --git a/deploy/terraform/aliyun/terraform.tfvars.example b/deploy/terraform/aliyun/terraform.tfvars.example index 92052cd..8ff286a 100644 --- a/deploy/terraform/aliyun/terraform.tfvars.example +++ b/deploy/terraform/aliyun/terraform.tfvars.example @@ -88,11 +88,12 @@ core_namespace = "akernel" # iam_litebus_data_key = "<64-char-hex-seed>" # --- Component images --- -# Override image repository/tag for each component. AKernel components default -# to the configured ACR. The guided make config flow writes sibling etcd and -# BusyBox repositories automatically; direct Terraform can override them here. -# etcd_image_repository = "akerneldev/etcd" -# etcd_image_tag = "3.6.8" +# Override image repository/tag for each component. The guided make config flow +# writes sibling etcd and BusyBox mirrors automatically; direct Terraform uses +# the pinned upstream images unless overridden here. +# etcd_image_repository = "gcr.io/etcd-development/etcd" +# etcd_image_tag = "v3.6.8" +# etcd_volume_permissions_image = "busybox:1.37.0-musl" # master_image_repository = "my-registry.com/akernel/all-in-one" # master_image_tag = "" # node_image_repository = "my-registry.com/akernel/all-in-one" diff --git a/deploy/terraform/aliyun/values-akernel.yaml.tmpl b/deploy/terraform/aliyun/values-akernel.yaml.tmpl index 474fb19..f97b9fb 100644 --- a/deploy/terraform/aliyun/values-akernel.yaml.tmpl +++ b/deploy/terraform/aliyun/values-akernel.yaml.tmpl @@ -28,6 +28,8 @@ etcd: image: repository: "${etcd_image_repository}" tag: "${etcd_image_tag}" + volumePermissions: + image: "${etcd_volume_permissions_image}" persistence: enabled: true storageClassName: "${etcd_storage_class}" diff --git a/deploy/terraform/aliyun/variables.tf b/deploy/terraform/aliyun/variables.tf index 17a313e..2589d68 100644 --- a/deploy/terraform/aliyun/variables.tf +++ b/deploy/terraform/aliyun/variables.tf @@ -348,14 +348,20 @@ variable "iam_litebus_data_key" { variable "etcd_image_repository" { type = string - description = "Image repository for etcd. Empty uses the AKernel-maintained public image." + description = "Image repository for etcd. Empty uses the official etcd primary registry." default = "" } variable "etcd_image_tag" { type = string description = "Image tag for etcd." - default = "3.6.8" + default = "v3.6.8" +} + +variable "etcd_volume_permissions_image" { + type = string + description = "BusyBox image used to prepare the etcd data volume." + default = "busybox:1.37.0-musl" } variable "master_image_repository" { diff --git a/deploy/terraform/huaweicloud/README.md b/deploy/terraform/huaweicloud/README.md index d20b378..07d15a7 100644 --- a/deploy/terraform/huaweicloud/README.md +++ b/deploy/terraform/huaweicloud/README.md @@ -76,9 +76,9 @@ are enabled. Its generated administrator password is stored at ## Images Master, frontend, and node use the same configured AKernel all-in-one image. -etcd uses the AKernel-maintained `akerneldev/etcd:3.6.8` image. Traefik, -Grafana, Prometheus, Loki, Tempo, and BusyBox use pinned upstream public images -by default. The guided make flow derives sibling etcd and BusyBox mirror +etcd uses the official `gcr.io/etcd-development/etcd:v3.6.8` image. Its volume +permissions init container and Traefik internal-stats sidecar use pinned +BusyBox. The guided make flow derives sibling etcd and BusyBox mirror repositories from the all-in-one image repository; direct Terraform users can set the component image variables or `monitor_image_registry` explicitly. diff --git a/deploy/terraform/huaweicloud/main.tf b/deploy/terraform/huaweicloud/main.tf index 99cdc02..6f96f5f 100644 --- a/deploy/terraform/huaweicloud/main.tf +++ b/deploy/terraform/huaweicloud/main.tf @@ -100,6 +100,7 @@ locals { core_values = templatefile("${path.module}/values-akernel.yaml.tmpl", { etcd_image_repository = var.etcd_image_repository etcd_image_tag = var.etcd_image_tag + etcd_volume_permissions_image = var.etcd_volume_permissions_image master_image_repository = var.master_image_repository master_image_tag = var.master_image_tag node_image_repository = var.node_image_repository diff --git a/deploy/terraform/huaweicloud/terraform.tfvars.example b/deploy/terraform/huaweicloud/terraform.tfvars.example index e1581a0..38906a6 100644 --- a/deploy/terraform/huaweicloud/terraform.tfvars.example +++ b/deploy/terraform/huaweicloud/terraform.tfvars.example @@ -76,8 +76,9 @@ monitor_storage_class = "csi-disk" # --- Component images --- # Override image repository/tag for each component. -# etcd_image_repository = "akerneldev/etcd" -# etcd_image_tag = "3.6.8" +# etcd_image_repository = "gcr.io/etcd-development/etcd" +# etcd_image_tag = "v3.6.8" +# etcd_volume_permissions_image = "busybox:1.37.0-musl" master_image_repository = "swr.cn-north-4.myhuaweicloud.com/akernel/all-in-one" master_image_tag = "" node_image_repository = "swr.cn-north-4.myhuaweicloud.com/akernel/all-in-one" diff --git a/deploy/terraform/huaweicloud/values-akernel.yaml.tmpl b/deploy/terraform/huaweicloud/values-akernel.yaml.tmpl index 1d8622a..ea1803f 100644 --- a/deploy/terraform/huaweicloud/values-akernel.yaml.tmpl +++ b/deploy/terraform/huaweicloud/values-akernel.yaml.tmpl @@ -16,6 +16,8 @@ etcd: image: repository: "${etcd_image_repository}" tag: "${etcd_image_tag}" + volumePermissions: + image: "${etcd_volume_permissions_image}" persistence: enabled: true storageClassName: "csi-disk" diff --git a/deploy/terraform/huaweicloud/variables.tf b/deploy/terraform/huaweicloud/variables.tf index 03fce3a..07bb196 100644 --- a/deploy/terraform/huaweicloud/variables.tf +++ b/deploy/terraform/huaweicloud/variables.tf @@ -409,13 +409,19 @@ variable "iam_litebus_data_key" { variable "etcd_image_repository" { type = string description = "Image repository for etcd." - default = "akerneldev/etcd" + default = "gcr.io/etcd-development/etcd" } variable "etcd_image_tag" { type = string description = "Image tag for etcd." - default = "3.6.8" + default = "v3.6.8" +} + +variable "etcd_volume_permissions_image" { + type = string + description = "BusyBox image used to prepare the etcd data volume." + default = "busybox:1.37.0-musl" } variable "master_image_repository" {