101 lines
5.1 KiB
Markdown
101 lines
5.1 KiB
Markdown
# quarto-deploy
|
|
|
|
The container image our Gitea Actions runners use to build and publish Quarto sites.
|
|
|
|
## What it is
|
|
|
|
A push to a site repository triggers a runner to render the site and then copy the result to the web server.
|
|
This image is the environment in which that job runs.
|
|
It is deliberately small: rendering uses Quarto's frozen output, so the executed R and Python results are committed to each site repository rather than recomputed here.
|
|
The image carries no language kernels; only what it takes to check out a repository, render, and sync files.
|
|
|
|
Node runs the JavaScript actions Gitea uses to bootstrap a job, such as `actions/checkout`. `git` performs the checkout, `rsync` copies the rendered site into place, and `curl` fetches Pixi baked into the image, so each run neither downloads the tool nor pipes a script into a shell.
|
|
|
|
The image stays generic about project dependencies on purpose: it ships Pixi but no packages.
|
|
The Quarto it fixes, baked in and named by the tag, is the renderer the runner uses, and each site mirrors that version in its own `pixi.toml` so local work matches what the runner produces.
|
|
|
|
## Build
|
|
|
|
Build the image on your own machine and push it to Gitea's container registry.
|
|
The runners only ever pull it.
|
|
|
|
You will need an access token with `package:write` access.
|
|
Go to your Gitea settings and under “Applications,” you will find “Generate New Token.”
|
|
Give the token a name like `quarto-deploy-package` and select “Read and Write” for package permissions.
|
|
Next, we will authenticate Docker for pushing packages by running `docker login` and using the newly generated token as the password.
|
|
|
|
```bash
|
|
docker login git.scient.ing
|
|
```
|
|
|
|
Now we can build the package for our servers, which are `linux/amd64`.
|
|
Note that Apple Silicon defaults to `arm64`, and an `arm64` image may push but then fail to start on the runner with an exec-format error.
|
|
|
|
`buildx` cross-compiles for the platform you specify; `--push` sends the result straight to the registry, so the build and upload are one step, and the trailing `.` is the build context (the directory containing this `Dockerfile`).
|
|
|
|
```bash
|
|
docker buildx build --platform linux/amd64 \
|
|
-t git.scient.ing/infra/quarto-deploy:1.9.38 --push .
|
|
```
|
|
|
|
Bump the tag whenever the `Dockerfile` changes: to the new Quarto version on a Quarto bump, or with a revision suffix like `:1.9.38-2` otherwise.
|
|
The image is always pulled by an explicit version, never `latest`, so a runner's behavior stays tied to a named artifact you can roll back to.
|
|
|
|
## Quarto versions
|
|
|
|
Quarto is pinned in the image, not pulled fresh at render time.
|
|
The version lives in the `Dockerfile` as the `QUARTO_VERSION` build argument, paired with `QUARTO_SHA256`, the checksum of that release's `linux-amd64` tarball.
|
|
The image tag carries the same number, so a runner renders against one known Quarto, and that Quarto travels with the artifact you push, pull, and roll back to.
|
|
|
|
Each site mirrors this version in its own `pixi.toml` for local work, so a bump happens in two places.
|
|
To move to a new Quarto, set `QUARTO_VERSION` in the `Dockerfile` to the release you want and `QUARTO_SHA256` to the matching `quarto-<version>-linux-amd64.tar.gz` checksum from the [releases page](https://github.com/quarto-dev/quarto-cli/releases), then change the `quarto` pin in each site's `pixi.toml` to the same number.
|
|
The build verifies the download against the checksum, so a wrong or stale hash fails the build instead of shipping a Quarto you didn't intend.
|
|
Then build and push under the new version tag as shown above, point each runner's label at it, and restart the runner.
|
|
Site workflows stay untouched. They select the runner by its `quarto-deploy` label, never by version.
|
|
|
|
## Local development
|
|
|
|
You author and test a site in a Pixi environment that pins the same Quarto image renders with, so what you see locally is what the runner publishes.
|
|
Quarto comes from conda-forge:
|
|
|
|
```toml
|
|
[dependencies]
|
|
quarto = { version = "==1.9.38", channel = "conda-forge" }
|
|
```
|
|
|
|
Keep this equal to `QUARTO_VERSION` in the `Dockerfile`.
|
|
A few tasks cover the loop:
|
|
|
|
```toml
|
|
[tasks]
|
|
serve = { cmd = ["quarto", "preview", "content"] }
|
|
build = { cmd = ["quarto", "render", "content", "--output-dir", "../public"] }
|
|
bump = { cmd = ["bump-my-version", "bump", "patch"] }
|
|
```
|
|
|
|
`pixi run serve` previews `content/` while you write.
|
|
`pixi run build` renders it into `public/`, the directory the runner publishes.
|
|
`pixi run bump` advances the site's own version, which is separate from the Quarto pin.
|
|
If a site executes code, add the kernels it needs (`jupyter`, `r-base`, and so on) to `pixi.toml`, render once, and commit the resulting `_freeze` so the runner reproduces the output without running anything.
|
|
|
|
## Use
|
|
|
|
A runner advertises a label that maps to this image, and a workflow selects it with `runs-on`.
|
|
|
|
```yaml
|
|
# in a runner's config.yaml
|
|
runner:
|
|
labels:
|
|
- "quarto-deploy:docker://git.scient.ing/infra/quarto-deploy:1.9.38"
|
|
```
|
|
|
|
```yaml
|
|
# in a site repository's .gitea/workflows/deploy.yml
|
|
jobs:
|
|
deploy:
|
|
runs-on: quarto-deploy
|
|
```
|
|
|
|
Changing the image for each runner involves pointing the label at a new tag and restarting the runner.
|
|
The workflows never change.
|