Skip to main content

Loki: Automated Promtail Container Deployment with Ansible

1024 words·
Loki Promtail Ansible Docker Debian
Table of Contents
Loki-Stack - This article is part of a series.
Part 5: This Article

Overview
#

I’m using the following Debian 12 servers in this tutorial:

192.168.30.20 # Ansible server
192.168.30.21 # Promtail var-log logging server 1
192.168.30.22 # Promtail var-log logging server 2

Ansible Server
#

Ansible Installation
#

# Update package index & install dependencies
sudo apt update && sudo apt install software-properties-common wget gpg -y

# Downloads the GPG key to verify the authenticity of the Ansible packages
wget -O- "https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=get&search=0x6125E2A8C77F2818FB7BD15B93C4A3FD7BB9C367" | sudo gpg --dearmour -o /usr/share/keyrings/ansible-archive-keyring.gpg

# Add the repository
echo "deb [signed-by=/usr/share/keyrings/ansible-archive-keyring.gpg] http://ppa.launchpad.net/ansible/ansible/ubuntu jammy main" | sudo tee /etc/apt/sources.list.d/ansible.list

# Install Ansible
sudo apt update && sudo apt install ansible -y
# Verify installation / check version
ansible --version

Ansible Inventory
#

Create hosts groups for the different promtail configuration:

sudo vi /etc/ansible/hosts
[promtail_var_log]
192.168.30.21
192.168.30.22
[promtail_systemd_journal]
192.168.30.23

SSH key
#

# Create a SSH key on the Ansible server
ssh-keygen -t rsa -b 4096
# Copy the SSH key to the Promtail logging servers
ssh-copy-id debian@192.168.30.21
ssh-copy-id debian@192.168.30.22

Test the Hosts Connection
#

# Check connection to Promtail hosts:
ansible promtail_var_log -m ping

# Shell output:
192.168.30.22 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
192.168.30.21 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

Ansible Playbooks
#

Folderstructure
#

├── ansible_promtail_var_log
│   ├── docker-compose_var-log.yml
│   └── promtail.yaml
├── docker_installation.yml
├── docker_network.yml
├── docker_user.yml
├── promtail_main_playbook.yml
└── promtail_var_log.yml

Description
#

The following Ansible playbooks sets up a Promtail container based on docker-compose_var-log.yml with the configuration promtail.yaml, with the following steps:

  • docker_installation.yml Install Docker & Docker Compose
  • docker_network.yml Create the external Docker network “promtail”
  • docker_user.yml Create a dedicated docker system user that is in the docker group
  • ansible_promtail_var_log Deploy the Promtail container

The promtail_main_playbook.yml playbook just runs the above playbooks in order.

The check_promtail_container.yml playbook is used to list the Promtail container details / verify the container deployment.


Install Docker & Docker Compose
#

Playbook
#

vi docker_installation.yml
---
- hosts: all
  remote_user: debian
  become: true
  vars:
    docker_apt_release_channel: stable
    docker_apt_arch: amd64
    docker_apt_repository: "deb [arch={{ docker_apt_arch }}] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }} {{ docker_apt_release_channel }}"
    docker_apt_gpg_key: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg"

  tasks:
    - name: Install packages using apt
      apt:
        name:
          - apt-transport-https
          - ca-certificates
          - curl
          - gnupg2
          - software-properties-common
        state: present
        cache_valid_time: 86400

    - name: Add Docker GPG apt Key
      apt_key:
        url: "{{ docker_apt_gpg_key }}"
        state: present

    - name: Add Docker Repository
      apt_repository:
        repo: "{{ docker_apt_repository }}"
        state: present
        update_cache: true

    - name: Install Docker
      apt:
        name: docker-ce,docker-ce-cli,containerd.io,docker-buildx-plugin,docker-compose-plugin
        state: present

    - name: Run and enable docker
      service:
        name: docker
        state: started
        enabled: true

    - name: Add debian user to the docker group
      ansible.builtin.user:
        name: debian
        groups: docker
        append: yes

Run the Playbook
#

# Run the playbook for a specific hostgroup
ansible-playbook docker_installation.yml --limit promtail_var-log

# Run the playbook for a specific host
ansible-playbook docker_installation.yml --limit 192.168.30.21

Create Docker Network
#

Playbook
#

vi docker_network.yml
---
- hosts: all
  remote_user: debian
  become: true
  tasks:
    - name: Create Docker network for promtail
      community.docker.docker_network:
        name: promtail
        state: present

Run the Playbook
#

# Run the playbook for a specific hostgroup
ansible-playbook docker_network.yml --limit promtail_var-log

