서비스를 시작한 후 Docker 컨테이너를 계속 실행하는 방법은 무엇입니까?


156

내가하려고하는 것과 똑같은 일을하는 많은 자습서를 보았지만 어떤 이유로 Docker 컨테이너가 종료됩니다. 기본적으로 Docker 컨테이너 안에 웹 서버와 몇 가지 데몬을 설정하고 있습니다. run-all.shDockerfile에서 CMD를 통해 실행 되는 bash 스크립트를 통해 마지막 부분을 수행합니다 . run-all.sh다음과 같이 보입니다 :

service supervisor start
service nginx start

그리고 다음과 같이 Dockerfile 내에서 시작합니다.

CMD ["sh", "/root/credentialize_and_run.sh"]

수동으로 작업을 실행할 때 서비스가 모두 올바르게 시작되는 것을 볼 수 있습니다 (예 : -i -t / bin / bash를 사용하여 이미지에 가져 오기). 이미지를 실행할 때 모든 것이 올바르게 실행되는 것처럼 보이지만 한 번 종료됩니다. 프로세스 시작을 마칩니다. 프로세스가 무기한으로 실행되기를 원하며 이해하는 한 컨테이너가 계속 실행되어야합니다. 그럼에도 불구하고을 실행 docker ps -a하면 다음을 볼 수 있습니다.

➜  docker_test  docker ps -a
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS                      PORTS               NAMES
c7706edc4189        some_name/some_repo:blah   "sh /root/run-all.sh   8 minutes ago       Exited (0) 8 minutes ago                        grave_jones

무엇을 제공합니까? 왜 종료 되나요? bash 스크립트 끝에 while 루프를 배치하여 유지할 수 있다는 것을 알고 있지만 종료하지 못하게하는 올바른 방법은 무엇입니까?


1
서비스 포트를 외부에 노출하고 있습니까 (-p 옵션을 docker run)? (물론 이것이 종료되는 것을 막지는 못할 것입니다)
ribamar

1
Dockerfile에서 ENTRYPOINT를 사용하고 있었고 ENTRYPOINT (내 init 스크립트)에 정의 된 스크립트가 실행 된 후 로그에 표시되었지만 컨테이너가 종료 된 것 같습니다. 따라서 ENTRYPOINT 대신 RUN 명령을 사용하여 스크립트를 실행했으며 컨테이너가 여전히 백그라운드에서 실행 중입니다.
ypahalajani

답변:


50

이것이 실제로 Docker 컨테이너를 디자인하는 방법이 아닙니다.

도커 컨테이너를 설계 할 때, 당신은이 같은에만이 있음을 구축하는데있어 하나의 실행중인 프로세스 (즉, 하나 개 Nginx에 대한 컨테이너 및 supervisord 또는 응용 프로그램이 실행중인 하나가 있어야합니다) 또한 해당 프로세스는 포 그라운드에서 실행되어야합니다.

컨테이너는 프로세스 자체가 종료 될 때 "종료"됩니다 (이 경우 해당 프로세스는 bash 스크립트입니다).


그러나 실제로 Docker 컨테이너에서 여러 서비스를 실행 해야하는 경우 의사 초기화 프로세스로 사용 되는 "Docker Base Image"로 시작하는 것을 고려하십시오 runit( runitNginx 및 Supervisor가 실행되는 동안 온라인 상태로 유지됨). 다른 프로세스가 자신의 작업을 수행하는 동안

그들은 상당한 문서를 가지고 있으므로, 당신은 당신이 합리적으로 쉽게하려는 것을 달성 할 수 있어야합니다.


1
왜 하나의 서비스 만 실행해야하는지 설명 할 수 있습니까? 필요한 경우 관리자에게 nginx를 추가 할 수 있지만 이것이 왜 필요한지 잘 모르겠습니다.
Eli

3
@Eli 짧은 대답은 Docker가 작동하는 방식입니다. Docker는 컨테이너 당 하나의 프로세스 (및 해당 하위) 만 실행합니다. 이 프로세스는 실제 애플리케이션 프로세스 (권장되는 경우 Docker는 알고 있음) 인 것이 좋지만 실제로는 관리자를 해당 프로세스로 사용할 수 있습니다. --nodaemon옵션을 통해 수행되는 수퍼바이저가 포 그라운드에서 실행되도록 (즉 데몬이 아닌) 구성해야합니다 .
Thomas Orozco

1
@Eli 이 Docker 블로그 게시물 에서는 여러 프로세스를 실행하고 (일반적으로 컨테이너를 "작은 VPS"로 보는) 차선책을 제시합니다. 귀하의 경우 주석 스레드가 실제 블로그 게시물보다 관련성이 높을 것입니다.
Thomas Orozco

1
Docker 기본 이미지는 RHEL / Centos 트리 대신 우분투를 사용하는 심각한 회사가 거의 없기 때문에 많은 엔터프라이즈 문제에 대한 끔찍한 솔루션입니다.
소프트웨어 엔지니어

9
"진정한 회사는 거의 없다"고 말할 수 없다 OS의 선택은 전적으로 유스 케이스에 기반한 것으로 보입니다. 회사마다 내부 개발자 사용, 내부 직원 사용, 영업 지원, 준비, POC 및 최종 생산 (모호한 용어)을 포함하여 다양한 환경이 있습니다. 나는 OP가 그들의 유스 케이스를 그렇게 언급하지 않았다고 생각하지만 (아주 죄송합니다) 이런 종류의 의견은 이유에 대한 논쟁없이 높은 의견을 가진 정보를 유포하는 유형 인 것 같습니다.
John Carrell

155

Dockerfile을 사용하는 경우 다음을 시도하십시오.

ENTRYPOINT ["tail", "-f", "/dev/null"]

(이것은 분명히 개발 목적으로 만 사용됩니다. 예를 들어 nginx ...와 같은 프로세스를 실행하지 않는 한 컨테이너를 살아있게 유지할 필요는 없습니다.)


5
나는 사용하고 CMD["sleep", "1d"]있지만 솔루션이 더 좋아 보인다
George Pligoropoulos

@GeorgiosPligoropoulos이 줄에 갇힐 것입니다; 어쩌면 백그라운드에서 실행이 작동합니다
Prashanth Sams

5
사용할 수도 있습니다 CMD["sleep", "infinity"].
Romain

5
또는 '고양이'이지만 사람들은 동물 학대라고 말할 수 있습니다. xD
lawphotog

진입 점 스크립트를 완료 할 수 exec tail -f /dev/null있지만 tail진입 점으로 사용하는 것은 잘못된 대답입니다.
Torsten Bronger

86

방금 같은 문제가 있었고 -tand 및 -d플래그로 컨테이너를 실행하면 계속 실행 된다는 것을 알았습니다 .

docker run -td <image>

다음은 플래그에 따라 수행되는 작업입니다 docker run --help.

-d, --detach=false         Run container in background and print container ID
-t, --tty=false            Allocate a pseudo-TTY

가장 중요한 것은 -t깃발입니다. -d컨테이너를 백그라운드에서 실행할 수 있습니다.


3
이것을 재현 할 수 없습니다. 예를 들어 주시겠습니까? 이것이 작동하기 위해 필요한 Dockerfile에 대한 특정 사항 (예 : CMD)이 있습니까?
Matheus Santana

2
이것은 나를 위해 작동하지 않았습니다. docker logs <image>도커 컨테이너가 종료되는 오류인지 확인하기 위해 명령 을 사용했습니다. 종료 상태는 0lighttpd서버가 실행 중이 라는 마지막 출력입니다 .[ ok ] Starting web server: lighttpd.
ob1

나는 한동안 Docker와 함께 일하지 않았습니다. 따라서 명령 행 인터페이스가 변경되어이 명령이 더 이상 작동하지 않을 수 있습니다.
arne.z

4
이것이 실제로 최신 도커 버전으로 작동하고 있음을 확인할 수 있습니다. 나중에이 세션에 연결하려면 -dit를 사용하면 작동합니다.
John Hamilton

1
@ 긴 스크립트는 tty를 추가 exec bash하거나 exec shbash가 설치되지 않은 경우 start.sh의 끝에 허용하지 않습니다. 그런 다음 -t 플래그를 사용할 수 있습니다
123

43

종료하는 이유는 쉘 스크립트가 PID 1로 먼저 실행되고 완료되면 PID 1이 없어지고 docker는 PID 1이있는 동안에 만 실행되기 때문입니다.

수퍼바이저를 사용하여 모든 작업을 수행 할 수 있습니다. "-n"플래그를 사용하여 실행하면 데몬으로 초기화하지 않도록 지시되므로 첫 번째 프로세스로 유지됩니다.

CMD ["/usr/bin/supervisord", "-n"]

그리고 supervisord.conf :

[supervisord]
nodaemon=true

[program:startup]
priority=1
command=/root/credentialize_and_run.sh
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false
startsecs=0

[program:nginx]
priority=10
command=nginx -g "daemon off;"
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.log
autorestart=true

그런 다음 원하는만큼 다른 프로세스를 가질 수 있으며 필요한 경우 감독자가 프로세스 재시작을 처리합니다.

