Dies ist eine alte Version des Dokuments!
Inhaltsverzeichnis
Docker
Docker ist eine Containerplattform.
Installation
Quelle: https://docs.docker.com/install/linux/docker-ce/ubuntu/
Üblicherweise installiert man Docker unter Ubuntu über Repositories. Um Verbindungen zu https Repositories aufbauen zu können, benötigt man noch folgendes Paket
apt-get install apt-transport-https
Nun holt man sich den Key des Repos, installiert diesen und fügt das Repo hinzu.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
Danach wird Docker installiert.
apt-get install docker-ce
Um die Installation und den Docker-Daemon zu testen, holt man sich den ersten Container und startet diesen.
docker run hello-world
Grundsätzlich kann man die Installation nun so belassen. Alle Benutzer können, wenn sie dies dürfen, per sudo
Container bedienen.
Dies ist so, da der Daemon über einen Unix-Socket und nicht über einen TCP-Port erreichbar ist. Der Socket gehört dem Benutzer „root“ und der Gruppe „docker“.
Soll jeder Benutzer dies machen dürfen, auch ohne sudo
, so fügt man diesen der, bei der Installation hinzugefügten, Gruppe „docker“ hinzu.
usermod -aG docker <BENUTZER>
Hat man docker mit sudo
bedient und hat sich danach der Gruppe „docker“ hinzugefügt, so müssen noch die Rechte des eigenen Docker-Verzeichnisses angepasst werden.
sudo chown -R <BENUTZER>:<BENUTZERGRUPPE> /home/<BENUTZER>/.docker chmod -R g+rwx /home/<BENUTZER>/.docker
Konfiguration
Die Konfiguration des Daemons wird mit Startparametern geregelt.
Diese werden normalerweise über die Datei /etc/docker/daemon.json
gesetzt.
Bei Betriebssystemen mit „Systemd“ als init-System werden die Parameter direkt in Systemd eigetragen.
Dazu erstellt man eine override.conf mit folgendem Befehl:
systemctl edit docker.service
Nun setzen wir z.B. den DNS-Server welcher an die Container übergeben werden soll.
Der Inhalt der override.conf sieht wie folgt aus:
[Service] ExecStart= ExecStart=/usr/bin/dockerd --dns=1.1.1.1 --dns=8.8.8.8 --dns-search="dns.domain.tld" -H fd://
Die leere „ExecStart=“ Zeile ist wichtig, da Systemd erst die Startsequenz löscht um sie dann neu zu definieren.
Nun noch Systemd die Änderungen mitteilen und dann den Docker-Daemon neustarten.
systemctl daemon-reload systemctl restart docker
Note that the empty ExecStart= is required, as systemctl only will overrule the ExecStart if it is cleared first.
Debug
Mit der Startoption -D|–debug
kann man das Debugging bei Docker einschalten.
Danach startet man die Log-Ansicht für einen Container wie folgt:
docker logs [<OPTIONEN>] <CONTAINER_NAME>
RUN, ENTRYPOINT, CMD
Die Befehle RUN
, ENTRYPOINT
und CMD
werden im Dockerfile
unterschiedlich benutzt.
Grundsätzlich können diese Befehle als Exec und Shell Format übergeben werden.
Exec:
Beispiel
[RUN|ENTRYPOINT|CMD] ["<BEFEHL>", "<PARAMETER1>", "<PARAMETER2>"]
- Im Exec Format wir der Befehl direkt so ausgeführt. Mit
ENV
gesetzte Variablen werden nicht übersetzt. Dazu muss der Befehl als Parameter für eine Shell angegeben werden (wie beim Shell Format) - Wenn Bash ausgeführt werden muss, so sollte dies im Exec Format geschehen. Hier lassen sich Parameter eindeutig übergeben.
Shell:
Beispiel
[RUN|ENTRYPOINT|CMD] <BEFEHL> <PARAMETER1> <PARAMETER2>
- Im Shell Format wird der Befehl mit Shell (
/bin/sh -c <BEFEHL>
) ausgeführt. - kann verwendet werden um mehrere gleiche Befehlszeilen zu minimieren
Beispiel:apt-get update && apt-get install -y \ nginx \ mysql
Befehl | Beschreibung | kann mehrmals verwendet werden |
---|---|---|
RUN | * wird verwendet um Befehle beim erstellen eines Images auszuführen | ja |
Entrypoint | * wird verwendet um Befehle nach dem Start des Containers auszuführen * wird auch ausgeführt wenn der docker run Befehl einen Standard Befehl am Ende ausführt * wenn im Shell Format angegeben, wird jeder CMD Befehl ignoriert | ja |
CMD | * wird verwendet um eine Standard Befehl nach dem start des Containers abzusetzen * Wenn beim docker run Befehl ein Standard Befehl am Ende angegeben wird, wird CMD ignoriert * Kann auch verwendet werden um nur Parameter an ENTRYPOINT zu übergeben, wenn kein Standard Befehl beim docker run übergeben wird, wird der ENTRYPOINT ausgeführt | nein (bzw. nur der letzte CMD -Befehl wird ausgeführt) |
Nützliche Befehle
dem Befehl docker
können verschiedene Parameter übergeben werden.
Parameter | Beschreibung |
---|---|
–version | zeigt die Version von Docker in Kurzfassung |
version | zeigt die Version von Docker ausführlich |
ps | zeigt laufende Container |
build -t <IMAGE_NAME> . | erstellt ein Image mit angegebenen Namen über das im aktuellen Ordner befindlichen Dockerfile |
run | startet ein Image |
run -p 8080:80 <IMAGE_NAME> | startet ein Image wo der, von aussen, erreichbare Port 8080 auf den, im Container erreichbaren, Port 80 gemappt wird |
run -d <IMAGE_NAME> | startet ein Image im detached Modus (das Prompt ist wieder frei) |
container ls | listet alle laufenden Container auf |
container ls -a | listet alle Container auf (gestartet oder gestoppt) |
container stop <CONTAINER_ID> | stoppt den jew. Container (wie shutdown) |
container kill <CONTAINER_ID> | erzwingt das stoppen des jew. Containers |
container rm <CONTAINER_ID> | löscht den jew. Container vom Server |
container rm $(docker container ls -a -q) | löscht alle Container vom Server |
image ls | zeigt vorhandene Images |
image ls -a | zeigt alle Images |
image rm <IMAGE_ID> | löscht das jew. Image vom Server |
image rm $(docker image ls -a -q) | löscht alle Images vom Server |
logs <CONTAINER_ID> | zeigt logs über den jew. Container |
inspect <CONTAINER_ID> | zeigt ausführliche Infos über den jew. Container |
attach <CONTAINER_ID> | Verbindet sich zum Container auf die Konsole (detach per STRG+P und danach STRG+Q) |
Images und Container
Erstellen
Um ein Image zu erstellen, benötigt man eine Datei namens Dockerfile
. Darin stehen die Anweisungen zum erstellen eines Containers.
Alle benötigten Dateien zum Erstellen eines Images, sollten sich in einem eigenen Ordner befinden.
Beispiel zum Erstellen eines Images mit Nginx und PHP:
mkdir nginx-php cd nginx-php
Konfigurationsdateien
Folgende Dateien müssen erstellt und mit Inhalt gefüllt werden.
Erklärung
Datei | Beschreibung |
---|---|
Dockerfile | * steuert das Erstellen des Images und das Startverhalten des Containers |
package.list | * enthält die, in das Image, zu installierenden Pakete |
startup.sh | * Startscript welches nach dem Starten des Containers ausgeführt wird * hier werden die Daemons für nginx und php gestartet * der letzte Befehl ist dafür da, damit das Script und somit auch der Container dauerhaft läuft |
nginx.conf | * Konfiguration für nginx |
my-website-conf | * Konfiguration für Webseite |
fastcgi-php.conf | * Konfiguration für php und fastcgi |
snakeoil.conf | * Konfiguration für die SSL Verschlüsselung mit Snakeoil Zertifikaten |
ssl-cert-snakeoil.key | * SSL Zertifikat von Snakeoil |
ssl-cert-snakeoil.pem | * SSL privater Schlüssel von Snakeoil |
ssl-conf | * Konfiguration für SSL verschlüsselte Webseiten |
dhparam.pem | * Diffie Hellmann Schlüssel |
index.php | * Startseite |
phpinfo.php | * PHP-Info Webseite |
hallo.html | * SSL verschlüsselte Webseite |
Dockerfile
FROM ubuntu:bionic # Define environment variable ENV WWW_DIR /var/www/html ENV TERM xterm ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin ENV DEBIAN_FRONTEND noninteractive # set Timezone with `--build-arg TIMEZONE=Europe/Berlin` in `docker build` ARG TIMEZONE # Set the working directory to /var/www/html WORKDIR /var/www/html # Copy files ADD *.html /var/www/html/ ADD *.php /var/www/html/ ADD package.list /tmp ADD timezone /etc # Install any needed packages specified in requirements.txt RUN \ apt-get update && \ apt-get upgrade -y && \ apt-get install -y apt-utils && \ cat /tmp/package.list | xargs apt-get install -y # set Timezone RUN if [ ! -z "${TIMEZONE}" ]; \ then ln -sf /usr/share/zoneinfo/$TIMEZONE /etc/localtime && \ dpkg-reconfigure -f noninteractive tzdata; \ fi # Create directories RUN mkdir -p /etc/ssl/certs /etc/ssl/private /var/log/nginx # Install Snakeoil Cert and Key ADD ssl-cert-snakeoil.pem /etc/ssl/certs ADD ssl-cert-snakeoil.key /etc/ssl/private # Copy Nginx Configs ADD nginx.conf /etc/nginx/ ADD fastcgi-php.conf /etc/nginx/snippets/ ADD snakeoil.conf /etc/nginx/snippets/ ADD dhparam.pem /etc/nginx/snippets/ ADD ssl-conf /etc/nginx/sites-available/ ADD my-website-conf /etc/nginx/sites-available/ ADD startup.sh /usr/local/bin RUN \ ln -s /etc/nginx/sites-available/my-website-conf /etc/nginx/sites-enabled && \ unlink /etc/nginx/sites-enabled/default # Define mountable directories. VOLUME ["/etc/nginx", "/var/log", "/var/www/html"] # Make ports 80 and 443 available EXPOSE 80 EXPOSE 443 ENTRYPOINT ["/bin/bash", "-c", "startup.sh"]
package.list
vim rsyslog nginx php-fpm fcgiwrap openssl
startup.sh
#!/bin/bash while ! pgrep nginx; do service nginx start sleep 1 done while ! pgrep php-fpm; do service php7.2-fpm start sleep 1 done tail -f /dev/null
nginx.conf
user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; ## FCGI: Detect when HTTPS is used map $scheme $fastcgi_https { default off; https on; } upstream php { server unix:/var/run/php/php7.2-fpm.sock; } upstream fcgiwrap { server unix:/var/run/fcgiwrap.socket; } ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
my-website-conf
server { listen 80; server_name _; root /var/www/html; index index.html index.htm index.php; location / { index index.html index.htm index.php; try_files $uri $uri/ /index.php; } location ~ \.php$ { include snippets/fastcgi-php.conf; try_files $fastcgi_script_name =404; } # We don't want to allow the browsers to see .hidden linux/unix files location ~ /\. { deny all; access_log off; log_not_found off; } } server { listen 443 ssl; include snippets/snakeoil.conf; include /etc/nginx/sites-available/ssl-conf; root /var/www/html; index index.html index.htm index.php; server_name _; location / { index index.php; try_files $uri $uri/ /index.php; } location ~ \.php$ { include snippets/fastcgi-php.conf; try_files $fastcgi_script_name =404; } # We don't want to allow the browsers to see .hidden linux/unix files location ~ /\. { deny all; access_log off; log_not_found off; } }
fastcgi-php.conf
# regex to split $uri to $fastcgi_script_name and $fastcgi_path fastcgi_split_path_info ^(.+\.php)(/.+)$; # Check that the PHP script exists before passing it #try_files $fastcgi_script_name =404; # Bypass the fact that try_files resets $fastcgi_path_info # see: http://trac.nginx.org/nginx/ticket/321 set $path_info $fastcgi_path_info; fastcgi_param PATH_INFO $path_info; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; fastcgi_index index.php; fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; fastcgi_read_timeout 240;
snakeoil.conf
# Self signed certificates generated by the ssl-cert package # Don't use them in a production server! ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem; ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl-cert-snakeoil.pem
: SSL-Zertifikat kann vom lokalen Docker Host kopiert werdenssl-cert-snakeoil.key
: SSL privater Schlüssel kann vom lokalen Docker Host kopiert werdenssl-conf
#SSL-Protocols ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #HSTS Security add_header Strict-Transport-Security max-age=15768000; ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; # openssl dhparam -out dhparam.pem 2048 ssl_dhparam /etc/nginx/snippets/dhparam.pem; ##ssl_protocols TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK'; ssl_prefer_server_ciphers on;
dhparam.pem
Diese Datei muss überopenssl
einmalig, auf dem Docker-Host, erzeugt werdenopenssl dhparam -out dhparam.pem 2048
index.php
: Hier noch die IP Adresse oder Hostnamen anpassen<html> <head> <title>NGINX im Docker-Container</title> </head> <body> <h1>Testseiten</h1> <li><a href="http://<IP_ADDRESS>/phpinfo.php">zeige PHP-Info</a></li> <li><a href="https://<IP_ADDRESS>/hallo.html">zeige PHP-Info</a></li> </body> </html>
phpinfo.php
<?php // Zeigt alle Informationen (Standardwert ist INFO_ALL) phpinfo(); ?>
Build and Run
Nun kann man das Docker-Image bauen lassen. Dazu führt man folgenden Befehl aus:
docker build --build-arg TIMEZONE=Europe/Berlin -t <NAME_DES_IMAGES> .
Mit folgendem Befehl sieht man das nun erstellte Image
docker image ls
Das Images ist nun erstellt. Nun kann man seinen Docker-Container starten.
docker run -d -p 80:80 -p 443:443 --name nginx <IMAGE_NAME>:<TAG>
Zur Erklärung der Parameter:
-d
steht für „detach“. Der Container wird dann im Hintergrund ausgeführt.-p
stellt Ports welche innerhalb des Containers laufen nach außen bereit. <PORT_AUSSEN>:<PORT_IM_CONTAINER>
Der Container sollte nun dauerhaft laufen und die Ports 80 und 443 nach außen bereitstellen.
Man kann nun im Webbrowser die URL http://<IP_DES_DOCKER_HOSTS> eingeben und die Webseite der index.php sehen.
Der folgende Befehl zeigt alle laufenden Container.
docker container ls
Dieser Befehl beendet den jew. Container
docker container stop <ID>
Volumes
Damit man wegen Konfigurationsänderungen nicht ständig zum Container verbinden muss, erstellt man sich Docker-Volumes und mountet diese mit den Volumes welche im Dockerfile angegeben wurden.
Die Volumes werden folgendermaßen angelegt:
docker volume create <VOLUME_NAME>
Der Docker Container wird dann so gestartet:
docker run -d -p 80:80 -p 443:443 -v nginx-nginx:/etc/nginx -v nginx-log:/var/log -v nginx-html:/var/www/html <IMAGE_NAME>:<TAG>
Zur Erklärung der Parameter:
-v
mountet Verzeichnisse aus dem Container in Volumes auf dem Docker-Host oder anderer Container. <VOLUME_NAME>:<ZIELPFAD_IM_CONTAINER>- im Dockerfile werden Verzeichnisse im Parameter
VOLUME
gekennzeichnet, welche als mountpoints gelten.
Docker umziehen
Wenn Container oder Images auf einen anderen Host umziehen sollen, so kann man dies wie folgt tun.
- Image
- sichern
docker save -o <OUTPUT_FILE_NAME>.tar <IMAGE_ID>
- importieren
docker load -i <INPUT_FILE_NAME>.tar
- Daten innerhalb des Containers können so gesichert werden
- Container
- sichern
docker export -o <OUTPUT_FILE_NAME>.tar <CONTAINER_ID>
- importieren
docker import <INPUT_FILE_NAME>.tar
- Daten innerhalb des Containers werden nicht gesichert