Creating an instance service file using an ansible template

ansibleansible-playbooksystemd

I have been using ansible for a while to install and configure several services, but this is the first time I am trying to set up a service that can have multiple instances running at the same time. I'm using a template for the service file, something like this:

[Unit]
Description=My Service
[Service]
WorkingDirectory=/var/lib/service/api
ExecStart=/usr/bin/python -O /var/lib/service/api/main.py -f /var/lib/service/api/cfg/service_api.cfg -p {{ port }}
Type=simple

And then my role for installing and configuring this service contains tasks like this:

- name: Configure api.service
  template: src=api.service.j2 dest=/etc/systemd/system/api@{{port}}.service

- name: Start service
  systemd: name=api@{{port}} state=restarted enabled=yes

Right now this is working for something like port = 80, but I don't think I made it generic enough. I don't fully understand how to create these instance services. How can I modify the service file and the role such that each listening port can have its own service file? Should I use the "Wants" keyword, or something like "WantedBy=multi-user.target"?

Best Answer

Rename your local file to api@.service (not api.service.j2) — we'll be using systemd templating instead of ansible's Jinja2 templating. Then change it like below:

[Unit]
Description=My Service on port %i
[Service]
...
ExecStart=... -p %i
...
[Install]
WantedBy=multi-user.target

Then you should be able to use it with ansible with a playbook like the following one:

- name: Deploy api@.service
  copy: src=api@.service dest=/etc/systemd/system/

- name: Start service
  systemd: name=api@{{item}} state=restarted enabled=yes
  with_items:
    - 80

(Though I'm not sure if it's better to use systemd or service module here; I'm still a newbie with ansible.)

See also: https://serverfault.com/a/730339/74509