.. _containers:
==========
Containers
==========
.. contents:: Nesta seção:
:local:
:depth: 2
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?
=========================
1. **Reprodutibilidade:** O mesmo ambiente exato pode ser usado por diferentes usuários
2. **Isolamento:** Dependências conflitantes não interferem
3. **Portabilidade:** O mesmo container funciona em diferentes sistemas
4. **Facilidade:** Distribua seu ambiente com um único arquivo
5. **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”):
.. code-block:: bash
:caption: pull_container.sh
#!/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``):
.. code-block:: text
:caption: 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``):
.. code-block:: bash
:caption: build_container.sh
#!/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:
1. **apptainer run:** Executa o comando padrão definido no container
2. **apptainer exec:** Executa um comando específico
3. **apptainer shell:** Abre um shell interativo
**Exemplo básico:**
.. code-block:: bash
:caption: run_container.sh
#!/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):**
.. code-block:: bash
apptainer shell ubuntu.sif
# Dentro do container
ls -la
python3
exit
Compartilhando Arquivos
=======================
Por padrão, Apptainer monta automaticamente:
- ``$HOME`` do usuário
- Diretório atual de trabalho
- Diretórios temporários do sistema
**Montagem explícita:**
.. code-block:: bash
# Montar diretórios adicionais
apptainer exec --bind /caminho/no/host:/caminho/no/container ubuntu.sif comando
**No job-nanny:**
.. code-block:: bash
:caption: container_com_dados.sh
#!/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``:
.. code-block:: bash
:caption: container_gpu.def
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:
.. code-block:: bash
:caption: job_gpu_container.sh
# 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:
.. code-block:: bash
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:**
.. code-block:: text
:caption: mpi_container.def
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):**
.. code-block:: c
#include
#include
#include
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:**
.. code-block:: bash
:caption: build_mpi_container.sh
#!/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
.. code-block:: bash
:caption: compile_in_container.sh
#!/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
.. code-block:: bash
:caption: run_mpi_container.sh
#!/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.
.. attention::
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
------------------------------
.. code-block:: text
:caption: gromacs.def
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
.. code-block:: bash
:caption: build_gromacs.sh
#!/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
.. code-block:: bash
:caption: run_gromacs.sh
#!/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
--------------------------------------------
.. code-block:: text
:caption: python_sci.def
Bootstrap: docker
From: python:3.9-slim
%post
pip install --upgrade pip
pip install numpy scipy pandas matplotlib scikit-learn jupyter
%runscript
python "$@"
.. code-block:: bash
:caption: build_python_sci.sh
#!/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
.. code-block:: bash
:caption: run_python.sh
#!/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
============================
1. **Imagens leves**
- Use imagens base mínimas (`slim `_, `alpine `_)
- Remova caches desnecessários no %post
.. code-block:: text
%post
apt-get update && apt-get install -y \
git \
python3 \
&& rm -rf /var/lib/apt/lists/*
2. **Versionamento**
.. code-block:: text
Bootstrap: docker
From: ubuntu:20.04 # Versão fixa, não "latest"
3. **Reprodutibilidade**
- Inclua versões exatas dos pacotes
- Documente o processo de construção
4. **Segurança**
- Não coloque senhas ou chaves na imagem
- Use variáveis de ambiente para configurações sensíveis
5. **Organização**
.. code-block:: text
meus_containers/
├── ubuntu-python/
│ ├── ubuntu-python.def
│ ├── build.slurm
│ └── ubuntu-python.sif
├── gromacs/
│ ├── gromacs.def
│ └── build.slurm
└── mpi-base/
├── mpi.def
└── README.md
6. **Limpeza**
- Remova caches desnecessários em ``/home/$USER/.apptainer/``
.. code-block:: text
apptainer cache clean
Solução de Problemas
====================
**Erro: "no space left on device" durante build**
- Use a opção ``LARGE_FILES="true"`` do ``job-nanny``.
.. code-block:: bash
#!/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 ``--nv``
- Verifique se CUDA está instalado no container
**Erro: "MPI version mismatch"**
- Use a flag ``--sharens``
- Compile MPI no container com mesma versão do sistema (ou versão menor)
.. seealso::
- :ref:`usando_job_nanny`
- :ref:`instalando_aplicacoes` - Alternativas de instalação
- :ref:`uso_gpus`
- :ref:`memoria_distribuida` - MPI
- `Documentação do Apptainer `_