Difference between revisions of "Docker"

From VeRLab Wiki
Jump to: navigation, search
m
(Testando Docker Rootless)
 
(60 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Importante: para estas configurações é necessário que a máquina tenha um docker instalado com versão >= 20.10
+
== Docker Rootless Mode ==
  
Configuração inicial
+
O modo disponível do Docker para os usuários da rede é o '''Docker Engine no modo Rootless''', ou seja, apenas a versão em linha de comando e no modo de acesso non-root.
  
# Crie a pasta ~/.config/docker com mkdir -p ~/.config/docker.
+
Em geral, funciona para todas as aplicações e pode-se ler mais informações no [https://docs.docker.com/engine/security/rootless/ link Docker Rootless]
 +
<br><br>
 +
'''Importante''': para estas configurações é necessário que a máquina tenha um docker instalado com versão >= 20.10 (pode ser conferido com: <code>docker version</code>)
  
# Altere a pasta de armazenamento do Docker para a /homeLocal com:
+
Este processo ainda se encontra em uma fase experimental e não está disponível em todas as máquinas. As máquinas disponíveis com docker até o momento são '''PROC1, PROC2, PROC5, PROC6, PROC7, EPONA, NYMERIA, DROGON''', '''EVA, WALL-E, MAGRITTE''' e '''DALEK'''.
 +
<br><br><br>
  
echo '{"data-root":"/homeLocal/user/docker"}' | tee ~/.config/docker/daemon.json.
+
== Modo 1(systemd): Configuração Docker rootless com Systemd (<span style="color: red">não é possível usar simultaneamente em outras máquinas, apenas em uma máquina da rede por vez</span>) ==
  
Importante: Lembre-se de trocar o /user para alguma pasta sua.
+
<br><br>
 +
A opção mais intuitiva para executar o Docker Rootless é gerenciando pelo '''systemctl --user'''. Porém tem a limitação de <span style="color: red;">'''funcionar em apenas uma máquina da rede por vez'''</span>, pois o arquivo que gerencia o systemctl do usuário é salvo na /home que é compartilhada em todas as máquinas, portanto '''apenas um processo docker rootless do usuário pode ser criado, mas em qualquer máquina da rede'''.
  
Esses dois primeiros passos são específicos para as máquinas do VeRLab: por padrão o Docker guarda arquivos na /home do usuário, mas essa pasta é compartilhada por NFS e o Docker não dá suporte a isso.[https://github.com/docker/for-linux/issues/1172 Aqui está um issue citando o problema]
+
=== Pré-requisitos ===
 +
Para utilizar docker rootless em uma máquina no laboratório é preciso que o usuário:  
  
# Execute dockerd-rootless-setuptool.sh install.
+
* solicite à equipe de rede para criar uma pasta de rascunho no disco local como /draft-xxx/nome_do_usuario e dar permissão de leitura/escrita.
Importante: Após terminar, o comando vai pedir que você altere seu .bashrc para adicionar uma linha semelhante a export DOCKER_HOST=unix:///run/user/<uid>/docker.sock (varia por usuário). Faça essa alteração antes de prosseguir.
+
* solicite à equipe de rede a instalação do docker na máquina.
 +
<br><br>
  
# Reinicie o Bash com exec bash.
+
=== Configuração ===
 +
Feito estas etapas, para configurar o acesso na máquina é preciso seguir os seguintes passos para executar o docker rootless:
  
# Ative a inicialização automática do Docker: systemctl --user enable --now docker ou manualmente: systemctl --user start docker
+
# Crie a pasta <code>~/.config/docker</code> com o comando <code>mkdir -p ~/.config/docker</code>.
 +
# Altere a pasta de armazenamento dos arquivos de cache do Docker para a pasta de rascunho /draft-xxx com:
  
Com isso, a configuração está pronta. Confirme que o Docker está funciona com docker run hello-world
+
<code>echo '{"data-root":"/<path-em-disco-local>/<user>/docker-cache"}' | tee ~/.config/docker/daemon.json</code>
 +
<br><br>
 +
'''Importante:''' Lembre-se de ajustar o <code><path-em-disco-local>/<user></code> para uma armazenamento de rascunho na máquina e alguma pasta do seu usuário (por exemplo, <code>/draft-hdd/fulano</code>).
 +
<br><br>
 +
Esses dois primeiros passos são específicos para as máquinas do VeRLab: por padrão o Docker guarda arquivos na /home do usuário, mas essa pasta é compartilhada em rede (por NFS ou MooseFS) e o Docker não dá suporte a isso.[https://github.com/docker/for-linux/issues/1172 Aqui está um issue citando o problema]
 +
 
 +
# Execute <code>dockerd-rootless-setuptool.sh install</code>.
 +
<br><br>
 +
'''Importante''': Após terminar, o comando vai pedir que você altere seu .bashrc para adicionar uma linha semelhante a <code>export DOCKER_HOST=unix:///run/user/<uid>/docker.sock</code> (varia por usuário). Faça essa alteração antes de prosseguir copiando e colando o comando no terminal.
 +
# Reinicie o Bash com <code>exec bash</code>.
 +
# Ative a inicialização automática do Docker em seu usuário: <code>systemctl --user enable --now docker</code> ou manualmente: <code>systemctl --user start docker</code>
 +
 
 +
 
 +
Com isso, a configuração está pronta!
 +
 
 +
=== Utilização ===
 +
Comandos para confirmar se o Docker está funcionando:
 +
* Verificar status do docker daemon:  <code>systemctl --user status docker.service</code>
 +
* Parar docker daemon:  <code>systemctl --user stop docker.service</code>
 +
* Verificar configurações do Docker Rootless: <code>docker version</code>  ou  <code>docker info</code>
 +
* Baixar uma imagem teste e executá-la: <code>docker run hello-world</code>
 +
<br><br><br>
 +
 
 +
== Modo 2 (Manual): Configuração Docker Rootless "Manual" para <span style="color: red;">execução simultânea em várias máquinas da rede<span> ==
 +
 
 +
<br><br>
 +
Essa opção pode parecer menos intuitiva, pois o usuário precisará executar manualmente o '''daemon do docker rootless''' em um terminal e mantê-lo em execução para poder utilizar os comandos docker em outros terminais.
 +
 
 +
Isso pode ser facilmente feito utilizando os [https://www.verlab.dcc.ufmg.br/mediawiki/index.php/Trabalhando_remotamente#Usando_tmux_ou_byobu:_multiplexador_de_terminais  multiplexadores de terminal como tmux ou byobu].
 +
 
 +
Uma vez que parar a execução do docker daemon com ctrl+c ou fechar o terminal, isso vai "matar" a execução do docker rootless na máquina e parar todos seus containers de forma abrupta. Porém tem a flexibilidade de não precisar da pasta /home para armazenar as configurações do daemon, então <span style="color: red;">com essa configuração é possível executar o docker rootless em várias máquinas simultaneamente!<span>
 +
 
 +
=== Pré-requisitos ===
 +
Para utilizar Docker Rootless em uma máquina no laboratório é preciso que o usuário:
 +
 
 +
* solicite à equipe de rede para criar uma pasta de rascunho no disco local como /draft-xxx/nome_do_usuario e dar permissão de leitura/escrita.
 +
* solicite à equipe de rede a instalação do docker na máquina.
 +
 
 +
 
 +
 
 +
=== Configuração ===
 +
 
 +
# Abra seu arquivo <code>~/.bashrc</code> no editor de texto preferido, se for no terminal pode usar o nano: <code>'''nano ~/.bashrc'''</code>
 +
# Cole as seguintes funções no final desse arquivo e salve o mesmo:
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Adicionar funções no .bashrc para facilitar o uso do '''docker-rootless mode'''
 +
|-
 +
 +
<pre>
 +
# Funções para adicionar no final do arquivo ~/.bashrc e usar docker rootless na rede VeRLab/JLab
 +
# v4 mai/2025 by mauferrari
 +
 
 +
# Path para o diretório base a ser utilizado pelo docker rootless do usuário
 +
export USER_DOCKER_BASE_DIR=/draft-hdd
 +
 
 +
# Função para criar pastas e configuração do docker rootless
 +
function docker-rootless-create-dir(){
 +
  MYUSER=$(whoami)
 +
  # Cria environment variables para pastas
 +
  echo -e "Creating Docker Rootless Folder for user $MYUSER..."
 +
  export USER_BASE_DIR=$USER_DOCKER_BASE_DIR/${MYUSER}
 +
  export USER_DOCKER_DIR=$USER_BASE_DIR/docker-rootless
 +
  echo -e "  USER_BASE_DIR=$USER_BASE_DIR\n  USER_DOCKER_DIR=$USER_DOCKER_DIR"
 +
  # Verfica se o diretorio base do usuário existe
 +
  if [ ! -d "$USER_BASE_DIR" ]; then
 +
    echo -e "ERROR!\n  USER_BASE_DIR=$USER_BASE_DIR needs to be created by user '$MYUSER'!"
 +
    unset USER_BASE_DIR
 +
    unset USER_DOCKER_DIR
 +
    return 1
 +
  fi
 +
 
 +
  # Verifica pasta do usuário usada pelo docker rootless
 +
  if [ ! -w "$USER_BASE_DIR" ]; then
 +
    echo -e "ERROR!\n  USER_BASE_DIR=$USER_BASE_DIR needs to be writable by user '$MYUSER'!"
 +
    unset USER_BASE_DIR
 +
    unset USER_DOCKER_DIR
 +
    return 2
 +
  fi
 +
  # Verifica se a pasta do usuário já existe
 +
  if [ -d "$USER_DOCKER_DIR" ]; then
 +
    echo -e "ERROR!\n  USER_DOCKER_DIR=$USER_DOCKER_DIR already exists!"
 +
    echo -e "  Please remove it or use another folder!"
 +
    unset USER_BASE_DIR
 +
    unset USER_DOCKER_DIR
 +
    return 3
 +
  fi
 +
  # Cria pastas usadas pelo docker rootless
 +
  mkdir --parents $USER_DOCKER_DIR
 +
  export XDG_RUNTIME_DIR=$USER_DOCKER_DIR/.docker/run
 +
  export XDG_CONFIG_HOME=$USER_DOCKER_DIR/.config
 +
  mkdir --parents $XDG_RUNTIME_DIR
 +
  mkdir --parents $XDG_CONFIG_HOME/docker
 +
 
 +
  # Cria configuração do docker rootless
 +
  echo "{\"data-root\":\"${USER_DOCKER_DIR}/docker-cache\"}" | tee $XDG_CONFIG_HOME/docker/daemon.json  && \
 +
  nvidia-ctk runtime configure --runtime=docker --config=$XDG_CONFIG_HOME/docker/daemon.json
 +
 
 +
  echo -e "\n\n  HOME=$HOME \n  XDG_CONFIG_HOME=$XDG_CONFIG_HOME \n  XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \n  XDG_DATA_HOME=$XDG_DATA_HOME \n  DOCKER_HOST=$DOCKER_HOST"
 +
  echo -e "\n\ncat $XDG_CONFIG_HOME/docker/daemon.json\n" && cat $XDG_CONFIG_HOME/docker/daemon.json
 +
  echo -e "\n\nDocker Rootless Folders and Config Files Successfully Created!"
 +
}
 +
 
 +
# Função para iniciar manualmente daemon do docker no modo rootless
 +
function docker-rootless-daemon-run(){
 +
  MYUSER=$(whoami)
 +
  echo -e "Exporting Environment Variables for Docker Rootless Daemon..."
 +
  export USER_DOCKER_DIR=$USER_DOCKER_BASE_DIR/${MYUSER}/docker-rootless
 +
 
 +
  echo -e "  USER_DOCKER_DIR=$USER_DOCKER_DIR\n  XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR\n  XDG_CONFIG_HOME=$XDG_CONFIG_HOME"
 +
  # Verifica se o diretório do usuário existe e pode ser escrita pelo docker rootless
 +
  if [ ! -d "$USER_DOCKER_DIR" ] && [ ! -w "$USER_DOCKER_DIR" ]; then
 +
    echo -e "ERROR!\n  USER_DOCKER_DIR=$USER_DOCKER_DIR does not exist or is not writable!"
 +
    echo -e "  Please run docker-rootless-create-dir first!"
 +
    unset USER_DOCKER_DIR
 +
    return 1
 +
  fi
 +
  export XDG_RUNTIME_DIR=$USER_DOCKER_DIR/.docker/run
 +
  export XDG_CONFIG_HOME=$USER_DOCKER_DIR/.config
 +
  # Verifica se o daemon do docker rootless está rodando
 +
  echo -e "Checking Docker Rootless Daemon..."
 +
  if [ -S $XDG_RUNTIME_DIR/docker.sock ]; then
 +
    echo -e "ERROR!\n  Docker Rootless Daemon is already running at $XDG_RUNTIME_DIR!"
 +
    echo -e "  Please stop it first!"
 +
    unset USER_DOCKER_DIR
 +
    unset XDG_RUNTIME_DIR
 +
    unset XDG_CONFIG_HOME
 +
    return 2
 +
  fi
 +
  # Start docker daemon
 +
  echo -e "\n\n  HOME=$HOME \n  XDG_CONFIG_HOME=$XDG_CONFIG_HOME \n  XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \n  XDG_DATA_HOME=$XDG_DATA_HOME \n  DOCKER_HOST=$DOCKER_HOST"
 +
  echo -e "\n\ncat $XDG_CONFIG_HOME/docker/daemon.json\n" && cat $XDG_CONFIG_HOME/docker/daemon.json
 +
  echo -e "Starting Docker Rootless Daemon..."
 +
  dockerd-rootless.sh
 +
}
 +
 
 +
# Função para exportar variáveis de ambiente para executar comandos do docker rootless
 +
function docker-rootless-export(){
 +
  MYUSER=$(whoami)
 +
  echo -e "Exporting Environment Variables for Docker Rootless Daemon..."
 +
  export USER_DOCKER_DIR=$USER_DOCKER_BASE_DIR/${MYUSER}/docker-rootless
 +
  # Verifica se o diretório do usuário existe e pode ser escrita pelo docker rootless
 +
  if [ -d "$USER_DOCKER_DIR" ] && [ -w "$USER_DOCKER_DIR" ]; then
 +
    export DOCKER_HOST=unix://$USER_DOCKER_DIR/.docker/run/docker.sock
 +
    echo -e "  USER_DOCKER_DIR=$USER_DOCKER_DIR\n  DOCKER_HOST=$DOCKER_HOST"
 +
  else
 +
    echo -e "ERROR!\n  USER_DOCKER_DIR=$USER_DOCKER_DIR does not exist or is not writable!"
 +
    echo -e "  Please run docker-rootless-create-dir first!"
 +
    unset USER_DOCKER_DIR
 +
    return 1
 +
  fi
 +
}
 +
</pre>
 +
|}
 +
 
 +
=== Utilização ===
 +
Uma vez que tiver as funções salvas em seu <code>'''~/.bashrc'''</code> elas serão usadas para:
 +
 
 +
{| class="wikitable"
 +
|+ Como usar as funções docker-rootless-*
 +
|-
 +
! Função !! Descrição !! Utilização
 +
|-
 +
|''docker-rootless-create-dir()''<br><br>
 +
|Cria uma pasta para os arquivos do docker rootless daemon em <code>"/draft-hdd/<usuario>/docker-rootless"</code>
 +
|Usada apenas a primeira vez na máquina. Se a pasta já foi criada anteriormente, não precisa mais usar essa função na mesma máquina.
 +
|-
 +
|''docker-rootless-daemon-run()''<br><br>
 +
|Executar o docker rootless daemon no terminal atual no tmux ou byobu
 +
|Usada uma vez, para não haver outro terminal executando o docker rootless daemon na máquina.
 +
|-
 +
|''docker-rootless-export()''<br><br>
 +
|Exportar as variáveis de ambiente com o path correto do docker rootless daemon e do docker.sock (''XDG_RUNTIME_DIR'' e ''DOCKER_HOST'')
 +
|Usada em todo novo terminal que abrir e quiser usar comando docker. Também pode ser colocada no final do ~/.bashrc para valer automaticamente.
 +
|}
 +
 
 +
 
 +
Para utilizar o docker:
 +
 
 +
# Faça ''ssh'' numa das máquinas que tem o docker rootless instalado
 +
# Se a pasta <code>"/draft-hdd/<usuario>/docker-rootless"</code> ainda não foi criada para seu usuário na máquina, execute: <code>'''docker-rootless-create-dir'''</code>
 +
# No terminal abra o multiplexador de terminais, por exemplo, comando: <code>'''tmux'''</code>
 +
# Dentro da '''janela 0''' do tmux, execute o docker rootless daemon: <code>'''docker-rootless-daemon-run'''</code>
 +
# Abra outra janela no tmux: ctrl+b c
 +
# Na '''janela 1''' faça o export do path para executar comandos docker:  <code>'''docker-rootless-export'''</code>
 +
# Na '''janela 1''' execute os comandos docker:  <code>'''docker version ; docker compose version; docker info;'''</code>
 +
# Na '''janela 1''' download e execute uma imagem de teste (13kB):  <code>'''docker run hello-world'''</code>
 +
 
 +
<br><br><br>
 +
 
 +
=== Testando Docker Rootless ===
 +
Considerando que a pasta para seu usuário na máquina já foi criada, ou seja, já existe o caminho <code>"/draft-hdd/<usuario>/docker-rootless"</code>. Caso ainda não exista, execute: <code>'''docker-rootless-create-dir'''</code>
 +
<br><br>
 +
# Faça ''ssh'' numa das máquinas que tem o docker rootless instalado
 +
# No terminal abra o multiplexador de terminais, por exemplo, comando: <code>'''tmux'''</code>
 +
# Dentro da '''janela 0''' do tmux, execute o docker rootless daemon: <code>'''docker-rootless-daemon-run'''</code>
 +
# Abra outra janela no tmux: ctrl+b c
 +
# Na '''janela 1''' faça o export do path para executar comandos docker:  <code>'''docker-rootless-export'''</code>
 +
# Na '''janela 1''' download e execute uma das imagens de teste abaixo: 
 +
<span style="color: red;">Atenção para escolher uma imagem com CUDA compatível com o driver de vídeo Nvidia instalado na máquina!</span><br>Para saber a versão de CUDA toolkit suportada pelo driver Nvidia utilize o comando <code>'''nvidia-smi'''</code>
 +
<br><br>
 +
{| class="wikitable" style="font-weight:bold; font-family:serif !important;"
 +
|- style="font-weight:normal; text-align:center;"
 +
! Comando docker
 +
! image size
 +
|-
 +
| style="background-color:#CCC;" | docker run hello-world
 +
| style="font-weight:normal;" | 13kB
 +
|-
 +
| style="background-color:#CCC;" | docker run --gpus all nvidia/cuda:11.2.2-base-ubuntu20.04 nvidia-smi
 +
| style="font-weight:normal;" | 125MB
 +
|-
 +
| style="background-color:#CCC;" | docker run --gpus all nvidia/cuda:11.6.2-base-ubuntu20.04 nvidia-smi
 +
| style="font-weight:normal;" | 154MB
 +
|-
 +
| style="background-color:#CCC;" | docker run --gpus all nvidia/cuda:12.0.0-base-ubuntu20.04 nvidia-smi
 +
| style="font-weight:normal;" | 240MB
 +
|-
 +
| style="background-color:#CCC;" | docker run --gpus all nvidia/cuda:12.2.2-base-ubuntu20.04 nvidia-smi
 +
| style="font-weight:normal;" | 242MB
 +
|-
 +
| style="background-color:#CCC;" | docker run --gpus all nvidia/cuda:12.2.2-base-ubuntu22.04 nvidia-smi
 +
| style="font-weight:normal;" | 239MB
 +
|}
 +
<br><br><br>
 +
 
 +
== Limpar dados do docker rootless: cache, images e containers ==
 +
 
 +
Para desocupar espaço em disco das máquinas, caso não esteja utilizando o docker, mas deseja manter a estrutura de pastas do docker rootless daemon, pode-se apagar todas as imagens, cache e containers com:
 +
 
 +
<code>'''docker system prune --all'''</code>
 +
 
 +
 
 +
 
 +
Alguns links de referencia:
 +
* https://stackoverflow.com/questions/44785585/how-can-i-delete-all-local-docker-images
 +
* https://contabo.com/blog/how-to-remove-docker-volumes-images-and-containers/?gad_source=1&gclid=CjwKCAjwydSzBhBOEiwAj0XN4JA5Mz8X1bAK-PaXKPz9PyQnJKdahvYG3Z6CBm5ydgRmsNymOFU9FhoC4a0QAvD_BwE
 +
* https://earthly.dev/blog/docker-image-storage-on-host/
 +
* https://docs.docker.com/reference/cli/docker/system/prune/#extended-description
 +
 
 +
 
 +
== Docker abrindo janela no Ubuntu ==
 +
exemplo com ROS<br>
 +
 
 +
 
 +
<pre>
 +
docker run --detach --privileged \
 +
--volume /tmp/.X11-unix:/tmp/.X11-unix \
 +
--volume /home:/home/host \
 +
--device=/dev/bus/usb:/dev/bus/usb \
 +
--volume /dev:/dev \
 +
--runtime=nvidia \
 +
--gpus 'all,"capabilities=utility,display,compute"' \
 +
--env DISPLAY=$DISPLAY \
 +
--network=host \
 +
--name ros_noetic_gps_testing_container \
 +
ros_noetic_gps_testing:latest \
 +
tail -f /dev/null
 +
</pre>
 +
 
 +
 
 +
<pre>
 +
#docker run -it -v "$PWD":/ros2_ws/ -P --device=/dev/ttyACM0 --device=/dev/bus/usb:/dev/bus/usb --name ros2_dev ros2_ws
 +
 
 +
#docker exec -it ros2_dev /bin/bash
 +
 
 +
docker run -it \
 +
--name ros2_work \
 +
--privileged \
 +
--env DISPLAY=$DISPLAY \
 +
--volume /tmp/.X11-unix:/tmp/.X11-unix \
 +
--volume "$PWD":/ros2_ws/ \
 +
--device=/dev/ttyACM0 \
 +
--device=/dev/ttyACM1 \
 +
--device=/dev/bus/usb:/dev/bus/usb \
 +
--gpus 'all,"capabilities=utility,display,compute"' \
 +
--runtime=nvidia \
 +
--network=host \
 +
ros2_dev \
 +
bash
 +
</pre>
 +
 
 +
== Criar regra udev para dispositivo USB ==
 +
Para descobrir o idProduct e idVendor do dispositivo, pode-se usar:
 +
 
 +
<code> udevadm info -a -n /dev/ttyACM0 </code>
 +
 
 +
 
 +
Para criar o arquivo com a regra:
 +
 
 +
<code> sudo nano /etc/udev/rules.d/99-ublox-gps.rules </code>
 +
 
 +
Adicionar essa linha no arquivo e salvar o arquivo:
 +
 
 +
<code>
 +
SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", MODE="0666", GROUP="dialout"
 +
 
 +
</code>
 +
 
 +
Se quiser criar um novo nome (link simbolico /dev/ublox) adicionar SYMLINK:
 +
 
 +
<code>SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", SYMLINK+="ublox", MODE="0666", GROUP="dialout"
 +
</code>
 +
 
 +
 
 +
Desconectar e conectar o dispositivo da USB novamente para acionar a nova regra
 +
 
 +
<br><br><br>
 +
 
 +
== Criar docker com S.O. windows ou macOs com acesso por site web ==
 +
 
 +
* https://github.com/dockur/windows
 +
 
 +
* https://github.com/dockur/macos
 +
 
 +
<br><br>
 +
Exemplo de docker compose com win11, 2 Cores, HD 64GB, RAM 8GB
 +
 
 +
{| class="wikitable"
 +
|-
 +
! <code>compose.yaml</code>
 +
|-
 +
|
 +
<pre>
 +
services:
 +
  windows:
 +
    image: dockurr/windows
 +
    container_name: windows
 +
    environment:
 +
      VERSION: "11"
 +
      DISK_SIZE: "64"
 +
      RAM_SIZE: "8"
 +
      CPU_CORES: "2"
 +
    devices:
 +
      - /dev/kvm
 +
      - /dev/net/tun
 +
    cap_add:
 +
      - NET_ADMIN
 +
    ports:
 +
      - 8006:8006
 +
      - 3389:3389/tcp
 +
      - 3389:3389/udp
 +
    volumes:
 +
      - ./windows:/storage
 +
    restart: always
 +
    stop_grace_period: 2m
 +
</pre>
 +
|}
 +
 
 +
Para acessar a tela do Win11 entre a URL no navegador <code>localhost:8006</code>
 +
<br><br><br>
 +
 
 +
 
 +
== Exemplo de Dockerfile usado no Jetracer ==
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Modelo de Dockerfile usado no Jetracer
 +
|-
 +
 +
<pre>
 +
# Usa a imagem base do Ubuntu 20.04 para arquitetura ARM64 (Jetson Nano)
 +
FROM arm64v8/ubuntu:20.04
 +
 
 +
# Evita prompts interativos durante a instalação de pacotes
 +
ENV DEBIAN_FRONTEND=noninteractive
 +
 
 +
# Atualiza o sistema e instala ferramentas básicas
 +
RUN apt-get update && apt-get install -y \
 +
curl \                # Utilitário para baixar arquivos via HTTP
 +
    gnupg2 \              # Para importar chaves GPG
 +
    lsb-release \        # Para detectar a versão do Ubuntu
 +
    locales \            # Para configurar o sistema com suporte a UTF-8
 +
    sudo \                # Permite uso do comando sudo
 +
    && locale-gen en_US en_US.UTF-8 \            # Gera locale UTF-8
 +
    && update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8  # Atualiza variáveis de locale
 +
 
 +
# Define variáveis de ambiente para o locale em UTF-8
 +
ENV LANG=en_US.UTF-8 \
 +
    LC_ALL=en_US.UTF-8
 +
 
 +
# Adiciona o repositório do ROS oficial e sua chave GPG
 +
RUN curl -sSL "http://packages.ros.org/ros.key" | apt-key add - && \
 +
    echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list
 +
 
 +
# Instala o ROS Noetic (ros-base) e ferramentas auxiliares
 +
RUN apt-get update && apt-get install -y \
 +
    ros-noetic-ros-base \              # ROS básico, sem GUI (leve)
 +
    python3-rosdep \                    # Gerenciador de dependências ROS
 +
    python3-rosinstall \              # Para importar pacotes ROS
 +
    python3-rosinstall-generator \    # Ferramenta para gerar dependências
 +
    python3-wstool \                  # Gerenciador de workspaces
 +
    python3-pip \                      # Gerenciador de pacotes Python
 +
    && rm -rf /var/lib/apt/lists/*    # Remove cache para reduzir tamanho da imagem
 +
 
 +
# Inicializa o rosdep (necessário para instalar dependências de pacotes ROS)
 +
RUN rosdep init && rosdep update
 +
 
 +
# Adiciona o script de configuração do ROS no bashrc do root
 +
RUN echo "source /opt/ros/noetic/setup.bash" >> /root/.bashrc
 +
 
 +
# Define o shell padrão como bash (necessário para scripts do ROS funcionarem corretamente)
 +
SHELL ["/bin/bash", "-c"]
 +
 
 +
# Define uma variável de ambiente com a distro do ROS
 +
ENV ROS_DISTRO=noetic
 +
 
 +
# Cria o diretório do workspace ROS (catkin workspace)
 +
RUN mkdir -p /root/catkin_ws/src
 +
 
 +
# Define o diretório de trabalho padrão para o contêiner
 +
WORKDIR /root/catkin_ws
 +
 
 +
# Comando padrão ao iniciar o contêiner: inicia um terminal bash
 +
CMD ["bash"]
 +
 
 +
</pre>
 +
|}
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Comando para o docker build
 +
|-
 +
 +
<pre>
 +
docker build -t ros-noetic-nano .
 +
</pre>
 +
|}
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Comando de RUN, primeira vez
 +
|-
 +
 +
<pre>
 +
docker run -it --name meu_ros_container \-v ~/jetrace/container:/root/catkin_ws \
 +
  ros-noetic-nano
 +
</pre>
 +
|}
 +
 
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Comando START
 +
|-
 +
 +
<pre>
 +
docker start -ai develop_container
 +
</pre>
 +
|}
 +
 
 +
== Dicas Docker Compose ==
 +
* https://docs.docker.com/compose/gettingstarted/
 +
<br><br><br>

Latest revision as of 14:28, 25 July 2025

Docker Rootless Mode

O modo disponível do Docker para os usuários da rede é o Docker Engine no modo Rootless, ou seja, apenas a versão em linha de comando e no modo de acesso non-root.

Em geral, funciona para todas as aplicações e pode-se ler mais informações no link Docker Rootless

Importante: para estas configurações é necessário que a máquina tenha um docker instalado com versão >= 20.10 (pode ser conferido com: docker version)

Este processo ainda se encontra em uma fase experimental e não está disponível em todas as máquinas. As máquinas disponíveis com docker até o momento são PROC1, PROC2, PROC5, PROC6, PROC7, EPONA, NYMERIA, DROGON, EVA, WALL-E, MAGRITTE e DALEK.


Modo 1(systemd): Configuração Docker rootless com Systemd (não é possível usar simultaneamente em outras máquinas, apenas em uma máquina da rede por vez)



A opção mais intuitiva para executar o Docker Rootless é gerenciando pelo systemctl --user. Porém tem a limitação de funcionar em apenas uma máquina da rede por vez, pois o arquivo que gerencia o systemctl do usuário é salvo na /home que é compartilhada em todas as máquinas, portanto apenas um processo docker rootless do usuário pode ser criado, mas em qualquer máquina da rede.

Pré-requisitos

Para utilizar docker rootless em uma máquina no laboratório é preciso que o usuário:

  • solicite à equipe de rede para criar uma pasta de rascunho no disco local como /draft-xxx/nome_do_usuario e dar permissão de leitura/escrita.
  • solicite à equipe de rede a instalação do docker na máquina.



Configuração

Feito estas etapas, para configurar o acesso na máquina é preciso seguir os seguintes passos para executar o docker rootless:

  1. Crie a pasta ~/.config/docker com o comando mkdir -p ~/.config/docker.
  2. Altere a pasta de armazenamento dos arquivos de cache do Docker para a pasta de rascunho /draft-xxx com:

echo '{"data-root":"/<path-em-disco-local>/<user>/docker-cache"}' | tee ~/.config/docker/daemon.json

Importante: Lembre-se de ajustar o <path-em-disco-local>/<user> para uma armazenamento de rascunho na máquina e alguma pasta do seu usuário (por exemplo, /draft-hdd/fulano).

Esses dois primeiros passos são específicos para as máquinas do VeRLab: por padrão o Docker guarda arquivos na /home do usuário, mas essa pasta é compartilhada em rede (por NFS ou MooseFS) e o Docker não dá suporte a isso.Aqui está um issue citando o problema

  1. Execute dockerd-rootless-setuptool.sh install.



Importante: Após terminar, o comando vai pedir que você altere seu .bashrc para adicionar uma linha semelhante a export DOCKER_HOST=unix:///run/user/<uid>/docker.sock (varia por usuário). Faça essa alteração antes de prosseguir copiando e colando o comando no terminal.

  1. Reinicie o Bash com exec bash.
  2. Ative a inicialização automática do Docker em seu usuário: systemctl --user enable --now docker ou manualmente: systemctl --user start docker


Com isso, a configuração está pronta!

Utilização

Comandos para confirmar se o Docker está funcionando:

  • Verificar status do docker daemon: systemctl --user status docker.service
  • Parar docker daemon: systemctl --user stop docker.service
  • Verificar configurações do Docker Rootless: docker version ou docker info
  • Baixar uma imagem teste e executá-la: docker run hello-world




Modo 2 (Manual): Configuração Docker Rootless "Manual" para execução simultânea em várias máquinas da rede



Essa opção pode parecer menos intuitiva, pois o usuário precisará executar manualmente o daemon do docker rootless em um terminal e mantê-lo em execução para poder utilizar os comandos docker em outros terminais.

Isso pode ser facilmente feito utilizando os multiplexadores de terminal como tmux ou byobu.

Uma vez que parar a execução do docker daemon com ctrl+c ou fechar o terminal, isso vai "matar" a execução do docker rootless na máquina e parar todos seus containers de forma abrupta. Porém tem a flexibilidade de não precisar da pasta /home para armazenar as configurações do daemon, então com essa configuração é possível executar o docker rootless em várias máquinas simultaneamente!

Pré-requisitos

Para utilizar Docker Rootless em uma máquina no laboratório é preciso que o usuário:

  • solicite à equipe de rede para criar uma pasta de rascunho no disco local como /draft-xxx/nome_do_usuario e dar permissão de leitura/escrita.
  • solicite à equipe de rede a instalação do docker na máquina.


Configuração

  1. Abra seu arquivo ~/.bashrc no editor de texto preferido, se for no terminal pode usar o nano: nano ~/.bashrc
  2. Cole as seguintes funções no final desse arquivo e salve o mesmo:
Adicionar funções no .bashrc para facilitar o uso do docker-rootless mode
# Funções para adicionar no final do arquivo ~/.bashrc e usar docker rootless na rede VeRLab/JLab
# v4 mai/2025 by mauferrari

# Path para o diretório base a ser utilizado pelo docker rootless do usuário
export USER_DOCKER_BASE_DIR=/draft-hdd

# Função para criar pastas e configuração do docker rootless
function docker-rootless-create-dir(){
  MYUSER=$(whoami)
  # Cria environment variables para pastas
  echo -e "Creating Docker Rootless Folder for user $MYUSER..."
  export USER_BASE_DIR=$USER_DOCKER_BASE_DIR/${MYUSER}
  export USER_DOCKER_DIR=$USER_BASE_DIR/docker-rootless
  echo -e "  USER_BASE_DIR=$USER_BASE_DIR\n  USER_DOCKER_DIR=$USER_DOCKER_DIR"
  # Verfica se o diretorio base do usuário existe
  if [ ! -d "$USER_BASE_DIR" ]; then
    echo -e "ERROR!\n  USER_BASE_DIR=$USER_BASE_DIR needs to be created by user '$MYUSER'!"
    unset USER_BASE_DIR
    unset USER_DOCKER_DIR
    return 1
  fi

  # Verifica pasta do usuário usada pelo docker rootless
  if [ ! -w "$USER_BASE_DIR" ]; then
    echo -e "ERROR!\n  USER_BASE_DIR=$USER_BASE_DIR needs to be writable by user '$MYUSER'!"
    unset USER_BASE_DIR
    unset USER_DOCKER_DIR
    return 2
  fi
  # Verifica se a pasta do usuário já existe
  if [ -d "$USER_DOCKER_DIR" ]; then
    echo -e "ERROR!\n  USER_DOCKER_DIR=$USER_DOCKER_DIR already exists!"
    echo -e "  Please remove it or use another folder!"
    unset USER_BASE_DIR
    unset USER_DOCKER_DIR
    return 3
  fi
  # Cria pastas usadas pelo docker rootless
  mkdir --parents $USER_DOCKER_DIR
  export XDG_RUNTIME_DIR=$USER_DOCKER_DIR/.docker/run
  export XDG_CONFIG_HOME=$USER_DOCKER_DIR/.config
  mkdir --parents $XDG_RUNTIME_DIR
  mkdir --parents $XDG_CONFIG_HOME/docker

  # Cria configuração do docker rootless
  echo "{\"data-root\":\"${USER_DOCKER_DIR}/docker-cache\"}" | tee $XDG_CONFIG_HOME/docker/daemon.json  && \
  nvidia-ctk runtime configure --runtime=docker --config=$XDG_CONFIG_HOME/docker/daemon.json

  echo -e "\n\n  HOME=$HOME \n  XDG_CONFIG_HOME=$XDG_CONFIG_HOME \n  XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \n  XDG_DATA_HOME=$XDG_DATA_HOME \n  DOCKER_HOST=$DOCKER_HOST"
  echo -e "\n\ncat $XDG_CONFIG_HOME/docker/daemon.json\n" && cat $XDG_CONFIG_HOME/docker/daemon.json
  echo -e "\n\nDocker Rootless Folders and Config Files Successfully Created!"
}

# Função para iniciar manualmente daemon do docker no modo rootless
function docker-rootless-daemon-run(){
  MYUSER=$(whoami)
  echo -e "Exporting Environment Variables for Docker Rootless Daemon..."
  export USER_DOCKER_DIR=$USER_DOCKER_BASE_DIR/${MYUSER}/docker-rootless

  echo -e "  USER_DOCKER_DIR=$USER_DOCKER_DIR\n  XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR\n  XDG_CONFIG_HOME=$XDG_CONFIG_HOME"
  # Verifica se o diretório do usuário existe e pode ser escrita pelo docker rootless
  if [ ! -d "$USER_DOCKER_DIR" ] && [ ! -w "$USER_DOCKER_DIR" ]; then
    echo -e "ERROR!\n  USER_DOCKER_DIR=$USER_DOCKER_DIR does not exist or is not writable!"
    echo -e "  Please run docker-rootless-create-dir first!"
    unset USER_DOCKER_DIR
    return 1
  fi
  export XDG_RUNTIME_DIR=$USER_DOCKER_DIR/.docker/run
  export XDG_CONFIG_HOME=$USER_DOCKER_DIR/.config
  # Verifica se o daemon do docker rootless está rodando
  echo -e "Checking Docker Rootless Daemon..."
  if [ -S $XDG_RUNTIME_DIR/docker.sock ]; then
    echo -e "ERROR!\n  Docker Rootless Daemon is already running at $XDG_RUNTIME_DIR!"
    echo -e "  Please stop it first!"
    unset USER_DOCKER_DIR
    unset XDG_RUNTIME_DIR
    unset XDG_CONFIG_HOME
    return 2
  fi
  # Start docker daemon
  echo -e "\n\n  HOME=$HOME \n  XDG_CONFIG_HOME=$XDG_CONFIG_HOME \n  XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \n  XDG_DATA_HOME=$XDG_DATA_HOME \n  DOCKER_HOST=$DOCKER_HOST"
  echo -e "\n\ncat $XDG_CONFIG_HOME/docker/daemon.json\n" && cat $XDG_CONFIG_HOME/docker/daemon.json
  echo -e "Starting Docker Rootless Daemon..."
  dockerd-rootless.sh
}

# Função para exportar variáveis de ambiente para executar comandos do docker rootless
function docker-rootless-export(){
  MYUSER=$(whoami)
  echo -e "Exporting Environment Variables for Docker Rootless Daemon..."
  export USER_DOCKER_DIR=$USER_DOCKER_BASE_DIR/${MYUSER}/docker-rootless
  # Verifica se o diretório do usuário existe e pode ser escrita pelo docker rootless
  if [ -d "$USER_DOCKER_DIR" ] && [ -w "$USER_DOCKER_DIR" ]; then
    export DOCKER_HOST=unix://$USER_DOCKER_DIR/.docker/run/docker.sock
    echo -e "  USER_DOCKER_DIR=$USER_DOCKER_DIR\n  DOCKER_HOST=$DOCKER_HOST"
  else
    echo -e "ERROR!\n  USER_DOCKER_DIR=$USER_DOCKER_DIR does not exist or is not writable!"
    echo -e "  Please run docker-rootless-create-dir first!"
    unset USER_DOCKER_DIR
    return 1
  fi
}

Utilização

Uma vez que tiver as funções salvas em seu ~/.bashrc elas serão usadas para:

Como usar as funções docker-rootless-*
Função Descrição Utilização
docker-rootless-create-dir()

Cria uma pasta para os arquivos do docker rootless daemon em "/draft-hdd/<usuario>/docker-rootless" Usada apenas a primeira vez na máquina. Se a pasta já foi criada anteriormente, não precisa mais usar essa função na mesma máquina.
docker-rootless-daemon-run()

Executar o docker rootless daemon no terminal atual no tmux ou byobu Usada uma vez, para não haver outro terminal executando o docker rootless daemon na máquina.
docker-rootless-export()

Exportar as variáveis de ambiente com o path correto do docker rootless daemon e do docker.sock (XDG_RUNTIME_DIR e DOCKER_HOST) Usada em todo novo terminal que abrir e quiser usar comando docker. Também pode ser colocada no final do ~/.bashrc para valer automaticamente.


Para utilizar o docker:

  1. Faça ssh numa das máquinas que tem o docker rootless instalado
  2. Se a pasta "/draft-hdd/<usuario>/docker-rootless" ainda não foi criada para seu usuário na máquina, execute: docker-rootless-create-dir
  3. No terminal abra o multiplexador de terminais, por exemplo, comando: tmux
  4. Dentro da janela 0 do tmux, execute o docker rootless daemon: docker-rootless-daemon-run
  5. Abra outra janela no tmux: ctrl+b c
  6. Na janela 1 faça o export do path para executar comandos docker: docker-rootless-export
  7. Na janela 1 execute os comandos docker: docker version ; docker compose version; docker info;
  8. Na janela 1 download e execute uma imagem de teste (13kB): docker run hello-world




Testando Docker Rootless

Considerando que a pasta para seu usuário na máquina já foi criada, ou seja, já existe o caminho "/draft-hdd/<usuario>/docker-rootless". Caso ainda não exista, execute: docker-rootless-create-dir

  1. Faça ssh numa das máquinas que tem o docker rootless instalado
  2. No terminal abra o multiplexador de terminais, por exemplo, comando: tmux
  3. Dentro da janela 0 do tmux, execute o docker rootless daemon: docker-rootless-daemon-run
  4. Abra outra janela no tmux: ctrl+b c
  5. Na janela 1 faça o export do path para executar comandos docker: docker-rootless-export
  6. Na janela 1 download e execute uma das imagens de teste abaixo:

Atenção para escolher uma imagem com CUDA compatível com o driver de vídeo Nvidia instalado na máquina!
Para saber a versão de CUDA toolkit suportada pelo driver Nvidia utilize o comando nvidia-smi

Comando docker image size
docker run hello-world 13kB
docker run --gpus all nvidia/cuda:11.2.2-base-ubuntu20.04 nvidia-smi 125MB
docker run --gpus all nvidia/cuda:11.6.2-base-ubuntu20.04 nvidia-smi 154MB
docker run --gpus all nvidia/cuda:12.0.0-base-ubuntu20.04 nvidia-smi 240MB
docker run --gpus all nvidia/cuda:12.2.2-base-ubuntu20.04 nvidia-smi 242MB
docker run --gpus all nvidia/cuda:12.2.2-base-ubuntu22.04 nvidia-smi 239MB




Limpar dados do docker rootless: cache, images e containers

Para desocupar espaço em disco das máquinas, caso não esteja utilizando o docker, mas deseja manter a estrutura de pastas do docker rootless daemon, pode-se apagar todas as imagens, cache e containers com:

docker system prune --all


Alguns links de referencia:


Docker abrindo janela no Ubuntu

exemplo com ROS


docker run --detach --privileged \ 
--volume /tmp/.X11-unix:/tmp/.X11-unix \ 
--volume /home:/home/host \ 
--device=/dev/bus/usb:/dev/bus/usb \ 
--volume /dev:/dev \ 
--runtime=nvidia \ 
--gpus 'all,"capabilities=utility,display,compute"' \ 
--env DISPLAY=$DISPLAY \ 
--network=host \ 
--name ros_noetic_gps_testing_container \ 
ros_noetic_gps_testing:latest \ 
tail -f /dev/null


#docker run -it -v "$PWD":/ros2_ws/ -P --device=/dev/ttyACM0 --device=/dev/bus/usb:/dev/bus/usb --name ros2_dev ros2_ws

#docker exec -it ros2_dev /bin/bash

docker run -it \
--name ros2_work \
--privileged \
--env DISPLAY=$DISPLAY \
--volume /tmp/.X11-unix:/tmp/.X11-unix \
--volume "$PWD":/ros2_ws/ \
--device=/dev/ttyACM0 \
--device=/dev/ttyACM1 \
--device=/dev/bus/usb:/dev/bus/usb \
--gpus 'all,"capabilities=utility,display,compute"' \
--runtime=nvidia \
--network=host \
ros2_dev \
bash

Criar regra udev para dispositivo USB

Para descobrir o idProduct e idVendor do dispositivo, pode-se usar:

udevadm info -a -n /dev/ttyACM0


Para criar o arquivo com a regra:

sudo nano /etc/udev/rules.d/99-ublox-gps.rules

Adicionar essa linha no arquivo e salvar o arquivo:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", MODE="0666", GROUP="dialout"

Se quiser criar um novo nome (link simbolico /dev/ublox) adicionar SYMLINK:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", SYMLINK+="ublox", MODE="0666", GROUP="dialout"


Desconectar e conectar o dispositivo da USB novamente para acionar a nova regra




Criar docker com S.O. windows ou macOs com acesso por site web



Exemplo de docker compose com win11, 2 Cores, HD 64GB, RAM 8GB

compose.yaml
services:
  windows:
    image: dockurr/windows
    container_name: windows
    environment:
      VERSION: "11"
      DISK_SIZE: "64"
      RAM_SIZE: "8"
      CPU_CORES: "2"
    devices:
      - /dev/kvm
      - /dev/net/tun
    cap_add:
      - NET_ADMIN
    ports:
      - 8006:8006
      - 3389:3389/tcp
      - 3389:3389/udp
    volumes:
      - ./windows:/storage
    restart: always
    stop_grace_period: 2m

Para acessar a tela do Win11 entre a URL no navegador localhost:8006



Exemplo de Dockerfile usado no Jetracer

Modelo de Dockerfile usado no Jetracer
# Usa a imagem base do Ubuntu 20.04 para arquitetura ARM64 (Jetson Nano)
FROM arm64v8/ubuntu:20.04

# Evita prompts interativos durante a instalação de pacotes
ENV DEBIAN_FRONTEND=noninteractive

# Atualiza o sistema e instala ferramentas básicas
RUN apt-get update && apt-get install -y \
		curl \                # Utilitário para baixar arquivos via HTTP
    gnupg2 \              # Para importar chaves GPG
    lsb-release \         # Para detectar a versão do Ubuntu
    locales \             # Para configurar o sistema com suporte a UTF-8
    sudo \                # Permite uso do comando sudo
    && locale-gen en_US en_US.UTF-8 \             # Gera locale UTF-8
    && update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8  # Atualiza variáveis de locale

# Define variáveis de ambiente para o locale em UTF-8
ENV LANG=en_US.UTF-8 \
    LC_ALL=en_US.UTF-8

# Adiciona o repositório do ROS oficial e sua chave GPG
RUN curl -sSL "http://packages.ros.org/ros.key" | apt-key add - && \
    echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list

# Instala o ROS Noetic (ros-base) e ferramentas auxiliares
RUN apt-get update && apt-get install -y \
    ros-noetic-ros-base \               # ROS básico, sem GUI (leve)
    python3-rosdep \                    # Gerenciador de dependências ROS
    python3-rosinstall \               # Para importar pacotes ROS
    python3-rosinstall-generator \     # Ferramenta para gerar dependências
    python3-wstool \                   # Gerenciador de workspaces
    python3-pip \                      # Gerenciador de pacotes Python
    && rm -rf /var/lib/apt/lists/*     # Remove cache para reduzir tamanho da imagem

# Inicializa o rosdep (necessário para instalar dependências de pacotes ROS)
RUN rosdep init && rosdep update

# Adiciona o script de configuração do ROS no bashrc do root
RUN echo "source /opt/ros/noetic/setup.bash" >> /root/.bashrc

# Define o shell padrão como bash (necessário para scripts do ROS funcionarem corretamente)
SHELL ["/bin/bash", "-c"]

# Define uma variável de ambiente com a distro do ROS
ENV ROS_DISTRO=noetic

# Cria o diretório do workspace ROS (catkin workspace)
RUN mkdir -p /root/catkin_ws/src

# Define o diretório de trabalho padrão para o contêiner
WORKDIR /root/catkin_ws

# Comando padrão ao iniciar o contêiner: inicia um terminal bash
CMD ["bash"]

Comando para o docker build
docker build -t ros-noetic-nano .
Comando de RUN, primeira vez
docker run -it --name meu_ros_container \-v ~/jetrace/container:/root/catkin_ws \
  ros-noetic-nano


Comando START
docker start -ai develop_container

Dicas Docker Compose