Overview

migetpacks produces optimized runtime containers that run as non-root users by default. The container configuration depends on whether you are using standard images or Docker Hardened Images (DHI).

Standard Runtime

When USE_DHI=false (default), migetpacks generates containers with the following configuration:
PropertyValue
Usermiget (uid: 1000)
Groupmiget (gid: 1000)
Working directory/app
Exposed port5000 (configurable via PORT)
ShellAvailable (/bin/sh)

Container Structure

/app/                    # Application source and dependencies
/app/node_modules/       # Node.js dependencies (if applicable)
/app/vendor/bundle/      # Ruby gems (if applicable)
/app/.venv/              # Python virtualenv (if applicable)

User Configuration

The miget user is created in the runtime image:
RUN groupadd -g 1000 miget && \
    useradd -u 1000 -g miget -m miget
USER miget
WORKDIR /app

Port Configuration

The default exposed port is 5000. Override it with the PORT environment variable:
docker run --rm \
  -e PORT=3000 \
  -e OUTPUT_IMAGE=my-app:local \
  miget/migetpacks:latest
The PORT environment variable is set in the generated Dockerfile, so the application can read it at runtime.

DHI Runtime (Distroless)

When USE_DHI=true, migetpacks uses Docker Hardened Images from dhi.io. These are distroless containers with a minimal attack surface.
PropertyValue
Usernonroot (uid varies by image)
Working directory/app
Exposed port5000 (configurable via PORT)
ShellNot available
Package managerNot available

Distroless Constraints

DHI runtime images have no shell, no package manager, and no common utilities. This means:
  1. No shell commands — Commands cannot use /bin/sh -c wrappers
  2. Exec format only — Process commands must use exec format
  3. No shebangs — Scripts like ./bin/rails must be invoked as ruby bin/rails
  4. No variable expansion — Shell variables like ${PORT:-5000} must be pre-expanded
  5. No debugging tools — No ls, cat, curl, etc. in production

Command Transformation

migetpacks automatically transforms commands for distroless:
OriginalTransformed
./bin/rails serverruby bin/rails server
bundle exec pumaruby -S bundle exec puma
${PORT:-5000}Pre-expanded to actual port value

Result JSON Indicator

When DHI is used, the result JSON includes "_shell": false to signal that the container is distroless. Deployment systems should use this flag to determine how to execute commands in the container.

Runtime Cleanup

migetpacks automatically removes unnecessary files from runtime images to reduce size and attack surface.

Node.js

RemovedDescription
.git/Git history
.github/GitHub configuration
test/, tests/Test files
spec/Spec files
__tests__/Jest tests
coverage/Coverage reports
.nyc_output/NYC coverage data
.cache/Build cache

Ruby

RemovedDescription
.git/Git history
.github/GitHub configuration
test/, tests/Test files
spec/RSpec files
features/Cucumber features
.rspecRSpec config
.rubocop*Rubocop config
vendor/bundle/*/cache/Gem cache

Python

RemovedDescription
.git/Git history
.github/GitHub configuration
test/, tests/Test files
__pycache__/Bytecode cache
.pytest_cache/Pytest cache
.coverageCoverage data
htmlcov/Coverage HTML

.NET

RemovedDescription
.git/Git history
.github/GitHub configuration
*.csC# source files
*.csprojProject files
*.sln, *.slnxSolution files
obj/Intermediate build output
bin/Release/net*/Additional framework outputs
bin/Debug/Debug builds
.NET is a compiled language, so source code is completely removed from the runtime image. Node.js, Ruby, and Python are interpreted languages, so source code is kept but development/test files are removed.

Inspecting Built Containers

List Files

docker run --rm my-app:local ls -la /app/

Check Environment

docker run --rm my-app:local env

Check User

docker run --rm my-app:local id
# uid=1000(miget) gid=1000(miget) groups=1000(miget)

Check Exposed Ports

docker inspect my-app:local --format='{{json .Config.ExposedPorts}}'
# {"5000/tcp":{}}

Check Entrypoint/CMD

docker inspect my-app:local --format='{{json .Config.Cmd}}'
# ["node","server.js"]

Layer History

docker history my-app:local

Image Size

docker images my-app:local --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

Security

Non-Root by Default

All migetpacks containers run as a non-root user. This provides:
  • Process isolation from the host
  • Prevention of privilege escalation
  • Compliance with Kubernetes Pod Security Standards (restricted profile)

Read-Only Filesystem

For maximum security, run the container with a read-only root filesystem:
docker run --rm \
  --read-only \
  --tmpfs /tmp \
  -p 5000:5000 \
  my-app:local

No Credentials in Image

migetpacks never includes AWS credentials or other secrets in the built image. The KNOWN_BUILDER_VARS filter ensures sensitive variables (like AWS_ACCESS_KEY_ID) are excluded from the generated Dockerfile.