Charliecloud
Charliecloud is a lightweight container system developed by Los Alamos National Laboratory that provides user-defined software stacks (UDSS) for high-performance computing (HPC). Unlike Docker or Singularity, Charliecloud uses Linux user namespaces to run completely unprivileged containers with no setuid binaries or daemons required.
Key Features
- Unprivileged execution - No root or privileged operations needed
- HPC-native - Designed specifically for HPC environments with Slurm integration
- Docker-compatible - Can build and run Docker container images
- Minimal overhead - Fast startup with near bare-metal performance
- Flexible storage - Supports directory-format and SquashFS images
Available Modules
Charliecloud is available on Midway3 via the Spack module system. First, load the Spack modules:
module load spack.modules
Then check available Charliecloud versions:
module avail charliecloud
Available versions include:
- charliecloud/0.35-gcc-12.2.0-6ifrorq (built with GCC)
- charliecloud/0.35-aocc-4.1.0-65aqmle (built with AMD AOCC)
Load the recommended GCC version:
module load charliecloud/0.35-gcc-12.2.0-6ifrorq
This will also load required dependencies: Python 3.11, Git, and py-requests.
Core Commands
Charliecloud provides several key commands:
| Command | Purpose |
|---|---|
ch-image |
Build, pull, and manage container images |
ch-run |
Execute commands inside a container |
ch-convert |
Convert between image formats (e.g., Docker to SquashFS) |
ch-checkns |
Verify user namespace support |
ch-fromhost |
Inject host files into a container |
ch-test |
Test container functionality |
Basic Usage
Pulling a Docker Image
Pull an image from Docker Hub:
ch-image pull ubuntu:22.04
This will download and cache the image in /var/tmp/$USER.ch/img/. Note that image names in the storage directory use + instead of : (e.g., ubuntu+22.04).
Running a Container
Execute a command inside a container:
ch-run ubuntu:22.04 -- uname -a
The basic syntax is:
ch-run <image> -- <command> [args...]
Note
Images can be referenced by name (e.g., ubuntu:22.04) which resolves from ch-image storage, or by absolute path to a directory or SquashFS file. Running by name is the recommended approach.
Binding Directories
Mount host directories into the container using the -b flag:
ch-run -b $PWD:/mnt/0 ubuntu:22.04 -- python3 /mnt/0/script.py
Multiple bind mounts are supported:
ch-run -b /path/to/input:/mnt/1 \
-b /path/to/output:/mnt/2 \
ubuntu:22.04 -- /run/my_pipeline.sh
Warning
The bind mount destination must already exist inside the container image. Most images provide pre-created mount points at /mnt/0 through /mnt/9. If you need a custom destination like /data, either use --write-fake (-W) to enable automatic directory creation, or add RUN mkdir -p /data to your Dockerfile when building custom images.
Example Job Script
Here is a complete SLURM job script example for running a containerized application on Midway3:
#!/bin/bash
#SBATCH --job-name=charliecloud-test
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=4
#SBATCH --time=01:00:00
#SBATCH --partition=caslake
#SBATCH --account=pi-<group>
# Load Charliecloud module
module load spack.modules
module load charliecloud/0.35-gcc-12.2.0-6ifrorq
# Define paths
IMAGE=ubuntu:22.04
INPUT_DIR=/project/$USER/my_data
OUTPUT_DIR=/scratch/$USER/results
# Create output directory if it doesn't exist
mkdir -p $OUTPUT_DIR
# Run the containerized application
ch-run -b $INPUT_DIR:/mnt/0:ro \
-b $OUTPUT_DIR:/mnt/1 \
$IMAGE -- python3 /process_data.py --input /mnt/0 --output /mnt/1
Building Custom Images
You can build custom images using a Dockerfile. Charliecloud supports Dockerfile syntax:
FROM ubuntu:22.04
# Install dependencies
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
&& apt-get clean
# Install Python packages
RUN pip3 install numpy scipy matplotlib
# Set working directory
WORKDIR /workspace
# Copy your application
COPY . /workspace/
# Run your application
CMD ["python3", "my_app.py"]
Build the image:
ch-image build -t myapp:latest .
Converting Images to SquashFS
For better performance, especially on network filesystems, convert images to SquashFS format:
# First, pull the image into ch-image storage
ch-image pull ubuntu:22.04
# Then convert to SquashFS
ch-convert ubuntu:22.04 ubuntu.sqfs
SquashFS images: - Are single files that encapsulate the entire filesystem - Have better metadata performance (important for Lustre) - Are recommended for production use on HPC systems
MPI Workloads
Charliecloud supports MPI applications, but requires careful configuration. Key considerations:
MPI Launch Methods
- Host MPI (Recommended): Use the host system's MPI installation
- Guest MPI: MPI is installed inside the container
Multi-node MPI Example
#!/bin/bash
#SBATCH --job-name=charliecloud-mpi
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --time=02:00:00
#SBATCH --partition=caslake
module load spack.modules
module load charliecloud/0.35-gcc-12.2.0-6ifrorq
module load openmpi
# Use host MPI with containerized application
srun ch-run --join myapp:latest -- /app/mpi_hello_world
The --join flag is critical for MPI - it places all ranks in the same container instance to enable shared memory communication.
Warning
MPI with containers requires careful configuration. See the official Charliecloud best practices for detailed guidance on MPI, PMI, and fabric selection.
Storage and Performance
Image Storage Location
By default, Charliecloud stores images in:
/var/tmp/$USER.ch/img/— pulled and built images (directory format)/var/tmp/$USER.ch/— build cache, download cache, and metadata
You can change the storage location using the CH_IMAGE_STORAGE environment variable or the -s flag:
# Option 1: Set environment variable (recommended)
export CH_IMAGE_STORAGE=$HOME/.charliecloud
# Option 2: Use -s flag per command
ch-image -s $HOME/.charliecloud pull ubuntu:22.04
ch-run -s $HOME/.charliecloud ubuntu:22.04 -- uname -a
Note
If setting CH_IMAGE_STORAGE, ensure the parent directory exists but let Charliecloud create the final directory. For example, set CH_IMAGE_STORAGE=$HOME/.charliecloud only if $HOME exists — do not pre-create the .charliecloud directory.
Temporary Directory
For large builds, you may need to redirect temporary files:
export TMPDIR=$SCRATCH/$USER/tmp
mkdir -p $TMPDIR
Note
On Midway3, $SCRATCH is set to /scratch/midway3, so it is essential to include $USER in the path to ensure your files are stored in your personal scratch directory.
Moving Charliecloud Cache to Scratch
To move the Charliecloud cache location to a scratch location, set the CH_IMAGE_STORAGE environment variable:
export CH_IMAGE_STORAGE=$SCRATCH/$USER/charliecloud
Add this to your ~/.bashrc or SLURM job scripts for persistence. Alternatively, use the mvln command from the utilities module to symlink the default storage:
module load utilities
mvln /var/tmp/$USER.ch $SCRATCH/$USER
Best Practices
- Use SquashFS images for better performance on shared filesystems
- Bind mount strategically - mount only the directories you need; use existing mount points (
/mnt/0–/mnt/9) or pre-create destinations in your Dockerfile - Keep images small - use multi-stage builds and clean package caches
- Use
--joinfor MPI - required for multi-rank MPI jobs on the same node - Prefer host MPI over guest MPI for better compatibility with cluster interconnects
- Test locally first - verify your container works on login nodes before submitting jobs
Comparison with Singularity
| Feature | Charliecloud | Singularity/Apptainer |
|---|---|---|
| Privilege required | Unprivileged | Setuid helper required |
| Image formats | Directory, SquashFS, Docker | SIF, Docker |
| Startup speed | Very fast | Moderate |
| Slurm integration | Native | Native |
| Complexity | Simpler | More features |