devcontainer
Configuration
There are two supported devcontainer configurations for the root project (ref spec): - .devcontainer/dev-build
- manually rebuild the container on your machines - deafult
- pull CI build image and attach
You can either open the root folder and select one of these two configurations when prompted by VSCode, or open a .devcontainer
config from a tutorial/blog post if you want to use the custom environment there.
Codespaces
Since codespaces are naive, they just use the root spec in .devcontainer
. Because of this, I have copied the prebuilt config into that directory. This shows up as Main, and should be a safe option for developers.
Dockerfile
For the core docs, I used Python as the base image, and then installed Quarto, TeX, and other dependencies in the Dockerfile:
# syntax=docker/dockerfile:1.3-labs
# ^ Need this for syntax specific to heredoc aliases
# Lets use the latest Python (3.11 was latest at the time)
# https://github.com/devcontainers/images/tree/main/src/python
FROM mcr.microsoft.com/devcontainers/python:3.11-bookworm
ENV QUARTO_VERSION=1.4.533
RUN apt-get update && \
apt-get install -y --no-install-recommends fontconfig=2.14.1-4 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install Tex Live - this isn't 100% reproducible, but the build will always work and update...
RUN curl -L -o install-tl-unx.tar.gz https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN zcat < install-tl-unx.tar.gz | tar xf -
RUN rm install-tl-unx.tar.gz
RUN mv "$(find . -maxdepth 1 -type d -regex ".*install-tl.*")" ./install-tlmgr
WORKDIR /install-tlmgr
RUN perl ./install-tl --no-interaction --scheme=small --no-doc-install --no-src-install
# 2024 might break first
ENV PATH=$PATH:/usr/local/texlive/2024/bin/x86_64-linux
WORKDIR /
# Update tlmgr - https://www.tug.org/texlive/tlmgr.html
# Also install any other extensions that are used
# - This was trial and error as far as I can tell
RUN tlmgr update --self --all && \
tlmgr install tcolorbox \
\
environ \
tikzfill \
titlesec \
xstring \
pdfcol
fontawesome5
# Install pre-commit CLI
RUN pip install --no-cache-dir pre-commit==3.7.0
# Configure aliases with a heredoc
COPY <<-"end_aliases" /home/vscode/.bash_aliases
#!/bin/bash
"ls -alF"
alias ll="git log --graph --oneline --color"
alias gg="git commit"
alias gc="git checkout"
alias gck="git status"
alias gs="git add"
alias ga="git diff"
alias gd="git fetch --all"
alias gf="git push"
alias gp="git reset --hard"
alias grs="quarto render && quarto preview"
alias qrp=
end_aliases
# Install quarto
RUN curl -L -o quarto-${QUARTO_VERSION}-linux-amd64.tar.gz https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.tar.gz \
&& tar -xvzf quarto-${QUARTO_VERSION}-linux-amd64.tar.gz \
&& rm quarto-${QUARTO_VERSION}-linux-amd64.tar.gz
# Configure PATH
ENV PATH=$PATH:/quarto-${QUARTO_VERSION}/bin
# When running locally, we really need to expose a port
EXPOSE 8080
Note that TeX is installed here, as well as convenient aliases and other tools like pre-commit.
JSON config
Local Build Config
{
"build": {
"dockerfile": "Dockerfile",
"context": "../.."
},
"customizations": {
"vscode": {
"extensions": [
"quarto.quarto",
"sumneko.lua",
"ms-azuretools.vscode-docker",
"github.vscode-github-actions",
"tomoki1207.pdf",
"GitHub.copilot"
]
}
},
"workspaceFolder": "/home/app/",
"postCreateCommand": ".devcontainer/dev-build/postCreateCommand.sh",
"workspaceMount": "source=${localWorkspaceFolder},target=/home/app/,type=bind,consistency=cached"
}
CI Image Config
{
"image": "ghcr.io/cameronrutherford/quarto-ci:latest",
"customizations": {
"vscode": {
"extensions": [
"quarto.quarto",
"sumneko.lua",
"ms-azuretools.vscode-docker",
"github.vscode-github-actions",
"tomoki1207.pdf",
"GitHub.copilot"
]
}
},
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"username": "automatic",
"uid": "automatic",
"gid": "automatic",
"installZsh": false,
"installOhMyZsh": false,
"upgradePackages": false,
"nonFreePackages": false
}
},
"workspaceFolder": "/home/app/",
"postCreateCommand": ".devcontainer/dev-build/postCreateCommand.sh",
"workspaceMount": "source=${localWorkspaceFolder},target=/home/app/,type=bind,consistency=cached"
}
You can’t quite inherit configurations in devcontainers so this is a little repetitive, but it could be worse.
postCreateCommand.sh
I use a postCreateCommand
to run any final configurations inside of the container once it’s running:
#!/bin/bash
# Install username/email for convenience
git config --global --add safe.directory /home/app
git config --global user.email "cameron.rutherford@me.com"
git config --global user.name "cameronrutherford"
# Install pre-commit hooks
cd /home/app
# If poetry is installed, run with that. Otherwise just try running
poetry run pre-commit install --install-hooks || pre-commit install --install-hooks
Since pre-commit was buggy being installed in the quarto-ci
base image, we have moved that into the postCreateCommand.sh
script, so that every image still gets to share the fix, but none have anything installed by default, making the image smaller! We could also consider removing pre-commit
from the base image entirely.
There seems to be a caching issue somewhere, so that file lives in .devcontainer/dev-build
. It’s totally possible it can be moved, but I am leving it for now.
The git user is customized to me here for convenience, but you can change this for yourself. As noted in Quickstart, you will want to do git operations outside of the container still.