Es ist ein bisschen chaotisch.
Richten Sie zuerst den Raspberry Pi 4B ein.
Ich habe gehört, dass Stretch, das auf 3B + funktioniert, auf 4B nicht funktioniert, deshalb habe ich einen neuen Raspbian Buster von Raspbian für Raspberry Pi herunterladen mitgebracht. Brennen Sie auf eine Micro-SD-Karte. Buster ist Lite anstelle von Desktop, da es anscheinend Speicher spart (obwohl es zugenommen hat) (für den Servergebrauch sowieso).
~~ Ich hatte kein Mini-HDMI-Kabel / Adapter (es ist schwer, obwohl es Micro ist ...), also ~~ (20/03/07 Nachtrag: falsch. Micro HDMI. Mini ist ein dünner Typ?) Monitorlos einrichten. Es kostet 100 Yen, also besorgen Sie es sich bei Bedarf. Legen Sie die Micro SD-Karte in das Hauptgerät ein und verbinden Sie sie mit einem LAN-Kabel mit dem Router. Schließen Sie ein 5V 3A Typ-C-Netzteil an (fest, von Micro ersetzen) und schalten Sie das Gerät ein (Wenn Sie das Netzteil nicht ersetzen möchten, weil die Konvertierung zwischen Micro-USB und Typ-C zu 100% zu sein scheint, ist dies etwas beängstigend).
Überprüfen Sie die vom Router über DHCP zugewiesene IP-Adresse und stellen Sie im LAN eine SSH-Verbindung (anfängliches Kennwort) her.
Wenn "Zu viele Authentifizierungsfehler" angezeigt wird oder mit "publickey" gespielt wird, kann die Authentifizierung nicht mit dem öffentlichen Schlüssel erfolgen. Setzen Sie daher als Option des Befehls ssh "-o PreferredAuthentications = password" oder "-o PubkeyAuthentication = no". Oder fügen Sie ~ / .ssh / config`` PreferredAuthentications password
oder PubkeyAuthentication no
hinzu.
Ändern Sie gleichzeitig das Passwort und dann den Benutzernamen. Sie können den Benutzernamen nicht ändern, während Sie beim pi-Benutzer angemeldet sind. Erstellen Sie daher einen neuen sudoer-Benutzer und melden Sie sich erneut an (diesmal im LAN, sodass Sie möglicherweise ein temporäres Root-Kennwort festlegen können).
Erstellen Sie einen tmpuser, indem Sie den folgenden Befehl als pi-Benutzer ausführen.
#Das Home-Verzeichnis wurde nicht für useradd erstellt
sudo useradd tmpuser
sudo passwd tmpuser
Fügen Sie dann tmpuser zu sudoers hinzu.
sudo adduser tmpuser sudo
Wenn Sie einen kleinen Umweg wünschen, bearbeiten Sie / etc / sudoers und fügen Sie tmpuser hinzu. Irgendwie sind / etc / sudoers und andere schreibgeschützt (chmod ist in Ordnung), also erstelle /etc/sudoers.d/011_tmpuser (du kannst es der sudo-Gruppe hinzufügen).
# /etc/sudoers.d/011_tmpuser
tmpuser ALL=(ALL:ALL) ALL
Melden Sie sich einmal ab, melden Sie sich erneut als tmpuser-Benutzer an, ändern Sie den Namen des pi-Benutzers mit dem folgenden Befehl, ändern Sie den Namen der pi-Gruppe und verschieben Sie schließlich das Ausgangsverzeichnis.
sudo usermod -l NEW_NAME pi
sudo groupmod -n NEW_NAME pi
sudo usermod -m -d /home/NEW_NAME NEW_NAME
Melden Sie sich vom Benutzer tmpuser ab, melden Sie sich erneut als Benutzer NEW_NAME an und löschen Sie den Benutzer tmpuser. Wenn Sie einen Umweg machen, löschen Sie auch /etc/sudoers.d/011_tmpuser. Standardmäßig gehört der pi-Benutzer zur sudo-Gruppe, sodass der Benutzer NEW_NAME nicht erneut zu sudoers hinzugefügt werden muss (sollte).
sudo userdel tmpuser
# sudo rm /etc/sudoers.d/011_tmpuser
# /etc/hostname
NEW_HOSTNAME
# /etc/hosts
...
127.0.1.1 NEW_HOSTNAME
Registrieren Sie den öffentlichen Schlüssel beim Benutzer NEW_NAME und bearbeiten Sie / etc / ssh / sshd_config, um die SSH-Authentifizierung nur zum öffentlichen Schlüssel zu machen.
pi Seite
mkdir ~/.ssh
chmod 700 ~/.ssh
Host-Seite
cd ~/.ssh
ssh-keygen -f KEY_NAME
scp KEY_NAME.pub RPI4_HOST:.ssh/
pi Seite
cd ~/.ssh
cat KEY_NAME.pub >> authorized_keys
chmod 600 authorized_keys
Sie müssen lediglich "IdentityFile" in ~ / .ssh / config angeben. Wenn immer noch "Zu viele Authentifizierungsfehler" angezeigt wird, fügen Sie "IdentitiesOnly yes" hinzu.
Bearbeiten Sie / etc / ssh / sshd_config
, um bei Bedarf PasswordAuthentication no
festzulegen.
sudo curl -fsSL https://get.docker.com/ | sh
sudo apt install python3-pip
sudo apt install libffi-dev
sudo pip3 install docker-compose
Da das Django-Projekt von git verwaltet wurde, habe ich das Programm mit "git clone" auf den neuen Server migriert. DB (SQLite3) wird mit scp
migriert.
Da die Umgebung von virtualenv auf dem alten Server verwaltet wurde, wird von hier aus die Datei require.txt generiert.
pip3 freeze > requirements.txt
Da es eine große Sache ist, werden wir die Umgebung für den neuen Server mit Docker / Docker-Compose erstellen. Es war eine Konfiguration von Django: wsgi-gunicorn-nginx, aber vor allem war es ein Betriebstest für sich.
# Dockerfile
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
# docker-compose.yml
version: '3'
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "127.0.0.1:8000:8000"
environment:
- ENVIRONMENT=production
sudo docker-compose up
Führen Sie MySQL (MariaDB) mit Docker-Compose auf Raspberry Pi aus. Verwenden Sie jsurf / rpi-mariadb
.
...
db:
# image: mariadb
image: jsurf/rpi-mariadb
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- DATABASE_DIRECTORY:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=ROOT_PASSWORD
- MYSQL_DATABASE=DATABASE_NAME
- MYSQL_USER=USER
- MYSQL_PASSWORD=PASSWORD
web:
...
Ich werde es später zurückgeben. Um die Rückgabe zu vereinfachen, werde ich entsprechend mit settings.py
von Django spielen und die DB aus der Umgebungsvariablen angeben.
DATABASE_ENGINE = os.environ.get('DATABASE_ENGINE', 'django.db.backends.sqlite3')
DATABASE_OPTIONS = {}
if DATABASE_ENGINE == 'django.db.backends.mysql':
DATABASE_OPTIONS = {
'charset': os.environ.get('DATABASE_CHARSET'),
}
DATABASES = {
'default': {
'ENGINE': DATABASE_ENGINE,
'HOST': os.environ.get('DATABASE_HOST'),
'PORT': os.environ.get('DATABASE_PORT'),
'NAME': os.environ.get('DATABASE_NAME', os.path.join(BASE_DIR, 'db.sqlite3')),
'USER': os.environ.get('DATABASE_USER'),
'PASSWORD': os.environ.get('DATABASE_PASSWORD'),
'OPTIONS': DATABASE_OPTIONS,
},
}
Bearbeiten Sie docker-compose.yml
wie folgt. Kommentieren Sie den gesamten DATABASE-Teil der Umgebung aus oder erstellen Sie eine andere "docker-compose.yml", damit die Datenbank an SQLite3 zurückgegeben werden kann.
web:
...
environment:
- ENVIRONMENT=production
- DATABASE_ENGINE=django.db.backends.mysql
- DATABASE_HOST=db
- DATABASE_PORT=3306
- DATABASE_NAME=DATABASE_NAME
- DATABASE_USER=USER
- DATABASE_PASSWORD=PASSWORD
- DATABASE_CHARSET=utf8mb4
depends_on:
- db
Fügen Sie "PyMySQL" zu "require.txt" hinzu und fügen Sie oben in "manage.py" Folgendes hinzu.
if os.environ.get('DATABASE_ENGINE') == 'django.db.backends.mysql':
import pymysql
pymysql.install_as_MySQLdb()
Wenn Django zugreift, bevor die Initialisierung von MySQL abgeschlossen ist, wird Django einen Fehler löschen. Führen Sie daher "Docker-Compose Up" bei der ersten Ausführung erneut aus. Wenn Django bei der zweiten Migration zuerst gestartet wird, können Sie einen entsprechenden Ruhezustand einfügen oder ein Warteskript erstellen. Nach dem Sandwiching von Gunicorn im 9. Abschnitt verschwindet der Fehler (wie), selbst wenn Django (Gunicorn) zuerst startet, sodass Sie sich möglicherweise nicht zu viele Sorgen machen müssen.
command: bash -c "sleep 5 && python manage.py runserver 0.0.0.0:8000"
Abhängig von der Definition des DB-Modells geben "sudo docker-compose up -d" und "sudo docker-compose exec web python3 manage.py migrate" einen Fehler aus. Wenn Sie beispielsweise ein TextField mit einer eindeutigen Einschränkung haben und nicht "max_length" angeben. Dieses Mal habe ich die URL von TextField anstelle von URLField in URLField geändert und max_length
(255 oder weniger) für TextField angegeben, das als kurze Zeichenfolge bekannt ist, und es gelöst (auf Raspberry Pi reicht dies jedoch nicht aus. Es hat nicht funktioniert, daher habe ich die eindeutige Einschränkung später entfernt.
In diesem Bereich habe ich das Projekt und die Datenbank zur Beschleunigung auf die Hauptmaschine verschoben und Experimente durchgeführt. Dieses Mal muss das Image von MySQL geändert werden. Der gute Punkt von Docker ist jedoch, dass es (im Allgemeinen) automatisch dieselbe Umgebung vorbereitet und die Host-Umgebung nicht verschmutzt / beeinträchtigt (kompatibel ohne offizielles Image). Sex macht mir Sorgen ...?).
Nachdem Sie den Migrationsfehler behoben haben, geben Sie die Datenbank an SQLite3 zurück, migrieren Sie sie und sichern Sie die Daten an json.
sudo docker-compose run web bash
python3 manage.py makemigrations
python3 manage.py migrate
# python3 manage.py dumpdata > dump.json
python3 manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission > dump.json
python3 manage.py migrate
python3 manage.py loaddata dump.json
django.db.utils.IntegrityError: Problem installing fixture '/code/dump.json': Could not load APP.MODELNAME(pk=PK_NUM): (1062, "Duplicate entry 'ONE_FIELD_NUM' for key 'ONE_FIELD'")
Es scheint nicht gut zu sein, die Einschränkung unique_together für OneToOneField festzulegen (OneToOne kann nicht einzeln verwendet werden), daher habe ich sie in ForeignKey geändert. Zu diesem Zeitpunkt funktionierte es zwar nicht mit mariadb
, aber nicht, da der Fehler um die Schlüssellänge wahrscheinlich nicht verschwand, weil er in jsurf / rpi-mariadb
auf utf8mb4 gesetzt war, sodass ich die eindeutige Einschränkung aller Zeichenketten entfernte. Außerdem musste ich die Dateien unter Migrationen direkt neu schreiben, da die Migration hier auf halbem Weg gestoppt wurde. Selbst wenn ich die von einem anderen PC verarbeitete Datenbank direkt gesendet habe, hat sie nicht funktioniert, sodass ich mir immer noch Sorgen um die Kompatibilität mache. Nach vielen Versuchen und Fehlern konnte ich endlich Daten laden.
Füge gunicorn
zu require.txt
hinzu.
Bearbeiten Sie "docker-compose.yml". Da es Speicher verbraucht (glaube ich), passen Sie die Anzahl der Arbeiter -w
nach Bedarf an.
# command: /usr/local/bin/gunicorn -w 4 -b 0.0.0.0:8000 MY_PROJECT.wsgi -t 300
command: bash -c "sleep 5 && gunicorn -w 4 -b 0.0.0.0:8000 MY_PROJECT.wsgi -t 300"
Fügen Sie wie bei manage.py
oben in wsgi.py
Folgendes hinzu.
if os.environ.get('DATABASE_ENGINE') == 'django.db.backends.mysql':
import pymysql
pymysql.install_as_MySQLdb()
(20/02/15 Nachtrag)
Ich habe die Einstellungen mit Busybox Crond unten vorgenommen, aber es scheint, dass das Produktionsskript aufgrund der Unannehmlichkeiten im Protokoll nicht gut funktioniert hat. Deshalb habe ich ein Skript für die regelmäßige Ausführung in Python und einen Container mit derselben Konfiguration wie der Django-Container geschrieben Ich beschloss, einen anderen zu machen und ihn auszuführen. Da es jedoch redundant ist, ist es möglicherweise besser, einen Endpunkt für die regelmäßige Ausführung auf der Django-Containerseite zu erstellen und ihn zu einem Container zu machen, der nur HTTP-Anforderungen überspringt.
(Alte Version)
Führen Sie dieses Mal einen regulären Lauf im selben Container wie Django aus.
Bisher wurde das periodische Ausführungsskript normalerweise in Python geschrieben oder vom Systemd-Timer ausgeführt. Diesmal war es systemd / timer, also habe ich versucht, es in den Docker-Container zu verschieben, aber obwohl ich das Skript im Docker-Container vom Host mit exec
ausführen kann, führe ich systemd / timer im Docker-Container aus Ich bin mir nicht sicher.
Wie auch immer, das Basis-Betriebssystem von python: 3
ist Debian und es scheint kein systemd (init.d) zu geben, also werde ich es regelmäßig mit cron ausführen.
Es war mein erstes Mal, dass ich Cron benutzte, also habe ich mich endlich verlaufen.
Ich möchte die von Docker angegebenen Umgebungsvariablen erben, daher verwende ich crond, das in der Busybox enthalten ist.
Erstellen Sie zunächst die folgende Datei "crontab" im Ausführungsverzeichnis.
# * * * * * cd /code && echo `env` >> env.txt
0 */6 * * * cd /code && /usr/local/bin/python3 AUTORUN_SCRIPT.py
Oben ist die Einstellung zum Schreiben der Umgebungsvariablen jede Minute in eine Datei (zum Debuggen) und unten die Einstellung zum automatischen Ausführen von /code/AUTORUN_SCRIPT.py als Root-Benutzer und Arbeitsverzeichnis / Code alle 6 Stunden. Die Zeit ist in Ordnung mit JST.
Definieren Sie als Nächstes die Installation von crond und das Hinzufügen der Konfigurationsdatei in der Docker-Datei. Die richtige Antwort lautet, dass / var / spool / cron / crontabs / root eher eine Datei als ein Verzeichnis ist.
# Dockerfile
...
RUN apt update && apt install -y \
busybox-static
ENV TZ Asia/Tokyo
COPY crontab /var/spool/cron/crontabs/root
...
Stellen Sie dann sicher, dass crond startet, wenn der Docker-Container startet. Beachten Sie, dass "CMD" in "Dockerfile" nicht ausgeführt wird, da wir diesmal Docker-Compose verwenden. Fügen Sie stattdessen den Startbefehl für crond zu command
in docker-compose.yml
hinzu. Da crond
im Hintergrund ausgeführt wird, wird gunicorn
automatisch gestartet.
# docker-compose.yml
...
# command: bash -c "busybox crond && gunicorn -w 4 -b 0.0.0.0:8000 MY_PROJECT.wsgi -t 300"
command: bash -c "sleep 5 && busybox crond && gunicorn -w 4 -b 0.0.0.0:8000 MY_PROJECT.wsgi -t 300"
...
Da ich mit der DB von Django spiele, habe ich pymysql install in AUTORUN_SCRIPT.py
hinzugefügt (wie manage.py
, wsgi.py
) und bestätigt, dass das experimentelle Skript funktioniert. .. Löschen Sie die Cron-Einstellungen für das Debuggen und vervollständigen Sie die Einstellungen.
Fügen Sie restart: always
zu docker-compose.yml
hinzu, damit es automatisch startet, wenn der Host gestartet wird, und starten Sie es im Hintergrund mit sudo docker-compose up -d
. Danach können Sie den Host neu starten (sudo docker-compose ps
, sudo docker ps
).
Wir haben die Hardware (Raspberry Pi) erfolgreich migriert, die Datenbank migriert, die DB-Engine migriert, auf Docker migriert und sie dauerhaft gemacht.
Die Leistung hat sich (anscheinend) aufgrund von Verbesserungen der Hardwarespezifikationen und der Migration zu MySQL verbessert, und DB-Vorgänge können jetzt parallel (wie) ausgeführt werden, also beim gleichzeitigen Zugriff auf die DB Der aufgetretene Fehler "Datenbank ist gesperrt" wird nicht mehr angezeigt.
Es ist ein persönliches Projekt, also versuche ich, die Protokolleinstellungen zu brechen oder sie eindeutig zu schneiden ... Ich habe aufgegeben, weil ich lange gebraucht habe. Nach dem Laden der Daten kann es jedoch möglich sein, durch Migration ein eindeutiges Ergebnis zurückzugeben.
Danach dachte ich, dass es besser wäre, cron in separate Container zu trennen, aber da es genau die gleiche Abhängigkeit wie das Django-Projekt hat, habe ich es zusammengestellt, ohne es zu teilen. Wie teilt man das auf ...?
Recommended Posts