Rode aplicações gráficas em um Docker Container

 Por Ciro Mota |  7, Maio 2021 |  Tempo de leitura aproximadamente 11 minutos.
 Edições: Pequena correção para seção Silverblue. Em 13, Agosto 2022.

Olá amigos, como vão? Espero que estejam todos bem.

Já comentei aqui em outras oportunidades que virei um fã boy dos containers devido a sua extrema facilidade com que podemos lidar com as aplicações. Eis que em um dos grupos no Telegram em que participo um dos membros levantou uma questão há alguns dias sobre o quanto a abordagem de instalação de algumas aplicações podem ser ruins para um usuário final em uma distro Linux, o que de fato é verdade para algumas situações onde o app não esteja na loja/repositórios das distribuições.

Com isso resolvi fazer alguns testes e verificar sobre a viabilidade de executar aplicações gráficas em containers. E sim, não só é possível como muito prático e acaba eliminando essa complexidade, ou se você precisa da disponibilização dessa mesma aplicação em várias distros, ou quiçá um ambiente de testes.

Vamos lá.

Distrobox

Distrobox

Baseada no projeto Toolbox do Fedora essa é sem dúvida a mais rápida, eficiente e eficaz ferramenta no momento para executar seja qual distro for (desde existam imagens dela disponíveis) em seu PC e com isso as aplicações gráficas contidas nele. Utiliza como motor para isso o Docker ou o Podman, este último preferencialmente de se utilizar devido a sua característica rootless e isso faz muita diferença.

A Distrobox está disponível em uma boa gama de distros em seus repositórios assim como é possível sua instalação manual. O ideal é que você opte pela instalação via repositório por contar com uma aplicação mais estável.

Após instalado nós precisamos apenas executar alguns comandos. No meu caso abaixo decidi executar um Kali Linux em meu Fedora.

distrobox create --image docker.io/kalilinux/kali-rolling:latest --name fedora-kali

Rápida explicada nos comandos…

  • distrobox create = Chama a ferramenta para a criação do container.
  • –image docker.io/kalilinux/kali-rolling:latest = Chama o comando para imagem e as tags da imagem que quer utilizar.
  • –name fedora-kali = Aqui você nomeia o container.

Assim como na execução de um comando Docker ou Podman caso a ferramenta não localize a imagem que precisa localmente, será então feito o download e inicialização.

Comandos iniciais para execução da distro Kali Linux com a Distrobox

A própria ferramenta já nos dá o próximo passo que é acessar a distro no container. No meu caso distrobox enter como comando da ferramenta e fedora-kali o nome do container dado anteriormente:

distrobox enter fedora-kali

Algumas tarefas iniciais serão executadas, ao final voilà teremos um Kali Linux rodando dentro de um Fedora.

Comandos demonstrando se tratar de um Kali Linux com a Distrobox

Seguindo o link indicado nesta tela de prompt vamos então instalar os complementos para que ele funcione com todas as funcionalidades. Para isso basta instalar o metapacote sudo apt install -y kali-linux-default. Depois de baixar a internet inteira nós podemos finalmente executar algumas das aplicações do Kali.

Aplicação rodando dentro de um Kali Linux com a Distrobox

PS: O tema do neofetch é o meu, modificado por mim, no sistema principal. Observem também o Kernel Linux utilizado que é correspondente ao Fedora, distro usada no momento que escrevo/atualizo esse trecho do artigo.

O mesmo se aplicaria para um Debian por exemplo, ou um Arch Linux, bastaria a instalação do metapacote com o ambiente desktop desejado ou a instalação a partir de pacotes chave.

Após a conclusão dos testes basta remover o container em questão.

distrobox rm -f fedora-kali

E por fim após a remoção nenhum arquivo usado no container fica para trás, como tem que ser. Apenas a imagem base utilizada para sua construção.

Demostração de remoção do container e lista de imagens utilizadas com a Distrobox

Consulte a documentação com o link no badge no início desta seção e veja o quanto a Distrobox é flexível e poderá ajudar a depender do seu cenário.

Um método mais manual

Tudo o que é necessário nada mais é do que um único arquivo Dockerfile, algo simples de ser executado e um Shell Script para rodar o container. Mesmo que você ainda não manje de Dockerfile (e é interessante que você saiba como ele funciona) será possível replicar para boa parte das aplicações.

Se você já tem experiência basta transcrever todos os passos que você usaria para o Dockerfile ou para um arquivo de script que poderá também ser utilizado para isso.

No meu exemplo optei por usar o Google Chrome que normalmente não está disponível nos repositórios das distribuições onde sua instalação é através de um arquivo .deb ou rpm fornecido pelo próprio Google.

Crie um arquivo Dockerfile com o seguinte conteúdo:

FROM ubuntu

LABEL maintainer="ciromota"
LABEL version="Developer"

ADD https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb /tmp/google-chrome-stable.deb

