Skip to content

Commit

Permalink
Update Dockerfile and add workflow to register.
Browse files Browse the repository at this point in the history
[ci skip]
  • Loading branch information
maleadt committed Dec 19, 2024
1 parent 830c49b commit 73ed8f9
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 10 deletions.
98 changes: 98 additions & 0 deletions .github/workflows/Container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: Publish Docker image

on:
workflow_dispatch:
inputs:
tag:
description: 'Tag to build instead'
required: false
default: ''
mark_as_latest:
description: 'Mark as latest'
type: boolean
required: false
default: false
push:
tags:
- 'v*'
branches:
- master

jobs:
push_to_registry:
name: Build container - Julia ${{ matrix.julia }} - CUDA ${{ matrix.cuda }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

strategy:
matrix:
julia: ["1.10", "1.11"]
cuda: ["11.8", "12.6"]
include:
- julia: "1.11"
cuda: "12.6"
default: true

steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Check out the package
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref_name }}
path: package

- name: Get package spec
id: pkg
run: |
if [[ -n "${{ inputs.tag }}" ]]; then
echo "ref=${{ inputs.tag }}" >> $GITHUB_OUTPUT
echo "name=${{ inputs.tag }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
echo "ref=${{ github.ref_name }}" >> $GITHUB_OUTPUT
echo "name=${{ github.ref_name }}" >> $GITHUB_OUTPUT
else
echo "ref=${{ github.sha }}" >> $GITHUB_OUTPUT
echo "name=dev" >> $GITHUB_OUTPUT
fi
VERSION=$(grep "^version = " package/Project.toml | cut -d'"' -f2)
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ steps.pkg.outputs.name }}-julia${{ matrix.julia }}-cuda${{ matrix.cuda }}
type=raw,value=latest,enable=${{ matrix.default == true && (github.ref_type == 'tag' || inputs.mark_as_latest) }}
type=raw,value=dev,enable=${{ matrix.default == true && github.ref_type == 'branch' && inputs.tag == '' }}
labels: |
org.opencontainers.image.version=${{ steps.pkg.outputs.version }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
push: true
provenance: false # the build fetches the repo again, so provenance tracking is not useful
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
JULIA_VERSION=${{ matrix.julia }}
CUDA_VERSION=${{ matrix.cuda }}
PACKAGE_SPEC=CUDA#${{ steps.pkg.outputs.ref }}
69 changes: 59 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,59 @@
# example of a Docker container for CUDA.jl with a specific toolkit embedded at run time.
#
# supports selecting a Julia and CUDA toolkit version, as well as baking in specific
# versions of the CUDA.jl package (identified by a spec recorgnized by the Pkg REPL).
#
# CUDA.jl and other packages are shipped in a system depot, with the user depot mounted
# at `/depot`. persistency is possible by mounting a volume at this location.
# running with reduced privileges (by using `--user`) is also supported.

FROM julia:1.8-bullseye
ARG JULIA_VERSION=1
FROM julia:${JULIA_VERSION}

ARG CUDA_VERSION=12.6

ARG PACKAGE_SPEC=CUDA

LABEL org.opencontainers.image.authors "Tim Besard <[email protected]>"
LABEL org.opencontainers.image.description "CUDA.jl container with CUDA ${CUDA_VERSION} installed for Julia ${JULIA_VERSION}"
LABEL org.opencontainers.image.title "CUDA.jl"
LABEL org.opencontainers.image.url "https://juliagpu.org/cuda/"
LABEL org.opencontainers.image.source "https://github.com/JuliaGPU/CUDA.jl"
LABEL org.opencontainers.image.licenses "MIT"


# system-wide packages

# no trailing ':' as to ensure we don't touch anything outside this directory. without it,
# Julia touches the compilecache timestamps in its shipped depot (for some reason; a bug?)
ENV JULIA_DEPOT_PATH=/usr/local/share/julia

RUN julia -e 'using Pkg; Pkg.add("CUDA")'
# pre-install the CUDA toolkit from an artifact. we do this separately from CUDA.jl so that
# this layer can be cached independently. it also avoids double precompilation of CUDA.jl in
# order to call `CUDA.set_runtime_version!`.
RUN julia -e '#= configure the preference =# \
env = "/usr/local/share/julia/environments/v$(VERSION.major).$(VERSION.minor)"; \
mkpath(env); \
write("$env/LocalPreferences.toml", \
"[CUDA_Runtime_jll]\nversion = \"'${CUDA_VERSION}'\""); \
\
#= install the JLL =# \
using Pkg; \
Pkg.add("CUDA_Runtime_jll")' && \
#= demote the JLL to an [extras] dep =# \
find /usr/local/share/julia/environments -name Project.toml -exec sed -i 's/deps/extras/' {} + && \
#= remove nondeterminisms =# \
cd /usr/local/share/julia && \
rm -rf compiled registries scratchspaces logs && \
find -exec touch -h -d "@0" {} + && \
touch -h -d "@0" /usr/local/share

# hard-code a CUDA toolkit version
RUN julia -e 'using CUDA; CUDA.set_runtime_version!(v"12.2")'
# re-importing CUDA.jl below will trigger a download of the relevant artifacts

# generate the device runtime library for all known and supported devices.
# this is to avoid having to do this over and over at run time.
RUN julia -e 'using CUDA; CUDA.precompile_runtime()'
# install CUDA.jl itself
RUN julia -e 'using Pkg; pkg"add '${PACKAGE_SPEC}'"; \
using CUDA; CUDA.precompile_runtime()' && \
#= remove useless stuff =# \
cd /usr/local/share/julia && \
rm -rf registries scratchspaces logs


# user environment
Expand All @@ -25,6 +63,17 @@ RUN julia -e 'using CUDA; CUDA.precompile_runtime()'
# case there might not be a (writable) home directory.

RUN mkdir -m 0777 /depot
ENV JULIA_DEPOT_PATH=/depot:/usr/local/share/julia

# we add the user environment from a start-up script
# so that the user can mount `/depot` for persistency
ENV JULIA_DEPOT_PATH=/usr/local/share/julia:
COPY <<EOF /usr/local/share/julia/config/startup.jl
if !isdir("/depot/environments/v$(VERSION.major).$(VERSION.minor)")
mkpath("/depot/environments")
cp("/usr/local/share/julia/environments/v$(VERSION.major).$(VERSION.minor)",
"/depot/environments/v$(VERSION.major).$(VERSION.minor)")
end
pushfirst!(DEPOT_PATH, "/depot")
EOF

WORKDIR "/workspace"
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ This may take a while, as it will precompile the package and download a suitable
the CUDA toolkit. If your GPU is not fully supported, the above command (or any other
command that initializes the toolkit) will issue a warning.

For quick testing, you can also use [the `juliagpu/cuda.jl` container
image](https://github.com/JuliaGPU/CUDA.jl/pkgs/container/cuda.jl/versions) from the GitHub
Container Registry, which provides Julia, a precompiled version of CUDA.jl, and a matching
CUDA toolkit:

```sh
docker run -it --rm --gpus=all ghcr.io/juliagpu/cuda.jl:latest # other tags available too
```

For more usage instructions and other information, please refer to [the
documentation](https://juliagpu.github.io/CUDA.jl/stable/).

Expand Down

0 comments on commit 73ed8f9

Please sign in to comment.