Tym razem, będę próbował wyjaśnić jeden ze sposobów iteracji po wielu hostach w Ansible. Czasem mamy potrzebę zrobić deploy czegoś, co korzysta z wielu hostów, ale konfiguracja tego, co będziemy deplojować nie jest identyczna na wszystkich hostach i tu mogą zacząć się pewne schody.

Film porusza taką kwestię właśnie na przykładzie klastra dystrybuowanej bazy danych Apache Cassandra. Pokażę moje proste podejście do tego problemu próbując deplojować klaster. Na filmie zademonstruję użycie takiego pseudo dynamic inventory.

Deploy apache cassandra w Docker za pomocą Ansible

Film o tym zagadnieniu

Pamiętaj o szczególnej ostrożności, przy używaniu obcych obrazów Docker z sieci, traktuj je zawsze jako potencjalnie groźne dla Twojego systemu.

 

doctl

W filmie użyłem toola o wdzięcznej nazwie command line tool for DigitalOcean services - jego zastosowanie pozwoli odpytać nasze konto w Digital Ocean o nasze zasoby. Na profilu na githubie znajdziesz sposoby instalacji tego toola. Czasem można go “spotkać” w niektórych dystrybucjach, sprawdź w swom managierze pakietów, czy nie posiadasz programu doctl lub doctl-bin

Jednak, zanim użyjemy tego toola, to musimy uzyskać tzw. API key w Manage > API w naszym interfejsie administracyjnym w Digital Ocean. Należy strzec tego klucza, ponieważ jego zgubienie lub, co gorsza, wykradzenie, umożliwi stawianie infrastruktury na nasz koszt.

Gdy już posiadasz swój klucz API i zainstalowanego doctl-bin można spróbować zautoryzować się  pisząc:

$ doctl --access-token TWOJKLUCZAPIDLUGIKOD auth init

Jeżeli wszystko poszło ok, możesz np. wyświetlić listę swoich dropletów (serwerów):

$ doctl compute droplet list

Jeżeli wynikiem jest pusta lista lub lista Twoich serwerów, to znaczy, że zautoryzowano się poprawnie. Jeżeli są jakieś problemy, sprawdź klucz API w pierwszej kolejności.

 

Cassandra i Docker

Na filmie użyto tego obrazu Dockera.

Pamiętaj o szczególnej ostrożności, przy używaniu obcych obrazów z sieci, traktuj je zawsze jako potencjalnie groźne dla Twojego systemu.

 

Ansible

W tym filmie kursu Ansible dowiesz się o sposobach instalacji Ansible jeśli jeszcze go nie posiadasz.

 

Pseudo-dynamic inventory, create_ansible_inventory.py

Nazwałem ten skrypt tak, ponieważ to nie jest ściśle skrypt do tzw. dynamic inventory. Skrypt ten jedynie generuje listę hostów, na podstawie tagów, która może zostać użyta jako statyczne, normalne inventory. Jest to więc rozwiązanie pośrednie pomiędzy statycznym a dynamicznym inventory.

Należy pamiętać, że skrypt korzysta z outputu doctl i korzysta z tzw. private networks w Digital Ocean! Private networks zostały użyte celem zabezpieczenia klastra, aby nikt z zewnątrz nie mógł się  do niego wpiąć.

Jak jesteś zainteresowany jakie są konwencje tworzenia dynamic inventory, skorzystaj z informacji zawartych na tej stronie.

Zasadę działania tego skryptów wytłumaczono na filmie. Tutaj załączam jego kod:

 1#!/usr/bin/env python3
 2
 3import subprocess
 4
 5OUTPUT = ""
 6COMMAND = """doctl compute droplet list --no-header --format Name,PublicIPv4,PrivateIPv4,Tags"""
 7cmd = subprocess.Popen(COMMAND, shell=True, stdout=subprocess.PIPE,
 8                       stderr=subprocess.STDOUT)
 9
10for line in cmd.stdout.readlines():
11    OUTPUT += line.decode("utf-8")
12
13num = 0
14tags = {}
15format = ""
16for line in OUTPUT.strip().split("\n"):
17    line = " ".join(line.split())
18    num = 0
19    public_host = ""
20    private_host = ""
21    for hostdata in line.split(" "):
22        if num == 0:
23            format += "["+hostdata+"]\n"
24        if num == 1:
25            format += hostdata+" "
26            public_host = hostdata
27        if num == 2:
28            format += "private_ip="+hostdata+" "
29            private_host = hostdata
30        if num == 3 and hostdata != "":
31            format += "tag="+hostdata+" "
32            pubkey = hostdata + "_public"
33            prvkey = hostdata + "_private"
34            if pubkey not in tags:
35                tags[pubkey] = []
36            if prvkey not in tags:
37                tags[prvkey] = []
38            tags[pubkey].append(public_host)
39            tags[prvkey].append(private_host)
40
41        num = num+1
42    format += "\n\n"
43
44for k in tags.keys():
45    format += "["+k+"]\n"
46    format += "\n".join(tags[k])
47    format += "\n\n"
48
49print(format)

 

Dumpowanie zmiennych w Ansible

Wykorzystaj do tego playbook o następnej zawartości:

Kod playbooka:

1- hosts: all
2  gather_facts: no
3  connection: local
4  tasks:
5    - name: Dump all vars to file
6      action: template src=templates/dumpall.j2 dest=/tmp/ansible.dump

Kod template (przy założeniu, że jest w templates/dumpall.j2)

 1Module Variables ("vars"):
 2--------------------------------
 3{{ vars | to_nice_json }} 
 4
 5Environment Variables ("environment"):
 6--------------------------------
 7{{ environment | to_nice_json }} 
 8
 9GROUP NAMES Variables ("group_names"):
10--------------------------------
11{{ group_names | to_nice_json }}
12
13GROUPS Variables ("groups"):
14--------------------------------
15{{ groups | to_nice_json }}
16
17HOST Variables ("hostvars"):
18--------------------------------
19{{ hostvars | to_nice_json }} 

 

Taski iterujące po hostach z przykładu na filmie

 1---
 2- name: Starting cassandra on host 1
 3  shell: >
 4       touch first_node && docker run --restart=always --name {{ tag }} -d -e CASSANDRA_BROADCAST_ADDRESS={{ private_ip }} -p 7000:7000 -p 9042:9042 cassandra:latest
 5  run_once: yes
 6  tags:
 7   - bootstrap
 8
 9- pause:
10       seconds: 60
11  tags:
12   - bootstrap
13
14- name: Starting cassandra on other nodes
15  shell: >
16       ! test -f first_node && docker run --restart=always --name {{ tag }} -d -e CASSANDRA_BROADCAST_ADDRESS={{ private_ip }} -e CASSANDRA_SEEDS={{ groups.cassandra_private | difference([private_ip]) | join(',')}} -p 7000:7000 -p 9042:9042 cassandra:latest
17  ignore_errors: yes
18  tags:
19   - bootstrap