Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 3143 – 표준 데몬 프로세스 라이브러리

Author:
Ben Finney <ben+python at benfinney.id.au>
Status:
Deferred
Type:
Standards Track
Created:
26-Jan-2009
Python-Version:
3.x
Post-History:


Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

올바르게 동작하는 Unix 데몬이 될 프로그램을 작성하는 일은 다소 복잡하고 제대로 구현하기 까다롭지만, 프로그램이 그 밖에 무엇을 해야 하는지와 관계없이 데몬마다 단계는 대체로 유사합니다.

이 PEP는 데몬 프로세스가 되는 작업에 간단한 인터페이스를 제공하는 패키지를 Python 표준 라이브러리에 도입합니다.

PEP 보류

이 PEP에서 다루는 개념에 대한 추가 검토는 PEP의 목표를 추진하고 피드백을 수집·반영하는 데 관심이 있는 현재의 담당자와 이를 효과적으로 수행할 수 있는 충분한 시간이 없기 때문에 보류되었습니다.

사양

사용 예

직접 DaemonContext를 사용하는 간단한 예:

import daemon

from spam import do_main_program

with daemon.DaemonContext():
    do_main_program()

더 복잡한 사용 예:

import os
import grp
import signal
import daemon
import lockfile

from spam import (
    initial_program_setup,
    do_main_program,
    program_cleanup,
    reload_program_config,
    )

context = daemon.DaemonContext(
    working_directory='/var/lib/foo',
    umask=0o002,
    pidfile=lockfile.FileLock('/var/run/spam.pid'),
    )

context.signal_map = {
    signal.SIGTERM: program_cleanup,
    signal.SIGHUP: 'terminate',
    signal.SIGUSR1: reload_program_config,
    }

mail_gid = grp.getgrnam('mail').gr_gid
context.gid = mail_gid

important_file = open('spam.data', 'w')
interesting_file = open('eggs.data', 'w')
context.files_preserve = [important_file, interesting_file]

initial_program_setup()

with context:
    do_main_program()

인터페이스

새로운 daemon 패키지가 표준 라이브러리에 추가됩니다.

데몬 프로세스로 실행되는 프로그램의 설정과 프로세스 컨텍스트를 나타내도록 DaemonContext 클래스가 정의됩니다.

DaemonContext 객체

DaemonContext 인스턴스는 프로그램이 데몬이 될 때의 동작 설정과 프로세스 컨텍스트를 나타냅니다. open 메서드를 호출하기 전에 인스턴스에서 옵션을 설정하여 동작과 환경을 사용자 지정합니다.

각 옵션은 DaemonContext 생성자에 키워드 인자로 전달하거나, open을 호출하기 전 언제든지 인스턴스의 특성에 할당하여 이후에 변경할 수 있습니다. 즉, wibblewubble이라는 옵션의 경우 다음 호출은:

foo = daemon.DaemonContext(wibble=bar, wubble=baz)
foo.open()

다음과 동등합니다.:

foo = daemon.DaemonContext()
foo.wibble = bar
foo.wubble = baz
foo.open()

다음 옵션이 정의됩니다.

files_preserve
Default:
None

데몬을 시작할 때 닫히지 않아야 하는 파일 목록입니다. None이면 열려 있는 모든 파일 디스크립터가 닫힙니다.

목록의 요소는 파일 객체의 fileno() 메서드가 반환하는 파일 디스크립터 또는 Python file 객체입니다. 각 요소는 데몬을 시작하는 동안 닫지 않을 파일을 지정합니다.

chroot_directory
Default:
None

프로세스의 유효 루트 디렉터리로 설정할 디렉터리의 전체 경로입니다. None이면 루트 디렉터리를 변경하지 않도록 지정합니다.

working_directory
Default:
'/'

데몬을 시작할 때 프로세스가 변경해야 하는 작업 디렉터리의 전체 경로입니다.

프로세스의 현재 작업 디렉터리가 파일 시스템에 있으면 해당 파일 시스템을 마운트 해제할 수 없으므로, 기본값을 그대로 두거나 데몬이 실행되는 동안 사용할 적절한 “홈 디렉터리”인 디렉터리로 설정해야 합니다.

umask
Default:
0

데몬 시작 시 프로세스에 설정할 파일 접근 생성 마스크(“umask”)입니다.

프로세스는 부모 프로세스에서 umask를 상속하므로, 데몬을 시작하면 umask가 이 값으로 재설정되어 데몬이 예상하는 접근 모드로 파일을 생성합니다.

pidfile
Default:
None

PID 잠금 파일을 위한 컨텍스트 관리자입니다. 데몬 컨텍스트가 열리고 닫힐 때 pidfile 컨텍스트 관리자에 진입하고 종료합니다.

