Tag: ansible

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

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 novíssimo 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:

dockerpull2

 

(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).

ansible_run_windows2

(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.
  • –enrypoint /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.

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.

Anúncios
Ansible + Windows: o básico, NTLM, DSC e mais.

Ansible + Windows: o básico, NTLM, DSC e mais.

Eu passei os últimos 6 anos trabalhando muito pouco quase nada com Windows. Meu coração está com o linux, mas eu não sou dado a fanatismos, e agora me encontro novamente trabalhando em um ambiente multiplataforma, com uso forte de Windows. Hora de aprender novos truques e tirar a poeira das minhas adormecidas Windows skills.

Parte disso está sendo testar como está o suporte de Windows no Ansible. Puppet, Salt (e acho que Chef também) tem um suporte mais avançado e/ou maduro a Windows, mas o Ansible tem avançado bastante recentemente. Nem tudo está muito bem documentado e difundido ainda, e nessa jornada eu descobri algumas jóias um pouco escondidas. Então, let’s blog.

Mantendo a filosofia agentless, o Ansible acessa o Windows remotamente usando recursos de acesso remoto do Powershell (Powershell Remoting). Para quem não sabe (eu não sabia), é possível abrir um console ou rodar comandos remotamente usando os comandos Enter-PSession e Invoke-Command no Powershell. Assim meio que parecido com um ssh, mas com uma sintaxe esquisita :D. Esse acesso remoto pode ser implementado de mais de uma maneira, usando RPC, WMI ou WS-Management, este último provido pelo serviço Windows Remote Management (WinRM). E é o WinRM que o Ansible utiliza.

Para isso tudo funcionar, algumas coisas precisam ser preparadas. Há scripts prontos para ajudar, mas vejamos uma lista:

  • Instalar o ansible, dãã.
  • Instalar a pywinrm na máquina que vai rodar o ansible
  • Habilitar o Powershell Remoting no Windows, se já não estiver (o procedimento depende da versão do Windows)
  • Habilitar o listener SSL no serviço WinRM do Windows (e gerar um certificado auto-assinado ou utilizar um “quente”).
  • Configurar o ansible para conectar usando o winrm e se autenticar …
    • … usando Kerberos …
    • … ou usando NTLM.
    • Nota: Pelo que investiguei eu aaacho que talvez seja possível se autenticar com base no certificado SSL do cliente (na ansible control machine), mas eu não testei nem achei nenhum documento sobre isso relacionado ao ansible.

Antes de botar na massa, só mais um comentário. O cenário normal e suportado é rodar o ansible em uma estação linux/unix. Para rodar o ansible a partir de uma estação Windows, a coisa complica. Cygwin não serve, Bash for Ubuntu no Windows 10 talvez, e eu já testei com sucesso uma solução usando docker. Mas isso é o assunto de outro post 😀

Mãos à obra

Leia a documentação oficial sobre Windows Support. Sério, leia, não é longa. Depois volte aqui e veja o meu resumo e o que funcionou pra mim.

(é, eu sei que você não vai ler, mas eu avisei)

Na máquina que roda o ansible (a control machine):

pip install "pywinrm>=0.1.1

Eu geralmente prefiro instalar o pacote da distro quando disponível, mas a versão pode acabar sendo antiga e não suportar alguma coisa, por exemplo a autenticação NTLM que eu explico abaixo. Teste.

No Windows, rode este script mencionado na documentação. Ele tem alguns parâmetros que você pode ou não precisar. Veja a seção Windows System Prep na documentação. Eu li e entendi o script. Ele gera um certificado auto assinado, configura um listener SSL no WinRM na porta 5986 (5985 é a padrão sem SSL), e libera essa porta no firewall para as redes privadas.

Dependendo da versão do Windows, o trabalho pode ser maior:

PowerShell 3.0 or higher is needed for most provided Ansible modules for Windows, and is also required to run the above setup script. Note that PowerShell 3.0 is only supported on Windows 7 SP1, Windows Server 2008 SP1, and later releases of Windows.

Eles sugerem um script para fazer o upgrade do powershell, veja na doc.

No meu ambiente, estou fazendo essa preparação do windows já na imagem base de Windows que estou gerando (go packer!). Daí quando a máquina nasce já está pronta para acesso via ansible.

Configurando

Precisamos passar para o ansible alguns parâmetros para ele saber como conectar nas máquinas windows. Eu faço isso associando elas a um grupo “windows” no inventário e aí criando este arquivo de vars:

$ cat group_vars/windows 
---
ansible_port: 5986
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore

Com tudo que já falamos, acho que é bastante auto-explicativo. Claro que é necessário ter as credenciais também. Dá para fornecê-las iterativamente, se for seu caso, com os parâmetros normais -u e –ask-pass, ou manter em outro arquivo de variáveis criptografado com ansible vault:

$ ansible-vault edit group_vars/ansiblelab 
Vault password: 
# opens in my $EDITOR:
---
ansible_user: myuser
ansible_password: mypassword

Bom, com isso, já dá para acessar a máquina utilizando o usuário da base local do Windows. Agora vamos ao AD…

Autenticando Windows com o Active Directory

Para autenticar no Windows, usando uma conta do AD (ao invés de uma conta local do servidor), o procedimento normal descrito na documentação do Ansible é utilizar Kerberos, tendo inclusive que colocar a control machine no domínio.

Arrrghh, que dor só de ouvir. E imagina se eu tiver mais de um domínio não relacionado (sem relação de confiança entre eles), vou ter que ter uma control machine para cada domínio?

Felizmente, não é bem assim. Para começar, é algo meio recente, mas dá para utilizar NTLM, que me parece uma alternativa muito mais simples e flexível.

Autenticando com NTLM

Basta adicionar essa opção aqui junto daquelas outras lá em cima:

ansible_winrm_transport: ntlm

Além disso, é preciso informar o domínio ao passar o usuário:

ansible_user: myuser@ANSIBLELAB.LOCAL
ansible_password: mypassword

Pronto, só isso! Note que eu usei o formato user@FULL.DNS.DOMAIN em vez do mais comum SHORTDOMAIN\user. Esse foi o jeito de funcionar da mesma com ntlm ou Kerberos, meu próximo teste.

Autenticando com Kerberos

Eu não sei se meu ambiente de teste (só nele eu testei com Kerberos) não representou bem a realidade, mas eu não precisei adicionar a control machine no domínio. No entanto, tem vários detalhes importantes:

  •  Obviamente, a control machine precisa enxergar perfeitamente o domínio DNS associado ao AD em questão.
  • O relógio precisa estar sincronizado, isso é básico para qualquer ambiente Kerberos.
  • O registro reverso no DNS precisa estar correto. Isso me mordeu, demorei a me dar conta. Confesso que agora não tenho certeza se só os registros dos servidores windows ou da control machine também. Eu acertei todos eles.
  • O inventário precisa utilizar o nome do servidor Windows, e não o IP.

O método NTLM não precisa dessas coisas, mas cabe notar que são todas boas práticas a serem seguidas de qualquer forma.

Pacotes:

yum -y install python-devel krb5-devel gcc krb5-libs krb5-workstation
pip install kerberos requests_kerberos

Eu criei um domínio de teste, chamado ANSIBLELAB (ansiblelab.local), promovendo a Domain Controller o meu host de teste ansiblelab-w02. Não vou entrar em detalhes aqui sobre como fazer isso no Windows.  Mas a configuração do Kerberos na minha control machine ficou assim:

# cat /etc/krb5.conf 
includedir /var/lib/sss/pubconf/krb5.include.d/ 
[logging] 
 default = FILE:/var/log/krb5libs.log 
 kdc = FILE:/var/log/krb5kdc.log 
 admin_server = FILE:/var/log/kadmind.log 
 
[libdefaults] 
 dns_lookup_realm = false 
 ticket_lifetime = 24h 
 renew_lifetime = 7d 
 forwardable = true 
 rdns = false 
 default_realm = ANSIBLELAB.LOCAL 
 default_ccache_name = KEYRING:persistent:%{uid} 
 
[realms] 
ANSIBLELAB.LOCAL = { 
  kdc = ansiblelab-w02.ansiblelab.local 
  kdc = ansiblelab-w02.ansiblelab.local 
} 
 
[domain_realm] 
.ansiblelab.local = ANSIBLELAB.LOCAL

E nas minhas variáveis do ansible, eu setei para a WinRM usar kerberos:

ansible_winrm_transport: kerberos

Para que o ansible possa se autenticar via Kerberos, eu preciso rodar o kinit (para obter o TGT). Eu criei um usuário configurado como admin das máquinas windows, para testar.

kinit -U myuser@ANSIBLELAB.LOCAL

Ele pede a senha, e pronto, depois é só conectar com o ansible informando apenas o usuário e domínio (igual ao mostrado acima com o NTLM), não precisa mais colocar a senha.

Testando

Para começar, aquele teste com módulo ping do ansible, sempre útil para testar a conectividade básica antes de mais nada. Só que no caso do windows, vocês deve usar o módulo win_ping:

ansible_win_ping

Se por acaso der um erro tal como “ssl: HTTPSConnectionPool(host=’w2′, port=5986): Max retries exceeded with url: /wsman (Caused by ConnectTimeoutError …”, então o listener SSL não foi habilitado na porta 5986 (veja lá em cima onde eu cito o script powershell que habilita isso).

Agora vamos rodar um playbook simples. Eu resolvi testar subir um virtual host no IIS, copiando os arquivos do site em um zip para o servidor. Veja aqui o playbook:

Destacando as principais tarefas nele:

  • Instala o IIS (win_feature, linha 8)
  • Cria o Website/VirtualHost (win_iis_website, linha 25)
  • Abre a porta do novo website no firewall (win_firewall_rule, linha 31)
  • Copia um arquivo zip com o conteúdo do site para um diretório de staging (win_copy, linha 45)
  • Descompacta o arquivo zip no diretório do site (win_unzip, linha 49)

Algumas outras tarefas menos interessantes estão ali também, para criar os diretórios envolvidos e para subir um arquivo index.html para o site default, em geral usando o win_file.

A execução fica assim:

ansible_iis2

 

 

Essa não foi a minha primeira execução, então algumas tarefas no início já estavam feitas (como a instalação do IIS), e ele não precisou fazer nada, marcando apenas como OK. O resto não tinha sido feito ainda e então ele executou e marcou como changed.

Esses dois warnings aparecem devido a algum bug inócuo introduzido recentemente. Nothing to worry about, eu achei dito na lista no Google Groups.

Mas tem um outro bug mais chato escondido aí. Ao executar novamente o playbook, a task do firewall me deu erro:

ansible_iis_error

The rule exists but has different values. Arrgh. A vida não é um moranguinho, definitivamente. Há um issue aberto. Uma “solução” é setar force=true neste módulo, mas daí ele executa toda vez, marcando sempre como changed. Indesejável, para dizer o mínimo.

Módulos para Windows, e DSC

A lista de módulos para Windows já é grandinha, e tem crescido a cada versão. Vimos alguns no exemplo acima. A maioria é específico, com prefixo win_, mas alguns poucos funcionam tanto para linux quanto para windows, como o módulo script, que pode fazer upload e executar scripts powershell, bash, python, whatever. Tirado da doc:

Note:: There are a few other Ansible modules that don’t start with “win” that also function with Windows, including “fetch”, “slurp”, “raw”, and “setup” (which is how fact gathering works).

Além disso, existem outros ainda não oficiais, e os mais interessantes que eu achei foram os que linkei abaixo relativos ao DSC. Eu não testei eles ainda, mas é preciso comentar sobre eles pois o potencial é gigante.

O que é DSC? Desired State Configuration (DSC) é um conjunto de extensões ao Powershell para uma gerência de configuração de forma declarativa, nativa do Windows. Existe já um caminhão de resources DSC para realizar as mais variadas tarefas. E estão no GitHub. Tem módulo Puppet para  DSC.

A partir do Powershell 5.0, é possível utilizar o DSC de forma mais isolada e pontual. O que permitiu um tal de trondhindenes criar um módulo ansible para executar DSC, win_dsc. Mas isso não é o melhor. Ele criou um gerador automático de módulos DSC pra ansible, com o qual ele conseguiu converter todo aquele caminhão módulos DSC já prontos, para módulos DSC ansible.

São 176 (!) módulos. Eu ainda não sei se eles funcionam muito bem (testarei, não precisei deles ainda), mas caso positivo, o suporte do Ansible a Windows está catapultado a outro patamar.

Considerações finais e próximos passos

É preciso lembrar que nem tudo é uma beleza. O ansible não é tão maduro quanto caras mais antigos como Puppet ou Chef, e o suporte dele a Windows é especialmente novo. Haverão pedras no caminho. Eu não fiz muita coisa séria ainda e já encontrei algumas, como o bug do win_firewall_rule acima. Sinceramente, acho que qualquer destas alternativas ainda vai dar uma dor de cabeça extra ao lidar com Windows. Mas o cenário está evoluindo e o ansible é uma alternativa muito interessante nele.

Coisas que estou testando e que podem virar posts logo logo:

  • Instalar o novo Docker for Windows com containers nativos do Windows 2016, usando Ansible.
  • Examinar as alternativas (i.e. gambiarras) disponíveis para rodar o Ansible a partir de uma estação Windows.
  • Examinar alguns problemas que tive executando alguns módulos no Windows Server Core.

Outras ideias interessantes a serem exploradas:

  • O Active Directory tem um recurso de geração e distribuição automática de certificados (Auto Enrollment) que eu acredito ser uma boa solução para evitar os certificados auto-assinados. A geração “em massa” de certificados auto-assinados é uma nojeira, e um risco de segurança. Com certificados de uma CA confiada a segurança iria ficar muito mais séria.
  • Dado o passo acima, testar a autenticação via certificado SSL do cliente fica mais fácil. Pelo que vi superficialmente, acho que o serviço WinRM suporta isso e a pywinrm também.
  • Obter as credenciais de acesso ao Windows via HashiCorp Vault, ou talvez armazená-las no Ansible Tower ou quem sabe do Rundeck.
  • Testar aqueles módulos DSC mencionados acima, ver se funcionam bem.

Se alguém lendo isso tiver alguma experiência com os itens acima, please compartilhe 😀

Ansible: an easy way to start with config management

Many, many years back, I developed a script to help me run commands on many unix machines or network equipment easyly. I called it tabatool (yeah, weird name, don’t ask). It used Tcl/expect, it had a config file with host names, groups, usernames for login and sudo, etc. I eventually stopped working on it and settled on using a mix of parallel-ssh, clusterssh, fabric, and more specific expect scripts when needed. And them later got to config management with Puppet.

But I really miss a good push mode for Puppet sometimes. Some way of saying “take this code I have right here live in front of me, and apply it to that (or these) machines, NOW” and bam, it goes and do it. Not always, but sometimes. Like adding more powerful config management to fabric or to my old script.

Ansible is like that. It is all that I ever wanted my old script to be, and much much more. It is very flexible, powerful, and it tries very hard to KISS as much as possible. It runs over SSH and it needs no agent on the remote machine. Having played with it a little bit already, I believe Ansible is about the easiest way for a sysadmin to start at configuration management. With the plus of having a very good chance of not needing/wanting to leave it for other tools as the journey progresses.

If you want to follow the examples bellow with “hands on”, let’s get installation out of the way: see the docs here. They publish packages for Ubuntu, CentOS/RHEL, and it’s also pretty common running from a source checkout from Github. On Debian and Ubuntu, a straight apt-get install ansible will also work, but the versions on the official repos might be quite old.

Basic start: ad-hoc usage

Say you want to make sure NTP is installed on all your Debian/Ubuntu machines. List their names on a file (it will be your ansible inventory) and run the command below. I’ll call my file production.

ansible -i production all -u morales --ask-pass --sudo \
  --ask-sudo-pass -m apt -a "name=ntp update-cache=yes"

Depending on your machines setup you might not need any or all of the user and password options above. You can set them as default in a configuration file as well. Ansible recommends you use authorized SSH keys to login, but is fine with passwords, sudo, su and all that. The all soon after -i means all hosts of that inventory, -m apt means the ansible module for apt, and you pass parameters to that module with -a.

You can also run an arbitrary command in a similar way:

ansible -i production all -u morales --ask-pass --sudo \
  --ask-sudo-pass -a "rm -f /tmp/sad_unwanted_file"

This uses the command module, which happens to be the default module, so you don’t need to say -m command in this case. There are many many other modules available. Want just to upload a script and run it? Fine, use the script module. Bonus: with the optional creates= parameter it only runs the script if the said file does not exist.

ansible -i production all -u morales --ask-pass --sudo \
  --ask-sudo-pass -m script -a "/tmp/myscript.sh \ 
  --some-arguments 1234 creates=/etc/blah/file.conf"

Enter configuration management

Ok, that’s cool, you can already dump parallel-ssh in favor of ansible. But the real deal comes next. We can organize several of those module calls together in a file or set of files, called playbooks. Very very shortly, a playbook is an ordered set of plays, and a play is an ordered set of tasks applied to a set of hosts. Playbooks and plays are written in YAML, Yet Another Markup Language, one that’s pretty easy for humans to work with. The tasks are performed by modules like apt and script and so on.

Let’s see that ad-hoc ntp install, in a playbook called ntp.yml:

---
- hosts: all
  tasks:
  - name: Install NTP
    apt: name=ntp update-cache=yes

You now run it using the ansible-playbook executable instead of ansible:

ansible-playbook -i production -u morales --ask-pass --sudo \
--ask-sudo-pass ntp.yml

Too much work for just installing a lame package. So let’s also set the configuration file and make sure NTP is restarted whenever ansible changes that file:

---
- name: Install and Configure NTP
 hosts: all
 vars:
   ntp_server: [pool.ntp.org, south-america.pool.ntp.org]
 tasks:
 - name: Install NTP
   apt: name=ntp update_cache=yes
 - name: Copy the ntp.conf template file
   template: src=ntp.conf.j2 dest=/etc/ntp.conf
   notify: 
     - restart ntp
 handlers:
 - name: restart ntp
   service: name=ntp state=restarted

Now the play has two tasks and calls a handler to restart NTP. It also sets variables in the beggining of the play (but they could be set on other files), and one of the tasks fills a template of the ntp.conf file, using those variables. The templating language is Jinja 2. Here’s a possible ntp.conf.j2 for use above:

driftfile /var/lib/ntp/drift

{% for i in ntp_server %}
server {{ i }}
{% endfor %}

restrict -4 default kod notrap nomodify nopeer noquery
restrict 127.0.0.1
restrict -6 default kod notrap nomodify nopeer noquery
restrict ::1

statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable

Let’s finish showing some ansible’s output for the code above (assuming the machines didn’t have ntp installed):

 $ ansible-playbook -i production -u morales --ask-pass --sudo \
     --ask-sudo-pass ntp.yml
 
 PLAY [Install and Configure NTP] ***********************************
 
 GATHERING FACTS ****************************************************
 ok: [box1]
 ok: [box2]
 
 TASK: [Install NTP] ************************************************
 changed: [box2]
 changed: [box1]
 
 TASK: [Copy the ntp.conf template file] ****************************
 changed: [box1]
 changed: [box2]
 
 NOTIFIED: [restart ntp] ********************************************
 changed: [box2]
 changed: [box1]
 
 PLAY RECAP *********************************************************
 box1 : ok=4 changed=3 unreachable=0 failed=0 
 box2 : ok=4 changed=3 unreachable=0 failed=0

If you decide to change the ntp_server list, for example, and run it again, here’s what yout get:

 $ ansible-playbook -i production -u morales --ask-pass --sudo \
     --ask-sudo-pass ntp.yml

 PLAY [Install and Configure NTP] ***********************************
 
 GATHERING FACTS ****************************************************
 ok: [box2]
 ok: [box1]
 
 TASK: [Install NTP] ************************************************
 ok: [box2]
 ok: [box1]
 
 TASK: [Copy the ntp.conf template file] ****************************
 changed: [box2]
 changed: [box1]
 
 NOTIFIED: [restart ntp] ********************************************
 changed: [box1]
 changed: [box2]
 
 PLAY RECAP *********************************************************
 box1 : ok=4 changed=2 unreachable=0 failed=0 
 box2 : ok=4 changed=2 unreachable=0 failed=0 

It figures out ntp is already installed, but changes the file and restarts the service. And if you run it again without changing anything, it will just report ok=4 changed=0 at the end: nothing needs doing, so nothing is done.

And there you have it. A small piece of your infrastructure codified in a text file, which can be versioned, reviewed, debugged, shared, and… run. It’s also executable documentation, the only kind of documentation that has a real chance of not getting outdated. New guy arrives in the team, and needs to understand how we do X? Read the code.

Beautiful. Welcome to configuration management.

That was just a very tiny scratch on the surface of Ansible

Really tiny. Let me list some others things Ansible can do:

  • The inventory can be organized in groups. You can define variables based on those groups and use them inside plays (think stuff like “this group of servers uses NTP/DNS servers A and B, that other one uses NTP/DNS servers B and C).
  • There are some automatically available variables with facts about the system: things like hostname, FQDN, os version, and much more.
  • You have loops and conditionals.
  • You can “package” your tasks in reusable roles, and them apply them to hosts in several different plays/playbooks.
  • There are many community-made roles on the Ansible Galaxy (like the Forge for Puppet).
  • You can do a dry run before doing it for real.
  • Sensitive vars/data may be encrypted using ansible-vault, so you don’t need to store it in clear text inside your code.
  • You can run commands on your local control machine, having them in same playbook together with other regular remote tasks. You can also prompt yourself for information.
  • You can even wait for reboots.
  • Windows support already exists, modules for it are starting to appear.
  • You can do everything from the command line, but you can pay for support and access to the web interface called Ansible Tower.

The Ansible documentation could maybe be richer, but it’s also pretty easy to follow.

Final Remarks

I guess the main thing I would like to transmit here can be summed up like this: ANY sysadmin (at least *nix ones) can find an immediate use for Ansible, and can start using it without really studying it any more than reading this post, and then move on to automating more and more stuff with it, little by little, in an easy learning/practice curve.

There are other alternatives. I have used a lot of Puppet, and intend to take Salt for a spin next. But most of all I find Ansible KISS attitude really compelling, specially for people starting with this class of tools.