Skip to content

Commit 8c1f440

Browse files
Debloat base docker image (2.63GB → 1.03GB) (#114)
1 parent e489cbb commit 8c1f440

File tree

11 files changed

+192
-178
lines changed

11 files changed

+192
-178
lines changed

.changeset/violet-needles-wait.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/sandbox": patch
3+
---
4+
5+
Debloat base docker image (2.63GB → 1.03GB)

.github/changeset-version.ts

Lines changed: 93 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { execSync } from "node:child_process";
22
import * as fs from "node:fs";
3+
import fg from "fast-glob";
34

45
// This script is used by the `release.yml` workflow to update the version of the packages being released.
56
// The standard step is only to run `changeset version` but this does not update the package-lock.json file.
@@ -13,41 +14,108 @@ execSync("npm install", {
1314
stdio: "inherit",
1415
});
1516

16-
// Update Dockerfile and README version references after changeset updates package.json
17+
// Update all version references across the codebase after changeset updates package.json
1718
try {
1819
const packageJson = JSON.parse(fs.readFileSync("./packages/sandbox/package.json", "utf-8"));
1920
const newVersion = packageJson.version;
2021

21-
const dockerfilePath = "./examples/basic/Dockerfile";
22-
let dockerfileContent = fs.readFileSync(dockerfilePath, "utf-8");
22+
console.log(`\n🔍 Searching for version references to update to ${newVersion}...\n`);
2323

24-
// Update the production image version in the comment
25-
dockerfileContent = dockerfileContent.replace(
26-
/# FROM docker\.io\/cloudflare\/sandbox:[\d.]+/,
27-
`# FROM docker.io/cloudflare/sandbox:${newVersion}`
28-
);
24+
// Patterns to match version references in different contexts
25+
const versionPatterns = [
26+
// Docker image versions (production and test)
27+
{
28+
pattern: /FROM docker\.io\/cloudflare\/sandbox:[\d.]+/g,
29+
replacement: `FROM docker.io/cloudflare/sandbox:${newVersion}`,
30+
description: "Production Docker image",
31+
},
32+
{
33+
pattern: /# FROM docker\.io\/cloudflare\/sandbox:[\d.]+/g,
34+
replacement: `# FROM docker.io/cloudflare/sandbox:${newVersion}`,
35+
description: "Commented production Docker image",
36+
},
37+
{
38+
pattern: /FROM cloudflare\/sandbox-test:[\d.]+/g,
39+
replacement: `FROM cloudflare/sandbox-test:${newVersion}`,
40+
description: "Test Docker image",
41+
},
42+
{
43+
pattern: /docker\.io\/cloudflare\/sandbox-test:[\d.]+/g,
44+
replacement: `docker.io/cloudflare/sandbox-test:${newVersion}`,
45+
description: "Test Docker image (docker.io)",
46+
},
47+
// Image tags in docker commands
48+
{
49+
pattern: /cloudflare\/sandbox:[\d.]+/g,
50+
replacement: `cloudflare/sandbox:${newVersion}`,
51+
description: "Docker image reference",
52+
},
53+
{
54+
pattern: /cloudflare\/sandbox-test:[\d.]+/g,
55+
replacement: `cloudflare/sandbox-test:${newVersion}`,
56+
description: "Test Docker image reference",
57+
},
58+
];
2959

30-
// Update the test image version
31-
dockerfileContent = dockerfileContent.replace(
32-
/FROM cloudflare\/sandbox-test:[\d.]+/,
33-
`FROM cloudflare/sandbox-test:${newVersion}`
34-
);
60+
// Files to search and update
61+
const filePatterns = [
62+
"**/*.md", // All markdown files
63+
"**/Dockerfile", // All Dockerfiles
64+
"**/Dockerfile.*", // Dockerfile variants
65+
"**/*.ts", // TypeScript files (for documentation comments)
66+
"**/*.js", // JavaScript files
67+
"**/*.json", // JSON configs (but not package.json/package-lock.json)
68+
"**/*.yaml", // YAML configs
69+
"**/*.yml", // YML configs
70+
];
3571

36-
fs.writeFileSync(dockerfilePath, dockerfileContent);
37-
console.log(`✅ Updated Dockerfile versions to ${newVersion}`);
72+
// Ignore patterns
73+
const ignorePatterns = [
74+
"**/node_modules/**",
75+
"**/dist/**",
76+
"**/build/**",
77+
"**/.git/**",
78+
"**/package.json", // Don't modify package.json (changeset does this)
79+
"**/package-lock.json", // Don't modify package-lock.json (npm install does this)
80+
"**/.github/changeset-version.ts", // Don't modify this script itself
81+
];
3882

39-
// Update README.md
40-
const readmePath = "./README.md";
41-
let readmeContent = fs.readFileSync(readmePath, "utf-8");
83+
// Find all matching files
84+
const files = await fg(filePatterns, {
85+
ignore: ignorePatterns,
86+
onlyFiles: true,
87+
});
4288

43-
// Update the Docker image version in README
44-
readmeContent = readmeContent.replace(
45-
/FROM docker\.io\/cloudflare\/sandbox:[\d.]+/,
46-
`FROM docker.io/cloudflare/sandbox:${newVersion}`
47-
);
89+
console.log(`📁 Found ${files.length} files to check\n`);
4890

49-
fs.writeFileSync(readmePath, readmeContent);
50-
console.log(`✅ Updated README.md version to ${newVersion}`);
91+
let updatedFilesCount = 0;
92+
let totalReplacementsCount = 0;
93+
94+
for (const file of files) {
95+
let content = fs.readFileSync(file, "utf-8");
96+
let fileModified = false;
97+
let fileReplacementsCount = 0;
98+
99+
// Try all patterns on this file
100+
for (const { pattern, replacement, description } of versionPatterns) {
101+
const matches = content.match(pattern);
102+
if (matches) {
103+
content = content.replace(pattern, replacement);
104+
fileModified = true;
105+
fileReplacementsCount += matches.length;
106+
}
107+
}
108+
109+
if (fileModified) {
110+
fs.writeFileSync(file, content);
111+
updatedFilesCount++;
112+
totalReplacementsCount += fileReplacementsCount;
113+
console.log(` ✅ ${file} (${fileReplacementsCount} replacement${fileReplacementsCount > 1 ? 's' : ''})`);
114+
}
115+
}
116+
117+
console.log(`\n✨ Updated ${totalReplacementsCount} version reference${totalReplacementsCount !== 1 ? 's' : ''} across ${updatedFilesCount} file${updatedFilesCount !== 1 ? 's' : ''}`);
118+
console.log(` New version: ${newVersion}\n`);
51119

52120
} catch (error) {
53121
console.error("❌ Failed to update file versions:", error);

.github/workflows/release.yml

Lines changed: 70 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -64,79 +64,77 @@ jobs:
6464
run: npm run test -w @repo/sandbox-container
6565

6666
# E2E tests run in parallel with unit tests
67-
# e2e-tests:
68-
# if: ${{ github.repository_owner == 'cloudflare' }}
69-
# runs-on: ubuntu-latest
70-
# timeout-minutes: 30
71-
72-
# steps:
73-
# - uses: actions/checkout@v4
74-
75-
# - uses: actions/setup-node@v4
76-
# with:
77-
# node-version: 24
78-
# cache: "npm"
79-
80-
# - uses: oven-sh/setup-bun@v2
81-
# with:
82-
# bun-version: latest
83-
84-
# - name: Install dependencies
85-
# run: npm ci
86-
87-
# - name: Build packages
88-
# run: npm run build
89-
90-
# - name: Set worker name
91-
# id: worker-name
92-
# run: |
93-
# # Use git SHA for unique, meaningful naming (not sequential run number)
94-
# SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
95-
# echo "worker_name=sandbox-e2e-test-worker-release-${SHORT_SHA}" >> $GITHUB_OUTPUT
96-
97-
# # Generate unique wrangler config for this release
98-
# - name: Generate wrangler config
99-
# run: |
100-
# cd tests/e2e/test-worker
101-
# ./generate-config.sh ${{ steps.worker-name.outputs.worker_name }}
102-
103-
# - name: Build test worker Docker image
104-
# run: npm run docker:local -w @cloudflare/sandbox
105-
106-
# - name: Deploy test worker
107-
# uses: cloudflare/wrangler-action@v3
108-
# with:
109-
# apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
110-
# accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
111-
# command: deploy --name ${{ steps.worker-name.outputs.worker_name }}
112-
# workingDirectory: tests/e2e/test-worker
113-
114-
# - name: Get deployment URL
115-
# id: get-url
116-
# run: |
117-
# echo "worker_url=https://${{ steps.worker-name.outputs.worker_name }}.agents-b8a.workers.dev" >> $GITHUB_OUTPUT
118-
119-
# - name: Run E2E tests
120-
# run: npx vitest run --config vitest.e2e.config.ts
121-
# env:
122-
# TEST_WORKER_URL: ${{ steps.get-url.outputs.worker_url }}
123-
# CI: true
124-
125-
# - name: Cleanup test deployment
126-
# if: always()
127-
# continue-on-error: true
128-
# run: |
129-
# cd tests/e2e/test-worker
130-
# ../../../scripts/cleanup-test-deployment.sh ${{ steps.worker-name.outputs.worker_name }}
131-
# env:
132-
# CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
133-
# CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
67+
e2e-tests:
68+
if: ${{ github.repository_owner == 'cloudflare' }}
69+
runs-on: ubuntu-latest
70+
timeout-minutes: 30
71+
72+
steps:
73+
- uses: actions/checkout@v4
74+
75+
- uses: actions/setup-node@v4
76+
with:
77+
node-version: 24
78+
cache: "npm"
79+
80+
- uses: oven-sh/setup-bun@v2
81+
with:
82+
bun-version: latest
83+
84+
- name: Install dependencies
85+
run: npm ci
86+
87+
- name: Build packages
88+
run: npm run build
89+
90+
- name: Set worker name
91+
id: worker-name
92+
run: |
93+
# Use git SHA for unique, meaningful naming (not sequential run number)
94+
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
95+
echo "worker_name=sandbox-e2e-test-worker-release-${SHORT_SHA}" >> $GITHUB_OUTPUT
96+
97+
# Generate unique wrangler config for this release
98+
- name: Generate wrangler config
99+
run: |
100+
cd tests/e2e/test-worker
101+
./generate-config.sh ${{ steps.worker-name.outputs.worker_name }}
102+
103+
- name: Build test worker Docker image
104+
run: npm run docker:local -w @cloudflare/sandbox
105+
106+
- name: Deploy test worker
107+
uses: cloudflare/wrangler-action@v3
108+
with:
109+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
110+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
111+
command: deploy --name ${{ steps.worker-name.outputs.worker_name }}
112+
workingDirectory: tests/e2e/test-worker
113+
114+
- name: Get deployment URL
115+
id: get-url
116+
run: |
117+
echo "worker_url=https://${{ steps.worker-name.outputs.worker_name }}.agents-b8a.workers.dev" >> $GITHUB_OUTPUT
118+
119+
- name: Run E2E tests
120+
run: npx vitest run --config vitest.e2e.config.ts
121+
env:
122+
TEST_WORKER_URL: ${{ steps.get-url.outputs.worker_url }}
123+
CI: true
124+
125+
- name: Cleanup test deployment
126+
if: always()
127+
continue-on-error: true
128+
run: |
129+
cd tests/e2e/test-worker
130+
../../../scripts/cleanup-test-deployment.sh ${{ steps.worker-name.outputs.worker_name }}
131+
env:
132+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
133+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
134134

135135
# Prerelease publish - always runs after tests pass
136136
publish-prerelease:
137-
needs: [unit-tests,
138-
# e2e-tests
139-
]
137+
needs: [unit-tests, e2e-tests]
140138
if: ${{ github.repository_owner == 'cloudflare' }}
141139
runs-on: ubuntu-latest
142140
timeout-minutes: 20
@@ -187,9 +185,7 @@ jobs:
187185

188186
# Release publish - only runs if changesets exist
189187
publish-release:
190-
needs: [unit-tests,
191-
# e2e-tests
192-
]
188+
needs: [unit-tests, e2e-tests]
193189
if: ${{ github.repository_owner == 'cloudflare' }}
194190
runs-on: ubuntu-latest
195191
timeout-minutes: 20
@@ -236,4 +232,4 @@ jobs:
236232
env:
237233
GITHUB_TOKEN: ${{ secrets.SANDBOX_GITHUB_TOKEN }}
238234
NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
239-
NPM_PUBLISH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
235+
NPM_PUBLISH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

examples/basic/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ FROM cloudflare/sandbox-test:0.4.2
66

77
# On a mac, you might need to actively pick up the
88
# arm64 build of the image.
9-
# FROM --platform=linux/arm64 cloudflare/sandbox-test:0.1.3
9+
# FROM --platform=linux/arm64 cloudflare/sandbox-test:0.4.2
1010

1111
# Expose the ports you want to expose
1212
EXPOSE 8080
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# This image is unique to this repo, and you'll never need it.
22
# Whenever you're integrating with sandbox SDK in your own project,
33
# you should use the official image instead:
4-
# FROM docker.io/cloudflare/sandbox:0.2.3
5-
FROM cloudflare/sandbox-test:0.2.3
4+
# FROM docker.io/cloudflare/sandbox:0.4.2
5+
FROM cloudflare/sandbox-test:0.4.2
66

77
# On a mac, you might need to actively pick up the
88
# arm64 build of the image.
9-
# FROM --platform=linux/arm64 cloudflare/sandbox-test:0.1.3
9+
# FROM --platform=linux/arm64 cloudflare/sandbox-test:0.4.2

examples/minimal/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM docker.io/cloudflare/sandbox:0.3.6
1+
FROM docker.io/cloudflare/sandbox:0.4.2
22

33
# On a Mac with Apple Silicon, you might need to specify the platform:
4-
# FROM --platform=linux/arm64 docker.io/cloudflare/sandbox:0.3.6
4+
# FROM --platform=linux/arm64 docker.io/cloudflare/sandbox:0.4.2

0 commit comments

Comments
 (0)