El TeX Live 2024 desplegado en el disco que tengo al lado ocupa 8,7 GB. La imagen texlive/texlive:latest de Docker Hub pesa unos 2,5 GB comprimida, y la etiqueta latest-minimal unos 335 MB (cifras amd64 tal como figuraban en agosto de 2026). Elegir ejecutar LaTeX en Docker es, antes que nada, una conversación sobre esos números. Esta página trata de la imagen texlive/texlive en sí: quién la construye, qué lleva dentro, qué etiqueta tomar y cómo fijar una versión, además de la trampa propia de los contenedores: el PDF que sale siendo propiedad de root. Cómo escribir el flujo de trabajo de GitHub Actions corresponde a la página de CI.
Por qué ejecutar TeX en un contenedor
Hay una razón: la reproducibilidad. Que un mismo .tex dé el mismo PDF no lo decide solo el manuscrito. Depende de qué año de TeX Live esté instalado, de la revisión de cada paquete y de qué fuentes estén registradas. Una imagen Docker es ese entorno congelado junto con su sistema operativo y enviado en una caja. Dentro hay una instantánea de TeX Live con sus motores, paquetes y fuentes, de modo que, sea el anfitrión Windows, macOS o un runner de CI, abrir la misma caja da el mismo entorno. Por eso deja de ocurrir aquello de «compila en mi máquina y falla en la del coautor y en CI».
Contenedores e instalación local no se excluyen. El reparto realista es escribir a diario en el editor contra un TeX Live local y ceder solo la compilación final y la copia que se envía a los coautores a un contenedor. Otra ventaja es poder experimentar sin ensuciar la propia instalación: para aislar por qué falla un \usepackage{...}, un TeX Live impoluto está a unos minutos. Hay un precio, eso sí. Hay que descargar varios gigabytes al menos una vez, y dentro de un contenedor no hay visor gráfico ni búsqueda inversa de SyncTeX. Dicho con honestidad: un contenedor es un entorno de compilación, no de edición.
Quién construye la imagen texlive/texlive y qué lleva dentro
No la construye el TeX Users Group sino una comunidad llamada Island of TeX; no es una imagen oficial de TeX Live. La misma imagen se obtiene desde Docker Hub como texlive/texlive y desde GitLab como registry.gitlab.com/islandoftex/images/texlive. La base es una imagen slim de Debian testing, y el Dockerfile deja constancia de por qué no se eligió Alpine: cuando se escribió, binarios como biber no se distribuían para la plataforma Linux/musl. Lo que hay dentro es más que TeX Live: la imagen incluye Java para arara, Perl para biber y xindy, Python con Pygments para minted, Ghostscript para la conversión de EPS e incluso gnuplot para pgfplots.
# One-off build of ./main.tex. The image's own WORKDIR is /workdir.
docker run --rm -v "$PWD":/workdir -w /workdir texlive/texlive \
latexmk -pdf main.tex
# Poke around inside instead of building:
docker run --rm -it -v "$PWD":/workdir -w /workdir texlive/texlive bash--rm descarta el contenedor al salir, -v "$PWD":/workdir enlaza su ubicación actual con /workdir dentro del contenedor, y -w la convierte en el directorio de trabajo. Entrada y salida viven en su propia carpeta, así que el PDF aparece allí mismo. Para japonés, LuaLaTeX es el camino más corto: basta con poner latexmk -lualatex main.tex. Para la ruta de upLaTeX y dvipdfmx, coloque el .latexmkrc que se muestra más adelante junto al manuscrito y llame a latexmk main.tex. Una cosa que conviene recordar: se puede ejecutar tlmgr update --self --all dentro de la imagen, pero en cuanto se descarta el contenedor todo vuelve atrás.
Qué etiqueta descargar: esquemas y sus tamaños reales
Las etiquetas son el producto de dos ejes: el esquema (cuánto TeX Live) y si se incluyen documentación y fuentes. El esquema tiene cinco escalones —minimal, basic, small, medium, full— o seis si se cuenta context para quienes usan ConTeXt, y el latest a secas es un alias de latest-full. Encima se añade -doc (manuales), -src (los fuentes .dtx) o -doc-src (ambos). El efecto es drástico: Docker Hub lista latest (= full) en unos 2,5 GB y latest-doc-src en unos 6,7 GB; solo la documentación más que duplica la imagen. Sabiendo que texmf-dist/doc ocupa por sí solo 3,7 GB, no sorprende.
| Etiqueta | Contenido | Tamaño según Docker Hub (amd64, agosto de 2026) |
|---|---|---|
latest | Alias de latest-full: todos los paquetes, sin docs ni fuentes | unos 2,53 GB: la opción por defecto sensata |
latest-medium | El esquema medium; suficiente para la mayoría de documentos cotidianos | unos 898 MB |
latest-small | El esquema small; cuando se quiere un trabajo de CI ligero | unos 590 MB |
latest-basic | El esquema basic: LaTeX básico y poco más | unos 367 MB |
latest-minimal | El esquema minimal: en esencia plain TeX, el más pequeño | unos 335 MB |
latest-doc-src | full más manuales más fuentes; aquí texdoc funciona | unos 6,69 GB: para consultar en local |
TL2018-historic | Una versión pasada; hay imágenes desde 2013 | Para recompilar un manuscrito antiguo; vea la advertencia de abajo |
La elección práctica es simple. En CI, tome el latest a secas, o latest-medium si resulta llevar lo que necesita. Solo se recurre a una etiqueta -doc cuando se quiere texdoc en local. Los esquemas pequeños traen una salvedad: según el README de Island of TeX, en cualquier imagen que no sea full, un ejecutable instalado con tlmgr install no se añade al PATH automáticamente. Hay que encadenar, por ejemplo tlmgr install <pkg> && tlmgr path add. También se publican compilaciones ARMv8 (arm64), pero el README las califica de experimentales, así que si algo se comporta raro en Apple Silicon vale la pena probar --platform linux/amd64.
Una etiqueta historic no es inmutable: fije también el digest
Incluso una etiqueta de versión pasada apunta a una imagen que cambia. El README de Island of TeX dice sin rodeos de las imágenes historic que se reconstruyen cada mes y se actualizan siempre que la imagen del sistema operativo subyacente recibe actualizaciones. TeX Live estará congelado, pero las bibliotecas de Debian de debajo no. Además, latest pasa cada semana a una nueva instantánea de CTAN, y cada una de esas compilaciones semanales lleva una etiqueta con la forma TL{versión}-{año}-{mes}-{día} (antes de TL2021 el formato incluía también la hora y el minuto). Así que si de verdad quiere congelar la compilación final de un artículo, escriba un digest en lugar de una etiqueta: es la única vía fiable.
# A tag can be re-pointed later; a digest cannot.
docker pull texlive/texlive:latest
docker image inspect --format '{{index .RepoDigests 0}}' texlive/texlive:latest
# -> texlive/texlive@sha256:0123abcd...
# Record that string in the repository and build against it forever:
docker run --rm -v "$PWD":/workdir -w /workdir \
texlive/texlive@sha256:0123abcd... latexmk -pdf main.tex
# Belt and braces for archival work: keep your own copy of the image.
docker save texlive/texlive@sha256:0123abcd... | gzip > texlive-frozen.tar.gzUn digest es un hash del contenido mismo de la imagen, así que pase lo que pase aguas arriba, solo se descargan los mismos bytes. Para una tesis, o para un trabajo cuya reproducción podría pedir un revisor años después, dejar esa línea en el repositorio es un regalo a su yo futuro. Para las compilaciones cotidianas donde ese rigor sobra, latest basta. El criterio aquí no es «da igual cuál» sino para qué es la compilación.
El PDF sale siendo propiedad de root
En Linux es lo primero con lo que se topa uno. El usuario por defecto de la imagen es root —el README de Island of TeX dice sin rodeos que root es el predeterminado para poder añadir paquetes con apt con facilidad—, de modo que main.pdf y main.aux escritos en un directorio montado por bind salen siendo de root, y después el editor no puede sobrescribirlos ni git clean eliminarlos. Docker Desktop en macOS y Windows lo oculta porque su capa de compartición reescribe la propiedad, pero en Linux y en CI se tropieza con ello a diario. El remedio es pasar el propio UID y GID con --user.
# Run as the calling user, so the PDF belongs to you.
docker run --rm --user "$(id -u):$(id -g)" \
-v "$PWD":/workdir -w /workdir \
texlive/texlive latexmk -pdf main.tex
# If a package writes to $HOME (luaotfload caches, fontconfig), give it one:
docker run --rm --user "$(id -u):$(id -g)" -e HOME=/workdir \
-v "$PWD":/workdir -w /workdir \
texlive/texlive latexmk -lualatex main.texPasar --user lo convierte entonces en un usuario sin directorio personal, y LuaTeX o fontconfig pueden quejarse al intentar escribir una caché. Apuntar HOME a un directorio con permiso de escritura, como arriba, basta. Desde febrero de 2025 la imagen incluye además un usuario no root llamado texlive, que el README recomienda para las imágenes derivadas, añadiendo de paso que los permisos de los montajes bind pueden requerir ajuste. En el fondo, usar el mismo UID en el anfitrión y en el contenedor es la única solución real.
Construir una imagen propia del proyecto
En vez de ejecutar tlmgr install en cada compilación, es más rápido —y mucho más fácil de depurar— construir una imagen con lo necesario y fijarla. Se parte de FROM texlive/texlive:latest-medium y se añaden los paquetes o fuentes que falten. Aquí se esconde un truco bonito. La imagen de Island of TeX fabrica con equivs un paquete Debian ficticio llamado texlive-local, en versión 9999.99999999, y lo marca como instalado. Gracias a eso, instalar un paquete Debian que dependa de TeX —apt-get install pandoc, por ejemplo— no arrastra un segundo TeX Live empaquetado por Debian.
# Dockerfile
FROM texlive/texlive:latest-medium
# Extra TeX packages. On a non-full scheme, "path add" is required
# for any package that installs a new executable.
RUN tlmgr install latexmk siunitx biblatex biber \
&& tlmgr path add
# Extra system packages: the image already claims texlive is installed,
# so this will not pull in Debian's own TeX Live.
RUN apt-get update \
&& apt-get install -y --no-install-recommends fonts-noto-cjk \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workdirSe construye con docker build -t myproject-tex . y a partir de ahí solo se usa esa etiqueta. Con las fuentes CJK dentro, la combinación de LuaLaTeX y luatexja-fontspec queda autocontenida en la caja. Para entregar la imagen a coautores o a un equipo, súbala a un registro interno o congélela con docker save. Llegados aquí, la verdadera ganancia no son los megabytes: es que la instrucción a un colaborador ocupa una línea, en vez de «instálate TeX Live».
Usar la imagen desde CI: GitHub Actions y GitLab CI
En GitLab CI se nombra la imagen en el image: del trabajo; en GitHub Actions se especifica un contenedor directamente o se usa xu-cheng/latex-action. Conviene desmontar aquí una suposición: xu-cheng/latex-action no usa texlive/texlive. La acción descarga ghcr.io/xu-cheng/texlive-alpine o ghcr.io/xu-cheng/texlive-debian, publicadas por el proyecto xu-cheng/latex-docker del mismo autor. Por eso su entrada os vale alpine por defecto; texlive_version acepta de 2020 a 2026, o latest. En resumen: dos cosas descritas ambas como «un contenedor con TeX Live» pueden ser bien distintas por dentro.
# .gitlab-ci.yml - the image goes straight into the job.
build:
image: texlive/texlive:latest
script:
- latexmk -pdf main.tex
artifacts:
paths:
- main.pdf
# GitHub Actions, run inside the same image instead of an action:
jobs:
build:
runs-on: ubuntu-latest
container: texlive/texlive@sha256:0123abcd...
steps:
- uses: actions/checkout@v7
- run: latexmk -pdf main.texEscribir la imagen en container: tiene la ventaja de que su docker run local y la CI son literalmente el mismo entorno. Usar xu-cheng/latex-action es más breve y ofrece entradas finas como latexmk_use_lualatex y latexmk_shell_escape (sus argumentos latexmk por defecto son -pdf -file-line-error -halt-on-error -interaction=nonstopmode). La elección es un compromiso entre identidad con el entorno local y brevedad; si la reproducibilidad manda, tome lo primero. El montaje del flujo de trabajo, la caché y el manejo de artefactos son terreno de la página de CI.
Dejar el manuscrito listo para el contenedor
Los manuscritos que fallan dentro de un contenedor tienen algo en común: el procedimiento de compilación solo existe en un ajuste del editor. Archivo raíz, motor, comandos auxiliares, ubicación de salida: en cuanto esos cuatro existen como texto dentro del repositorio, la misma línea latexmk main.tex sirve en local, en Docker y en CI. Si usa upLaTeX y dvipdfmx para japonés, ponga un .latexmkrc junto a main.tex y escriba la ruta de forma explícita. $pdf_mode = 3 significa «produce un DVI y luego conviértelo en PDF con dvipdfmx».
# .latexmkrc: upLaTeX + dvipdfmx
$latex = "uplatex -interaction=nonstopmode -halt-on-error %O %S";
$bibtex = "upbibtex %O %B";
$dvipdf = "dvipdfmx %O -o %D %S";
$pdf_mode = 3;Con ese .latexmkrc en el repositorio, el PDF se construye bajo las mismas reglas se le llame desde docker run, GitLab CI o GitHub Actions. Junto a ello, adopte la costumbre de revisar la etiqueta de la imagen cada vez que añada de verdad un \usepackage. Añada tikz-cd con el esquema todavía fijado en medium y un día se caerá solo la CI, con ! LaTeX Error: File 'tikz-cd.sty' not found. Versione juntos el manuscrito y el entorno: en el fondo, ese es el compromiso que se adquiere al componer dentro de un contenedor.