Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ Sessionx.vim
tags
# Persistent undo
[._]*.un~

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

ARG USERNAME
ENV username=${USERNAME}

# Dependencies installation
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential \
micro \
nano \
git \
openssh-server \
&& rm -rf /var/lib/apt/lists/*

# Read secrets and create user with home directory
RUN --mount=type=secret,id=username \
--mount=type=secret,id=password \
--mount=type=secret,id=ssh_key \
export NAME=$(cat /run/secrets/username) && \
export PASSWORD=$(cat /run/secrets/password) && \
export SSH_PUB_KEY=$(cat /run/secrets/ssh_key) && \
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

# Configure SSH permissions for devcontainer
RUN mkdir /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

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

# Set up custom entrypoint
WORKDIR /home/${username}/
COPY dev-container/scripts/custom-entrypoint.sh /opt/custom-entrypoint.sh
RUN chmod +x /opt/custom-entrypoint.sh

# Set up and initialize conda environment
RUN echo "export condaPath=/home/${username}/miniconda3/bin/" >> /tmp/conda_env
ENV condaPath="/home/${username}/miniconda3/bin"
RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh && \
bash miniconda.sh -b -p /home/${username}/miniconda3 && \
rm -f miniconda.sh && \
chown -R ${username}:${username} /home/${username}/miniconda3/

# Initialize user's conda environment, TOS agreements
USER ${username}
WORKDIR /home/${username}/
# Initialize conda in bash and ensure it's loaded in every shell
RUN ${condaPath}/conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main && \
${condaPath}/conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r && \
${condaPath}/conda init

# Clone myself to this container
RUN git clone https://github.com/kokkos/pykokkos.git

# Expose port in order to be able to connect from IDEs
USER root
EXPOSE 2222

# Add ~/.local/bin to PATH (for pip installs etc.)
RUN echo "export PATH=\"/home/${username}/miniconda3/bin:/home/${username}/miniconda3/condabin:/home/${username}/.local/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"" >> /home/${username}/.bashrc

ENTRYPOINT ["/opt/custom-entrypoint.sh"]
62 changes: 62 additions & 0 deletions dev-container/build-container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash

# Get absolute paths for all directories we need
SCRIPT_PATH=$(readlink -f "${BASH_SOURCE[0]}")
CONTAINER_DIR=$(dirname "$SCRIPT_PATH")
SCRIPTS_DIR="${CONTAINER_DIR}/scripts"
PROJECT_ROOT=$(dirname "$CONTAINER_DIR")

pushd "$CONTAINER_DIR" &> /dev/null

# Secrets initialization
bash "${SCRIPTS_DIR}/init.sh"

# Container name initialization
DEFAULT_CONTAINER_NAME="pykokkos-dev-container"
echo "Container name configuration. Press 'Enter' to use default"
read -p "Enter container name [${DEFAULT_CONTAINER_NAME}]: " CONTAINER_NAME
CONTAINER_NAME=${CONTAINER_NAME:-$DEFAULT_CONTAINER_NAME}
USERNAME="$(cat ${CONTAINER_DIR}/secrets/username)"

# Docker container build (add secret to use in `RUN` commands and arg to use in
# Dockerfile commands)
echo "Building docker container: ${CONTAINER_NAME}"

docker build \
--no-cache \
--build-arg USERNAME="${USERNAME}" \
--secret id=username,src="${CONTAINER_DIR}/secrets/username" \
--secret id=password,src="${CONTAINER_DIR}/secrets/pass" \
--secret id=ssh_key,src="${CONTAINER_DIR}/secrets/sha" \
-t "${CONTAINER_NAME}:latest" \
-f "${CONTAINER_DIR}/Dockerfile" \
"${PROJECT_ROOT}"

if [ $? != 0 ]; then
exit
fi
# Stopping same environment, if exists
echo "Stopping ${CONTAINER_NAME}"
docker stop "${CONTAINER_NAME}"

echo "Removing ${CONTAINER_NAME}"
docker rm "${CONTAINER_NAME}"

docker run -dit \
--gpus all \
--name "${CONTAINER_NAME}" \
-p 2222:2222 \
--restart unless-stopped \
"${CONTAINER_NAME}"

function farewell {
echo "##################"
echo "Container started."
echo "To access container from terminal, enter: "
echo "> docker exec -it -u ${USERNAME} ${CONTAINER_NAME} bash"
echo "To access sudo mode, enter 'su' and password, entered/generated above."
}

# Call farewell function at the end
farewell
popd
4 changes: 4 additions & 0 deletions dev-container/scripts/custom-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

/usr/sbin/sshd -D -p 2222 &
/opt/nvidia/nvidia_entrypoint.sh
71 changes: 71 additions & 0 deletions dev-container/scripts/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/bin/bash
# Main initialization script.
# Initializes devcontainer username, password, ssh keys and number of processors, during pykokkos-base installation phase
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
CONTAINER_DIR="$SCRIPT_DIR/../"

NAME_PATH="${CONTAINER_DIR}/secrets/username"
PASS_PATH="${CONTAINER_DIR}/secrets/pass"
SHA_KEY_PATH="${CONTAINER_DIR}/secrets/sha"
PAR_PATH="${CONTAINER_DIR}/secrets/parallel"

# Initialize default values
DEFAULT_USERNAME="pykokkos-dev"
DEFAULT_PASSWORD=$(openssl rand -base64 16 | tr -d "=+/" | cut -c1-16)
DEFAULT_SSH_KEY=""
DEFAULT_PARALLEL_LEVEL=$(nproc)

# Create secrets directory if it doesn't exist
mkdir -p "${CONTAINER_DIR}/secrets"

# Initialize secret files with defaults if they don't exist
if [ ! -f "${NAME_PATH}" ]; then
echo -n "${DEFAULT_USERNAME}" > "${NAME_PATH}"
fi
if [ ! -f "${PASS_PATH}" ]; then
echo -n "${DEFAULT_PASSWORD}" > "${PASS_PATH}"
fi
if [ ! -f "${SHA_KEY_PATH}" ]; then
echo -n "${DEFAULT_SSH_KEY}" > "${SHA_KEY_PATH}"
fi
if [ ! -f "${PAR_PATH}" ]; then
echo -n "${DEFAULT_PARALLEL_LEVEL}" > "${PAR_PATH}"
fi

# Secrets input
echo "Secrets initialization. Press 'Enter' to use [default values]"
read -p "Enter username for dev container [${DEFAULT_USERNAME}]: " dev_name
dev_name=${dev_name:-$DEFAULT_USERNAME}

read -p "Enter password for dev container [randomly generated]: " -s dev_pass
echo
dev_pass=${dev_pass:-$DEFAULT_PASSWORD}

read -p "Enter public SSH key for dev container [none]: " dev_ssh_pubkey
dev_ssh_pubkey=${dev_ssh_pubkey:-$DEFAULT_SSH_KEY}

read -p "Enter cmake parallel level for build [${DEFAULT_PARALLEL_LEVEL}]: " dev_parallel
dev_parallel=${dev_parallel:-$DEFAULT_PARALLEL_LEVEL}

# Put secrets into secret files
echo -n "${dev_name}" > "${NAME_PATH}"
echo -n "${dev_ssh_pubkey}" > "${SHA_KEY_PATH}"
echo -n "${dev_pass}" > "${PASS_PATH}"
echo -n "${dev_parallel}" > "${PAR_PATH}"

# Output default and autogenerated variables, if some variables are not initialized
echo "Username set: ${dev_name}"
if [ "${dev_pass}" = "${DEFAULT_PASSWORD}" ]; then
echo "Password set (randomly generated): ${DEFAULT_PASSWORD}"
else
echo "Password set"
fi
if [ -n "${dev_ssh_pubkey}" ]; then
echo "SSH key set"
else
echo "No SSH key provided"
fi

# Set secure permissions (600) of all secrets
chmod 600 "${NAME_PATH}" "${PASS_PATH}" "${SHA_KEY_PATH}" "${PAR_PATH}" 2>/dev/null || true
echo "Secrets initialization complete"
48 changes: 48 additions & 0 deletions dev-container/scripts/pykokkos-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash



# Show warning about processor usage
echo "WARNING: Using too many processors for building may slow down your system significantly."
echo "Available processors: $(nproc)"

# Determine PARALLEL_LEVEL:
# - prefer environment variable PARALLEL_LEVEL if set and >0 (can be baked-in via Docker ARG/ENV)
# - otherwise fall back to container/host nproc
if [ -n "${PARALLEL_LEVEL:-}" ] && [ "${PARALLEL_LEVEL}" -gt 0 ] 2>/dev/null; then
PARALLEL_LEVEL="${PARALLEL_LEVEL}"
else
read -p "Enter number of processors to use [default: $(nproc)]: " USER_PARALLEL
PARALLEL_LEVEL=${USER_PARALLEL:-$(nproc)}
fi

pushd "/home/${USERNAME}"
# Prefer the Miniconda installed in the user's home; fall back to any `conda` in PATH.
if [ -n $(which conda) ]; then
echo "ERROR: conda not found."
dirs -c
exit 1
fi

# Begin pykokkos-base installation process
git clone https://github.com/kokkos/pykokkos-base.git
pushd pykokkos-base

# Create the conda environment using the resolved conda command
"${CONDA_CMD}" create -y --name pyk --file requirements.txt python=3.11
"${CONDA_CMD}" activate pyk

python setup.py install -- -DENABLE_LAYOUTS=ON -DENABLE_MEMORY_TRAITS=OFF \
-DCMAKE_BUILD_PARALLEL_LEVEL=${PARALLEL_LEVEL} \
-DENABLE_VIEW_RANKS=4 \
-DENABLE_CUDA=ON -DKokkos_ENABLE_CUDA=ON \
-DENABLE_OPENMP=ON -DKokkos_ENABLE_OPENMP=ON \
-DENABLE_THREADS=OFF \
-DCMAKE_CXX_STANDARD=20 \
-DCMAKE_CXX_COMPILER=/usr/bin/c++ -DCMAKE_C_COMPILER=/usr/bin/cc -DCMAKE_POLICY_VERSION_MINIMUM=3.5

popd
dirs -c

# Make hidden file to check that pykokkos is installed now
# touch /home/"${USERNAME}"/.pyk-installed