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.
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/
Mehr erfahren
Docker Docker-compose Flask ISPConfig
Neueste
- Don't Repeat Yourself (DRY) mit Jinja2
- SQLAlchemy, PostgreSQL, maximale Anzahl von Zeilen pro user
- Anzeige der Werte in den dynamischen Filtern SQLAlchemy
- Sichere Datenübertragung mit Public Key Verschlüsselung und pyNaCl
- rqlite: eine hochverfügbare und distverteilte SQLite -Alternative
- Sollte ich meinen Docker Swarm auf Kubernetes migrieren?
Meistgesehen
- Verwendung von Pythons pyOpenSSL zur Überprüfung von SSL-Zertifikaten, die von einem Host heruntergeladen wurden
- Verwendung von UUIDs anstelle von Integer Autoincrement Primary Keys mit SQLAlchemy und MariaDb
- Verbindung zu einem Dienst auf einem Docker -Host von einem Docker -Container aus
- SQLAlchemy: Verwendung von Cascade Deletes zum Löschen verwandter Objekte
- PyInstaller und Cython verwenden, um eine ausführbare Python-Datei zu erstellen
- Flask RESTful API Validierung von Anfrageparametern mit Marshmallow-Schemas