Build Context & .dockerignore
When you run 1ctl deploy without --image, the CLI packages your project directory and sends it to Satusky’s cloud build service, which builds your container image using Kaniko. No local Docker installation is required.
Understanding what gets packaged — and how to control it — directly affects deploy speed and build cache efficiency.
How cloud builds work
Section titled “How cloud builds work”1ctl deploy │ ├─ 1. Package project directory → build.tar.gz (respects .dockerignore) ├─ 2. Upload → POST /v1/cli/builds ├─ 3. Kaniko job runs your Dockerfile in-cluster ├─ 4. Build logs stream to your terminal in real time ├─ 5. Finished image pushed to registry.satusky.com/{namespace}/{app}:{tag} └─ 6. Image reference passed to deployment upsertEvery step runs in the cloud. The only local operations are packaging the context and streaming the log output.
What gets included by default
Section titled “What gets included by default”Without a .dockerignore, the CLI includes everything in the current directory, recursively. Common directories that inflate context size unnecessarily:
| Directory / pattern | Typical size | Problem |
|---|---|---|
node_modules/ | 50 MB – 1 GB | Installed by npm install in Dockerfile; uploading is redundant |
.git/ | Variable | Not useful inside the image |
venv/ / .venv/ | 20 MB – 500 MB | Python virtualenv; same problem as node_modules |
data/ | Variable | Training data, fixtures — usually not needed at build time |
*.ipynb | Variable | Jupyter notebooks; rarely needed in the production image |
model/ | 1 GB+ | Local model weights — should be downloaded at build time |
Using .dockerignore
Section titled “Using .dockerignore”Create a .dockerignore file in your project root. The syntax is identical to .gitignore. Files and directories matching any pattern are excluded from the build context before upload — they are never sent to the build service.
.dockerignore patterns are evaluated against paths relative to the project root. A leading / anchors to the root; without it, the pattern matches anywhere in the tree.
Node.js
Section titled “Node.js”node_modules.git.gitignore*.md.env.env.*npm-debug.logdistcoverage.nyc_output.DS_StorePython
Section titled “Python”__pycache__*.pyc*.pyo*.pyd.git.gitignore.envvenv/.venv/*.egg-infodist/build/.pytest_cache.mypy_cache.DS_StoreML / data science
Section titled “ML / data science”__pycache__*.pycdata/notebooks/*.ipynbmodel/checkpoints/.git.env.DS_StoreFor ML projects, exclude model/ and data/ from the build context entirely. Download weights at build time instead (see below).
Downloading large files at build time
Section titled “Downloading large files at build time”Instead of COPY-ing large files (which requires them in the build context), download them during the RUN step in your Dockerfile. Docker layer caching means the download only runs again when the RUN instruction or its dependencies change.
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
# Download model weights at build time — not from the local filesystemRUN python -c "from transformers import AutoModelForCausalLM; \ AutoModelForCausalLM.from_pretrained('my-org/my-model')"
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]The advantages:
- Build context stays small (fast uploads on every deploy).
- The weights layer is cached after the first build — subsequent deploys only rebuild layers that changed.
- The final image still contains the weights; there is no runtime download penalty.
Using a pre-built image
Section titled “Using a pre-built image”If you already have an image built and pushed — by your own CI pipeline or a previous 1ctl deploy — skip the cloud build entirely:
1ctl deploy --image registry.satusky.com/org-acme-prod/my-api:abc1234With --image, steps 1–5 of the build pipeline are skipped. The CLI calls the deployment upsert directly with the provided image reference. This is the fastest possible deploy path.
The --image flag accepts any image reference accessible from the cluster’s network, including images in Satusky’s private registry, Docker Hub public images, and images in other registries that don’t require authentication. For private external registries, contact support.
Dockerfile best practices for fast rebuilds
Section titled “Dockerfile best practices for fast rebuilds”Layer ordering determines what gets cached. Docker (and Kaniko) cache each layer independently. A change to a layer invalidates all layers below it.
Recommended ordering:
# 1. Base image — changes rarelyFROM node:22-alpine
WORKDIR /app
# 2. Dependency manifest — changes less often than sourceCOPY package.json package-lock.json ./
# 3. Install dependencies — heavy, but cached until manifest changesRUN npm ci --production
# 4. Source code — changes most often, so it goes lastCOPY . .
# 5. Build step (if needed)RUN npm run build
CMD ["node", "dist/server.js"]If you COPY . . before npm ci, any source change busts the install cache and triggers a full reinstall on every deploy.
Multi-stage builds reduce final image size by separating the build environment from the runtime environment:
# Build stageFROM node:22-alpine AS builderWORKDIR /appCOPY package.json package-lock.json ./RUN npm ciCOPY . .RUN npm run build
# Runtime stage — only what the app needs to runFROM node:22-alpine AS runtimeWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesCMD ["node", "dist/server.js"]The runtime image excludes dev dependencies, build tools, and intermediate artifacts.
Verifying build context size
Section titled “Verifying build context size”Before deploying, you can estimate the build context size by running:
tar -czf - --exclude-from=.dockerignore . | wc -cThis pipes a dry-run tarball through wc to show the byte count. The actual upload uses the same exclusion logic as your .dockerignore.
As a rough target: build contexts under 10 MB upload in under a second on a typical connection. Contexts over 100 MB noticeably slow down every deploy.