How to Dockerize a Telegram Bot: A Step-by-Step Guide
Tags: docker, cloud, hosting, telegrambot
Published: 2024-04-01 18:52:56

## Introduction

In a [previous article](https://dev.to/tjtanjin/how-to-host-a-telegram-bot-on-ubuntu-a-step-by-step-guide-4jk3), I covered how to host a Telegram bot with **Screen**. More recently I also did a sharing on my gradual shift [from **Screen** to **Docker**](https://dev.to/tjtanjin/from-screen-to-docker-a-look-at-two-hosting-options-42eh) for hosting applications. Building upon this progression, this tutorial aims to guide you through the process of **dockerizing** a Telegram bot!

This preparation sets the stage for our next article, where we will delve into fully automating deployment using **Docker and GitHub CI/CD**. By the conclusion of this tutorial, not only will you have acquired practical knowledge on dockerizing your bot, you'll also gain a better appreciation for leveraging Docker as a deployment tool.

## Prerequisites

Before we dive into the world of Docker, do note that this guide assumes knowledge of the following:
- Familiarity with linux command line
- Basic Understanding of Python
- Basic Understanding of Docker (if you don't, check out [this article](https://tjtanjin.medium.com/from-screen-to-docker-a-look-at-two-hosting-options-6682a08d51bf)!)

We will not be covering the above as they are not the focus of this guide - there are plenty of guides out there for them as well! All that said, if you need help with any of the above, you are more than welcome to [reach out](https://discord.gg/X8VSdZvBQY) for assistance.

Note that the contents of this tutorial can be generalized and applied to programs other than Telegram bots. However, for the purpose of this tutorial, you are encouraged to follow it through with [a simple Telegram bot that I have](https://github.com/tjtanjin/tele-qr). Even better if you have read my previous articles, because then you would be comfortable working with Telegram bots by now. So without further ado, let us begin!

## Step 1: Installing Docker

Unsurprisingly, the first step to dockerizing our Telegram bot is to have Docker installed. Depending on your operating system, the installation steps **may differ** as provided in [Docker's installation guide](https://docs.docker.com/engine/install/ubuntu/). The steps below are for **Ubuntu** but you should reference Docker's installation guide if you're using a different operating system:

#### 1. Set up Docker's apt repository.
```
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
```
#### 2. Install the Docker packages.
```
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
#### 3. Verify that the Docker Engine installation is successful by running the hello-world image.
```
sudo docker run hello-world
```

## Step 2 Clone the Project

Once we've got Docker setup, proceed to **clone** the [sample Telegram bot](https://github.com/tjtanjin/tele-qr) project with the following command:
```
git clone https://github.com/tjtanjin/tele-qr.git
```

## Step 3: Setup the Project
Within the project directory, you'll find a file called _main.py_ which has the following contents:
```
import os

from dotenv import load_dotenv
from health_ping import HealthPing
from telegram.ext import Application, CommandHandler, MessageHandler, filters

from submodules.user_input import show_help, get_input

dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
load_dotenv(dotenv_path)

if os.getenv("HEALTHCHECKS_ENDPOINT"):
    HealthPing(url=os.getenv("HEALTHCHECKS_ENDPOINT"),
               schedule="1 * * * *",
               retries=[60, 300, 720]).start()

def main():
    """
    Handles the initial launch of the program (entry point).
    """
    token = os.getenv("BOT_TOKEN")
    application = Application.builder().token(token).concurrent_updates(True).read_timeout(30).write_timeout(30).build() # noqa
    application.add_handler(CommandHandler('start', show_help))
    application.add_handler(CommandHandler('help', show_help))
    application.add_handler(MessageHandler(filters.TEXT, get_input))
    print("TeleQR instance started!")
    application.run_polling()

if __name__ == '__main__':
    main()
```
Notice that a **BOT_TOKEN** is required but it has not been set. If you'd like the complete experience, then you may wish to obtain a bot token which was covered in the guide on [how to build a telegram bot](https://dev.to/tjtanjin/how-to-build-a-telegram-bot-a-beginners-step-by-step-guide-1kd1).

Alternatively, for ease of following through this tutorial, you may also use a modified code snippet which contains a `while True` loop to simulate a permanently running program. Here's how the modified script would look like if you choose the latter option:
```
import time

def main():
    """
    Handles the initial launch of the program (entry point).
    """
    print("TeleQR instance started!")
    while True:
       time.sleep(5)
       print("I am running!")

if __name__ == '__main__':
    main()
```
Now, let us verify that the project is working by installing the required packages and then running the program:
```
pip install -r requirements.txt
python main.py
```
If the program is running successfully, you will see "TeleQR instance started!" printed into the console.

## Step 4: Create a Dockerfile

Now that we've got the project running, it's time to look at the _Dockerfile_. For those of you who are using the [sample Telegram bot project](https://github.com/tjtanjin/tele-qr), you will notice that a _Dockerfile_ already exists. That's because the sample project is already dockerized. Fret not, go ahead and delete the file and we will recreate it in no time!

#### 1. Create an empty Dockerfile:
In your project directory, create an empty file named _Dockerfile_. This file will contain instructions for Docker on **how to build your container**.

#### 2. Adding the base image:
The first line in the _Dockerfile_ specifies the base image that our container will use. In this case, we're using **Python version 3.10.12** as our base image so we'll declare this at the top of the file:
```
FROM python:3.10.12
```
#### 3. Setting the working directory:
Next, we set the working directory inside the docker container **where our application code will reside**:
```
WORKDIR /usr/src/app
```
#### 4. Copying files into the container:
Following which, we need to **copy all the files** from our local directory into the container which includes our Python scripts, requirements file, and any other project files. In the `COPY` command below, the first `.` represents our **current project directory** while the second `.` represents the docker **container's working directory** (which we have just set with the previous command):
```
COPY . .
```
#### 5. Creating a directory:
Then, we use the `RUN` command to execute `mkdir ./images` within our docker container's working directory. This step is **specific to the sample Telegram bot project** we are using but you can generalize this portion of the _Dockerfile_ for any other setup in your projects:
```
RUN mkdir ./images
```

#### 6. Installing dependencies:
With the project files setup, we now install the dependencies required by our Python application. We'll first install the packages listed in _requirements.txt_ using `pip`.
```
RUN pip install - no-cache-dir -r requirements.txt
```
Additionally, we'll install the **python-telegram-bot** package with the **[job-queue]** extras (again specific to the project):
```
RUN pip install python-telegram-bot[job-queue]
```

#### 7. Specifying the command to run the application:
Finally, we specify the command that should be executed when the container starts. In this case, we're running our Python script named _main.py_.
  ```
  CMD ["python", "-u", "./main.py"]
  ```
Phew! That was quite a lot to step through, wasn't it? But if you've followed till this far, then congratulations! You've successfully created a _Dockerfile_ for your Telegram bot. There's just one last step left - to build a Docker image based on this _Dockerfile_ and run your bot inside a Docker container!

## Step 5: Build & Run

Let us first build our docker image with `docker build`. Within your project directory, run the following command:
```
docker build -t my_telegram_bot .
```
This process may take a while the first time so give it a few moments. The above command essentially reads the instructions from your _Dockerfile_ and builds a Docker image with it. Feel free to replace `my_telegram_bot` with whatever you wish to name your Docker image.

Once the Docker image is built, we can then finally run our Docker container with `docker run`:
```
docker run my_telegram_bot
```
If you've followed all the steps so far, you'll see your application launching successfully! Before you happily call it a day, here are some **useful basic Docker commands** to know:
- `docker run -d <image_id_or_name>` - to run the Docker container in detached mode
- `docker ps` - to list all running containers
- `docker stop <container_id_or_name>` - to stop a running container
- `docker rm <container_id_or_name>` - to remove a container
- `docker images` - to list all images
- `docker rmi <image_id_or_name>` - to remove an image
- `docker logs <container_id_or_name>` - to view the logs of a container

These are some basic commands you may find useful but there are plenty of other commands that you will be able to find from [Docker's documentation](https://docs.docker.com/reference/cli/docker/).

## Conclusion

With that, we've successfully dockerized and run our Telegram bot inside a Docker container! In this tutorial, we stepped through the process of **creating a Dockerfile**, **building a Docker image** from it, and finally **running a Docker container** based on that image. Additionally, we've explored some **useful Docker commands** for managing containers and images.

As you continue your journey with Docker, remember that there are plenty of other features to explore. Docker's documentation is a **great place** to checkout if you wish to learn more about advanced Docker concepts and best practices. As always, if you've got ideas, suggestions or feedback to share, feel free to drop them in the comments or [reach out](https://discord.com/invite/X8VSdZvBQY)!

Happy coding, and if you're keen to automate your deployment process with me, then **stay tuned for the upcoming article!**