angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

ISPConfig: Ausführen eines Python Flask Docker Containers als inhaftierter Shell-Benutzer

Die beschriebene Methode setzt voraus, dass Sie root sind, d.h. sie ist nicht universell, kann aber ausreichen, wenn Sie der Systemadministrator sind.

18 Oktober 2019 Aktualisiert 18 Oktober 2019
post main image
unsplash.com/@emilydafinchy

Ich betreibe einen Server mit ISPConfig ca. 50 Standorten. Sie können virtuelle Umgebungen auf dem Server erstellen und ISPConfig Ihre Anwendung von hier aus ausführen, aber vor einiger Zeit habe ich mich für die Entwicklung Docker und Produktion entschieden Python Flask . staging Es braucht Zeit, um dies einzurichten, aber es lohnt sich wirklich. Docker ist ein guter Weg.

Ich werde einen im Gefängnis befindlichen Shell-Benutzer verwenden, um den Container auszuführen. Der Grund dafür ist, dass, wenn der Container bricht, der Zugriff auf die im Gefängnis befindlichen Shell-Benutzerrechte beschränkt ist, oder? Siehe auch Zusammenfassung unten.

Mein ISPConfig System:

  • ISPConfig3 3.1.13
  • Debian 9 (Dehnen)
  • MariaDB 10.3
  • Nginx 1.10.3

Mein Docker Container läuft ISPConfig

Für staging und Produktion verwendet der Python Flask Docker Container, der auf der Anwendung und dem Gunicorn WSGI-Webserver basiert Alpine und diese enthält Python, ein'Volume-Mapping' auf Protokolldateien, Sitzungsdateien und Cache-Dateien. Zusätzlich enthält es ein'volumes' Mapping auf das statische Verzeichnis.

Für die Entwicklung, staging, und Produktion verwende ich eine.dockerignore Datei, um den statischen Ordner aus dem Docker image.... Es wächst schnell mit allen Bildern. Für die Entwicklung brauchen wir es sowieso nicht, da wir alles außerhalb des Docker Containers bedienen. Für staging und Produktion wollen wir auch nicht den statischen Ordner im Container. Hier bedienen wir die statischen Artikel nicht mit, Gunicorn sondern direkt mit Nginx.

Der Docker Python Flask Container enthält keine Datenbank usw., sondern nutzt die ISPConfig Dienste zur einfachen Konfiguration und Verwaltung:

  • Die ISPConfig Domain- und Seitenverwaltung (einschließlich Letsencrypt SSL)
  • Die Host-Datenbank (MariaDB), verbinden über einen Socket
  • Die Host-Mail (Postfix), verbinden Sie sich über port 25
  • Der Host-Webserver (Nginx), umgekehrt proxy und dient statisch.

Beachten Sie, dass ich das Docker image Programm auf meinem lokalen Rechner mit:

docker save ...

Die resultierende Tar-Datei wird auf den ISPConfig Server kopiert und entpackt, siehe unten.

Um für unsere Website zu konfigurieren ISPConfig , gehen wir wie gewohnt vor:

  • Installation Docker und DockerZusammenstellung (nur einmalig)
  • Domain hinzufügen
  • Website hinzufügen, Letsencrypt SSL einstellen
  • Hinzufügen von Datenbankbenutzern und Datenbanken
  • Füge einen gefangenen (!) Shell-Benutzer, Chroot Shell hinzu: Gefängnis-Set

Verzeichnisse auf ISPConfig, Benutzer und Gruppe

Als wir die Website hinzugefügt haben (und den Shell-Benutzer erstellt haben), haben wir einen (Linux) Benutzer dafür ISPConfig erstellt: My Shell User:

  • Benutzername: peterpepyco

Der Linux-Benutzer und die Gruppe, siehe ISPConfig -> Shell-Benutzer -> Optionen, in meinem Fall:

  • Web-Benutzername: web73
  • Webgruppe: Kunde2

Sie können dies auch sehen, indem Sie sich mit dem Shell-Benutzer anmelden und durch einige Verzeichnisse gehen und ein'ls -n' ausführen.

Es gibt einen Unterschied zwischen einem inhaftierten Shell-Benutzer und einem nicht inhaftierten Shell-Benutzer. In beiden Fällen ist das Basisverzeichnis:

