Ansible + Windows: Rodando Ansible a partir do Windows com Docker

Diego Morales
7 min readJul 16, 2017

--

Apesar de ser em python, e python rodar tranquilamente em Windows, rodar o Ansible dentro do Windows não é suportado, já diz claramente a doc.

Mas eu estou agora com um ambiente multiplataforma, com um bando de gente rodando Windows, e eu quero que o Ansible seja uma opção pra eles, inclusive rodando de sua própria máquina. E agora?

Bom, dá pra rodar dentro de uma VM, claro. Mas há outras opções também. Eu explorei 3 delas:

  • Cygwin
  • O novo Bash for Ubuntu on Windows 10
  • Um container docker linux dentro do Windows.

Cygwin

No fim das contas, o cygwin NÃO é uma opção viável. Eu tentei, não perca o seu tempo também. Já diz, novamente, a doc:

Cygwin is not supported, so please do not ask questions about Ansible running from Cygwin.

Eu fui cabeça-dura e comprovei que não funciona, tomando erros malucos na cabeça. Vi vários relatos de que na versão 1.9 esses erros não acontecem. Mas uma thread recente na lista ansible-users me convenceu. Nela o “Windows Guy” da Ansible/RedHat dá mais detalhes:

“Ansible is most decidedly *not* supported or tested under cygwin (or any mechanism under Windows except a Linux VM, currently). Cygwin’s fork() syscall is unstable (even by their own admission), so you *will* run into issues and heisenbugs, even more so under 2.0+ where we’re making extensive use of fork() behavior that’s more likely to break under Cygwin.

Ansible *may* at some point be supported under the new Bash/Ubuntu on Windows stuff in Win10 (because their fork() is actually functional), but even there things are not working 100% yet.

As the “Windows Guy” at Ansible, nothing would make me happier than to have full Windows support for running the controller on my favorite OS, but there are major technical hurdles to doing so reliably, which is the reason we don’t.

Please don’t run the Ansible controller for anything real on Windows. Please.

Love,

Matt Davis
Ansible Core Engineering (The Windows Guy)”

Desisti. Vamos para a alternativa que na verdade eu tentei primeiro:

Bash on Ubuntu on Windows 10

Eu sou um linux guy, e um que ama o apt-get. No badalado Aniversary Update lançado em agosto (neste 2016), foi lançado o impensável feature dentro do próprio Windows, que permite habilitar um bash no Windows, que roda nativo (ou algo próximo disso) através do Windows Subsystem for Linux — WSL (em 2000 e poucos isso seria motivo de gargalhada). Não é só um bash, é um pequeno ambiente Ubuntu completo. Com apt-get.

E eu dei apt-get install ansible (acho que eu usei até o ppa de ansible), e lá foi o apt-get fazendo o seu trabalho, e funcionou, instalou. E uma lágrima de felicidade e incredulidade escorreu no meu rosto. Isso foi em casa.

Fui testar no trabalho, e bateu o reality check. O apt-get não funcionava direito. Acontece que o anti-vírus/anti-malware/firewall utilizado na empresa interfere no WSL, aparentemente isso está acontecendo com vários fabricantes de soluções de segurança. Única solução que eu achei até agora foi desabilitar o firewall da solução. Sem ele, o ansible pareceu funcionar bem ali, apesar do Matt Davis no comentário acima falar em alguns problemas nesse cenário. Mas infelizmente desabilitar esse firewall não é uma solução decente para a adoção que eu busco nesse ambiente. E agora? Vai ter que ser VM, pensei.

Mas no meio de uma discussão sobre docker, me surgiu uma ideia.

Docker to the rescue

Vamos à principal ideia deste post.

O Rafael Gomes (@gomex) tem uma palestra muito interessante sobre “Docker como super comandos” (tem uma gravação dela aqui). O caso dele é muito mais elaborado, mas me inspirou nessa solução. Simplificando drasticamente a ideia dele, é utilizar docker não só para subir um serviço, mas para encapsular um ou mais comandos em um processo, com todas as dependências necessárias. Aproveitando assim várias propriedades interessantes trazidas pelo Docker: empacotamento, distribuição fácil, versionamento, descartabilidade (inventei a palavra, talvez).

Looks very nice. E vou levar de certa forma essa ideia a um extremo: um container que encapsula vários comandos potencialmente interativos que para completar precisam ler arquivos no meu host, fora do container.

Eu usei para isso o Docker Toolboox, que usa docker-machine: ele levanta uma VM linux no virtualbox que é o host docker, e esse host é acessado pelo cliente docker rodando no Windows (dentro de um shell bash.exe que ele instala, usando MinGW). Oh… wait, na real então eu não me escapei da VM :-o. É verdade, não tem muita escapatória. Mas a forma de utilização vai ficar bem mais interessante do que a VM pura ou até do que uma via vagrant.

O novo Docker for Windows também é uma opção, mais interessante até, mas ele requer o Hyper-V, o que quebra o VirtualBox, que eu utilizo para outras coisas também. Espero testar com ele também em breve.

