[PYTHON] J'ai créé une commande appdo pour exécuter des commandes dans le contexte de l'application

La préparation de la connexion à l'hôte à l'exécution de rake dans l'application Ruby on Rails est trop longue, alors combinons-la en une seule commande, ʻappdo`.

Le problème que vous souhaitez résoudre

Si vous mettez Ruby dans rbenv ou rvm, vous ne pourrez pas trouver ruby lors de l'exécution de commandes avec sudo ou cron. Eh bien, vous pouvez lire ~ / .bashrc etc. à chaque fois, mais cela complique la commande. Si le nombre d'endroits où un tel traitement est effectué augmente, des omissions de correction sont susceptibles de se produire. C'est emballé.

Lors de l'exécution d'une application Ruby on Rails, ni bundle exec rake ni bin / rails runner ne peuvent être exécutés sans plus de cd $ RAILS_ROOT. En conséquence, les commandes opérationnelles deviennent de plus en plus longues, et "crontab" et "config / deploy.rb" deviennent difficiles à maintenir. C'est emballé.

** Quoi qu'il en soit, le même hôte prépare la même chose, donc je devrais avoir un tel paramètre sur l'hôte **, donc j'ai fait une telle commande.

La solution est ʻappdo`

J'ai créé une commande ʻappdo pour exécuter des commandes dans le contexte de l'application. [pip install`](https://pypi.python.org/pypi/appdo) Vous pouvez.

pip install appdo

Avec ʻappdo, les rails c` qui fonctionnaient comme ça ...

$ su - web                       #S'enregistrer d'abord ...
$ cd my-awesome-app              #Il y avait ce répertoire
$ cd current                     #Oh, c'était sous le contrôle de capistrano
$ export RAILS_ENV=production    #Définir les variables d'environnement
$ export RACK_ENV=production     #(Quelque chose de différent)
$ bundle exec rails c            #Hoi

C'est tout ce que vous devez faire.

$ sudo -iu web appdo rails c     #rails c dans l'application de l'utilisateur Web

Écrivez le fichier de configuration dans $ HOME / .appdo.conf comme indiqué ci-dessous. Le format est TOML.

# /home/web/.appdo.conf
#
##Si vous faites sudo, l'utilisateur de destination sudo.appdo.conf s'applique

[default]
cd = "~/my-awesome-app/current"
source = ["/etc/profile", "~/.bashrc"]
prefix = "bundle exec"

[default.env]
RAILS_ENV = production
RACK_ENV = production

Comme vous pouvez le voir, cd et source sont utilisés pour définir les variables d'environnement, puis la commande est bundle exec.

Si vous le faites à chaque fois, ce n'est pas un travail que les humains devraient faire. Cela rend les gens plus heureux de le mettre dans un fichier de configuration et de l'approvisionner et de le gérer.

Autres changements

Changements dans crontab

Quand il n'y a pas d'appdo

RAILS_ROOT=/home/web/my-awesome-app/current
BASHRC=/home/web/.bashrc
RAILS_ENV=production

30 3 * * * bash -c "cd $RAILS_ROOT; source $BASHRC; bundle exec rails runner MyAwesomeApp::MyCron.run()"
30 4 * * * bash -c "cd $RAILS_ROOT; source $BASHRC; bundle exec rails runner MyAwesomeApp::MyCron2.run()"
30 5 * * * bash -c "cd $RAILS_ROOT; source $BASHRC; bundle exec rails runner MyAwesomeApp::MyCron3.run()"

Quand il y a appdo

30 3 * * * appdo rails runner MyAwesomeApp::MyCron.run()
30 4 * * * appdo rails runner MyAwesomeApp::MyCron2.run()
30 5 * * * appdo rails runner MyAwesomeApp::MyCron3.run()

Puisqu'il n'est pas nécessaire de définir des variables d'environnement (appdo les absorbe), crontab devient super simple. Vous pouvez voir quelle commande vous tapez avec appdo. Je peux le voir

Changement de commande dans ssh

Quand il n'y a pas d'appdo

ssh my.server.example.com sudo -u web bash -c "cd /home/web/my-awesome-app/current; source ~/.bashrc; RAILS_ENV=production bundle exec rake assets:precompile"

Quand il y a appdo

ssh my.server.example.com sudo -iu web appdo rake assets:precompile

C'est aussi simple que «crontab». Simplifier ssh a le grand avantage de simplifier config / deploy.rb. La séparation est meilleure car vous n'avez pas à mettre d'informations spécifiques à l'hôte (chemins, variables d'environnement, etc.) dans le code de votre application.

Simplification du manuel de procédure

Imaginez que tous les cd / sources quittent le document sensationnel

La migration d'hôte est facile

Par exemple, même si les chemins de l'application sont différents ou si ruby est dans un environnement mixte de rvm / rbenv, le fichier de configuration sur chaque hôte peut absorber cette différence. Par conséquent, la migration séquentielle peut être beaucoup plus facile, car le script de déploiement n'a pas besoin d'être modifié.

Autres exemples d'utilisation

Gestion des fichiers de configuration du serveur

# /root/.appdo.conf

[apache]
cd = "/etc/apache2"

[bind]
cd = "/var/bind/etc/bind"

Il peut être pratique de spécifier uniquement la destination cd et de ne partager que la commande de gestion du fichier de paramètres.

# appdo --app=apache -- ls sites-available
# appdo --app=apache -- ln -s sites-available/99-default sites-enabled
# appdo --app=bind -- co -l master/my.example.com
# appdo --app=bind -- vim master/my.example.com
# appdo --app=bind -- ci -u master/my.example.com

Résumé

--Utilisez appdo pour exécuter des commandes dans le "contexte de l'application" --Utilisez appdo pour déposer le "contexte de l'application" dans le fichier de paramètres --Utilisez appdo pour organiser les pauses entre les applications et l'infrastructure

Marmonnant à la fin

C'est un script que je viens de faire moi-même et qui n'est pas à l'épreuve des balles, mais j'ai décidé de le publier et de répondre aux spécifications en premier. Nous attendons avec impatience vos rapports de bogues et vos demandes.

À l'origine, j'ai pensé à cette commande ʻappdo parce que c'était stressant de ne pas pouvoir utiliser rubydesudo lorsque j'utilisais rvm / rbenv. Les exigences imposées à l'infrastructure changent à nouveau ces jours-ci, mais je pense qu'il est préférable de concevoir l'hôte pour qu'il se comporte de manière autonome, qu'il s'agisse de docker, de serf / consul ou d'autoscaling. Même dans un tel endroit, si vous pouvez créer quelque chose comme une "couche hôte" en utilisant ʻappdo et absorber diverses choses, je pense que vous serez satisfait de moins utiliser votre tête.

L'implémentation Python est le soi-disant premier type de prototypage. Je n'ai jamais créé de paquet avec Python, j'ai donc utilisé le [bootstrap-py] de @ mkouhei (https://github.com/mkouhei/bootstrap-py) pour l'implémentation. Je pense qu'il serait préférable de passer à Go lorsque les exigences telles que les options sont fixées.

e? Est-ce que Rust est meilleur? ...

Recommended Posts

J'ai créé une commande appdo pour exécuter des commandes dans le contexte de l'application
J'ai fait une commande pour afficher un calendrier coloré dans le terminal
Je souhaite laisser une commande arbitraire dans l'historique des commandes de Shell
J'ai fait un programme pour vérifier la taille d'un fichier avec Python
J'ai fait une commande pour marquer le clip de la table
Un mémorandum expliquant comment exécuter la commande magique! Sudo dans Jupyter Notebook
J'ai fait une commande pour générer un commentaire pour une table dans Django
J'ai fait une fonction pour vérifier le modèle de DCGAN
Je vous ai fait exécuter des commandes depuis un navigateur WEB
[Python] J'ai créé une application pour pratiquer la délicate distinction vocale des mots anglais.
J'ai créé un programme en Python qui change les données de 1 minute de FX en une heure arbitraire (1 heure, etc.)
J'ai créé une application pour découvrir à qui ressemblent les membres des Pirates du Chapeau de Paille
[Linux] Une commande pour obtenir une liste des commandes exécutées dans le passé
Je souhaite trier une liste dans l'ordre des autres listes
Je veux colorer une partie de la chaîne Excel avec Python
J'ai fait une erreur en récupérant la hiérarchie avec MultiIndex of pandas
J'ai essayé d'afficher la valeur d'altitude du DTM dans un graphique
J'ai créé une fonction pour voir le mouvement d'un tableau à deux dimensions (Python)
J'ai fait un outil pour estimer le temps d'exécution de cron (+ débuts de PyPI)
Comment passer le résultat de l'exécution d'une commande shell dans une liste en Python
Avec LINEBot, j'ai fait une application qui m'informe de "l'heure du bus"
Je souhaite définir un cycle de vie dans la définition de tâche d'ECS
Je souhaite voir une liste de fichiers WebDAV dans le module Requêtes
J'ai créé un outil pour sauvegarder automatiquement les métadonnées de l'organisation Salesforce
Je souhaite stocker les résultats de% time, %% time, etc. dans un objet (variable)
J'ai fait un script pour enregistrer la fenêtre active en utilisant win32gui de Python
Lorsque j'essaie d'exécuter la commande make de Makefile avec os / exec de golang, la deuxième exécution et les suivantes entraînent une erreur.
Comment exécuter une commande à l'aide d'un sous-processus en Python
Je voulais connaître le nombre de lignes dans plusieurs fichiers et j'ai essayé de l'obtenir avec une commande
J'ai créé une application Twitter qui décrypte les caractères de pré-connexion avec heroku (échec)
J'ai fait une commande pour attendre que Django démarre jusqu'à ce que la base de données soit prête
J'ai fait une image ponctuelle de l'image d'Irasutoya. (partie 1)
J'ai fait une image ponctuelle de l'image d'Irasutoya. (partie 2)
J'ai créé un outil pour obtenir les liens de réponse d'OpenAI Gym en même temps
[Pour les débutants] Je souhaite expliquer le nombre d’apprentissage d’une manière facile à comprendre.
J'ai créé une fonction pour découper l'image de python openCV, alors veuillez l'utiliser.
J'ai écrit un doctest dans "J'ai essayé de simuler la probabilité d'un jeu de bingo avec Python"
Comment passer le résultat de l'exécution d'une commande shell dans une liste en Python (version non bloquante)
Dans la commande python, python pointe vers python3.8
J'ai essayé de faire un programme pour résoudre (indice) la recherche d'erreur de Saiseriya
[Linux] J'ai essayé de résumer les commandes de confirmation des ressources
[sh] Comment stocker les résultats de l'exécution de la commande dans des variables
Comment déterminer l'existence d'un élément sélénium en Python
Comment connaître la structure interne d'un objet en Python
J'ai créé un programme qui résout la recherche d'erreur en quelques secondes
Comment vérifier la taille de la mémoire d'une variable en Python
[Introduction à StyleGAN] J'ai joué avec "The Life of a Man" ♬
J'ai écrit le code pour écrire le code Brainf * ck en python
Un moyen simple de réexécuter une commande précédemment exécutée dans ipython
Comment vérifier la taille de la mémoire d'un dictionnaire en Python
Comment afficher le résultat de sortie de la commande man Linux dans un fichier
Comment obtenir les coordonnées de sommet d'une entité dans ArcPy
J'ai essayé de faire 5 modèles de base d'analyse en 3 ans
Une commande pour vérifier facilement la vitesse du réseau sur la console
J'ai fait un bot mou qui m'informe de la température
Créez une fonction pour obtenir le contenu de la base de données dans Go
J'ai utilisé la commande coupe du monde pour vérifier le résultat de la Coupe du monde.
Je veux connaître la population de chaque pays du monde.
[Kaggle] J'ai fait une collection de problèmes en utilisant le didacticiel Titanic