RUN apt-get update && \
    apt-get install wget sudo \
    libcanberra-gtk-module -y && \
    apt-get install -f ./tmp/google-chrome-stable.deb -y

RUN export uid=1000 gid=1000 && \
    mkdir -p /home/usearpp && \
    echo "usearpp:x:${uid}:${gid}:usearpp,,,:/home/usearpp:/bin/bash" >> /etc/passwd && \
    echo "usearpp:x:${uid}:" >> /etc/group && \
    echo "usearpp ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/usearpp && \
    chmod 0440 /etc/sudoers.d/usearpp && \
    chown ${uid}:${gid} -R /home/usearpp

USER usearpp

ENV HOME /home/usearpp

CMD /usr/bin/google-chrome

Explicando rapidamente cada linha:

  • Linha 1 = Chama a imagem latest do Ubuntu. Poderia ser Debian também.
  • Linha 2 = TAG de mantenedor da imagem. Altere para seu nome ou empresa.
  • Linha 3 = TAG de versionamento. Altere para o que melhor aplicar para seu cenário.
  • Linha 4 = Adiciona o pacote do Google Chrome à imagem. Ou link direto de download para o app desejado.
  • Linha 5 = Atualiza os repositórios e instala o wget e o sudo, uma biblioteca para o tema GTK que serão essenciais e instala o Google Chrome.
  • Linha 6 = Exporta seu gid e uid, cria uma pasta home para o usuário, “cadastra” este usuário no arquivo passwd e group, libera completamente seu uso para o sudo e define as permissões para sua pasta de usuário.
  • Linha 7 = Nome de usuário.
  • Linha 8 = Definição da variável de ambiente para a pasta home do usuário recém criada acima.
  • Linha 9 = Faz com que a aplicação seja executada a cada nova inicialização do container.

Caso você precise executar um script dentro do container, utilize o conteúdo abaixo dentro do Dockerfile:

COPY script.sh .
RUN chmod +x /script.sh && ./script.sh

Se possível adicione esta linha RUN no mesmo conjunto de linhas do passo acima. Quanto menos etapas, melhor.

E por fim, construiremos o container com o comando abaixo, no meu caso optei por chamar o container de chrome:

docker build -t chrome .

Após a construção do container, basta executá-lo com a seguinte linha:

docker container run -ti --privileged --name chrome -e DISPLAY=$DISPLAY \
-v /etc/localtime:/etc/localtime \
-v /tmp/.X11-unix:/tmp/.X11-unix chrome

Explicando cada parâmetro:

  • docker container run -ti = Executará o container em modo interativo e com acesso ao terminal.
  • –privileged = Desabilita a marcação de segurança do container, requerido para rodar aplicações que necessitem de sandbox lá dentro do container, como o Chrome requer.
  • –name chrome = Defino o nome do container como “chrome”.
  • -e DISPLAY=$DISPLAY = Defino a variável de ambiente Display, que são as funcionalidades de tela.
  • -v /etc/localtime:/etc/localtime = Faz o mapeamento das configurações de horário do Host para o container.
  • -v /tmp/.X11-unix:/tmp/.X11-unix = Mapeia em volume o arquivo “.X11-unix” do host para o container. o Arquivo “.X11-unix” é responsável pelo soquete do Xorg.
  • chrome = A imagem do container que criamos no passo anterior.

Certo, porém sabemos que container são efêmeros, cumprem sua função e são descartáveis afinal, como faremos para executá-lo novamente após sairmos da aplicação? Com o comando abaixo isso é possível:

docker container start -a chrome

Observem que para executar o container pela primeira vez eu defino em --name o nome de chrome, isso serve não serve só para identificação como para facilitar a execução de comandos. É possível criar um novo arquivo de script (o segundo a que me referi acima) e chamar esse arquivo através de um arquivo .desktop, ou seja, a aplicação aparecerá como um atalho do menu de apps da sua distro. Para isso basta este conjunto de linhas abaixo:

#!/usr/bin/env bash

docker container start -a chrome
[Desktop Entry]
Encoding=UTF-8
Name=Chrome
Comment=Rodando Chrome em um Docker Container
Icon=docker.png
Exec=$HOME/aplicação/roda_container_app.sh
Type=Application
Terminal=false
StartupNotify=true

O arquivo .desktop deverá ser salvo no diretório $HOME\.local\share\applications.

E o resultado é isso que podemos ver na imagem abaixo, meu Chrome nativo ao fundo e a janela de execução do Chrome partindo do container.

Google Chrome rodando dentro de um container

Infelizmente neste modo de utilização não é possível incorporar o tema utilizado no sistema para a aplicação do container.

Fedora Silverblue

E já que falamos do Fedora Silverblue logo acima vamos discorrer então um pouco sobre ele. O Fedora Silverblue e seu irmão Kinoite (versão com o KDE Plasma) trabalham com o conceito de sistemas imutáveis e que podem ser uma mão na roda para PCs corporativos. A característica do sistema imutável é que programas não são instalados diretamente no sistema e sim, são adotados o conceito de containers, aqui leia-se, os apps no formato de empacotamento Flatpak e eles trabalharão em um ambiente isolado do core do sistema.

