docker rework start

This commit is contained in:
sadnub 2020-11-14 16:54:29 -05:00
parent 717803c665
commit f05908f570
25 changed files with 350 additions and 311 deletions

2
.gitignore vendored
View File

@ -42,3 +42,5 @@ api/tacticalrmm/accounts/management/commands/random_data.py
versioninfo.go
resource.syso
htmlcov/
docker-compose.override.yml
docker-compose.dev.yml

View File

@ -1,46 +0,0 @@
FROM tiangolo/uwsgi-nginx:python3.8
WORKDIR /app
ARG DJANGO_SEKRET
ARG DJANGO_DEBUG
ARG POSTGRES_USER
ARG POSTGRES_PASS
ARG POSTGRES_HOST
ARG SALT_HOST
ARG SALT_USER
ARG SALT_PASS
ARG REDIS_HOST
ARG MESH_USER
ARG MESH_HOST
ARG MESH_TOKEN_KEY
ARG APP_HOST
ARG API_HOST
ARG ADMIN_URL
EXPOSE 80
RUN apt-get update && apt-get install -y gettext-base wget ca-certificates
COPY ./api/tacticalrmm/requirements.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache-dir setuptools==49.6.0 wheel==0.35.1
RUN pip install --no-cache-dir -r requirements.txt
RUN wget https://golang.org/dl/go1.15.linux-amd64.tar.gz -P /tmp
COPY ./api/tacticalrmm/ .
COPY ./scripts/ /scripts
COPY ./docker/api/prestart.sh .
COPY ./docker/api/uwsgi.ini .
COPY ./docker/api/api.conf /app/api.conf.tmp
COPY ./api/tacticalrmm/core/goinstaller/bin/goversioninfo /usr/local/bin/goversioninfo
RUN envsubst '\$APP_HOST, \$API_HOST' < /app/api.conf.tmp > /app/nginx.conf && \
rm /app/api.conf.tmp
COPY ./docker/api/local_settings.py.keep ./tacticalrmm/local_settings.py.tmp
RUN envsubst < /app/tacticalrmm/local_settings.py.tmp > /app/tacticalrmm/local_settings.py && rm /app/tacticalrmm/local_settings.py.tmp
RUN tar -xzf /tmp/go1.15.linux-amd64.tar.gz -C /tmp && \
mkdir /usr/local/rmmgo && \
mv /tmp/go /usr/local/rmmgo/ && \
rm -rf /tmp/go
RUN /usr/local/rmmgo/go/bin/go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo && \
chmod +x /usr/local/bin/goversioninfo

View File

@ -1,47 +0,0 @@
SECRET_KEY = '${DJANGO_SEKRET}'
ALLOWED_HOSTS = ['${API_HOST}']
ADMIN_URL = "${ADMIN_URL}"
CORS_ORIGIN_WHITELIST = ["https://${APP_HOST}",]
DEBUG = ${DJANGO_DEBUG}
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'tacticalrmm',
'USER': '${POSTGRES_USER}',
'PASSWORD': '${POSTGRES_PASS}',
'HOST': '${POSTGRES_HOST}',
'PORT': '5432',
}
}
REST_FRAMEWORK = {
'DATETIME_FORMAT': "%b-%d-%Y - %H:%M",
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'knox.auth.TokenAuthentication',
),
}
if not DEBUG:
REST_FRAMEWORK.update({
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
})
SALT_USERNAME = "${SALT_USER}"
SALT_PASSWORD = "${SALT_PASS}"
MESH_USERNAME = "${MESH_USER}"
MESH_SITE = "https://${MESH_HOST}"
MESH_WS_URL="ws://meshcentral:443"
MESH_TOKEN_KEY = "${MESH_TOKEN_KEY}"
REDIS_HOST = "${REDIS_HOST}"
SALT_HOST = "${SALT_HOST}"

View File

@ -1,10 +0,0 @@
#! /usr/bin/env bash
sleep 10
python manage.py migrate --no-input
python manage.py collectstatic --no-input
python manage.py initial_db_setup
python manage.py initial_mesh_setup
python manage.py load_chocos
python manage.py fix_salt_key
python manage.py load_community_scripts

View File

