C'est un peu brouillon.
Tout d'abord, configurez le Raspberry Pi 4B.
J'ai entendu dire que Stretch qui fonctionnait sur 3B + ne fonctionnait pas sur 4B, j'ai donc apporté un nouveau Raspbian Buster de Télécharger Raspbian pour Raspberry Pi. Gravez sur une carte Micro SD. Buster est Lite au lieu de Desktop car il semble économiser de la mémoire (bien qu'il ait augmenté) (pour une utilisation serveur de toute façon).
~~ Je n'avais pas de câble / adaptateur mini HDMI (c'est dur, même si c'est Micro ...), donc ~~ (PostScript 20/03/07: faux. Micro HDMI. Mini est un gars mince?) Monitorless installer. Il se vend 100 yens, alors procurez-vous-le en cas de besoin. Insérez la carte Micro SD dans l'unité principale et connectez-la au routeur avec un câble LAN. Connectez une alimentation 5V 3A Type-C (dur, remplacez par Micro) et allumez l'alimentation (j'ai un peu peur si je ne veux pas acheter une nouvelle alimentation car la conversion entre Micro USB et Type-C semble être d'environ 100).
Vérifiez l'adresse IP attribuée par DHCP à partir du routeur et établissez une connexion SSH (mot de passe initial) sur le LAN.
Quand il dit Trop d'échecs d'authentification
ou est joué avec publickey
, il ne parvient pas à s'authentifier avec la clé publique, alors définissez -o PreferredAuthentications = password
ou -o PubkeyAuthentication = no
comme option de la commande ssh Ou ajoutez PreferredAuthentications password
ou PubkeyAuthentication no
à ~ / .ssh / config
.
Changez le mot de passe, puis changez le nom d'utilisateur en même temps. Vous ne pouvez pas changer le nom d'utilisateur lorsque vous êtes connecté à l'utilisateur pi, alors créez un nouvel utilisateur sudoer et connectez-vous à nouveau (cette fois, c'est dans le LAN, vous pouvez donc définir un mot de passe root temporaire).
Créez un tmpuser en exécutant la commande suivante en tant qu'utilisateur pi.
#Le répertoire de base n'est pas créé pour useradd
sudo useradd tmpuser
sudo passwd tmpuser
Ajoutez ensuite tmpuser aux sudoers.
sudo adduser tmpuser sudo
Si vous voulez un petit détour, modifiez / etc / sudoers et ajoutez tmpuser. D'une manière ou d'une autre, / etc / sudoers et d'autres sont en lecture seule (chmod convient parfaitement), alors créez /etc/sudoers.d/011_tmpuser (vous pouvez l'ajouter au groupe sudo).
# /etc/sudoers.d/011_tmpuser
tmpuser ALL=(ALL:ALL) ALL
Déconnectez-vous une fois, reconnectez-vous en tant qu'utilisateur tmpuser, changez le nom de l'utilisateur pi avec la commande suivante, changez le nom du groupe pi et enfin déplacez le répertoire de base.
sudo usermod -l NEW_NAME pi
sudo groupmod -n NEW_NAME pi
sudo usermod -m -d /home/NEW_NAME NEW_NAME
Déconnectez-vous de l'utilisateur tmpuser, reconnectez-vous en tant qu'utilisateur NEW_NAME et supprimez l'utilisateur tmpuser. Si vous faites un détour, supprimez également /etc/sudoers.d/011_tmpuser. Par défaut, l'utilisateur pi appartient au groupe sudo, il n'est donc pas nécessaire d'ajouter à nouveau l'utilisateur NEW_NAME aux sudoers (devrait).
sudo userdel tmpuser
# sudo rm /etc/sudoers.d/011_tmpuser
# /etc/hostname
NEW_HOSTNAME
# /etc/hosts
...
127.0.1.1 NEW_HOSTNAME
Enregistrez la clé publique auprès de l'utilisateur NEW_NAME et modifiez / etc / ssh / sshd_config pour que l'authentification SSH soit uniquement la clé publique.
côté pi
mkdir ~/.ssh
chmod 700 ~/.ssh
Côté hôte
cd ~/.ssh
ssh-keygen -f KEY_NAME
scp KEY_NAME.pub RPI4_HOST:.ssh/
côté pi
cd ~/.ssh
cat KEY_NAME.pub >> authorized_keys
chmod 600 authorized_keys
Après cela, spécifiez ʻIdentity File` dans ~ / .ssh / config. Lorsqu'il est toujours appelé «Trop d'échecs d'authentification», ajoutez «Identités uniquement oui».
Modifiez / etc / ssh / sshd_config
pour définir PasswordAuthentication no
si nécessaire.
sudo curl -fsSL https://get.docker.com/ | sh
sudo apt install python3-pip
sudo apt install libffi-dev
sudo pip3 install docker-compose
Puisque le projet Django était géré par git, j'ai migré le programme vers le nouveau serveur avec git clone
. DB (SQLite3) est migré avec scp
.
Étant donné que l'environnement était géré par virtualenv sur l'ancien serveur, requirements.txt est généré à partir d'ici.
pip3 freeze > requirements.txt
Comme c'est un gros problème, nous allons créer l'environnement pour le nouveau serveur avec Docker / docker-compose. C'était une configuration de django: wsgi-gunicorn-nginx, mais avant tout, c'était un test de fonctionnement en soi.
# 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
Exécutez MySQL (MariaDB) avec docker-compose sur Raspberry Pi. Utilisez 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:
...
Je le retournerai plus tard, donc tout en facilitant le retour, je jouerai avec settings.py
de Django de manière appropriée et spécifierai la base de données à partir de la variable d'environnement.
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,
},
}
Modifiez docker-compose.yml
comme suit. Mettez en commentaire toute la partie DATABASE de l'environnement, ou créez un autre docker-compose.yml
pour que la base de données puisse être retournée à SQLite3.
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
Ajoutez PyMySQL
à requirements.txt
et ajoutez ce qui suit en haut de manage.py
.
if os.environ.get('DATABASE_ENGINE') == 'django.db.backends.mysql':
import pymysql
pymysql.install_as_MySQLdb()
Si Django accède avant que l'initialisation de MySQL ne soit terminée, Django supprimera une erreur, alors réexécutez docker-compose up
à la première exécution. Si Django démarre en premier lors de la deuxième migration, gérez-le en insérant un sleep approprié ou en créant un script d'attente. Après avoir pris en sandwich gunicorn dans la 9e section, même si Django (gunicorn) commence en premier, l'erreur disparaît (comme), vous n'aurez peut-être pas trop à vous inquiéter.
command: bash -c "sleep 5 && python manage.py runserver 0.0.0.0:8000"
Selon la définition du modèle de base de données, sudo docker-compose up -d
et sudo docker-compose exec web python3 manage.py migrate
donneront une erreur. Par exemple, si vous avez un TextField avec une contrainte unique et que vous ne spécifiez pas max_length
. Cette fois, j'ai changé l'URL de TextField au lieu d'URLField en URLField, et j'ai spécifié max_length
(255 ou moins) pour TextField, qui est connue pour être une courte chaîne de caractères, et je l'ai résolue (cependant, sur Raspberry Pi, ce n'est pas suffisant. Cela n'a pas fonctionné, j'ai donc fini par supprimer la contrainte unique plus tard).
Dans ce domaine, j'ai déplacé le projet et la base de données vers la machine principale pour accélérer et mener des expériences. Cette fois, il faut changer l'image de MySQL, mais le bon point de Docker est qu'il prépare automatiquement le même environnement (généralement) et ne pollue / n'affecte pas l'environnement hôte (compatible sans image officielle) Je suis troublé par le sexe ...?).
Après avoir éliminé l'erreur de migration, renvoyez la base de données vers SQLite3, migrez-la, puis videz les données dans 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'")
Il semble que ce n'était pas bon de mettre la contrainte unique_together sur OneToOneField (OneToOne ne peut pas être utilisé plusieurs-à-un), alors je l'ai changé en ForeignKey. De plus, à ce stade, même si cela fonctionnait avec mariadb
, cela ne fonctionnait pas car l'erreur autour de la longueur de la clé n'a probablement pas disparu parce qu'elle était définie sur utf8mb4 dans jsurf / rpi-mariadb
, j'ai donc supprimé la contrainte unique de toutes les chaînes de caractères. En plus de cela, j'ai dû réécrire directement les fichiers sous migrations car la migration s'est arrêtée à mi-chemin ici. Même si j'ai envoyé la base de données traitée par un autre PC directement, cela n'a pas fonctionné, donc je suis toujours inquiet pour la compatibilité. Après de nombreux essais et erreurs, j'ai enfin pu charger des données.
Ajoutez gunicorn
à requirements.txt
.
Modifiez docker-compose.yml
. Puisqu'il consomme de la mémoire (je pense), ajustez le nombre de travailleurs -w
si nécessaire.
# 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"
Comme pour manage.py
, ajoutez ce qui suit en haut de wsgi.py
.
if os.environ.get('DATABASE_ENGINE') == 'django.db.backends.mysql':
import pymysql
pymysql.install_as_MySQLdb()
(Post-scriptum du 20/02/15)
J'ai défini les paramètres en utilisant busybox crond ci-dessous, mais il semble que le script de production n'ait pas bien fonctionné en raison des inconvénients liés au journal, j'ai donc écrit un script d'exécution périodique en Python et un conteneur avec la même configuration que le conteneur Django J'ai décidé d'en faire un autre et de l'exécuter. Cependant, comme il est redondant, il peut être préférable de créer un point de terminaison pour une exécution périodique du côté du conteneur Django et d'en faire un conteneur qui ignore simplement les requêtes HTTP.
(Ancienne version)
Cette fois, exécutez une exécution régulière dans le même conteneur que Django.
Jusqu'à présent, le script d'exécution périodique était généralement écrit en python ou exécuté par la minuterie de systemd. Cette fois, c'était systemd / timer, j'ai donc essayé de le déplacer dans le conteneur Docker, mais bien que je puisse exécuter le script dans le conteneur Docker à partir de l'hôte avec ʻexec`, j'exécute systemd / timer dans le conteneur Docker Je ne suis pas sûr.
Quoi qu'il en soit, le système d'exploitation de base de python: 3
est Debian et il ne semble pas y avoir de systemd (init.d), donc je vais l'exécuter régulièrement avec cron.
C'était la première fois que j'utilisais cron, donc je me suis finalement perdu.
Je veux hériter des variables d'environnement spécifiées par Docker, j'utilise donc crond inclus dans busybox.
Tout d'abord, créez le fichier suivant crontab
dans le répertoire d'exécution.
# * * * * * cd /code && echo `env` >> env.txt
0 */6 * * * cd /code && /usr/local/bin/python3 AUTORUN_SCRIPT.py
Le haut est le paramètre pour écrire des variables d'environnement dans un fichier toutes les minutes (pour le débogage), et le bas est le paramètre pour exécuter automatiquement /code/AUTORUN_SCRIPT.py dans l'utilisateur root et le répertoire de travail / code toutes les 6 heures. Le temps est bien avec JST.
Ensuite, définissez l'installation de crond et l'ajout du fichier de configuration dans le Dockerfile. La bonne réponse est que / var / spool / cron / crontabs / root est un fichier plutôt qu'un répertoire.
# Dockerfile
...
RUN apt update && apt install -y \
busybox-static
ENV TZ Asia/Tokyo
COPY crontab /var/spool/cron/crontabs/root
...
Assurez-vous ensuite que crond démarre au démarrage du conteneur Docker. Notez que CMD
dans Dockerfile
n'est pas exécuté car nous utilisons cette fois-ci docker-compose. À la place, ajoutez la commande start pour crond à command
dans docker-compose.yml
. Puisque crond
est exécuté en arrière-plan, gunicorn
sera lancé automatiquement.
# 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"
...
Depuis que je joue avec la base de données de Django, j'ai ajouté l'installation de pymysql dans ʻAUTORUN_SCRIPT.py (identique à
manage.py,
wsgi.py`), et j'ai confirmé que le script expérimental fonctionne. .. Supprimez les paramètres cron pour le débogage et complétez les paramètres.
Ajoutez restart: always
à docker-compose.yml
pour qu'il démarre automatiquement au démarrage de l'hôte et démarrez-le en arrière-plan avec sudo docker-compose up -d
. Après cela, vous pouvez redémarrer l'hôte (sudo docker-compose ps
, sudo docker ps
).
Nous avons réussi à migrer le matériel (Raspberry Pi), à migrer la base de données, à migrer le moteur de base de données, à migrer vers Docker et à le rendre persistant.
Les performances se sont améliorées (semble être) en raison des améliorations des spécifications matérielles et de la migration vers MySQL, et les opérations de base de données peuvent maintenant être effectuées en parallèle (comme), donc lors de l'accès à la base de données en même temps L'erreur «La base de données est verrouillée» qui se produisait n'est plus visible.
C'est un projet personnel, alors j'essaie de casser les paramètres du journal ou de le couper de manière unique ... J'ai abandonné parce que cela m'a pris du temps. Cependant, après le chargement des données, il peut être possible de retourner des données uniques par migration.
Après cela, j'ai pensé qu'il serait préférable de séparer cron dans un autre conteneur, mais comme il a exactement la même dépendance que le projet Django, je l'ai mis ensemble sans le diviser. Comment divisez-vous cela ...?
Recommended Posts