Введение
У меня была задача «Собирать статистику постов в vk каждый час». Я не являюсь разработчиком или DevOps специалистом. Поэтому мой способ решения задачи сложился из поисковых запросов, личного опыта, советов друзей и коллег.
Решение я разбил на 2 части:
Написать код для сбора. (см. статью https://habr.com/ru/post/720862/)
Запустить процедуру на сервере с интервалом 1 час
В этой статье мы рассмотрим реализацию 2-го пункта. Если у вас нет 2 пункта подойдет любой другой код, которые требуется запускать по расписанию.
На схеме это будет выглядеть следующим образом.
Подготавливаем данные для Docker
Про Docker написано очень много статей, поэтому я не буду писать еще раз, что это и для чего используется. В контексте данной статьи Docker будет частью нашего решения. В следующем разделе будет ссылка на материал по теме Docker, который помог мне.
План действий:
Создаем файл requrements.txt
Настраиваем Dockerfile
Настраиваем переменное окружение в коде python
Оставляем словарь, который использует google sheet api*
requrements.txt
В папке с вашим кодом создаем файл с точно таким же именем requrements.txt Этим файлом мы говорим Docker, какие библиотеки нужно дополнительно установить и какой версии.
Как понять, что туда написать?
Обязательно вносим в файл библиотеки, которые вы устанавливали дополнительно. В моем случае все библиотеки, которые использованы в коде в самом начале.
import os
import requests
from pandas import json_normalize
import pandas as pd
from datetime import datetime
from datetime import *
import httplib2
from oauth2client.service_account import ServiceAccountCredentials
import apiclient.discovery
В IDE в консоле пишем pip freeze.
Видим список всех установленных пакетов в вашем виртуальном окружение и их версии
Выбираем библиотеки, которые мы с вами используем в коде и переносим в requrements.txt
На выходе это будет выглядеть так:
Dockerfile
Создаем файл Dockerfile, без расширения. Открываем его и заносим данные
FROM python: «ваша версия python». Узнать ее можно набрав в терминале: python –V
Подробно останавливаться на всем не буду. Выше собранный requrements.txt будет использован в RUN.
ENV это переменное окружение, которые будут храниться внутри Docker. ENV TZ Europe/Moscow – установление московского времени.
Все остальные переменные необходимы для корректной работы кода. (см. статью https://habr.com/ru/post/720862/)
Конечно можно их и не прописывать и все оставить в коде. В моем случае, я решил, что оставлю все переменные в одном месте просто для своего удобства.
CMD указываем язык программирования и названия вашего файла с кодом в моем случае это vk_stat.py
Настраиваем переменное окружение в коде python
Мы удаляем значение переменных из кода, так как они у нас уже в Dockerfile.
Прописываем команду, которая будет забирать переменные окружения.
TOKEN_USER = os.getenv('TOKEN_USER')
VERSION = os.getenv('VERSION')
DOMAIN = os.getenv('DOMAIN')
Создаем сервер, публикуем код на GitHub
Я бы посоветовал прежде, чем перейти к этому шагу скачать отдельно docker desktop и провести тестирование на вашей локальной машине.
В этом видео вы найдете все что нужно по установки docker и кратко для чего он применяется. Мне данное видео очень помогло. https://www.youtube.com/watch?v=QF4ZF857m44
Для тех кто c Docker знаком предлагаю просмотреть фрагмент видео (ссылка выше) с 1:05:23 по 1:10:17
Добавлю лишь, если вы не хотите прописывать переменные внутри сервера, то сделайте закрытый репозиторий на GitHub!
Здесь не вижу смысла перечислять все шаги, если вы повторите за автором видео.
90% работы вами уже сделано. По итогам у вас:
- Создан сервер с опубликованном кодом через github + установленный docker
Отладка Cron
Далее через командную строку заходим на наш сервер.
Мне понравилась статья про cron здесь https://losst.pro/nastrojka-cron, но далее кратко напишу по сути. Набираем «crontab –e» в командной строке.
В самом конце набираем интервал для запуска контейнер. В моем случае каждый час. В помощь хороший сайт, который позволит сразу настроить интервал https://crontab.guru
Далее пишем команду Docker run –rm «имя вашего образа». Флажок –rm удаляет контейнер после его отработки. Не забываем сохранить наши изменения.
Проверить, не падает ли контейнер при запуске можно в логах. Введите команду grep CRON /var/log/syslog
Заключение
Данное решение позволяет выполнить поставленную задачу. Конечно его можно улучшить. Например, добавить логирование, написать класс и завернуть все в функции что позволит в будущем расширять функционал. Возможно радикально пересмотреть в целом предлагаемое мной решение.
Сервер обходиться в 200 рублей за месяц аренды. Работать код будет 4-6 месяцев. Если у кого-то есть решение, как можно сделать тоже самое без использования сервера, будет интересно почитать.
Комментарии (35)
BlackSCORPION
00.00.0000 00:00+1Если у кого-то есть решение, как можно сделать тоже
самое без использования сервера, будет интересно почитать.Амазон лямбды могут запускатся по таймеру, думаю аналогичные сервисы от других клауд провайдеров тоже так умеют это не рокет сайнс.
vainkop
00.00.0000 00:00Следующий шаг, конечно, https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
Tzimie
00.00.0000 00:00+1А просто так, без докера, питон не запустить?
iig
00.00.0000 00:00+2Какой же ты
хакер без ноутбукадевопс без докера? ;)Tzimie
00.00.0000 00:00+1А, понял, то есть дело опять в смузи и цветных носках)
iig
00.00.0000 00:00+1Нет, автор же не скрывает, что нагуглил, то и сделал. Попался рецепт с докером - он его применил.
Tzimie
00.00.0000 00:00-1То есть карго культ в чистом виде. Вместо самолёта из соломы - докер
iig
00.00.0000 00:00+2Только в этом случае самолёт из соломы полетел ;) Скорее забили гвоздь микроскопом.
То ли ещё будет, когда chatgpt пойдёт в массы ;). Он же будет подсказывать самые трендовые решения.DmitriyB_33 Автор
00.00.0000 00:00+1Почитав мнение коллег, понимаю, что действительно забил гвоздь микроскопом. Есть более простые рецепты. Осталось найти хитрую книгу/статью, откуда можно понять, что если написал просто скрипт смысла в докере нет, можно попробовать так. А вот если в твоем сервисе есть функции такие-то... то тут поможет докер и прочие инструменты.
Tzimie
00.00.0000 00:00А тут просто здравый смысл. Докер полезен если очень хитрая конфигурация, или надо одно и тоже раздавать на разные машины или разными людям. А что-то сделать на одном сервере для себя - точно нет. Отлаживать внутри докера неудобно. Туда пихают что-то готовое как правило
DmitriyB_33 Автор
00.00.0000 00:00Если подскажите или скинете ссылку на реализацию буду признателен.
orthlus
00.00.0000 00:00+3в целом для этого подойдут облачные функции и тригеры по времени в Яндекс облаке. И квоты там большие
если очень нужны контейнеры, то там же есть servless containers
Sadok
00.00.0000 00:00+1Набираем «crontab –e»
... и получаем в глаз, если ты не админ localhost. Это статья про man 5 crontab?
DmitriyB_33 Автор
00.00.0000 00:00Я не являюсь DevOps специалистом, можете пояснить? Не совсем понимаю, что не так с «crontab –e»
Sadok
00.00.0000 00:00+1Я не зря про localhost упомянул. Когда начинаются странные вещи, то администратору хоста очень весело ползать по всем пользовательским кронам в том числе
Areso
00.00.0000 00:00+1у каждого пользователя на хосте - свой кронтаб. Не вижу проблемы :)
Sadok
00.00.0000 00:00+1Я не зря про localhost упомянул. Когда начинаются странные вещи, то администратору хоста очень весело ползать по всем пользовательским кронам в том числе
Areso
00.00.0000 00:00Ну тут тоже вопрос - администратор хоста отвечает за ОС хоста (дистрибутив Линукс) или отвечает за всё на хосте, включая приклад? Если шкодничают юзвери, а крайний всегда админ - ну тогда грустно, полностью согласен.
aborouhin
00.00.0000 00:00+4Хм... весь смысл docker - закинуть контейнер на сервер и не думать, что там на самóм сервере ещё необходимо для его корректной работы. Так зачем, если уж мы с docker связались (что для данной задачи тоже overkill, но Бог с ним), настраивать crontab на самóм сервере, а не внутри docker-контейнера?.. Настроили crontab внутри контейнера, запустили его один раз - всё.
a_f
00.00.0000 00:00+1я не проще какую-нить библиотеку типа schedule использовать в самом питоне ?
DmitriyB_33 Автор
00.00.0000 00:00Еще одно предложение в копилку опыта. Спасибо! Рассмотрю такой вариант.
ky0
"Негодующий комментарий про крон в 2023 году и systemd-таймеры"
DmitriyB_33 Автор
Благодарю. Подскажите, а чем крон плох? Я в статье обозначил, что не являюсь DevOps специалистом, нашел решение которое работает. Вполне может быть оно и не самое корректное. Статей много по настройки systemd-таймер , а пока разницы между ними плюсы/минусы не уловил.
Areso
systemd-таймеры это не про DevOps, а про владение Linux'ом.
ky0
Крон просто запускает скрипт. Таймер же оперирует сервисом, у которого есть собственные логи, состояние и понятные способы управления.
Самый простой пример — что произойдёт со скриптом, если он не закончит выполняться до следующего запуска задания в кроне? Хорошо, если несколько экземпляров допустимы. А если нет? Как в рамках крона это контролировать?
Areso
У человека простой скрипт, он решил свою проблему и его устроило решение.
Если бы он столкнулся бы с проблемами, он бы пошёл исследовать проблему и методы её решения.
Опять же, резидентный сервис и ad-hoc скрипт - разные сценарии.
Тут нужно очень четко формулировать ограничения, чтобы понимать, какие средства будут наилучшими в этих условиях. Зависит от контекста.
ky0
Именно поэтому я оформил свой первый комментарий в ироническом стиле, а не начал холиварить и сомневаться в профпригодности автора.
DmitriyB_33 Автор
Может быть я конечно не так гуглил. В процессе сложилось впечатление, что не хватает обзорной статьи, которая хотя бы показывала связь между сложностью сервиса и инструментов для их запуска на сервере. Очень много информации про докер. Спасибо всем кто оставил комментарии, теперь у меня есть понимание, что вариантов запустить мой простой скрипт есть несколько и можно вполне обойтись без докера.
ky0
Связь тут скорее не со сложностью, а с контекстом. В соседних ветках народ может сколько угодно улюлюкать насчёт того, что ради одного скрипта с обвязкой городить контейнеры не стоит, но если, например, вам нужно этот скрипт разложить по нескольким серверам, администрируемым не вами, синхронно обновлять и мочь без проблем проводить диагностику в случае каких-то проблем — лично я бы потратил бы сначала немного времени и докеризировал.
DHeart
По идее, если прямо в скрипте загнать вызов первой функции в бесконечный цикл и после вызова прописать time.sleep(N) и проследить, чтоб после отработки итерации в памяти ничего лишнего не оставалось, то и крон не понадобится. Но если скрипт упадет, его никто не поднимет. Отсюда уже можно посмотреть на создание юнитов systemd. На истину не претендую, просто был подобный кейс, решал вот так.
Вам успехов в начинаниях)