วิธีการตั้งค่าตัวแปรสภาพแวดล้อมในบริการ systemd?


162

ฉันมีระบบArch Linux ที่มี systemdและฉันได้สร้างบริการของตัวเอง บริการกำหนดค่าที่/etc/systemd/system/myservice.serviceมีลักษณะดังนี้:

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

/bin/myforegroundcmdตอนนี้ผมต้องการที่จะมีการตั้งค่าตัวแปรสภาพแวดล้อมสำหรับ ฉันจะทำอย่างไร

คำตอบ:


197

การเปลี่ยนแปลงครั้งและทำแนวทางปฏิบัติที่ดีที่สุด

ปัจจุบันวิธีที่ดีที่สุดที่จะทำนี้คือการทำงานsystemctl edit myserviceซึ่งจะสร้างไฟล์แทนที่สำหรับคุณหรือให้คุณแก้ไขที่มีอยู่

ในการติดตั้งปกติสิ่งนี้จะสร้างไดเรกทอรี/etc/systemd/system/myservice.service.dและภายในไดเรกทอรีนั้นจะสร้างไฟล์ที่มีชื่อลงท้ายด้วย.conf(โดยทั่วไปoverride.conf) และในไฟล์นี้คุณสามารถเพิ่มหรือลบล้างส่วนใด ๆ ของหน่วยที่จัดส่งโดยการกระจาย

ตัวอย่างเช่นในไฟล์/etc/systemd/system/myservice.service.d/myenv.conf:

[Service]
Environment="SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN"
Environment="ANOTHER_SECRET=JP8YLOc2bsNlrGuD6LVTq7L36obpjzxd"

โปรดทราบด้วยว่าหากมีไดเรกทอรีอยู่และว่างเปล่าบริการของคุณจะถูกปิดใช้งาน! หากคุณไม่ต้องการใส่บางสิ่งในไดเรกทอรีให้แน่ใจว่าไม่มีอยู่


สำหรับการอ้างอิงวิธีเดิมคือ:

วิธีที่แนะนำการทำเช่นนี้คือการสร้างไฟล์ที่มีตัวแปรของคุณแล้วโหลดพวกเขาด้วย/etc/sysconfig/myserviceEnvironmentFile

สำหรับรายละเอียดทั้งหมดโปรดดูเอกสาร Fedora เกี่ยวกับวิธีการเขียนสคริปต์ systemd


4
ฉันเดาsysconfigเส้นทางนั้นเฉพาะกับ Fedora แต่คำถามเกี่ยวกับ Arch Linux คำตอบโดย paluh น่าสนใจยิ่งขึ้นฉันคิดว่า
Ludovic Kuty

1
/etc/sysconfigเฉพาะของ Fedora AFAIR Arch Linux ผลักดันให้มีไฟล์ปรับแต่งอยู่ที่ไหนสักแห่งเฉพาะแพคเกจแทนที่จะอยู่ใน/etcตำแหน่งเฉพาะของ Fedora เช่นเดียวกับการ/etc/myservice.confใช้ไฟล์พิเศษดูเหมือนจะไม่ถูกต้องที่นี่
MichałGórny

5
ไม่ไม่ไม่. / etc / sysconfig ไม่แนะนำให้ใช้ มันเป็นท้อแท้พร้อมกับ / etc / default / * จาก debian เพราะไม่มีจุดหมายและชื่อนั้นไม่มีความหมายและสมเหตุสมผลสำหรับเหตุผลด้านความเข้ากันได้เท่านั้น (/ etc / ทั้งหมดเป็นเรื่องเกี่ยวกับการกำหนดค่าของระบบไม่ใช่แค่ / etc / sysconfig และ / etc / defaults ใช้สำหรับการแทนที่ไม่ใช่ค่าเริ่มต้น) เพียงแค่ใส่คำจำกัดความโดยตรงในไฟล์หน่วยหรือถ้ามันเป็นไปไม่ได้ในไฟล์สภาพแวดล้อมที่มีสถานที่เฉพาะแพคเกจ (เช่นความคิดเห็นของMichałแนะนำ)
zbyszek