detach_process
Default:
None

True인 경우 데몬 컨텍스트를 열 때 프로세스 컨텍스트를 분리하고, False인 경우 분리하지 않습니다.

인스턴스 초기화 중 지정되지 않은 경우(None), 기본적으로 True로 설정되며, 프로세스 분리가 불필요하다고 판단되는 경우에만 False로 설정됩니다. 예를 들어 프로세스가 init, initd또는 inetd에 의해 시작된 경우입니다.

signal_map
Default:
system-dependent

운영 체제 시그널에서 콜백 동작으로의 매핑입니다.

이 매핑은 데몬 컨텍스트가 열릴 때 사용되며 각 시그널의 시그널 핸들러에 대한 동작을 결정합니다.

  • None값은 시그널 동작을 signal.SIG_IGN으로 설정하여 해당 시그널을 무시합니다.
  • 문자열 값은 DaemonContext 인스턴스의 속성 이름으로 사용됩니다. 해당 속성의 값이 시그널 핸들러의 동작으로 사용됩니다.
  • 그 밖의 값은 시그널 핸들러의 동작으로 사용됩니다.

기본값은 실행 중인 시스템에 어떤 시그널이 정의되어 있는지에 따라 달라집니다. 아래 목록에서 시그널이 signal 모듈에 실제로 정의되어 있는 각 항목이 기본 매핑에 포함됩니다.

  • signal.SIGTTIN: None
  • signal.SIGTTOU: None
  • signal.SIGTSTP: None
  • signal.SIGTERM: 'terminate'

프로그램이 자식 프로세스와 상호 작용하는 방식에 따라, 자식 프로세스가 종료될 때 수신되는 signal.SIGCHLD 시그널을 포함하는 시그널 매핑을 지정해야 할 수 있습니다. 시그널 핸들러가 필요한 상황을 판단하는 방법에 관한 자세한 내용은 해당 운영 체제의 문서를 참조하십시오.

uid
Default:
os.getuid()
gid
Default:
os.getgid()

데몬 시작 시 프로세스를 전환할 사용자 ID(“UID”) 값과 그룹 ID(“GID”) 값입니다.

기본값인 프로세스의 실제 UID 및 GID는 프로세스가 상속한 유효 권한 상승을 모두 포기하게 합니다.

prevent_core
Default:
True

참이면 root로 실행되는 데몬에서 민감한 정보가 유출되지 않도록 코어 파일 생성을 방지합니다.

stdin
Default:
None
stdout
Default:
None
stderr
Default:
None

stdin, stdout, stderr각각은 표준 I/O 스트림 sys.stdin, sys.stdout, sys.stderr각각의 새 파일로 사용될 파일과 유사한 객체입니다. 따라서 파일은 열려 있어야 하며, stdin의 경우 최소 모드 ‘r’이어야 하고, stdoutstderr의 경우 모드 ‘w+’이어야 합니다.

객체에 파일 디스크립터를 반환하는 fileno()메서드가 있으면, 해당 파일은 데몬 시작 중 닫히지 않도록 제외됩니다(즉, files_preserve에 나열된 것처럼 처리됩니다).

None인 경우 해당 시스템 스트림은 os.devnull이라는 이름의 파일에 다시 바인딩됩니다.

다음 메서드가 정의됩니다.

open()
Return:
None

데몬 컨텍스트를 열어 현재 프로그램을 데몬 프로세스로 전환합니다. 다음 단계를 수행합니다.

  • 이 인스턴스의 is_open속성이 참이면 즉시 반환합니다. 이렇게 하면 한 인스턴스에서 open을 여러 번 호출해도 안전합니다.
  • prevent_core속성이 참이면 프로세스의 리소스 제한을 설정하여 프로세스에서 코어 덤프가 생성되지 않도록 합니다.
  • chroot_directory속성이 None이 아니면, 프로세스의 유효 루트 디렉터리를 해당 디렉터리로 설정합니다(os.chroot를 사용합니다).

    이를 통해 프로세스가 시스템을 악의적인 동작에 노출하는 것을 제한하는 수단으로 데몬 프로세스를 “chroot gaol” 내부에서 실행할 수 있습니다. 지정된 디렉터리는 이 목적에 맞게 미리 설정되어 있어야 합니다.

  • 프로세스 UID와 GID를 uidgid속성 값으로 설정합니다.
  • 열려 있는 모든 파일 디스크립터를 닫습니다. 단, files_preserve속성에 나열된 것과 stdin, stdout, stderr속성에 해당하는 것은 제외됩니다.
  • 현재 작업 디렉터리를 working_directory속성으로 지정된 경로로 변경합니다.
  • 파일 접근 생성 마스크를 umask속성으로 지정된 값으로 재설정합니다.
  • detach_process옵션이 참이면 현재 프로세스를 자체 프로세스 그룹으로 분리하고 제어 터미널과의 연결을 해제합니다.
  • signal_map속성에 지정된 대로 신호 처리기를 설정합니다.
  • stdin, stdout, stderr속성 중 하나라도 None이 아니면, 시스템 스트림 sys.stdin, sys.stdout및/또는 sys.stderr를 해당 속성으로 표현되는 파일에 바인딩합니다. 속성에 파일 디스크립터가 있는 경우 이름을 다시 바인딩하는 대신 디스크립터를 복제합니다.
  • pidfile속성이 None이 아니면 해당 컨텍스트 관리자에 진입합니다.
  • 이 인스턴스를 열림 상태로 표시합니다(이후 openclose호출을 위한 것입니다).
  • Python의 종료 처리 중에 호출되도록 close메서드를 등록합니다.