@ -1,14 +0,0 @@
[uwsgi]
logto = /app/tacticalrmm/private/log/uwsgi.log
chdir = /app
wsgi-file = tacticalrmm/wsgi.py
master = true
processes = 4
threads = 2
socket = /app/tacticalrmm.sock
# clear environment on exit
vacuum = true
die-on-term = true
max-requests = 500
max-requests-delta = 1000

View File

@ -0,0 +1,46 @@
FROM python:3.8-slim AS builder
ARG DEBIAN_FRONTEND=noninteractive
ARG BUILD_DATE
ENV TACTICAL_DIR /opt/tactical/
ENV TACTICAL_TMP_DIR /tmp/tacticalrmm/
ENV TACTICAL_READY_FILE ${TACTICAL_DIR}/tmp/tactical.ready
ENV TACTICAL_USER tactical
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
# install tactical
COPY docker/containers/tactical/setup.sh /tmp
COPY api/tacticalrmm/requirements.txt ${TACTICAL_TMP_DIR}
RUN chmod +x /tmp/setup.sh && \
/tmp/setup.sh install
FROM python:3.8-slim
ARG DEBIAN_FRONTEND=noninteractive
ARG BUILD_DATE
ENV TACTICAL_DIR /opt/tactical/
ENV TACTICAL_TMP_DIR /tmp/tacticalrmm/
ENV TACTICAL_SCRIPTS_DIR ${TACTICAL_DIR}/scripts/
ENV TACTICAL_GO_DIR /usr/local/rmmgo/
ENV TACTICAL_READY_FILE ${TACTICAL_DIR}/tmp/tactical.ready
ENV TACTICAL_USER tactical
COPY docker/containers/tactical/setup.sh /tmp
RUN chmod +x /tmp/setup.sh; \
/tmp/setup.sh run
COPY from=builder /tmp/go ${TACTICAL_GO_DIR}
COPY from=builder ${TACTICAL_TMP_DIR}/env ${TACTICAL_DIR}
COPY api/tacticalrmm/ ${TACTICAL_DIR}
COPY scripts/ ${TACTICAL_SCRIPTS_DIR}
COPY api/tacticalrmm/core/goinstaller/bin/goversioninfo /usr/local/bin/goversioninfo
# docker init
COPY containers/backend/docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
WORKDIR ${TACTICAL_DIR}

View File

