เริ่มต้นกระบวนการ N ด้วยหนึ่งไฟล์เซอร์วิส systemd


36

ฉันพบไฟล์ serviced systemd นี้เพื่อเริ่ม autossh เพื่อติดตามอุโมงค์ ssh: https://gist.github.com/thomasfr/9707568

[Unit]
Description=Keeps a tunnel to 'remote.example.com' open
After=network.target

[Service]
User=autossh
# -p [PORT]
# -l [user]
# -M 0 --> no monitoring
# -N Just open the connection and do nothing (not interactive)
# LOCALPORT:IP_ON_EXAMPLE_COM:PORT_ON_EXAMPLE_COM
ExecStart=/usr/bin/autossh -M 0 -N -q -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -p 22 -l autossh remote.example.com -L 7474:127.0.0.1:7474 -i /home/autossh/.ssh/id_rsa

[Install]
WantedBy=multi-user.target

มีวิธีการกำหนดค่า systemd เพื่อเริ่มอุโมงค์หลายแห่งในบริการเดียวหรือไม่

ฉันไม่ต้องการสร้างไฟล์บริการของระบบ N เนื่องจากฉันต้องการหลีกเลี่ยงการคัดลอก + วาง

ไฟล์บริการทั้งหมดจะเหมือนกันยกเว้น "remote.example.com" จะถูกแทนที่ด้วยชื่อโฮสต์อื่น

1.5 ปีต่อมา ...

ฉันถามคำถามนี้ประมาณ 1.5 ปีที่ผ่านมา

ใจของฉันเปลี่ยนไปเล็กน้อย ใช่มันดีที่คุณสามารถทำได้ด้วย systemd (ฉันยังใช้อยู่) แต่ฉันจะใช้การจัดการการกำหนดค่าในอนาคต

ทำไม systemd ควรใช้ภาษาเทมเพลตและแทนที่% h

หลายเดือนต่อมาฉันคิดว่าการวนซ้ำและการสร้างเทมเพลตนี้ควรได้รับการแก้ไขด้วยเครื่องมือที่กำหนดค่าอัตโนมัติ ฉันใช้หนึ่งเครื่องมือของรายการนี้ที่วิกิพีเดียตอนนี้


พูดอีกอย่างก็คือคุณกำลังใช้ระบบจัดการการกำหนดค่าเพื่อสร้างไฟล์บริการที่เหมือนกันเกือบหลายไฟล์เพื่อทำงานนี้ให้สำเร็จ อืมบางที เช่นเดียวกับเรื่องส่วนใหญ่ไม่มีเส้นแบ่งที่ชัดเจนที่แยกสิ่งเหล่านี้
pgoetz

@pgoetz config management ยังใหม่สำหรับฉัน แต่มันมีประโยชน์ถ้าคุณดูที่หัวข้อของคำถามนี้: ถ้าคุณดูผลลัพธ์ของการจัดการ config ทุกคนที่รู้ว่าไฟล์เซอร์วิส systemd จะเข้าใจ: ไฟล์เซอร์วิสธรรมดาและเรียบง่าย . ฉันคิดว่ามันเหมาะสมกว่าที่จะเรียนรู้และใช้ระบบจัดการการกำหนดค่าเนื่องจากสามารถใช้ความรู้สำหรับการกำหนดค่าทั้งหมดใน / etc ไม่ใช่แค่ systemd
guettli

คำตอบ:


47

ดีสมมติว่าเพียง แต่สิ่งที่เปลี่ยนแปลงต่อไฟล์หน่วยเป็นremote.example.comส่วนหนึ่งที่คุณสามารถใช้อินสแตนซ์ บริการ

จากsystemd.unitหน้าคน:

หน่วยอาจถูกอินสแตนซ์จากไฟล์เท็มเพลตเมื่อรันไทม์ สิ่งนี้อนุญาตให้สร้างหลายหน่วยจากไฟล์กำหนดค่าเดียว หาก systemd ค้นหาไฟล์การกำหนดค่าหน่วยมันจะค้นหาชื่อหน่วยตามตัวอักษรในระบบไฟล์ก่อน หากไม่ประสบความสำเร็จและชื่อหน่วยประกอบด้วยอักขระ "@" systemd จะค้นหาเทมเพลตหน่วยที่ใช้ชื่อเดียวกัน แต่ด้วยสตริงอินสแตนซ์ (เช่นส่วนที่อยู่ระหว่างอักขระ "@" และส่วนต่อท้าย) ตัวอย่าง: หากมีการร้องขอบริการ getty@tty3.service และไม่พบไฟล์ตามชื่อนั้น systemd จะค้นหา getty @ .service และสร้างอินสแตนซ์ของบริการจากไฟล์กำหนดค่านั้นหากพบ