함수가 반환되면 실행 중인 프로그램은 데몬 프로세스가 됩니다.

close()
Return:
None

데몬 컨텍스트를 닫습니다. 다음 단계를 수행합니다.

  • 이 인스턴스의 is_open속성이 거짓이면 즉시 반환합니다. 이렇게 하면 한 인스턴스에서 close를 여러 번 호출해도 안전합니다.
  • pidfile 특성이 None이 아니면 해당 컨텍스트 관리자에서 나갑니다.
  • 이 인스턴스를 닫힌 상태로 표시합니다(향후 openclose 호출을 위한 목적입니다).
is_open
Return:
True if the instance is open, False otherwise.

이 속성은 인스턴스가 현재 열려 있는지를 나타내는 상태를 노출합니다. 인스턴스의 open 메서드가 호출되었고 이후 close 메서드가 호출되지 않았으면 True입니다.

terminate(signal_number, stack_frame)
Return:
None

signal.SIGTERM 신호의 신호 처리기입니다. 다음 단계를 수행합니다:

  • 신호를 설명하는 SystemExit 예외를 발생시킵니다.

이 클래스는 __enter____exit__ 메서드를 통해 컨텍스트 관리자 프로토콜도 구현합니다.

__enter__()
Return:
The DaemonContext instance

인스턴스의 open() 메서드를 호출한 다음 인스턴스를 반환합니다.

__exit__(exc_type, exc_value, exc_traceback)
Return:
True or False as defined by the context manager 프로토콜

인스턴스의 close() 메서드를 호출한 다음 예외가 처리되었으면 True를, 처리되지 않았으면 False를 반환합니다.

동기

Unix 데몬으로 작성된 프로그램 대부분은 Specification에 있는 것과 매우 유사한 동작을 구현하거나, Correct daemon behaviour에 비추어 잘못 동작하는 데몬입니다.

이러한 단계는 대부분 구현에서 거의 같아야 하지만 매우 구체적이고 누락하거나 잘못 구현하기 쉽기 때문에, 표준 라이브러리에서 표준적이고 충분히 테스트된 구현의 주요 대상입니다.

근거

올바른 데몬 동작

Stevens가 [stevens] §2.6에서 설명한 바에 따르면, 프로그램이 Unix 데몬 프로세스가 되려면 다음 단계를 수행해야 합니다.

  • 모든 열린 파일 디스크립터를 닫습니다.
  • 현재 작업 디렉터리를 변경합니다.
  • 파일 접근 생성 마스크를 재설정합니다.
  • 백그라운드에서 실행합니다.
  • 프로세스 그룹과의 연결을 해제합니다.
  • 터미널 I/O 신호를 무시합니다.
  • 제어 터미널과의 연결을 해제합니다.
  • 제어 터미널을 다시 획득하지 않습니다.
  • 다음 상황을 올바르게 처리합니다:
    • System V init 프로세스에 의해 시작됩니다.
    • SIGTERM 신호에 의한 데몬 종료.
    • 자식 프로세스가 SIGCLD 신호를 생성합니다.

daemon 도구 [slack-daemon]는 (기능 요약에서) 프로그램을 올바르게 동작하는 Unix 데몬 프로세스로 전환할 때 수행해야 하는 동작을 나열합니다. 이 PEP의 의도와 다른 점은 별도의 프로그램을 데몬 프로세스로 호출한다는 것입니다. 다음 기능은 프로그램이 이미 실행 중일 때 스스로 시작하는 데몬에 적합합니다:

  • 데몬에 올바른 프로세스 컨텍스트를 설정합니다.
  • initd(8) 또는 inetd(8)에 의해 시작될 때 합리적으로 동작합니다.
  • 데몬이 특수 권한으로 잘못 설치된 경우의 보안 위험을 줄이기 위해 suid 또는 sgid 권한을 취소합니다.
  • root로 실행되는 데몬에서 민감한 정보가 유출되는 것을 방지하기 위해 코어 파일 생성을 방지합니다(선택 사항).
  • PID 파일을 생성하고 잠가 데몬의 이름을 지정하며, 주어진 이름의 데몬은 언제든 하나만 실행될 수 있도록 보장합니다(선택 사항).
  • 데몬을 실행할 사용자와 그룹을 설정합니다(선택 사항, root만 해당).
  • chroot 감옥을 생성합니다(선택 사항, root만 해당).
  • 데몬의 stdout과 stderr을 캡처하여 syslog로 보냅니다(선택 사항).

