diff --git a/.env.release.example b/.env.release.example index 21d73140..d83858eb 100644 --- a/.env.release.example +++ b/.env.release.example @@ -3,6 +3,8 @@ SKILLHUB_VERSION=edge SKILLHUB_SERVER_IMAGE=ghcr.io/iflytek/skillhub-server SKILLHUB_WEB_IMAGE=ghcr.io/iflytek/skillhub-web +POSTGRES_IMAGE=postgres:16-alpine +REDIS_IMAGE=redis:7-alpine # Public entrypoint seen by browsers/CLI, no trailing slash. SKILLHUB_PUBLIC_BASE_URL=https://skillhub.example.com diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml index b5e42548..d5351fac 100644 --- a/.github/workflows/publish-images.yml +++ b/.github/workflows/publish-images.yml @@ -19,6 +19,11 @@ env: jobs: publish: runs-on: ubuntu-latest + env: + MIRROR_REGISTRY: ${{ secrets.MIRROR_REGISTRY || secrets.ALIYUN_REGISTRY }} + MIRROR_NAMESPACE: ${{ secrets.MIRROR_NAMESPACE || secrets.ALIYUN_NAME_SPACE }} + MIRROR_REGISTRY_USERNAME: ${{ secrets.MIRROR_REGISTRY_USERNAME || secrets.ALIYUN_REGISTRY_USER }} + MIRROR_REGISTRY_PASSWORD: ${{ secrets.MIRROR_REGISTRY_PASSWORD || secrets.ALIYUN_REGISTRY_PASSWORD }} strategy: fail-fast: false matrix: @@ -27,10 +32,12 @@ jobs: context: ./server dockerfile: ./server/Dockerfile image: ghcr.io/${{ github.repository_owner }}/skillhub-server + mirror_image: skillhub-server - name: web context: ./web dockerfile: ./web/Dockerfile image: ghcr.io/${{ github.repository_owner }}/skillhub-web + mirror_image: skillhub-web steps: - name: Check out repository @@ -49,11 +56,41 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Detect mirror configuration + id: mirror + shell: bash + run: | + if [[ -n "${MIRROR_REGISTRY}" && -n "${MIRROR_NAMESPACE}" && -n "${MIRROR_REGISTRY_USERNAME}" && -n "${MIRROR_REGISTRY_PASSWORD}" ]]; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + fi + + - name: Log in to mirror registry + if: ${{ steps.mirror.outputs.enabled == 'true' }} + shell: bash + run: | + echo "${MIRROR_REGISTRY_PASSWORD}" | docker login "${MIRROR_REGISTRY}" \ + --username "${MIRROR_REGISTRY_USERNAME}" \ + --password-stdin + + - name: Prepare image targets + id: targets + run: | + { + echo "images<> "$GITHUB_OUTPUT" + - name: Extract image metadata id: meta uses: docker/metadata-action@v5 with: - images: ${{ matrix.image }} + images: ${{ steps.targets.outputs.images }} tags: | type=raw,value=edge,enable={{is_default_branch}} type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} @@ -75,3 +112,47 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha,scope=${{ matrix.name }} cache-to: type=gha,mode=max,scope=${{ matrix.name }} + + mirror-runtime-images: + name: Mirror Runtime Images + runs-on: ubuntu-latest + needs: publish + env: + MIRROR_REGISTRY: ${{ secrets.MIRROR_REGISTRY || secrets.ALIYUN_REGISTRY }} + MIRROR_NAMESPACE: ${{ secrets.MIRROR_NAMESPACE || secrets.ALIYUN_NAME_SPACE }} + MIRROR_REGISTRY_USERNAME: ${{ secrets.MIRROR_REGISTRY_USERNAME || secrets.ALIYUN_REGISTRY_USER }} + MIRROR_REGISTRY_PASSWORD: ${{ secrets.MIRROR_REGISTRY_PASSWORD || secrets.ALIYUN_REGISTRY_PASSWORD }} + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Detect mirror configuration + id: mirror + shell: bash + run: | + if [[ -n "${MIRROR_REGISTRY}" && -n "${MIRROR_NAMESPACE}" && -n "${MIRROR_REGISTRY_USERNAME}" && -n "${MIRROR_REGISTRY_PASSWORD}" ]]; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + fi + + - name: Set up Docker Buildx + if: ${{ steps.mirror.outputs.enabled == 'true' }} + uses: docker/setup-buildx-action@v3 + + - name: Log in to mirror registry + if: ${{ steps.mirror.outputs.enabled == 'true' }} + shell: bash + run: | + echo "${MIRROR_REGISTRY_PASSWORD}" | docker login "${MIRROR_REGISTRY}" \ + --username "${MIRROR_REGISTRY_USERNAME}" \ + --password-stdin + + - name: Mirror runtime dependency images + if: ${{ steps.mirror.outputs.enabled == 'true' }} + run: bash scripts/mirror-runtime-images.sh + + - name: Skip mirroring when registry secrets are not configured + if: ${{ steps.mirror.outputs.enabled != 'true' }} + run: echo "Mirror registry secrets are not configured; skipping runtime image mirroring." diff --git a/README.md b/README.md index 077b0dda..4fe98109 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,13 @@ Recommended image tags: - `SKILLHUB_VERSION=edge` for the latest `main` build - `SKILLHUB_VERSION=vX.Y.Z` for a fixed release +If you maintain a closer registry mirror, start the runtime with: + +```bash +curl -fsSL https://raw.githubusercontent.com/iflytek/skillhub/main/scripts/runtime.sh | sh -s -- up \ + --mirror-registry / +``` + Start the runtime: ```bash diff --git a/compose.release.yml b/compose.release.yml index b08eedde..99f0934d 100644 --- a/compose.release.yml +++ b/compose.release.yml @@ -1,6 +1,6 @@ services: postgres: - image: postgres:16-alpine + image: ${POSTGRES_IMAGE:-postgres:16-alpine} restart: unless-stopped ports: - "${POSTGRES_BIND_ADDRESS:-127.0.0.1}:${POSTGRES_PORT:-5432}:5432" @@ -17,7 +17,7 @@ services: retries: 10 redis: - image: redis:7-alpine + image: ${REDIS_IMAGE:-redis:7-alpine} restart: unless-stopped ports: - "${REDIS_BIND_ADDRESS:-127.0.0.1}:${REDIS_PORT:-6379}:6379" diff --git a/deploy/runtime-mirror-images.txt b/deploy/runtime-mirror-images.txt new file mode 100644 index 00000000..4ad7de89 --- /dev/null +++ b/deploy/runtime-mirror-images.txt @@ -0,0 +1,7 @@ +# source_image target_image +postgres:16-alpine postgres:16-alpine +redis:7-alpine redis:7-alpine +minio/minio:latest minio:latest +prom/prometheus:latest prometheus:latest +grafana/grafana:latest grafana:latest +nginx:alpine nginx:alpine diff --git a/docker-compose.yml b/docker-compose.yml index 63b0e8e8..3da70c7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: postgres: - image: postgres:16-alpine + image: ${POSTGRES_IMAGE:-postgres:16-alpine} ports: - "5432:5432" environment: @@ -16,7 +16,7 @@ services: retries: 5 redis: - image: redis:7-alpine + image: ${REDIS_IMAGE:-redis:7-alpine} ports: - "6379:6379" healthcheck: @@ -26,7 +26,7 @@ services: retries: 5 minio: - image: minio/minio:latest + image: ${MINIO_IMAGE:-minio/minio:latest} ports: - "9000:9000" - "9001:9001" diff --git a/monitoring/docker-compose.monitoring.yml b/monitoring/docker-compose.monitoring.yml index 75056f43..7ae63321 100644 --- a/monitoring/docker-compose.monitoring.yml +++ b/monitoring/docker-compose.monitoring.yml @@ -1,13 +1,13 @@ services: prometheus: - image: prom/prometheus:latest + image: ${PROMETHEUS_IMAGE:-prom/prometheus:latest} ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro grafana: - image: grafana/grafana:latest + image: ${GRAFANA_IMAGE:-grafana/grafana:latest} ports: - "3001:3000" environment: diff --git a/scripts/mirror-runtime-images.sh b/scripts/mirror-runtime-images.sh new file mode 100644 index 00000000..fcd80ef9 --- /dev/null +++ b/scripts/mirror-runtime-images.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -euo pipefail + +IMAGES_FILE="${1:-deploy/runtime-mirror-images.txt}" + +: "${MIRROR_REGISTRY:?MIRROR_REGISTRY is required}" +: "${MIRROR_NAMESPACE:?MIRROR_NAMESPACE is required}" + +target_prefix="${MIRROR_REGISTRY%/}/${MIRROR_NAMESPACE}" + +while read -r source target; do + if [[ -z "${source}" || "${source}" == \#* ]]; then + continue + fi + + if [[ -z "${target:-}" ]]; then + echo "Missing target image mapping for ${source}" >&2 + exit 1 + fi + + if docker buildx imagetools inspect "${target_prefix}/${target}" >/dev/null 2>&1; then + echo "Skipping existing image ${target_prefix}/${target}" + continue + fi + + echo "Mirroring ${source} -> ${target_prefix}/${target}" + docker buildx imagetools create --tag "${target_prefix}/${target}" "${source}" +done < "${IMAGES_FILE}" diff --git a/scripts/runtime.sh b/scripts/runtime.sh index 1d04b4d5..fbec3e87 100644 --- a/scripts/runtime.sh +++ b/scripts/runtime.sh @@ -12,8 +12,11 @@ SKILLHUB_REF="${SKILLHUB_REF:-main}" SKILLHUB_HOME_DEFAULT="${TMPDIR:-/tmp}/skillhub-runtime" SKILLHUB_HOME="${SKILLHUB_HOME:-$SKILLHUB_HOME_DEFAULT}" SKILLHUB_VERSION_VALUE="${SKILLHUB_VERSION:-}" +SKILLHUB_MIRROR_REGISTRY_VALUE="${SKILLHUB_MIRROR_REGISTRY:-}" SKILLHUB_SERVER_IMAGE_VALUE="${SKILLHUB_SERVER_IMAGE:-}" SKILLHUB_WEB_IMAGE_VALUE="${SKILLHUB_WEB_IMAGE:-}" +POSTGRES_IMAGE_VALUE="${POSTGRES_IMAGE:-}" +REDIS_IMAGE_VALUE="${REDIS_IMAGE:-}" while [ "$#" -gt 0 ]; do case "$1" in @@ -22,6 +25,11 @@ while [ "$#" -gt 0 ]; do SKILLHUB_VERSION_VALUE="$2" shift 2 ;; + --mirror-registry) + [ "$#" -ge 2 ] || { echo "Missing value for --mirror-registry" >&2; exit 1; } + SKILLHUB_MIRROR_REGISTRY_VALUE="$2" + shift 2 + ;; --home) [ "$#" -ge 2 ] || { echo "Missing value for --home" >&2; exit 1; } SKILLHUB_HOME="$2" @@ -42,16 +50,29 @@ while [ "$#" -gt 0 ]; do SKILLHUB_WEB_IMAGE_VALUE="$2" shift 2 ;; + --postgres-image) + [ "$#" -ge 2 ] || { echo "Missing value for --postgres-image" >&2; exit 1; } + POSTGRES_IMAGE_VALUE="$2" + shift 2 + ;; + --redis-image) + [ "$#" -ge 2 ] || { echo "Missing value for --redis-image" >&2; exit 1; } + REDIS_IMAGE_VALUE="$2" + shift 2 + ;; --help|-h) cat < Use a specific image tag, for example v0.1.0 + --mirror-registry Use mirrored images from / --home Store runtime files in a specific directory --ref Download runtime files from a specific Git ref --server-image Override backend image repository --web-image Override frontend image repository + --postgres-image Override PostgreSQL image + --redis-image Override Redis image EOF exit 0 ;; @@ -117,10 +138,34 @@ prepare_runtime_files() { cp "$ENV_EXAMPLE_FILE" "$ENV_FILE" fi + if [ -n "$SKILLHUB_MIRROR_REGISTRY_VALUE" ]; then + mirror_registry="${SKILLHUB_MIRROR_REGISTRY_VALUE%/}" + if [ -z "$POSTGRES_IMAGE_VALUE" ]; then + POSTGRES_IMAGE_VALUE="$mirror_registry/postgres:16-alpine" + fi + if [ -z "$REDIS_IMAGE_VALUE" ]; then + REDIS_IMAGE_VALUE="$mirror_registry/redis:7-alpine" + fi + if [ -z "$SKILLHUB_SERVER_IMAGE_VALUE" ]; then + SKILLHUB_SERVER_IMAGE_VALUE="$mirror_registry/skillhub-server" + fi + if [ -z "$SKILLHUB_WEB_IMAGE_VALUE" ]; then + SKILLHUB_WEB_IMAGE_VALUE="$mirror_registry/skillhub-web" + fi + fi + if [ -n "$SKILLHUB_VERSION_VALUE" ]; then set_env_value "SKILLHUB_VERSION" "$SKILLHUB_VERSION_VALUE" fi + if [ -n "$POSTGRES_IMAGE_VALUE" ]; then + set_env_value "POSTGRES_IMAGE" "$POSTGRES_IMAGE_VALUE" + fi + + if [ -n "$REDIS_IMAGE_VALUE" ]; then + set_env_value "REDIS_IMAGE" "$REDIS_IMAGE_VALUE" + fi + if [ -n "$SKILLHUB_SERVER_IMAGE_VALUE" ]; then set_env_value "SKILLHUB_SERVER_IMAGE" "$SKILLHUB_SERVER_IMAGE_VALUE" fi