โดยพื้นฐานแล้วคุณสร้างไฟล์หน่วยเดียวซึ่งมีตัวแปร (ปกติ%i) ซึ่งมีความแตกต่างเกิดขึ้นจากนั้นไฟล์จะถูกเชื่อมโยงเมื่อคุณ "เปิดใช้งาน" บริการนั้น

ตัวอย่างเช่นฉันมีไฟล์หน่วยเรียก/etc/systemd/system/autossh@.serviceว่ามีลักษณะเช่นนี้:

[Unit]
Description=AutoSSH service for ServiceABC on %i
After=network.target

[Service]
Environment=AUTOSSH_GATETIME=30 AUTOSSH_LOGFILE=/var/log/autossh/%i.log AUTOSSH_PIDFILE=/var/run/autossh.%i.pid
PIDFile=/var/run/autossh.%i.pid
#Type=forking
ExecStart=/usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC %i

[Install]
WantedBy=multi-user.target

ซึ่งฉันได้เปิดใช้งานแล้ว

[user@anotherhost ~]$ sudo systemctl enable autossh@somehost.example.com
ln -s '/etc/systemd/system/autossh@.service' '/etc/systemd/system/multi-user.target.wants/autossh@somehost.example.com.service'

และสามารถติดต่อกับ

[user@anotherhost ~]$ sudo systemctl start autossh@somehost.example.com
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
autossh@somehost.example.service - AutoSSH service for ServiceABC on somehost.example
   Loaded: loaded (/etc/systemd/system/autossh@.service; enabled)
   Active: active (running) since Tue 2015-10-20 13:19:01 EDT; 17s ago
 Main PID: 32524 (autossh)
   CGroup: /system.slice/system-autossh.slice/autossh@somehost.example.com.service
           ├─32524 /usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC somehost.example.com
           └─32525 /usr/bin/ssh -L 40000:127.0.0.1:40000 -R 40000:127.0.0.1:40001 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC somehost.example.com

Oct 20 13:19:01 anotherhost.example.com systemd[1]: Started AutoSSH service for ServiceABC on somehost.example.com.
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
autossh@somehost.example.com.service - AutoSSH service for ServiceABC on somehost.example.com
   Loaded: loaded (/etc/systemd/system/autossh@.service; enabled)
   Active: inactive (dead) since Tue 2015-10-20 13:24:10 EDT; 2s ago
  Process: 32524 ExecStart=/usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC %i (code=exited, status=0/SUCCESS)
 Main PID: 32524 (code=exited, status=0/SUCCESS)

Oct 20 13:19:01 anotherhost.example.com systemd[1]: Started AutoSSH service for ServiceABC on somehost.example.com.
Oct 20 13:24:10 anotherhost.example.com systemd[1]: Stopping AutoSSH service for ServiceABC on somehost.example.com...
Oct 20 13:24:10 anotherhost.example.com systemd[1]: Stopped AutoSSH service for ServiceABC on somehost.example.com.

ในขณะที่คุณสามารถมองเห็นทุกกรณีในแฟ้มหน่วยได้รับการแทนที่ด้วย%isomehost.example.com

มีตัวระบุเพิ่มเติมมากมายที่คุณสามารถใช้ในไฟล์หน่วยได้ แต่ฉันพบว่า%iทำงานได้ดีที่สุดในกรณีเช่นนี้


ว้าว systemd ยอดเยี่ยม
guettli

คุณไม่แสดงวิธีเริ่มโดยอัตโนมัติเมื่อเริ่มระบบรวมถึงวิธีที่จะเริ่มต้น
Craig Hicks

ด้วย Systemd การenableกระทำคือสิ่งที่ทำให้หน่วย / บริการเริ่มทำงานเมื่อเริ่มระบบ
GregL

ฉันสามารถเปิด / ปิดการใช้งานอินสแตนซ์ได้อย่างอิสระหรือไม่
Soumya Kanti

ใช่นั่นคือสิ่งที่คุณกำลังทำเมื่อคุณเปิด / ปิดการใช้งานพวกเขา
GregL

15

นี่คือตัวอย่างของไพ ธ อนซึ่งเป็นสิ่งที่ฉันกำลังมองหา @ในชื่อไฟล์บริการช่วยให้คุณสามารถเริ่มต้นกระบวนการ N:

$ cat /etc/systemd/system/my-worker@.service

[Unit]
Description=manages my worker service, instance %i
After=multi-user.target

[Service]
PermissionsStartOnly=true
Type=idle
User=root
ExecStart=/usr/local/virtualenvs/bin/python /path/to/my/script.py
Restart=always
TimeoutStartSec=10
RestartSec=10

วิธีการต่าง ๆ ที่จะเรียกมันว่า

การเปิดใช้งานการนับที่หลากหลายเช่น:

  • เปิดใช้งาน 30 คน:

    sudo systemctl enable my-worker\@{1..30}.service
    
  • เปิดใช้งาน 2 คน:

    sudo systemctl enable my-worker\@{1..2}.service
    

