2015-08-05 14 views
16

Używam aplikacji Java Dropwizard w kontenerze Docker przy użyciu obrazu java:7u79 na podstawie debian/jessie.SIGTERM nie został odebrany przez proces java używający 'przystanku docker' i oficjalnego obrazu java

Moja aplikacja Java obsługuje sygnał SIGTERM, aby zamknąć się z wdziękiem. Obsługa SIGTERM działa idealnie, gdy uruchamiam aplikację bez Dockera.

Po uruchomieniu w kontenerze Docker SIGTERM nie dociera do aplikacji Java po wydaniu komendy docker stop. Zabija proces gwałtownie po 10 sekundach.

My Dockerfile:

FROM java:7u79 

COPY dropwizard-example-1.0.0.jar /opt/dropwizard/ 
COPY example.keystore /opt/dropwizard/ 
COPY example.yml /opt/dropwizard/ 

WORKDIR /opt/dropwizard 

RUN java -jar dropwizard-example-1.0.0.jar db migrate /opt/dropwizard/example.yml 

CMD java -jar dropwizard-example-1.0.0.jar server /opt/dropwizard/example.yml 

EXPOSE 8080 8081 

Co jest nie tak z tym Dockerfile? Czy istnieje jakiś inny sposób rozwiązania tego problemu?

Odpowiedz

24

Zakładając uruchomić usługę Java poprzez zdefiniowanie następujących w Dockerfile:

CMD java -jar ... 

Kiedy teraz wejść do pojemnika i listy procesów np przez docker exec -it <containerName> ps AHf (nie próbowałem, że z java ale z ubuntu obrazu) widać, że proces Java nie jest procesem root (nie proces z PID 1), ale proces potomny procesu /bin/sh:

UID  PID PPID C STIME TTY   TIME CMD 
root   1  0 0 18:27 ?  00:00:00 /bin/sh -c java -jar ... 
root   8  1 0 18:27 ?  00:00:00 java -jar ... 

Zasadniczo masz powłokę Linux, która jest głównym procesem z PID 1, który ma proces potomny (Java) z PID 8.

Aby obsługa sygnałów działała poprawnie, powinieneś unikać tego procesu. Można to zrobić za pomocą wbudowanego polecenia powłoki exec. To spowoduje, że proces potomny przejmie proces nadrzędny. Tak więc na końcu poprzedni proces nadrzędny już nie istnieje. A proces dziecko staje się proces z PID 1. Spróbuj wykonać następujące czynności w Dockerfile:

CMD exec java -jar ... 

Proces wystawianie następnie powinien pokazać coś takiego:

UID  PID PPID C STIME TTY   TIME CMD 
root   1  0 0 18:30 ?  00:00:00 java -jar ... 

Teraz trzeba tylko, że jeden proces z PID 1. Ogólnie dobrą praktyką jest, aby kontenery dokowane zawierały tylko jeden proces - ten z PID 1 (lub jeśli naprawdę potrzebujesz więcej procesów, powinieneś użyć np. supervisord jako PID 1, który sam zajmuje się obsługą sygnałów dla swoich procesów potomnych).

Przy tej konfiguracji SIGTERM będzie traktowany bezpośrednio przez proces Java. Nie ma już żadnego procesu powłoki, który mógłby przerwać obsługę sygnału.

EDIT:

To samo exec efekt można osiągnąć stosując inny CMD składnię, że robi to w sposób dorozumiany (dzięki Andy dla jego komentarzu):

CMD ["java", "-jar", "..."] 
+1

To dobra odpowiedź, ale może być jeszcze lepiej, gdyby używali 'CMD' lub' ENTRYPOINT' w formacie _exec_, na przykład 'ENTRYPOINT [" java "," - jar "," ... "]' https://docs.docker.com/reference/builder/#entrypoint – Andy

+0

Tak, dziękuję za wskazanie tego . Odpowiednio zaktualizowałem swoją odpowiedź. – h3nrik

+2

'CMD [" java "," -jar ", ...]' nie działało ze zmiennymi 'ENV', ale' CMD exec java -jar' rozwiązał mój problem :) –

2

@ h3nrik odpowiedź jest prawo ale czasami naprawdę trzeba użyć skryptu, aby skonfigurować uruchomienie.Wystarczy użyć polecenia exec rade w większości przypadków:

#!/bin/sh 

#--- Preparations 

exec java -jar ... 

Zobacz ten wspaniały blog post