feat(host): start docker addon
This commit is contained in:
parent
7423b40337
commit
c7ddba1bae
22 changed files with 394 additions and 12 deletions
7
.envs/.local/.postgres
Normal file
7
.envs/.local/.postgres
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# PostgreSQL
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
POSTGRES_HOST=postgres
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
POSTGRES_DB=tuxbot_bot
|
||||||
|
POSTGRES_USER=debug
|
||||||
|
POSTGRES_PASSWORD=debug
|
4
.envs/.local/.tuxbot
Normal file
4
.envs/.local/.tuxbot
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# General
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
USE_DOCKER=yes
|
||||||
|
IPYTHONDIR=/app/.ipython
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -36,4 +36,10 @@ venv
|
||||||
dist
|
dist
|
||||||
build
|
build
|
||||||
*.egg
|
*.egg
|
||||||
*.egg-info
|
*.egg-info
|
||||||
|
|
||||||
|
|
||||||
|
.ipython/
|
||||||
|
.env
|
||||||
|
.envs/*
|
||||||
|
!.envs/.local/
|
|
@ -2,7 +2,7 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/tuxbot-bot.iml" filepath="$PROJECT_DIR$/.idea/tuxbot-bot.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/tuxbot_bot.iml" filepath="$PROJECT_DIR$/.idea/tuxbot_bot.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -6,7 +6,7 @@
|
||||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.9 (tuxbot-bot)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.9 (venv)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PyDocumentationSettings">
|
<component name="PyDocumentationSettings">
|
37
compose/local/tuxbot/Dockerfile
Normal file
37
compose/local/tuxbot/Dockerfile
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
FROM python:3.8-slim-buster
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE 1
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
# dependencies for building Python packages
|
||||||
|
&& apt-get install -y build-essential \
|
||||||
|
# psycopg2 dependencies
|
||||||
|
&& apt-get install -y libpq-dev \
|
||||||
|
# Translations dependencies
|
||||||
|
&& apt-get install -y gettext \
|
||||||
|
# Git
|
||||||
|
&& apt-get install -y git \
|
||||||
|
# cleaning up unused files
|
||||||
|
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Requirements are installed here to ensure they will be cached.
|
||||||
|
COPY ./dev.requirements.txt /app/dev.requirements.txt
|
||||||
|
COPY ./tuxbot /app/tuxbot
|
||||||
|
COPY ./setup.cfg /app/setup.cfg
|
||||||
|
COPY ./setup.py /app/setup.py
|
||||||
|
RUN pip install -r /app/dev.requirements.txt
|
||||||
|
RUN pip install ./app
|
||||||
|
|
||||||
|
COPY ./compose/production/tuxbot/entrypoint /entrypoint
|
||||||
|
RUN sed -i 's/\r$//g' /entrypoint
|
||||||
|
RUN chmod +x /entrypoint
|
||||||
|
|
||||||
|
COPY ./compose/local/tuxbot/start /start
|
||||||
|
RUN sed -i 's/\r$//g' /start
|
||||||
|
RUN chmod +x /start
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint"]
|
6
compose/local/tuxbot/start
Normal file
6
compose/local/tuxbot/start
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
6
compose/production/postgres/Dockerfile
Normal file
6
compose/production/postgres/Dockerfile
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
FROM postgres:12.3
|
||||||
|
|
||||||
|
COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance
|
||||||
|
RUN chmod +x /usr/local/bin/maintenance/*
|
||||||
|
RUN mv /usr/local/bin/maintenance/* /usr/local/bin \
|
||||||
|
&& rmdir /usr/local/bin/maintenance
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
BACKUP_DIR_PATH='/backups'
|
||||||
|
BACKUP_FILE_PREFIX='backup'
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
countdown() {
|
||||||
|
declare desc="A simple countdown. Source: https://superuser.com/a/611582"
|
||||||
|
local seconds="${1}"
|
||||||
|
local d=$(($(date +%s) + "${seconds}"))
|
||||||
|
while [ "$d" -ge `date +%s` ]; do
|
||||||
|
echo -ne "$(date -u --date @$(($d - `date +%s`)) +%H:%M:%S)\r";
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
}
|
41
compose/production/postgres/maintenance/_sourced/messages.sh
Normal file
41
compose/production/postgres/maintenance/_sourced/messages.sh
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
message_newline() {
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
message_debug()
|
||||||
|
{
|
||||||
|
echo -e "DEBUG: ${@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
message_welcome()
|
||||||
|
{
|
||||||
|
echo -e "\e[1m${@}\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
message_warning()
|
||||||
|
{
|
||||||
|
echo -e "\e[33mWARNING\e[0m: ${@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
message_error()
|
||||||
|
{
|
||||||
|
echo -e "\e[31mERROR\e[0m: ${@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
message_info()
|
||||||
|
{
|
||||||
|
echo -e "\e[37mINFO\e[0m: ${@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
message_suggestion()
|
||||||
|
{
|
||||||
|
echo -e "\e[33mSUGGESTION\e[0m: ${@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
message_success()
|
||||||
|
{
|
||||||
|
echo -e "\e[32mSUCCESS\e[0m: ${@}"
|
||||||
|
}
|
16
compose/production/postgres/maintenance/_sourced/yes_no.sh
Normal file
16
compose/production/postgres/maintenance/_sourced/yes_no.sh
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
yes_no() {
|
||||||
|
declare desc="Prompt for confirmation. \$\"\{1\}\": confirmation message."
|
||||||
|
local arg1="${1}"
|
||||||
|
|
||||||
|
local response=
|
||||||
|
read -r -p "${arg1} (y/[n])? " response
|
||||||
|
if [[ "${response}" =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
38
compose/production/postgres/maintenance/backup
Normal file
38
compose/production/postgres/maintenance/backup
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
### Create a database backup.
|
||||||
|
###
|
||||||
|
### Usage:
|
||||||
|
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres backup
|
||||||
|
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
|
working_dir="$(dirname ${0})"
|
||||||
|
source "${working_dir}/_sourced/constants.sh"
|
||||||
|
source "${working_dir}/_sourced/messages.sh"
|
||||||
|
|
||||||
|
|
||||||
|
message_welcome "Backing up the '${POSTGRES_DB}' database..."
|
||||||
|
|
||||||
|
|
||||||
|
if [[ "${POSTGRES_USER}" == "postgres" ]]; then
|
||||||
|
message_error "Backing up as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export PGHOST="${POSTGRES_HOST}"
|
||||||
|
export PGPORT="${POSTGRES_PORT}"
|
||||||
|
export PGUSER="${POSTGRES_USER}"
|
||||||
|
export PGPASSWORD="${POSTGRES_PASSWORD}"
|
||||||
|
export PGDATABASE="${POSTGRES_DB}"
|
||||||
|
|
||||||
|
backup_filename="${BACKUP_FILE_PREFIX}_$(date +'%Y_%m_%dT%H_%M_%S').sql.gz"
|
||||||
|
pg_dump | gzip > "${BACKUP_DIR_PATH}/${backup_filename}"
|
||||||
|
|
||||||
|
|
||||||
|
message_success "'${POSTGRES_DB}' database backup '${backup_filename}' has been created and placed in '${BACKUP_DIR_PATH}'."
|
22
compose/production/postgres/maintenance/backups
Normal file
22
compose/production/postgres/maintenance/backups
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
### View backups.
|
||||||
|
###
|
||||||
|
### Usage:
|
||||||
|
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres backups
|
||||||
|
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
|
working_dir="$(dirname ${0})"
|
||||||
|
source "${working_dir}/_sourced/constants.sh"
|
||||||
|
source "${working_dir}/_sourced/messages.sh"
|
||||||
|
|
||||||
|
|
||||||
|
message_welcome "These are the backups you have got:"
|
||||||
|
|
||||||
|
ls -lht "${BACKUP_DIR_PATH}"
|
55
compose/production/postgres/maintenance/restore
Normal file
55
compose/production/postgres/maintenance/restore
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
### Restore database from a backup.
|
||||||
|
###
|
||||||
|
### Parameters:
|
||||||
|
### <1> filename of an existing backup.
|
||||||
|
###
|
||||||
|
### Usage:
|
||||||
|
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres restore <1>
|
||||||
|
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
|
working_dir="$(dirname ${0})"
|
||||||
|
source "${working_dir}/_sourced/constants.sh"
|
||||||
|
source "${working_dir}/_sourced/messages.sh"
|
||||||
|
|
||||||
|
|
||||||
|
if [[ -z ${1+x} ]]; then
|
||||||
|
message_error "Backup filename is not specified yet it is a required parameter. Make sure you provide one and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
backup_filename="${BACKUP_DIR_PATH}/${1}"
|
||||||
|
if [[ ! -f "${backup_filename}" ]]; then
|
||||||
|
message_error "No backup with the specified filename found. Check out the 'backups' maintenance script output to see if there is one and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
message_welcome "Restoring the '${POSTGRES_DB}' database from the '${backup_filename}' backup..."
|
||||||
|
|
||||||
|
if [[ "${POSTGRES_USER}" == "postgres" ]]; then
|
||||||
|
message_error "Restoring as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export PGHOST="${POSTGRES_HOST}"
|
||||||
|
export PGPORT="${POSTGRES_PORT}"
|
||||||
|
export PGUSER="${POSTGRES_USER}"
|
||||||
|
export PGPASSWORD="${POSTGRES_PASSWORD}"
|
||||||
|
export PGDATABASE="${POSTGRES_DB}"
|
||||||
|
|
||||||
|
message_info "Dropping the database..."
|
||||||
|
dropdb "${PGDATABASE}"
|
||||||
|
|
||||||
|
message_info "Creating a new database..."
|
||||||
|
createdb --owner="${POSTGRES_USER}"
|
||||||
|
|
||||||
|
message_info "Applying the backup to the new database..."
|
||||||
|
gunzip -c "${backup_filename}" | psql "${POSTGRES_DB}"
|
||||||
|
|
||||||
|
message_success "The '${POSTGRES_DB}' database has been restored from the '${backup_filename}' backup."
|
46
compose/production/tuxbot/Dockerfile
Normal file
46
compose/production/tuxbot/Dockerfile
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
FROM node:10-stretch-slim as client-builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./package.json /app
|
||||||
|
RUN npm install && npm cache clean --force
|
||||||
|
COPY . /app
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Python build stage
|
||||||
|
FROM python:3.8-slim-buster
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
# dependencies for building Python packages
|
||||||
|
&& apt-get install -y build-essential \
|
||||||
|
# psycopg2 dependencies
|
||||||
|
&& apt-get install -y libpq-dev \
|
||||||
|
# Translations dependencies
|
||||||
|
&& apt-get install -y gettext \
|
||||||
|
# cleaning up unused files
|
||||||
|
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN addgroup --system tuxbot \
|
||||||
|
&& adduser --system --ingroup tuxbot tuxbot
|
||||||
|
|
||||||
|
# Requirements are installed here to ensure they will be cached.
|
||||||
|
RUN pip install --no-cache-dir psycopg2==2.8.6
|
||||||
|
|
||||||
|
COPY --chown=tuxbot:tuxbot ./compose/production/tuxbot/entrypoint /entrypoint
|
||||||
|
RUN sed -i 's/\r$//g' /entrypoint
|
||||||
|
RUN chmod +x /entrypoint
|
||||||
|
|
||||||
|
|
||||||
|
COPY --chown=tuxbot:tuxbot ./compose/production/tuxbot/start /start
|
||||||
|
RUN sed -i 's/\r$//g' /start
|
||||||
|
RUN chmod +x /start
|
||||||
|
COPY --from=client-builder --chown=tuxbot:tuxbot /app /app
|
||||||
|
|
||||||
|
|
||||||
|
USER tuxbot
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint"]
|
42
compose/production/tuxbot/entrypoint
Normal file
42
compose/production/tuxbot/entrypoint
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [ -z "${POSTGRES_USER}" ]; then
|
||||||
|
base_postgres_image_default_user='postgres'
|
||||||
|
export POSTGRES_USER="${base_postgres_image_default_user}"
|
||||||
|
fi
|
||||||
|
export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"
|
||||||
|
|
||||||
|
postgres_ready() {
|
||||||
|
python << END
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
|
||||||
|
try:
|
||||||
|
psycopg2.connect(
|
||||||
|
dbname="${POSTGRES_DB}",
|
||||||
|
user="${POSTGRES_USER}",
|
||||||
|
password="${POSTGRES_PASSWORD}",
|
||||||
|
host="${POSTGRES_HOST}",
|
||||||
|
port="${POSTGRES_PORT}",
|
||||||
|
)
|
||||||
|
except psycopg2.OperationalError:
|
||||||
|
sys.exit(-1)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
END
|
||||||
|
}
|
||||||
|
until postgres_ready; do
|
||||||
|
>&2 echo 'Waiting for PostgreSQL to become available...'
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
>&2 echo 'PostgreSQL is available'
|
||||||
|
|
||||||
|
exec "$@"
|
8
compose/production/tuxbot/start
Normal file
8
compose/production/tuxbot/start
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
|
||||||
|
tuxbot dev
|
33
local.yml
Normal file
33
local.yml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
local_postgres_data: {}
|
||||||
|
local_postgres_data_backups: {}
|
||||||
|
|
||||||
|
services:
|
||||||
|
tuxbot:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./compose/local/tuxbot/Dockerfile
|
||||||
|
image: tuxbot_bot_local_tuxbot
|
||||||
|
container_name: tuxbot
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
volumes:
|
||||||
|
- .:/app:z
|
||||||
|
env_file:
|
||||||
|
- ./.envs/.local/.tuxbot
|
||||||
|
- ./.envs/.local/.postgres
|
||||||
|
command: /start
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./compose/production/postgres/Dockerfile
|
||||||
|
image: tuxbot_bot_production_postgres
|
||||||
|
container_name: postgres
|
||||||
|
volumes:
|
||||||
|
- local_postgres_data:/var/lib/postgresql/data:Z
|
||||||
|
- local_postgres_data_backups:/backups:z
|
||||||
|
env_file:
|
||||||
|
- ./.envs/.local/.postgres
|
|
@ -26,7 +26,7 @@ install_requires =
|
||||||
psutil==5.7.2
|
psutil==5.7.2
|
||||||
pydig==0.3.0
|
pydig==0.3.0
|
||||||
rich==9.10.0
|
rich==9.10.0
|
||||||
sentry_sdk==0.19.5
|
sentry_sdk==0.20.0
|
||||||
structured_config==4.12
|
structured_config==4.12
|
||||||
tortoise-orm==0.16.17
|
tortoise-orm==0.16.17
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import sys
|
||||||
from tuxbot import ExitCodes
|
from tuxbot import ExitCodes
|
||||||
from tuxbot.core.utils.console import console
|
from tuxbot.core.utils.console import console
|
||||||
|
|
||||||
|
@ -9,10 +10,7 @@ def main() -> None:
|
||||||
run()
|
run()
|
||||||
except SystemExit as exc:
|
except SystemExit as exc:
|
||||||
if exc.code == ExitCodes.RESTART:
|
if exc.code == ExitCodes.RESTART:
|
||||||
# reimport to load changes
|
sys.exit(exc.code)
|
||||||
from .__run__ import run # pylint: disable=import-outside-toplevel
|
|
||||||
|
|
||||||
run()
|
|
||||||
else:
|
else:
|
||||||
raise exc
|
raise exc
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -366,10 +366,10 @@ class Tux(commands.AutoShardedBot):
|
||||||
and reboot.
|
and reboot.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not restart:
|
|
||||||
self.shutdown_code = ExitCodes.SHUTDOWN
|
self.shutdown_code = (
|
||||||
else:
|
ExitCodes.RESTART if restart else ExitCodes.SHUTDOWN
|
||||||
self.shutdown_code = ExitCodes.RESTART
|
)
|
||||||
|
|
||||||
await self.logout()
|
await self.logout()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue