Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
152742a
docker: add dev-container Dockerfile and scripts
IvanGrigorik Nov 1, 2025
fdd200a
dev-container: finalaize container structure and user prompts
IvanGrigorik Nov 2, 2025
7f7ced7
docker: change port exposure in order to correctly ssh straight into …
IvanGrigorik Nov 3, 2025
931d968
add pykokkos into devcontainer
IvanGrigorik Nov 12, 2025
c883081
change EOF format
IvanGrigorik Nov 12, 2025
97e7a2f
change EOF format
IvanGrigorik Nov 12, 2025
ee4f50a
remove deprecated Dockerfile
IvanGrigorik Dec 18, 2025
2fbfeb8
sync up with `main`
IvanGrigorik Dec 18, 2025
c6903ea
Merge branch 'main' into grigorik/docker-devcontainer
IvanGrigorik Dec 18, 2025
5c66b36
update docker installation
IvanGrigorik Dec 18, 2025
d72ab1b
Merge branch 'main' into grigorik/docker-devcontainer
IvanGrigorik Dec 19, 2025
4d5d04f
merge conflict resolution
IvanGrigorik Dec 19, 2025
1733c7e
add flexible NVIDIA docker container with custom kernel
IvanGrigorik Dec 21, 2025
c679035
Merge branch 'grigorik/docker-devcontainer' of github.com:kokkos/pyko…
IvanGrigorik Dec 21, 2025
90f5153
add template for secrets
IvanGrigorik Dec 21, 2025
32c443e
add default template proper handling
IvanGrigorik Dec 21, 2025
ccb78f5
add pykokkos installation after base install
IvanGrigorik Dec 22, 2025
49bf16c
shellcheck warns fix
IvanGrigorik Dec 23, 2025
0aa1fc7
add workflow to check devcontainer linting errors, shell errors and b…
IvanGrigorik Dec 23, 2025
e52f2d0
fix shellcheck warns
IvanGrigorik Dec 23, 2025
2ea84b3
fix hadolint docker container issues
IvanGrigorik Dec 23, 2025
8f89922
fix shellcheck warns
IvanGrigorik Dec 23, 2025
1c19d31
add wget to install list
IvanGrigorik Dec 23, 2025
9e269c9
address all shellcheck warns
IvanGrigorik Dec 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/array_api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
platform: [ubuntu-latest]
python-version: ["3.13"]
python-version: [3.11, 3.12, 3.13]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
Expand Down
88 changes: 88 additions & 0 deletions .github/workflows/dev-container-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Dev Container CI

on:
push:
branches: [main, develop]
paths:
- "dev-container/**"
- ".github/workflows/dev-container-ci.yml"
pull_request:
branches: [main, develop]
paths:
- "dev-container/**"
- ".github/workflows/dev-container-ci.yml"

jobs:
# Dockerfile linting
dockerfile-lint:
name: Lint Dockerfile
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run hadolint
uses: hadolint/[email protected]
with:
dockerfile: dev-container/Dockerfile
failure-threshold: warning
ignore: DL3002

# Shell scripts check
shellcheck:
name: ShellCheck Scripts
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run ShellCheck on build-container.sh
uses: ludeeus/action-shellcheck@master
with:
scandir: "./dev-container"
severity: warning
ignore_paths: secrets.yaml secrets-template.yaml

- name: Run ShellCheck on scripts directory
uses: ludeeus/action-shellcheck@master
env:
SHELLCHECK_OPTS: -e SC1090
with:
scandir: "./dev-container/scripts"
severity: warning

# Dockerfile building
dockerfile-build-test:
name: Test Dockerfile Build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Create dummy secrets for build test
run: |
mkdir -p dev-container/secrets
echo "testuser" > dev-container/secrets/username
echo "testpass" > dev-container/secrets/password
echo "" > dev-container/secrets/ssh_key

- name: Build Docker image (test only)
uses: docker/build-push-action@v5
with:
context: .
file: ./dev-container/Dockerfile
push: false
tags: pykokkos-dev:test
cache-from: type=gha
cache-to: type=gha,mode=max
secret-files: |
username=dev-container/secrets/username
password=dev-container/secrets/password
ssh_key=dev-container/secrets/ssh_key

- name: Clean up secrets
if: always()
run: rm -rf dev-container/secrets
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,9 @@ tags
# Persistent undo
[._]*.un~

# Docker files and secrets
dev-container/secrets.yaml

# Output files and directories
build/
dev-container/secrets.yaml
35 changes: 0 additions & 35 deletions Dockerfile

This file was deleted.

131 changes: 131 additions & 0 deletions dev-container/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
FROM nvidia/cuda:12.4.1-devel-ubuntu22.04

# Optional ARG for username (only set if secret is provided)
ARG USERNAME=""
ENV username="${USERNAME}"

# Optional ARG for SSH port
ARG PORT="2222"
ENV SSH_PORT="${PORT}"

# Dependencies installation
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
build-essential=12.9ubuntu3 \
micro=2.0.9-1ubuntu0.22.04.3 \
nano=6.2-1ubuntu0.1 \
git=1:2.34.1-1ubuntu1.15 \
openssh-server=1:8.9p1-3ubuntu0.13 \
wget=1.21.2-2ubuntu1.1 \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /var/run/sshd \
&& ssh-keygen -A