데몬은 서비스가 아닙니다.

이 PEP는 위의 올바른 동작이 관련되는 Unix 스타일 데몬만 다루며, 다른 운영 체제의 유사한 동작은 다루지 않습니다.

여러 시스템에는 “서비스”라고 하는 관련 개념이 있습니다. 서비스는 이 PEP의 모델과 다릅니다. 현재 프로그램이 데몬 프로세스로 계속 실행되도록 하는 대신, 서비스는 백그라운드에서 실행할 추가 프로세스를 시작하며, 현재 프로세스는 정의된 일부 채널을 통해 해당 추가 프로세스와 통신합니다.

이 PEP의 Unix 스타일 데몬 모델은 여러 용도 중에서도 서비스의 백그라운드 프로세스 부분을 구현하는 데 사용할 수 있지만, 이 PEP는 서비스를 설정하고 관리하는 다른 측면은 다루지 않습니다.

참조 구현

python-daemon 패키지 [python-daemon].

기타 데몬 구현

이 PEP 이전에도 여러 기존 서드파티 Python 라이브러리 또는 도구가 이 PEP의 Correct daemon behaviour 일부를 구현했습니다.

Reference Implementation은 다음 구현에서 상당 부분 직접 계승되었습니다.

이 PEP와 다른 기타 Python 데몬 구현:

  • zdaemon 도구 [zdaemon]는 Zope 프로젝트를 위해 작성되었습니다. [slack-daemon]와 마찬가지로, 다른 프로그램을 데몬 프로세스로 실행하는 데 사용되므로 이 사양과 다릅니다.
  • Python 라이브러리 daemon은 홈페이지에 따르면 더 이상 유지 관리되지 않습니다. 버전 1.0.1부터 [stevens]의 기본 단계를 구현합니다.
  • daemonize 라이브러리 [seutter-daemonize][stevens]의 기본 단계를 구현합니다.
  • Ray Burr의 daemon.py 모듈 [burr-daemon][stevens]절차와 PID 파일 처리 및 출력을 syslog로 리디렉션하는 기능을 제공합니다.
  • Twisted [twisted]는 예상할 수 있듯이, 나머지 Twisted 프레임워크와 통합된 프로세스 데몬화 API의 구현을 포함하며, 이 PEP의 API와는 상당히 다릅니다.
  • Python initd 라이브러리 [dagitses-initd][clapper-daemon]를 사용하며, 데몬 프로세스를 제어하기 위한 유닉스 initd(8)에 해당하는 기능을 구현합니다.

참고 문헌

[stevens] (1, 2, 3, 4)
Unix Network Programming, W. Richard Stevens, 1994 Prentice Hall.
[slack-daemon] (1, 2)
The (non-Python) “libslack” implementation of a daemon tool http://www.libslack.org/daemon/ by “raf” <raf@raf.org>.
[python-daemon] (1, 2)
The python-daemon library http://pypi.python.org/pypi/python-daemon/ by Ben Finney et al.
[cookbook-66012] (1, 2)
Python Cookbook recipe 66012, “Fork a daemon process on Unix” http://code.activestate.com/recipes/66012/.
[cookbook-278731]
Python Cookbook recipe 278731, “Creating a daemon the Python way” http://code.activestate.com/recipes/278731/.
[bda.daemon]
The bda.daemon library http://pypi.python.org/pypi/bda.daemon/ by Robert Niederreiter et al.
[zdaemon]
The zdaemon tool http://pypi.python.org/pypi/zdaemon/ by Guido van Rossum et al.
[clapper-daemon]
The daemon library http://pypi.python.org/pypi/daemon/ by Brian Clapper.
[seutter-daemonize]
The daemonize library http://daemonize.sourceforge.net/ by Jerry Seutter.
[burr-daemon]
The daemon.py module http://www.nightmare.com/~ryb/code/daemon.py by Ray Burr.
[twisted]
The Twisted application framework http://pypi.python.org/pypi/Twisted/ by Glyph Lefkowitz et al.
[dagitses-initd]
The Python initd library http://pypi.python.org/pypi/initd/ by Michael Andreas Dagitses.