refactor(openclaw): thin Docker image with Nix deps offloaded to Harmonia
Strips runtime packages (nodejs_22, kubectl, jq, git, emacs, tsx, tea, pythonEnv, qmd) from the Docker image contents, reducing image size from ~2.7GB to ~1.5GB. Key changes: - Removed 9 runtime packages from contents (moved to openclaw-runtime-closure) - Removed pythonEnv let binding and qmd parameter (no longer needed in image) - Added OPENCLAW_RUNTIME_CLOSURE env var (bakes closure path for init container) - Added runtime closure bin dir to PATH (resolves after PVC population) - Added curl to contents (needed by init container for Harmonia health checks) - CI: added openclaw-runtime-closure to build-and-cache PACKAGES array - CI: added second sed command for CronJob image tag update - CI: removed inherit qmd from openclaw-image callPackage (qmd now in runtime closure) Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -50,6 +50,7 @@ jobs:
|
||||
custom-rclone-torbox-setup
|
||||
custom-opencode
|
||||
custom-qmd
|
||||
openclaw-runtime-closure
|
||||
custom-nextcloud-talk-desktop
|
||||
qt-pinned-jellyfin-media-player
|
||||
qt-pinned-stremio
|
||||
@@ -186,8 +187,12 @@ jobs:
|
||||
- name: Update HelmRelease image tag
|
||||
run: |
|
||||
cd k3s-cluster-config
|
||||
# Update HelmRelease image tags (quoted format: tag: "version")
|
||||
sed -i 's|tag: ".*"|tag: "${{ needs.build-and-push-openclaw.outputs.image_tag }}"|' \
|
||||
clusters/oglenet/apps/communication/openclaw.yaml
|
||||
# Update CronJob image reference (registry:tag format)
|
||||
sed -i 's|registry.johnogle.info/openclaw:.*|registry.johnogle.info/openclaw:${{ needs.build-and-push-openclaw.outputs.image_tag }}|' \
|
||||
clusters/oglenet/apps/communication/openclaw.yaml
|
||||
|
||||
- name: Commit and push
|
||||
run: |
|
||||
|
||||
@@ -9,6 +9,6 @@ rec {
|
||||
nextcloud-talk-desktop = pkgs.callPackage ./nextcloud-talk-desktop { };
|
||||
opencode = pkgs.callPackage ./opencode { };
|
||||
qmd = pkgs.callPackage ./qmd { };
|
||||
openclaw-image = pkgs.callPackage ./openclaw-image { inherit qmd; };
|
||||
openclaw-image = pkgs.callPackage ./openclaw-image { };
|
||||
openclaw-runtime-closure = pkgs.callPackage ./openclaw-image/runtime-closure.nix { inherit qmd; };
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
qmd,
|
||||
}:
|
||||
|
||||
let
|
||||
@@ -82,9 +81,6 @@ let
|
||||
echo "Successfully extracted openclaw app"
|
||||
'';
|
||||
|
||||
# Python environment with pymupdf
|
||||
pythonEnv = pkgs.python3.withPackages (ps: [ ps.pymupdf ]);
|
||||
|
||||
# Custom NSS files that include the "node" user (UID 1000, GID 1000).
|
||||
# fakeNss only creates root/nobody, so we create our own with all three.
|
||||
openclawNss = pkgs.runCommand "openclaw-nss" { } ''
|
||||
@@ -164,30 +160,19 @@ pkgs.dockerTools.buildLayeredImage {
|
||||
entrypointPkg
|
||||
|
||||
# Runtime package manager (agents can `nix run` arbitrary packages)
|
||||
# Also needed by init container for `nix copy --from` to populate PVC from Harmonia
|
||||
pkgs.nix
|
||||
|
||||
# Tools baked into the image
|
||||
pkgs.kubectl
|
||||
pkgs.jq
|
||||
# HTTP client (needed for init container Harmonia health checks and fallback)
|
||||
pkgs.curl
|
||||
pkgs.git
|
||||
pkgs.emacs
|
||||
|
||||
# Node.js 22+ (for openclaw runtime, QMD, matrix-bot-sdk)
|
||||
pkgs.nodejs_22
|
||||
|
||||
# TypeScript runtime (for running TypeScript files directly, e.g. via nix run)
|
||||
pkgs.tsx
|
||||
|
||||
# Python with pymupdf (PDF-to-image for Claude vision)
|
||||
pythonEnv
|
||||
|
||||
# Gitea CLI (PR workflow)
|
||||
pkgs.tea
|
||||
|
||||
# QMD — on-device hybrid search for markdown (built with Node.js 22, not Bun)
|
||||
qmd
|
||||
];
|
||||
# NOTE: Runtime packages (nodejs_22, kubectl, jq, git, emacs, tsx, tea,
|
||||
# pythonEnv, qmd) are NOT in contents. They live in the
|
||||
# `openclaw-runtime-closure` meta-package, which CI pushes to the
|
||||
# Harmonia binary cache. The init container pulls them from Harmonia
|
||||
# into the PVC at pod startup. This keeps the Docker image thin (~1.5GB
|
||||
# vs the previous ~2.7GB) and makes CI pushes fast.
|
||||
#
|
||||
# NOTE: openclawApp is NOT in contents. It would create /app as a symlink
|
||||
# to /nix/store/..., which breaks OpenClaw's symlink escape security check
|
||||
# (resolved paths "escape" /app/dist/extensions). Instead, extraCommands
|
||||
@@ -232,12 +217,17 @@ pkgs.dockerTools.buildLayeredImage {
|
||||
# Nix configuration
|
||||
"NIX_PATH=nixpkgs=flake:nixpkgs"
|
||||
|
||||
# PATH: standard dirs + Nix store bin dirs are appended by buildLayeredImage
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
# PATH: standard dirs + Nix store bin dirs appended by buildLayeredImage
|
||||
# + runtime closure bin dir (populated from Harmonia by init container into PVC)
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${pkgs.custom.openclaw-runtime-closure}/bin"
|
||||
"NODE_ENV=production"
|
||||
|
||||
# Home directory (Docker User directive doesn't set HOME from /etc/passwd)
|
||||
"HOME=/home/node"
|
||||
# Runtime closure path — init container uses this to `nix copy --from` Harmonia
|
||||
# This creates a build dependency (Nix resolves the path) but the closure
|
||||
# is NOT in `contents`, so it won't be in the image layers.
|
||||
"OPENCLAW_RUNTIME_CLOSURE=${pkgs.custom.openclaw-runtime-closure}"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user