rodando-aplicacoes-gui-em-docker.pt-br.md 11.6 KB
Newer Older
1 2 3
+++
title = "Rodando aplicações GUI em Docker"
date = "2016-11-12T10:24:00Z"
4
aliases = [ "/post/rodando-aplicacoes-gui-em-docker/" ]
5 6 7 8 9 10 11 12 13 14 15 16 17
categories = [ "Docker" ]
tags = [ "Docker", "X11" ]
author = "somatorio"
+++
Já roda serviços usando containers em [Docker](https://docker.com/)?  
Que tal rodar também as suas aplicações GUI com ele? Isso mesmo, estou falando de rodar seu browser, editor de texto, jogos, enfim...

## Porque? X11 em Docker parece ser complicado
Isso é bem simples (ou ao menos mais do que se imagina) e te dá um controle absurdo sobre a aplicação... Não quer que o aplicativo acesse a rede/internet por algum motivo? Só usar a flag `--net null`. De repente rodar em uma rede isolada? `--net nomedarede` (Neste caso precisa criar a rede Docker antes). Quer limitar a quantidade de ram que ela vai usar? `--memory mem` (exemplo: `--memory 1gb`). Quer definir que cores do processador vão rodar a aplicação? `--cpuset-cpus cpus` (ex: `--cpuset-cpus 0,3` ou `--cpuset-cpus 0-3`). Enfim... Sinta-se livre para usar a imaginação. :)  
(sim, eu sei que é possível fazer esse tipo de coisa no linux... mas não é tão fácil quanto colocar uma flag em um comando)

Outra vantagem é que assim instalações de um programa acabam sendo simplesmente "mandar abrir o programa", quando você roda um "`docker run [...] nomedaimagem`" o Docker engine verifica se essa imagem está disponível no repositório local, e em caso negativo, baixa a mesma e então roda.

18
Isso sem falar de que a aplicação já fica com as suas dependencias no container, ou seja, nada de "sujeira" ficando pra trás na forma de pacotes órfãos (e arquivos de configuração) quando a aplicação for removida por algum motivo ;)
19 20 21 22 23 24 25 26 27 28

Essa experiência além de divertida, proporciona uma imersão total no funcionamento do Docker, simplesmente não há como usar as suas ferramentas diariamente sem acabar precisando usar vários recursos diferentes proporcionados pelo Docker.

## Ah tá que é tudo fácil, simples e a vida vira um arco-íris... Fala a real aí
Ok, ok... Nem tudo são flores, principalmente quando chega no ponto em que não há uma imagem pronta pro aplicativo que tu queres...

Nem sempre as dependencias listadas pelos desenvolvedores são as únicas dependencias... O que é aceitável se pensar bem, porque são dependencias que geralmente já estão instaladas nos computadores, mas no caso de containers acaba não sendo bem assim. Isso acaba sendo bem frustrante às vezes, há outros momentos que podem te frustrar um pouco, mas este é o principal pra mim (porém quando se consegue descobrir o que era o problema, é indescritível a sensação :p)

### Ok, então se eu só rodar aplicações que já tem imagem, não vou ter problema algum?
Bem, como eu disse antes, os problemas são **principalmente** quando se monta uma imagem, não os únicos...  
29
Algumas integrações com outros softwares são bem difíceis (na verdade até agora eu não consegui resolver nenhum desses casos, mas como "nada é impossível"...), por exemplo: alguns softwares permitem que se clique em um link e o navegador padrão abre
30 31 32 33 34 35 36 37 38 39 40
com a página do link, mas quando se tem um container de digamos "Telegram-desktop", não há um navegador instalado na máquina (na maioria das vezes nem o software que faz essa verificação sobre qual é o navegador padrão e que chama ele).

Nada é "bala de prata" e é quase certo que alguns problemas irão acontecer... E às vezes vai ficar uma verdadeira "pulga atrás da orelha" em relação ao problema ser exatamente por ser em um container (ao menos no meu caso nunca era, mas sempre vinha a dúvida).

## Não gosto muito de pular de cara em novidades...
Bem, depende do que tu considera como novidade, hehe...  
O próprio Docker não é exatamente velho (na verdade é bem novo até... 3 aninhos), mas muita gente já usa inclusive em produção (e diz que há alguns desafios, mas que vale o esforço) e... (rufem os tambores)  
...isso que eu estou falando começou praticamente junto com o lançamento público do Docker :)

