A Dockerfile Linter and Optimizer Built on AST Parsing
Static analysis and transformation of Dockerfile instructions using structured syntax trees.
Docktor is a static analysis tool for Dockerfiles that uses Abstract Syntax Tree (AST) parsing to identify issues and apply optimizations. Unlike regex-based approaches, Docktor constructs a structured representation of Dockerfile instructions, enabling reliable pattern matching and safe transformations.
The project demonstrates end-to-end architecture design: recursive descent parsing β plugin-based rule engine β automated optimization β Docker SDK benchmarking.
- AST-Based Parsing β Recursive descent parser with multi-line continuation handling (
\), not regex-based pattern matching - Extensible Rule Engine β Plugin architecture using Python decorators for linting rules (best practices, performance, security, registry checks)
- Safe Optimization Pipeline β 8-stage transformation pipeline with isolated optimization passes and change tracking
- Benchmarking Harness β Direct Docker SDK integration to measure real build metrics (image size, layer count, build duration) in isolated temp environments
- Structured Output β Both human-readable (Rich) and machine-readable (JSON) formats for CI/CD integration
- Registry Rule (REG001) β Docker Hub API integration to detect newer patch versions of base images
- GitHub Actions Composite Action β Pre-built workflow for CI/CD automation
- Improved CLI β Encoding auto-detection (chardet) for non-UTF-8 Dockerfiles, better error handling
- Python 3.8+
- Docker (for benchmarking feature; linting works without it)
pip install docktor-pyRun static analysis against 21 rules:
docktor lint DockerfileEach rule includes a structured explanation of the issue and suggested fix:
docktor lint Dockerfile --explainApply automated transformations (RUN merging, layer reduction, cache cleanup):
# View transformations with change summary
docktor optimize Dockerfile
# Output clean Dockerfile without pretty printing (for piping)
docktor optimize Dockerfile --raw > Dockerfile.optimizedBuild both images in isolated temp environments and compare metrics:
# Must run from directory containing all COPY/ADD source files
docktor benchmark Dockerfile Dockerfile.optimizedFor CI/CD integration:
docktor lint Dockerfile --format jsonDocktor enforces 20 rules across four categories. Each rule is implemented as a plugin with explicit checks against the AST:
| Rule ID | Description | Auto-Optimized? |
|---|---|---|
| BP001 | FROM uses :latest or no tag |
Yes |
| BP002 | EXPOSE present without HEALTHCHECK | No |
| BP003 | EXPOSE missing /tcp or /udp protocol |
Yes |
| BP004 | LABEL instruction missing for metadata | No |
| BP005 | RUN command used in scratch image | No (error) |
| BP006 | COPY --from refers to non-existent stage | No (error) |
| BP007 | CMD/ENTRYPOINT uses shell form | No |
| BP008 | WORKDIR path is not absolute | No |
| BP009 | apt-get install missing apt-get update | No (error) |
| Rule ID | Description | Auto-Optimized? |
|---|---|---|
| PERF001 | Consecutive RUN commands can be merged | Yes |
| PERF002 | apt-get install missing cache cleanup | Yes |
| PERF003 | Broad COPY before dependency install | No |
| PERF004 | Build-time packages installed in final image | No |
| PERF005 | Unsafe apt-get upgrade command used | No |
| PERF006 | Broad COPY . . pattern used |
No |
| PERF007 | Redundant apt-get update command | No |
| Rule ID | Description | Auto-Optimized? |
|---|---|---|
| SEC001 | ADD used instead of COPY | Yes |
| SEC002 | Container runs as root user | No |
| SEC003 | Potential secrets in ENV variables | No |
| SEC004 | COPY missing --chown for non-root user | No |
| Rule ID | Description | Auto-Optimized? |
|---|---|---|
| REG001 | Newer patch version available on Docker Hub | No |
The DockerfileParser uses recursive descent with regex anchors to tokenize and structure Dockerfile content:
- Strips and normalizes lines
- Handles line continuations (backslash escape)
- Constructs
DockerInstructionobjects with metadata (line number, type, value, image/tag/alias) - Tolerates malformed input gracefully
The Analyzer loads all rule implementations as plugins (via Rule.__subclasses__()) and runs them:
- Each rule performs AST traversal over instructions
- Rules check for specific patterns (e.g.,
instruction.instruction_type == InstructionType.RUN) - Issues are collected with severity, explanation, and fix suggestions
The DockerfileOptimizer applies 8 sequential transformations:
- RUN Merging β Combines consecutive RUN commands with
&& - FROM Pinning β Tags untagged base images with
:latest - apt-get Cache Cleanup β Appends
rm -rf /var/lib/apt/lists/* - EXPOSE Protocol β Adds
/tcpsuffix to port numbers - ADD β COPY β Security-motivated instruction replacement
- Metadata Combining β Merges consecutive LABEL/ENV/ARG instructions
- sudo Removal β Strips unnecessary sudo from RUN commands
- apt-get Update β Prepends
apt-get updatewhere required
Each pass is isolated and order-dependent. Changes are tracked and reported.
The DockerBenchmarker uses Docker SDK to build images in ephemeral containers:
- Creates temp directory with Dockerfile
- Calls
docker.client.api.build()to measure build duration - Captures final image size and layer count from image metadata
- Cleans up images after measurement
- Computes % improvement across metrics
Scope Note: Benchmarking metrics are measured in local test environments (validated on 8GB RAM, Docker daemon on host). No multi-machine or cluster testing.
Automate linting in workflows:
name: Dockerfile Quality Check
on: [push, pull_request]
jobs:
docktor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Docktor Linter
uses: nash0810/docktor@v0.2.0
with:
dockerfile: "./Dockerfile"
explain: "true"Inputs:
dockerfile(optional, default:Dockerfile)explain(optional, default:false)format(optional, default:text, acceptsjson)
Any CI/CD system supporting Python and Docker:
pip install docktor-py
docktor lint Dockerfile --format jsonThe docktor benchmark command measures real Docker builds using the Docker SDK:
- Builds each Dockerfile in an isolated temporary directory
- Extracts image size (bytes), layer count, and build duration from Docker metadata
- Computes percentage improvements (
(original - optimized) / original * 100) - Cleans up images after measurement
Requirements:
- Docker daemon must be running
- Must run from directory containing all source files referenced in COPY/ADD instructions
- Builds are not cached between runs (fresh builds each time)
Tested Scenario: Reduced image size by ~40% in sample Python/Node.js multi-stage build scenarios with aggressive layer merging.
Clone and install in editable mode:
git clone https://github.com/Nash0810/docktor.git
cd docktor
pip install -e ".[dev]"
pytestThis project is licensed under the MIT License.