# Run the playbook for a specific host
ansible-playbook docker_network.yml --limit 192.168.30.21

Create Docker User
#

Playbook
#

vi docker_user.yml
---
- hosts: all
  remote_user: debian
  become: yes
  vars:
    source_files_directory: "/home/debian/ansible-files"

  tasks:
    - name: Check if user docker-system exists
      ansible.builtin.command: id docker-system
      register: user_check
      ignore_errors: true

    - name: Create system user docker-system if it does not exist
      ansible.builtin.user:
        name: docker-system
        system: yes
        group: docker
        shell: /sbin/nologin
      when: user_check.rc != 0

Run the Playbook
#

# Run the playbook for a specific hostgroup
ansible-playbook docker_user.yml --limit promtail_var-log

# Run the playbook for a specific host
ansible-playbook docker_user.yml --limit 192.168.30.21

Deploy Promtail Container
#

Playbook
#

vi promtail_var_log.yml
---
- hosts: all
  remote_user: debian
  become: yes
  vars:
    source_files_directory: "/home/debian/ansible_promtail_var_log"

  tasks:
    - name: Ensure the /opt/promtail directory exists
      ansible.builtin.file:
        path: /opt/promtail
        state: directory
        mode: '0755'
        owner: docker-system
        group: docker

    - name: Gather facts about promtail.yaml and docker-compose_var-log.yml
      ansible.builtin.stat:
        path: "/opt/promtail/{{ item }}"
      register: file_stats
      loop:
        - promtail.yaml
        - docker-compose_var-log.yml

    - name: Copy files to /opt/promtail if they do not exist
      ansible.builtin.copy:
        src: "{{ source_files_directory }}/{{ item.item }}"
        dest: "/opt/promtail/{{ item.item }}"
        owner: docker-system
        group: docker
        mode: '0644'
      loop: "{{ file_stats.results }}"
      when: not item.stat.exists

    - name: Ensure /opt/promtail ownership is set
      ansible.builtin.file:
        path: /opt/promtail
        state: directory
        owner: docker-system
        group: docker
        recurse: yes

    - name: Docker Compose up -d
      ansible.builtin.shell: |
        sudo -u docker-system docker compose -f /opt/promtail/docker-compose_var-log.yml up -d
      become: yes
      args:
        chdir: /opt/promtail
        executable: /bin/bash

Run the Playbook
#

# Run the playbook for a specific hostgroup
ansible-playbook promtail_var_log.yml --limit promtail_var-log

# Run the playbook for a specific host
ansible-playbook promtail_var_-_log.yml --limit 192.168.30.21

Main Playbook
#

This playbook just runs the other playbooks in the order they are listed. Any subsequent playbooks listed after the one that encounteres an error will not run.

Playbook
#

vi promtail_main_playbook.yml
---
# Main playbook
- name: Run Docker Installation Playbook
  import_playbook: docker_installation.yml

- name: Run Docker Network Playbook
  import_playbook: docker_network.yml

- name: Run Docker Network Playbook
  import_playbook: docker_user.yml

- name: Run Docker Network Playbook
  import_playbook: promtail_var_log.yml

Runt he Playbook
#

# Run the playbook for a specific hostgroup
ansible-playbook promtail_main_playbook.yml --limit promtail_var_log

# Run the playbook for a specific host
ansible-playbook promtail_main_playbook.yml --limit 192.168.30.21

List Containers Details
#

The following playbook is used to list the Promtail container details / verify the container deployment.

Prerequisites
#

Install the Ansible module “Community Docker Collection” on the Ansible server:

# Install Ansible module "Community Docker Collection"
ansible-galaxy collection install community.docker

Playbook
#

vi check_promtail_container.yml
---
- hosts: all
  remote_user: debian
  become: yes
  gather_facts: no
  vars:
    docker_network: "promtail"
  tasks:
    - name: Get infos on container
      docker_container_info:
        name: "{{ docker_network }}"
      register: result

    - name: Does container exist?
      debug:
        msg: "The container {{ 'exists' if result.exists else 'does not exist' }}"

    - name: Print information about container
      debug:
        var: result.container
      when: result.exists

Run the Playbook
#

# Run the playbook for a specific hostgroup
ansible-playbook check_promtail_container.yml --limit promtail_var-log

# Run the playbook for a specific host
ansible-playbook check_promtail_container.yml --limit 192.168.30.21

Links #

# Install Ansible
https://docs.ansible.com/ansible/latest/installation_guide/installation_distros.html#installing-ansible-on-debian
# GitHub repository with the Ansible playbooks
https://github.com/jueklu/ansible-promtail-container-deployment
Loki-Stack - This article is part of a series.
Part 5: This Article