### Sério?
Sim! Aqui vai a *timeline* que eu consegui levantar:
41

42 43 44 45 46 47 48
*   Março 2013: [Docker 0.1 liberado para o público](https://www.infoq.com/news/2013/03/Docker)
*   Abril 2013: [Primeira implementação conhecida de X11 em Docker (utilizando vnc)](http://stackoverflow.com/questions/16296753/can-you-run-gui-apps-in-a-docker-container)
*   Julho 2013: [Implementação de X11 em Docker utilizando ssh com X11-forward](https://blog.docker.com/2013/07/docker-desktop-your-desktop-over-ssh-running-inside-of-a-docker-container/)
*   Setembro 2014: [Implementação utilizando o socket X11 do host](http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/)
*   Fevereiro 2015: [Jessica Frazelle faz um post em seu blog sobre  container em desktop](https://blog.jessfraz.com/post/docker-containers-on-the-desktop/)
*   Abril 2015: [Jessica Frazelle faz uma palestra durante a Container Camp 2015 mostrando que roda tudo no seu computador em containers](https://www.youtube.com/watch?v=GsLZz8cZCzc)

49 50 51 52 53 54 55 56 57 58
Porque os últimos itens foram incluidos? Bem, basicamente porque sempre que se fala sobre GUI em Docker, ou a pessoa fala sobre a Jess ou lembra dela (há outros vídeos dela falando sobre isso, mas achei melhor incluir só o primeiro)  
Como pode ver, apenas 1 mês depois do lançamento público do Docker já haviam pessoas querendo rodar aplicações GUI no Docker :)

## Certo, me convenceu... Conta mais aí, como funciona? Quão simples (ou complicado) vai ser pra mim?
Funciona basicamente assim, é montado um volume do arquivo de socket do X11 da tua máquina (/tmp/.X11-unix) no mesmo caminho no container e é definida a variável de ambiente `DISPLAY` do container como o display do servidor X do teu host, assim quando o aplicativo dentro do container enviar as instruções de como renderizar ele no ambiente gráfico, estará enviando elas para o X do host.

### É... meio que parece complicado isso aí, hein?
Relaxa que eu só estava explicando a teoria por trás da coisa, na prática vamos colocar duas flags: `-e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix` e a "mágica" está feita :)

## Ok, vamos aos comandos?
59
Antes de mais nada... Em 99% dos casos é preciso liberar ,o acesso ao X: `xhost local` (essa liberação ficará vigente até desligar/reiniciar o host)
60 61 62 63 64 65 66 67 68

Comando mais simples o possível, monta o socket X11 do host no container e define o display (note que vamos "evoluindo" o comando aos poucos, mas pode usar apenas as flags que achar necessário):
```
docker run [--rm [-it]|-d] \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY \
imagem [comando]
```
Em alguns casos a variável `DISPLAY` tem de ser `DISPLAY=unix$DISPLAY` (mas pra ser sincero até agora eu não sei bem o motivo, somente que era o indicado pela pessoa que fez a imagem)  
69
*Obs: "`[--rm [-it]|-d]`" quer dizer "Opcionalmente pode usar o `--rm` que pode ou não estar em conjunto com `-it` OU pode (ou não :p) usar o `-d`"*
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143


Com suporte a aceleração 3D por hardware:
```
docker run [--rm [-it]|-d] \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY \
--device /dev/dri \
imagem [comando]
```

Adicionando audio:
```
docker run [--rm [-it]|-d] \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY \
--device /dev/dri \
--device /dev/snd \
imagem [comando]
```

Adicionando webcam:
```
docker run [--rm [-it]|-d] \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY \
--device /dev/dri \
--device /dev/snd \
--device /dev/video0 \
imagem [comando]
```

Usando a mesma data/hora do host:
```
docker run [--rm [-it]|-d] \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY \
--device /dev/dri \
--device /dev/snd \
--device /dev/video0 \
-v /etc/localtime:/etc/localtime:ro \
imagem [comando]
```
Atenção: dependendo da distribuição, não há um /etc/localtime, tem de averiguar como ela define o timezone e "replicar" no container.

Mantendo as configurações do aplicativo:
```
docker run [--rm [-it]|-d] \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY \
--device /dev/dri \
--device /dev/snd \
--device /dev/video0 \
-v /etc/localtime:/etc/localtime:ro \
-v $HOME/.config/app:/root/.config/app \
imagem [comando]
```
Obs: o caminho é apenas um exemplo :p

**Bônus:** Controle do video-game :) (na real qualquer dispositivo de entrada)
```
docker run [--rm [-it]|-d] \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY \
--device /dev/dri \
--device /dev/snd \
--device /dev/video0 \
-v /etc/localtime:/etc/localtime:ro \
-v $HOME/.config/app:/root/.config/app \
--device /dev/input \
imagem [comando]
```

## Certo, acho que consigo começar por aí... Alguma dica pra me dar?
144 145 146
*   Organize as flags em ordem alfabética (facilita bastante em *troubleshootings*) - *sim, eu sei que nos exemplos eu não fiz isso, mas foi mais para facilitar o reconhecimento da flag adicionada*
*   Crie um script com os comandos que rodam os containers separados em funções, assim se pode incluir o script ao perfil do bash e rodar como se fosse um comando (além de facilitar o uso de launchers) - *mais abaixo vou colocar um link para o script que eu uso*
*   Utilize o detach (--detach ou -d) e uma função para apagar o container que esteja parado ao executar a função do aplicativo desejado novamente - *isso também estará no meu script ;)*
147 148 149

## Beleza! Mais alguma coisa? Algum outro lugar que eu possa ler sobre o assunto?
Bem, claro que tem outros lugares pra ler :)  
150
MAS antes aqui vai um "bônus": <https://github.com/somatorio/dockercompose-sample-workbench>  
151
Se podemos rodar as aplicações em container, que tal rodá-las através do [Docker Compose](https://docs.docker.com/compose/)? Assim se pode definir todas as ferramentas a serem utilizadas e elas estarão disponíveis após um único comando :)  
152
Essa ideia é do [@gomex](http://techfree.com.br), não minha... Ele falou disso durante uma conversa em um [meetup](https://www.meetup.com/pt-BR/Docker-Porto-Alegre/events/232916179/) sobre GUI em Docker (se olharem o link verão que tem um belo tempo entre a conversa e este post... foi mal =p) e eu apenas "executei" ela.
153 154

Buenas, quanto a recomendações de leitura:  
155

156 157
*   [Livro do Gomex (sobre Docker em geral)](https://leanpub.com/dockerparadesenvolvedores)
*   [Post da Jess sobre GUI em Docker](https://blog.jessfraz.com/post/docker-containers-on-the-desktop/)
158
*   [Meu singelo script - altamente baseado no da Jess (não, definitivamente não é coincidência)](https://github.com/somatorio/docker-desktop/blob/master/comandosdocker)
159 160 161

## AH, alguns amigos meus usam Mac e Windows, eles podem aproveitar isso?
Claro, só precisa de umas gambiarras (não que isso que fizemos até agora não tenha sido, hehe)  
162
*   [Mac OS X](https://github.com/docker/docker/issues/8710#issuecomment-71113263)  
163 164 165 166 167 168 169 170
Instalar o Docker for Mac

```
brew install socat
brew cask install xquartz
open -a XQuartz

socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"
171
docker run -e DISPLAY=hostip:0 [...] image OU DISPLAY=hostip:0 docker-compose up [-d]
172
```  
173
*   [Windows](https://github.com/docker/docker/issues/8710#issuecomment-135109677)  
174 175 176 177 178
Instalar o xming  
Instalar o Docker for Windows

```
xming :0 -ac -clipboard -multiwindow
179
docker run -e DISPLAY=hostip:0 [...] image OU DISPLAY=hostip:0 docker-compose up [-d]
180 181
```
### E funciona tudo direitinho?
182 183 184 185 186 187
Infelizmente nem tudo (ao menos até agora...), o som por exemplo não funciona e como o Docker for windows/Mac roda o Docker em uma VM, espere uma perda de desempenho...

#### Então é melhor não falar pra eles sobre isso?
Ei, eu só estava falando o que eles podem esperar, não para evitar isso :)  
Dentro do que eu testei afetou mais jogos e programas que exigem muito do hardware.  
Eles podem inclusive encontrar uma solução para o que eu comentei... maneiro, hein?