Skip to content

Commit 8edac61

Browse files
authored
feat(ci): allow routing apt traffic through an alternate Ubuntu mirror (mudler#9650)
* feat(ci): allow routing apt traffic through an alternate Ubuntu mirror Adds opt-in APT_MIRROR / APT_PORTS_MIRROR knobs to all Dockerfiles, the Makefile, and CI workflows so we can fail over to a non-canonical Ubuntu mirror when archive.ubuntu.com / security.ubuntu.com / ports.ubuntu.com are degraded (recently observed: multi-day DDoS against the default pool). Defaults are empty everywhere — behavior is unchanged unless a mirror is configured. To enable in CI, set the repo-level GitHub Actions variables APT_MIRROR (and APT_PORTS_MIRROR for arm64 builds). Locally: make docker APT_MIRROR=http://azure.archive.ubuntu.com A small POSIX-sh helper in .docker/apt-mirror.sh rewrites both DEB822 (/etc/apt/sources.list.d/ubuntu.sources, Ubuntu 24.04+) and the legacy /etc/apt/sources.list before the first apt-get update. Dockerfile stages load it via RUN --mount=type=bind, so there is no extra layer and no cache invalidation when the script is unchanged. Reusable workflows also rewrite the runner's own /etc/apt sources before any sudo apt-get call. Assisted-by: Claude:claude-opus-4-7[1m] [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * ci(apt-mirror): default to the Azure mirror, visible in the workflow source Bakes Azure (http://azure.archive.ubuntu.com / http://azure.ports.ubuntu.com) in as the default for both Docker builds and runner-side apt — rather than hiding the URL behind a GitHub Actions repo variable that's not visible from the source tree. A new composite action at .github/actions/configure-apt-mirror is the single source of truth for runner-side rewrites. Five standalone workflows (build-test, release, tests-e2e, tests-ui-e2e, update_swagger) just `uses: ./.github/actions/configure-apt-mirror`. Three workflows (image_build, backend_build, checksum_checker) keep an inline bash rewrite, because they install/upgrade git via apt *before* the checkout step (so the local composite action isn't loadable yet). The Azure URL is visible in those files too. The `apt-mirror` / `apt-ports-mirror` inputs of the reusable workflows keep their now-Azure defaults — they still feed the Docker build-args block in addition to the inline runner-side rewrite. Callers (image.yml, image-pr.yml, backend.yml, backend_pr.yml) drop the previous `vars.APT_MIRROR` plumbing and rely on those defaults. Assisted-by: Claude:claude-opus-4-7[1m] [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * ci(apt-mirror): drop Force Install GIT, consolidate on the composite action The PPA git upgrade ran add-apt-repository ppa:git-core/ppa, which talks to api.launchpad.net — also part of Canonical's infrastructure and currently returning HTTP 504. The Azure mirror only covers archive.ubuntu.com / security.ubuntu.com / ports.ubuntu.com, not PPAs. The system git that ubuntu-latest already ships is sufficient for actions/checkout and the build pipeline, so just drop the upgrade. With that gone, the apt-before-checkout constraint disappears too — all three holdouts (image_build, backend_build, checksum_checker) can now switch to ./.github/actions/configure-apt-mirror like the other five. Net: 0 inline apt-mirror blocks, all 8 workflows route through the composite action. Assisted-by: Claude:claude-opus-4-7[1m] [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
1 parent 0b024f0 commit 8edac61

18 files changed

Lines changed: 241 additions & 43 deletions

.docker/apt-mirror.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/sh
2+
# Reconfigure Ubuntu apt sources to point at an alternate mirror.
3+
#
4+
# Used by Dockerfiles via `RUN --mount=type=bind,source=.docker/apt-mirror.sh,...`
5+
# and by CI workflows on the runner to mitigate outages of the default
6+
# archive.ubuntu.com / security.ubuntu.com / ports.ubuntu.com pool.
7+
#
8+
# Inputs (env):
9+
# APT_MIRROR Replacement for archive.ubuntu.com and security.ubuntu.com
10+
# (e.g. "http://azure.archive.ubuntu.com" or
11+
# "https://mirrors.edge.kernel.org").
12+
# Leave empty to keep upstream. The trailing "/ubuntu/..."
13+
# path is preserved by the rewrite.
14+
# APT_PORTS_MIRROR Replacement for ports.ubuntu.com (arm64/ppc64el/...).
15+
# Leave empty to keep upstream.
16+
#
17+
# Both default to empty, in which case the script is a no-op.
18+
19+
set -e
20+
21+
if [ -z "${APT_MIRROR}" ] && [ -z "${APT_PORTS_MIRROR}" ]; then
22+
exit 0
23+
fi
24+
25+
# Ubuntu 24.04 (noble) ships DEB822 sources at /etc/apt/sources.list.d/ubuntu.sources;
26+
# older releases use /etc/apt/sources.list. We rewrite whichever exists.
27+
for f in /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list; do
28+
[ -f "$f" ] || continue
29+
if [ -n "${APT_MIRROR}" ]; then
30+
# Use a comma delimiter so the alternation pipe in the regex
31+
# is not interpreted as the s/// separator.
32+
sed -i -E "s,https?://(archive\.ubuntu\.com|security\.ubuntu\.com),${APT_MIRROR},g" "$f"
33+
fi
34+
if [ -n "${APT_PORTS_MIRROR}" ]; then
35+
sed -i -E "s,https?://ports\.ubuntu\.com,${APT_PORTS_MIRROR},g" "$f"
36+
fi
37+
done
38+
39+
echo "apt-mirror: rewrote sources (APT_MIRROR='${APT_MIRROR}', APT_PORTS_MIRROR='${APT_PORTS_MIRROR}')"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: 'Configure apt mirror'
2+
description: |
3+
Reconfigure the GitHub Actions runner's Ubuntu apt sources to use an
4+
alternate mirror. Defaults to the Azure-hosted Ubuntu mirror, which lives
5+
on the same network as the runners and is independent of the canonical
6+
Ubuntu pool — useful as a fallback when archive.ubuntu.com /
7+
security.ubuntu.com / ports.ubuntu.com are degraded.
8+
9+
Pass mirror: '' (empty string) to skip the rewrite and keep upstream.
10+
11+
inputs:
12+
mirror:
13+
description: 'Replacement URL for archive.ubuntu.com / security.ubuntu.com (empty = keep upstream)'
14+
required: false
15+
default: 'http://azure.archive.ubuntu.com'
16+
ports-mirror:
17+
description: 'Replacement URL for ports.ubuntu.com on arm64 (empty = keep upstream)'
18+
required: false
19+
default: 'http://azure.ports.ubuntu.com'
20+
21+
runs:
22+
using: 'composite'
23+
steps:
24+
- name: Rewrite apt sources
25+
shell: bash
26+
env:
27+
APT_MIRROR: ${{ inputs.mirror }}
28+
APT_PORTS_MIRROR: ${{ inputs.ports-mirror }}
29+
run: |
30+
set -e
31+
if [ -z "${APT_MIRROR}" ] && [ -z "${APT_PORTS_MIRROR}" ]; then
32+
echo "configure-apt-mirror: both inputs empty, leaving upstream sources untouched"
33+
exit 0
34+
fi
35+
# Ubuntu 24.04 (noble) ships DEB822 sources at
36+
# /etc/apt/sources.list.d/ubuntu.sources; older releases use
37+
# /etc/apt/sources.list. Rewrite whichever exists.
38+
for f in /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list; do
39+
sudo test -f "$f" || continue
40+
if [ -n "${APT_MIRROR}" ]; then
41+
# Comma delimiter so the alternation pipe in the regex is not
42+
# interpreted as the s/// separator.
43+
sudo sed -i -E "s,https?://(archive\.ubuntu\.com|security\.ubuntu\.com),${APT_MIRROR},g" "$f"
44+
fi
45+
if [ -n "${APT_PORTS_MIRROR}" ]; then
46+
sudo sed -i -E "s,https?://ports\.ubuntu\.com,${APT_PORTS_MIRROR},g" "$f"
47+
fi
48+
done
49+
echo "configure-apt-mirror: APT_MIRROR='${APT_MIRROR}' APT_PORTS_MIRROR='${APT_PORTS_MIRROR}'"

.github/workflows/backend_build.yml

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ on:
6363
required: false
6464
default: ''
6565
type: string
66+
apt-mirror:
67+
description: 'Replacement URL for archive.ubuntu.com / security.ubuntu.com (empty = use upstream)'
68+
required: false
69+
default: 'http://azure.archive.ubuntu.com'
70+
type: string
71+
apt-ports-mirror:
72+
description: 'Replacement URL for ports.ubuntu.com (arm64 etc., empty = use upstream)'
73+
required: false
74+
default: 'http://azure.ports.ubuntu.com'
75+
type: string
6676
secrets:
6777
dockerUsername:
6878
required: false
@@ -80,6 +90,16 @@ jobs:
8090
quay_username: ${{ secrets.quayUsername }}
8191
steps:
8292

93+
- name: Checkout
94+
uses: actions/checkout@v6
95+
with:
96+
submodules: true
97+
98+
- name: Configure apt mirror on runner
99+
uses: ./.github/actions/configure-apt-mirror
100+
with:
101+
mirror: ${{ inputs.apt-mirror }}
102+
ports-mirror: ${{ inputs.apt-ports-mirror }}
83103

84104
- name: Free Disk Space (Ubuntu)
85105
if: inputs.runs-on == 'ubuntu-latest'
@@ -97,20 +117,6 @@ jobs:
97117
docker-images: true
98118
swap-storage: true
99119

100-
- name: Force Install GIT latest
101-
run: |
102-
sudo apt-get update \
103-
&& sudo apt-get install -y software-properties-common \
104-
&& sudo apt-get update \
105-
&& sudo add-apt-repository -y ppa:git-core/ppa \
106-
&& sudo apt-get update \
107-
&& sudo apt-get install -y git
108-
109-
- name: Checkout
110-
uses: actions/checkout@v6
111-
with:
112-
submodules: true
113-
114120
- name: Release space from worker
115121
if: inputs.runs-on == 'ubuntu-latest'
116122
run: |
@@ -231,6 +237,8 @@ jobs:
231237
BACKEND=${{ inputs.backend }}
232238
UBUNTU_VERSION=${{ inputs.ubuntu-version }}
233239
AMDGPU_TARGETS=${{ inputs.amdgpu-targets }}
240+
APT_MIRROR=${{ inputs.apt-mirror }}
241+
APT_PORTS_MIRROR=${{ inputs.apt-ports-mirror }}
234242
DEPS_REFRESH=${{ steps.deps_refresh.outputs.key }}
235243
context: ${{ inputs.context }}
236244
file: ${{ inputs.dockerfile }}
@@ -255,6 +263,8 @@ jobs:
255263
BACKEND=${{ inputs.backend }}
256264
UBUNTU_VERSION=${{ inputs.ubuntu-version }}
257265
AMDGPU_TARGETS=${{ inputs.amdgpu-targets }}
266+
APT_MIRROR=${{ inputs.apt-mirror }}
267+
APT_PORTS_MIRROR=${{ inputs.apt-ports-mirror }}
258268
DEPS_REFRESH=${{ steps.deps_refresh.outputs.key }}
259269
context: ${{ inputs.context }}
260270
file: ${{ inputs.dockerfile }}

.github/workflows/build-test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ jobs:
5050
uses: actions/checkout@v6
5151
with:
5252
fetch-depth: 0
53+
- name: Configure apt mirror on runner
54+
uses: ./.github/actions/configure-apt-mirror
5355
- name: Set up Go
5456
uses: actions/setup-go@v5
5557
with:

.github/workflows/checksum_checker.yaml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,9 @@ jobs:
88
if: github.repository == 'mudler/LocalAI'
99
runs-on: ubuntu-latest
1010
steps:
11-
- name: Force Install GIT latest
12-
run: |
13-
sudo apt-get update \
14-
&& sudo apt-get install -y software-properties-common \
15-
&& sudo apt-get update \
16-
&& sudo add-apt-repository -y ppa:git-core/ppa \
17-
&& sudo apt-get update \
18-
&& sudo apt-get install -y git
1911
- uses: actions/checkout@v6
12+
- name: Configure apt mirror on runner
13+
uses: ./.github/actions/configure-apt-mirror
2014
- name: Install dependencies
2115
run: |
2216
sudo apt-get update

.github/workflows/image_build.yml

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ on:
5656
required: false
5757
default: 'noble'
5858
type: string
59+
apt-mirror:
60+
description: 'Replacement URL for archive.ubuntu.com / security.ubuntu.com (empty = use upstream)'
61+
required: false
62+
default: 'http://azure.archive.ubuntu.com'
63+
type: string
64+
apt-ports-mirror:
65+
description: 'Replacement URL for ports.ubuntu.com (arm64 etc., empty = use upstream)'
66+
required: false
67+
default: 'http://azure.ports.ubuntu.com'
68+
type: string
5969
secrets:
6070
dockerUsername:
6171
required: true
@@ -70,6 +80,15 @@ jobs:
7080
runs-on: ${{ inputs.runs-on }}
7181
steps:
7282

83+
- name: Checkout
84+
uses: actions/checkout@v6
85+
86+
- name: Configure apt mirror on runner
87+
uses: ./.github/actions/configure-apt-mirror
88+
with:
89+
mirror: ${{ inputs.apt-mirror }}
90+
ports-mirror: ${{ inputs.apt-ports-mirror }}
91+
7392
- name: Free Disk Space (Ubuntu)
7493
if: inputs.runs-on == 'ubuntu-latest'
7594
uses: jlumbroso/free-disk-space@main
@@ -85,16 +104,6 @@ jobs:
85104
large-packages: true
86105
docker-images: true
87106
swap-storage: true
88-
- name: Force Install GIT latest
89-
run: |
90-
sudo apt-get update \
91-
&& sudo apt-get install -y software-properties-common \
92-
&& sudo apt-get update \
93-
&& sudo add-apt-repository -y ppa:git-core/ppa \
94-
&& sudo apt-get update \
95-
&& sudo apt-get install -y git
96-
- name: Checkout
97-
uses: actions/checkout@v6
98107

99108
- name: Release space from worker
100109
if: inputs.runs-on == 'ubuntu-latest'
@@ -205,6 +214,8 @@ jobs:
205214
SKIP_DRIVERS=${{ inputs.skip-drivers }}
206215
UBUNTU_VERSION=${{ inputs.ubuntu-version }}
207216
UBUNTU_CODENAME=${{ inputs.ubuntu-codename }}
217+
APT_MIRROR=${{ inputs.apt-mirror }}
218+
APT_PORTS_MIRROR=${{ inputs.apt-ports-mirror }}
208219
context: .
209220
file: ./Dockerfile
210221
cache-from: type=registry,ref=quay.io/go-skynet/ci-cache:cache-localai${{ inputs.tag-suffix }}
@@ -228,6 +239,8 @@ jobs:
228239
SKIP_DRIVERS=${{ inputs.skip-drivers }}
229240
UBUNTU_VERSION=${{ inputs.ubuntu-version }}
230241
UBUNTU_CODENAME=${{ inputs.ubuntu-codename }}
242+
APT_MIRROR=${{ inputs.apt-mirror }}
243+
APT_PORTS_MIRROR=${{ inputs.apt-ports-mirror }}
231244
context: .
232245
file: ./Dockerfile
233246
cache-from: type=registry,ref=quay.io/go-skynet/ci-cache:cache-localai${{ inputs.tag-suffix }}

.github/workflows/release.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ jobs:
4949
uses: actions/checkout@v6
5050
with:
5151
fetch-depth: 0
52+
- name: Configure apt mirror on runner
53+
uses: ./.github/actions/configure-apt-mirror
5254
- name: Set up Go
5355
uses: actions/setup-go@v5
5456
with:

.github/workflows/tests-e2e.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ jobs:
3030
uses: actions/checkout@v6
3131
with:
3232
submodules: true
33+
- name: Configure apt mirror on runner
34+
uses: ./.github/actions/configure-apt-mirror
3335
- name: Setup Go ${{ matrix.go-version }}
3436
uses: actions/setup-go@v5
3537
with:

.github/workflows/tests-ui-e2e.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ jobs:
2626
uses: actions/checkout@v6
2727
with:
2828
submodules: true
29+
- name: Configure apt mirror on runner
30+
uses: ./.github/actions/configure-apt-mirror
2931
- name: Setup Go ${{ matrix.go-version }}
3032
uses: actions/setup-go@v5
3133
with:

.github/workflows/update_swagger.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ jobs:
1111
runs-on: ubuntu-latest
1212
steps:
1313
- uses: actions/checkout@v6
14+
- name: Configure apt mirror on runner
15+
uses: ./.github/actions/configure-apt-mirror
1416
- uses: actions/setup-go@v5
1517
with:
1618
go-version: 'stable'

0 commit comments

Comments
 (0)