Introduction
I often get asked about what the “best” way to deploy a Python Telegram bot is. I’ve tried a lot of different ways, and I’ve settled on a workflow that I’m quite happy with for @SuperSeriousBot
. It’s probably not ideal and I’d like to change a few things, but it’s a process that has evolved over the last ~4 years.
Committing
In general I like to follow KISS for my projects. The actual code of @SuperSeriousBot
is fairly straightforward. In a nutshell:
- Python 3.10 (asyncio)
- Poetry for dependency management
black
for code formatting- The fantastic
python-telegram-bot
wrapper as the core
The code is stored on GitHub. For releases, I follow the Angular commit message convention. Using this, I’m able to largely automate the process of version management by using semantic-release
.
Building
Being on GitHub, I make heavy use of GitHub actions. I have a workflow that runs on every push to the master
branch. This workflow does the following:
- Run
npx semantic-release
to calculate the next version number - Publish a release on the repository page with an auto-generated changelog
- Build Docker images of
@SuperSeriousBot
foramd64
andarm64
architectures - Push the Docker images to ghcr.io
I’ve tried to trim down the Docker image size but it still sits at around ~400MB. This part’s still a work in progress. Lately, I’ve also been looking into Nuitka for static binaries. No luck on that front so far. All builds are cached based on poetry.lock
so we never rebuild layers. It matters a lot when you’re building for multiple architectures.
As of right now, there’s no tests. It’s up for discussion if I’ll ever add any. To me, a good code review process and robust logging is sufficient for a side project.
Here’s the .releaserc
I use to automate the version management and changelog generation:
{
"branches": ["master"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/git",
"@semantic-release/github"
]
}
Deploying
I use watchtower to automatically update my Docker containers. I have a docker-compose.yml
file that looks like this:
version: "3"
services:
ssgbot: ...
redis: ...
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 30
It’s not a zero downtime deployment, so I usually like to do it in the late AMs. Along with the bot itself, I use a mix of Redis and SQLite for caching and persistence. In production, I run @SuperSeriousBot
in webhook mode. I front the bot with nginx for which I use systemd
.
Conclusion
I find this setup to be quite robust and easy to maintain. If you have any suggestions, feel free to reach out to me on Telegram at @obviyus.
Wishlist
- Use Hashicorp Nomad for container orchestration
- Experiment with Nuitka for static binaries
- DuckDB instead of SQLite