Dies ist eine alte Version des Dokuments!


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/Brussels` 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 && \
        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 werden
  • ssl-cert-snakeoil.key: SSL privater Schlüssel kann vom lokalen Docker Host kopiert werden
  • ssl-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 über openssl einmalig, auf dem Docker-Host, erzeugt werden
    openssl 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();
    ?>
  • hallo.html
    <html>
     <head>
      <title>NGINX im Docker-Container</title>
     </head>
     <body>
      <h1>Webseite SSL verschl&uuml;sselt</h1>
      <p>Diese Seite ist SSL verschl&uuml;sselt.</p>
     </body>
    </html>

Build and Run

Nun kann man das Docker-Image bauen lassen. Dazu führt man folgenden Befehl aus:

docker build -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 <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.
Navigation
Drucken/exportieren
QR-Code
QR-Code Docker (erstellt für aktuelle Seite)