A docker project to use Docling to provide an easy conversion tool
69
Convert PDF files to Markdown using Docling, packaged as a self-contained Docker image.
The image is designed to be a pipeline component: PDF in via STDIN, Markdown out via STDOUT, with all logs on STDERR.
make build # build the image (downloads ~1.4 GB of model weights)
./pdfToMarkdown mydoc.pdf # convert; writes mydoc.md in the current folder
make build tags the image twice: pdf-to-markdown:latest and a version tag
naming the docling release actually installed in the image, e.g.
pdf-to-markdown:docling-2.126.0 (read from inside the image, so the tag can
never drift from the build). Pin to the version tag for reproducible builds.
Equivalent manual pipeline:
cat mydoc.pdf | docker run --rm -i pdf-to-markdown > mydoc.md
Extra arguments are passed through to docling convert, for example:
./pdfToMarkdown --image-export-mode placeholder mydoc.pdf # don't embed images
./pdfToMarkdown --verbose mydoc.pdf # see what's happening
Override the image with PDF_TO_MARKDOWN_IMAGE=name:tag.
pdfToMarkdown <file.pdf>
Writes <file.md> (input stem + .md) in the current folder. A failed
conversion never leaves a truncated output file.
Note: docling's default --image-export-mode embedded inlines every image in
the PDF as base64, which can make outputs much larger than the source. For
text-processing pipelines, pass --image-export-mode placeholder.
The image is fully self-contained: model weights are baked in at build time
(docling-tools models download, ~1.4 GB under /root/.cache/docling/models),
so conversion works offline — no network access needed at run time.
| Layer | Size | Contents |
|---|---|---|
| pip install | ~1.8 GB | docling + CPU-only PyTorch tree |
| model download | ~1.4 GB | layout, table-structure, code-formula, OCR, figure-classifier weights |
| apt packages | ~0.2 GB | native libs for OpenCV (libgl1, libglib2.0-0) |
Total image size: ~1.9 GB (content), ~5.5 GB on disk with containerd's decompressed layers.
A naive pip install docling pulls in the full CUDA-enabled PyTorch stack —
nvidia-cudnn, nvidia-cublas, nvidia-nccl and friends — adding several
gigabytes that this image will never use, since conversion runs on CPU only.
Docling constrains torch loosely (torch>=2.2.2,<3.0.0, via
docling-ibm-models), which gives the resolver room to accept an older
torch, and pip can be pointed at PyTorch's CPU-only wheel index. The result:
torch's entire CUDA dependency tree is replaced by a single self-contained
wheel.
The practical pin set in docker/Dockerfile:
RUN pip install --no-cache-dir \
docling \
"torch==2.4.1+cpu" \
"torchvision==0.19.1+cpu" \
"transformers>=4.42.0,<5.0.0" \
--extra-index-url https://download.pytorch.org/whl/cpu
The decisions behind each line, and the dead ends we hit:
--extra-index-url .../whl/cpu, not -f .../torch_stable.html. The
commonly-cited legacy torch_stable.html links page stopped carrying
+cpu wheels newer than 2.3.1; the real PEP 503 index at
https://download.pytorch.org/whl/cpu serves the full set. Because the
+cpu local version is pinned exactly, PyPI's CUDA-bundled bare torch
can never be selected.numpy<2 pin is needed. (2.4.1 is the last
2.4.x patch release.)transformers>=4.42,<6 and was originally built against the 4.x line, so
pinning 4.x keeps the old torch. If docling ever needs transformers 5
features, the fallback is torch 2.5.1+cpu with no transformers pin.--no-deps gymnastics. Docling's loose torch constraint lets pip
resolve the entire tree normally with the pins in place. This is cleaner
than hand-deriving the dependency list (the approach some projects need,
e.g. forcing whisperx onto torch 2.3.1+cpu by installing the tree with
docling's deps first and whisperx with --no-deps).docling-tools models download fetches the default model set into
/root/.cache/docling/models at build time. Two gotchas we hit:
DOCLING_ARTIFACTS_PATH — it always downloads to its
default path. The env var is therefore set after the download layer and
only matters at convert time, which also keeps the big download layer's
cache key stable across env changes.DOCLING_ARTIFACTS_PATH must match where the weights actually are
(/root/.cache/docling/models), or docling re-downloads at run time.docker/Dockerfile image build
docker/entrypoint.sh STDIN -> temp file -> docling convert -> STDOUT
pdfToMarkdown shell wrapper (PDF path -> <stem>.md)
Makefile make build / make convert
test/test.pdf sample PDF for smoke testing
Content type
Image
Digest
sha256:c31a64bcd…
Size
1.8 GB
Last updated
10 days ago
docker pull gencore/pdf-to-markdown