Tutorial: Como criar um container Singularity para executar scripts R com Java e Rclone
Imagem criada pela autora.
Olá pessoal da prensa!! Estou de volta com um tutorial! Sim, hoje vou compartilhar com vocês o que aprendi recentemente e realmente deu bastante trabalho pra mim. Como sempre, eu gosto de compartilhar o que aprendo o quanto antes, pois acredito que outras pessoas possam se beneficiar disto. Não é preciso que todo mundo reinvente a roda não é mesmo?
No tutorial de hoje vou mostrar como instalar o Singularity e em seguida como construir um container Singularity com Ubuntu, Java, R e Rclone. No meu doutorado eu executo muitos experimentos em clusters. Nestes ambientes nós precisamos criar o nosso ambiente de execução para que os experimentos rodem corretamente, portanto temos de replicar o ambiente que temos localmente em nosso computador lá no servidor.
Para quem quiser usar os arquivos que eu já criei, aqui está o link onde vocês poderão baixá-los: https://www.4shared.com/folder/P-0nFM-1/Singularity.html
Não me prenderei muito nas explicações onceituais pois senão este tutorial se tornaria um livro. Este tutorial será bem um passo a passo mesmo, pra te guiar na construção do seu ambiente. O sistema onde fiz os testes foram no Ubuntu ok, portanto, se você usa windows, não tenho certeza se o comportamento será o mesmo. Bora começar então.
Instalando o GO
Antes de qualquer outra coisa, verifique a versão do GO no site oficial e então mude a variável VERSION na string abaixo par ao número correto. A seguir está o código que eu usei no meu computador. Lembrando que você dever abrir o seu terminal para realizar os procedimentos aqui descritos. Você pode copiar o texto abaixo e colar no seu terminal caso a versão do GO ainda seja a mesma. Se for outra versão, copie o texto e edite mudando o número da versão.
===================================================================
export VERSION=1.17 OS=linux ARCH=amd64 && \
wget [https://dl.google.com/go/go$VERSION.$OS-$ARCH.tar.gz](https://dl.google.com/go/go$VERSION.$OS-$ARCH.tar.gz) && \
sudo tar -C /usr/local -xzvf go$VERSION.$OS-$ARCH.tar.gz && \
rm go$VERSION.$OS-$ARCH.tar.gz
===================================================================
Agora copie e cole o código a seguir no seu terminal:
===================================================================
wget -O- <http://neuro.debian.net/lists/xenial.us-ca.full> | tee /etc/apt/sources.list.d/neurodebian.sources.list && \\
apt-key adv --recv-keys --keyserver hkp://pool.sks-keyservers.net:80 0xA5D32F012649A5A9 && \\
apt-get update
===================================================================
Após estes 2 procedimentos é para o GO estar instalado e funcionando. Se você tiver qualquer problema durante o tutorial, por favor, entre em contato. O que você também pode fazer quando copia e cola os textos do tutorial, é copia-los para um editor antes de colar no seu terminal, para eliminar possíveis problemas com codificação de caracters, particularrmente se estiver usando o terminal do windows.
Instalando o Singularity
Novamente, verifique a versão do singularity que você quer instalar. Mude a string abaixo de acordo com esse número de versão. Você pode entrar neste site https://github.com/apptainer/singularity/releases/ para verificar. Use o código a seguir para baixar a versão que você deseja:
===================================================================
wget <https://github.com/apptainer/singularity/releases/download/v3.8.6/singularity-3.8.6.tar.gz>
===================================================================
Agora descompacte o arquivo que foi baixado no comando anterior:
===================================================================
tar -xzvf singularity-3.8.6.tar.gz
===================================================================
Entre na pasta:
===================================================================
cd singularity-3.8.6
===================================================================
Vamos construir o singularity a partir de agora. Siga a ordem dos comandos a seguir. Digite um por vez no terminal, isto é, digite o primeiro, espere, e somente então digite o próximo e assim por diante.
===================================================================
1. ./mconfig
2. cd builddir
3. make
4. sudo make install
5. .etc/bash_completion.d/singularity
6. sudo cp etc/bash_completion.d/singularity /etc/bash_completion.d/
7. singularity --version
===================================================================
Pronto! Com isto o singularity está instaldo e funcionando no seu computador. Vamos para o próximo passo.
Container Base
Para facilitar nossa vida, vamos criar um container base que poderá ser usado para criar outros container depois. Esse container conterá apenas o Ubuntu. Para isto, primeiro criamos um arquivo txt que é chamado de recipe. Você vai salvar este arquito txt com o nome que quer dar ao seu container.
===================================================================
Bootstrap: docker
From: ufscar/ubuntu_ompi:latest
%post
apt-get update
apt-get install -y build-essentials
apt-get install -y rclone
%test
echo $(whoami)
echo " "
===================================================================
Chamarei este arquivo de recipe-base.txt. Ele vai construir um ambiente UBUNTU a partir de uma versão que está disponível na UFSCar e é compatível com o cluster da UFSCar que é acessível apenas aos pesquisadores da UFSCar. Você pode usar uma versão disponível no próprio singularity, para isto consulte este site aqui https://sylabs.io/guides/3.5/user-guide/build_a_container.html
Isso é o que faz a linha FROM: ufscar/ubuntu_ompi:latest. %post é a seção do arquivo de texto onde colocamos tudo o que queremos que seja instaldo no container, e %test é a seção onde podemos realizar testes automáticos assim que a construção do container termina. Portanto, quando terminar as instalações na seção post, o construtor do singularity vai executar a seção test que no nosso caso apenas vai verificar qual é o S.O. que está instalado.
Dentro da seção %post estou mandando instalar o ubuntu da ufscar, o pacote build-essentials para que possamos usar o make, por exemplo, e também o rclone, para que possamos fazer upload/download de arquivos na nuvem.
Você precisa verificar com o administrador do cluster onde vai executar seus experimentos, qual S.O. está disponível e se o cluster tem suporte ao singularity. Caso contrário isto aqui não vai ajudá-lo. Agora vamos construir esse container. Abra um terminal e entre na pasta onde está salvo o arquivo .txt. O comando para criar o container é:
===================================================================
sudo singularity build -F [NOME].simg NOME.txt
===================================================================
O comando que vou digitar para mim é:
===================================================================
sudo singularity build -F base.simg recipe-base.txt
===================================================================
Agora é só esperar terminar. Feito isto, você já terá um ambiente com ubuntu. Se quiser testar, digite:
===================================================================
sudo singularity shell base.simg
===================================================================
Isso vai abrir um terminal e você poderá executar alguns comandos linux no container, como o ls, por exemplo. A partir do shell você tem acesso as pastas do container e pode verificar o que há lá dentro. No entanto para copiar arquivos do seu computador para dentro do container, precisamos usar um recipe também.
Bom, agora que temos um container base, podemos usá-lo para criar novos containers mais específicos. O próximo passo então é instalar o java no container e assim ter uma versão do container com o java. Você também pode conferir o vídeo aqui https://youtu.be/A6spvqaS9bg.
Container Java
Nós vamos seguir o mesmo passo a passo do item anterior, mas agora o receipe vai ser um pouco diferente, observe:
===================================================================
Bootstrap: localimage
From: base.simg
IncludeCmd: yes
%post
echo " "
echo UPDATE
apt-get update
echo " "
echo TIMEZONE
ln -fs /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime
export TZ=America/Sao_Paulo
echo " "
echo INSTALANDO O JAVA
apt install default-jre -y
java -version
echo " "
apt install default-jdk -y
javac -version
===================================================================
As primeira linha do arquivo (Bootstrap: localimage) indica que vamos construir um container com base em uma imagem local, isto é, um container criado por nós. Na segunda linha indicamos o nome dessa localimage que acabamos de construir, no meu caso, base.simg. Na seção %post faço a atualização do sistema e então mando instalar o Java. Também defino a time zone para São Paulo. Salvo esse recipe com o nome de recipe-java.txt. Dai é só criar o container com o seguinte comando:
===================================================================
sudo singularity build -F java.simg recipe-java.txt
===================================================================
Nos meus testes eu não tive nenhum erro, mas caso você obtenha algum erro durante os procedimentos, por favor, me contate. Verifique também o seu arquivo txt pois pode haver problemas de codificação de caracteres, ou algo que você tenha digitado errado sem perceber. Você também pode conferir o vídeo aqui https://youtu.be/eVEG63sGgyY
Container R
Vamos agora criar o container que conterá o ambiente R. Ele será construído com base no container Java pois, no meu caso específico, eu preciso do Java para usar os pacotes do R: rWeka e rJava. Se você não precisa do Java, você pode usar o container base diretamente.
Aqui é importante que você tenha conhecimento de todos os pacotes linux que você precisa ter instalada para que os pacotes R que você for usar funcionem corretamente. Nesta fase podem ocorrer erros, pois alguns pacotes do R poderão dar erro na instalação.
Nesta eu penei bastante, pois obtive vários erros na instalação dos diversos pacotes que uso e não conseguia identificar os erros, nem localizá-los depois. A única solução que encontrei foi ficar olhando, literalmente, a instalação dos pacotes no container e, conforme surgiram os erros, eu segurava a saída do terminal para anotar os pacotes linux que estavam faltando instalar.
Portanto, para você ter menos dor de cabeça, sugiro olhar as dependências de pacotes linux de cada pacote R que você for instalar e já coloca-los na lista de instalação no post antes da instalação dos pacotes R. Mas aviso que nem sempre isso será possível, as vezes ocorrerão outros erros, e outros pacotes podem ser necessários.
Para não demorar muito nesta fase, eu coloquei apenas alguns pacotes do R para instalar. Como vocês podem notar, primeiro colocamos localimagem e qual a imagem. Neste arquivo estou usando o %environment para determinar a versão do R que seja instalada.
Em seguida eu também coloquei uma seção de rótulos, onde coloco minhas informações. Vocês também podem colocar esta seção nos outros recipes. A seção %apprun determina que o container será capaz de executar um script R e o Rscript também. O $@ será substituido pelo seu comando digitado no terminal para o singularity. Exemplo: Rscript /caminho/script.txt argumento1 argumento2 argumento3 ......
Na minha seção %post coloquei todos os possíveis pacotes linux que poderão ser solicitados pelos pacotes R. Depois da linha onde aparece R --version estão os pacotes R que estarão neste ambiente. Observe que eu determinei que as dependencias dos pacotes sejam buscadas e também determinei uma pasta para a biblioteca R dentro do container.
===================================================================
Bootstrap: localimage
From: java.simg
IncludeCmd: yes
%environment
R_VERSION=4.1.1
export R_VERSION
R_CONFIG_DIR=/etc/R/
export R_CONFIG_DIR
export LC_ALL=C
export lib=$lib
%labels
Author Elaine Cecilia Gatto
Version v0.0.1
R_Version 4.1.1
build_date 2022 Fev 24
R_bioconductor True
%apprun R
exec R "$@"
%apprun Rscript
exec Rscript "$@"
%post
echo " "
echo UPDATE
apt-get update
echo " "
echo INSTALL HELPER PACKAGES
apt install -y --no-install-recommends software-properties-common dirmngr
echo " "
echo Add the following key by Michael Rutter to the repository
wget -qO- https://cloud.r-project.org/bin/linux/ubuntu/marutter_pubkey.asc | tee -a /etc/apt/trusted.gpg.d/cran_ubuntu_key.asc
gpg --show-keys /etc/apt/trusted.gpg.d/cran_ubuntu_key.asc
echo " "
echo ADD THE R.4.1.1.REPOSITORY FROM CRAM
add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/'
apt-get install -y wget nano
apt-get install -y libblas3 libblas-dev liblapack-dev liblapack3 curl
apt-get install -y gcc fort77 aptitude
aptitude install -y g++
aptitude install -y xorg-dev
aptitude install -y libreadline-dev
aptitude install -y gfortran
gfortran --version
apt-get install -y libssl-dev libxml2-dev libpcre3-dev liblzma-dev libbz2-dev libcurl4-openssl-dev
apt-get install -y libhdf5-dev hdf5-helpers
apt-get install -y libgmp3-dev
apt-get install -y libsodium-dev
apt-get install -y libudunits2-dev
echo " "
echo DEPENDENCIES
apt install --no-install-recommends r-base r-base-dev -y
R --version
echo " "
echo installing packages from cran
R --version
echo installing packages from cran
R --slave -e 'install.packages("devtools", repos="https://cran.rstudio.com/",
dependencies = TRUE, lib = "/usr/lib/R/library")'
R --slave -e 'install.packages("openssl", repos="https://cran.rstudio.com/",
dependencies = TRUE, lib = "/usr/lib/R/library")'
R --slave -e 'install.packages("mldr", repos="https://cran.rstudio.com/",
dependencies = TRUE, lib = "/usr/lib/R/library")'
R --slave -e 'install.packages("utiml", repos="https://cran.rstudio.com/",
dependencies = TRUE, lib = "/usr/lib/R/library")'
R --slave -e 'install.packages("rJava", repos="https://cran.rstudio.com/",
dependencies = TRUE, lib = "/usr/lib/R/library")'
R --slave -e 'install.packages("RWeka", repos="https://cran.rstudio.com/",
dependencies = TRUE, lib = "/usr/lib/R/library")'
rm -rf /var/lib/apt/lists/*
===================================================================
Agora é só usar o comando:
===================================================================
sudo singularity build -F R.simg recipe-R.txt
===================================================================
Este processo vai demorar um pouco e pode demorar bastante dependendo da quantidade de pacotes linux e R que você for instalar. Aconselho a fazer outras coisas enquanto o container é construído. Segue aqui os vídeos desta parte: https://youtu.be/Q503k473Gf8 e https://youtu.be/s9Pp8pujasM
Copiando seus projetos R para dentro do container criado
Para ser possível executar seus scripts R dentro do container, você precisa copiá-los da sua máquina para dentro do container. Vamos criar mais um recipe, o qual vai apenas copiar os arquivos. Isto é bem útil pois, se você precisar mudar o código, você pode fazê-lo e depois é só colocar a nova versão para dentro do container novamente.
Aqui precisamos ter cuidado com uma coisa, a pasta raíz do seu projeto. No meu caso, sempre deixo meus projetos R na minha home e deixo a pasta raíz dos scritps assim também. Pra facilitar o entendimento, meus projetos estão em /home/elaine e, dentro do script está assim:
===================================================================
FolderRoot = "~/NomeDoProjeto/"
===================================================================
Para que o meu código funcione corretamente dentro do container, eu preciso mudar o ~/ para o diretório onde o código ficará dentro do container, que no caso será apenas /NomeDoProjeto e /NomeDoProjeto. Então, antes de subir os arquivos para dentro do container, eu preciso mudar esse caminho nos scripts R onde eles aparecem, caso contrário o código não funcionará.
Você ainda tem a opção de passar o caminho absoluto do projeto na hora de chamar o seu Rscript do container, e esse caminho pode ser um caminho externo ao container. Vai funcionar também! Exemplificando:
Fora do container:
===================================================================
Rscript /home/elaine/NomeDoProjeto/script_r.R
===================================================================
Dentro do container:
===================================================================
Rscript /NomeDoProjeto/R/script_r.R
===================================================================
Aqui está a receita (recipe):
===================================================================
Bootstrap: localimage
From: R.simg
%post
apt-get update
%files
/home/elaine/NomeDoProjeto/* /NomeDoProjeto
/home/elaine/NomeDoProjeto/* /NomeDoProjeto
%test
echo " "
ls -l /NomeDoProjeto
===================================================================
Na seção %files colocamos o caminho completo das pastas dos projetos que queremos copiar e para onde queremos copiar, a sintaxe é:
===================================================================
/pastaOrigem/* /pastaDestino
===================================================================
Na seção %test vamos apenas listar o que há dentro das pastas copiadas. Com o arquivo pronto, agora criamos o container:
===================================================================
sudo singularity build -F experimentos.simg recipe-copia.txt
===================================================================
Agora é só aguardar! Segue aqui o video: https://youtu.be/wNqyuMqGf7Y
Testando
Para usarmos o container agora precisamos seguir alguns passos. A primeira coisa a se fazer é instancia-lo:
===================================================================
sudo singularity instance start experimentos.simg EXP
===================================================================
Dei o nome de EXP para a instancia do container. No caso do comando acima poderemos usar o container tranquilamente, mas não será possível usar o rclone. O comando correto para quando desejar usar o rclone é:
===================================================================
sudo singularity instance start --bind ~/.config/rclone/:/root/.config/rclone experimentos.simg EXP
===================================================================
Agora sim posso mandar executar o meu script R:
===================================================================
sudo singularity run --app Rscript instance://EXP /Global-Clus/R/global.R 22 10 10 "/dev/shm/res"
===================================================================
Ao terminar a execução você pode parar a execução da instância do container usando:
===================================================================
sudo singularity instance stop EXP
===================================================================
Abstraindo os comandos ficarão da seguinte forma:
===================================================================
sudo singularity instance start [nome].simg [nome-instancia]
sudo singularity instance start --bind ~/.config/rclone/:/root/.config/rclone [nome].simg [nome-instancia]]
sudo singularity run --app Rscript instance://[nome-instancia] [caminhoDoScript/script.R argumentos se houver]
sudo singularity instance stop [nome-instancia]
===================================================================
Ah sim! Estou considerando aqui que você já tem o seu rclone configurado. Caso ainda não use o rclone, ou caso ainda não o tenha configurado, você deve fazê-lo antes de instânciar o container. Aqui tem um passo a passo que você pode seguir https://maisgeek.com/como-usar-rclone-para-fazer-backup-no-google-drive-no-linux/
Se quiser parar todas as instâncias que estiverem executando, basta usar --all no lugar de EXP. Sim, você pode executar várias instâncias ao mesmo tempo. Segue aqui o vídeo https://youtu.be/CD7_xbx3gQU
Finalizando
Com isto terminamos o tutorial! Espero que este lhes tenha sido útil. Caso tenham dúvidas, entrem em contato comigo! Muito Obrigada por ter lido até o final. Lembrem-se de compartilhar este artigo com seus amigos. Até a pŕoxima.
Este artigo foi escrito por Elaine Cecília Gatto - Cissa e publicado originalmente em Prensa.li.