You can build Moru templates directly from Dockerfiles, making it easy to migrate existing Docker-based workflows.
From Dockerfile Content
from moru import Template
dockerfile = """
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
"""
template = Template().from_dockerfile(dockerfile)
info = Template.build(template, alias="my-python-app")
From Dockerfile Path
from moru import Template
# Read from file path
template = Template().from_dockerfile("./Dockerfile")
info = Template.build(template, alias="my-app")
Supported Instructions
| Instruction | Support | Reason |
|---|
FROM | ✅ Full | Sets the base image for the template |
RUN | ✅ Full | Commands executed during template build |
COPY | ✅ Full | Files uploaded and copied into the template |
WORKDIR | ✅ Full | Sets the working directory for subsequent commands |
ENV | ✅ Full | Environment variables persisted in the template (both KEY=value and KEY value formats) |
USER | ✅ Full | Sets the user context for subsequent commands |
CMD | ✅ Full | Converted to Moru’s start command |
ENTRYPOINT | ⚠️ Partial | Converted to CMD - ENTRYPOINT and CMD are not distinguished |
ADD | ⚠️ Partial | Local files only - URL sources not supported (use RUN curl or RUN wget instead) |
ARG | ❌ Ignored | Build arguments not expanded - use ENV instead for runtime variables |
EXPOSE | ❌ Ignored | Not needed - all ports are accessible in Moru sandboxes by default |
VOLUME | ❌ Ignored | Not applicable - Moru sandboxes use ephemeral filesystems |
HEALTHCHECK | ❌ Ignored | Use Moru’s ready_cmd instead for health checks |
LABEL | ❌ Ignored | Metadata labels not used in Moru templates |
STOPSIGNAL | ❌ Ignored | Moru manages sandbox lifecycle directly |
SHELL | ❌ Ignored | Moru uses the default shell |
Why Some Instructions Are Ignored
Moru templates are not Docker containers. They run in lightweight Firecracker microVMs with a different execution model:
- No port mapping needed: Sandboxes expose all ports directly -
EXPOSE is unnecessary
- Ephemeral by design: Sandbox filesystems reset on restart -
VOLUME doesn’t apply
- Build-time vs runtime:
ARG is for Docker build-time only; use ENV for Moru templates
- Native health checks: Use
set_ready_cmd() instead of HEALTHCHECK for better integration
Example: Node.js Application
Dockerfile:
FROM node:20-slim
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci --only=production
# Copy application
COPY . .
# Start
EXPOSE 3000
CMD ["node", "server.js"]
Build it:
template = Template().from_dockerfile("./Dockerfile")
# Add a ready command for health checks
template = template.set_ready_cmd("curl -s localhost:3000/health")
info = Template.build(template, alias="my-node-app")
Not Supported: Multi-stage Builds
Multi-stage Dockerfiles are not supported. If your Dockerfile contains multiple FROM instructions, you’ll get an error.
If you have a multi-stage Dockerfile like this:
# This will NOT work with Moru
FROM node:20 AS builder
WORKDIR /app
RUN npm ci && npm run build
FROM node:20-slim
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/server.js"]
You have two options:
Option 1: Build locally, use production image
Build your application locally, then create a template from the production stage only:
# production.Dockerfile - single stage
FROM node:20-slim
WORKDIR /app
COPY dist ./dist
COPY node_modules ./node_modules
CMD ["node", "dist/server.js"]
# Build locally first: npm run build
template = Template().from_dockerfile("./production.Dockerfile")
info = Template.build(template, alias="my-built-app")
Option 2: Use the Template Builder API
For more complex builds, use the builder API directly:
template = (
Template()
.from_image("node:20-slim")
.set_workdir("/app")
.copy("./dist", "./dist")
.copy("./node_modules", "./node_modules")
.set_start_cmd("node dist/server.js")
)
info = Template.build(template, alias="my-built-app")
CLI Build
Use the CLI to build directly from Dockerfile:
# Basic build
moru template create my-app --dockerfile ./Dockerfile
# With start and ready commands
moru template create my-app \
--dockerfile ./Dockerfile \
--cmd "node server.js" \
--ready-cmd "curl localhost:3000/health"
# With more resources
moru template create my-app \
--dockerfile ./Dockerfile \
--cpu-count 4 \
--memory-mb 2048
Combining with Builder API
You can extend a Dockerfile-based template with additional configuration:
template = (
Template()
.from_dockerfile("./Dockerfile")
.set_envs({"NODE_ENV": "production"})
.apt_install(["curl"]) # For health checks
.set_start_cmd("node server.js", "curl -s localhost:3000/health")
)
info = Template.build(template, alias="my-extended-app")
Limitations Summary
| Limitation | Workaround |
|---|
| Multi-stage builds | Build locally, use single-stage Dockerfile for final image |
ARG build arguments | Use ENV for runtime variables |
ADD with URLs | Use RUN curl -O <url> or RUN wget <url> |
COPY --from=<stage> | Not supported without multi-stage builds |
HEALTHCHECK | Use set_ready_cmd() / --ready-cmd instead |
Best Practices
- Use slim base images: Smaller images build faster
- Layer caching: Put rarely-changing instructions first
- Combine RUN commands: Reduce layers for faster builds
- Add health checks: Use
set_ready_cmd() for reliable sandbox startup
Next Steps