Wie starte ich automatisch einen Dienst, wenn ein Docker-Container ausgeführt wird?

157

Ich habe eine Docker-Datei , um den MySQL-Server in einem Container zu installieren, den ich dann folgendermaßen starte :

sudo docker run -t -i 09d18b9a12be /bin/bash

Der MySQL-Dienst wird jedoch nicht automatisch gestartet. Ich muss ihn manuell ausführen (aus dem Container heraus):

service mysql start

Wie starte ich den MySQL-Dienst automatisch, wenn ich den Docker-Container ausführe?

mtmacdonald
quelle
1
Nein, für einen einfachen Dienst wird kein Supervisor benötigt, was den Startbenutzer kompliziert macht
Larry Cai
8
Vielleicht möchten Sie die Docker-Datei hier kopieren, anstatt sie mit einer Datei zu verknüpfen, die nicht mehr existiert
neo112
Der Docker-Artikel zu Supervisord ist jetzt hier: docs.docker.com/config/containers/multi-service_container Ich habe den Befehl && tail verwendet, um meinen Dienst zum Laufen zu bringen, musste aber "--cap-add SYS_PTRACE" zum Docker hinzufügen Führen Sie den Befehl aus.
Ted Cahall

Antworten:

205

Erstens gibt es ein Problem in Ihrem Dockerfile:

RUN service mysql restart && /tmp/setup.sh

Docker-Images speichern keine laufenden Prozesse. Daher wird Ihr RUNBefehl nur während der docker buildPhase ausgeführt und nach Abschluss des Builds gestoppt. Stattdessen müssen Sie den Befehl geben , wenn der Container gestartet wird die Verwendung CMDoder ENTRYPOINTBefehle wie folgt:

CMD mysql start

Zweitens benötigt der Docker-Container einen Prozess (letzter Befehl), um weiter ausgeführt zu werden, andernfalls wird der Container beendet / gestoppt. Daher kann der normale service mysql startBefehl nicht direkt in der Docker-Datei verwendet werden.

Lösung

Es gibt drei typische Möglichkeiten, um den Prozess am Laufen zu halten:

  • Verwenden Sie den serviceBefehl und hängen Sie danach den Non-End-Befehl antail -F

    CMD service mysql start && tail -F /var/log/mysql/error.log
    

Dies wird häufig bevorzugt, wenn ein einzelner Dienst ausgeführt wird, da das ausgegebene Protokoll für Docker zugänglich ist.

  • Oder verwenden Sie dazu den Befehl Vordergrund

    CMD /usr/bin/mysqld_safe
    

Dies funktioniert nur, wenn es ein Skript wie gibt mysqld_safe.

  • Oder wickeln Sie Ihre Skripte ein start.shund beenden Sie dies

    CMD /start.sh
    

Dies ist am besten, wenn der Befehl eine Reihe von Schritten ausführen muss und erneut ausgeführt werden /start.shsoll.

Hinweis

Für Anfänger wird die Verwendung supervisordnicht empfohlen. Ehrlich gesagt ist es übertrieben. Es ist viel besser, einen einzelnen Dienst / einen einzelnen Befehl für den Container zu verwenden.

Übrigens: Bitte überprüfen Sie https://registry.hub.docker.com auf vorhandene MySQL-Docker-Bilder als Referenz

Larry Cai
quelle
Wie würden Sie den Dienst neu starten, sobald er im Docker-Container gestartet wurde?
K - Die Toxizität in SO nimmt zu.
3
@ KarlMorrisondocker exec -it <CONTAINER NAME> mysql /etc/init.d/mysqld restart
Kaiser
1
Ich würde nicht empfehlen, das MySQL-Fehlerprotokoll zu verfolgen, um festzustellen, ob die Datenbank ausgeführt wird oder nicht. In den meisten mysqld-Setups wird der Server von solchen Fehlern wiederhergestellt, und dabei wird das Fehlerprotokoll geschlossen und dann wieder geöffnet. Ich bin mir auch nicht sicher, ob Ihr Schwanz -F in allen oder sogar in einigen Fällen für Sie funktioniert.
Brian Aker
Ich bin nicht sicher warum, aber die erste Lösungsoption funktioniert gut für Service-Skript. Wenn Sie tail nicht verwenden, schlägt dies fehl, obwohl der Dienst gestartet wurde (zumindest für den Tomcat7-Dienst). Mit Schwanz funktioniert es. In beiden Fällen müssen Sie den Schalter cap_add (- cap-add SYS_PTRACE für run) mit mindestens SYS_PTRACE
zhrist
1
Nein, mehr dazu unter stackoverflow.com/questions/46800594/…
Larry Cai
73

Fügen Sie in Ihrem Dockerfilein der letzten Zeile hinzu

ENTRYPOINT service ssh restart && bash

Für mich geht das

Und das ist das Ergebnis:

root@ubuntu:/home/vagrant/docker/add# docker run -i -t ubuntu
 * Restarting OpenBSD Secure Shell server sshd   [ OK ]                                                                      
root@dccc354e422e:~# service ssh status
 * sshd is running
Jia
quelle
2
Das ist schön, aber ich denke, man kann auf diese Weise keinen abgetrennten Container haben.
Mdob
1
Das hat bei mir super funktioniert. Ich hatte Probleme, Nginx 1.8 zum automatischen Start zu bringen. Möglicherweise ist das Hinzufügen der folgenden Elemente hilfreich: RUN echo "daemon off;" >> /etc/nginx/nginx.conf RUN ln -sf / dev / stdout /var/log/nginx/access.log RUN ln -sf / dev / stderr /var/log/nginx/error.log
Lionel Morrison
1
Gibt es irgendwelche Nachteile bei dieser Lösung?
srph
2
Das endgültige Starten von Bash ist eine schlechte Idee, wenn Sie Ihre Dienste ordnungsgemäß beenden möchten, da auf diese Weise der Docker-Contaienr nicht von docker stopoder ordnungsgemäß gestoppt werden docker restartkann, sondern nur getötet werden kann.
Mohammed Noureldin
Ich habe an Packer gearbeitet, um Docker-Images zu erstellen, und dies scheint mein Problem mit dem Conaitner in der Packer-Datei zu beheben. "Änderungen": ["ENTRYPOINT Service Nginx Start && / bin / bash"]
karthik101
8

Einfach! Fügen Sie am Ende der Docker-Datei hinzu:

ENTRYPOINT service mysql start && /bin/bash
Thiago
quelle
Dies ist die beste Antwort, die mein aktuelles Docker Container-Problem löst: Docker version 18.09.7, build 2d0083dOhne && /bin/bashden Dienst wird sofort gestoppt
Long
7

Es gibt noch einen anderen Weg, den ich immer als besser lesbar empfunden habe.

Angenommen, Sie möchten rabbitmq und mongodb starten, wenn Sie es ausführen, dann CMDwürde Ihr ungefähr so aussehen:

CMD /etc/init.d/rabbitmq-server start && \
    /etc/init.d/mongod start

Da Sie nur einen CMDpro DockerfileTrick haben können, besteht es darin, alle Anweisungen mit zu verketten &&und dann \für jeden Befehl eine neue Zeile zu beginnen.

Wenn Sie am Ende viele davon hinzufügen, schlage ich vor, dass Sie alle Ihre Befehle in eine Skriptdatei einfügen und wie von @ larry-cai vorgeschlagen starten:

CMD /start.sh
Francesco Casula
quelle
3

In meinem Fall wird eine PHP-Webanwendung von Apache2 im Docker-Container bereitgestellt, der eine Verbindung zu einer MYSQL-Backend-Datenbank herstellt. Die Lösung von Larry Cai funktionierte mit geringfügigen Änderungen. Ich habe eine entrypoint.shDatei erstellt, in der ich meine Dienste verwalte. Ich denke, das Erstellen entrypoint.sheines Befehls, wenn Sie beim Starten Ihres Containers mehr als einen Befehl ausführen müssen, ist eine sauberere Methode zum Booten des Dockers.

#!/bin/sh

set -e

echo "Starting the mysql daemon"
service mysql start

echo "navigating to volume /var/www"
cd /var/www
echo "Creating soft link"
ln -s /opt/mysite mysite

a2enmod headers
service apache2 restart

a2ensite mysite.conf
a2dissite 000-default.conf
service apache2 reload

if [ -z "$1" ]
then
    exec "/usr/sbin/apache2 -D -foreground"
else
    exec "$1"