@ -0,0 +1,142 @@
#!/usr/bin/env bash
set -e
: "${POSTGRES_HOST:=tactical-postgres}"
: "${POSTGRESQL_PORT:=5432}"
: "${POSTGRES_USER:=tactical}"
: "${POSTGRES_PASS:=tactical}"
: "${POSTGRES_DB:=tactical}"
: "${SALT_HOST:=tactical-salt}"
: "${SALT_USER:=saltapi}"
: "${MESH_CONTAINER:=tactical-meshcentral}"
: "${MESH_USER:=meshcentral}"
: "${MESH_PASS:=meshcentralpass}"
: "${MESH_HOST:=tactical-meshcentral}"
: "${API_HOST:=tactical-backend}"
: "${APP_HOST:=tactical-frontend}"
: "${REDIS_HOST:=tactical-redis}"
function check_tactical_ready {
sleep 15
until [ -f "${TACTICAL_READY_FILE}" ]; do
echo "waiting for init container to finish install or update..."
sleep 10
done
}
# tactical-init
if [ "$1" = 'tactical-init' ]; then
test -f "${TACTICAL_READY_FILE}" && rm "${TACTICAL_READY_FILE}"
until (echo > /dev/tcp/"${POSTGRES_HOST}"/"${POSTGRES_PORT}") &> /dev/null; do
echo "waiting for postgresql server to be ready..."
sleep 5
done
cd "${TACTICAL_DIR}"
# configure django settings
DJANGO_SEKRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 80 | head -n 1)
SALT_PASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1)
ADMINURL=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 70 | head -n 1)
localvars="$(cat << EOF
SECRET_KEY = '${DJANGO_SEKRET}'
DEBUG = False
ALLOWED_HOSTS = ['${API_HOST}']
ADMIN_URL = '${ADMINURL}/'
CORS_ORIGIN_WHITELIST = [
'https://${APP_HOST}'
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': '${POSTGRES_DB}',
'USER': '${POSTGRES_USER}',
'PASSWORD': '${POSTGRES_PASS}',
'HOST': '${POSTGRES_HOST}',
'PORT': '${POSTGRES_PORT}',
}
}
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%b-%d-%Y - %H:%M',
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'knox.auth.TokenAuthentication',
),
}
if not DEBUG:
REST_FRAMEWORK.update({
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
})
SALT_USERNAME = '${SALT_USER}'
SALT_PASSWORD = '${SALT_PASS}'
SALT_HOST = '${SALT_HOST}'
MESH_USERNAME = '${MESH_USER}'
MESH_SITE = 'https://${MESH_HOST}'
REDIS_HOST = '${REDIS_HOST}'
MESH_WS_URL = 'ws://${MESH_CONTAINER}:443'
EOF
)"
echo "${localvars}" > ${TACTICAL_DIR}/tacticalrmm/local_settings.py
# check mesh setup and wait for mesh token
if [ ! test -f "${TACTICAL_DIR}/mesh_token" ]; then
until (test -f "${TACTICAL_DIR}/mesh_token") do
echo "waiting for mesh token to be generated..."
sleep 5
done
# run migrations and init scripts
python manage.py migrate --no-input
python manage.py collectstatic --no-input
python manage.py initial_db_setup
python manage.py initial_mesh_setup
python manage.py load_chocos
python manage.py load_community_scripts
# chown everything to tactical user
chown -R "${TACTICAL_USER}":"${TACTICAL_USER}" "${TACTICAL_DIR}"
# create install ready file
su -c "echo 'tactical-init' > ${TACTICAL_READY_FILE}" "${TACTICAL_USER}"
fi
# backend container
if [ "$1" = 'tactical-backend' ]; then
check_tactical_ready
# Prepare log files and start outputting logs to stdout
touch ${TACTICAL_DIR}/tacticalrmm/logs/gunicorn.log
touch ${TACTICAL_DIR}/tacticalrmm/logs/gunicorn-access.log
tail -n 0 -f ${TACTICAL_DIR}/tacticalrmm/logs/gunicorn*.log &
export DJANGO_SETTINGS_MODULE=tactical.settings
exec gunicorn tacticalrmm.wsgi:application \
--name tactical-backend \
--bind 0.0.0.0:80 \
--workers 5 \
--log-level=info \
--log-file=${TACTICAL_DIR}/tacticalrmm/logs/gunicorn.log \
--access-logfile=${TACTICAL_DIR}/tacticalrmm/logs/gunicorn-access.log \
"$@"
fi