/var/www/clients/client2/web73

Das Home-Verzeichnis ist:

/var/www/clients/client2/web73/home/peterpepyco

und das Webverzeichnis ist:

/var/www/clients/client2/web73/web

Wenn der Shell-Benutzer inhaftiert wird, wechselt die Wurzel des Dateisystems in das Basisverzeichnis, um die Gruppe vom Typ Shell-Benutzer zu erhalten:

groups

was in meinem Fall zurückkommt:

client2

Um den Docker als einen anderen Benutzer auszuführen, benötigen wir die Benutzer-ID, UID und Gruppen-ID, GID. Um den UID-Typ zu erhalten:

id -u

was in meinem Fall 5055 zurückkommt, und:

id -g

was in meinem Fall 5006 zurückkommt. Es gibt viele Möglichkeiten, UID und GID zu erhalten. Du kannst auch tippen:

cat /etc/passwd

die zurückkommt:

root:x:0:0:root:/root:/bin/bash
peterpepyco:x:5055:5006:::/bin/bash

und

cat /etc/group

die zurückkommt:

root:x:0:
client2:x:5006:

Sie können auch eine Datei erstellen,'echo "" > a', und dann'ls -n', etc. ausführen.

Ändern der Nginx Konfiguration

ISPConfig Gehen Sie zur Website und wählen Sie die Registerkarte Optionen. Im Abschnitt Nginx Richtlinien einfügen:

 location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    client_max_body_size 1M;  
  }

  location /static {
    alias /var/www/clients/client2/web73/web/static;
  }

Beachten Sie, dass Reverse proxy Requests an Port 8000 weitergeleitet werden. Dies ist der Port, an dem der Gunicorn WSGI-Server im Container lauscht.

Kopieren der Dateien

Im Shell User Home erstelle ich ein Verzeichnis-Docker, in dem ich den komprimierten Container, die Umgebungsvariablen-Datei, die docker-compose Dateien und die Datenbank kopiere. Nach dem Kopieren sieht das Verzeichnis so aus:

.
└── docker
    ├── .env
    ├── docker-compose_base_1.283_production.yml
    ├── docker-compose_production.yml
    ├── docker-volumes
    │   ├── cache
    │   │   ├── other
    │   │   ├── query_result
    │   │   └── render_template
    │   ├── flask_session
    │   └── log
    ├── peterspython2.dump_20191017
    ├── peterspython_image_web_1.283.tar
    └── project
        ├── Dockerfile
        └── requirements.txt

Zum Laden der Datenbank:

mysql -upeterspythonuser -p peterspython2 < peterspython2.dump_20191017

Um das Docker-Image zu laden, muss man root sein:

docker load -i peterspython_image_web_1.283.tar

Als nächstes wird der statische Ordner von meinem lokalen System in den Ordner'/web' kopiert, siehe auch oben.

Hinzufügen von Benutzer, UID und Gruppe, GID, zu docker-compose und DockerDatei

Ich benutze Docker-compose, um den Container zu starten und zu stoppen, Volumes zuzuordnen, etc. Die.env-Datei enthält eine Reihe von Konfigurationsvariablen, an die wir übergeben. Erster Teil dieser Datei:

# production environment vars

PROJECT_NAME=peterspython

FLASK_CONFIG=production

# docker-compose, docker
# peterpepyco:client2
CONTAINER_USER=peterpepyco
CONTAINER_UID=5055
CONTAINER_GROUP=client2
CONTAINER_GID=5006
...

Der erste Teil der Compose-Datei:

# docker-compose_base.yml

version: '3.2'

services:
  web:
    image: ${PROJECT_NAME}_image_web:1.283
    container_name: ${PROJECT_NAME}_container_web
    env_file:
      - ./.env
    restart: always
    build:
      context: ./project
      dockerfile: Dockerfile
      args:
        - CONTAINER_USER=${CONTAINER_USER}
        - CONTAINER_UID=${CONTAINER_UID}
        - CONTAINER_GROUP=${CONTAINER_GROUP}
        - CONTAINER_GID=${CONTAINER_GID}

    ports:
      - "${SERVER_PORT_HOST}:${SERVER_PORT_CONTAINER}"
    volumes:
...

und dann in der DockerDatei:

...
# create and set working directory
RUN mkdir -p /home/flask/project
WORKDIR /home/flask/project

# copy app code into container
COPY . ./

# create group and user used in this container
ARG CONTAINER_USER
ARG CONTAINER_UID
ARG CONTAINER_GROUP
ARG CONTAINER_GID

RUN addgroup -g $CONTAINER_GID $CONTAINER_GROUP && \
    adduser -D -H -G $CONTAINER_GROUP -u $CONTAINER_UID $CONTAINER_USER && \
    chown -R $CONTAINER_USER:$CONTAINER_GROUP /home/flask

USER $CONTAINER_USER

Starten des Containers

Auch dies erfordert, dass du root bist:

docker-compose -f docker-compose_base_1.283_production.yml -f docker-compose_production.yml up -d

Das Ergebnis ist:

Creating network "docker_default" with the default driver
Creating peterspython_container_web ... done

Wenn der Container keine Prüfprotokolle, Nachrichten startet. Wenn es läuft, aber Sie Fehler erhalten, können Sie den laufenden Container eingeben, indem Sie zuerst die Container-ID erhalten:

docker ps

die zurückkommt:

CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                    NAMES
292aa9bcecaf        peterspython_image_web:1.283   "/usr/local/bin/guni…"   18 hours ago        Up 18 hours         0.0.0.0:8000->8000/tcp   peterspython_container_web

Geben Sie dann den laufenden Behälter ein:

docker exec -it 292aa9bcecaf sh

Beachten Sie, dass wir sh und nicht bash starten, da bash nicht im Alpine Bild ist.

Zusammenfassung

Es ist nicht wirklich schwierig, wenn man (Teil von) Docker und (Teil von) ISPConfigversteht. Jetzt können Sie alles, was Sie wollen, auf einem ISPConfig Server ausführen.

Ich habe ein Maximum an ISPConfig Diensten genutzt, ich bin zufrieden damit, MariaDB aber einige Leute mögen sich beschweren, dass z.B. PostgreSQL nicht unterstützt wird. Es wäre schön, wenn ISPConfig Sie PostgreSQL als Option hinzufügen würden. Das wäre besser, als dem Container einen Postgre-ServiceSQL hinzuzufügen, der die Größe des Containers erhöht.

Ein Problem ist, dass wir beim Laden des Containers Docker image und beim Starten und Stoppen des Containers root sein müssen, tatsächlich ist dies für jeden Docker Befehl erforderlich, d.h. diese Methode ist nicht nur für einige zufällige Clients geeignet. Es wäre schön, wenn ISPConfig es eine Methode unterstützen würde, um Befehle pro Site Docker und Docker-Compose zu erlauben. Auch Container zeigen Häfen, die mit bestehenden in Konflikt geraten können. Dies kann durch die Zuweisung eines Portbereichs pro Standort gelöst werden.

Ist das Setup ISPConfig sicher genug, um die im Gefängnis befindlichen Shell-Benutzer-Anmeldeinformationen zu verwenden, um den Container auszuführen? Ich sehe ein mögliches Problem mit der Verwendung der UID und dem Starten des Containers als root. Die UID des gefangenen Shell-Benutzers peterpepyco ist die gleiche wie die UID von web73, was bedeutet, dass der Docker Container tatsächlich als web73:client2 und nicht als peterpepyco:client2 läuft. Ich muss das weiter untersuchen. Möglicherweise kann ein Namensraum verwendet werden. Aber im Moment bin ich froh, dass es läuft.

Links / Impressum

How do I add a user when I'm using Alpine as a base image?
https://stackoverflow.com/questions/49955097/how-do-i-add-a-user-when-im-using-alpine-as-a-base-image

Running Docker Containers as Current Host User
https://jtreminio.com/blog/running-docker-containers-as-current-host-user/

Compose file version 3 reference
https://docs.docker.com/compose/compose-file/

How to copy Docker images from one host to another without using a repository
https://stackoverflow.com/questions/23935141/how-to-copy-docker-images-from-one-host-to-another-without-using-a-repository

Isolate containers with a user namespace
https://docs.docker.com/engine/security/userns-remap/

Einen Kommentar hinterlassen

Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.

Kommentare

Eine Antwort hinterlassen

Antworten Sie anonym oder melden Sie sich an, um zu antworten.