diff --git a/registry/joergklein/.images/avatar.jpg b/registry/joergklein/.images/avatar.jpg new file mode 100644 index 000000000..d71831071 Binary files /dev/null and b/registry/joergklein/.images/avatar.jpg differ diff --git a/registry/joergklein/README.md b/registry/joergklein/README.md new file mode 100644 index 000000000..132f5b53c --- /dev/null +++ b/registry/joergklein/README.md @@ -0,0 +1,11 @@ +--- +display_name: "Jörg Klein" +bio: "Data Scientists" +github: "joergklein" +avatar: "./.images/avatar.jpeg" +status: "community" +--- + +# Jörg Klein + +Data Scientists diff --git a/registry/joergklein/templates/docker-texlive/README.md b/registry/joergklein/templates/docker-texlive/README.md new file mode 100644 index 000000000..eee3a4129 --- /dev/null +++ b/registry/joergklein/templates/docker-texlive/README.md @@ -0,0 +1,88 @@ +--- +display_name: Docker TeX Live +description: Provision Docker containers with TeX Live, code-server +icon: ../../../../.icons/docker.svg +tags: [docker, texlive] +--- + +# TeX Live Development on Docker Containers + +Provision Docker containers pre-configured for TeX development as [Coder workspaces](https://coder.com/docs/workspaces) with this template. + +Each workspace comes with: + +- **TeX Live** — TeX Live is a comprehensive, cross-platform distribution for TeX and LaTeX systems that provides all necessary programs, macro packages, and fonts for professional typesetting. +- **code-server** — VS Code in the browser for general editing. + +The workspace is based on the [TeX Live](https://www.tug.org/texlive) image. It provides nearly all packages from the [Comprehensive TeX Archive Network (CTAN)](https://www.ctan.org), although some non-free packages may be restricted. + +## Prerequisites + +### Infrastructure + +#### Running Coder inside Docker + +If you installed Coder as a container within Docker, you will have to do the following things: + +- Make the Docker socket available to the container + - **(recommended) Mount `/var/run/docker.sock` via `--mount`/`volume`** + - _(advanced) Restrict the Docker socket via https://github.com/Tecnativa/docker-socket-proxy_ +- Set `--group-add`/`group_add` to the GID of the Docker group on the **host** machine + - You can get the GID by running `getent group docker` on the **host** machine + +#### Running Coder outside of Docker + +If you installed Coder as a system package, the VM you run Coder on must have a running Docker socket and the `coder` user must be added to the Docker group: + +```bash +# Add coder user to Docker group +sudo adduser coder docker + +# Restart Coder server +sudo systemctl restart coder + +# Test Docker +sudo -u coder docker ps +``` + +## Architecture + +This template provisions the following resources: + +- Docker image (built from `build/Dockerfile`, extending `registry.gitlab.com/islandoftex/images/texlive` with system dependencies) +- Docker container (ephemeral — destroyed on workspace stop) +- Docker volume (persistent on `/home/texlive`) + +When the workspace restarts, tools and files outside `/home/texlive` are not persisted. + +> [!NOTE] +> This template is designed to be a starting point! Edit the Terraform to extend it for your use case. + +## Customization + +The continuous integration is scheduled to rebuild all Docker images weekly. Hence, pulling the latest image will provide you with an at most one week old snapshot of TeX Live including all packages. You can manually update within the container by running `tlmgr update --self --all`. + +Each of the weekly builds is tagged with `TL{RELEASE}-{YEAR}-{MONTH}-{DAY}-{HOUR}-{MINUTE}` apart from being latest for one week. If you want to have reproducible builds or happen to find a regression in a later image you can still revert to a date that worked, e.g. `TL2019-2019-08-01-08-14 or latest`. + +- [Container Registry TeX Live](https://gitlab.com/islandoftex/images/texlive/container_registry) +- [Dockerhub TeX Live](https://hub.docker.com/r/texlive/texlive) + +### Installing additional TeX packages + +If you want to update packages from CTAN after installation, see these [examples of using tlmgr](https://tug.org/texlive/doc/tlmgr.html#EXAMPLES). This is not required, or even necessarily recommended; it's up to you to decide if it makes sense to get continuing updates in your particular situation. + +Typically the main binaries are not updated in TeX Live between major releases. If you want to get updates for LuaTeX and other packages and programs that aren't officially released yet, they may be available in the [TLContrib repository](http://contrib.texlive.info), or you may need to [compile the sources](https://tug.org/texlive/svn) yourself. + +### Adding system dependencies + +The `build/Dockerfile` extends the `registry.gitlab.com/islandoftex/images/texlive` base image with system packages required by modules (e.g. `curl` for code-server). If you add modules that need additional system-level tools, add them to the `Dockerfile`: + +```dockerfile +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + curl \ + unzip \ + wget \ + your-package-here \ + && rm -rf /var/lib/apt/lists/* +``` diff --git a/registry/joergklein/templates/docker-texlive/build/Dockerfile b/registry/joergklein/templates/docker-texlive/build/Dockerfile new file mode 100644 index 000000000..f3e776cc7 --- /dev/null +++ b/registry/joergklein/templates/docker-texlive/build/Dockerfile @@ -0,0 +1,23 @@ +ARG TEXLIVE_VERSION=latest +FROM registry.gitlab.com/islandoftex/images/texlive:${TEXLIVE_VERSION} + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + curl \ + unzip \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# Set locale to UTF-8 +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 + +# Optional: Update TeX Live packages +# Only enable if you need the latest packages +# RUN tlmgr update --self --all + +# Working directory inside the container +WORKDIR /home/texlive + +# Icon +COPY icon/ /icon/ diff --git a/registry/joergklein/templates/docker-texlive/build/icon/texlive.png b/registry/joergklein/templates/docker-texlive/build/icon/texlive.png new file mode 100644 index 000000000..315f6846e Binary files /dev/null and b/registry/joergklein/templates/docker-texlive/build/icon/texlive.png differ diff --git a/registry/joergklein/templates/docker-texlive/main.tf b/registry/joergklein/templates/docker-texlive/main.tf new file mode 100644 index 000000000..5b8845288 --- /dev/null +++ b/registry/joergklein/templates/docker-texlive/main.tf @@ -0,0 +1,203 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + docker = { + source = "kreuzwerker/docker" + } + } +} + +locals { + username = data.coder_workspace_owner.me.name + + build_context_hash = sha1(join("", [ + for f in fileset("${path.module}/build", "**") : + filesha1("${path.module}/build/${f}") + ])) + + latest_rebuild_trigger = var.texlive_version == "latest" ? formatdate("YYYY-ww", timestamp()) : "" +} + +variable "docker_socket" { + default = "" + description = "(Optional) Docker socket URI" + type = string +} + +variable "texlive_version" { + default = "latest" + description = "The TeX Live image tag to use (e.g., TL2025-2025-01-01-08-14 or latest)" + type = string +} + +provider "docker" { + host = var.docker_socket != "" ? var.docker_socket : null +} + +data "coder_provisioner" "me" {} +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +resource "coder_agent" "main" { + arch = data.coder_provisioner.me.arch + os = "linux" + + startup_script = <<-EOT + set -e + if [ ! -f ~/.init_done ]; then + cp -rT /etc/skel ~ 2>/dev/null || true + touch ~/.init_done + fi + EOT + + env = { + GIT_AUTHOR_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) + GIT_AUTHOR_EMAIL = data.coder_workspace_owner.me.email + GIT_COMMITTER_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) + GIT_COMMITTER_EMAIL = data.coder_workspace_owner.me.email + } + + metadata { + display_name = "CPU Usage" + key = "0_cpu_usage" + script = "coder stat cpu" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "RAM Usage" + key = "1_ram_usage" + script = "coder stat mem" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Home Disk" + key = "3_home_disk" + script = "coder stat disk --path $${HOME}" + interval = 60 + timeout = 1 + } +} + +module "code-server" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/code-server/coder" + + version = "~> 1.0" + agent_id = coder_agent.main.id + agent_name = "main" + order = 1 + folder = "/home/texlive" +} + +resource "docker_image" "texlive" { + name = "registry.example.com/texlive:${var.texlive_version}-${data.coder_workspace.me.id}-${substr(local.build_context_hash, 0, 8)}" + + build { + context = "${path.module}/build" + dockerfile = "Dockerfile" + + build_args = { + TEXLIVE_VERSION = var.texlive_version + } + } + + triggers = { + dir_hash = local.build_context_hash + texlive_version = var.texlive_version + latest_rebuild = local.latest_rebuild_trigger + } +} + +resource "docker_volume" "home_volume" { + name = "coder-${data.coder_workspace.me.id}-home" + + lifecycle { + ignore_changes = all + } + + labels { + label = "coder.owner" + value = data.coder_workspace_owner.me.name + } + labels { + label = "coder.owner_id" + value = data.coder_workspace_owner.me.id + } + labels { + label = "coder.workspace_id" + value = data.coder_workspace.me.id + } + labels { + label = "coder.workspace_name_at_creation" + value = data.coder_workspace.me.name + } +} + +resource "docker_container" "workspace" { + count = data.coder_workspace.me.start_count + image = docker_image.texlive.image_id + name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}" + hostname = data.coder_workspace.me.name + + entrypoint = [ + "sh", + "-c", + replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal") + ] + + env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"] + + host { + host = "host.docker.internal" + ip = "host-gateway" + } + + volumes { + container_path = "/home/texlive" + volume_name = docker_volume.home_volume.name + read_only = false + } + + labels { + label = "coder.owner" + value = data.coder_workspace_owner.me.name + } + labels { + label = "coder.owner_id" + value = data.coder_workspace_owner.me.id + } + labels { + label = "coder.workspace_id" + value = data.coder_workspace.me.id + } + labels { + label = "coder.workspace_name" + value = data.coder_workspace.me.name + } +} + +resource "null_resource" "cleanup_old_texlive_images" { + triggers = { + current_image = docker_image.texlive.name + } + + provisioner "local-exec" { + command = <