Last active
November 20, 2023 08:40
-
-
Save seppzer0/96bee25332ba93fcaa847f0f90114f4c to your computer and use it in GitHub Desktop.
tgbotdocker.py: A compact solution for deploying a Telegram bot via Docker.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import sys | |
| import time | |
| import signal | |
| import subprocess | |
| class TgBotHandler: | |
| """Handle a Telegram bot in a Docker container easily.""" | |
| def __init__( | |
| self, | |
| name_image: str, | |
| name_container: str, | |
| path_dockerfile: os.PathLike | |
| ) -> None: | |
| self._name_image = name_image | |
| self._name_container = name_container | |
| self._path_dockerfile = path_dockerfile | |
| @staticmethod | |
| def _custom_cmd(cmd: str) -> None: | |
| """A simple 'subprocess' wrapper.""" | |
| print(f"[CMD] {cmd}") | |
| rc = subprocess.run(cmd, shell=True).returncode | |
| if rc != 0: | |
| print(f"[ ! ] Could not launch: {cmd}") | |
| sys.exit(1) | |
| def recipe_generate(self) -> None: | |
| """Generate a Dockerfile to build a primitive image.""" | |
| contents = """"""\ | |
| """FROM python:3.11-alpine3.18\n""" \ | |
| """# prepare environment\n""" \ | |
| """WORKDIR /app\n""" \ | |
| """COPY . /app\n""" \ | |
| """# get project dependencies\n""" \ | |
| """RUN python3 -m pip install -r requirements.txt\n""" \ | |
| """# setup CMD\n""" \ | |
| """CMD [ "python3", "app.py" ]""" | |
| # delete potential old recipe and generate a new one | |
| if self._path_dockerfile in os.listdir(): | |
| os.remove(self._path_dockerfile) | |
| with open(self._path_dockerfile, "w") as f: | |
| f.write(contents) | |
| def deploy(self) -> None: | |
| """Prepare and launch the bot.""" | |
| self._custom_cmd(f"docker build --no-cache -f {self._path_dockerfile} . -t {self._name_image}") | |
| os.remove(self._path_dockerfile) | |
| self._custom_cmd(f"docker run --rm -d --name {self._name_container} {self._name_image}") | |
| print("\n[ * ] Bot is running!") | |
| print("[ * ] Logs are below..") | |
| # start monitoring logs | |
| self._custom_cmd(f"docker logs --follow {self._name_container}") | |
| def handler(self, signum: int, frame) -> None: | |
| """Custom SIGINT handler.""" | |
| res = input("\n\n[ ? ] Stop bot hosting? [y/n]: ").lower() | |
| if res == "y": | |
| print("\n[ * ] Cleaning the environment..") | |
| self._custom_cmd(f"docker stop {self._name_container}") | |
| # need a short time window to actually remove the container | |
| time.sleep(1) | |
| self._custom_cmd(f"docker rmi {self._name_image}") | |
| print("[ * ] Done!\n") | |
| sys.exit(1) | |
| elif res == "n": | |
| print("\n[ * ] Keeping the bot running..") | |
| # keep monitoring logs | |
| self._custom_cmd(f"docker logs --follow {self._name_container}") | |
| else: | |
| # assume that the bot should be kept running | |
| print("\n[ * ] Invalid option selected, keeping the bot up..") | |
| self._custom_cmd(f"docker logs --follow {self._name_container}") | |
| # deploy | |
| tgbot = TgBotHandler( | |
| name_image="image-name", | |
| name_container="image-name-runner", | |
| path_dockerfile="Dockerfile" | |
| ) | |
| tgbot.recipe_generate() | |
| signal.signal(signal.SIGINT, tgbot.handler) | |
| tgbot.deploy() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment