ทำให้แอปพลิเคชัน Docker เขียนลงใน stdout


49

ฉันกำลังปรับใช้แอปพลิเคชันของบุคคลที่สามให้สอดคล้องกับคำแนะนำ 12 ปัจจัยและอย่างใดอย่างหนึ่งที่บอกว่าควรพิมพ์แอปพลิเคชันบันทึกไปยัง stdout / stderr: จากนั้นซอฟต์แวร์การจัดกลุ่มสามารถรวบรวมได้

อย่างไรก็ตามแอปพลิเคชันสามารถเขียนไปยังไฟล์หรือ syslog เท่านั้น ฉันจะพิมพ์บันทึกเหล่านี้ได้อย่างไร


พวกเขากำลังจะไป syslog คุณสามารถรับพวกเขาจากที่นั่น!
Michael Hampton

@MichaelHampton ดูเหมือนจะดี แต่ Docker มีกระบวนการเดียวที่สามารถเขียนถึง stdout ได้และฟังดูเหมือนจะรวมสองอย่างเข้าด้วยกันหรือไม่
kolypto

1
คุณสามารถมีกระบวนการภูตใช้ syslog และมีกระบวนการด้านหน้าที่พิมพ์?
qkrijger

@qkrijger จุดดี! ทีนี้ถ้าใครมีประสบการณ์กับมัน ... ?
kolypto

คำตอบ:


107

มีสูตรที่น่าทึ่งในnginx Dockerfile :

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

เพียงแค่แอปสามารถเขียนเป็นไฟล์ต่อไปได้ แต่ผลลัพธ์ก็จะไปที่stdout& stderr!


2
นี้. คือ. เพียงแค่ สุกใส และหลากหลาย
spacediver

11
สิ่งหนึ่งที่เป็นปัญหากับสิ่งนี้คือเมื่อสิ่งที่คุณกำลังเรียกใช้ยืนยันการฟอร์กตัวเองไปยังพื้นหลังเป็นกระบวนการที่ไม่ใช่รูท ฉันมีนี้กับและมันก็มีปัญหาเกี่ยวกับสิทธิ์ในsquid3 /dev/stdout
mikepurvis

4
วิธีนี้ใช้ไม่ได้ผลตัวอย่างเช่นหากแอปพลิเคชันพยายามค้นหาไฟล์โดยทั่วไปวิธีนี้จะใช้ไม่ได้
mixja

ลิงก์ไม่ทำงาน ...
Babken Vardanyan

4
ทุกอย่างเป็นไฟล์สำหรับผู้ชนะ
RubberDuck

16

ในอีกคำถามหนึ่งฆ่ากระบวนการลูกเมื่อผู้ปกครองออกจากฉันได้รับคำตอบที่ช่วยในการเรียงลำดับ

วิธีนี้เรากำหนดค่าโปรแกรมประยุกต์เพื่อที่จะบันทึกไปยังแฟ้มและต่อเนื่องtail -fมัน โชคดีที่tailสามารถยอมรับ--pid PID: มันจะออกเมื่อกระบวนการที่ระบุออกจาก เราใส่ที่$$นั่น: PID ของเชลล์ปัจจุบัน

ในขั้นตอนสุดท้ายแอปพลิเคชั่นที่เปิดตัวคือexec'ed ซึ่งหมายความว่าเชลล์ปัจจุบันจะถูกแทนที่ด้วยแอปพลิเคชันนั้นอย่างสมบูรณ์

สคริปต์ของ Runner run.shจะมีลักษณะเช่นนี้:

#! /usr/bin/env bash
set -eu

rm -rf /var/log/my-application.log
tail --pid $$ -F /var/log/my-application.log &

exec /path/to/my-application --logfile /var/log/my-application.log

หมายเหตุ: โดยการใช้tail -Fเราจะลิสต์ชื่อไฟล์และมันจะอ่านมันแม้ว่ามันจะปรากฏในภายหลัง!

ในที่สุด, Dockerfile เรียบง่าย:

FROM ubuntu
ADD run.sh /root/run.sh
CMD ['/root/run.sh']

หมายเหตุ: เพื่อหลีกเลี่ยงtail -fพฤติกรรมที่แปลกประหลาดบางอย่าง(ซึ่งบอกว่า "ถูกแทนที่ด้วยไฟล์รีโมตเลิกใช้ชื่อนี้") ฉันลองวิธีอื่น: ไฟล์บันทึกที่รู้จักทั้งหมดถูกสร้างขึ้น & ถูกตัดทอนเมื่อเริ่มต้น: วิธีนี้ฉันมั่นใจได้ว่า และหลังจากนั้นก็ให้ปิดมัน:

#! /usr/bin/env bash
set -eu

LOGS=/var/log/myapp/

( umask 0 && truncate -s0 $LOGS/http.{access,error}.log )
tail --pid $$ -n0 -F $LOGS/* &

exec /usr/sbin/apache2 -DFOREGROUND

โดยเฉพาะอย่างยิ่งสำหรับเซิร์ฟเวอร์ Apache ฉันใช้ไฟล์Piped ( httpd.apache.org/docs/2.4/logs.html#piped ) และดูเหมือนว่าจะใช้งานได้
php-coder

แก้ไขปัญหาที่คล้ายกันกับอัลไพน์และดูเหมือนว่าจะทำงานได้ดีบน BusyBox tailโดยไม่ต้อง --pid ตัวเลือก
Ryan

วิธีแก้ปัญหาใช้งานได้สำหรับฉัน มีประโยชน์มากขอบคุณ
Tamas Kalman

7

สำหรับกระบวนการพื้นหลังในคอนเทนเนอร์นักเทียบท่าเช่นการเชื่อมต่อกับ exec กับ / bin / bash ฉันสามารถใช้งานได้

echo "test log1" >> /proc/1/fd/1

สิ่งนี้ส่งเอาต์พุตไปที่ stdout ของ pid 1 ซึ่งเป็นหนึ่งในการเลือกนักเทียบท่า


นี่คือคำตอบที่ถูกต้อง บันทึกควรจะส่งไป stdout สำหรับ PID1 และหากใบสมัครของคุณกำลังทำงานภายใต้ PID อื่นก็จะมองไม่เห็นโดยหรือdocker logs kubectl logsฉันมีคอนเทนเนอร์ที่กำหนดเวลางานผ่าน crontab ซึ่งไม่ได้ทำงานเป็น PID1
leeman24

6

สำหรับ Nginx คุณสามารถได้nginx.confชี้ไป/dev/stderrและ/dev/stdoutเช่นนี้

user  nginx;
worker_processes  4;
error_log  /dev/stderr;
http {
    access_log  /dev/stdout  main;
...

และDockerfileรายการของคุณควรเป็น

/usr/sbin/nginx -g 'daemon off;'

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