[PYTHON] J'ai essayé de créer un service qui vend des données apprises par machine à une vitesse explosive avec Docker

Il y a environ 3 ans [Résultat du développement d'un programme de prévision du cours des actions d'apprentissage automatique par moi-même en tant que boutique WEB \ | Masamunet](http://masamunet.com/2016/11/09/web%E5%B1%8B%E3%81 % AE% E8% 87% AA% E5% 88% 86% E3% 81% 8C% E6% A9% 9F% E6% A2% B0% E5% AD% A6% E7% BF% 92% E6% A0% AA % E4% BE% A1% E4% BA% 88% E6% 83% B3% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% A0% E3 % 82% 92% E9% 96% 8B% E7% 99% BA /) J'ai écrit un article, et je n'ai pas fait grand-chose avec l'apprentissage automatique ou les actions, mais cette fin d'année et cette nouvelle année, j'ai franchi le pas. J'ai essayé diverses choses. C'est pourquoi j'ai obtenu un assez bon résultat, donc je vais écrire sur le contexte technique qui a conduit à l'opération en tant que service tel quel. Le lien vers le service lui-même est un service payant, donc si vous le liez pour des raisons religieuses, certaines personnes peuvent ne pas être en mesure de le voir, donc je ne le mettrai pas ici. Personnellement, je pense qu'il est important de créer un système qui permette aux ingénieurs de gagner de l'argent de manière appropriée, mais en d'autres termes, je pense que ce serait bien si nous pouvions fournir des conseils sur les services qui sont des livrables, même s'ils sont payés. Ce n'est pas un endroit pour discuter de telles choses ici, donc je m'abstiendrai de toute façon de lier le service lui-même. Cependant, je pense qu'il y a des opinions que vous ne pouvez pas juger sans voir le service réel, je voudrais donc mettre un lien à la fin de l'article qui vous mènera au service si vous le suivez à la légère. .. Voilà pour l'introduction, je vais vous présenter la structure finale.

resemble_stock_全体.png

En un mot, ce que je veux dire à propos de l'article, c'est que lorsque j'ai essayé d'en faire un service WEB afin qu'il puisse être largement utilisé car les résultats de l'apprentissage automatique étaient bons, je voudrais le présenter car Docker était compatible.

J'utilise diverses technologies dans tous les domaines, mais toutes n'utilisent que les bases, donc je ne pense pas qu'une explication détaillée soit nécessaire. Cependant, je crains de continuer avec l'histoire avec le corps de "Je te connais", donc je vais parler un peu de l'explication de chaque technologie.

Édition Docker

Je n'ai plus besoin d'expliquer l'histoire de Docker ici, mais même si j'omets l'explication, l'histoire ne se poursuivra pas, donc je n'introduirai que la partie superficielle sans crainte de malentendu. .. Docker se caractérise par deux fonctionnalités: la virtualisation avec une faible surcharge et la conteneurisation d'un environnement librement empilable. N'oubliez pas ces deux éléments, la virtualisation et la conteneurisation. La technologie de virtualisation de conteneurs existait avant Docker, et en fait Docker a également un historique d'utilisation d'une bibliothèque de virtualisation de conteneurs externe dans les versions antérieures à 0.9, donc seul Docker est exclusivement destiné à la virtualisation de conteneurs Bien que ce ne soit pas un brevet, la relation maître-esclave selon laquelle Docker a la virtualisation de conteneurs comme fonctionnalité majeure est établie. Tout d'abord, la virtualisation. La plupart des virtualisations traditionnelles autres que la virtualisation de conteneurs utilisent l'idée d'une machine virtuelle et essaient de tout préparer virtuellement à partir du processeur. C'était une technologie qui se comportait comme s'il y avait une machine pour l'environnement d'exécution (également appelé environnement invité). À ce stade, Docker a virtualisé l'entrée et la sortie du fichier. En contrôlant la partie lecture / écriture du fichier et en agissant comme s'il y avait une machine dédiée là-bas, l'environnement d'exécution a été séparé. Cela crée moins de frais généraux. Ensuite, conteneurisez. Cela signifie que si vous mettez l'appareil hors tension, vous pouvez revenir en arrière jusqu'à ce point et définir librement le point de rembobinage. Imaginez un PC où vous effectuez un point de rembobinage une fois dans un Windows propre et où Windows fraîchement installé démarre à chaque fois que vous éteignez l'appareil. Ensuite, disons que vous avez également créé un point de rembobinage avec Solitaire installé, car ce serait inefficace. Le premier Windows, le Windows avec Solitaire installé et la deuxième couche de conteneurs dans Docker ont été empilés. Ensuite, je voudrais installer Netscape Navigator 4. Vous pouvez l'installer sur un Windows propre, ou vous pouvez l'installer davantage sur l'environnement où Solitaire est installé. Vous pourrez choisir quel environnement ajouter. Il s'agit d'une pile de conteneurs Docker. L'avantage de la conteneurisation est que vous pouvez empiler autant de choses que vous en avez besoin et les restaurer lorsque vous coupez l'alimentation. Virtualisation avec moins de frais généraux et de conteneurisation qui vous permet de créer un environnement gratuit et de le renvoyer à tout moment. C'est la bonne chose à propos de Docker. Cette fois, nous profiterons pleinement de cette technologie.

Apprentissage automatique

J'ai procédé à cette configuration.

resebble_stock_python.png

Dans l'apprentissage automatique, les données sont collectées, prédites, calculées, vérifiées en fonction des résultats, puis prédites et répétées, de sorte que la collecte de données et l'apprentissage automatique sont inévitablement dans les deux sens au cours du développement. Je le répète souvent. Dès le début, il peut être difficile de concevoir pour être publié en tant que service. Donc, si je l'ai conçu uniquement pour que chaque opération soit séparée pour chaque dossier, il était facile de le rendre API en utilisant Flask ensuite uniquement la partie apprentissage automatique. En guise de talent, lorsque vous commencez progressivement à penser qu'il semble que vous pouvez le publier en tant que service au fur et à mesure que vous répétez l'apprentissage automatique, si vous en faites une fonction tout en étant conscient de l'entrée de l'API, il sera plus facile de le faire tel quel avec Flask plus tard. est. De plus, le backend décrit plus tard peut être construit séparément, de sorte que Flask peut être fermé localement dans le réseau Docker ultérieurement. Il est également pratique que le côté API ne nécessite ici qu'une désinfection et une validation minimales. Bien sûr, vous devez faire attention aux vulnérabilités qui peuvent prendre le contrôle de l'hôte du côté invité de Docker, mais comme vous pouvez échanger des données à l'état authentifié etc., ici ** presque ** ne faites rien Pouvoir transférer des données sans cela est un grand avantage. Encore une fois, ne rien faire est une histoire avec un minimum de désinfection, de validation et de certification. Veuillez noter qu'il s'agit de faire du SQL en utilisant des espaces réservés, de ne rien exécuter avec les privilèges root et de faire au moins des choses normales. La définition de ce qui est normal est importante, mais l'histoire est trop répandue, alors laissez-moi l'omettre.

Pour référence, je publierai le code en cours d'exécution. Le code est bâclé, mais si vous êtes humble avec le code bâclé, l'histoire ne continuera pas, alors passons à autre chose. Ce que je veux dire, c'est que si vous pouvez le gérer dans un état correctement fermé, vous pouvez faire fonctionner le code simplement en le passant comme ça jusqu'à la production.

service.py


# %%
@app.route('/')
def index():
  return jsonify({
    'status':200,
    'data': {}
  })

# %%
@app.route('/count')
def count():
  return jsonify({
    'status':200,
    'data': search_stock.get_last_data_count()
  })

# %%
@app.route('/last-date')
def last_date():
  return jsonify({
    'status': 200,
    'data': search_stock.get_last_date()
  })

# %%
@app.route('/getstock/<code>')
def getstock(code):
  low = int(request.args.get('low'))
  high = int(request.args.get('high'))
  isStockExist = search_stock.get_stock_name(code)
  if isStockExist is None or isStockExist is '':
    message = '{0} is not found'.format(code)
    return jsonify({'message': 'error'}), 500
  data = search_stock.get_stock_list(low, high, code)
  return jsonify({
    'status': 200,
    'data': data
  })

# %%
@app.route('/getresemble/<code>', methods=['POST'])
def get_resemble(code):
  data = request.get_data()
  json_data = json.loads(data)
  stock_list = json_data['list']
  isStockExist = search_stock.get_stock_name(code)
  if isStockExist is None or isStockExist is '':
    message = '{0} is not found'.format(code)
    return jsonify({'message': 'error'}), 500
  result = get_stock.start(code, stock_list)
  return jsonify({
    'status': 200,
    'data': result,
  })

# %%
if __name__ == "__main__":
  app.run(host='0.0.0.0',port=5000,debug=True)

Partie données

Je ne pense pas que ce soit correct de tout faire dans un conteneur Docker, mais j'ai également transformé les données dans un conteneur Docker. Au début, la partie données devait être montée en tant que volume externe à partir de Docker, mais comme beaucoup d'entre vous le savent, lorsque vous essayez de monter un volume hôte à partir de Docker sur Linux, vous avez besoin des privilèges root du côté hôte. La seule solution est de faire quelque chose à propos du côté conteneur Docker ou du côté hôte Docker, mais dans mon cas, il y a un utilisateur gitlab-runner fonctionnant sur le CI / CD de Gitlab. , Il existe un environnement où gitlab-runner est exécuté par sudo, c'est-à-dire que la situation de l'utilisateur varie en fonction de l'environnement d'exploitation, je l'ai donc verrouillé docilement dans Docker. L'avantage d'en faire un conteneur Docker ici est que la portabilité des données a également augmenté, nous avons donc créé un environnement de grattage puissant avec la partie de grattage qui suit. Pour référence, je vais vous présenter le Dockerfile de la partie données.

FROM busybox
WORKDIR /data
COPY . ./
VOLUME [ "/data" ]

L'avantage de sqlite est que vous pouvez transporter tout l'environnement DB avec vous tant que vous verrouillez les fichiers. En outre, en tant que conception de tableau des données de cours boursier, il existe des problèmes tels que la division du tableau pour chaque émission ou l'utilisation du code d'émission comme le code GROUP BY dans une table, mais tous ont des bons et des mauvais points. C'est difficile à attacher. Cette fois, j'ai essayé de le faire fonctionner avec un DB d'une marque. Pour accéder au code de marque 1234, accédez à la base de données du code de marque 1234. Il faut un peu de frais généraux pour accéder aux actions dans tous les domaines, mais de toute façon, c'est aussi bon et mauvais, alors je l'ai fait cette fois. Je voudrais parler plus en détail des avantages et des inconvénients de la conception DB des cours des actions s'il y a une opportunité.

L'inconvénient d'exploiter l'ensemble du fichier sqlite avec une image Docker est que vous devez recréer l'image à chaque fois que vous mettez à jour les données, donc si vous ne gérez pas bien l'environnement CI / CD, les images s'accumuleront de plus en plus. La portabilité n'est pas si élevée, car elle dépend de la façon de penser de l'utilisateur d'autoriser ou non Docker-in-Docker (DinD), mais si DinD n'est pas utilisé, les données doivent être mises à jour sur le shell. C'est parce que l'environnement d'exécution est sélectionné après tout. Si vous n'aimez pas cela, vous n'avez pas d'autre choix que de creuser plus profondément dans l'environnement DinD, mais si vous souhaitez apporter DinD réglé à l'environnement de production à l'avenir, s'il est préférable de le stabiliser sous l'environnement shell, même kubernetes Il est plus rapide de le recréer avec le SGBDR, et de nombreuses parties doivent être prises en compte. D'un point de vue très personnel, DinD a un contexte historique qui a été utilisé à l'origine de manière assez inattendue même s'il était pris en charge par le responsable de Docker, et DonD pourrait devenir une faille de sécurité du système d'exploitation hôte s'il n'est pas bon. Il est difficile de dire que l'environnement entourant DinD est prêt, comme devoir le faire, donc j'essaye de toucher le Dockerfile du shell autant que possible. Il ne fait aucun doute qu'il s'agit d'une technologie très pratique et puissante, les attentes sont donc très élevées. J'ai fait semblant de ne pas jeter un coup d'œil rapide sur ces choses, et pour le moment, en donnant la priorité au déplacement, j'ai pensé que créer une image entière avec sqlite pouvait être une option.

Partie de grattage

Étant donné que les données traitées cette fois sont les cours des actions, l'amélioration de la portabilité de l'environnement de grattage était une priorité absolue. Je veux toujours récupérer les dernières données, j'ai donc choisi le conteneur Docker sans hésitation au début. C'est très pratique car vous pouvez automatiser jusqu'à ce point, sans penser à rien, en grattant lorsque le conteneur démarre et en laissant tomber le conteneur entier une fois terminé. Vous pouvez l'utiliser tel quel avec crontab, ou vous pouvez facilement créer EC2 le moment venu, démarrer automatiquement le conteneur lorsque le côté EC2 démarre et terminer EC2 pour chaque conteneur lorsque le grattage est terminé. Tout allait bien, mais à la fin, j'ai préparé deux parties principales de la partie grattage, l'une qui peut être exécutée par Docker et l'autre qui peut être exécutée directement par le shell. En effet, Docker n'était pas pratique dans tous les environnements. Après tout, le problème selon lequel le volume côté hôte monté par Docker devient la propriété de la racine ne peut pas être évité ici également, et dans un tel environnement, il était préférable de l'exécuter dans le shell côté hôte. Par conséquent, nous avons rendu possible la préparation de trois types d'environnements, par exemple quand il peut être exécuté directement dans le shell, lorsque l'environnement d'exécution Python est couvert par Docker, et lorsque l'environnement de scraping est effectué dans le conteneur Docker.

L'extrémité avant

C'est un gaspillage de faire de ce produit uniquement le vôtre au fur et à mesure de la progression de l'apprentissage automatique, je veux donc que vous le publiiez sur le WEB et que vous l'utilisiez largement! Ensuite, la prochaine étape est le développement frontal. Comme guide lorsque je choisis personnellement un framework, j'ai tendance à choisir un framework backend tel que laravel lorsque le développement backend est lourd, et un framework frontend autant que possible sinon. Bien sûr, selon le projet, il peut y avoir des restrictions sur les serveurs qui peuvent être exploités, donc ce n'est pas le cas, mais au moins si vous pouvez choisir librement, essayez autant que possible de construire à partir du front-end. Encore une fois, la partie la plus compliquée de l'apprentissage automatique est déjà terminée, j'ai donc choisi la configuration Express.js + NuxtJS sans hésitation car je n'avais pas besoin de traitement backend plus compliqué.

resemble_stock_front.png

Encore une fois, je ne veux pas dire que c'est sûr parce qu'il est fermé. Cependant, c'est la seule partie qui peut être vue dans le tableau, et il n'y a aucun moyen de savoir ce qui se passe à l'intérieur à moins que vous n'utilisiez une autre méthode telle que le piratage depuis le noyau. Je pense que plus les ingénieurs sont expérimentés, plus il est facile de concevoir.

Je ne pense pas qu'il soit bon de tout transformer en conteneur Docker, mais à la fin, je l'ai également transformé en conteneur Docker. Il y a beaucoup d'essais et d'erreurs en cours de développement ici, donc je ne veux pas faire des choses comme conteneuriser et démarrer, vérifier les journaux dans le conteneur, etc., en particulier la partie où l'environnement d'exécution est fixé dans le domaine, Node du côté hôte Je ne pouvais pas commencer avec .js, ou c'était la partie qui était emballée jusqu'à la fin. Mais à la fin, j'ai également tout verrouillé dans un conteneur Docker. La raison en est que lors de l'interaction avec le backend, il est facile d'être influencé par l'environnement réseau, donc j'ai trouvé plus pratique de le garder entièrement dans le réseau Docker. En fin de compte, Docker n'a ouvert que les ports https et http 443 et 80, et le reste a été fait pour communiquer à l'intérieur du réseau Docker.

AmazonPay C'était la partie la plus difficile, et Amazon m'a fourni des explications japonaises polies et des SDK pour différentes langues, donc mes compétences n'étaient pas suffisantes, mais j'ai passé beaucoup de temps à le développer. .. Tout d'abord, bien que le SDK soit disponible en plusieurs langues, il n'y en a pas pour Node.js, il a donc fallu du temps pour essayer de communiquer directement depuis Express.js. Je voulais essayer d'utiliser axios pour interagir directement avec l'API, mais peut-être que je ne le cherchais pas, je ne pouvais trouver qu'un simple échantillon pour une communication directe avec l'API, et il a fallu énormément de temps pour trouver la bonne réponse par essais et erreurs. J'ai utilisé. Étant donné qu'AmazpnPay n'accepte que les communications de https sous le domaine pré-enregistré, si vous en essayez un à ce stade, fusionnez-le dans la branche de développement pour ajouter une console.log → git lab-runner fonctionnera Attendre la conteneurisation Docker → Docker Après le démarrage, je savais que ce n'était pas très réaliste car je devais refaire la vérification du fonctionnement avec le navigateur → afficher le journal du conteneur d'exploitation avec les logs Docker du serveur SSH. Je trouverai peut-être un meilleur moyen à l'avenir, mais la seule chose que je puisse faire avec le flux actuel est de créer une API qui atteint l'API avec le SDK fourni, j'ai donc choisi le SDK Python cette fois. L'avant a également eu un petit problème. Étant donné que la conception est basée sur la même hypothèse que les temps de chargement et de dessin sont les mêmes, il n'est pas possible de charger uniquement le module à l'avance et de générer l'interface utilisateur au moment du dessin. De plus, comme le cycle de vie de rejet du module → génération n'est pas pris en compte, il est extrêmement difficile de le recharger à chaque fois qu'il est dessiné, donc je l'ai ajusté dans une certaine mesure en utilisant le cycle de vie de Vue.js. C'était une mise en œuvre un peu difficile car ce n'était pas le comportement que le créateur de la chose attendait. Ceci est fatal pour le bouton de paiement où le spectateur se déplace entre les écrans du panier à sa convenance, et le seul moyen de redessiner est de recharger. La commodité de ce créateur est que le bouton Amazon Pay au moins le bloc-notes est conservé Il y a 4 ans quand c'était fait, je dois dire que le design est vieux. Je viens de me plaindre, mais je pense que c'est un service de paiement avec un grand potentiel, alors j'aimerais vraiment voir des améliorations.

Ce que je voulais dire, c'est qu'il était facile d'en faire un service avec Docker

Cette fois, tous ont été opérés de manière inattendue dans le conteneur Docker, mais j'ai senti que la méthode de création du conteneur sans y penser d'abord, puis de concevoir le conteneur est très compatible avec le service d'apprentissage automatique. C'était. Puisqu'il s'agit d'un conteneur, il peut être facile de l'introduire avec kubernetes lors de la mise à l'échelle du service à l'avenir, et je pense que cela fera beaucoup de progrès. Cette fois, nous avons introduit diverses technologies dans tous les domaines, mais elles ne touchent toutes que les bases, donc cela peut ne pas être suffisant selon le point de vue. Cependant, ceux qui sont fous de l'apprentissage automatique peuvent ne pas savoir comment déployer facilement à l'aide de Docker, et ceux qui sont fous de Nuxt.js peuvent trouver un bon moyen d'utiliser l'apprentissage automatique. J'espère que le bilan de la technologie introduite à tous les niveaux vous donnera quelques indices. Je n'ai pas abordé la méthode d'apprentissage automatique en elle-même cette fois, mais lisez l'article ici sur la façon de gérer les cours des actions avec l'apprentissage automatique. Il est écrit séparément. Si vous le souhaitez, veuillez vous y référer également.

Recommended Posts

J'ai essayé de créer un service qui vend des données apprises par machine à une vitesse explosive avec Docker
[Go + Gin] J'ai essayé de créer un environnement Docker
[Python] Un mémo que j'ai essayé de démarrer avec asyncio
J'ai essayé de mettre en œuvre une blockchain qui fonctionne réellement avec environ 170 lignes
J'ai essayé de créer un environnement de développement Mac Python avec pythonz + direnv
J'ai essayé de créer un service de raccourcissement d'url sans serveur avec AWS CDK
J'ai essayé de créer une méthode de super résolution / ESPCN
J'ai essayé de créer une méthode de super résolution / SRCNN ①
J'ai essayé de sauvegarder les données avec discorde
J'ai essayé d'obtenir des données CloudWatch avec Python
J'ai essayé de créer une méthode de super résolution / SRCNN ③
J'ai essayé de créer une méthode de super résolution / SRCNN ②
J'ai essayé de créer un pipeline ML avec Cloud Composer
Une histoire à laquelle j'étais accro chez np.where
J'ai essayé de collecter des données sur un site Web avec Scrapy
J'ai essayé de créer un environnement avec WSL + Ubuntu + VS Code dans un environnement Windows
[Python + Bottle] J'ai publié un service Web qui visualise les tweets positionnés de Twitter.
[AWS] J'ai essayé de créer un environnement Python avec un environnement de développement eb [Elastic Beanstalk]
J'ai essayé de créer un cadre de données pandas en grattant les informations de rappel d'aliments avec Python
J'ai essayé d'implémenter une ligne moyenne mobile de volume avec Quantx
J'ai essayé de créer automatiquement un rapport avec la chaîne de Markov
[1 hour challenge] J'ai essayé de créer un site de bonne aventure qui soit trop adapté à Python
Créez un serveur Web API à une vitesse explosive en utilisant HUG
J'ai essayé de résoudre le problème d'optimisation des combinaisons avec Qiskit
J'ai essayé de commencer avec Hy ・ Définir une classe
J'ai essayé de créer un générateur qui génère une classe conteneur C # à partir de CSV avec Python
J'ai essayé de trier une colonne FizzBuzz aléatoire avec un tri à bulles.
J'ai essayé d'écrire dans un modèle de langage profondément appris
[Diplômé de l'encombrement d'articles] J'ai essayé de développer un service qui peut répertorier les articles par objectif
[AWS] Version de déploiement d'application Flask qui a tenté de créer un environnement Python avec eb [Elastic Beanstalk]
Une histoire qui n'a pas fonctionné lorsque j'ai essayé de me connecter avec le module de requêtes Python
J'ai essayé de créer une configuration RAID logicielle SATA qui démarre le système d'exploitation sur Ubuntu Server
[5e] J'ai essayé de créer un certain outil de type Authenticator avec python
Je souhaite utiliser un caractère générique que je souhaite décortiquer avec Python remove
J'ai essayé de créer un système qui ne récupère que les tweets supprimés
[2nd] J'ai essayé de créer un certain outil de type Authenticator avec python
Un mémorandum lors de l'acquisition automatique avec du sélénium
[3ème] J'ai essayé de créer un certain outil de type Authenticator avec python
J'ai essayé de créer une liste de nombres premiers avec python
[Pandas] J'ai essayé d'analyser les données de ventes avec Python [Pour les débutants]
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai essayé de créer des taureaux et des vaches avec un programme shell
J'ai essayé un outil qui imite le modèle de Goch avec l'IA
J'ai essayé de créer une application todo en utilisant une bouteille avec python
[4th] J'ai essayé de créer un certain outil de type Authenticator avec python
[1er] J'ai essayé de créer un certain outil de type Authenticator avec python
Création d'un service qui vous permet de rechercher des données J-League
J'ai essayé de faire une étrange citation pour Jojo avec LSTM
J'ai essayé de créer un mécanisme de contrôle exclusif avec Go
Créer un fichier deb avec Docker
J'ai essayé de créer un environnement capable d'acquérir, de stocker et d'analyser les données de tweet en WSL (bash)
[AWS] Préparation du déploiement de l'application Flask pour la création d'un environnement Python avec eb [Elastic Beanstalk]
[Bases de la science des données] J'ai essayé d'enregistrer de csv à mysql avec python
J'ai essayé de mettre en œuvre un apprentissage en profondeur qui n'est pas profond avec uniquement NumPy
J'ai essayé de communiquer avec un serveur distant par communication Socket avec Python.
J'ai essayé de créer un programme qui convertit les nombres hexadécimaux en nombres décimaux avec python