Ahh, mas Ciro, eu tenho uma aplicação, um belo monólito, se o sistema só aceita Flatpaks e uma lista pequena de programas do repositório, como eu poderia usar?
Aqui temos um pulo do gato.

Apesar disso estar previsto na documentação, eu particularmente acho que isso quebraria toda característica do sistema. Mas sim, podemos utilizar de um novo container com algumas poucas restrições para rodar nossas aplicações nele. Grosso modo falando, um outro Fedora dentro de um Fedora (artifício usado pelo Distrobox que comentei logo acima).

Para PCs corporativos isso faz todo o sentido já que somente poucas e principais aplicações seriam usadas, diminuindo os pontos de falha e trazendo uma robustez maior para o sistema operacional. A cada nova atualização de componentes do sistema é criado um novo snapshot, ondemos podemos retornar a qualquer momento em caso de falhas. Podemos também trabalhar no conceito de uma estação de trabalho de desenvolvimento e montar as aplicações essenciais nos containers. Há quem diga que esse é o sistema operacional do futuro.

A exemplo do Distrobox citado logo no início do artigo, a toolbox que é a ferramenta nativa do Fedora Silverblue/Kinoite permite a utilização de muitas outras ferramentas dentro de um mesmo “espaço”. No meu exemplo decidi pegar o Brave Browser que não está nativamente nos repositórios da distro e é preciso adicionar um “PPA” (a denominação PPA existe somente para a base Debian) para download.

toolbox create myapps

O comando é um tanto autoexplicativo, o “myapps” é o nome que você dará para o espaço que você deseja criar e no exemplo específico ele puxará por padrão uma imagem do Fedora comum na sua versão mais recente.

Instalação do toolbox no Fedora Silverblue

Brave Browser rodando no toolbox no Fedora Silverblue

Mas se a aplicação roda em container, não haveria atalhos e isso é ruim para um usuário final.Praticamente tudo é possível no Linux, amigo.

Realmente esse é um ponto negativo, mas você pode criar no host um arquivo de terminação .desktop em $HOME\.local\share\applications e editar a linha Exec para:

toolbox run --container <nome-do-container> brave-browser-stable %u

Mesmo conceito que usamos para o caso do Chrome. O comando chama a função toolbox no modo de execução, com o nome do container e o nome da aplicação.

Ou se você for preguiçoso e perigoso como eu, copia o arquivo firefox.desktop de /usr/share/applications no host, para a pasta $HOME\.local\share\applications e apenas edita apenas o ícone e o caminho de execução para o que eu cito acima, de acordo com o seu caso.

Caso você precise passar uma imagem de um Ubuntu por exemplo, execute o comando:

toolbox create myapps -i docker.io/jmennius/ubuntu-toolbox:22.04

Novamente o comando é autoexplicativo e semelhante ao anterior, o “myapps” é o nome que você dará para o espaço que você deseja criar e é passado o caminho para a imagem de container que será utilizada.

Container Ubuntu rodando no toolbox no Fedora Silverblue

Atenção: Ao contrário da Distrobox, infelizmente você não poderia nesse caso passar qualquer imagem de sistema disponível no Docker Hub. Não há compatibilidade plena entre elas. Neste caso em específico um desenvolvedor publicou as imagens do Ubuntu e você pode acompanhar o andamento delas nessa Issue do próprio projeto Toolbox.

Eu sei, entendo que para algumas pessoas isso poderia sinalizar um problema de segurança devido a não ser uma imagem oficial dos mantenedores. Contudo através deste mesmo link acima, se clicar na guia Commits você verá todo o processo de criação da imagem, ou seja, o Dockerfile que foi utilizado e com isso inspecionar que nada de errado está sendo salvo e disponibilizado ali.

Com isso você terá o seu sistema imutável com aplicações de fora. Conheça a documentação do Silverblue e veja se poderá tirar algum proveito dele no seu dia a dia.

Tudo isso que foi falado acima também poderá ser executado no seu mais novo irmão o Fedora Kinoite (pessoal do KDE tem uma criatividade peculiar pra nomes). Por se tratar da interface KDE Plasma reforço que essa é uma solução que pra mim faria todo sentido o seu aproveitamento em empresas devido a curva de adaptação bem menor de um usuário do Windows. Recomendo conhecer ambas.

Considerações finais

Se você precisa diminuir a complexidade na implantação de uma aplicação, ou a utilização de um ambiente de testes, ou fugir de um saltador de distros, ou quiçá até mesmo rodando uma aplicação do Windows através do Wine sem que seja necessária a sua instalação no sistema ou ter um sistema “inquebrável”, este tipo de abordagem via containers pode ser uma boa pedida.

E você, já tinha pensado em algo parecido ou já implementa esse tipo de implementação em suas instalações? Me deixe saber abaixo nos comentários.

Até a próxima!