View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
# install tactical
groupadd -g 1000 "${TACTICAL_USER}"
useradd -M -d "${TACTICAL_DIR}" -s /bin/bash -u 1000 -g 1000 "${TACTICAL_USER}"
if [ "$1" = 'install' ]; then
apt-get update
apt-get upgrade -y
apt-get install -y --no-install-recommends wget ca-certificates gcc libc6-dev
rm -rf /var/lib/apt/lists/*
pip install --upgrade pip
pip install --no-cache-dir virtualenv && python -m virtualenv ${TACTICAL_TMP_DIR}/env
${TACTICAL_TMP_DIR}/env/bin/pip install --no-cache-dir setuptools wheel gunicorn
${TACTICAL_TMP_DIR}/env/bin/pip install --no-cache-dir -r ${TACTICAL_TMP_DIR}/requirements.txt
wget https://golang.org/dl/go1.15.linux-amd64.tar.gz -P /tmp
tar -xzf /tmp/go1.15.linux-amd64.tar.gz -C /tmp
fi
if [ "$1" = 'run' ]; then
mkdir /usr/local/rmmgo
fi

View File

@ -1,143 +0,0 @@
# FOR PROD
version: "3.7"
volumes:
# Gives access to the debug log for celery tasks
debug_log:
services:
# Container that hosts Vue frontend
app:
build:
context: ..
args:
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
dockerfile: "./docker/app/dockerfile"
networks:
- proxy
# Container for Django backend
api:
build:
context: ..
dockerfile: "./docker/api/dockerfile"
args:
- DJANGO_SEKRET=${DJANGO_SEKRET}
- DJANGO_DEBUG=${DJANGO_DEBUG}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASS=${POSTGRES_PASS}
- POSTGRES_HOST=${POSTGRES_HOST}
- SALT_PASS=${SALT_PASS}
- SALT_USER=${SALT_USER}
- SALT_HOST=${SALT_HOST}
- REDIS_HOST=${REDIS_HOST}
- MESH_USER=${MESH_USER}
- MESH_HOST=${MESH_HOST}
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
- ADMIN_URL=${ADMIN_URL}
networks:
- proxy
- database
- redis
volumes:
- scripts:/srv
- mesh_token:/token
- debug_log:/app/tacticalrmm/private/log
depends_on:
- db
- meshcentral
# Container for Celery worker service
celery-service:
build:
context: ..
dockerfile: "./docker/api/dockerfile"
args:
- DJANGO_SEKRET=${DJANGO_SEKRET}
- DJANGO_DEBUG=${DJANGO_DEBUG}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASS=${POSTGRES_PASS}
- POSTGRES_HOST=${POSTGRES_HOST}
- SALT_PASS=${SALT_PASS}
- SALT_USER=${SALT_USER}
- SALT_HOST=${SALT_HOST}
- REDIS_HOST=${REDIS_HOST}
- MESH_USER=${MESH_USER}
- MESH_HOST=${MESH_HOST}
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
- ADMIN_URL=${ADMIN_URL}
command: celery -A tacticalrmm worker -l debug
networks:
- redis
- proxy
- database
volumes:
- debug_log:/app/tacticalrmm/private/log
depends_on:
- db
- redis
# Container for Celery beat service
celery-beat:
build:
context: ..
dockerfile: "./docker/api/dockerfile"
args:
- DJANGO_SEKRET=${DJANGO_SEKRET}
- DJANGO_DEBUG=${DJANGO_DEBUG}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASS=${POSTGRES_PASS}
- POSTGRES_HOST=${POSTGRES_HOST}
- SALT_PASS=${SALT_PASS}
- SALT_USER=${SALT_USER}
- SALT_HOST=${SALT_HOST}
- REDIS_HOST=${REDIS_HOST}
- MESH_USER=${MESH_USER}
- MESH_HOST=${MESH_HOST}
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
- ADMIN_URL=${ADMIN_URL}
command: celery -A tacticalrmm beat -l debug
networks:
- redis
- proxy
- database
volumes:
- debug_log:/app/tacticalrmm/private/log
depends_on:
- db
- redis
# Container for Celery Winupdate tasks
celery-winupdate:
build:
context: ..
dockerfile: "./docker/api/dockerfile"
args:
- DJANGO_SEKRET=${DJANGO_SEKRET}
- DJANGO_DEBUG=${DJANGO_DEBUG}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASS=${POSTGRES_PASS}
- POSTGRES_HOST=${POSTGRES_HOST}
- SALT_PASS=${SALT_PASS}
- SALT_USER=${SALT_USER}
- SALT_HOST=${SALT_HOST}
- REDIS_HOST=${REDIS_HOST}
- MESH_USER=${MESH_USER}
- MESH_HOST=${MESH_HOST}
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
- ADMIN_URL=${ADMIN_URL}
command: celery -A tacticalrmm worker -Q wupdate -l debug
networks:
- redis
- proxy
- database
volumes:
- debug_log:/app/tacticalrmm/private/log
depends_on:
- db
- redis

View File

@ -1,6 +1,6 @@
version: "3.7"
# Userdefined Networks
# networks
networks:
proxy:
driver: bridge
@ -8,102 +8,187 @@ networks:
driver: default
config:
- subnet: 172.20.0.0/24
database:
api-db:
redis:
mesh-mongodb:
mesh-db:
# Docker managed persistent volumes
# docker managed persistent volumes
volumes:
# Volume for userdefined scripts
scripts:
# Volume for mesh token initial setup
mesh_token:
# Used to make the salt data persistent
tactical_data:
salt_data:
# Makes Postgres data persistent
postgres_data13:
# Makes mesh central data persistent
postgres_data:
mongo_data:
services:
# Postgres Database for API service
db:
# postgres database for api service
tactical-postgres:
image: postgres:13
environment:
POSTGRES_DB: tacticalrmm
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASS}
volumes:
- postgres_data13:/var/lib/postgresql/data
- postgres_data:/var/lib/postgresql/data
networks:
- database
- api-db
# Redis Container for Celery tasks
redis:
# redis container for celery tasks
tactical-redis:
image: redis
networks:
- redis
# Salt Master and API
salt:
build:
context: ..
dockerfile: ./docker/salt/dockerfile
args:
- SALT_USER=${SALT_USER}
- SALT_PASS=${SALT_PASS}
tactical-init:
image: ${IMAGE_REPO}:tactical-${VERSION}
restart: on-failure
command: ["tactical-init"]
environment:
POSTGRES_DB: tacticalrmm
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASS}
APP_HOST: ${APP_HOST}
API_HOST: ${API_HOST}
MESH_HOST: ${MESH_HOST}
depends_on:
- tactical-postgres
- tactical-meshcentral
networks:
- api-db
- proxy
volumes:
- tacticalrmm:/opt/tactical
# salt master and api
tactical-salt:
image: {IMAGE_REPO}:tactical-salt-${VERSION}
restart: always
ports:
- "4505:4505"
- "4506:4506"
volumes:
- scripts:/srv
- tacticalrmm:/opt/tactical
- salt_data:/etc/salt
networks:
- proxy
# MeshCentral Container
meshcentral:
build:
context: ./meshcentral
args:
- MESH_HOST=${MESH_HOST}
- MESH_USER=${MESH_USER}
- MESH_PASS=${MESH_PASS}
- EMAIL_USER=${EMAIL_USER}
- MONGODB_USER=${MONGODB_USER}
- MONGODB_PASSWORD=${MONGODB_PASSWORD}
tactical-meshcentral:
image: ${IMAGE_REPO}:tactical-meshcentral-${VERSION}
restart: always
networks:
- proxy
- mesh-mongodb
- mesh-db
volumes:
- mesh_token:/token
- tacticalrmm:/opt/tactical
depends_on:
- mesh-mongodb
- nginx-proxy
- tactical-mongodb
# MongoDB Container for MeshCentral
mesh-mongodb:
tactical-mongodb:
image: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGODB_USER}
MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD}
MONGO_INITDB_DATABASE: meshcentral
networks:
- mesh-mongodb
- mesh-db
volumes:
- mongo_data:/data
# Nginx Container Reverse Proxy that handles all http/https traffic
nginx-proxy:
build:
context: ./nginx-proxy
args:
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
- MESH_HOST=${MESH_HOST}
# Container that hosts Vue frontend
tactical-frontend:
image: ${IMAGE_REPO}:tactical-frontend-${VERSION}
command: exec /usr/sbin/nginx -g 'daemon off;'
restart: always
environment:
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
volumes:
- tactical_data:/opt/tactical
ports:
- "80:80"
- "443:443"
networks:
proxy:
ipv4_address: 172.20.0.20
# Container for Django backend
tactical-backend:
image: ${IMAGE_REPO}:tactical-${VERSION}
command: ["tactical-backend"]
restart: always
environment:
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
- MESH_HOST=${MESH_HOST}
networks:
- proxy
- api-db
- redis
volumes:
- tactical_data:/opt/tactical
depends_on:
- tactical-postgres
- tactical-meshcentral
tactical-nginx:
# Container for tactical proxy
image: ${IMAGE_REPO}:tactical-${VERSION}
command: ["tactical-nginx"]
restart: always
environment:
- APP_HOST=${APP_HOST}
- API_HOST=${API_HOST}
- MESH_HOST=${MESH_HOST}
networks:
- proxy
volumes:
- tactical_data:/opt/tactical
depends_on:
- tactical-postgres
- tactical-meshcentral
# container for celery worker service
tactical-celery:
image: ${IMAGE_REPO}:tactical-${VERSION}
command: ["tactical-celery"]
restart: always
networks:
- redis
- proxy
- api-db
volumes:
- tactical_data:/opt/tactical
depends_on:
- tactical-postgres
- tactical-redis
# container for celery beat service
tactical-celerybeat:
image: ${IMAGE_REPO}:tactical-${VERSION}
command: ["tactical-celerybeat"]
restart: always
networks:
- redis
- api-db
- database
volumes:
- tactical_data:/opt/tactical
depends_on:
- tactical-postgres
- tactical-redis
# container for celery winupdate tasks
tactical-celerywinupdate:
image: ${IMAGE_REPO}:tactical-${VERSION}
command: ["tactical-celerywinupdate"]
restart: always
networks:
- redis
- proxy
- api-db
volumes:
- tactical_data:/opt/tactical
depends_on:
- tactical-postgres
- tactical-redis