# Set shell to bash with pipefail for safer pipe operations
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# Create user using Docker secrets for sensitive data
RUN --mount=type=secret,id=username \
--mount=type=secret,id=password \
--mount=type=secret,id=ssh_key \
if [ -f "/run/secrets/username" ] && [ -s "/run/secrets/username" ] && [ -f "/run/secrets/password" ] && [ -s "/run/secrets/password" ]; then \
export NAME && \
NAME="$(cat /run/secrets/username)" && \
export PASSWORD && \
PASSWORD="$(cat /run/secrets/password)" && \
useradd -m -u 1000 -s /bin/bash "${NAME}" && \
echo "${NAME}:${PASSWORD}" | chpasswd && \
echo "root:${PASSWORD}" | chpasswd && \
usermod -aG sudo "${NAME}" && \
chown -R "${NAME}":"${NAME}" "/home/${NAME}" && \
echo "${NAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
echo "${NAME}" > /tmp/username; \
else \
echo "root" > /tmp/username; \
fi

# Configure SSH permissions for devcontainer (only if custom user was created)
RUN export USERNAME && \
USERNAME="$(cat /tmp/username)" && \
if [ "${USERNAME}" != "root" ]; then \
mkdir -p /var/run/sshd && \
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config && \
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config; \
fi

# Conditionally add SSH public key if provided
RUN --mount=type=secret,id=ssh_key \
export USERNAME && \
USERNAME="$(cat /tmp/username)" && \
if [ -f /run/secrets/ssh_key ] && [ -s /run/secrets/ssh_key ] && [ "${USERNAME}" != "root" ]; then \
export SSH_PUB_KEY && \
SSH_PUB_KEY="$(cat /run/secrets/ssh_key)" && \
mkdir -p "/home/${USERNAME}/.ssh/" && \
echo "${SSH_PUB_KEY}" >> "/home/${USERNAME}/.ssh/authorized_keys" && \
chmod 700 "/home/${USERNAME}/.ssh/" && \
chown -R "${USERNAME}":"${USERNAME}" "/home/${USERNAME}/.ssh/" && \
chmod 600 "/home/${USERNAME}/.ssh/authorized_keys"; \
fi

# Set up custom entrypoint and init scripts
COPY dev-container/scripts/custom-entrypoint.sh /opt/custom-entrypoint.sh
COPY dev-container/scripts/init-pykokkos.sh /opt/init-pykokkos.sh
RUN chmod +x /opt/custom-entrypoint.sh /opt/init-pykokkos.sh

# Set working directory based on USERNAME ARG
# WORKDIR_PATH will be passed as build arg from build script
ARG WORKDIR_PATH="/root"

# Set WORKDIR - use WORKDIR_PATH from build arg
WORKDIR ${WORKDIR_PATH}

# Temporarily switch to user for conda and git operations
USER ${USERNAME:-root}

# Set up and initialize conda environment
# Install conda in the user's home directory
RUN export USERNAME && \
USERNAME="$(cat /tmp/username)" && \
if [ "${USERNAME}" != "root" ]; then \
export HOME_DIR="/home/${USERNAME}" && \
wget -q https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh && \
bash miniconda.sh -b -p "${HOME_DIR}/miniconda3" && \
rm -f miniconda.sh && \
echo "${HOME_DIR}/miniconda3/bin" > /tmp/conda_path; \
else \
export HOME_DIR="/root" && \
wget -q https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh && \
bash miniconda.sh -b -p "${HOME_DIR}/miniconda3" && \
rm -f miniconda.sh && \
echo "${HOME_DIR}/miniconda3/bin" > /tmp/conda_path; \
fi

# Initialize user's conda environment, TOS agreements and ensure it's loaded in every shell
RUN export CONDA_PATH && \
CONDA_PATH="$(cat /tmp/conda_path)" && \
"${CONDA_PATH}"/conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main && \
"${CONDA_PATH}"/conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r && \
"${CONDA_PATH}"/conda init

# Clone pykokkos repository (installation will happen at runtime)
RUN git clone https://github.com/kokkos/pykokkos.git

# Add conda to PATH in .bashrc
RUN export CONDA_PATH && \
CONDA_PATH="$(cat /tmp/conda_path)" && \
export HOME_DIR && \
HOME_DIR="$(dirname "$(dirname "${CONDA_PATH}")")" && \
if [ "${HOME_DIR}" != "/root" ]; then \
echo "export PATH=\"${CONDA_PATH}:${HOME_DIR}/miniconda3/condabin:${HOME_DIR}/.local/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"" >> "${HOME_DIR}/.bashrc" && \
echo "export condaPath=${CONDA_PATH}" >> "${HOME_DIR}/.bashrc"; \
else \
echo "export PATH=\"${CONDA_PATH}:${HOME_DIR}/miniconda3/condabin:${HOME_DIR}/.local/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"" >> "${HOME_DIR}/.bashrc" && \
echo "export condaPath=${CONDA_PATH}" >> "${HOME_DIR}/.bashrc"; \
fi

# Switch back to root for entrypoint execution (required for sshd and init scripts)
USER root

# Expose port in order to be able to connect from IDEs
EXPOSE ${SSH_PORT}

ENTRYPOINT ["/opt/custom-entrypoint.sh"]
Loading