1
@FrederickNord เป็นเพียงตัวแปรคู่ = ค่าเช่นDJANGO_SETTINGS_MODULE=project.settingsหนึ่งรายการต่อบรรทัด
Michael Hampton

1
@MichaelHampton คุณช่วยเพิ่มลิงค์เอกสารสำหรับ "วิธีที่ดีที่สุดในปัจจุบัน" ได้ไหม?
jb

77

คำตอบขึ้นอยู่กับว่าตัวแปรควรจะเป็นค่าคงที่ (นั่นคือไม่ควรแก้ไขโดยผู้ใช้รับหน่วย) หรือตัวแปร (ควรตั้งค่าโดยผู้ใช้)

เนื่องจากเป็นหน่วยในพื้นที่ของคุณขอบเขตจึงค่อนข้างพร่ามัวและไม่ว่าจะด้วยวิธีใด อย่างไรก็ตามหากคุณเริ่มแจกจ่ายและจะสิ้นสุดลง/usr/lib/systemd/systemสิ่งนี้จะกลายเป็นเรื่องสำคัญ

ค่าคงที่

หากค่าไม่จำเป็นต้องเปลี่ยนแปลงตามอินสแตนซ์วิธีที่ต้องการจะวางไว้Environment=ในไฟล์หน่วยโดยตรง:

[Unit]
Description=My Daemon

[Service]
Environment="FOO=bar baz"
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

ข้อดีของการทำเช่นนั้นคือตัวแปรจะถูกเก็บไว้ในไฟล์เดียวกับหน่วย ดังนั้นไฟล์หน่วยจะง่ายต่อการย้ายระหว่างระบบ

ค่าตัวแปร

อย่างไรก็ตามโซลูชันข้างต้นใช้งานไม่ได้เมื่อ sysadmin ควรเปลี่ยนค่าของตัวแปรสภาพแวดล้อมแบบโลคัล โดยเฉพาะอย่างยิ่งจะต้องตั้งค่าใหม่ทุกครั้งที่มีการอัปเดตไฟล์หน่วย

สำหรับกรณีนี้ต้องใช้ไฟล์พิเศษ อย่างไร - มักจะขึ้นอยู่กับนโยบายการกระจาย

ทางออกหนึ่งที่น่าสนใจอย่างยิ่งคือการใช้/etc/systemd/system/myservice.service.dไดเรกทอรี ไม่เหมือนกับโซลูชันอื่น ๆ ไดเร็กทอรีนี้ได้รับการสนับสนุนโดย systemd เองและดังนั้นจึงไม่มีพา ธ เฉพาะการแจกจ่าย

ในกรณีนี้คุณวางไฟล์เช่น/etc/systemd/system/myservice.service.d/local.confนั้นเพิ่มส่วนที่ขาดหายไปของไฟล์หน่วย:

[Service]
Environment="FOO=bar baz"

หลังจากนั้น systemd จะรวมสองไฟล์เมื่อเริ่มบริการ (อย่าลืมsystemctl daemon-reloadหลังจากเปลี่ยนไฟล์ใดไฟล์หนึ่ง) และเนื่องจากเส้นทางนี้ถูกใช้โดยตรงโดย systemd คุณจึงไม่ได้ใช้EnvironmentFile=สิ่งนี้

หากค่าควรเปลี่ยนแปลงในระบบที่ได้รับผลกระทบบางระบบเท่านั้นคุณอาจรวมทั้งวิธีแก้ไขปัญหาโดยให้ค่าเริ่มต้นโดยตรงในหน่วยและการแทนที่แบบโลคัลในไฟล์อื่น


systemctl daemon-reloadคือคำสั่งให้โหลด systemd
Dmitry Buzolin

EnvironmentFile=จะดีกว่าเมื่อค่าเป็นความลับเช่นรหัสผ่าน ดูคำตอบของฉันสำหรับรายละเอียด
Don Kirkby


17