Meu roteiro rápido para rodar o ansible no Windows, então:

  1. Instale o Docker Toolbox no Windows.
  2. Faça pull da minha imagem dgmorales/ansible no DockerHub.
  3. Configure alguns aliases no bash que o docker-toolbox utiliza.
  4. Profit!

Quanto ao passo 1, o link tá ali em cima, siga as instruções. O passo 2 é só um docker pull dgmorales/ansible:

(nessa saída aí, eu já tinha a imagem baixada)

A criação dessa imagem não tem lá muito mistério. É só instalar o ansible e algumas dependências necessárias (como a pywinrm). Eu não mostro o Dockerfile dela, pois resolvi criá-la usando o ansible-container, e isso vai ser assunto para um próximo post.

Agora aos aliases… aqui a gente mascara uma série chata de opções que precisamos passar ao docker. Usando o Docker Toolbox, eles podem ser colocados no ~/.bash_profile. São 2 aliases:

$ cat .bash_profile
alias ansible='docker run -it --rm -w /code -v `pwd`:/code \
--entrypoint /usr/bin/ansible dgmorales/ansible'
alias ansible-playbook='docker run -it --rm -w /code -v `pwd`:/code \
dgmorales/ansible'

Já vamos explicar eles melhor, mas antes…

Ver pra crer

Antes de continuar, só deixa eu mostrar que funciona. Nesse caso eu estou rodando um playbook que instala o ansible em uma máquina linux (é um container com ansible que eu gerei usando ansible(-container), instalando o ansible, então são 2 níveis de meta).

(nessa saída, eu já havia executado o playbook antes, então na verdade ele não fez nada, só conferiu e deu OK pra tudo.)

Explicando

Olhando os aliases podemos entender melhor como funciona (a diferença entre os dois é apenas o –entrypoint). Os parâmetros aí são a chave da mágica:

docker run -it –rm -w /code -v `pwd`:/code –entrypoint /usr/bin/ansible dgmorales/ansible

  • -it: roda o container em modo interativo. É necessário porque em alguns casos o Ansible pode solicitar input (por exemplo com o –ask-pass, ou para aceitar um ssh fingerprint na primeira conexão).
  • –rm: faz com que o container seja automaticamente destruído após terminar sua execução. Isso é vital, pois caso contrário cada execução do ansible vai deixar armazenado mais um container que nunca mais será reusado.
  • -v `pwd`:/code: mapeia o diretório atual no windows para o diretório /code dentro do container.
  • -w /code: define o diretório atual para o comando sendo executado. O diretório atual fora do container foi mapeado para /code.
  • –entrypoint /usr/bin/ansible: a definição do container indica o comando a ser executado como /usr/bin/ansible-playbook. Para rodar o /usr/bin/ansible eu não preciso de outra imagem, eu só preciso dar um override no entrypoint.

Detalhe IMPORTANTE: é preciso rodar o ansible no windows estando na da raiz do repositório ansible, para que ele mapeie todo o repositório (e apenas o repositório) para o /code e encontre tudo no lugar certo.

Depois eu me dei conta que falta uma coisinha ainda (pelo menos) aí: mapear mais um local com as chaves ssh. No caso eu loguei com usuário e senha. É um ajuste que farei.

Concluindo

Vejamos essa solução com docker. Eu usei pouco ela ainda, mas ela tem algum potencial. Talvez até em um linux eventualmente, pois além de me possibilitar a execução do ansible no windows de uma forma quase transparente, ela me traz algumas outras vantagens:

  • Se o usuário já tiver o docker instalado, a instalação é quase só um docker pull.
  • O processo de instalação do ansible em si, daonde pegar (source, ppa, rpm, pacote xyz), e dependências (pywinrm, python-kerberos, e outras assim), ficam transparentes para o usuário.
  • Adicione aí alguma configuração do ansible, temos o controle sobre a configuração recomendada, que está dentro do container.
  • Todos vão rodar os “pacotes” de ansible que foram testados e “aprovados” antes por pessoas mais experientes com ele.
  • Qualquer atualização nos fatores acima é fácil de distribuir, é só gerar uma nova versão da imagem e as pessoas fazerem um novo pull.
  • Não interfere com nada instalado na máquina, e felizmente os anti-vírus e firewalls parecem deixá-lo em paz também.
  • Pode ser inserido mais facilmente em um pipeline de CI/CD.

Onde estou, é um dos nossos objetivos que todas as pessoas da TI ganhem alguma familiaridade com docker, e que também tenham o ansible como ferramenta para seu uso, com o mínimo de entraves. Então a proposta encaixa bastante bem.

Se alguém quiser testar, aproveite, e me conte como foi. Docker para rodar comandos, e não serviços. Guarde esse conceito, ele é poderoso.

--

--

Diego Morales

SRE Tech Lead na Stone. Doido por automação, DevOps, Agile, churrasco e corridas de aventura.