Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ docs/build
lib
private
examples
# The Python env CondaPkg creates for the export tests; it ships BUILD files of its own.
packages/ReactantServerExport/test/.CondaPkg
72 changes: 72 additions & 0 deletions .github/workflows/image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Build the locked CUDA node image with Bazel (//deploy:image) and push it to Docker Hub as :latest.
# Triggered by hand only: Actions > Image > Run workflow, or `gh workflow run image.yml --ref <branch>`.
#
# Releases are not named yet, so every run overwrites :latest. The image digest is printed in the
# run summary; pull by that digest to pin a deployment.
#
# Needs, in the repository settings:
# variable DOCKERHUB_REPOSITORY the target, e.g. index.docker.io/<org>/<name>
# secret DOCKERHUB_USERNAME
# secret DOCKERHUB_TOKEN a Docker Hub access token with write access to that repository
name: Image

on:
workflow_dispatch:

# Two runs pushing :latest at once would race; the later one waits instead.
concurrency:
group: image-latest
cancel-in-progress: false

permissions:
contents: read

jobs:
image:
runs-on: ubuntu-latest
timeout-minutes: 240
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

# The CUDA base, the depot (Reactant's CUDA artifact included) and the layers built from them
# need tens of gigabytes. The runner's root disk is too small for that once its preinstalled
# toolchains are counted, so those are removed and Bazel keeps everything on /mnt.
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
sudo mkdir -p /mnt/bazel
sudo chown "$(id -u):$(id -g)" /mnt/bazel
printf '%s\n' \
'startup --output_user_root=/mnt/bazel/root' \
'common --repository_cache=/mnt/bazel/repository-cache' \
> user.bazelrc
df -h / /mnt

# Bazelisk is preinstalled as `bazel` and runs the version in .bazelversion.
- name: Check the Julia lock
run: bazel test //deploy:manifest_current

# Builds every layer, then loads every entry project from them with nothing precompiled and
# no cache rejected. A failure here stops the run before anything is pushed.
- name: Build the image and check it starts warm
run: bazel test //deploy:image_precompile_test

- name: Log in to Docker Hub
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Push :latest
env:
REPOSITORY: ${{ vars.DOCKERHUB_REPOSITORY }}
run: |
: "${REPOSITORY:?set the DOCKERHUB_REPOSITORY repository variable}"
bazel run //deploy:image_push -- --repository "$REPOSITORY"
digest="$(jq -r '.manifests[0].digest' bazel-bin/deploy/image/index.json)"
{
echo "Pushed \`$REPOSITORY:latest\`"
echo
echo "Digest: \`$digest\` (commit \`$GITHUB_SHA\`)"
} >> "$GITHUB_STEP_SUMMARY"
3 changes: 3 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

package(default_visibility = ["//deploy:__pkg__"])

# The root project, which //deploy:depot_layer instantiates from the committed deploy/Manifest.toml.
exports_files(["Project.toml"])

# ReactantServerExport is offline tooling and not a workspace member (see Project.toml); the image
# does not carry it.
_NOT_IN_IMAGE = ["packages/ReactantServerExport/**"]
Expand Down
8 changes: 6 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,18 @@ bazel test //deploy:manifest_current

The Ubuntu packages the image adds to the CUDA base (`curl`, `tini`) are locked the same way in
`deploy/debs.lock.json`; moving the base image digest in `MODULE.bazel` calls for
`bazel run //deploy:relock_debs`. After any change to the image, load it and check that it starts
without precompiling:
`bazel run //deploy:relock_debs`. After any change to the image, check that it starts without
precompiling, on its layers and then in a loaded container:

```
bazel test //deploy:image_precompile_test
bazel run //deploy:image_load
bazel run //deploy:image_check
```

The image is published to Docker Hub as `:latest` by the manually triggered
`.github/workflows/image.yml`; see [`deploy/README.md`](deploy/README.md#publishing).

## Kaimon gate tools (dev only)

`packages/ReactantServer/ext/ReactantServerKaimonGateExt.jl` registers four `rserver_*` GateTools with a running
Expand Down
38 changes: 25 additions & 13 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,32 @@ module(
# build, so the same commit always yields the same package and artifact set.

# Bazel 9 moved sh_binary/sh_test out of the core into rules_shell.
bazel_dep(name = "rules_shell", version = "0.7.1")
bazel_dep(name = "rules_shell", version = "0.8.0")

# rules_oci assembles OCI images with no daemon; podman is needed only to load and run the result.
bazel_dep(name = "rules_oci", version = "2.2.6")
#
# 2.3.3, the latest release, which has not reached the Bazel Central Registry (2.3.0 is the newest
# there), so it is fetched from the release archive. The fix that matters here is oci_load's: before
# 2.3.1 (#881) it reported success when the tar it streams into the loader failed, so a broken
# load of this multi-gigabyte image looked like a good one. 2.3.1 also makes oci_pull repositories
# resolve their own dependencies under bzlmod (#891). Since 2.3.0 it also depends on a
# current aspect_bazel_lib, so the Bazel 9 workaround of naming aspect_bazel_lib here is gone.
# Drop the override once the registry has 2.3.3 or later.
bazel_dep(name = "rules_oci", version = "2.3.3")
archive_override(
module_name = "rules_oci",
integrity = "sha256-JD6sh+xB1o0dnm0hiEpQ7CjgMfcCsLn83H+Xw/PVOJo=",
strip_prefix = "rules_oci-2.3.3",
urls = ["https://github.com/bazel-contrib/rules_oci/releases/download/v2.3.3/rules_oci-v2.3.3.tar.gz"],
)

# rules_oci 2.2.6 pins aspect_bazel_lib 2.7.2, which registers its tar and zstd toolchains
# against @local_config_platform. Bazel 9 removed that repo, so toolchain resolution fails for
# every target, including ones unrelated to images ("invalid registered toolchain
# '@zstd_toolchains//:all'"). MVS takes the higher version, so naming it here is the whole fix.
bazel_dep(name = "aspect_bazel_lib", version = "2.22.5")
# bsdtar, from the toolchain rules_oci uses (tar.bzl since rules_oci 2.3), reads .deb files (ar
# archives holding zstd or xz tarballs) and the pulled base image's layers, so //deploy needs
# neither dpkg nor ar on the host.
bazel_dep(name = "tar.bzl", version = "0.10.9")

# bsdtar, from the same toolchain rules_oci uses, reads .deb files (ar archives holding zstd or xz
# tarballs) and the pulled base image's layers, so //deploy needs neither dpkg nor ar on the host.
bazel_lib_toolchains = use_extension("@aspect_bazel_lib//lib:extensions.bzl", "toolchains")
use_repo(bazel_lib_toolchains, "bsd_tar_toolchains")
tar = use_extension("@tar.bzl//tar:extensions.bzl", "toolchains")
use_repo(tar, "bsd_tar_toolchains")

# The Ubuntu packages the image adds to the CUDA base (curl, tini and their dependencies), each
# pinned by snapshot URL and sha256 in deploy/debs.lock.json. Re-resolve with
Expand All @@ -36,11 +47,12 @@ debs.lock(
)
use_repo(debs, "reactantserver_debs")

# The Julia toolchain, the clean-depot image layer and the podman loader.
# The Julia toolchain, and the image rules (julia/image.bzl): the distribution, depot and
# precompile-cache layers, the image environment, and the precompile test.
bazel_dep(name = "rules_julia_depot", version = "0.1.0")
git_override(
module_name = "rules_julia_depot",
commit = "49bc678d037fa967920edccc380a6721a20050ee",
commit = "cead3479d64e7bf56fac66a15b72e9c4cd45ddc8",
remote = "https://github.com/csvance/rules_julia_depot.git",
)

Expand Down
Loading
Loading