From d49df0522da480f5ed67b01637ca216f7922b9fa Mon Sep 17 00:00:00 2001 From: Leonid Kozarin Date: Fri, 16 Nov 2018 02:36:40 +0300 Subject: [PATCH] Dockerize the bot Add configuration files for Docker to be able to build an image. --- .dockerignore | 1 + .gitignore | 2 +- Dockerfile | 13 +++++++++++++ README.md | 30 ++++++++++++++++++++++++++---- app/bot.py | 2 +- app/data/__init__.py | 0 app/msgdb.py | 2 +- docker-compose.yml | 14 ++++++++++++++ examples/nginx-textUtilsBot.conf | 2 +- init.sh | 8 ++++---- start_container.sh | 25 +++++++++++++++++++++++++ 11 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 app/data/__init__.py create mode 100644 docker-compose.yml create mode 100755 start_container.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..99e02a7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +app/data diff --git a/.gitignore b/.gitignore index a6cd26c..d4ae009 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,6 @@ __pycache__/ venv/ -app/config.py +app/data/config.py log.txt messages.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0fc744c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.7 + +WORKDIR /home/textUtilsBot + +COPY requirements.txt . +RUN pip install -r requirements.txt + +USER www-data +COPY app ./app + +EXPOSE 8443/tcp + +CMD ["python", "app/bot.py"] diff --git a/README.md b/README.md index fa92ca1..1050426 100644 --- a/README.md +++ b/README.md @@ -29,20 +29,42 @@ To execute the tests: How to deploy ------------- -The project is supposed to be used within a virtual environment. There is a special [initialization script](init.sh), +As of [v2.0.0](https://github.com/kozalosev/textUtilsBot/releases/tag/v2.0.0), there are two options to run the bot. +The first one is to use a Docker container. To use this option, you need [Docker](https://docs.docker.com/install/#supported-platforms) +and [Docker Compose](https://docs.docker.com/compose/install/) to be installed on your system. This approach allows you +to don't care about the version of the Python interpreter installed on your machine. + +The other way is to run the bot within a virtual environment. There is a special [initialization script](init.sh), that can help you on Linux. On Windows, you have to manually run *venv*, install all dependencies using *pip* and copy -the *config.py* file from the [`examples/`](examples) directory into [`app/`](app). +the *config.py* file from the [`examples/`](examples) directory into [`app/data/`](app/data). Note, however, that there +is only built-in support for Linux based servers for production use. But it's OK to utilize Windows machines for +development and debugging. + + +### Using Docker + +1. Clone the repository. +2. Configure [nginx](http://nginx.org) or any other front-end web server (keep reading for more information). +3. Run the `./start-container.sh` script. +4. Edit [app/data/config.py](app/data/config.py) according to your environment. +5. Run `./start-container.sh` again. + + +### Using _venv_ 1. Clone the repository. 2. `./init.sh` 3. Configure [nginx](http://nginx.org) or any other front-end web server (keep reading for more information). -4. Edit [app/config.py](app/config.py) according to your environment. +4. Edit [app/data/config.py](app/data/config.py) according to your environment. 5. Run `./start.sh` using one of the following ways: - directly (`nohup ./start.sh &>/dev/null &`); - configure [supervisord](http://supervisord.org/) or **systemd** to do it for you (see [exemplary configuration files](examples)); - configure any other service manager on your choice (but you have to write configuration by yourself). + +### Common notes + I encourage you to use the application as a local server that receives requests from Telegram from an external web server. In such case, you can configure a TLS certificate for all at once. This is especially handy in the case if you're using [Cloudflare](https://www.cloudflare.com/) services. @@ -68,7 +90,7 @@ web.run_app(app, host='0.0.0.0', port=APP_PORT, ssl_context=context) How to contribute a new feature ------------------------------- -As of [v1.1.0](https://github.com/kozalosev/textUtilsBot/releases/tag/1.1.0), it became much easier to add new text +As of [v1.1.0](https://github.com/kozalosev/textUtilsBot/releases/tag/v1.1.0), it became much easier to add new text processors to the bot. If [earlier](https://github.com/kozalosev/textUtilsBot/tree/c25df0e0f246ca9c2143098d4cf7c72535b96591) you had to embed calls of new functions into the entangled and confusing [inline_request_handler](https://github.com/kozalosev/textUtilsBot/blob/c25df0e0f246ca9c2143098d4cf7c72535b96591/app/bot.py#L64) diff --git a/app/bot.py b/app/bot.py index 39c0b6f..ec29b21 100755 --- a/app/bot.py +++ b/app/bot.py @@ -11,7 +11,7 @@ import strconv from strconv.util import escape_html from txtproc import TextProcessorsLoader, TextProcessor -from config import * +from data.config import * from queryutil import * from userutil import * diff --git a/app/data/__init__.py b/app/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/msgdb.py b/app/msgdb.py index a0e5ae0..219a9ab 100644 --- a/app/msgdb.py +++ b/app/msgdb.py @@ -4,7 +4,7 @@ import logging from typing import * -__db = sqlite3.connect('messages.db') +__db = sqlite3.connect('app/data/messages.db') __db.execute("CREATE TABLE IF NOT EXISTS Messages(message TEXT NOT NULL)") _logger = logging.getLogger(__name__) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1b10640 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: "3" +services: + textUtilsBot: + build: . + image: kozalo/textutilsbot + container_name: textutilsbot + hostname: testUtilsBot + working_dir: /home/textUtilsBot + restart: always + ports: + - "8080:8443" # host:container + volumes: + - "./app/data:/home/textUtilsBot/app/data" + - "/tmp:/tmp" diff --git a/examples/nginx-textUtilsBot.conf b/examples/nginx-textUtilsBot.conf index 5fb4732..5513bfc 100644 --- a/examples/nginx-textUtilsBot.conf +++ b/examples/nginx-textUtilsBot.conf @@ -12,7 +12,7 @@ server { #access_log /dev/null; #error_log /home/username/logs/nginx/textUtilsBot.err.log; - # Ensure the paths are consistent with the NAME and UNIX_SOCKET constants from 'app/config.py'. + # Ensure the paths are consistent with the NAME and UNIX_SOCKET constants from 'app/data/config.py'. location /textUtilsBot/ { proxy_pass http://unix:/tmp/textUtilsBot.sock; } diff --git a/init.sh b/init.sh index d899ff3..01d7dd7 100755 --- a/init.sh +++ b/init.sh @@ -10,12 +10,12 @@ pip install -r requirements.txt echo echo "Creating a configuration file..." -cp examples/config.py app/ -sudo chgrp www-data app/config.py || echo "Group 'www-data' not found. Change the group of 'app/config' file manually!" -chmod o-r app/config.py +cp examples/config.py app/data/ +sudo chgrp www-data app/data/config.py || echo "Group 'www-data' not found. Change the group of the 'app/data/config.py' file manually!" +chmod o-r app/data/config.py echo -echo "Done. Don't forget to replace fake values in 'app/config.py' with your actual ones." +echo "Done. Don't forget to replace fake values in 'app/data/config.py' with your actual ones." echo "Use the '. venv/bin/activate' command to enable the virtual environment. Inside, type 'deactivate' to disable it." echo "The 'start.sh' script is a shortcut to enter the virtual environment and run the bot." echo diff --git a/start_container.sh b/start_container.sh new file mode 100755 index 0000000..64f5f1c --- /dev/null +++ b/start_container.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +if [ ! -f "app/data/config.py" ]; then + echo "A configuration file was not found. Copying the skeleton..." + + cp examples/config.py app/data/config.py + sudo chgrp www-data app/data/config.py + chmod o-r app/data/config.py + + echo "Edit the 'app/data/config.py' file and run this script again." + exit +fi + +cmp --silent "examples/config.py" "app/data/config.py" +if [ $? -eq 0 ]; then + echo "Don't forget to change the values in the 'app/data/config.py' file!" + exit +fi + +if [ $(stat -c "%U" app/data) != "www-data" ]; then + echo "The 'app/data' directory must be owned by the 'www-data' user! Trying to fix it..." + sudo chown www-data app/data +fi + +docker-compose up -d