그렇게하면 nginx와 php5-fpm이 필요할 수 있으며 supervisord를 사용할 수없는 경우 supervisord를 사용할 수 있습니다.


문서의 어느 부분에서 PID 1이 도커 컨테이너 종료를 멈 추면 실행이 중지됩니까?
8oh8

@ 8oh8 기본적으로 프로세스 네임 스페이스가 작동하는 방식입니다. "모든 컨테이너의 기본"인만큼 Docker에 한정되지 않습니다. 에서 man7.org/linux/man-pages/man7/pid_namespaces.7.html :If the "init" process of a PID namespace terminates, the kernel terminates all of the processes in the namespace via a SIGKILL signal. This behavior reflects the fact that the "init" process is essential for the correct operation of a PID namespace.
dannysauer

40

catbro @ Sa'ad가 언급 한대로 아무런 주장없이 평범하게 실행할 수 있습니다 . 컨테이너가 실제로 작동하도록 유지하십시오 (실제로 사용자 입력을 기다리는 것만 없음) (Jenkins의 Docker 플러그인은 동일한 작업을 수행합니다)


내 대답 외에도 : docker-compose (demonized되지 않음)가 컨테이너의 워크 플로우를 표시하는 데 사용되므로 시작된 서비스의 로그 파일을 조정하는 것이 편리 할 수 ​​있습니다. 건배
Serge Velikanov

1
또는 cat. jenkin의 도커 플러그인이 그렇게합니다.
Sa'ad

12

daemon off;nginx.conf 를 추가 하거나 CMD ["nginx", "-g", "daemon off;"]공식 nginx 이미지에 따라 실행하십시오.

그런 다음 다음을 사용하여 수퍼바이저를 서비스로 실행하고 nginx를 포 그라운드 프로세스로 실행하여 컨테이너가 종료되지 않도록하십시오.

service supervisor start && nginx

경우에 따라 컨테이너에 프로세스가 두 개 이상 있어야하므로 컨테이너에 프로세스가 정확히 하나만 있으면 작동하지 않아 배포시 더 많은 문제가 발생할 수 있습니다.

따라서 절충점을 이해하고 그에 따라 결정해야합니다.


7

자극:

도커 컨테이너 내에서 여러 프로세스를 실행하는 데 아무런 문제없습니다 . 도커를 경량 VM으로 사용하는 것을 좋아한다면 그렇게하십시오. 다른 사람들은 응용 프로그램을 마이크로 서비스로 나누기를 좋아합니다. 내 생각 : 하나의 컨테이너에 램프 스택? 그냥 좋아요

대답:

A를 스틱 좋은 기본 이미지phusion의 기본 이미지 . 다른 사람이있을 수 있습니다. 의견을주세요.

그리고 이것은 또 다른 감독자에게 간청입니다. phusion base 이미지는 cron 및 locale setup과 같은 다른 것 외에도 감독자를 제공하기 때문입니다. 그런 가벼운 VM을 실행할 때 설정하고 싶은 것들. 가치가있는 것은 컨테이너에 ssh 연결을 제공합니다.

이 기본 docker run 문을 실행하면 phusion 이미지 자체가 시작되고 계속 실행됩니다.

moin@stretchDEV:~$ docker run -d phusion/baseimage
521e8a12f6ff844fb142d0e2587ed33cdc82b70aa64cce07ed6c0226d857b367
moin@stretchDEV:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS
521e8a12f6ff        phusion/baseimage   "/sbin/my_init"     12 seconds ago      Up 11 seconds

또는 죽은 간단한 :

기본 이미지가 당신을위한 것이 아닌 경우 ... 빠른 CMD가 계속 실행되도록하려면 bash에 대해 다음과 같이 가정하십시오.

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

또는 busybox의 경우 :

CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"

a에서 즉시 종료 되기 때문에 좋습니다 docker stop. 컨테이너가 나오기까지 평범 sleep하거나 cat몇 초가 걸립니다.


PostgreSQL 11을로드하도록 centos7 기본 이미지를 사용자 정의했습니다. / usr / pgsql-11 / bin / pg_ctl을 호출하여 시작하지만 서버가 실행되면 pg_ctl이 종료됩니다. 함정 사용에 대한 제안은 훌륭했습니다. 내 스크립트의 마지막 줄입니다. pgstartwait.sh
Alchemistmatt

6

변수 (예 : $ NGNIX_PID)에서 ngnix 프로세스의 PID를 캡처하고 진입 점 파일의 끝에서

wait $NGNIX_PID 

이런 식으로 컨테이너는 ngnix가 활성화 될 때까지, ngnix가 중지되면 컨테이너도 중지해야합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.