Semaphore is actually more than just an Ansible GUI. It can also add Terraform, OpenTofu, and batch scripts. I will be moving my Ansible tasks over to Semaphore.

Installing Semaphore using Docker Compose

I’m not using LDAP, and will be using MySQL. This is pretty much straight from the Semaphore website.

Take note of the following:

services:
  mysql:
    restart: unless-stopped
    image: mysql:8.0
    hostname: mysql
    volumes:
      - semaphore-mysql:/var/lib/mysql
    environment:
      MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
      MYSQL_DATABASE: semaphore
      MYSQL_USER: semaphore
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
  semaphore:
    restart: unless-stopped
    ports:
      - 3111:3000
    image: semaphoreui/semaphore:latest
    environment:
      SEMAPHORE_DB_USER: semaphore
      SEMAPHORE_DB_PASS: ${MYSQL_PASSWORD}
      SEMAPHORE_DB_HOST: mysql # for postgres, change to: postgres
      SEMAPHORE_DB_PORT: 3306 # change to 5432 for postgres
      SEMAPHORE_DB_DIALECT: mysql # for postgres, change to: postgres
      SEMAPHORE_DB: semaphore
      SEMAPHORE_PLAYBOOK_PATH: /tmp/semaphore/
      SEMAPHORE_ADMIN_PASSWORD: ${SEMAPHORE_ADMIN_PASSWORD}
      SEMAPHORE_ADMIN_NAME: admin
      SEMAPHORE_ADMIN_EMAIL: admin@localhost
      SEMAPHORE_ADMIN: admin
      SEMAPHORE_ACCESS_KEY_ENCRYPTION: ${SEMAPHORE_ACCESS_KEY_ENCRYPTION}
      SEMAPHORE_LDAP_ACTIVATED: 'no' # if you wish to use ldap, set to: 'yes' 
      SEMAPHORE_LDAP_HOST: dc01.local.example.com
      SEMAPHORE_LDAP_PORT: '636'
      SEMAPHORE_LDAP_NEEDTLS: 'yes'
      SEMAPHORE_LDAP_DN_BIND: 'uid=bind_user,cn=users,cn=accounts,dc=local,dc=shiftsystems,dc=net'
      SEMAPHORE_LDAP_PASSWORD: 'ldap_bind_account_password'
      SEMAPHORE_LDAP_DN_SEARCH: 'dc=local,dc=example,dc=com'
      SEMAPHORE_LDAP_SEARCH_FILTER: "(\u0026(uid=%s)(memberOf=cn=ipausers,cn=groups,cn=accounts,dc=local,dc=example,dc=com))"
      TZ: UTC
    depends_on:
      - mysql # for postgres, change to: postgres
volumes:
  semaphore-mysql: # to use postgres, switch to: semaphore-postgres

Logging Into the Semaphore Web Interface

I exposed Semaphore on port 3111, so I will access it like this: http://192.168.1.109:3111/

I will use the password defined in this environment variable “${SEMAPHORE_ADMIN_PASSWORD}” as my admin password.

Getting Started

Ansible needs to log into your servers in order to execute the commands in the tasks. The easiest way is to create a user on each server and call it, for example “ansible_user” and give it a password. You can check out this page here for how to create the user. Check the “Authentication” section.

Authentication with an Ansible User

Setting up Semaphore

Keystore

Now add this ansible_user username and password to the Keystore

Add ansible user to Keystore

Next, add a “None” key in your keystore. This will be used by our Repository which we will set up next. Because our repo is public, we don’t need to provide it with any credentials, so we will just select this “None” key.

None keystore item

Repository

Your playbooks need to exist in a repository. The easiest way is to just create a public repository on Github. Mine is here: My Github Repository for all my Playbooks

Im using the “main” branch, so I just enter main for the branch

Adding a repository

We will start with a simple “ping” playbook, just to test things out.

Add a playbook to your repository

Add a new file called “play_ping.yaml” with this code to your repository, and save it.

- name: Play Ping
  hosts: ubuntu_ct_testing
  become: yes
  tasks:
   - name: Ping my hosts
     ansible.builtin.ping:

   - name: Print message
     ansible.builtin.debug:
       msg: Ping all good!

Inventory

Next, we need to add a server, VM, LCX container, etc to run this playbook on. I have an Ubuntu LXC container I use for messing around, so I will add this container’s IP address.

Select “Ansible Inventory” as in the below screenshot.

Select ansible inventory

Now add your server IP address and use the Key we added earlier (the one containing the ansible user). We will use static inventory for now, but you can also use a file.

Add server IP address

Task Template

Now lets add a task. Select “Ansible Playbook” as in the below screenshot.

Add Ansible Playbook Task Template

And enter the detail for your task:

  • The playbook file name should be exactly as it is in your repo.
  • Inventory is the inventory with the server we created just now.
  • The repository is the one we added a while back.
  • Environment can be empty for now.
Task template detail

Schedule

Next, we need to schedule our task template to run. The name of the template is the one you added above.

Create schedule

Schedule a task template

Your task template will run based on your schedule, or you can kick it off manually. Running it manually is a great way to test your playbook. Here is how you can do it:

In your task templates, click on the Run button. You will see I already have some history.

Run task template

I like to do a dry run first so that everything can be validated. For example, if your repo is not reachable, you will get an error here.

Dry run

Here we can see it is pulling our repo and executing our playbook.

Dryn run output

Now you can add your other servers and more playbooks and monitor runs from the web interface.

View task history

To view your task history, click on Task Templates and click the drop down arrow next to the task name. To see more then 5 entries, click on the Task name.

Task history

Backup your project

Click on Dashboard, then Settings.

Backup project

How “become” works in Semaphore

Sometimes you need to use “become” in your playbook, as in this example:

- name: Clear lancache
  hosts: virtual_machines_homeassistant
  become: true
  tasks:
    - name: Remove all files in the cache directory
      ansible.builtin.shell: rm -rf /opt/lancache/cache/cache/*

But then you keep on getting “permission denied” errors. It is because Semaphore’s Keystore is not very self explanatory. You need to add 2 keys as per the below screenshot.

The first key must contain your ansible user’s username and password, the second key must contain ONLY the password, WITHOUT any username.

two keys

Then in your inventory, you must use the keys like this:

So 1 must contain the username and password. This is used for SSH.

The “Sudo Credentials” key must be the key that contains ONLY the password (the same password). If 2 contains a username as well, it looks like Semaphore will execute “su <user>” so when you use a username in that key, it will always just become that user, and never become root.

how to use they keys in the inventory