Skip to main content

Ansible Getting Serious

Shenzhen, China

Adding the Production Host

Start by adding the ansible hosts by editing /etc/ansible/hosts:

[Wiki_Virtual]
18.19.251.137 ansible_port=12345

Adding SSH Public Keys

You can now use Vault to add your password. Or generate a RSA key pair to have Ansible use the public key to login:

ssh-keygen -t rsa -b 2048

I can now copy the generated ID to my production server:

ssh-copy-id root@18.19.251.137 -p 12345

Add you password when asked and afterwards try to login - now without a password - ssh root@18.19.251.137 -p 12345. Verify that it works. And try to use the Ansible ping module:

ansible Wiki_Virtual -m ping

18.19.251.137 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}

Installing Docker on Host

We can download ready to use roles for common problems from Ansible Galaxy:

Ansible requires the Python Docker library in addition to the regular Docker installation. You can use this role. But trying to install it gave me an error message: Failed to import the required Python library (setuptools) on wikivirtual's Python /usr/bin/python.. I was able to get rid of the error by executing the following on my external host: update-alternatives --install /usr/bin/python python /usr/bin/python3 10.

I had a different problem with docker-compose - different error message but also related to setuptools. I now added both of them to the pip install loop. Maybe this also solves issue 1. Compose now works as expected.

ansible-galaxy install geerlingguy.docker
ansible-galaxy install geerlingguy.pip

Docker Playbook

# nano /opt/ansible/playbooks/install_docker.yml
- hosts: Wiki_Virtual
gather_facts: yes

vars:
pip_install_packages:
- name: docker
- name: setuptools
- name: docker-compose

roles:
- geerlingguy.pip
- geerlingguy.docker
ansible-playbook /opt/ansible/playbooks/install_docker.yml

Setting Up Zabbix Agent

# nano /opt/ansible/playbooks/install_zabbix_agent2.yml
---
- hosts: Wiki_Virtual
gather_facts: no
tasks:

- name: Create directory for Zabbix Keyfile
file:
path: /opt/zabbix
state: directory
mode: '0755'

- name: Check if Zabbix Keyfile is already present
stat:
path: /opt/zabbix/agent_tls.psk
register: check_key_result

- name: Create Zabbix Keyfile
shell: openssl rand -hex 32 > agent_tls.psk
args:
chdir: /opt/zabbix/
when: not check_key_result.stat.exists

- name: Read Zabbix Keyfile
shell: cat /opt/zabbix/agent_tls.psk
register: zabbix_key

- name: Print Zabbix Keyfile
debug: var=zabbix_key

- name: Installing Zabbix Agent 2
docker_container:
name: zabbix-agent2
image: zabbix/zabbix-agent2:latest
networks:
- name: gateway
networks_cli_compatible: yes
privileged: yes
state: started
restart_policy: unless-stopped
ports:
- "10050:10050"
volumes:
- /opt/zabbix:/var/lib/zabbix/enc
env:
ZBX_HOSTNAME: "Wiki_Virtual"
ZBX_SERVER_HOST: "12.115.24.1"
ZBX_SERVER_PORT: "10051"
ZBX_TLSCONNECT: "psk"
ZBX_TLSACCEPT: "psk"
ZBX_TLSPSKIDENTITY: "Wiki_Virtual"
ZBX_TLSPSKFILE: "agent_tls.psk"
ansible-playbook /opt/ansible/playbooks/install_zabbix_agent2.yml

Runnig the Webservice

# nano /opt/ansible/playbooks/install_wiki.yml
---
- hosts: Wiki_Virtual
gather_facts: no

vars_prompt:

- name: "gitlabuser"
prompt: "Enter your INSTAR Gitlab Username"
private: no
- name: "gitlabpassword"
prompt: "Enter your INSTAR Gitlab Username"
private: yes

tasks:

- name: Log into Docker Registry and force re-authorization
docker_login:
registry: my.gitlab.com:12345
username: "{{ gitlabuser }}"
password: "{{ gitlabpassword }}"
reauthorize: yes

- name: Create the Gateway Network
docker_network:
name: gateway

- name: Run the EN Wiki Container
docker_container:
name: wiki_en
image: my.gitlab.com:12345/wiki/wiki_en_container
state: started
restart_policy: unless-stopped
networks:
- name: gateway
networks_cli_compatible: yes

- name: Run the DE Wiki Container
docker_container:
name: wiki_de
image: my.gitlab.com:12345/wiki/wiki_de_container
state: started
restart_policy: unless-stopped
networks:
- name: gateway
networks_cli_compatible: yes

- name: Run the FR Wiki Container
docker_container:
name: wiki_fr
image: my.gitlab.com:12345/wiki/wiki_fr_container
state: started
restart_policy: unless-stopped
networks:
- name: gateway
networks_cli_compatible: yes