fi
Mr. Doomsbuster
quelle
Legen Sie es einfach neben Ihre Docker-Datei. Dann sollten Sie in Ihrer Docker-Datei eine Anweisung haben, die diese Datei an den gewünschten Speicherort kopiert. Dann zeigen Sie die ENTRYPOINT ['your location']Anweisung auf die Skriptdatei. Denken Sie jedoch daran, die Ausführungsberechtigungen für Ihr Skript festzulegen. COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]. In diesem Beispiel habe ich meinen Einstiegspunkt in das Stammverzeichnis im Docker-Container kopiert.
Herr Doomsbuster
Wo ist Dockerfile?
Viktor Joras
3

Ich habe das gleiche Problem, wenn ich den SSH-Dienst automatisch starten möchte. Ich habe diesen Anhang gefunden

/etc/init.d/ssh start
zu
~ / .bashrc
kann es lösen, aber nur Sie öffnen es mit Bash reicht aus.

Weiping.Chen
quelle
1

Ich füge den folgenden Code zu /root/.bashrc hinzu, um den Code nur einmal auszuführen.

Bitte übergeben Sie den Container an das Image, bevor Sie dieses Skript ausführen. Andernfalls wird die Datei 'docker_services' in den Images erstellt und kein Dienst ausgeführt.

if [ ! -e /var/run/docker_services ]; then
    echo "Starting services"
    service mysql start
    service ssh start
    service nginx start
    touch /var/run/docker_services
fi
user136685
quelle
1

So starte ich den MySQL-Dienst automatisch, wenn der Docker-Container ausgeführt wird.

In meinem Fall muss ich nicht nur MySQL, sondern auch PHP, Nginx und Memcached ausführen

Ich habe die folgenden Zeilen in Dockerfile

RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80
EXPOSE 3306
CMD service mysql start && service php-fpm start && nginx -g 'daemon off;' && service memcached start && bash

Durch Hinzufügen von && bash bleiben Nginx, MySQL, PHP und Memcached im Container ausgeführt.

Chris
quelle
1

Das funktioniert nicht CMD service mysql start && /bin/bash

Das funktioniert nicht CMD service mysql start ; /bin/bash ;

- Ich denke, der interaktive Modus würde den Vordergrund nicht unterstützen.

Das funktioniert !! CMD service nginx start ; while true ; do sleep 100; done;

Das funktioniert !! CMD service nginx start && tail -F /var/log/nginx/access.log

Vorsicht, Sie sollten docker run -p 80:80 nginx_bashohne Befehlsparameter verwenden.

user3073309
quelle
0

Die folgende Dokumentation auf der Docker-Website zeigt, wie ein SSH-Dienst in einem Docker-Container implementiert wird. Es sollte leicht an Ihren Service anpassbar sein:

Eine Variation dieser Frage wurde auch hier gestellt:

Zammalad
quelle
Das nsenter-Tool ist ein weiterer Ansatz zum Eingeben in einen Container, ohne dass eine Installation des SSH-Servers erforderlich ist: github.com/jpetazzo/nsenter . Dieser Ansatz erfordert jedoch einen Zugriff auf Ihren Docker-Host (normalerweise reicht der SSH-Zugriff aus).
Fabien Balageas
Der Link docs.docker.com/sorry/#/examples/running_ssh_service funktioniert nicht. Kannst du es bitte aktualisieren?
Ankur
0
docker export -o <nameOfContainer>.tar <nameOfContainer>

Möglicherweise muss der vorhandene Container mit Docker Prune beschnitten werden ...

Import mit erforderlichen Änderungen:

cat <nameOfContainer>.tar | docker import -c "ENTRYPOINT service mysql start && /bin/bash" - <nameOfContainer>

Führen Sie den Container beispielsweise mit der Option "Immer neu starten" aus, um sicherzustellen, dass er nach dem Host / Daemon-Recycling automatisch fortgesetzt wird:

docker run -d -t -i --restart always --name <nameOfContainer> <nameOfContainer> /bin/bash

Randnotiz: Meiner Meinung nach ist es sinnvoll, nur den Cron-Service zu starten und den Container so sauber wie möglich zu lassen. Ändern Sie dann einfach crontab oder cron.hourly, .daily etc ... mit entsprechenden Überprüfungs- / Überwachungsskripten. Grund ist, dass Sie sich nur auf einen Daemon verlassen. Bei Änderungen ist es mit Ansible oder Puppet einfacher, Cron-Skripte neu zu verteilen, anstatt Dienste zu verfolgen, die beim Booten beginnen.

Daniel
quelle