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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules
.yarn
packages/cubejs-docker/stacklet-patches/*-dist/
.yarnrc
/.idea
/.vscode
Expand Down
41 changes: 41 additions & 0 deletions packages/cubejs-docker/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,44 @@ docker build -t cubejs/cube:latest-jdk -f latest-debian-jdk.Dockerfile .
docker build -t cubejs/cube:dev -f dev.Dockerfile ../../
docker buildx build --platform linux/amd64 -t cubejs/cube:dev -f dev.Dockerfile ../../
```

## Stacklet builds

The Stacklet fork patches certain Cube packages at the TypeScript source level.
Because `latest.Dockerfile` installs packages from npm (not from the local
workspace), a wrapper script is required to compile modified packages and stage
their compiled output before `docker build` runs.

**Always use the build script — never `docker build` directly:**

```sh
# From the repo root:
./scripts/build-docker.sh cubejs/cube:v1.6.6-stacklet-$(git rev-parse --short HEAD)
```

The script:
1. Runs `yarn workspace @cubejs-backend/server-core build` (and any other
patched packages)
2. Copies compiled `dist/` output into `stacklet-patches/<pkg>-dist/`
3. Runs `docker build`; the Dockerfile overlays those dist files on the
npm-installed versions
4. Cleans up the staged files on exit

### Adding a new patched package

1. Make source changes and compile: `yarn workspace @cubejs-backend/<pkg> build`
2. Add a compile + stage block to `scripts/build-docker.sh`:
```bash
mkdir -p "$PATCHES_DIR/<pkg>-dist"
cp -r "$REPO_ROOT/packages/cubejs-<pkg>/dist/." "$PATCHES_DIR/<pkg>-dist/"
```
3. No Dockerfile change is needed — `latest.Dockerfile` automatically applies
any `*-dist/` directories it finds in `stacklet-patches/`.

### Verifying a patch is in the image

```sh
docker run --rm <tag> grep -c "Performing query completed" \
/cube/node_modules/@cubejs-backend/server-core/dist/src/core/logger.js
# expected: 2
```
8 changes: 8 additions & 0 deletions packages/cubejs-docker/latest.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ RUN yarn install --prod \
&& rm -rf /cube/node_modules/duckdb/src \
&& yarn cache clean

# Stacklet: overlay locally compiled dist files over npm-installed packages.
# stacklet-patches/<pkg>-dist/ dirs are populated by scripts/build-docker.sh.
COPY stacklet-patches/ /cube/stacklet-patches/
RUN find /cube/stacklet-patches -maxdepth 1 -name '*-dist' -type d | while read d; do \
pkg=$(basename "$d" -dist); \
cp -r "$d/." "/cube/node_modules/@cubejs-backend/$pkg/dist/"; \
done && rm -rf /cube/stacklet-patches

FROM node:22.22.0-bookworm-slim

ARG IMAGE_VERSION=unknown
Expand Down
Empty file.
6 changes: 6 additions & 0 deletions packages/cubejs-server-core/src/core/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ export const prodLogger = (level?: LogLevel) => (msg: string, params: ProdLogPar

const logMessage = () => console.log(JSON.stringify({ message: msg, ...params }));

// Always emit regardless of log level — used by CloudWatch log metric filter
if (msg === 'Performing query completed') {
logMessage();
return;
}

// eslint-disable-next-line default-case
switch ((level || 'warn').toLowerCase()) {
case 'trace': {
Expand Down
58 changes: 58 additions & 0 deletions scripts/build-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Build a Stacklet Cube Docker image.
#
# Usage: ./scripts/build-docker.sh [TAG]
# TAG defaults to cubejs/cube:dev
#
# This script compiles Stacklet-patched packages and stages their dist output
# into packages/cubejs-docker/stacklet-patches/ before invoking docker build.
# The Dockerfile picks up whatever *-dist/ directories it finds there and
# overlays them on the npm-installed versions of those packages.
#
# To add a new patched package in the future:
# 1. Make your source changes and run: yarn workspace @cubejs-backend/<pkg> build
# 2. Add a compile + stage block below (following the server-core example)
# 3. No Dockerfile change is needed.

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
DOCKER_DIR="$REPO_ROOT/packages/cubejs-docker"
PATCHES_DIR="$DOCKER_DIR/stacklet-patches"
TAG="${1:-cubejs/cube:dev}"

cleanup() {
echo "Cleaning up staged patches..."
find "$PATCHES_DIR" -maxdepth 1 -name '*-dist' -type d -exec rm -rf {} + 2>/dev/null || true
}
trap cleanup EXIT

# ---------------------------------------------------------------------------
# Compile and stage Stacklet-patched packages
# ---------------------------------------------------------------------------

echo "==> Building @cubejs-backend/server-core..."
yarn --cwd "$REPO_ROOT" workspace @cubejs-backend/server-core build

echo "==> Staging server-core dist..."
mkdir -p "$PATCHES_DIR/server-core-dist"
cp -r "$REPO_ROOT/packages/cubejs-server-core/dist/." \
"$PATCHES_DIR/server-core-dist/"

# ---------------------------------------------------------------------------
# Docker build
# ---------------------------------------------------------------------------

echo "==> Building Docker image $TAG..."
docker build -t "$TAG" -f "$DOCKER_DIR/latest.Dockerfile" "$DOCKER_DIR"

echo "==> Done: $TAG"

echo "==> Verifying logger patch..."
COUNT=$(docker run --rm "$TAG" grep -c 'Performing query completed' \
/cube/node_modules/@cubejs-backend/server-core/dist/src/core/logger.js)
if [ "$COUNT" -ne 2 ]; then
echo "ERROR: logger patch check failed (expected 2 matches, got $COUNT)"
exit 1
fi
echo "Logger patch OK ($COUNT matches)"