From 80c5a783f523e3eedeba00f9fe80c365b4866714 Mon Sep 17 00:00:00 2001 From: Carl Boettiger Date: Mon, 23 Jun 2025 10:06:49 -0700 Subject: [PATCH 1/4] :fairy: --- .github/workflows/cuda-image.yml | 65 +++++++++++++++++++++----------- R/Dockerfile | 10 +++++ base/Dockerfile | 4 -- base/config.ts | 25 ------------ base/environment.yml | 14 ------- cuda/Dockerfile | 40 ++------------------ cuda/pixi.toml | 10 +++++ 7 files changed, 65 insertions(+), 103 deletions(-) create mode 100644 R/Dockerfile delete mode 100644 base/config.ts delete mode 100644 base/environment.yml create mode 100644 cuda/pixi.toml diff --git a/.github/workflows/cuda-image.yml b/.github/workflows/cuda-image.yml index dc9e60e..7cbb449 100644 --- a/.github/workflows/cuda-image.yml +++ b/.github/workflows/cuda-image.yml @@ -1,32 +1,51 @@ -name: CUDA +name: Docker Build and Push to GHCR + on: - workflow_dispatch: null push: - paths: ['cuda/*'] + tags: + - 'v*.*.*' # Example: trigger on Git tags like v1.0.0 + +env: + IMAGE_NAME: ghcr.io/${{ github.repository }}/cuda + jobs: - build: + build-and-push: runs-on: ubuntu-latest - permissions: write-all + permissions: + contents: read + packages: write # Necessary for pushing to GHCR + steps: - # For biggish images, github actions runs out of disk space. - - name: cleanup disk space - run: sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc - - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 with: registry: ghcr.io - username: ${{github.actor}} - password: ${{secrets.GITHUB_TOKEN}} - - - name: Build the Docker image (torch) - run: docker build cuda --build-arg BASE=quay.io/jupyter/pytorch-notebook:cuda12-ubuntu-24.04 --tag ghcr.io/schmidtdse/cuda:latest - - name: Publish cuda (torch) - run: docker push ghcr.io/schmidtdse/cuda:latest - - - name: Build the Docker image (tensorflow) - run: docker build cuda --build-arg BASE=quay.io/jupyter/tensorflow-notebook:cuda-latest --tag ghcr.io/schmidtdse/tensorflow:latest - - name: Publish tensorflow - run: docker push ghcr.io/schmidtdse/tensorflow:latest + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} + type=ref,event=branch + type=semver,pattern=v{{version}} + type=sha,format=short + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: cuda + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/R/Dockerfile b/R/Dockerfile new file mode 100644 index 0000000..e0b199a --- /dev/null +++ b/R/Dockerfile @@ -0,0 +1,10 @@ +FROM ghcr.io/schmidtdse/base + +# Install R, RStudio +USER root + +RUN curl -s https://raw.githubusercontent.com/rocker-org/ml/refs/heads/master/install_r.sh | bash +RUN curl -s https://raw.githubusercontent.com/rocker-org/ml/refs/heads/master/install_rstudio.sh | bash + +USER ${NB_USER} + diff --git a/base/Dockerfile b/base/Dockerfile index a25a611..2fb52be 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -41,10 +41,6 @@ RUN apt-get update -q && apt-get -y install curl && apt-get clean && rm -rf /var RUN mkdir -p ${CODE_EXTENSIONSDIR} && chown -R ${NB_USER}:users ${CODE_EXTENSIONSDIR} RUN curl -fsSL https://code-server.dev/install.sh | sh && rm -rf /home/${NB_USER}/.cache -# Install R, RStudio -RUN curl -s https://raw.githubusercontent.com/rocker-org/ml/refs/heads/master/install_r.sh | bash -RUN curl -s https://raw.githubusercontent.com/rocker-org/ml/refs/heads/master/install_rstudio.sh | bash - # Build the environment USER ${NB_USER} diff --git a/base/config.ts b/base/config.ts deleted file mode 100644 index 92e18c6..0000000 --- a/base/config.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Configuration helper for continue.dev -// From: https://github.com/continuedev/continue/issues/4323#issuecomment-2688947097 -// replace ${VAR_NAME} placeholders with their process.env values -const replaceEnvVars = (obj: T): T => { - if (Array.isArray(obj)) { - return obj.map(replaceEnvVars) as T; - } - - if (!obj || typeof obj !== 'object') { - return obj; - } - - const result = { ...obj } as Record; - for (const key in result) { - if (Object.prototype.hasOwnProperty.call(result, key)) { - if (typeof result[key] === 'string') { - result[key] = result[key].replace(/\$\{(.+?)\}/g, (_, varName) => - process.env[varName] ?? ''); - } else if (result[key] && typeof result[key] === 'object') { - result[key] = replaceEnvVars(result[key]); - } - } - } - return result as T; -}; diff --git a/base/environment.yml b/base/environment.yml deleted file mode 100644 index c4024fa..0000000 --- a/base/environment.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: base -channels: - - conda-forge -dependencies: - - glances - - git-filter-repo - - jupyter-resource-usage - - jupyter-vscode-proxy - - minio - - pypdf - - pip - - pip: - - jupyter-keepalive - diff --git a/cuda/Dockerfile b/cuda/Dockerfile index df19f52..3de9d1d 100644 --- a/cuda/Dockerfile +++ b/cuda/Dockerfile @@ -1,38 +1,4 @@ -ARG BASE=quay.io/jupyter/minimal-notebook:ubuntu-24.04 - -# cuda image uses: -# ARG BASE=quay.io/jupyter/pytorch-notebook:cuda12-ubuntu-24.04 -FROM $BASE - -# Make code-server extensions etc persist to container, not hub -ENV XDG_DATA_HOME=/opt/share -ENV PATH=/opt/share/pixi/bin:$PATH - -## Grant user sudoer privileges -USER root -RUN adduser "$NB_USER" sudo && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers -RUN mkdir /opt/share && chown -R ${NB_USER}:users /opt/share - -USER ${NB_USER} - - -## Create user-owned workspace -RUN sudo mkdir /workspace && sudo chown -R ${NB_USER}:users /workspace - -# code-server (VSCode) -RUN sudo curl -fsSL https://code-server.dev/install.sh | sh && rm -rf .cache - -# apt utilities, code-server setup -COPY install_utilities.sh /tmp/install_utilities.sh -RUN sudo bash /tmp/install_utilities.sh - -# install pixi -RUN curl -fsSL https://pixi.sh/install.sh | PIXI_HOME=/opt/share/pixi bash - -COPY vscode-extensions.txt vscode-extensions.txt -RUN xargs -n 1 code-server --install-extension < vscode-extensions.txt - -COPY environment.yml environment.yml -RUN conda update --all --solver=classic -n base -c conda-forge conda && \ - conda env update --file environment.yml +FROM ghcr.io/schmidtdse/base +COPY pixi.toml . +RUN pixi install diff --git a/cuda/pixi.toml b/cuda/pixi.toml new file mode 100644 index 0000000..97bbac0 --- /dev/null +++ b/cuda/pixi.toml @@ -0,0 +1,10 @@ +[workspace] +channels = ["https://prefix.dev/conda-forge"] +name = "pytorch-conda-forge" +platforms = ["linux-64", "win-64"] + +[system-requirements] +cuda = "12.7" + +[dependencies] +pytorch-gpu = "*" From 7c373372aeb03509179286f1a843a6d48797550a Mon Sep 17 00:00:00 2001 From: Carl Boettiger Date: Mon, 23 Jun 2025 10:13:01 -0700 Subject: [PATCH 2/4] :fairy: :boom: --- cuda/environment.yml | 14 -------------- cuda/install_utilities.sh | 30 ------------------------------ cuda/pixi.toml | 4 ++-- cuda/vscode-extensions.txt | 5 ----- 4 files changed, 2 insertions(+), 51 deletions(-) delete mode 100644 cuda/environment.yml delete mode 100644 cuda/install_utilities.sh delete mode 100644 cuda/vscode-extensions.txt diff --git a/cuda/environment.yml b/cuda/environment.yml deleted file mode 100644 index c4024fa..0000000 --- a/cuda/environment.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: base -channels: - - conda-forge -dependencies: - - glances - - git-filter-repo - - jupyter-resource-usage - - jupyter-vscode-proxy - - minio - - pypdf - - pip - - pip: - - jupyter-keepalive - diff --git a/cuda/install_utilities.sh b/cuda/install_utilities.sh deleted file mode 100644 index 32eb6e2..0000000 --- a/cuda/install_utilities.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# some apt-get utilities. -# NOTE: BSPM will get those required for any R packages. -apt-get update -qq && apt-get -y install \ - vim git-lfs wget curl qpdf sudo libcurl4-openssl-dev libxml2-dev python3-venv gettext - -# ensure user owns all of /opt/share (e.g. for vscode-plugins) -mkdir /opt/share && chown -R ${NB_USER}:users /opt/share - -# awscli tool for S3 use -curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \ - unzip awscliv2.zip && \ - ./aws/install - -# minio client for S3 use -curl https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc && chmod +x /usr/local/bin/mc - -# optional git config -# git config --system pull.rebase false && \ -# git config --system credential.credentialStore cache && \ -# git config --system credential.cacheOptions "--timeout 30000" && \ -# echo '"\e[5~": history-search-backward' >> /etc/inputrc && \ -# echo '"\e[6~": history-search-forward' >> /etc/inputrc - -# Optional credential manager for RStudio/Jupyter users. -- code-server extension provides easier alternative. -# wget https://github.com/git-ecosystem/git-credential-manager/releases/download/v2.6.0/gcm-linux_amd64.2.6.0.deb && dpkg -i gcm-*.deb && rm gcm-*.deb -# git-credential-manager configure --system - - diff --git a/cuda/pixi.toml b/cuda/pixi.toml index 97bbac0..511d077 100644 --- a/cuda/pixi.toml +++ b/cuda/pixi.toml @@ -1,10 +1,10 @@ [workspace] channels = ["https://prefix.dev/conda-forge"] name = "pytorch-conda-forge" -platforms = ["linux-64", "win-64"] +platforms = ["linux-64"] [system-requirements] -cuda = "12.7" +cuda = "12.0" [dependencies] pytorch-gpu = "*" diff --git a/cuda/vscode-extensions.txt b/cuda/vscode-extensions.txt deleted file mode 100644 index c2478f1..0000000 --- a/cuda/vscode-extensions.txt +++ /dev/null @@ -1,5 +0,0 @@ -ms-python.python -ms-toolsai.jupyter -ms-vscode.live-server -continue.continue - From 2d7a9366a0d34911e0588b77e5a6ab663bf0d4ee Mon Sep 17 00:00:00 2001 From: Carl Boettiger Date: Mon, 23 Jun 2025 11:27:20 -0700 Subject: [PATCH 3/4] :fairy: :fairy: :fairy: :fairy: :fairy: --- R/Dockerfile | 4 +++ base/Dockerfile | 5 ++- base/pixi.toml | 3 +- cuda/Dockerfile | 68 ++++++++++++++++++++++++++++++++++++-- cuda/install_utilities.sh | 30 +++++++++++++++++ cuda/pixi.toml | 25 ++++++++++++-- cuda/vscode-extensions.txt | 10 ++++++ 7 files changed, 134 insertions(+), 11 deletions(-) create mode 100644 cuda/install_utilities.sh create mode 100644 cuda/vscode-extensions.txt diff --git a/R/Dockerfile b/R/Dockerfile index e0b199a..0910174 100644 --- a/R/Dockerfile +++ b/R/Dockerfile @@ -8,3 +8,7 @@ RUN curl -s https://raw.githubusercontent.com/rocker-org/ml/refs/heads/master/in USER ${NB_USER} +# We either must modify the official /workdir/pixi.toml, or we can use pixi add +# We don't need to activate pixi env, just be in the correct workdir +RUN cd ${DOCKER_WORKDIR} && pixi add jupyter-rsession-proxy + diff --git a/base/Dockerfile b/base/Dockerfile index 2fb52be..e2b681a 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -47,12 +47,12 @@ USER ${NB_USER} COPY vscode-extensions.txt /tmp/vscode-extensions.txt RUN xargs -n 1 code-server --extensions-dir ${CODE_EXTENSIONSDIR} --install-extension < /tmp/vscode-extensions.txt -COPY pixi.toml . +COPY --chown=${NB_UID}:${NB_UID} pixi.toml . RUN pixi install \ && rm -rf ~/.cache/rattler # Set up shell activation script - RUN pixi shell-hook -s bash > ./shell-hook +RUN pixi shell-hook -s bash > ./shell-hook USER root ENV ENTRYPOINT_SCRIPT="/entrypoint.sh" RUN echo "#!/bin/bash" > ${ENTRYPOINT_SCRIPT} @@ -61,7 +61,6 @@ RUN echo 'exec "$@"' >> ${ENTRYPOINT_SCRIPT} RUN chmod +x ${ENTRYPOINT_SCRIPT} USER ${NB_USER} -WORKDIR "/home/${NB_USER}" EXPOSE 8888 ENTRYPOINT ["/entrypoint.sh"] CMD ["jupyter", "lab", "--no-browser", "--ip=0.0.0.0"] diff --git a/base/pixi.toml b/base/pixi.toml index ab9c482..ff4ee7e 100644 --- a/base/pixi.toml +++ b/base/pixi.toml @@ -1,7 +1,7 @@ [workspace] authors = ["Matt Fisher "] channels = ["conda-forge", "nodefaults"] -name = "geojupyter-pixi-docker-image" +name = "schmidtdse" platforms = ["linux-64"] version = "0.1.0" @@ -15,7 +15,6 @@ jupyterlab-favorites = "*" jupyter-collaboration = "*" jupyter-server-proxy = "*" jupyter-vscode-proxy = "*" -jupyter-rsession-proxy = "*" jupyterlab-myst = "*" typst = "*" ruff = "*" diff --git a/cuda/Dockerfile b/cuda/Dockerfile index 3de9d1d..e2b681a 100644 --- a/cuda/Dockerfile +++ b/cuda/Dockerfile @@ -1,4 +1,66 @@ -FROM ghcr.io/schmidtdse/base +FROM ghcr.io/prefix-dev/pixi:noble AS build +LABEL "org.opencontainers.image.description"="A pixi-based Docker image for a robust GeoJupyter environment" -COPY pixi.toml . -RUN pixi install +# Use bash as default shell instead of sh +ENV SHELL=/bin/bash +# Don't buffer Python stdout/stderr output +ENV PYTHONBUFFERED=1 +# Don't prompt in apt commands +ENV DEBIAN_FRONTEND=noninteractive + +# Set up JupyterLab user +ENV NB_USER=jovyan +ENV NB_UID=1000 +ENV USER="${NB_USER}" +ENV HOME="/home/${NB_USER}" +RUN userdel ubuntu \ + && groupadd \ + --gid ${NB_UID} \ + ${NB_USER} \ + && useradd \ + --comment "Default Jupyter user" \ + --create-home \ + --no-log-init \ + --uid ${NB_UID} \ + --gid ${NB_UID} \ + --shell ${SHELL} \ + ${NB_USER} + +ENV DOCKER_WORKDIR=/workdir +WORKDIR ${DOCKER_WORKDIR} +RUN chown ${NB_UID}:${NB_UID} ${DOCKER_WORKDIR} + +# this env var is recognized by jupyter-vscode-proxy: +ENV CODE_EXTENSIONSDIR=/opt/share/code-server +# put quarto on the path too +ENV PATH=$PATH:/usr/lib/rstudio-server/bin/quarto/bin + +USER root +# code-server (VSCode) +RUN apt-get update -q && apt-get -y install curl && apt-get clean && rm -rf /var/lib/apt/lists/* +RUN mkdir -p ${CODE_EXTENSIONSDIR} && chown -R ${NB_USER}:users ${CODE_EXTENSIONSDIR} +RUN curl -fsSL https://code-server.dev/install.sh | sh && rm -rf /home/${NB_USER}/.cache + +# Build the environment +USER ${NB_USER} + +COPY vscode-extensions.txt /tmp/vscode-extensions.txt +RUN xargs -n 1 code-server --extensions-dir ${CODE_EXTENSIONSDIR} --install-extension < /tmp/vscode-extensions.txt + +COPY --chown=${NB_UID}:${NB_UID} pixi.toml . +RUN pixi install \ + && rm -rf ~/.cache/rattler + +# Set up shell activation script +RUN pixi shell-hook -s bash > ./shell-hook +USER root +ENV ENTRYPOINT_SCRIPT="/entrypoint.sh" +RUN echo "#!/bin/bash" > ${ENTRYPOINT_SCRIPT} + RUN cat ${PWD}/shell-hook >> ${ENTRYPOINT_SCRIPT} +RUN echo 'exec "$@"' >> ${ENTRYPOINT_SCRIPT} +RUN chmod +x ${ENTRYPOINT_SCRIPT} + +USER ${NB_USER} +EXPOSE 8888 +ENTRYPOINT ["/entrypoint.sh"] +CMD ["jupyter", "lab", "--no-browser", "--ip=0.0.0.0"] diff --git a/cuda/install_utilities.sh b/cuda/install_utilities.sh new file mode 100644 index 0000000..32eb6e2 --- /dev/null +++ b/cuda/install_utilities.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# some apt-get utilities. +# NOTE: BSPM will get those required for any R packages. +apt-get update -qq && apt-get -y install \ + vim git-lfs wget curl qpdf sudo libcurl4-openssl-dev libxml2-dev python3-venv gettext + +# ensure user owns all of /opt/share (e.g. for vscode-plugins) +mkdir /opt/share && chown -R ${NB_USER}:users /opt/share + +# awscli tool for S3 use +curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \ + unzip awscliv2.zip && \ + ./aws/install + +# minio client for S3 use +curl https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc && chmod +x /usr/local/bin/mc + +# optional git config +# git config --system pull.rebase false && \ +# git config --system credential.credentialStore cache && \ +# git config --system credential.cacheOptions "--timeout 30000" && \ +# echo '"\e[5~": history-search-backward' >> /etc/inputrc && \ +# echo '"\e[6~": history-search-forward' >> /etc/inputrc + +# Optional credential manager for RStudio/Jupyter users. -- code-server extension provides easier alternative. +# wget https://github.com/git-ecosystem/git-credential-manager/releases/download/v2.6.0/gcm-linux_amd64.2.6.0.deb && dpkg -i gcm-*.deb && rm gcm-*.deb +# git-credential-manager configure --system + + diff --git a/cuda/pixi.toml b/cuda/pixi.toml index 511d077..396e3c9 100644 --- a/cuda/pixi.toml +++ b/cuda/pixi.toml @@ -1,10 +1,29 @@ [workspace] -channels = ["https://prefix.dev/conda-forge"] -name = "pytorch-conda-forge" +authors = ["Matt Fisher "] +channels = ["conda-forge", "nodefaults"] +name = "schmidtdse-cuda" platforms = ["linux-64"] +version = "0.1.0" + +[tasks] + +[dependencies] +python = ">=3.12" +jupyterhub-singleuser = "*" +jupyterlab = ">=4.4.2" +jupyterlab-favorites = "*" +jupyter-collaboration = "*" +jupyter-server-proxy = "*" +jupyter-vscode-proxy = "*" +jupyterlab-myst = "*" +typst = "*" +ruff = "*" +pre-commit = "*" +gh = "*" +gh-scoped-creds = "*" [system-requirements] -cuda = "12.0" +cuda = "12.6" [dependencies] pytorch-gpu = "*" diff --git a/cuda/vscode-extensions.txt b/cuda/vscode-extensions.txt new file mode 100644 index 0000000..8cf04f1 --- /dev/null +++ b/cuda/vscode-extensions.txt @@ -0,0 +1,10 @@ +ms-python.python +ms-toolsai.jupyter +ms-vscode.live-server +quarto.quarto +posit.shiny +reditorsupport.r +continue.continue +alefragnani.project-manager +saoudrizwan.claude-dev + From 2c8ada24d84cb07eaee1295357e0c82c21f4df74 Mon Sep 17 00:00:00 2001 From: Carl Boettiger Date: Mon, 23 Jun 2025 12:48:50 -0700 Subject: [PATCH 4/4] Refactor: Simplify CUDA image build workflow This commit simplifies the CUDA image build workflow, triggering on paths within the `cuda/` directory instead of tags. It also adds disk cleanup to prevent out-of-space errors during builds and uses Docker Hub credentials for image building and pushing. --- .github/workflows/cuda-image.yml | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/cuda-image.yml b/.github/workflows/cuda-image.yml index 7cbb449..7b8a2ec 100644 --- a/.github/workflows/cuda-image.yml +++ b/.github/workflows/cuda-image.yml @@ -1,31 +1,31 @@ -name: Docker Build and Push to GHCR - +name: CUDA on: + workflow_dispatch: null push: - tags: - - 'v*.*.*' # Example: trigger on Git tags like v1.0.0 - -env: - IMAGE_NAME: ghcr.io/${{ github.repository }}/cuda - + paths: ['cuda/*'] jobs: - build-and-push: + build: runs-on: ubuntu-latest - permissions: - contents: read - packages: write # Necessary for pushing to GHCR - + permissions: write-all steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + # For biggish images, github actions runs out of disk space. + - name: cleanup disk space + run: sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc + - name: Checkout code + uses: actions/checkout@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 + - name: Build and push Docker image + uses: docker/build-push-action@v4 with: - registry: ghcr.io + context: cuda + push: true + tags: ${{ github.ref }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }}