diff --git a/Jenkinsfile b/Jenkinsfile index 24e0616..ad74adf 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,24 +29,27 @@ pipeline { FNPACK_SHA256 = '54b97fa7b70968c4d05c79840f5daeff508957d0bb2062fdb0376d00d9615c93' DOTNET = '/home/nanxunai/.local/bin/dotnet' - BUILDER_NAME = "liverecorder-${BUILD_NUMBER}" + BUILDER_NAME = 'liverecorder-ci' BUILDKIT_IMAGE = 'docker.m.daocloud.io/moby/buildkit:buildx-stable-1' BINFMT_IMAGE = 'docker.m.daocloud.io/tonistiigi/binfmt:latest' ARM_TEST_IMAGE = 'docker.m.daocloud.io/library/alpine:latest' NODE_BUILD_IMAGE = 'docker.m.daocloud.io/library/node:22-alpine' NGINX_IMAGE = 'docker.m.daocloud.io/library/nginx:1.27-alpine' + DOTNET_SDK_IMAGE = 'mcr.m.daocloud.io/dotnet/sdk:8.0-bookworm-slim' + DOTNET_RUNTIME_IMAGE = 'mcr.m.daocloud.io/dotnet/aspnet:8.0-bookworm-slim' HTTP_PROXY_URL = 'http://192.168.5.200:7890' - NO_PROXY_HOSTS = '127.0.0.1,localhost,reg.nxsir.cn,gitea.nxsir.cn,openlist.nxsir.cn,mirrors.tuna.tsinghua.edu.cn,.tsinghua.edu.cn,mcr.microsoft.com' + NO_PROXY_HOSTS = '127.0.0.1,localhost,reg.nxsir.cn,gitea.nxsir.cn,openlist.nxsir.cn,mirrors.tuna.tsinghua.edu.cn,.tsinghua.edu.cn,mirrors.huaweicloud.com,.huaweicloud.com,mcr.m.daocloud.io,docker.m.daocloud.io,.m.daocloud.io' CI_ROOT = "${WORKSPACE}/.ci" - DOCKER_CONFIG = "${WORKSPACE}/.ci/docker" - NUGET_PACKAGES = "${WORKSPACE}/.ci/nuget-packages" - NUGET_HTTP_CACHE_PATH = "${WORKSPACE}/.ci/nuget-http" - NUGET_PLUGINS_CACHE_PATH = "${WORKSPACE}/.ci/nuget-plugins" - DOTNET_CLI_HOME = "${WORKSPACE}/.ci/dotnet-home" - NPM_CONFIG_CACHE = "${WORKSPACE}/.ci/npm-cache" - LIVERECORDER_NUGET_FEED = "${WORKSPACE}/.ci/nuget-feed" + CI_CACHE_ROOT = '/home/nanxunai/.cache/liverecorder-ci' + DOCKER_CONFIG = '/home/nanxunai/.cache/liverecorder-ci/docker' + NUGET_PACKAGES = '/home/nanxunai/.cache/liverecorder-ci/nuget-packages' + NUGET_HTTP_CACHE_PATH = '/home/nanxunai/.cache/liverecorder-ci/nuget-http' + NUGET_PLUGINS_CACHE_PATH = '/home/nanxunai/.cache/liverecorder-ci/nuget-plugins' + DOTNET_CLI_HOME = '/home/nanxunai/.cache/liverecorder-ci/dotnet-home' + NPM_CONFIG_CACHE = '/home/nanxunai/.cache/liverecorder-ci/npm-cache' + LIVERECORDER_NUGET_FEED = '/home/nanxunai/.cache/liverecorder-ci/nuget-feed' LIVERECORDER_BUILD_TMPDIR = "${WORKSPACE}/.ci/fnos-tmp" LIVERECORDER_VERIFY_TMPDIR = "${WORKSPACE}/.ci/fnos-verify" LIVERECORDER_SKIP_NPM_CI = '1' @@ -139,6 +142,7 @@ pipeline { fi mkdir -p \ + "$CI_CACHE_ROOT" \ "$DOCKER_CONFIG" \ "$NUGET_PACKAGES" \ "$NUGET_HTTP_CACHE_PATH" \ @@ -193,19 +197,22 @@ pipeline { fi ./scripts/ci-docker.sh run --rm --platform linux/arm64 "$ARM_TEST_IMAGE" uname -m | grep -q aarch64 - ./scripts/ci-docker.sh buildx rm -f "$BUILDER_NAME" >/dev/null 2>&1 || true - ./scripts/ci-docker.sh buildx create \ - --name "$BUILDER_NAME" \ - --driver docker-container \ - --driver-opt "image=$BUILDKIT_IMAGE" \ - --driver-opt network=host \ - --driver-opt "env.http_proxy=$HTTP_PROXY_URL" \ - --driver-opt "env.https_proxy=$HTTP_PROXY_URL" \ - --driver-opt "env.HTTP_PROXY=$HTTP_PROXY_URL" \ - --driver-opt "env.HTTPS_PROXY=$HTTP_PROXY_URL" \ - --driver-opt "env.no_proxy=reg.nxsir.cn" \ - --driver-opt "env.NO_PROXY=reg.nxsir.cn" \ - --use + if ./scripts/ci-docker.sh buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then + ./scripts/ci-docker.sh buildx use "$BUILDER_NAME" + else + ./scripts/ci-docker.sh buildx create \ + --name "$BUILDER_NAME" \ + --driver docker-container \ + --driver-opt "image=$BUILDKIT_IMAGE" \ + --driver-opt network=host \ + --driver-opt "env.http_proxy=$HTTP_PROXY_URL" \ + --driver-opt "env.https_proxy=$HTTP_PROXY_URL" \ + --driver-opt "env.HTTP_PROXY=$HTTP_PROXY_URL" \ + --driver-opt "env.HTTPS_PROXY=$HTTP_PROXY_URL" \ + --driver-opt "env.no_proxy=reg.nxsir.cn,mcr.m.daocloud.io,docker.m.daocloud.io,mirrors.huaweicloud.com" \ + --driver-opt "env.NO_PROXY=reg.nxsir.cn,mcr.m.daocloud.io,docker.m.daocloud.io,mirrors.huaweicloud.com" \ + --use + fi ./scripts/ci-docker.sh buildx inspect "$BUILDER_NAME" --bootstrap ''' } @@ -248,7 +255,9 @@ pipeline { ./scripts/ci-docker.sh buildx build \ --builder "$BUILDER_NAME" --platform "$platform" --network host \ - --progress=plain --provenance=false --no-cache \ + --progress=plain --provenance=false \ + --build-arg DOTNET_SDK_IMAGE="$DOTNET_SDK_IMAGE" \ + --build-arg DOTNET_RUNTIME_IMAGE="$DOTNET_RUNTIME_IMAGE" \ --build-arg HTTP_PROXY="$HTTP_PROXY_URL" \ --build-arg HTTPS_PROXY="$HTTP_PROXY_URL" \ --build-arg NO_PROXY="$NO_PROXY_HOSTS" \ @@ -256,12 +265,9 @@ pipeline { --build-arg https_proxy="$HTTP_PROXY_URL" \ --build-arg no_proxy="$NO_PROXY_HOSTS" \ -f src/LiveRecorder.WebApi/Dockerfile -t "$api_ref" --push . - ./scripts/ci-docker.sh buildx prune \ - --builder "$BUILDER_NAME" --all --force - ./scripts/ci-docker.sh buildx build \ --builder "$BUILDER_NAME" --platform "$platform" --network host \ - --progress=plain --provenance=false --no-cache \ + --progress=plain --provenance=false \ --build-arg NODE_IMAGE="$NODE_BUILD_IMAGE" \ --build-arg NGINX_IMAGE="$NGINX_IMAGE" \ --build-arg HTTP_PROXY="$HTTP_PROXY_URL" \ @@ -272,8 +278,6 @@ pipeline { --build-arg no_proxy="$NO_PROXY_HOSTS" \ --build-arg VITE_API_BASE_URL=/api \ -f frontend/Dockerfile -t "$web_ref" --push frontend - ./scripts/ci-docker.sh buildx prune \ - --builder "$BUILDER_NAME" --all --force ''' } } @@ -295,7 +299,9 @@ pipeline { ./scripts/ci-docker.sh buildx build \ --builder "$BUILDER_NAME" --platform "$platform" --network host \ - --progress=plain --provenance=false --no-cache \ + --progress=plain --provenance=false \ + --build-arg DOTNET_SDK_IMAGE="$DOTNET_SDK_IMAGE" \ + --build-arg DOTNET_RUNTIME_IMAGE="$DOTNET_RUNTIME_IMAGE" \ --build-arg HTTP_PROXY="$HTTP_PROXY_URL" \ --build-arg HTTPS_PROXY="$HTTP_PROXY_URL" \ --build-arg NO_PROXY="$NO_PROXY_HOSTS" \ @@ -303,12 +309,9 @@ pipeline { --build-arg https_proxy="$HTTP_PROXY_URL" \ --build-arg no_proxy="$NO_PROXY_HOSTS" \ -f src/LiveRecorder.WebApi/Dockerfile -t "$api_ref" --push . - ./scripts/ci-docker.sh buildx prune \ - --builder "$BUILDER_NAME" --all --force - ./scripts/ci-docker.sh buildx build \ --builder "$BUILDER_NAME" --platform "$platform" --network host \ - --progress=plain --provenance=false --no-cache \ + --progress=plain --provenance=false \ --build-arg NODE_IMAGE="$NODE_BUILD_IMAGE" \ --build-arg NGINX_IMAGE="$NGINX_IMAGE" \ --build-arg HTTP_PROXY="$HTTP_PROXY_URL" \ @@ -319,8 +322,6 @@ pipeline { --build-arg no_proxy="$NO_PROXY_HOSTS" \ --build-arg VITE_API_BASE_URL=/api \ -f frontend/Dockerfile -t "$web_ref" --push frontend - ./scripts/ci-docker.sh buildx prune \ - --builder "$BUILDER_NAME" --all --force ''' } } @@ -410,9 +411,6 @@ pipeline { )]) { sh ''' set +e - if [ -x ./scripts/ci-docker.sh ] && [ -n "${BUILDER_NAME:-}" ]; then - ./scripts/ci-docker.sh buildx rm -f "$BUILDER_NAME" >/dev/null 2>&1 || true - fi if [ -x ./scripts/ci-docker.sh ] && [ -n "${IMMUTABLE_TAG:-}" ]; then for repository in "$API_IMAGE_REPO" "$WEB_IMAGE_REPO"; do for suffix in amd64 arm64; do @@ -424,6 +422,11 @@ pipeline { if [ -f "$DOCKER_CONFIG/config.json" ]; then : >"$DOCKER_CONFIG/config.json" fi + if [ -x ./scripts/ci-docker.sh ] && [ -n "${BUILDER_NAME:-}" ]; then + ./scripts/ci-docker.sh buildx prune \ + --builder "$BUILDER_NAME" --filter until=168h \ + --keep-storage 8gb --force >/dev/null 2>&1 || true + fi if [ -d "${CI_ROOT:-}" ]; then printf '%s\n' "$JENKINS_NODE_PASSWORD" | \ sudo -S -p '' chown -R -- "$(id -u):$(id -g)" "$CI_ROOT" || true diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..96d4411 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docker-compose.yml b/docker-compose.yml index 7f21bf5..70aa2db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: postgres: - image: ${POSTGRES_IMAGE:-postgres:16-alpine} + image: ${POSTGRES_IMAGE:-docker.m.daocloud.io/library/postgres:16-alpine} restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB:-live_recorder} @@ -21,8 +21,8 @@ services: dockerfile: src/LiveRecorder.WebApi/Dockerfile network: host args: - DOTNET_SDK_IMAGE: ${DOTNET_SDK_IMAGE:-mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim} - DOTNET_RUNTIME_IMAGE: ${DOTNET_RUNTIME_IMAGE:-mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim} + DOTNET_SDK_IMAGE: ${DOTNET_SDK_IMAGE:-mcr.m.daocloud.io/dotnet/sdk:8.0-bookworm-slim} + DOTNET_RUNTIME_IMAGE: ${DOTNET_RUNTIME_IMAGE:-mcr.m.daocloud.io/dotnet/aspnet:8.0-bookworm-slim} restart: unless-stopped depends_on: postgres: @@ -43,8 +43,8 @@ services: dockerfile: Dockerfile network: host args: - NODE_IMAGE: ${NODE_IMAGE:-node:22-alpine} - NGINX_IMAGE: ${NGINX_IMAGE:-nginx:1.27-alpine} + NODE_IMAGE: ${NODE_IMAGE:-docker.m.daocloud.io/library/node:22-alpine} + NGINX_IMAGE: ${NGINX_IMAGE:-docker.m.daocloud.io/library/nginx:1.27-alpine} VITE_API_BASE_URL: /api restart: unless-stopped depends_on: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 6013667..2725c04 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,5 +1,5 @@ -ARG NODE_IMAGE=node:22-alpine -ARG NGINX_IMAGE=nginx:1.27-alpine +ARG NODE_IMAGE=docker.m.daocloud.io/library/node:22-alpine +ARG NGINX_IMAGE=docker.m.daocloud.io/library/nginx:1.27-alpine FROM ${NODE_IMAGE} AS build WORKDIR /app diff --git a/frontend/Dockerfile.arm64 b/frontend/Dockerfile.arm64 index 6b998cf..b28d3b8 100644 --- a/frontend/Dockerfile.arm64 +++ b/frontend/Dockerfile.arm64 @@ -1,4 +1,4 @@ -ARG NGINX_IMAGE=nginx:1.27-alpine +ARG NGINX_IMAGE=docker.m.daocloud.io/library/nginx:1.27-alpine FROM ${NGINX_IMAGE} diff --git a/scripts/build-arm64-image.sh b/scripts/build-arm64-image.sh index c5c8cdf..ebd58ed 100644 --- a/scripts/build-arm64-image.sh +++ b/scripts/build-arm64-image.sh @@ -12,7 +12,7 @@ # # Target environment: Windows + Docker Desktop (WSL2 backend) + a host HTTP proxy. # It encodes the workarounds discovered while building from a network where the -# Docker daemon cannot reliably reach mcr.microsoft.com / Docker Hub: +# Docker daemon cannot reliably reach upstream MCR / Docker Hub: # # 1. ARM64 QEMU emulation is registered via binfmt_misc with the `F` # (fix-binary) flag so the kernel-held fd works inside build containers. @@ -42,10 +42,10 @@ API_IMAGE_TAG="${API_IMAGE_TAG:-live-recorder-webapi:arm64}" FRONTEND_IMAGE_TAG="${FRONTEND_IMAGE_TAG:-live-recorder-frontend:arm64}" OUTPUT="${OUTPUT:-live-recorder-arm64.tar.gz}" WSL_DISTRO="${WSL_DISTRO:-Ubuntu}" -DOTNET_SDK_IMAGE="mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim" -DOTNET_RUNTIME_IMAGE="mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim" -NGINX_IMAGE="${NGINX_IMAGE:-nginx:1.27-alpine}" -NO_PROXY_HOSTS="mirrors.tuna.tsinghua.edu.cn,.tsinghua.edu.cn,localhost,127.0.0.1" +DOTNET_SDK_IMAGE="${DOTNET_SDK_IMAGE:-mcr.m.daocloud.io/dotnet/sdk:8.0-bookworm-slim}" +DOTNET_RUNTIME_IMAGE="${DOTNET_RUNTIME_IMAGE:-mcr.m.daocloud.io/dotnet/aspnet:8.0-bookworm-slim}" +NGINX_IMAGE="${NGINX_IMAGE:-docker.m.daocloud.io/library/nginx:1.27-alpine}" +NO_PROXY_HOSTS="mirrors.tuna.tsinghua.edu.cn,.tsinghua.edu.cn,mirrors.huaweicloud.com,.huaweicloud.com,mcr.m.daocloud.io,docker.m.daocloud.io,.m.daocloud.io,localhost,127.0.0.1" log() { printf '\n\033[1;36m[%s] %s\033[0m\n' "$(date +%H:%M:%S)" "$*"; } die() { printf '\n\033[1;31mERROR: %s\033[0m\n' "$*" >&2; exit 1; } diff --git a/scripts/build-fnos-package.sh b/scripts/build-fnos-package.sh index 20065f8..c11b2f3 100755 --- a/scripts/build-fnos-package.sh +++ b/scripts/build-fnos-package.sh @@ -75,7 +75,7 @@ npm run build --prefix "$ROOT_DIR/frontend" printf 'Publishing self-contained .NET application...\n' export NUGET_PACKAGES DOTNET_CLI_HOME -RESTORE_SOURCES=(--source "https://api.nuget.org/v3/index.json") +RESTORE_SOURCES=(--source "https://mirrors.huaweicloud.com/repository/nuget/v3/index.json") if [ -d "$NUGET_FEED" ]; then RESTORE_SOURCES=(--source "$NUGET_FEED" "${RESTORE_SOURCES[@]}") fi diff --git a/src/LiveRecorder.WebApi/Dockerfile b/src/LiveRecorder.WebApi/Dockerfile index 9109e28..55fce24 100644 --- a/src/LiveRecorder.WebApi/Dockerfile +++ b/src/LiveRecorder.WebApi/Dockerfile @@ -1,12 +1,11 @@ -ARG DOTNET_SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim -ARG DOTNET_RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim +ARG DOTNET_SDK_IMAGE=mcr.m.daocloud.io/dotnet/sdk:8.0-bookworm-slim +ARG DOTNET_RUNTIME_IMAGE=mcr.m.daocloud.io/dotnet/aspnet:8.0-bookworm-slim FROM ${DOTNET_SDK_IMAGE} AS build WORKDIR /src -# Proxy settings for NuGet restore (nuget.org is only reachable via the proxy -# from the build network). Declared as ARG then promoted to ENV so dotnet and -# the underlying HttpClient pick them up during restore/publish. +# Keep proxy settings available for any package endpoint fallback. The primary +# NuGet source is pinned to the domestic mirror in the repository NuGet.config. ARG HTTP_PROXY ARG HTTPS_PROXY ARG NO_PROXY