-
Notifications
You must be signed in to change notification settings - Fork 0
178 lines (163 loc) · 8.13 KB
/
Copy pathdocker-linux.yaml
File metadata and controls
178 lines (163 loc) · 8.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
---
name: docker-linux
"on":
pull_request:
paths:
- .github/workflows/docker-linux.yaml
- Dockerfile
workflow_dispatch:
permissions:
contents: read
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
defaults:
run:
shell: bash --noprofile --norc -euo pipefail {0}
env:
MISE_ENV: dart,dotnet,java,js,python,r,rust,zig
jobs:
build:
runs-on: ubuntu-latest
# Raised from 120 for the opensuse lane's CARGO_BUILD_JOBS=2 cap (see the cargo-test step).
# Capping concurrent jobs trades wall-clock for peak memory, and opensuse was already the slowest lane at
# 47m51s when green, so the old ceiling left too little margin. The other lanes finish in 39-44m and are
# unaffected; this only stops a slower-but-succeeding build from being cut off.
timeout-minutes: 150
strategy:
fail-fast: false
matrix:
base:
- amazonlinux:2023
- azurelinux v3.0
- debian:bookworm
- debian:trixie
- fedora:42
- opensuse/leap:15.6
- ubuntu:22.04
- ubuntu:24.04
- ubuntu:26.04
name: build (${{ matrix.base }})
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
persist-credentials: false
- name: Show MISE_ENV
run: echo "MISE_ENV=$MISE_ENV"
# Relocate Docker's data dir onto an LVM volume to maximize build space.
# jlumbroso/free-disk-space (which test.yaml uses) only frees space on the existing root partition. This
# workflow needs more: the image build writes to /var/lib/docker, so we have to relocate Docker's data dir
# onto an LVM volume that concatenates the freed root space with /mnt. easimon is the only maintained action
# that does that LVM remount, so we stay on it here despite its rougher edges (hard-fails on runners without
# /mnt or without a Docker daemon -- not a concern for this workflow's ubuntu-latest matrix, which has both).
- name: Maximize build space
uses: easimon/maximize-build-space@v10
with:
root-reserve-mb: 4096
swap-size-mb: 1024
remove-dotnet: "true"
remove-android: "true"
remove-haskell: "true"
remove-codeql: "true"
remove-docker-images: "true"
build-mount-path: /var/lib/docker
build-mount-path-ownership: "root:root"
- name: Restart Docker on the maximized volume
run: sudo systemctl restart docker
- name: Resolve BASE_IMAGE
env:
MATRIX_BASE: ${{ matrix.base }}
run: |
if [ "$MATRIX_BASE" = "azurelinux v3.0" ]; then
echo "BASE_IMAGE=mcr.microsoft.com/azurelinux/base/core:3.0" >> "$GITHUB_ENV"
else
echo "BASE_IMAGE=$MATRIX_BASE" >> "$GITHUB_ENV"
fi
- name: Build stage test
env:
DOCKER_BUILDKIT: "1"
GITHUB_TOKEN: ${{ github.token }}
run: |
args="--target test --build-arg BASE_IMAGE --build-arg MISE_ENV"
args="$args --secret id=gh_token,env=GITHUB_TOKEN -t et-test"
# $args is a word-split flag list by design; do not quote it.
# shellcheck disable=SC2086
docker build $args .
# The check stage needs `.git/` + every tracked Dockerfile.
# The main `.dockerignore` excludes both (`**/Dockerfile*` so Dockerfiles in subdirs don't bloat the build
# context), so we pre-stage them into a directory and hand it to docker as a named build context (`extras`).
# The check stage does `COPY --from=extras . ./` to land them in /workspace. `cp --parents` preserves the
# subdir path of each Dockerfile (e.g. services/ws-server/Dockerfile), so hadolint's
# `git ls-files '*Dockerfile' '*Dockerfile.*' | xargs hadolint` finds every entry on disk -- a top-level cp
# would have left subdir Dockerfiles unfindable.
- name: Build stage check
env:
CTX: target/check-ctx
DOCKER_BUILDKIT: "1"
TAG: et-check
gh_token: ${{ github.token }}
run: |
mkdir -p "$CTX"
cp -r .git "$CTX/"
git ls-files '*Dockerfile' '*Dockerfile.*' | xargs -I{} cp --parents {} "$CTX/"
args="--target check --build-arg BASE_IMAGE --build-arg MISE_ENV"
args="$args --build-context extras=$CTX --secret id=gh_token -t $TAG"
# $args is a word-split flag list by design; do not quote it.
# shellcheck disable=SC2086
docker build $args .
# Capture image + intermediate stage sizes after the builds.
# This also runs after the test/check runs leave any -rm'd container layers behind. `always()` so we still
# get the breakdown when a downstream step ran the disk dry; the typical failure mode (test-ws-web-runner
# compile inside `docker run`) leaves the host's image catalogue intact and this step is what surfaces
# which layer ballooned. -a includes intermediate/dangling layers each stage produces; `system df -v`
# totals per cache type (Images, Build Cache, Containers, Volumes).
- name: Docker disk usage (debug)
if: always()
run: |
echo "::group::docker images -a"
docker images -a
echo "::endgroup::"
echo "::group::docker system df -v"
docker system df -v
echo "::endgroup::"
echo "::group::df -h /var/lib/docker"
df -h /var/lib/docker || true
echo "::endgroup::"
# Report which paths inside the et-test image are eating space.
# `du --threshold=10M --max-depth=2` for a top-level subtree map (catches install dirs, tool caches,
# /var stragglers); `find ... -size +50M` for the individual heavyweights. Run in a throwaway container
# so the host's writable layer doesn't tilt the numbers; find/du stderr noise (unreadable /proc entries
# etc.) prints to the log but doesn't affect the sort pipeline.
echo "::group::et-test: largest dirs (depth 2, >=10M)"
docker run --rm et-test sh -c "du -h --threshold=10M --max-depth=2 / | sort -h | tail -50"
echo "::endgroup::"
echo "::group::et-test: individual files >50M"
docker run --rm et-test sh -c "find / -xdev -type f -size +50M -exec du -h {} + | sort -h | tail -50"
echo "::endgroup::"
# Every cargo knob here is passed INTO the container, not set on the job.
# The compile happens inside `docker run`, so a job-level env would never reach cargo.
#
# CARGO_INCREMENTAL=0: incremental caches buy nothing on a single-shot CI compile and cost disk.
#
# CARGO_PROFILE_DEV_DEBUG=0: debug info is the bulk of what the linker reads and writes, so dropping it
# cuts peak linker memory and disk while making the build faster -- unlike a parallelism cap, it costs no
# wall-clock. The trade is shallower backtraces if a test panics on these lanes. Applied to every lane
# because two of them have already died mid-`cargo-test`: amazonlinux once, and opensuse on all three
# attempts of run 30872860977, each time with the log never published and the step frozen `in_progress`
# at ~1h13m against a 120m limit -- the shape of the runner being killed rather than a build error.
#
# CARGO_BUILD_JOBS=2 on opensuse only: it is the slowest lane even when green (47m51s vs 39-44m) and the
# only one still failing, so it links under the most memory pressure. Capping concurrent codegen/link jobs
# is the direct lever, kept off the other lanes because it does cost wall-clock -- which is why
# timeout-minutes went to 150 alongside it.
- name: Run cargo-test
env:
LANE_ARGS: ${{ matrix.base == 'opensuse/leap:15.6' && '-e CARGO_BUILD_JOBS=2' || '' }}
run: |
# $LANE_ARGS is a word-split flag list by design; do not quote it.
# shellcheck disable=SC2086
docker run --rm -e CARGO_INCREMENTAL=0 -e CARGO_PROFILE_DEV_DEBUG=0 $LANE_ARGS et-test mise run cargo-test
- name: Run mise check
run: docker run --rm et-check