Containers
Nesta seção:
Containers são uma forma de empacotar software com todas as suas dependências, criando ambientes isolados e reproduzíveis. No GridUnesp, utilizamos o Apptainer (anteriormente Singularity) para executar containers.
Por que Usar Containers?
Reprodutibilidade: O mesmo ambiente exato pode ser usado por diferentes usuários
Isolamento: Dependências conflitantes não interferem
Portabilidade: O mesmo container funciona em diferentes sistemas
Facilidade: Distribua seu ambiente com um único arquivo
Segurança: Containers Apptainer não exigem privilégios root
Apptainer vs Docker
Apptainer é similar ao Docker, mas projetado para HPC:
Característica |
Docker |
Apptainer |
Permissões |
Requer root |
Usuário normal |
Integração HPC |
Limitada |
Nativa (MPI, GPUs) |
Imagens |
Camadas |
Arquivo único (.sif) |
Segurança |
Menos segura em HPC |
Projetada para ambientes compartilhados |
Conceitos Básicos
Imagem: Arquivo contendo o sistema de arquivos do container (
.sif)Definição: Arquivo de texto com instruções para construir a imagem (
.def)Sandbox: Diretório para desenvolvimento interativo (
apptainer shell image.sif)Registry: Repositório de imagens (Docker Hub, etc.)
Obtendo Imagens
Método 1: Pull do Docker Hub
Job para fazer o download e construir o container (um arquivo com sufixo “.sif”):
#!/bin/bash
#SBATCH -J pull_container
#SBATCH -t 01:00:00
#SBATCH -n 1
export INPUT=""
export OUTPUT="ubuntu.sif"
job-nanny apptainer pull ubuntu.sif docker://ubuntu:20.04
Neste caso, é construído o container ubuntu.sif, o qual é uma imagem do Ubuntu 20.04.
Método 2: Construir a partir de definição
Arquivo de definição (ubuntu.def):
Bootstrap: docker
From: ubuntu:20.04
%post
apt-get update
apt-get install -y python3 python3-pip
pip3 install numpy pandas matplotlib
%environment
export LC_ALL=C
%runscript
echo "Container Ubuntu com Python e pacotes científicos"
python3 "$@"
Script de construção (ubuntu.sif):
#!/bin/bash
#SBATCH -J build_container
#SBATCH -t 02:00:00
#SBATCH -n 1
#SBATCH --mem=4G
export INPUT="ubuntu.def"
export OUTPUT="ubuntu.sif"
job-nanny apptainer build ubuntu.sif ubuntu.def
Executando Containers
Modos de execução:
apptainer run: Executa o comando padrão definido no container
apptainer exec: Executa um comando específico
apptainer shell: Abre um shell interativo
Exemplo básico:
#!/bin/bash
#SBATCH -J run_container
#SBATCH -t 01:00:00
#SBATCH -n 1
export INPUT="ubuntu.sif script.py dados/"
export OUTPUT="resultados/"
job-nanny apptainer exec ubuntu.sif python3 script.py
Exemplo com shell interativo (para testes):
apptainer shell ubuntu.sif
# Dentro do container
ls -la
python3
exit
Compartilhando Arquivos
Por padrão, Apptainer monta automaticamente:
$HOMEdo usuárioDiretório atual de trabalho
Diretórios temporários do sistema
Montagem explícita:
# Montar diretórios adicionais
apptainer exec --bind /caminho/no/host:/caminho/no/container ubuntu.sif comando
No job-nanny:
#!/bin/bash
#SBATCH -J container_dados
#SBATCH -t 02:00:00
#SBATCH -n 1
export INPUT="ubuntu.sif dados/ script.py"
export OUTPUT="resultados/"
# O job-nanny copia INPUT para a área de trabalho
# Dentro do container, os arquivos estarão no diretório atual
job-nanny apptainer exec ubuntu.sif python3 script.py
Containers com GPU
Para usar GPUs, adicione a flag --nv:
Bootstrap: docker
From: nvidia/cuda:11.8.0-runtime-ubuntu20.04
%post
apt-get update
apt-get install -y python3 python3-pip
pip3 install torch torchvision
%runscript
python3 "$@"
Construção:
# Submeter job
#!/bin/bash
#SBATCH -J gpu_container
#SBATCH --partition=gpu
#SBATCH --gres=gpu:1
#SBATCH -t 02:00:00
#SBATCH -n 1
export INPUT="container_gpu.def treinamento.py"
export OUTPUT="modelo.pth"
module load cuda/11.8 # Opcional, Apptainer usa CUDA do container
job-nanny apptainer build --nv cuda_container.sif container_gpu.def
job-nanny apptainer exec --nv cuda_container.sif python3 treinamento.py
Execução:
sbatch job_gpu_container.sh
Containers com MPI
Apptainer pode executar aplicações MPI em múltiplos nós.
Arquivo de definição com MPI:
Bootstrap: docker
From: ubuntu:22.04
%environment
export OMPI_DIR=/opt/ompi
export PATH=$OMPI_DIR/bin:$PATH
export LD_LIBRARY_PATH=$OMPI_DIR/lib:$LD_LIBRARY_PATH
%post
apt-get update
apt-get install -y wget build-essential
# Instalar OpenMPI
export OMPI_DIR=/opt/ompi
export OMPI_VERSION=4.1.5
mkdir -p /tmp/ompi
cd /tmp/ompi
wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-$OMPI_VERSION.tar.bz2
tar -xjf openmpi-$OMPI_VERSION.tar.bz2
cd openmpi-$OMPI_VERSION
./configure --prefix=$OMPI_DIR
make -j4 install
# Instalar compiladores e bibliotecas
apt-get install -y gcc g++ gfortran
%files
mpitest.c /opt/mpitest.c
Código MPI de exemplo (mpitest.c):
#include <mpi.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv) {
MPI_Init(&argc, &argv);
int world_rank, world_size;
char hostname[256];
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
gethostname(hostname, sizeof(hostname));
printf("Processo %d de %d em %s\n", world_rank, world_size, hostname);
MPI_Finalize();
return 0;
}
Scripts para construção, compilação e execução:
#!/bin/bash
#SBATCH -J build_mpi
#SBATCH -t 02:00:00
#SBATCH -n 1
export INPUT="mpi_container.def"
export OUTPUT="mpi_container.sif"
job-nanny apptainer build mpi_container.sif mpi_container.def
#!/bin/bash
#SBATCH -J compile_mpi
#SBATCH -t 00:30:00
#SBATCH -n 1
export INPUT="mpi_container.sif mpitest.c"
export OUTPUT="mpitest"
job-nanny apptainer exec mpi_container.sif mpicc -o mpitest /opt/mpitest.c
#!/bin/bash
#SBATCH -J run_mpi
#SBATCH -N 4
#SBATCH --ntasks-per-node=28
#SBATCH -t 01:00:00
#SBATCH --mem-per-cpu=2G
export INPUT="mpi_container.sif mpitest"
export OUTPUT="mpi_output/"
module load openmpi/4.1.5 # MPI do sistema para orquestração
# --sharens evita conflitos de namespace
job-nanny mpirun -n 112 apptainer exec --sharens mpi_container.sif ./mpitest
Este job irá executar 112 processos, sendo 28 deles em cada nó. O OpenMPI utilizado é aquele já instalado no container (mpi_container.sif) e o executável (mpitest) é processado dentro deste container. O MPI instaldo no container é processado em conjunto com aquele do sistema, carregado via módulo (module load openmpi/4.1.5). Note que a versão do OpenMPI instalada no container, para o exemplo acima, é a 4.1.5, que é a mesma versão do módulo. As versões de ambos os OpenMPI devem ser compatíveis.
Atenção
Segundo a seção Using –sharens mode da página do Apptainer, no intuito de garantir que não haja conflito relacionado a namespace na paralelização, recomenda-se incluir o parâmetro --sharens logo após o comando exec. Assim: apptainer exec --sharens.
Containers para Aplicações Específicas
Exemplo: GROMACS em container
Bootstrap: docker
From: ubuntu:22.04
%post
apt-get update
apt-get install -y wget cmake build-essential
# Instalar GROMACS
wget ftp://ftp.gromacs.org/pub/gromacs/gromacs-2023.tar.gz
tar -xzf gromacs-2023.tar.gz
cd gromacs-2023
mkdir build
cd build
cmake .. -DGMX_BUILD_OWN_FFTW=ON -DCMAKE_INSTALL_PREFIX=/usr/local/gromacs
make -j4
make install
%environment
export PATH=/usr/local/gromacs/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/gromacs/lib:$LD_LIBRARY_PATH
#!/bin/bash
#SBATCH -J build_gromacs
#SBATCH -t 04:00:00
#SBATCH -n 1
export INPUT="gromacs.def"
export OUTPUT="gromacs.sif"
job-nanny apptainer build gromacs.sif gromacs.def
#!/bin/bash
#SBATCH -J gromacs_container
#SBATCH -N 2
#SBATCH --ntasks-per-node=28
#SBATCH -t 24:00:00
export INPUT="gromacs.sif topol.tpr"
export OUTPUT="resultado_gromacs/"
module load openmpi/4.1.5
job-nanny mpirun -n 56 apptainer exec gromacs.sif mdrun_mpi -deffnm resultado
Exemplo: Python com bibliotecas específicas
Bootstrap: docker
From: python:3.9-slim
%post
pip install --upgrade pip
pip install numpy scipy pandas matplotlib scikit-learn jupyter
%runscript
python "$@"
#!/bin/bash
#SBATCH -J build_python_sci
#SBATCH -t 02:00:00
#SBATCH -n 1
export INPUT="python_sci.def"
export OUTPUT="python_sci.sif"
job-nanny apptainer build python_sci.sif python_sci.def
#!/bin/bash
#SBATCH -J python_container
#SBATCH -n 1
#SBATCH -t 02:00:00
export INPUT="python_sci.sif analise.py dados.csv"
export OUTPUT="resultados_analise/"
job-nanny apptainer exec python_sci.sif python analise.py
Boas Práticas com Containers
Imagens leves
Versionamento
Bootstrap: docker From: ubuntu:20.04 # Versão fixa, não "latest"
Reprodutibilidade
Inclua versões exatas dos pacotes
Documente o processo de construção
Segurança
Não coloque senhas ou chaves na imagem
Use variáveis de ambiente para configurações sensíveis
Organização
meus_containers/ ├── ubuntu-python/ │ ├── ubuntu-python.def │ ├── build.slurm │ └── ubuntu-python.sif ├── gromacs/ │ ├── gromacs.def │ └── build.slurm └── mpi-base/ ├── mpi.def └── README.mdLimpeza
Remova caches desnecessários em
/home/$USER/.apptainer/apptainer cache clean
Solução de Problemas
Erro: “no space left on device” durante build
Use a opção
LARGE_FILES="true"dojob-nanny.#!/bin/bash #SBATCH -J build_ubuntu #SBATCH -t 02:00:00 #SBATCH -n 1 export INPUT="ubuntu.def" export OUTPUT="ubuntu.sif" export LARGE_FILES="true" job-nanny apptainer build ubuntu.sif ubuntu.def
Erro: “permission denied”
Verifique permissões do arquivo .sif
Certifique-se de que o container não requer root
Erro: “GPU not available” dentro do container
Use flag
--nvVerifique se CUDA está instalado no container
Erro: “MPI version mismatch”
Use a flag
--sharensCompile MPI no container com mesma versão do sistema (ou versão menor)
Ver também
Instalando Aplicações - Alternativas de instalação
Memória Distribuída - MPI