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.ymlInstall Docker & Docker Compose
- docker_network.ymlCreate the external Docker network “promtail”
- docker_user.ymlCreate a dedicated docker system user that is in the docker group
- ansible_promtail_var_logDeploy 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