คำตอบของMichaelและMichałมีประโยชน์และตอบคำถามดั้งเดิมของวิธีการตั้งค่าตัวแปรสภาพแวดล้อมสำหรับบริการ systemd อย่างไรก็ตามการใช้งานทั่วไปอย่างหนึ่งสำหรับตัวแปรสภาพแวดล้อมคือการกำหนดค่าข้อมูลที่ละเอียดอ่อนเช่นรหัสผ่านในสถานที่ที่ไม่ตั้งใจโดยไม่ตั้งใจที่จะควบคุมแหล่งที่มาด้วยรหัสแอปพลิเคชันของคุณ

หากนั่นเป็นสาเหตุที่คุณต้องการส่งตัวแปรสภาพแวดล้อมไปยังบริการของคุณห้ามใช้Environment=ในไฟล์การกำหนดค่าหน่วย ใช้EnvironmentFile=และชี้ไปที่ไฟล์กำหนดค่าอื่นที่บัญชีบริการสามารถอ่านได้เท่านั้น (และผู้ใช้ที่มีสิทธิ์เข้าถึงรูท)

รายละเอียดของไฟล์การกำหนดค่าหน่วยจะปรากฏแก่ผู้ใช้ทุกคนด้วยคำสั่งนี้:

systemctl show my_service

ฉันใส่ไฟล์กำหนดค่าที่/etc/my_service/my_service.confและใส่ความลับไว้ที่นั่น:

MY_SECRET=correcthorsebatterystaple

จากนั้นในไฟล์หน่วยบริการฉันใช้EnvironmentFile=:

[Unit]
Description=my_service

[Service]
ExecStart=/usr/bin/python /path/to/my_service.py
EnvironmentFile=/etc/my_service/my_service.conf
User=myservice

[Install]
WantedBy=multi-user.target

ฉันจะตรวจสอบว่าps auxeไม่สามารถดูตัวแปรสภาพแวดล้อมเหล่านั้นและผู้ใช้อื่น ๆ /proc/*/environไม่ได้มีการเข้าถึง ตรวจสอบระบบของคุณเองแน่นอน


8

Michael ให้โซลูชันที่สะอาดหนึ่งวิธี แต่ฉันต้องการรับการปรับปรุงตัวแปร env จากสคริปต์ น่าเสียดายที่การเรียกใช้คำสั่ง bash ไม่สามารถทำได้ในไฟล์ systemd unit โชคดีที่คุณสามารถเปิดใช้ bash ใน ExecStart:

http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service&sect=5

โปรดทราบว่าการตั้งค่านี้ไม่สนับสนุนบรรทัดคำสั่งของเชลล์โดยตรง หากจำเป็นต้องใช้บรรทัดคำสั่ง shell พวกเขาจำเป็นต้องส่งผ่านไปยังการใช้งานเชลล์อย่างชัดเจน

ตัวอย่างในกรณีของเราคือ:

[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"

7
สิ่งนี้จะไม่ทำงานด้วยเหตุผลหลายประการ (เว้นแต่จะเป็นบริการ "one-shot" ซึ่งค่อนข้างไม่มีจุดหมาย) ฉันจัดการเพื่อให้ได้งานต่อไปนี้: /bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'. -aมั่นใจสภาพแวดล้อมที่มีการส่งออกไปยังกระบวนการย่อย (ยกเว้นกรณีที่คุณต้องการที่จะนำหน้าตัวแปรทั้งหมดในwhateverด้วยexport)
Otheus

ทำไมมันไม่ทำงาน มันควรทริกเกอร์คำสั่งทั้งหมดซึ่งรวมถึงการเรียกใช้สคริปต์ใช่หรือไม่
user1830432

อาจExecStart=/usr/bin/env ENV=script /bin/myforegroundcmdเป็นทางออกที่ดีกว่าเล็กน้อยในกรณีนี้
kstep

@Othus: คำตอบที่ดีบันทึกโดยวันเมื่อฉันต้องสร้างไฟล์ Tomcat 8 Unit
Daniel

1
มีวิธีเรียกใช้งานคำสั่ง bash "ใน" ไฟล์เซอร์วิส systemd ดูลิงค์นี้: coreos.com/os/docs/latest/…
Mark Lakata
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.