จากนั้นให้แน่ใจว่าได้โหลดซ้ำ:

sudo systemctl daemon-reload

ตอนนี้คุณสามารถเริ่ม / หยุดจากนั้นได้หลายวิธี:

  • เริ่ม 1:

    sudo systemctl start my-worker@2.service
    
  • เริ่มหลายรายการ:

    sudo systemctl start my-worker@{1..2}
    
  • หยุดหลายรายการ:

    sudo systemctl stop my-worker@{1..2}
    
  • ตรวจสอบสถานะ:

    sudo systemctl status my-worker@1
    

อัปเดต : หากต้องการจัดการอินสแตนซ์เป็นบริการเดียวคุณสามารถทำสิ่งนี้:

/etc/systemd/system/some-worker@.service:

[Unit]
Description=manage worker instances as a service, instance %i
Requires=some-worker.service
Before=some-worker.service
BindsTo=some-worker.service

[Service]
PermissionsStartOnly=true
Type=idle
User=root
#EnvironmentFile=/etc/profile.d/optional_envvars.sh
ExecStart=/usr/local/virtualenvs/bin/python /path/to/my/script.py
TimeoutStartSec=10
RestartSec=10

[Install]
WantedBy=some-worker.service

/usr/bin/some-worker-start.sh:

#!/bin/bash
systemctl start some-worker@{1..10}

/etc/systemd/system/some-worker.service:

[Unit]
Description=manages some worker instances as a service, instance

[Service]
Type=oneshot
ExecStart=/usr/bin/sh /usr/bin/some-worker-start.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

และตอนนี้คุณสามารถจัดการอินสแตนซ์ทั้งหมดได้ด้วย sudo systemctl some-worker (start|restart|stop)

นี่คือตัวอย่างสำเร็จรูปสำหรับคุณscript.py:

#!/usr/bin/env python

import logging


def worker_loop():
    shutdown = False
    while True:

        try:
            if shutdown:
                break

            # Your execution logic here.
            # Common logic - i.e. consume from a queue, perform some work, ack message
            print("hello world")

        except (IOError, KeyboardInterrupt):
            shutdown = True
            logging.info("shutdown received - processing will halt when jobs complete")
        except Exception as e:
            logging.exception("unhandled exception on shutdown. {}".format(e))


if __name__ == '__main__':
    worker_loop()

@radek: สองสิ่งที่ฉันไม่เข้าใจ: อันดับแรก% i ใช้ในคำอธิบายของไฟล์หน่วยเท่านั้น คำสั่ง start รู้ได้อย่างไรว่าจะเริ่มต้นอย่างไร ประการที่สองจะsystemctl some-worker (start|restart|stop)ทราบได้อย่างไรว่าอินสแตนซ์ใดที่ใช้งานได้
U. Windl

% i เป็นผลลัพธ์จาก @ ในชื่อของไฟล์บริการ Now you can start/stop then in various waysส่วนที่สองจะมีการอธิบายไว้แล้วในคำตอบให้ดู
radtek

ฉันคิดว่าคำตอบของเขาไม่สมบูรณ์หากไม่มีสคริปต์เข้ามาเกี่ยวข้อง "เวทมนต์" ส่วนใหญ่ทำในสคริปต์ที่ขาดหายไป
U. Windl

ฉันได้เตรียมวิธีแก้ปัญหาการทำงานเต็มรูปแบบที่นี่จริง ๆ แล้ว คุณอ้างถึง "สคริปต์" ใด /path/to/my/script.py สามารถเป็นอะไรก็ได้ที่คุณต้องการ "สวัสดีโลก" หากคุณต้องการ สิ่งที่จะยังคงทำงานต่อไปจนกว่าจะได้รับสัญญาณการฆ่า โปรดทราบว่าคำถามนี้ไม่เฉพาะเจาะจงกับงูหลาม
radtek

ว้าวมันช่วยให้คุณเริ่มทวีคูณในเวลาหรือไม่ ใจ
ปลื้ม

1

คำตอบของ GregL ช่วยฉันอย่างมาก นี่คือตัวอย่างของเทมเพลตหน่วยที่ฉันใช้ในรหัสของฉันโดยใช้ตัวอย่างด้านบนสำหรับเซิร์ฟเวอร์งานเกียร์แมน ฉันสร้างเชลล์สคริปต์ที่ให้ฉันสร้างจำนวน X ของ "คนงาน" โดยใช้เทมเพลตนี้

[Unit]
Description=az gearman worker
After=gearman-job-server.service

[Service]
PIDFile=/var/run/gearman_worker_az%i.pid
Type=simple
User=www-data
WorkingDirectory=/var/www/mysite.com/jobs/
ExecStart=/usr/bin/php -f gearman_worker_az.php > /dev/null 2>&1
Restart=on-success
KillMode=process

[Install]
WantedBy=multi-user.target
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.