Dumb-Init는 Docker와 같은 최소 컨테이너 환경 내에서 PID 1으로 실행되도록 설계된 간단한 프로세스 관리자 및 Init 시스템입니다. C로 작성된 작은 정적으로 연결된 이진으로 배치됩니다.
경량 컨테이너는 SystemD 또는 Sysvinit과 같은 일반적인 Init 시스템없이 단일 프로세스 또는 서비스를 실행한다는 아이디어를 대중화했습니다. 그러나 INIT 시스템을 생략하면 종종 프로세스 및 신호를 잘못 처리 할 수 있으며 우아하게 멈출 수없는 컨테이너 또는 파괴되어야하는 컨테이너가 누출 될 수 있습니다.
dumb-init 사용하면 dumb-init 로 명령을 단순히 접두사 할 수 있습니다. 그것은 PID 1 역할을하며 즉시 자식 프로세스로 명령을 스폰하여 신호를 수신 할 때 적절하게 처리하고 전진하도록주의를 기울입니다.
일반적으로 Docker 컨테이너를 발사 할 때 실행중인 프로세스는 PID 1이되어 컨테이너의 초기 시스템이되는 기발한 책임과 책임을줍니다.
다음과 같은 두 가지 일반적인 문제가 있습니다.
대부분의 경우 신호는 제대로 처리되지 않습니다.
Linux 커널은 PID 1으로 실행되는 프로세스에 특수 신호 처리를 적용합니다.
프로세스가 일반적인 Linux 시스템에서 신호를 전송하면 커널은 먼저 해당 신호에 등록 된 프로세스가 해당 신호에 등록 된 사용자 지정 처리기를 확인하고 기본 동작 (예 : SIGTERM 에서 프로세스를 죽이는)으로 돌아갑니다.
그러나 신호를 수신하는 프로세스가 PID 1 인 경우 커널에 의해 특별한 처리를받습니다. 신호에 대한 핸들러를 등록하지 않은 경우 커널은 기본 동작으로 돌아 가지 않으며 아무 일도 일어나지 않습니다. 다시 말해, 프로세스가 이러한 신호를 명시 적으로 처리하지 않으면 SIGTERM 보내는 것은 전혀 영향을 미치지 않습니다.
일반적인 예는 docker run my-container script CI 작업입니다. docker run Process에 SIGTERM 보내면 일반적으로 docker run 명령을 죽이지 만 컨테이너는 백그라운드에 실행됩니다.
고아 좀비 프로세스는 제대로 거두지 않습니다.
프로세스는 종료 될 때 좀비가되고 부모가 wait() 시스템 호출의 변형을 호출 할 때까지 좀비로 남아 있습니다. 프로세스 테이블에 "소멸 된"프로세스로 남아 있습니다. 일반적으로 부모 프로세스는 즉시 wait() 호출하고 오래 살아있는 좀비를 피합니다.
부모가 자녀보다 먼저 나가면 자녀는 "고아"이며 PID 1에 따라 다시 부모가됩니다. 따라서 Init 시스템은 고아 좀비 프로세스에서 wait() -ing을 담당합니다.
물론, 대부분의 프로세스는 그들에게 붙어있는 임의의 프로세스에서 wait() 않으므로 컨테이너는 종종 PID 1에 뿌리를 둔 수십 개의 좀비로 끝납니다.
dumb-init 일 dumb-init PID 1으로 실행되며 간단한 Init 시스템처럼 작동합니다. 단일 프로세스를 시작한 다음 해당 아동 프로세스에 루팅 된 세션에 수신 된 신호를 프록시합니다.
실제 프로세스는 더 이상 PID 1이 아니기 때문에 dumb-init 로부터 신호를받을 때 기본 신호 처리기가 적용되며 예상대로 프로세스가 작동합니다. 프로세스가 사라지면 dumb-init 도 죽을 것이며 여전히 남아있는 다른 프로세스를 정리하기 위해주의를 기울일 것입니다.
기본 모드에서 dumb-init 아동에 루팅 된 세션을 설정하고 전체 프로세스 그룹에 신호를 보냅니다. 이것은 죽기 전에 자녀에게 일반적으로 신호를 보내지 않는 잘 작동하지 않는 아이 (예 : 쉘 스크립트)가있는 경우 유용합니다.
이것은 실제로 Deomontools와 같은 일반 프로세스 감독자 또는 쉘 스크립트를 감독하기위한 Supervisord에서 Docker 컨테이너 외부에서 유용 할 수 있습니다. 일반적으로 쉘에 의해 수신 된 SIGTERM 와 같은 신호는 하위 프로세스로 전달되지 않습니다. 대신 쉘 프로세스 만 죽습니다. Dumb-init를 사용하면 Shebang에서 Dumb-init로 쉘 스크립트를 쓸 수 있습니다.
#!/usr/bin/dumb-init /bin/sh
my-web-server & # launch a process in the background
my-other-server # launch another process in the foreground
일반적으로 껍질로 전송 된 SIGTERM 너는 쉘을 죽일 것이지만 그 과정을 실행합니다 (배경과 전경 모두). Dumb-Init를 사용하면 하위 프로세스가 쉘이하는 것과 동일한 신호를받습니다.
신호가 직접 자식으로 만 보내 지려면 --single-child 인수로 달리거나 dumb-init 실행할 때 환경 변수 DUMB_INIT_SETSID=0 설정할 수 있습니다. 이 모드에서 Dumb-init는 완전히 투명합니다. 당신은 심지어 여러 개의 끈을 함께 묶을 수도 있습니다 ( dumb-init dumb-init echo 'oh, hi' ).
Dumb-init을 사용하면 들어오는 신호를 다시 작성하기 전에 신호를 다시 작성할 수 있습니다. 이것은 항상 표준 신호 (예 : sigterm)를 보내는 Docker Supervisor (Mesos 또는 Kubernetes와 같은)가있는 경우에 유용합니다. 일부 앱은 우아한 정리를 위해 다른 정지 신호가 필요합니다.
예를 들어, 신호 sigterm (번호 15)을 sigquit (번호 3)로 다시 작성하려면 명령 줄에 --rewrite 15:3 추가하십시오.
신호를 완전히 삭제하려면 특수 번호 0 으로 다시 쓸 수 있습니다.
SetSID 모드에서 실행될 때 대부분의 경우 SIGTSTP / SIGTTIN / SIGTTOU 전달하는 것으로 충분하지 않습니다. 프로세스가 이러한 신호에 대한 사용자 정의 신호 처리기를 추가하지 않으면 커널은 기본 신호 처리 동작 (프로세스가 현탁 될 것)을 적용하지 않기 때문입니다. 이러한 이유로, 우리는이 세 가지 신호에서 기본 재 작성을 SIGSTOP 로 설정했습니다. 원하는 경우 신호를 원래 값으로 다시 작성 하여이 동작을 선택하지 못할 수 있습니다.
이 기능의 한 가지주의 사항 : 작업 제어 신호 ( SIGTSTP , SIGTTIN , SIGTTOU )의 경우 Dumb-init은 다른 것으로 다시 작성하더라도 신호를 수신 한 후에는 항상 스스로 중단됩니다.
dumb-init 사용할 수있는 몇 가지 옵션이 있습니다.
많은 인기있는 Linux 배포판 (Debian ( stretch 이후) 및 Ubuntu와 같은 데비안 파생 상품 ( bionic 이후)에는 이제 공식 리포지토리에 멍청한 패키지가 포함되어 있습니다.
데비안 기반 배포에서는 다른 패키지를 설치하는 것처럼 apt install dumb-init 실행하여 Dumb-init를 설치할 수 있습니다.
참고 : Dumb-Init의 대부분의 배포판 버전은 우리가 제공하는 버전과 달리 정적으로 연결되어 있지 않습니다 (아래의 다른 옵션 참조). 이것은 일반적으로 완벽하게 괜찮지 만, 이러한 버전의 Dumb-init은 일반적으로 우리가 제공하는 정적으로 연결된 버전과 달리 다른 Linux 배포판에 복사 할 때 작동하지 않음을 의미합니다.
내부 APT 서버가있는 경우 .deb 서버에 업로드하는 것이 dumb-init 사용하는 권장 방법입니다. Dockerfiles에서는 단순히 apt install dumb-init 수 있으며 사용할 수 있습니다.
데비안 패키지는 github 릴리스 탭에서 제공되거나 make builddeb 직접 실행할 수 있습니다.
.deb 패키지 설치 수동 (Debian/Ubuntu) 내부 APT 서버가없는 경우 dpkg -i 사용하여 .deb 패키지를 설치할 수 있습니다. 컨테이너에 .deb 을 얻는 방법을 선택할 수 있습니다 (디렉토리를 장착하거나 wget -ing은 옵션입니다).
한 가지 가능성은 Dockerfile의 다음 명령에 관한 것입니다.
RUN wget https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_amd64.deb
RUN dpkg -i dumb-init_*.debDumb-Init는 정적으로 연결된 이진으로 출시되므로 일반적으로 이미지에 넣을 수 있습니다. 다음은 dockerfile에서 그것을 수행하는 예입니다.
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64
RUN chmod +x /usr/local/bin/dumb-init dumb-init 완전히 C로 작성되었지만 이진을 컴파일하고 설치하는 파이썬 패키지도 제공합니다. pip 사용하여 PYPI에서 설치할 수 있습니다. 먼저 C 컴파일러를 설치하고 싶을 것입니다 (Debian/Ubuntu에서 apt-get install gcc pip install dumb-init 합니다).
1.2.0 기준으로 PYPI의 패키지는 사전 구축 된 휠 아카이브로 제공되며 일반적인 Linux 배포판에서 컴파일 할 필요가 없습니다.
Docker 컨테이너 내부에 설치되면 명령을 dumb-init 로 접두사로 접두사하십시오 (권장 JSON 구문을 사용하고 있는지 확인하십시오).
Dockerfile 내에서 Dumbinit을 컨테이너의 EntryPoint로 사용하는 것이 좋습니다. "EntryPoint"는 CMD 명령에 미래화되는 부분 명령으로, Dumb-init에 매우 적합합니다.
# Runs "/usr/bin/dumb-init -- /my/script --with --args"
ENTRYPOINT [ "/usr/bin/dumb-init" , "--" ]
# or if you use --rewrite or other cli flags
# ENTRYPOINT ["dumb-init", "--rewrite", "2:3", "--"]
CMD [ "/my/script" , "--with" , "--args" ] 기본 이미지에서 EntryPoint를 선언하는 경우, 그 내려 오는 이미지도 멍청한 것을 선언 할 필요가 없습니다. 평소와 같이 CMD 설정할 수 있습니다.
대화식 일회용 사용을 위해서는 수동으로 전부 할 수 있습니다.
$ docker run my_container dumb-init python -c 'while True: pass'
dumb-init 없이도 동일한 명령을 실행하면 SIGKILL 없이 컨테이너를 멈출 수 없지만 dumb-init 의 경우 SIGTERM 같은 더 많은 인도 신호를 보낼 수 있습니다.
CMD 및 ENTRYPOINT 에는 JSON 구문을 사용하는 것이 중요합니다. 그렇지 않으면 Docker는 명령을 실행하기 위해 쉘을 호출하여 껍질을 멍청한 대신 PID 1으로 만듭니다.
종종 컨테이너는 빌드 시간 동안 수행 할 수없는 사전 시작 작업을 원합니다. 예를 들어 환경 변수를 기반으로 일부 구성 파일을 템플릿을 제시 할 수 있습니다.
이를 Dumbinit과 통합하는 가장 좋은 방법은 다음과 같습니다.
ENTRYPOINT [ "/usr/bin/dumb-init" , "--" ]
CMD [ "bash" , "-c" , "do-some-pre-start-thing && exec my-server" ]아직도 멍청한 부분을 EntryPoint로 사용하면 항상 적절한 Init 시스템이 있습니다.
Bash 명령의 exec 부분은 Bash 프로세스를 서버로 대체하므로 쉘이 처음에는 순간적으로 만 존재하기 때문에 중요합니다.
멍청한 바이너리를 구축하려면 작업 컴파일러와 LIBC 헤더 및 기본값이 Glibc에 필요합니다.
$ make
정적으로 컴파일 된 멍청한 멍청한 놈은 glibc로 인해 700kb 이상이지만 이제 무슬림이 옵션입니다. Debian/Ubuntu apt-get install musl-tools 다음 :
$ CC=musl-gcc make
무슬림으로 정적으로 컴파일하면 이진 크기는 약 20kb입니다.
우리는 빌드 의존성을 지정하기 위해 표준 데비안 컨벤션을 사용합니다 ( debian/control 보면). 시작하는 쉬운 방법은 apt-get install build-essential devscripts equivs 다음 sudo mk-build-deps -i --remove 설치하여 누락 된 빌드 의존성을 자동으로 설치하는 것입니다. 그런 다음 make builddeb 사용하여 Dumb-init 데비안 패키지를 만들 수 있습니다.
Docker를 사용하여 자동 데비안 패키지 빌드를 선호하는 경우 make builddeb-docker 실행하십시오. 이것은 더 쉽지만 Docker를 컴퓨터에서 실행해야합니다.