- name: Get updated files from the NGINX Ingress repository
git:
repo: https://{{ gitlabuser | urlencode }}:{{ gitlabpassword | urlencode }}@my.gitlab.com/nginx_ingress.git
dest: /opt/wiki_ingress

- name: Get updated files from the NGINX Downloads repository
git:
repo: https://{{ gitlabuser | urlencode }}:{{ gitlabpassword | urlencode }}@my.gitlab.com/nginx_ingress.git
dest: /opt/wiki_downloads

- name: Setup a Nginx Ingress
docker_container:
name: ingress
image: nginx:stable-alpine
state: started
restart_policy: unless-stopped
networks:
- name: gateway
networks_cli_compatible: yes
ports:
- "80:80"
- "443:443"
volumes:
- /opt/wiki_ingress/configuration/conf.d:/etc/nginx/conf.d
- /opt/wiki_ingress/configuration/ssl:/etc/nginx/ssl
- /opt/wiki_ingress/configuration/nginx.conf:/etc/nginx/nginx.conf
- /opt/wiki_downloads:/opt/wiki_downloads
ansible-playbook /opt/ansible/playbooks/install_wiki.yml

Updating the Frontend Container

# nano /opt/ansible/playbooks/update_wiki.yml
---
- hosts: Wiki_Virtual
gather_facts: no

vars_prompt:

- name: "gitlabuser"
prompt: "Enter your INSTAR Gitlab Username"
private: no
- name: "gitlabpassword"
prompt: "Enter your INSTAR Gitlab Username"
private: yes

tasks:

- name: Log into Docker Registry and force re-authorization
docker_login:
registry: my.gitlab.com:12345
username: "{{ gitlabuser }}"
password: "{{ gitlabpassword }}"
reauthorize: yes

- name: Download the latest Wiki build images
shell: docker pull my.gitlab.com:12345/wiki/{{ item }}
with_items:
- wiki_en_container
- wiki_de_container
- wiki_fr_container

- name: Remove the EN Wiki Container
docker_container:
name: wiki_en
state: absent

- name: Rebuild the EN Wiki Container
docker_container:
name: wiki_en
image: my.gitlab.com:12345/wiki/wiki_en_container
state: started
restart_policy: unless-stopped
networks:
- name: gateway
networks_cli_compatible: yes

- name: Remove the DE Wiki Container
docker_container:
name: wiki_de
state: absent

- name: Rebuild the DE Wiki Container
docker_container:
name: wiki_de
image: my.gitlab.com:12345/wiki/wiki_de_container
state: started
restart_policy: unless-stopped
networks:
- name: gateway
networks_cli_compatible: yes

- name: Remove the FR Wiki Container
docker_container:
name: wiki_fr
state: absent

- name: Run the FR Wiki Container
docker_container:
name: wiki_fr
image: my.gitlab.com:12345/wiki/wiki_fr_container
state: started
restart_policy: unless-stopped
networks:
- name: gateway
networks_cli_compatible: yes
ansible-playbook /opt/ansible/playbooks/update_wiki.yml

Setting up Elasticsearch

# nano /opt/ansible/playbooks/install_elk.yml
---
- hosts: Wiki_Virtual
gather_facts: no

vars_prompt:

- name: "gitlabuser"
prompt: "Enter your INSTAR Gitlab Username"
private: no
- name: "gitlabpassword"
prompt: "Enter your INSTAR Gitlab Username"
private: yes

tasks:

- name: Get updated files from git repository
git:
repo: https://{{ gitlabuser | urlencode }}:{{ gitlabpassword | urlencode }}@my.gitlab.com/privrepo.git
dest: /opt/wiki_elk

- name: Start the Elasticsearch services
docker_compose:
project_src: /opt/wiki_elk
ansible-playbook /opt/ansible/playbooks/install_elk.yml

Managing Certificates with Certbot

I am going to use the Ansible Galaxy Role geerlingguy.certbot:

ansible-galaxy install geerlingguy.certbot 

Playbook

We can use vars to overwrite the default variables in /root/.ansible/roles/geerlingguy.certbot/defaults/main.yml:

# nano /opt/ansible/playbooks/install_certbot.yml
---
- hosts: servers

vars:
certbot_admin_email: me@email.com
certbot_create_if_missing: true
certbot_create_standalone_stop_services:
- docker
certbot_certs:
- domains:
- abc.com
- xyz.com

roles:
- geerlingguy.certbot

The Certbot command that is executed here is certbot certonly --cert-name abc.com -d abc.com,xyz.com. This means the resulting certificate will be filed under abc.com but will contain the keys for all domains that you list above.

You can check the installation by running the following commands on your host:

certbot -v
certbot certificates

To remove the certificate run:

certbot delete --cert-name abc.com