mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-12-10 05:52:31 -05:00
Compare commits
9 Commits
9ef4ef47f4
...
feat/ui-tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddf23271ea | ||
|
|
f2c83b8998 | ||
|
|
2c367d7eeb | ||
|
|
6eae3310ad | ||
|
|
e536c74576 | ||
|
|
aeef8284bf | ||
|
|
a90fcbf8dd | ||
|
|
1b3cdfd302 | ||
|
|
cd7dd4f72c |
@@ -1,113 +0,0 @@
|
|||||||
FROM python:3.13.5-slim-bookworm AS build-image
|
|
||||||
|
|
||||||
# Install system dependencies needed for downloading and extracting
|
|
||||||
RUN apt-get update -y && \
|
|
||||||
apt-get install -y --no-install-recommends wget xz-utils unzip && \
|
|
||||||
rm -rf /var/lib/apt/lists/* && \
|
|
||||||
apt-get purge --auto-remove && \
|
|
||||||
apt-get clean
|
|
||||||
|
|
||||||
RUN wget -q https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
|
|
||||||
|
|
||||||
RUN mkdir -p ffmpeg-tmp && \
|
|
||||||
tar -xf ffmpeg-release-amd64-static.tar.xz --strip-components 1 -C ffmpeg-tmp && \
|
|
||||||
cp -v ffmpeg-tmp/ffmpeg ffmpeg-tmp/ffprobe ffmpeg-tmp/qt-faststart /usr/local/bin && \
|
|
||||||
rm -rf ffmpeg-tmp ffmpeg-release-amd64-static.tar.xz
|
|
||||||
|
|
||||||
# Install Bento4 in the specified location
|
|
||||||
RUN mkdir -p /home/mediacms.io/bento4 && \
|
|
||||||
wget -q http://zebulon.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip && \
|
|
||||||
unzip Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip -d /home/mediacms.io/bento4 && \
|
|
||||||
mv /home/mediacms.io/bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/* /home/mediacms.io/bento4/ && \
|
|
||||||
rm -rf /home/mediacms.io/bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux && \
|
|
||||||
rm -rf /home/mediacms.io/bento4/docs && \
|
|
||||||
rm Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip
|
|
||||||
|
|
||||||
############ BASE RUNTIME IMAGE ############
|
|
||||||
FROM python:3.13.5-slim-bookworm AS base
|
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-c"]
|
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
|
||||||
ENV CELERY_APP='cms'
|
|
||||||
ENV VIRTUAL_ENV=/home/mediacms.io
|
|
||||||
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
|
||||||
|
|
||||||
# Install system dependencies first
|
|
||||||
RUN apt-get update -y && \
|
|
||||||
apt-get -y upgrade && \
|
|
||||||
apt-get install --no-install-recommends -y \
|
|
||||||
supervisor \
|
|
||||||
nginx \
|
|
||||||
imagemagick \
|
|
||||||
procps \
|
|
||||||
build-essential \
|
|
||||||
pkg-config \
|
|
||||||
zlib1g-dev \
|
|
||||||
zlib1g \
|
|
||||||
libxml2-dev \
|
|
||||||
libxmlsec1-dev \
|
|
||||||
libxmlsec1-openssl \
|
|
||||||
libpq-dev \
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Set up virtualenv first
|
|
||||||
RUN mkdir -p /home/mediacms.io/mediacms/{logs} && \
|
|
||||||
cd /home/mediacms.io && \
|
|
||||||
python3 -m venv $VIRTUAL_ENV
|
|
||||||
|
|
||||||
# Copy requirements files
|
|
||||||
COPY requirements.txt requirements-dev.txt ./
|
|
||||||
|
|
||||||
# Install Python dependencies using pip (within virtualenv)
|
|
||||||
ARG DEVELOPMENT_MODE=False
|
|
||||||
RUN pip install --no-cache-dir uv && \
|
|
||||||
uv pip install --no-binary lxml --no-binary xmlsec -r requirements.txt && \
|
|
||||||
if [ "$DEVELOPMENT_MODE" = "True" ]; then \
|
|
||||||
echo "Installing development dependencies..." && \
|
|
||||||
uv pip install -r requirements-dev.txt; \
|
|
||||||
fi && \
|
|
||||||
apt-get purge -y --auto-remove \
|
|
||||||
build-essential \
|
|
||||||
pkg-config \
|
|
||||||
libxml2-dev \
|
|
||||||
libxmlsec1-dev \
|
|
||||||
libpq-dev
|
|
||||||
|
|
||||||
# Copy ffmpeg and Bento4 from build image
|
|
||||||
COPY --from=build-image /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
|
|
||||||
COPY --from=build-image /usr/local/bin/ffprobe /usr/local/bin/ffprobe
|
|
||||||
COPY --from=build-image /usr/local/bin/qt-faststart /usr/local/bin/qt-faststart
|
|
||||||
COPY --from=build-image /home/mediacms.io/bento4 /home/mediacms.io/bento4
|
|
||||||
|
|
||||||
# Copy application files
|
|
||||||
COPY . /home/mediacms.io/mediacms
|
|
||||||
WORKDIR /home/mediacms.io/mediacms
|
|
||||||
|
|
||||||
# required for sprite thumbnail generation for large video files
|
|
||||||
COPY deploy/docker/policy.xml /etc/ImageMagick-6/policy.xml
|
|
||||||
|
|
||||||
# Set process control environment variables
|
|
||||||
ENV ENABLE_UWSGI='yes' \
|
|
||||||
ENABLE_NGINX='yes' \
|
|
||||||
ENABLE_CELERY_BEAT='yes' \
|
|
||||||
ENABLE_CELERY_SHORT='yes' \
|
|
||||||
ENABLE_CELERY_LONG='yes' \
|
|
||||||
ENABLE_MIGRATIONS='yes'
|
|
||||||
|
|
||||||
EXPOSE 9000 80
|
|
||||||
|
|
||||||
RUN chmod +x ./deploy/docker/entrypoint.sh
|
|
||||||
|
|
||||||
ENTRYPOINT ["./deploy/docker/entrypoint.sh"]
|
|
||||||
CMD ["./deploy/docker/start.sh"]
|
|
||||||
|
|
||||||
############ FULL IMAGE ############
|
|
||||||
FROM base AS full
|
|
||||||
COPY requirements-full.txt ./
|
|
||||||
RUN mkdir -p /root/.cache/ && \
|
|
||||||
chmod go+rwx /root/ && \
|
|
||||||
chmod go+rwx /root/.cache/
|
|
||||||
RUN uv pip install -r requirements-full.txt
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
nginx-proxy:
|
|
||||||
image: nginxproxy/nginx-proxy
|
|
||||||
container_name: nginx-proxy
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- conf:/etc/nginx/conf.d
|
|
||||||
- vhost:/etc/nginx/vhost.d
|
|
||||||
- html:/usr/share/nginx/html
|
|
||||||
- dhparam:/etc/nginx/dhparam
|
|
||||||
- certs:/etc/nginx/certs:ro
|
|
||||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
|
||||||
- ./deploy/docker/reverse_proxy/client_max_body_size.conf:/etc/nginx/conf.d/client_max_body_size.conf:ro
|
|
||||||
|
|
||||||
acme-companion:
|
|
||||||
image: nginxproxy/acme-companion
|
|
||||||
container_name: nginx-proxy-acme
|
|
||||||
volumes_from:
|
|
||||||
- nginx-proxy
|
|
||||||
volumes:
|
|
||||||
- certs:/etc/nginx/certs:rw
|
|
||||||
- acme:/etc/acme.sh
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
|
|
||||||
migrations:
|
|
||||||
image: mediacms/mediacms:latest
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_SHORT: 'no'
|
|
||||||
ENABLE_CELERY_LONG: 'no'
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ADMIN_USER: 'admin'
|
|
||||||
ADMIN_EMAIL: 'Y'
|
|
||||||
ADMIN_PASSWORD: 'X'
|
|
||||||
command: "./deploy/docker/prestart.sh"
|
|
||||||
restart: on-failure
|
|
||||||
depends_on:
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
web:
|
|
||||||
image: mediacms/mediacms:latest
|
|
||||||
deploy:
|
|
||||||
replicas: 1
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ENABLE_CELERY_SHORT: 'no'
|
|
||||||
ENABLE_CELERY_LONG: 'no'
|
|
||||||
ENABLE_MIGRATIONS: 'no'
|
|
||||||
VIRTUAL_HOST: 'X.mediacms.io'
|
|
||||||
LETSENCRYPT_HOST: 'X.mediacms.io'
|
|
||||||
LETSENCRYPT_EMAIL: 'X'
|
|
||||||
depends_on:
|
|
||||||
- migrations
|
|
||||||
celery_beat:
|
|
||||||
image: mediacms/mediacms:latest
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_SHORT: 'no'
|
|
||||||
ENABLE_CELERY_LONG: 'no'
|
|
||||||
ENABLE_MIGRATIONS: 'no'
|
|
||||||
depends_on:
|
|
||||||
- redis
|
|
||||||
celery_worker:
|
|
||||||
image: mediacms/mediacms:full
|
|
||||||
deploy:
|
|
||||||
replicas: 1
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ENABLE_MIGRATIONS: 'no'
|
|
||||||
depends_on:
|
|
||||||
- migrations
|
|
||||||
db:
|
|
||||||
image: postgres:17.2-alpine
|
|
||||||
volumes:
|
|
||||||
- ../postgres_data:/var/lib/postgresql/data/
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: mediacms
|
|
||||||
POSTGRES_PASSWORD: mediacms
|
|
||||||
POSTGRES_DB: mediacms
|
|
||||||
TZ: Europe/London
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
redis:
|
|
||||||
image: "redis:alpine"
|
|
||||||
restart: always
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli","ping"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
volumes:
|
|
||||||
conf:
|
|
||||||
vhost:
|
|
||||||
html:
|
|
||||||
dhparam:
|
|
||||||
certs:
|
|
||||||
acme:
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
migrations:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: ./Dockerfile
|
|
||||||
target: base
|
|
||||||
args:
|
|
||||||
- DEVELOPMENT_MODE=True
|
|
||||||
image: mediacms/mediacms-dev:latest
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
command: "./deploy/docker/prestart.sh"
|
|
||||||
environment:
|
|
||||||
DEVELOPMENT_MODE: True
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_SHORT: 'no'
|
|
||||||
ENABLE_CELERY_LONG: 'no'
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ADMIN_USER: 'admin'
|
|
||||||
ADMIN_EMAIL: 'admin@localhost'
|
|
||||||
ADMIN_PASSWORD: 'admin'
|
|
||||||
restart: on-failure
|
|
||||||
depends_on:
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
frontend:
|
|
||||||
image: node:20
|
|
||||||
volumes:
|
|
||||||
- ${PWD}/frontend:/home/mediacms.io/mediacms/frontend/
|
|
||||||
working_dir: /home/mediacms.io/mediacms/frontend/
|
|
||||||
command: bash -c "npm install && npm run start"
|
|
||||||
env_file:
|
|
||||||
- ${PWD}/frontend/.env
|
|
||||||
ports:
|
|
||||||
- "8088:8088"
|
|
||||||
depends_on:
|
|
||||||
- web
|
|
||||||
web:
|
|
||||||
image: mediacms/mediacms-dev:latest
|
|
||||||
command: "python manage.py runserver 0.0.0.0:80"
|
|
||||||
environment:
|
|
||||||
DEVELOPMENT_MODE: True
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
depends_on:
|
|
||||||
- migrations
|
|
||||||
db:
|
|
||||||
image: postgres:17.2-alpine
|
|
||||||
volumes:
|
|
||||||
- ../postgres_data:/var/lib/postgresql/data/
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: mediacms
|
|
||||||
POSTGRES_PASSWORD: mediacms
|
|
||||||
POSTGRES_DB: mediacms
|
|
||||||
TZ: Europe/London
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}", "--host=db", "--dbname=$POSTGRES_DB", "--username=$POSTGRES_USER"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
redis:
|
|
||||||
image: "redis:alpine"
|
|
||||||
restart: always
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
celery_worker:
|
|
||||||
image: mediacms/mediacms-dev:latest
|
|
||||||
deploy:
|
|
||||||
replicas: 1
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ENABLE_MIGRATIONS: 'no'
|
|
||||||
depends_on:
|
|
||||||
- web
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
migrations:
|
|
||||||
image: mediacms/mediacms:latest
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_SHORT: 'no'
|
|
||||||
ENABLE_CELERY_LONG: 'no'
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ADMIN_USER: 'admin'
|
|
||||||
ADMIN_EMAIL: 'admin@localhost'
|
|
||||||
# ADMIN_PASSWORD: 'uncomment_and_set_password_here'
|
|
||||||
command: "./deploy/docker/prestart.sh"
|
|
||||||
restart: on-failure
|
|
||||||
depends_on:
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
web:
|
|
||||||
image: mediacms/mediacms:latest
|
|
||||||
deploy:
|
|
||||||
replicas: 1
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ENABLE_CELERY_SHORT: 'no'
|
|
||||||
ENABLE_CELERY_LONG: 'no'
|
|
||||||
ENABLE_MIGRATIONS: 'no'
|
|
||||||
depends_on:
|
|
||||||
- migrations
|
|
||||||
celery_beat:
|
|
||||||
image: mediacms/mediacms:latest
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_SHORT: 'no'
|
|
||||||
ENABLE_CELERY_LONG: 'no'
|
|
||||||
ENABLE_MIGRATIONS: 'no'
|
|
||||||
depends_on:
|
|
||||||
- redis
|
|
||||||
celery_worker:
|
|
||||||
image: mediacms/mediacms:latest
|
|
||||||
deploy:
|
|
||||||
replicas: 1
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
environment:
|
|
||||||
ENABLE_UWSGI: 'no'
|
|
||||||
ENABLE_NGINX: 'no'
|
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
|
||||||
ENABLE_MIGRATIONS: 'no'
|
|
||||||
depends_on:
|
|
||||||
- migrations
|
|
||||||
db:
|
|
||||||
image: postgres:17.2-alpine
|
|
||||||
volumes:
|
|
||||||
- ../postgres_data:/var/lib/postgresql/data/
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: mediacms
|
|
||||||
POSTGRES_PASSWORD: mediacms
|
|
||||||
POSTGRES_DB: mediacms
|
|
||||||
TZ: Europe/London
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
redis:
|
|
||||||
image: "redis:alpine"
|
|
||||||
restart: always
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli","ping"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
@@ -1,37 +1,2 @@
|
|||||||
# Dependencies
|
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
||||||
# Local development files - exclude uploaded content but keep placeholder images
|
|
||||||
media_files/*
|
|
||||||
!media_files/userlogos/
|
|
||||||
media_files/userlogos/*
|
|
||||||
!media_files/userlogos/*.jpg
|
|
||||||
logs
|
|
||||||
static_collected
|
|
||||||
|
|
||||||
# Version control
|
|
||||||
.git
|
|
||||||
.github
|
|
||||||
.gitignore
|
|
||||||
|
|
||||||
# Development/testing
|
|
||||||
.pytest_cache
|
|
||||||
.qodo
|
|
||||||
.claude
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
.dockerignore
|
|
||||||
Dockerfile
|
|
||||||
docker-compose*.yml
|
|
||||||
.docker-backup
|
|
||||||
|
|
||||||
# Documentation (if you don't need it in the image)
|
|
||||||
docs
|
|
||||||
|
|
||||||
# Other
|
|
||||||
*.pyc
|
|
||||||
__pycache__
|
|
||||||
.env
|
|
||||||
.vscode
|
|
||||||
.idea
|
|
||||||
88
.github/workflows/docker-build-push.yml
vendored
88
.github/workflows/docker-build-push.yml
vendored
@@ -21,8 +21,8 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Docker meta for web image
|
- name: Docker meta for base image
|
||||||
id: meta-web
|
id: meta-base
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
@@ -40,95 +40,39 @@ jobs:
|
|||||||
org.opencontainers.image.source=https://github.com/mediacms-io/mediacms
|
org.opencontainers.image.source=https://github.com/mediacms-io/mediacms
|
||||||
org.opencontainers.image.licenses=AGPL-3.0
|
org.opencontainers.image.licenses=AGPL-3.0
|
||||||
|
|
||||||
- name: Build and push web image
|
- name: Docker meta for full image
|
||||||
uses: docker/build-push-action@v4
|
id: meta-full
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
target: web
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.meta-web.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta-web.outputs.labels }}
|
|
||||||
|
|
||||||
- name: Docker meta for worker image
|
|
||||||
id: meta-worker
|
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
mediacms/mediacms-worker
|
mediacms/mediacms
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
|
type=raw,value=full,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=semver,pattern={{major}}
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.title=MediaCMS Worker
|
|
||||||
org.opencontainers.image.description=MediaCMS Celery worker for background task processing.
|
|
||||||
org.opencontainers.image.vendor=MediaCMS
|
|
||||||
org.opencontainers.image.url=https://mediacms.io/
|
|
||||||
org.opencontainers.image.source=https://github.com/mediacms-io/mediacms
|
|
||||||
org.opencontainers.image.licenses=AGPL-3.0
|
|
||||||
|
|
||||||
- name: Build and push worker image
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
target: worker
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.meta-worker.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta-worker.outputs.labels }}
|
|
||||||
|
|
||||||
- name: Docker meta for worker-full image
|
|
||||||
id: meta-worker-full
|
|
||||||
uses: docker/metadata-action@v4
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
mediacms/mediacms-worker
|
|
||||||
tags: |
|
|
||||||
type=raw,value=latest-full,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
|
|
||||||
type=semver,pattern={{version}}-full
|
type=semver,pattern={{version}}-full
|
||||||
type=semver,pattern={{major}}.{{minor}}-full
|
type=semver,pattern={{major}}.{{minor}}-full
|
||||||
type=semver,pattern={{major}}-full
|
type=semver,pattern={{major}}-full
|
||||||
labels: |
|
labels: |
|
||||||
org.opencontainers.image.title=MediaCMS Worker Full
|
org.opencontainers.image.title=MediaCMS Full
|
||||||
org.opencontainers.image.description=MediaCMS Celery worker with additional codecs for advanced transcoding features.
|
org.opencontainers.image.description=MediaCMS is a modern, fully featured open source video and media CMS, written in Python/Django and React, featuring a REST API. This is the full version with additional dependencies.
|
||||||
org.opencontainers.image.vendor=MediaCMS
|
org.opencontainers.image.vendor=MediaCMS
|
||||||
org.opencontainers.image.url=https://mediacms.io/
|
org.opencontainers.image.url=https://mediacms.io/
|
||||||
org.opencontainers.image.source=https://github.com/mediacms-io/mediacms
|
org.opencontainers.image.source=https://github.com/mediacms-io/mediacms
|
||||||
org.opencontainers.image.licenses=AGPL-3.0
|
org.opencontainers.image.licenses=AGPL-3.0
|
||||||
|
|
||||||
- name: Build and push worker-full image
|
- name: Build and push full image
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
target: worker-full
|
target: full
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.meta-worker-full.outputs.tags }}
|
tags: ${{ steps.meta-full.outputs.tags }}
|
||||||
labels: ${{ steps.meta-worker-full.outputs.labels }}
|
labels: ${{ steps.meta-full.outputs.labels }}
|
||||||
|
|
||||||
- name: Docker meta for nginx image
|
- name: Build and push base image
|
||||||
id: meta-nginx
|
|
||||||
uses: docker/metadata-action@v4
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
mediacms/mediacms-nginx
|
|
||||||
tags: |
|
|
||||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=semver,pattern={{major}}
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.title=MediaCMS Nginx
|
|
||||||
org.opencontainers.image.description=Nginx web server for MediaCMS, serving static and media files.
|
|
||||||
org.opencontainers.image.vendor=MediaCMS
|
|
||||||
org.opencontainers.image.url=https://mediacms.io/
|
|
||||||
org.opencontainers.image.source=https://github.com/mediacms-io/mediacms
|
|
||||||
org.opencontainers.image.licenses=AGPL-3.0
|
|
||||||
|
|
||||||
- name: Build and push nginx image
|
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: Dockerfile.nginx
|
target: base
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.meta-nginx.outputs.tags }}
|
tags: ${{ steps.meta-base.outputs.tags }}
|
||||||
labels: ${{ steps.meta-nginx.outputs.labels }}
|
labels: ${{ steps.meta-base.outputs.labels }}
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -17,7 +17,7 @@ static/mptt/
|
|||||||
static/rest_framework/
|
static/rest_framework/
|
||||||
static/drf-yasg
|
static/drf-yasg
|
||||||
cms/local_settings.py
|
cms/local_settings.py
|
||||||
config/local_settings.py
|
deploy/docker/local_settings.py
|
||||||
yt.readme.md
|
yt.readme.md
|
||||||
/frontend-tools/video-editor/node_modules
|
/frontend-tools/video-editor/node_modules
|
||||||
/frontend-tools/video-editor/client/node_modules
|
/frontend-tools/video-editor/client/node_modules
|
||||||
@@ -35,3 +35,4 @@ frontend-tools/video-editor/client/public/videos/sample-video.mp3
|
|||||||
frontend-tools/chapters-editor/client/public/videos/sample-video.mp3
|
frontend-tools/chapters-editor/client/public/videos/sample-video.mp3
|
||||||
static/chapters_editor/videos/sample-video.mp3
|
static/chapters_editor/videos/sample-video.mp3
|
||||||
static/video_editor/videos/sample-video.mp3
|
static/video_editor/videos/sample-video.mp3
|
||||||
|
templates/todo-MS4.md
|
||||||
|
|||||||
@@ -1,254 +0,0 @@
|
|||||||
# MediaCMS Docker Restructure Summary
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This document summarizes the complete Docker architecture restructure for MediaCMS 7.3, eliminating supervisord and implementing modern Docker best practices.
|
|
||||||
|
|
||||||
## What Was Created
|
|
||||||
|
|
||||||
### New Files
|
|
||||||
|
|
||||||
#### Dockerfiles
|
|
||||||
- `Dockerfile` - Multi-stage Dockerfile with targets (replaced old Dockerfile):
|
|
||||||
- `build-image` - FFmpeg and Bento4 builder
|
|
||||||
- `base` - Python/Django base image
|
|
||||||
- `web` - uWSGI web server
|
|
||||||
- `worker` - Celery worker (standard)
|
|
||||||
- `worker-full` - Celery worker with extra codecs
|
|
||||||
|
|
||||||
- `Dockerfile.nginx` - Vanilla nginx with MediaCMS configs baked in
|
|
||||||
|
|
||||||
#### Docker Compose Files
|
|
||||||
- `docker-compose.yaml` - Production deployment (no file mounts) - REPLACED
|
|
||||||
- `docker-compose-cert.yaml` - Production with HTTPS (Let's Encrypt) - REPLACED
|
|
||||||
- `docker-compose-dev.yaml` - Development with file mounts and hot reload - REPLACED
|
|
||||||
|
|
||||||
#### Scripts
|
|
||||||
- `scripts/entrypoint-web.sh` - Web container entrypoint
|
|
||||||
- `scripts/entrypoint-worker.sh` - Worker container entrypoint
|
|
||||||
- `scripts/run-migrations.sh` - Migration runner script
|
|
||||||
|
|
||||||
#### Configuration
|
|
||||||
- `config/nginx/nginx.conf` - Main nginx config (from deploy/docker/)
|
|
||||||
- `config/nginx/site.conf` - Virtual host config (from deploy/docker/nginx_http_only.conf)
|
|
||||||
- `config/nginx/uwsgi_params` - uWSGI params (from deploy/docker/)
|
|
||||||
- `config/nginx-proxy/client_max_body_size.conf` - For nginx-proxy (from deploy/docker/reverse_proxy/)
|
|
||||||
- `config/uwsgi/uwsgi.ini` - uWSGI configuration (from deploy/docker/)
|
|
||||||
- `config/imagemagick/policy.xml` - ImageMagick policy (from deploy/docker/)
|
|
||||||
|
|
||||||
#### Documentation
|
|
||||||
- `docs/DOCKER_V7.3_MIGRATION.md` - Complete migration guide
|
|
||||||
- Updated `docs/admins_docs.md` - Sections 4 and 5
|
|
||||||
|
|
||||||
## Architecture Changes
|
|
||||||
|
|
||||||
### Before (Old Architecture)
|
|
||||||
```
|
|
||||||
Single Container (supervisord managing multiple processes)
|
|
||||||
├── nginx (port 80)
|
|
||||||
├── uwsgi (port 9000)
|
|
||||||
├── celery beat
|
|
||||||
├── celery short workers
|
|
||||||
└── celery long workers
|
|
||||||
|
|
||||||
Controlled by ENABLE_* environment variables
|
|
||||||
```
|
|
||||||
|
|
||||||
### After (New Architecture)
|
|
||||||
```
|
|
||||||
Dedicated Containers (one process per container)
|
|
||||||
├── nginx (port 80) → web:9000
|
|
||||||
├── web (uwsgi on port 9000)
|
|
||||||
├── celery_beat
|
|
||||||
├── celery_short (scalable)
|
|
||||||
├── celery_long (scalable, optional :full image)
|
|
||||||
├── migrations (runs on startup)
|
|
||||||
├── db (PostgreSQL)
|
|
||||||
└── redis
|
|
||||||
|
|
||||||
Volumes:
|
|
||||||
- static_files (nginx ← web)
|
|
||||||
- media_files (nginx ← web, workers)
|
|
||||||
- postgres_data
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Improvements
|
|
||||||
|
|
||||||
### 1. **Removed Components**
|
|
||||||
- ❌ supervisord and all configs in `deploy/docker/supervisord/`
|
|
||||||
- ❌ `deploy/docker/start.sh`
|
|
||||||
- ❌ `deploy/docker/entrypoint.sh`
|
|
||||||
- ❌ All `ENABLE_*` environment variables
|
|
||||||
|
|
||||||
### 2. **Separated Services**
|
|
||||||
- Nginx runs in its own container
|
|
||||||
- Django/uWSGI in dedicated web container
|
|
||||||
- Celery workers split by task duration
|
|
||||||
- Migrations run automatically on every startup
|
|
||||||
|
|
||||||
### 3. **Production Ready**
|
|
||||||
- No file mounts in production (immutable images)
|
|
||||||
- Named volumes for data persistence
|
|
||||||
- Proper health checks
|
|
||||||
- Individual service scaling
|
|
||||||
|
|
||||||
### 4. **Development Friendly**
|
|
||||||
- Separate `-dev` compose file with file mounts
|
|
||||||
- Django debug mode
|
|
||||||
- Frontend hot reload
|
|
||||||
- Live code editing
|
|
||||||
|
|
||||||
## Images to Build
|
|
||||||
|
|
||||||
For production, these images need to be built and pushed to Docker Hub:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build base and web image
|
|
||||||
docker build --target web -t mediacms/mediacms:7.3 .
|
|
||||||
|
|
||||||
# Build worker image
|
|
||||||
docker build --target worker -t mediacms/mediacms-worker:7.3 .
|
|
||||||
|
|
||||||
# Build worker-full image
|
|
||||||
docker build --target worker-full -t mediacms/mediacms-worker:7.3-full .
|
|
||||||
|
|
||||||
# Build nginx image
|
|
||||||
docker build -f Dockerfile.nginx -t mediacms/mediacms-nginx:7.3 .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deployment Options
|
|
||||||
|
|
||||||
### 1. Development
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose-dev.yaml up
|
|
||||||
```
|
|
||||||
- File mounts for live editing
|
|
||||||
- Django runserver
|
|
||||||
- Frontend dev server
|
|
||||||
|
|
||||||
### 2. Production (HTTP)
|
|
||||||
```bash
|
|
||||||
# Rename .new files first
|
|
||||||
mv docker-compose.yaml.new docker-compose.yaml
|
|
||||||
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
- Immutable images
|
|
||||||
- No file mounts
|
|
||||||
- Port 80
|
|
||||||
|
|
||||||
### 3. Production (HTTPS)
|
|
||||||
```bash
|
|
||||||
# Rename .new files first
|
|
||||||
mv docker-compose-cert.yaml.new docker-compose-cert.yaml
|
|
||||||
|
|
||||||
# Edit and set your domain/email
|
|
||||||
docker compose -f docker-compose-cert.yaml up -d
|
|
||||||
```
|
|
||||||
- Automatic Let's Encrypt certificates
|
|
||||||
- Auto-renewal
|
|
||||||
|
|
||||||
## Migration Path for Existing Systems
|
|
||||||
|
|
||||||
### For Production Systems Currently Running
|
|
||||||
|
|
||||||
1. **Backup first**
|
|
||||||
```bash
|
|
||||||
docker exec <db_container> pg_dump -U mediacms mediacms > backup.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Update compose file**
|
|
||||||
- Replace old docker-compose files with new ones
|
|
||||||
- Update domain settings in cert file if using HTTPS
|
|
||||||
|
|
||||||
3. **Pull new images**
|
|
||||||
```bash
|
|
||||||
docker pull mediacms/mediacms:7.3
|
|
||||||
docker pull mediacms/mediacms-worker:7.3
|
|
||||||
docker pull mediacms/mediacms-nginx:7.3
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Restart**
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
1. **No more ENABLE_* variables** - Remove from any custom configs
|
|
||||||
2. **deploy/docker/local_settings.py** - Now use environment variables or custom image
|
|
||||||
3. **Service names changed**:
|
|
||||||
- `celery_worker` → `celery_short` + `celery_long`
|
|
||||||
- Added `nginx` service
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
Before deploying to production, test:
|
|
||||||
|
|
||||||
- [ ] Migrations run successfully
|
|
||||||
- [ ] Static files served correctly
|
|
||||||
- [ ] Media files served correctly
|
|
||||||
- [ ] Django admin accessible
|
|
||||||
- [ ] Video upload works
|
|
||||||
- [ ] Video transcoding works (celery_long)
|
|
||||||
- [ ] Thumbnail generation works (celery_short)
|
|
||||||
- [ ] HTTPS redirects work (if using cert file)
|
|
||||||
- [ ] Database persistence across restarts
|
|
||||||
- [ ] Media files persistence across restarts
|
|
||||||
|
|
||||||
## Configuration Examples
|
|
||||||
|
|
||||||
### Use Full Worker Image
|
|
||||||
```yaml
|
|
||||||
celery_long:
|
|
||||||
image: mediacms/mediacms-worker:7.3-full
|
|
||||||
```
|
|
||||||
|
|
||||||
### Set Custom Domain
|
|
||||||
```yaml
|
|
||||||
environment:
|
|
||||||
FRONTEND_HOST: 'https://videos.example.com'
|
|
||||||
PORTAL_NAME: 'My Video Portal'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scale Workers
|
|
||||||
```bash
|
|
||||||
docker compose up -d --scale celery_short=3 --scale celery_long=2
|
|
||||||
```
|
|
||||||
|
|
||||||
## Files to Review Before Finalizing
|
|
||||||
|
|
||||||
1. **Dockerfile** - Review Python/Django/uWSGI configuration
|
|
||||||
2. **config/nginx/site.conf** - Review nginx paths and proxy settings
|
|
||||||
3. **docker-compose.yaml** - Review volume mounts and service dependencies
|
|
||||||
4. **scripts/run-migrations.sh** - Review migration logic
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
To finalize this restructure:
|
|
||||||
|
|
||||||
1. **Test locally** with docker-compose-dev.yaml
|
|
||||||
2. **Build images** and push to Docker Hub
|
|
||||||
3. **Update CI/CD** to build new images
|
|
||||||
4. **Test in staging environment**
|
|
||||||
5. **Create release notes** referencing migration guide
|
|
||||||
|
|
||||||
## Backup
|
|
||||||
|
|
||||||
Old Docker files have been backed up to `.docker-backup/` directory.
|
|
||||||
|
|
||||||
## Rollback Plan
|
|
||||||
|
|
||||||
If issues arise, rollback by:
|
|
||||||
1. Reverting to old docker-compose files
|
|
||||||
2. Using old image tags
|
|
||||||
3. Restoring database from backup if needed
|
|
||||||
|
|
||||||
Old files are preserved in `.docker-backup/` directory.
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
- Migration Guide: `docs/DOCKER_V7.3_MIGRATION.md`
|
|
||||||
- Admin Docs: `docs/admins_docs.md` (updated sections 4, 5)
|
|
||||||
- Issues: https://github.com/mediacms-io/mediacms/issues
|
|
||||||
79
Dockerfile
79
Dockerfile
@@ -26,22 +26,20 @@ RUN mkdir -p /home/mediacms.io/bento4 && \
|
|||||||
############ BASE RUNTIME IMAGE ############
|
############ BASE RUNTIME IMAGE ############
|
||||||
FROM python:3.13.5-slim-bookworm AS base
|
FROM python:3.13.5-slim-bookworm AS base
|
||||||
|
|
||||||
LABEL org.opencontainers.image.version="7.3"
|
|
||||||
LABEL org.opencontainers.image.title="MediaCMS"
|
|
||||||
LABEL org.opencontainers.image.description="Modern, scalable and open source video platform"
|
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-c"]
|
SHELL ["/bin/bash", "-c"]
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1 \
|
ENV PYTHONUNBUFFERED=1
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
CELERY_APP='cms' \
|
ENV CELERY_APP='cms'
|
||||||
VIRTUAL_ENV=/home/mediacms.io \
|
ENV VIRTUAL_ENV=/home/mediacms.io
|
||||||
PATH="$VIRTUAL_ENV/bin:$PATH"
|
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||||
|
|
||||||
# Install system dependencies (no nginx, no supervisor)
|
# Install system dependencies first
|
||||||
RUN apt-get update -y && \
|
RUN apt-get update -y && \
|
||||||
apt-get -y upgrade && \
|
apt-get -y upgrade && \
|
||||||
apt-get install --no-install-recommends -y \
|
apt-get install --no-install-recommends -y \
|
||||||
|
supervisor \
|
||||||
|
nginx \
|
||||||
imagemagick \
|
imagemagick \
|
||||||
procps \
|
procps \
|
||||||
build-essential \
|
build-essential \
|
||||||
@@ -55,8 +53,8 @@ RUN apt-get update -y && \
|
|||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Set up virtualenv
|
# Set up virtualenv first
|
||||||
RUN mkdir -p /home/mediacms.io/mediacms/{logs,media_files,static_files} && \
|
RUN mkdir -p /home/mediacms.io/mediacms/{logs} && \
|
||||||
cd /home/mediacms.io && \
|
cd /home/mediacms.io && \
|
||||||
python3 -m venv $VIRTUAL_ENV
|
python3 -m venv $VIRTUAL_ENV
|
||||||
|
|
||||||
@@ -84,51 +82,32 @@ COPY --from=build-image /usr/local/bin/ffprobe /usr/local/bin/ffprobe
|
|||||||
COPY --from=build-image /usr/local/bin/qt-faststart /usr/local/bin/qt-faststart
|
COPY --from=build-image /usr/local/bin/qt-faststart /usr/local/bin/qt-faststart
|
||||||
COPY --from=build-image /home/mediacms.io/bento4 /home/mediacms.io/bento4
|
COPY --from=build-image /home/mediacms.io/bento4 /home/mediacms.io/bento4
|
||||||
|
|
||||||
# Copy application files with correct ownership
|
# Copy application files
|
||||||
COPY --chown=www-data:www-data . /home/mediacms.io/mediacms
|
COPY . /home/mediacms.io/mediacms
|
||||||
WORKDIR /home/mediacms.io/mediacms
|
WORKDIR /home/mediacms.io/mediacms
|
||||||
|
|
||||||
# Copy imagemagick policy for sprite thumbnail generation
|
# required for sprite thumbnail generation for large video files
|
||||||
COPY config/imagemagick/policy.xml /etc/ImageMagick-6/policy.xml
|
COPY deploy/docker/policy.xml /etc/ImageMagick-6/policy.xml
|
||||||
|
|
||||||
# Copy local_settings.py from config to cms/ for default Docker config (if exists)
|
# Set process control environment variables
|
||||||
RUN cp config/local_settings.py cms/local_settings.py 2>/dev/null || true
|
ENV ENABLE_UWSGI='yes' \
|
||||||
|
ENABLE_NGINX='yes' \
|
||||||
|
ENABLE_CELERY_BEAT='yes' \
|
||||||
|
ENABLE_CELERY_SHORT='yes' \
|
||||||
|
ENABLE_CELERY_LONG='yes' \
|
||||||
|
ENABLE_MIGRATIONS='yes'
|
||||||
|
|
||||||
# Create www-data user directories and set permissions
|
EXPOSE 9000 80
|
||||||
RUN mkdir -p /var/run/mediacms && \
|
|
||||||
chown www-data:www-data /var/run/mediacms
|
|
||||||
|
|
||||||
############ WEB IMAGE (Django/uWSGI) ############
|
RUN chmod +x ./deploy/docker/entrypoint.sh
|
||||||
FROM base AS web
|
|
||||||
|
|
||||||
# Install uWSGI
|
ENTRYPOINT ["./deploy/docker/entrypoint.sh"]
|
||||||
RUN uv pip install uwsgi
|
CMD ["./deploy/docker/start.sh"]
|
||||||
|
|
||||||
# Copy uWSGI configuration
|
|
||||||
COPY config/uwsgi/uwsgi.ini /home/mediacms.io/mediacms/uwsgi.ini
|
|
||||||
|
|
||||||
USER www-data
|
|
||||||
|
|
||||||
EXPOSE 9000
|
|
||||||
|
|
||||||
CMD ["/home/mediacms.io/bin/uwsgi", "--ini", "/home/mediacms.io/mediacms/uwsgi.ini"]
|
|
||||||
|
|
||||||
############ WORKER IMAGE (Celery) ############
|
|
||||||
FROM base AS worker
|
|
||||||
|
|
||||||
USER www-data
|
|
||||||
|
|
||||||
# CMD will be overridden in docker-compose for different worker types
|
|
||||||
|
|
||||||
############ FULL WORKER IMAGE (Celery with extra codecs) ############
|
|
||||||
FROM worker AS worker-full
|
|
||||||
|
|
||||||
USER root
|
|
||||||
|
|
||||||
|
############ FULL IMAGE ############
|
||||||
|
FROM base AS full
|
||||||
COPY requirements-full.txt ./
|
COPY requirements-full.txt ./
|
||||||
RUN mkdir -p /root/.cache/ && \
|
RUN mkdir -p /root/.cache/ && \
|
||||||
chmod go+rwx /root/ && \
|
chmod go+rwx /root/ && \
|
||||||
chmod go+rwx /root/.cache/ && \
|
chmod go+rwx /root/.cache/
|
||||||
uv pip install -r requirements-full.txt
|
RUN uv pip install -r requirements-full.txt
|
||||||
|
|
||||||
USER www-data
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
FROM nginx:alpine
|
|
||||||
|
|
||||||
LABEL org.opencontainers.image.version="7.3"
|
|
||||||
LABEL org.opencontainers.image.title="MediaCMS Nginx"
|
|
||||||
LABEL org.opencontainers.image.description="Nginx server for MediaCMS"
|
|
||||||
|
|
||||||
# Copy nginx configurations
|
|
||||||
COPY config/nginx/nginx.conf /etc/nginx/nginx.conf
|
|
||||||
COPY config/nginx/site.conf /etc/nginx/conf.d/default.conf
|
|
||||||
COPY config/nginx/uwsgi_params /etc/nginx/uwsgi_params
|
|
||||||
|
|
||||||
# Create directories for static and media files (will be volumes)
|
|
||||||
RUN mkdir -p /var/www/media /var/www/static && \
|
|
||||||
chown -R nginx:nginx /var/www
|
|
||||||
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
@@ -69,7 +69,7 @@ Copyright Markos Gogoulos.
|
|||||||
|
|
||||||
## Support and paid services
|
## Support and paid services
|
||||||
|
|
||||||
We provide custom installations, development of extra functionality, migration from existing systems, integrations with legacy systems, training and support. Contact us at info@mediacms.io for more information.
|
We provide custom installations, development of extra functionality, migration from existing systems, integrations with legacy systems, training and support. Checkout our [services page](https://mediacms.io/#services/) for more information.
|
||||||
|
|
||||||
### Commercial Hostings
|
### Commercial Hostings
|
||||||
**Elestio**
|
**Elestio**
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
VERSION = "7.2.1"
|
VERSION = "7.3.0"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# MediaCMS: Document Changes for DEIC
|
# MediaCMS: Document Changes for DEIC
|
||||||
|
|
||||||
## Configuration Changes
|
## Configuration Changes
|
||||||
The following changes are required in `config/local_settings.py`:
|
The following changes are required in `deploy/docker/local_settings.py`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
||||||
|
|||||||
3
deploy/docker/README.md
Normal file
3
deploy/docker/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# MediaCMS on Docker
|
||||||
|
|
||||||
|
See: [Details](../../docs/Docker_deployment.md)
|
||||||
38
deploy/docker/entrypoint.sh
Executable file
38
deploy/docker/entrypoint.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# forward request and error logs to docker log collector
|
||||||
|
ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log && \
|
||||||
|
ln -sf /dev/stdout /var/log/nginx/mediacms.io.access.log && ln -sf /dev/stderr /var/log/nginx/mediacms.io.error.log
|
||||||
|
|
||||||
|
cp /home/mediacms.io/mediacms/deploy/docker/local_settings.py /home/mediacms.io/mediacms/cms/local_settings.py
|
||||||
|
|
||||||
|
|
||||||
|
mkdir -p /home/mediacms.io/mediacms/{logs,media_files/hls}
|
||||||
|
touch /home/mediacms.io/mediacms/logs/debug.log
|
||||||
|
|
||||||
|
mkdir -p /var/run/mediacms
|
||||||
|
chown www-data:www-data /var/run/mediacms
|
||||||
|
|
||||||
|
TARGET_GID=$(stat -c "%g" /home/mediacms.io/mediacms/)
|
||||||
|
|
||||||
|
EXISTS=$(cat /etc/group | grep $TARGET_GID | wc -l)
|
||||||
|
|
||||||
|
# Create new group using target GID and add www-data user
|
||||||
|
if [ $EXISTS == "0" ]; then
|
||||||
|
groupadd -g $TARGET_GID tempgroup
|
||||||
|
usermod -a -G tempgroup www-data
|
||||||
|
else
|
||||||
|
# GID exists, find group name and add
|
||||||
|
GROUP=$(getent group $TARGET_GID | cut -d: -f1)
|
||||||
|
usermod -a -G $GROUP www-data
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We should do this only for folders that have a different owner, since it is an expensive operation
|
||||||
|
# Also ignoring .git folder to fix this issue https://github.com/mediacms-io/mediacms/issues/934
|
||||||
|
# Exclude package-lock.json files that may not exist or be removed during frontend setup
|
||||||
|
find /home/mediacms.io/mediacms ! \( -path "*.git*" -o -name "package-lock.json" \) -exec chown www-data:$TARGET_GID {} + 2>/dev/null || true
|
||||||
|
|
||||||
|
chmod +x /home/mediacms.io/mediacms/deploy/docker/start.sh /home/mediacms.io/mediacms/deploy/docker/prestart.sh
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
36
deploy/docker/local_settings.py
Normal file
36
deploy/docker/local_settings.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
FRONTEND_HOST = os.getenv('FRONTEND_HOST', 'http://localhost')
|
||||||
|
PORTAL_NAME = os.getenv('PORTAL_NAME', 'MediaCMS')
|
||||||
|
SECRET_KEY = os.getenv('SECRET_KEY', 'ma!s3^b-cw!f#7s6s0m3*jx77a@riw(7701**(r=ww%w!2+yk2')
|
||||||
|
REDIS_LOCATION = os.getenv('REDIS_LOCATION', 'redis://redis:6379/1')
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": os.getenv('POSTGRES_NAME', 'mediacms'),
|
||||||
|
"HOST": os.getenv('POSTGRES_HOST', 'db'),
|
||||||
|
"PORT": os.getenv('POSTGRES_PORT', '5432'),
|
||||||
|
"USER": os.getenv('POSTGRES_USER', 'mediacms'),
|
||||||
|
"PASSWORD": os.getenv('POSTGRES_PASSWORD', 'mediacms'),
|
||||||
|
"OPTIONS": {'pool': True},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CACHES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
|
"LOCATION": REDIS_LOCATION,
|
||||||
|
"OPTIONS": {
|
||||||
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# CELERY STUFF
|
||||||
|
BROKER_URL = REDIS_LOCATION
|
||||||
|
CELERY_RESULT_BACKEND = BROKER_URL
|
||||||
|
|
||||||
|
MP4HLS_COMMAND = "/home/mediacms.io/bento4/bin/mp4hls"
|
||||||
|
|
||||||
|
DEBUG = os.getenv('DEBUG', 'False') == 'True'
|
||||||
@@ -23,8 +23,8 @@ http {
|
|||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
|
||||||
ssl_prefer_server_ciphers on;
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
access_log /var/log/mediacms/nginx-main.access.log;
|
access_log /var/log/nginx/access.log;
|
||||||
error_log /var/log/mediacms/nginx-main.error.log;
|
error_log /var/log/nginx/error.log;
|
||||||
|
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_disable "msie6";
|
gzip_disable "msie6";
|
||||||
@@ -2,20 +2,20 @@ server {
|
|||||||
listen 80 ;
|
listen 80 ;
|
||||||
|
|
||||||
gzip on;
|
gzip on;
|
||||||
access_log /var/log/mediacms/nginx.access.log;
|
access_log /var/log/nginx/mediacms.io.access.log;
|
||||||
|
|
||||||
error_log /var/log/mediacms/nginx.error.log warn;
|
error_log /var/log/nginx/mediacms.io.error.log warn;
|
||||||
|
|
||||||
location /static {
|
location /static {
|
||||||
alias /var/www/static ;
|
alias /home/mediacms.io/mediacms/static ;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /media/original {
|
location /media/original {
|
||||||
alias /var/www/media/original;
|
alias /home/mediacms.io/mediacms/media_files/original;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /media {
|
location /media {
|
||||||
alias /var/www/media ;
|
alias /home/mediacms.io/mediacms/media_files ;
|
||||||
add_header 'Access-Control-Allow-Origin' '*';
|
add_header 'Access-Control-Allow-Origin' '*';
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
||||||
@@ -28,7 +28,7 @@ server {
|
|||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
||||||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
|
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
|
||||||
|
|
||||||
include /etc/nginx/uwsgi_params;
|
include /etc/nginx/sites-enabled/uwsgi_params;
|
||||||
uwsgi_pass web:9000;
|
uwsgi_pass 127.0.0.1:9000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
71
deploy/docker/prestart.sh
Executable file
71
deploy/docker/prestart.sh
Executable file
@@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
RANDOM_ADMIN_PASS=`python -c "import secrets;chars = 'abcdefghijklmnopqrstuvwxyz0123456789';print(''.join(secrets.choice(chars) for i in range(10)))"`
|
||||||
|
ADMIN_PASSWORD=${ADMIN_PASSWORD:-$RANDOM_ADMIN_PASS}
|
||||||
|
|
||||||
|
if [ X"$ENABLE_MIGRATIONS" = X"yes" ]; then
|
||||||
|
echo "Running migrations service"
|
||||||
|
python manage.py migrate
|
||||||
|
EXISTING_INSTALLATION=`echo "from users.models import User; print(User.objects.exists())" |python manage.py shell`
|
||||||
|
if [ "$EXISTING_INSTALLATION" = "True" ]; then
|
||||||
|
echo "Loaddata has already run"
|
||||||
|
else
|
||||||
|
echo "Running loaddata and creating admin user"
|
||||||
|
python manage.py loaddata fixtures/encoding_profiles.json
|
||||||
|
python manage.py loaddata fixtures/categories.json
|
||||||
|
|
||||||
|
# post_save, needs redis to succeed (ie. migrate depends on redis)
|
||||||
|
DJANGO_SUPERUSER_PASSWORD=$ADMIN_PASSWORD python manage.py createsuperuser \
|
||||||
|
--no-input \
|
||||||
|
--username=$ADMIN_USER \
|
||||||
|
--email=$ADMIN_EMAIL \
|
||||||
|
--database=default || true
|
||||||
|
echo "Created admin user with password: $ADMIN_PASSWORD"
|
||||||
|
|
||||||
|
fi
|
||||||
|
echo "RUNNING COLLECTSTATIC"
|
||||||
|
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
# echo "Updating hostname ..."
|
||||||
|
# TODO: Get the FRONTEND_HOST from cms/local_settings.py
|
||||||
|
# echo "from django.contrib.sites.models import Site; Site.objects.update(name='$FRONTEND_HOST', domain='$FRONTEND_HOST')" | python manage.py shell
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setting up internal nginx server
|
||||||
|
# HTTPS setup is delegated to a reverse proxy running infront of the application
|
||||||
|
|
||||||
|
cp deploy/docker/nginx_http_only.conf /etc/nginx/sites-available/default
|
||||||
|
cp deploy/docker/nginx_http_only.conf /etc/nginx/sites-enabled/default
|
||||||
|
cp deploy/docker/uwsgi_params /etc/nginx/sites-enabled/uwsgi_params
|
||||||
|
cp deploy/docker/nginx.conf /etc/nginx/
|
||||||
|
|
||||||
|
#### Supervisord Configurations #####
|
||||||
|
|
||||||
|
cp deploy/docker/supervisord/supervisord-debian.conf /etc/supervisor/conf.d/supervisord-debian.conf
|
||||||
|
|
||||||
|
if [ X"$ENABLE_UWSGI" = X"yes" ] ; then
|
||||||
|
echo "Enabling uwsgi app server"
|
||||||
|
cp deploy/docker/supervisord/supervisord-uwsgi.conf /etc/supervisor/conf.d/supervisord-uwsgi.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ X"$ENABLE_NGINX" = X"yes" ] ; then
|
||||||
|
echo "Enabling nginx as uwsgi app proxy and media server"
|
||||||
|
cp deploy/docker/supervisord/supervisord-nginx.conf /etc/supervisor/conf.d/supervisord-nginx.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ X"$ENABLE_CELERY_BEAT" = X"yes" ] ; then
|
||||||
|
echo "Enabling celery-beat scheduling server"
|
||||||
|
cp deploy/docker/supervisord/supervisord-celery_beat.conf /etc/supervisor/conf.d/supervisord-celery_beat.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ X"$ENABLE_CELERY_SHORT" = X"yes" ] ; then
|
||||||
|
echo "Enabling celery-short task worker"
|
||||||
|
cp deploy/docker/supervisord/supervisord-celery_short.conf /etc/supervisor/conf.d/supervisord-celery_short.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ X"$ENABLE_CELERY_LONG" = X"yes" ] ; then
|
||||||
|
echo "Enabling celery-long task worker"
|
||||||
|
cp deploy/docker/supervisord/supervisord-celery_long.conf /etc/supervisor/conf.d/supervisord-celery_long.conf
|
||||||
|
rm /var/run/mediacms/* -f # remove any stale id, so that on forced restarts of celery workers there are no stale processes that prevent new ones
|
||||||
|
fi
|
||||||
17
deploy/docker/reverse_proxy/certs/localhost.crt
Normal file
17
deploy/docker/reverse_proxy/certs/localhost.crt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICwzCCAaugAwIBAgIJAOyvdwguJQd+MA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
|
||||||
|
BAMTCWxvY2FsaG9zdDAeFw0yMTAxMjQxMjUwMzFaFw0zMTAxMjIxMjUwMzFaMBQx
|
||||||
|
EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAONswEwBzkgoO+lkewiKUnwvYqC54qleCUg9hidqjoyzd5XWKh1mIF7aaSCG
|
||||||
|
rJGSxCce8CbqAqGkpvsgXzwwbY72l7FwmAXFHO5ObQfpmFhjt2fsKRM9MTCo/UyU
|
||||||
|
liuhgP+Q+BNzUontTUC40NVHs8R7IHG4z8unB7qB/7zGK2tfilLB8JDqPTkc22vN
|
||||||
|
C4P1YxiGyY5bm37wQrroC9zPJ8bqanrF9Y90QJHubibnPWqnZvK2HkDWjp5LYkn8
|
||||||
|
IuzBycs1cLd8eMjU9aT72kweykvnGDDc3YbXFzT2zBTGSFEBROsVdPrNF9PaeE3j
|
||||||
|
pu4UZ8Ge3Fp3VYd+04DnWtbQq0MCAwEAAaMYMBYwFAYDVR0RBA0wC4IJbG9jYWxo
|
||||||
|
b3N0MA0GCSqGSIb3DQEBBQUAA4IBAQAdm2aGn4evosbdWgBHgzr6oYWBIiPpf1SA
|
||||||
|
GXizuf5OaMActFP0rZ0mogndLH5d51J2qqSfOtaWSA5qwlPvDSTn1nvJeHoVLfZf
|
||||||
|
kQHaB7/DaOPGsZCQBELPhYHwl7+Ej3HYE+siiaRfjC2NVgf8P/pAsTlKbe2e+34l
|
||||||
|
GwWSFol24w5xAmUezCF41JiZbqHoZhSh7s/PuJnK2RvhpjkrIot8GvxnbvOcKDIv
|
||||||
|
JzEKo3qPq8pc5RBkpP7Kp2+EgAYn1xAn0CekxZracW/MY+tg2mCeFucZW2V1iwVs
|
||||||
|
LpAw6GJnjYz5mbrQskPbrJ9t78JGUKQ0kL/VUTfryUHMHYCiJlvd
|
||||||
|
-----END CERTIFICATE-----
|
||||||
27
deploy/docker/reverse_proxy/certs/localhost.key
Normal file
27
deploy/docker/reverse_proxy/certs/localhost.key
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEA42zATAHOSCg76WR7CIpSfC9ioLniqV4JSD2GJ2qOjLN3ldYq
|
||||||
|
HWYgXtppIIaskZLEJx7wJuoCoaSm+yBfPDBtjvaXsXCYBcUc7k5tB+mYWGO3Z+wp
|
||||||
|
Ez0xMKj9TJSWK6GA/5D4E3NSie1NQLjQ1UezxHsgcbjPy6cHuoH/vMYra1+KUsHw
|
||||||
|
kOo9ORzba80Lg/VjGIbJjlubfvBCuugL3M8nxupqesX1j3RAke5uJuc9aqdm8rYe
|
||||||
|
QNaOnktiSfwi7MHJyzVwt3x4yNT1pPvaTB7KS+cYMNzdhtcXNPbMFMZIUQFE6xV0
|
||||||
|
+s0X09p4TeOm7hRnwZ7cWndVh37TgOda1tCrQwIDAQABAoIBAQCmKKyOW7tlCNBN
|
||||||
|
AzbI1JbTWKOMnoM2DxhlCV5cqgOgVPcIKEL428bGxniMZRjr+vkJRBddtxdZFj1R
|
||||||
|
uSMbjJ5fF1dZMtQ/UvaCPhZ283p1CdXUPbz863ZnAPCf5Oea1RK0piw5ucYSM6h/
|
||||||
|
owgg65Qx92uK6uYW+uAwqg440+ihNvnaZoVTx5CjZbL9KISkrlNJnuYiB5vzOD0i
|
||||||
|
UVklO5Qz8VCuOcOVGZCA2SxHm4HAbg/aiQnpaUa9de4TsZ4ygF66pZh77T0wNOos
|
||||||
|
sS1riKtHQpX+osJyoTI/rIKFAhycsZ+AA7Qpu6GW4xQlNS6K8vRiIbktwkC+IT0O
|
||||||
|
RSn8Dg7BAoGBAPe5R8SpgXx9jKdA1eFa/Vjx5bmB96r2MviIOIWF8rs2K33xe+rj
|
||||||
|
v+BZ2ZjdpVjcm2nRMf9r/eDq2ScNFWmKoZsUmdyT84Qq9yLcTSUdno+zCy+L0LNH
|
||||||
|
DqJq5jIxJaV7amHeR/w10BVuiDmzhSsTmhfnXTUGRO/h2PjRyC3yEYdxAoGBAOsF
|
||||||
|
2+gTsdOGlq6AVzW5MLZkreq8WCU2wWpZRiCPh6HJa8htuynYxO5AWUiNUbYKddj2
|
||||||
|
0za9DFiXgH+Oo8wrkTYLEdN0T5/o+ScL5t3VG3m9R6pnuudLC2vmGQP0hNuZUpnF
|
||||||
|
7FzdJ85h6taR2bM1zFzOfl81K0BhTHGxTU2r70vzAoGAVXuLJ3LyqtnMKn72DzDN
|
||||||
|
0d6PTkdqBoW0qwyerHy/eRjFQ02MXE7BDJMUwmphv1tJCefVX/WNAwsnahFavTPI
|
||||||
|
dnJSccpgMtB8vXvV5yPkbmPzTTHrD6JKi4Nl8hYBjqwa1rDUmFSdfHfK7FZlcqrt
|
||||||
|
9qexAzYpnbmKnLoPYMNyhxECgYEAm5OCUeuPoL2MS7GLiXWwyFx3QFczZlcLzBGS
|
||||||
|
uYUpvLBwF/qDlhz3p9uS/tMFzyK3hktF4Ate+9o2ZroOtd31PzgusbJh7zIylGVt
|
||||||
|
i1VB3eGtaiFGeUuVIPTthE++Dvw80KxTXdnMOvNYmHduDBLF2H2c6/tvSSvfhbdf
|
||||||
|
u9XgD38CgYAiLcVySxMKNpsXatuC31wjT+rnaH22SD/7pXe2q6MRW/s+bGOspu0v
|
||||||
|
NeJSLoM98v8F99q0W0lgqesYJVI20Frru0DfXIp60ryaDolzve3Iwk8SOJUlcnUG
|
||||||
|
cCtmPUkjyr18QAlrcCB4PozJGjpPWyabaY8gGwo8wAEpJWHrIJlHew==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
17
deploy/docker/start.sh
Executable file
17
deploy/docker/start.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#! /usr/bin/env sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# If there's a prestart.sh script in the /app directory, run it before starting
|
||||||
|
PRE_START_PATH=deploy/docker/prestart.sh
|
||||||
|
echo "Checking for script in $PRE_START_PATH"
|
||||||
|
if [ -f $PRE_START_PATH ] ; then
|
||||||
|
echo "Running script $PRE_START_PATH"
|
||||||
|
. $PRE_START_PATH
|
||||||
|
else
|
||||||
|
echo "There is no script $PRE_START_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start Supervisor, with Nginx and uWSGI
|
||||||
|
echo "Starting server using supervisord..."
|
||||||
|
|
||||||
|
exec /usr/bin/supervisord
|
||||||
12
deploy/docker/supervisord/supervisord-celery_beat.conf
Normal file
12
deploy/docker/supervisord/supervisord-celery_beat.conf
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[program:celery_beat]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
startsecs=0
|
||||||
|
numprocs=1
|
||||||
|
user=www-data
|
||||||
|
directory=/home/mediacms.io/mediacms
|
||||||
|
priority=300
|
||||||
|
startinorder=true
|
||||||
|
command=/home/mediacms.io/bin/celery beat --pidfile=/var/run/mediacms/beat%%n.pid --loglevel=INFO --logfile=/home/mediacms.io/mediacms/logs/celery_beat.log
|
||||||
13
deploy/docker/supervisord/supervisord-celery_long.conf
Normal file
13
deploy/docker/supervisord/supervisord-celery_long.conf
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[program:celery_long]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
startsecs=10
|
||||||
|
numprocs=1
|
||||||
|
user=www-data
|
||||||
|
directory=/home/mediacms.io/mediacms
|
||||||
|
priority=500
|
||||||
|
startinorder=true
|
||||||
|
startsecs=0
|
||||||
|
command=/home/mediacms.io/bin/celery multi start long1 --pidfile=/var/run/mediacms/%%n.pid --loglevel=INFO --logfile=/home/mediacms.io/mediacms/logs/celery_long.log -Ofair --prefetch-multiplier=1 -Q long_tasks
|
||||||
12
deploy/docker/supervisord/supervisord-celery_short.conf
Normal file
12
deploy/docker/supervisord/supervisord-celery_short.conf
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[program:celery_short]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
startsecs=0
|
||||||
|
numprocs=1
|
||||||
|
user=www-data
|
||||||
|
directory=/home/mediacms.io/mediacms
|
||||||
|
priority=400
|
||||||
|
startinorder=true
|
||||||
|
command=/home/mediacms.io/bin/celery multi start short1 short2 --pidfile=/var/run/mediacms/%%n.pid --loglevel=INFO --logfile=/home/mediacms.io/mediacms/logs/celery_short.log --soft-time-limit=300 -c10 -Q short_tasks
|
||||||
2
deploy/docker/supervisord/supervisord-debian.conf
Normal file
2
deploy/docker/supervisord/supervisord-debian.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
11
deploy/docker/supervisord/supervisord-nginx.conf
Normal file
11
deploy/docker/supervisord/supervisord-nginx.conf
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[program:nginx]
|
||||||
|
command=/usr/sbin/nginx -g 'daemon off;'
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=200
|
||||||
|
startinorder=true
|
||||||
|
startsecs=0
|
||||||
|
# Graceful stop, see http://nginx.org/en/docs/control.html
|
||||||
|
stopsignal=QUIT
|
||||||
9
deploy/docker/supervisord/supervisord-uwsgi.conf
Normal file
9
deploy/docker/supervisord/supervisord-uwsgi.conf
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[program:uwsgi]
|
||||||
|
command=/home/mediacms.io/bin/uwsgi --ini /home/mediacms.io/mediacms/deploy/docker/uwsgi.ini
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=100
|
||||||
|
startinorder=true
|
||||||
|
startsecs=0
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
version: "3.8"
|
|
||||||
|
|
||||||
# Production setup with automatic HTTPS via Let's Encrypt
|
|
||||||
# Uses https://github.com/nginx-proxy/acme-companion
|
|
||||||
|
|
||||||
services:
|
|
||||||
nginx-proxy:
|
|
||||||
image: nginxproxy/nginx-proxy
|
|
||||||
container_name: nginx-proxy
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- conf:/etc/nginx/conf.d
|
|
||||||
- vhost:/etc/nginx/vhost.d
|
|
||||||
- html:/usr/share/nginx/html
|
|
||||||
- dhparam:/etc/nginx/dhparam
|
|
||||||
- certs:/etc/nginx/certs:ro
|
|
||||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
|
||||||
- ./config/nginx-proxy/client_max_body_size.conf:/etc/nginx/conf.d/client_max_body_size.conf:ro
|
|
||||||
|
|
||||||
acme-companion:
|
|
||||||
image: nginxproxy/acme-companion
|
|
||||||
container_name: nginx-proxy-acme
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes_from:
|
|
||||||
- nginx-proxy
|
|
||||||
volumes:
|
|
||||||
- certs:/etc/nginx/certs:rw
|
|
||||||
- acme:/etc/acme.sh
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
|
|
||||||
migrations:
|
|
||||||
image: mediacms/mediacms:7.3
|
|
||||||
command: ["/bin/bash", "/home/mediacms.io/mediacms/scripts/run-migrations.sh"]
|
|
||||||
environment:
|
|
||||||
ADMIN_USER: 'admin'
|
|
||||||
ADMIN_EMAIL: 'admin@localhost'
|
|
||||||
# ADMIN_PASSWORD: 'uncomment_and_set_password_here'
|
|
||||||
restart: "no"
|
|
||||||
depends_on:
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- static_files:/home/mediacms.io/mediacms/static_files
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
web:
|
|
||||||
image: mediacms/mediacms:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
expose:
|
|
||||||
- "9000"
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- static_files:/home/mediacms.io/mediacms/static_files
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
nginx:
|
|
||||||
image: mediacms/mediacms-nginx:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
expose:
|
|
||||||
- "80"
|
|
||||||
environment:
|
|
||||||
# These are required for nginx-proxy to route traffic correctly
|
|
||||||
VIRTUAL_HOST: 'mediacms.example.com' # CHANGE THIS to your domain
|
|
||||||
LETSENCRYPT_HOST: 'mediacms.example.com' # CHANGE THIS to your domain
|
|
||||||
LETSENCRYPT_EMAIL: 'admin@example.com' # CHANGE THIS to your email
|
|
||||||
depends_on:
|
|
||||||
- web
|
|
||||||
volumes:
|
|
||||||
- static_files:/var/www/static:ro
|
|
||||||
- media_files:/var/www/media:ro
|
|
||||||
- logs:/var/log/mediacms
|
|
||||||
|
|
||||||
celery_beat:
|
|
||||||
image: mediacms/mediacms-worker:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "beat", "--loglevel=INFO"]
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
celery_short:
|
|
||||||
image: mediacms/mediacms-worker:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "short_tasks", "-c", "10", "--soft-time-limit=300", "--loglevel=INFO", "-n", "short@%h"]
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
celery_long:
|
|
||||||
image: mediacms/mediacms-worker:7.3
|
|
||||||
# To use extra codecs, change image to: mediacms/mediacms-worker:7.3-full
|
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "long_tasks", "-c", "1", "-Ofair", "--prefetch-multiplier=1", "--loglevel=INFO", "-n", "long@%h"]
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: postgres:17.2-alpine
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: mediacms
|
|
||||||
POSTGRES_PASSWORD: mediacms
|
|
||||||
POSTGRES_DB: mediacms
|
|
||||||
TZ: Europe/London
|
|
||||||
volumes:
|
|
||||||
- postgres_data:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: redis:alpine
|
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
conf:
|
|
||||||
vhost:
|
|
||||||
html:
|
|
||||||
dhparam:
|
|
||||||
certs:
|
|
||||||
acme:
|
|
||||||
postgres_data:
|
|
||||||
static_files:
|
|
||||||
media_files:
|
|
||||||
logs:
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
version: "3.8"
|
version: "3"
|
||||||
|
|
||||||
# Development setup with hot-reload and file mounts
|
|
||||||
# This is the ONLY compose file that mounts the source code
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
migrations:
|
migrations:
|
||||||
@@ -11,126 +8,82 @@ services:
|
|||||||
target: base
|
target: base
|
||||||
args:
|
args:
|
||||||
- DEVELOPMENT_MODE=True
|
- DEVELOPMENT_MODE=True
|
||||||
image: mediacms/mediacms-dev:7.3
|
image: mediacms/mediacms-dev:latest
|
||||||
command: ["/bin/bash", "/home/mediacms.io/mediacms/scripts/run-migrations.sh"]
|
volumes:
|
||||||
|
- ./:/home/mediacms.io/mediacms/
|
||||||
|
command: "./deploy/docker/prestart.sh"
|
||||||
environment:
|
environment:
|
||||||
DEVELOPMENT_MODE: 'True'
|
DEVELOPMENT_MODE: True
|
||||||
DEBUG: 'True'
|
ENABLE_UWSGI: 'no'
|
||||||
|
ENABLE_NGINX: 'no'
|
||||||
|
ENABLE_CELERY_SHORT: 'no'
|
||||||
|
ENABLE_CELERY_LONG: 'no'
|
||||||
|
ENABLE_CELERY_BEAT: 'no'
|
||||||
ADMIN_USER: 'admin'
|
ADMIN_USER: 'admin'
|
||||||
ADMIN_EMAIL: 'admin@localhost'
|
ADMIN_EMAIL: 'admin@localhost'
|
||||||
ADMIN_PASSWORD: 'admin'
|
ADMIN_PASSWORD: 'admin'
|
||||||
restart: "no"
|
restart: on-failure
|
||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
|
|
||||||
web:
|
|
||||||
image: mediacms/mediacms-dev:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "80:8000"
|
|
||||||
command: ["python", "manage.py", "runserver", "0.0.0.0:8000"]
|
|
||||||
environment:
|
|
||||||
DEVELOPMENT_MODE: 'True'
|
|
||||||
DEBUG: 'True'
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
image: node:20-alpine
|
image: node:20
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/frontend:/home/mediacms.io/mediacms/frontend/
|
||||||
working_dir: /home/mediacms.io/mediacms/frontend/
|
working_dir: /home/mediacms.io/mediacms/frontend/
|
||||||
command: sh -c "npm install && npm run start"
|
command: bash -c "npm install && npm run start"
|
||||||
|
env_file:
|
||||||
|
- ${PWD}/frontend/.env
|
||||||
ports:
|
ports:
|
||||||
- "8088:8088"
|
- "8088:8088"
|
||||||
environment:
|
|
||||||
- NODE_ENV=development
|
|
||||||
env_file:
|
|
||||||
- ./frontend/.env
|
|
||||||
volumes:
|
|
||||||
- ./frontend:/home/mediacms.io/mediacms/frontend/
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- web
|
- web
|
||||||
|
web:
|
||||||
celery_beat:
|
image: mediacms/mediacms-dev:latest
|
||||||
image: mediacms/mediacms-dev:7.3
|
command: "python manage.py runserver 0.0.0.0:80"
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "beat", "--loglevel=INFO"]
|
|
||||||
environment:
|
environment:
|
||||||
DEVELOPMENT_MODE: 'True'
|
DEVELOPMENT_MODE: True
|
||||||
DEBUG: 'True'
|
ports:
|
||||||
depends_on:
|
- "80:80"
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/home/mediacms.io/mediacms/
|
- ./:/home/mediacms.io/mediacms/
|
||||||
|
|
||||||
celery_short:
|
|
||||||
image: mediacms/mediacms-dev:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "short_tasks", "-c", "10", "--soft-time-limit=300", "--loglevel=INFO", "-n", "short@%h"]
|
|
||||||
environment:
|
|
||||||
DEVELOPMENT_MODE: 'True'
|
|
||||||
DEBUG: 'True'
|
|
||||||
depends_on:
|
depends_on:
|
||||||
migrations:
|
- migrations
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
|
|
||||||
celery_long:
|
|
||||||
image: mediacms/mediacms-dev:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "long_tasks", "-c", "1", "-Ofair", "--prefetch-multiplier=1", "--loglevel=INFO", "-n", "long@%h"]
|
|
||||||
environment:
|
|
||||||
DEVELOPMENT_MODE: 'True'
|
|
||||||
DEBUG: 'True'
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- ./:/home/mediacms.io/mediacms/
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:17.2-alpine
|
image: postgres:17.2-alpine
|
||||||
restart: unless-stopped
|
volumes:
|
||||||
|
- ../postgres_data:/var/lib/postgresql/data/
|
||||||
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: mediacms
|
POSTGRES_USER: mediacms
|
||||||
POSTGRES_PASSWORD: mediacms
|
POSTGRES_PASSWORD: mediacms
|
||||||
POSTGRES_DB: mediacms
|
POSTGRES_DB: mediacms
|
||||||
TZ: Europe/London
|
TZ: Europe/London
|
||||||
volumes:
|
|
||||||
- postgres_data:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}", "--host=db", "--dbname=$POSTGRES_DB", "--username=$POSTGRES_USER"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: "redis:alpine"
|
||||||
restart: unless-stopped
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
interval: 10s
|
interval: 30s
|
||||||
timeout: 5s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
celery_worker:
|
||||||
|
image: mediacms/mediacms-dev:latest
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
- ./:/home/mediacms.io/mediacms/
|
||||||
|
environment:
|
||||||
|
ENABLE_UWSGI: 'no'
|
||||||
|
ENABLE_NGINX: 'no'
|
||||||
|
ENABLE_CELERY_BEAT: 'no'
|
||||||
|
ENABLE_MIGRATIONS: 'no'
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
|||||||
@@ -1,120 +1,86 @@
|
|||||||
version: "3.8"
|
version: "3"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
migrations:
|
migrations:
|
||||||
image: mediacms/mediacms:7.3
|
image: mediacms/mediacms:latest
|
||||||
command: ["/bin/bash", "/home/mediacms.io/mediacms/scripts/run-migrations.sh"]
|
volumes:
|
||||||
|
- ./:/home/mediacms.io/mediacms/
|
||||||
environment:
|
environment:
|
||||||
|
ENABLE_UWSGI: 'no'
|
||||||
|
ENABLE_NGINX: 'no'
|
||||||
|
ENABLE_CELERY_SHORT: 'no'
|
||||||
|
ENABLE_CELERY_LONG: 'no'
|
||||||
|
ENABLE_CELERY_BEAT: 'no'
|
||||||
ADMIN_USER: 'admin'
|
ADMIN_USER: 'admin'
|
||||||
ADMIN_EMAIL: 'admin@localhost'
|
ADMIN_EMAIL: 'admin@localhost'
|
||||||
# ADMIN_PASSWORD: 'uncomment_and_set_password_here'
|
# ADMIN_PASSWORD: 'uncomment_and_set_password_here'
|
||||||
restart: "no"
|
command: "./deploy/docker/prestart.sh"
|
||||||
|
restart: on-failure
|
||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
|
||||||
- static_files:/home/mediacms.io/mediacms/static_files
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
web:
|
web:
|
||||||
image: mediacms/mediacms:7.3
|
image: mediacms/mediacms:latest
|
||||||
restart: unless-stopped
|
deploy:
|
||||||
expose:
|
replicas: 1
|
||||||
- "9000"
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- static_files:/home/mediacms.io/mediacms/static_files
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
nginx:
|
|
||||||
image: mediacms/mediacms-nginx:7.3
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
depends_on:
|
|
||||||
- web
|
|
||||||
volumes:
|
volumes:
|
||||||
- static_files:/var/www/static:ro
|
- ./:/home/mediacms.io/mediacms/
|
||||||
- media_files:/var/www/media:ro
|
environment:
|
||||||
- logs:/var/log/mediacms
|
ENABLE_CELERY_BEAT: 'no'
|
||||||
|
ENABLE_CELERY_SHORT: 'no'
|
||||||
|
ENABLE_CELERY_LONG: 'no'
|
||||||
|
ENABLE_MIGRATIONS: 'no'
|
||||||
|
depends_on:
|
||||||
|
- migrations
|
||||||
celery_beat:
|
celery_beat:
|
||||||
image: mediacms/mediacms-worker:7.3
|
image: mediacms/mediacms:latest
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "beat", "--loglevel=INFO"]
|
|
||||||
depends_on:
|
|
||||||
migrations:
|
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
volumes:
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
- ./:/home/mediacms.io/mediacms/
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
environment:
|
||||||
|
ENABLE_UWSGI: 'no'
|
||||||
celery_short:
|
ENABLE_NGINX: 'no'
|
||||||
image: mediacms/mediacms-worker:7.3
|
ENABLE_CELERY_SHORT: 'no'
|
||||||
restart: unless-stopped
|
ENABLE_CELERY_LONG: 'no'
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "short_tasks", "-c", "10", "--soft-time-limit=300", "--loglevel=INFO", "-n", "short@%h"]
|
ENABLE_MIGRATIONS: 'no'
|
||||||
depends_on:
|
depends_on:
|
||||||
migrations:
|
- redis
|
||||||
condition: service_completed_successfully
|
celery_worker:
|
||||||
redis:
|
image: mediacms/mediacms:latest
|
||||||
condition: service_healthy
|
deploy:
|
||||||
|
replicas: 1
|
||||||
volumes:
|
volumes:
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
- ./:/home/mediacms.io/mediacms/
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
environment:
|
||||||
|
ENABLE_UWSGI: 'no'
|
||||||
celery_long:
|
ENABLE_NGINX: 'no'
|
||||||
image: mediacms/mediacms-worker:7.3
|
ENABLE_CELERY_BEAT: 'no'
|
||||||
# To use extra codecs, change image to: mediacms/mediacms-worker:7.3-full
|
ENABLE_MIGRATIONS: 'no'
|
||||||
restart: unless-stopped
|
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "long_tasks", "-c", "1", "-Ofair", "--prefetch-multiplier=1", "--loglevel=INFO", "-n", "long@%h"]
|
|
||||||
depends_on:
|
depends_on:
|
||||||
migrations:
|
- migrations
|
||||||
condition: service_completed_successfully
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:17.2-alpine
|
image: postgres:17.2-alpine
|
||||||
restart: unless-stopped
|
volumes:
|
||||||
|
- ../postgres_data:/var/lib/postgresql/data/
|
||||||
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: mediacms
|
POSTGRES_USER: mediacms
|
||||||
POSTGRES_PASSWORD: mediacms
|
POSTGRES_PASSWORD: mediacms
|
||||||
POSTGRES_DB: mediacms
|
POSTGRES_DB: mediacms
|
||||||
TZ: Europe/London
|
TZ: Europe/London
|
||||||
volumes:
|
|
||||||
- postgres_data:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: "redis:alpine"
|
||||||
restart: unless-stopped
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "redis-cli","ping"]
|
test: ["CMD", "redis-cli","ping"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
|
||||||
volumes:
|
|
||||||
postgres_data:
|
|
||||||
static_files:
|
|
||||||
media_files:
|
|
||||||
logs:
|
|
||||||
|
|||||||
@@ -1,367 +0,0 @@
|
|||||||
# MediaCMS 7.3 Docker Architecture Migration Guide
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
MediaCMS 7.3 introduces a modernized Docker architecture that removes supervisord and implements Docker best practices with one process per container.
|
|
||||||
|
|
||||||
## What Changed
|
|
||||||
|
|
||||||
### Old Architecture (pre-7.3)
|
|
||||||
- Single multi-purpose image with supervisord
|
|
||||||
- Environment variables (`ENABLE_UWSGI`, `ENABLE_NGINX`, etc.) to control services
|
|
||||||
- All services bundled in `deploy/docker/` folder
|
|
||||||
- File mounts required for all deployments
|
|
||||||
|
|
||||||
### New Architecture (7.3+)
|
|
||||||
- **Dedicated images** for each service:
|
|
||||||
- `mediacms/mediacms:7.3` - Django/uWSGI application
|
|
||||||
- `mediacms/mediacms-worker:7.3` - Celery workers
|
|
||||||
- `mediacms/mediacms-worker:7.3-full` - Celery workers with extra codecs
|
|
||||||
- `mediacms/mediacms-nginx:7.3` - Nginx web server
|
|
||||||
- **No supervisord** - Native Docker process management
|
|
||||||
- **Separated services**:
|
|
||||||
- `migrations` - Runs database migrations on every startup
|
|
||||||
- `nginx` - Serves static/media files and proxies to Django
|
|
||||||
- `web` - Django application (uWSGI)
|
|
||||||
- `celery_short` - Short-running tasks (thumbnails, etc.)
|
|
||||||
- `celery_long` - Long-running tasks (video encoding)
|
|
||||||
- `celery_beat` - Task scheduler
|
|
||||||
- **No ENABLE_* environment variables**
|
|
||||||
- **Config centralized** in `config/` directory
|
|
||||||
- **File mounts only for development** (`docker-compose-dev.yaml`)
|
|
||||||
|
|
||||||
## Directory Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
config/
|
|
||||||
├── nginx/
|
|
||||||
│ ├── nginx.conf # Main nginx config
|
|
||||||
│ ├── site.conf # Virtual host config
|
|
||||||
│ └── uwsgi_params # uWSGI parameters
|
|
||||||
├── nginx-proxy/
|
|
||||||
│ └── client_max_body_size.conf # For production HTTPS proxy
|
|
||||||
├── uwsgi/
|
|
||||||
│ └── uwsgi.ini # uWSGI configuration
|
|
||||||
└── imagemagick/
|
|
||||||
└── policy.xml # ImageMagick policy
|
|
||||||
|
|
||||||
scripts/
|
|
||||||
├── entrypoint-web.sh # Web container entrypoint
|
|
||||||
├── entrypoint-worker.sh # Worker container entrypoint
|
|
||||||
└── run-migrations.sh # Migration script
|
|
||||||
|
|
||||||
Dockerfile.new # Main Dockerfile (base, web, worker, worker-full)
|
|
||||||
Dockerfile.nginx # Nginx Dockerfile
|
|
||||||
docker-compose.yaml # Production deployment
|
|
||||||
docker-compose-cert.yaml # Production with HTTPS
|
|
||||||
docker-compose-dev.yaml # Development with file mounts
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration Steps
|
|
||||||
|
|
||||||
### For Existing Production Systems
|
|
||||||
|
|
||||||
#### Step 1: Backup your data
|
|
||||||
```bash
|
|
||||||
# Backup database
|
|
||||||
docker exec mediacms_db_1 pg_dump -U mediacms mediacms > backup.sql
|
|
||||||
|
|
||||||
# Backup media files
|
|
||||||
cp -r media_files media_files.backup
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 2: Update configuration location
|
|
||||||
```bash
|
|
||||||
# The client_max_body_size.conf has moved
|
|
||||||
# No action needed if you haven't customized it
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 3: Pull latest images
|
|
||||||
```bash
|
|
||||||
docker pull mediacms/mediacms:7.3
|
|
||||||
docker pull mediacms/mediacms-worker:7.3
|
|
||||||
docker pull mediacms/mediacms-nginx:7.3
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 4: Update docker-compose file
|
|
||||||
If using **docker-compose.yaml**:
|
|
||||||
- No changes needed, just use the new version
|
|
||||||
|
|
||||||
If using **docker-compose-cert.yaml** (HTTPS):
|
|
||||||
- Update `VIRTUAL_HOST`, `LETSENCRYPT_HOST`, and `LETSENCRYPT_EMAIL` in the nginx service
|
|
||||||
- Update the path to client_max_body_size.conf:
|
|
||||||
```yaml
|
|
||||||
- ./config/nginx-proxy/client_max_body_size.conf:/etc/nginx/conf.d/client_max_body_size.conf:ro
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 5: Restart services
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### For Development Systems
|
|
||||||
|
|
||||||
Development now requires the `-dev` compose file:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Old way (no longer works)
|
|
||||||
docker compose up
|
|
||||||
|
|
||||||
# New way (development)
|
|
||||||
docker compose -f docker-compose-dev.yaml up
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deployment Options
|
|
||||||
|
|
||||||
### Standard Deployment (HTTP)
|
|
||||||
|
|
||||||
**File**: `docker-compose.yaml`
|
|
||||||
|
|
||||||
**Command**:
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Self-contained images (no file mounts)
|
|
||||||
- Nginx serves on port 80
|
|
||||||
- Separate containers for each service
|
|
||||||
- Named volumes for persistence
|
|
||||||
|
|
||||||
**Architecture**:
|
|
||||||
```
|
|
||||||
Client → nginx:80 → web:9000 (uWSGI)
|
|
||||||
↓
|
|
||||||
static_files (volume)
|
|
||||||
media_files (volume)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Production Deployment (HTTPS with Let's Encrypt)
|
|
||||||
|
|
||||||
**File**: `docker-compose-cert.yaml`
|
|
||||||
|
|
||||||
**Prerequisites**:
|
|
||||||
1. Domain name pointing to your server
|
|
||||||
2. Ports 80 and 443 open
|
|
||||||
|
|
||||||
**Setup**:
|
|
||||||
```bash
|
|
||||||
# 1. Edit docker-compose-cert.yaml
|
|
||||||
# Update these values in the nginx service:
|
|
||||||
# VIRTUAL_HOST: 'your-domain.com'
|
|
||||||
# LETSENCRYPT_HOST: 'your-domain.com'
|
|
||||||
# LETSENCRYPT_EMAIL: 'your-email@example.com'
|
|
||||||
|
|
||||||
# 2. Start services
|
|
||||||
docker compose -f docker-compose-cert.yaml up -d
|
|
||||||
|
|
||||||
# 3. Check logs
|
|
||||||
docker compose -f docker-compose-cert.yaml logs -f nginx-proxy acme-companion
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Automatic HTTPS via Let's Encrypt
|
|
||||||
- Certificate auto-renewal
|
|
||||||
- Reverse proxy handles SSL termination
|
|
||||||
|
|
||||||
**Architecture**:
|
|
||||||
```
|
|
||||||
Client → nginx-proxy:443 (HTTPS) → nginx:80 → web:9000 (uWSGI)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Development Deployment
|
|
||||||
|
|
||||||
**File**: `docker-compose-dev.yaml`
|
|
||||||
|
|
||||||
**Command**:
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose-dev.yaml up
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Source code mounted for live editing
|
|
||||||
- Django debug mode enabled
|
|
||||||
- Django's `runserver` instead of uWSGI
|
|
||||||
- Frontend hot-reload on port 8088
|
|
||||||
- No nginx (direct Django access on port 80)
|
|
||||||
|
|
||||||
**Ports**:
|
|
||||||
- `80` - Django API
|
|
||||||
- `8088` - Frontend dev server
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
All configuration is done via environment variables or `cms/local_settings.py`.
|
|
||||||
|
|
||||||
**Key Variables**:
|
|
||||||
- `FRONTEND_HOST` - Your domain (e.g., `https://mediacms.example.com`)
|
|
||||||
- `PORTAL_NAME` - Your portal name
|
|
||||||
- `SECRET_KEY` - Django secret key
|
|
||||||
- `POSTGRES_*` - Database credentials
|
|
||||||
- `REDIS_LOCATION` - Redis connection string
|
|
||||||
- `DEBUG` - Enable debug mode (development only)
|
|
||||||
|
|
||||||
**Setting variables**:
|
|
||||||
|
|
||||||
Option 1: In docker-compose file:
|
|
||||||
```yaml
|
|
||||||
environment:
|
|
||||||
FRONTEND_HOST: 'https://mediacms.example.com'
|
|
||||||
PORTAL_NAME: 'My MediaCMS'
|
|
||||||
```
|
|
||||||
|
|
||||||
Option 2: Using .env file (recommended):
|
|
||||||
```bash
|
|
||||||
# Create .env file
|
|
||||||
cat > .env << EOF
|
|
||||||
FRONTEND_HOST=https://mediacms.example.com
|
|
||||||
PORTAL_NAME=My MediaCMS
|
|
||||||
SECRET_KEY=your-secret-key-here
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
### Customizing Settings
|
|
||||||
|
|
||||||
For advanced customization, you can build a custom image:
|
|
||||||
|
|
||||||
```dockerfile
|
|
||||||
# Dockerfile.custom
|
|
||||||
FROM mediacms/mediacms:7.3
|
|
||||||
COPY my_local_settings.py /home/mediacms.io/mediacms/cms/local_settings.py
|
|
||||||
```
|
|
||||||
|
|
||||||
## Celery Workers
|
|
||||||
|
|
||||||
### Standard Workers
|
|
||||||
|
|
||||||
By default, `celery_long` uses the standard image:
|
|
||||||
```yaml
|
|
||||||
celery_long:
|
|
||||||
image: mediacms/mediacms-worker:7.3
|
|
||||||
```
|
|
||||||
|
|
||||||
### Full Workers (Extra Codecs)
|
|
||||||
|
|
||||||
To enable extra codecs for better transcoding (including Whisper for subtitles):
|
|
||||||
|
|
||||||
**Edit docker-compose file**:
|
|
||||||
```yaml
|
|
||||||
celery_long:
|
|
||||||
image: mediacms/mediacms-worker:7.3-full # Changed from :7.3
|
|
||||||
```
|
|
||||||
|
|
||||||
**Then restart**:
|
|
||||||
```bash
|
|
||||||
docker compose up -d celery_long
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scaling Workers
|
|
||||||
|
|
||||||
You can scale workers independently:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Scale short task workers
|
|
||||||
docker compose up -d --scale celery_short=3
|
|
||||||
|
|
||||||
# Scale long task workers
|
|
||||||
docker compose up -d --scale celery_long=2
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Migrations not running
|
|
||||||
```bash
|
|
||||||
# Check migrations container logs
|
|
||||||
docker compose logs migrations
|
|
||||||
|
|
||||||
# Manually run migrations
|
|
||||||
docker compose run --rm migrations
|
|
||||||
```
|
|
||||||
|
|
||||||
### Static files not loading
|
|
||||||
```bash
|
|
||||||
# Ensure migrations completed (it runs collectstatic)
|
|
||||||
docker compose logs migrations
|
|
||||||
|
|
||||||
# Check nginx can access volumes
|
|
||||||
docker compose exec nginx ls -la /var/www/static
|
|
||||||
```
|
|
||||||
|
|
||||||
### Permission issues
|
|
||||||
```bash
|
|
||||||
# Check volume ownership
|
|
||||||
docker compose exec web ls -la /home/mediacms.io/mediacms/media_files
|
|
||||||
|
|
||||||
# If needed, rebuild images
|
|
||||||
docker compose build --no-cache
|
|
||||||
```
|
|
||||||
|
|
||||||
### Celery workers not processing tasks
|
|
||||||
```bash
|
|
||||||
# Check worker logs
|
|
||||||
docker compose logs celery_short celery_long
|
|
||||||
|
|
||||||
# Check Redis connection
|
|
||||||
docker compose exec redis redis-cli ping
|
|
||||||
|
|
||||||
# Restart workers
|
|
||||||
docker compose restart celery_short celery_long celery_beat
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removed Components
|
|
||||||
|
|
||||||
The following are **no longer used** in 7.3:
|
|
||||||
|
|
||||||
- ❌ `deploy/docker/supervisord/` - Supervisord configs
|
|
||||||
- ❌ `deploy/docker/start.sh` - Start script
|
|
||||||
- ❌ `deploy/docker/entrypoint.sh` - Old entrypoint
|
|
||||||
- ❌ Environment variables: `ENABLE_UWSGI`, `ENABLE_NGINX`, `ENABLE_CELERY_BEAT`, `ENABLE_CELERY_SHORT`, `ENABLE_CELERY_LONG`, `ENABLE_MIGRATIONS`
|
|
||||||
|
|
||||||
**These are still available but moved**:
|
|
||||||
- ✅ `config/nginx/` - Nginx configs (moved from `deploy/docker/`)
|
|
||||||
- ✅ `config/uwsgi/` - uWSGI config (moved from `deploy/docker/`)
|
|
||||||
- ✅ `config/nginx-proxy/` - Reverse proxy config (moved from `deploy/docker/reverse_proxy/`)
|
|
||||||
|
|
||||||
## Persistent Volumes
|
|
||||||
|
|
||||||
MediaCMS 7.3 uses Docker named volumes for data persistence:
|
|
||||||
|
|
||||||
- **`media_files`** - All uploaded media (videos, images, thumbnails, HLS streams)
|
|
||||||
- Mounted on: migrations, web, nginx, celery_beat, celery_short, celery_long
|
|
||||||
- Persists across container restarts, updates, and image removals
|
|
||||||
|
|
||||||
- **`logs`** - Application and nginx logs
|
|
||||||
- Mounted on: migrations, web, nginx, celery_beat, celery_short, celery_long
|
|
||||||
- Nginx logs: `/var/log/mediacms/nginx.access.log`, `/var/log/mediacms/nginx.error.log`
|
|
||||||
- Django/Celery logs: `/home/mediacms.io/mediacms/logs/`
|
|
||||||
- Persists across container restarts, updates, and image removals
|
|
||||||
|
|
||||||
- **`static_files`** - Django static files (CSS, JS, images)
|
|
||||||
- Mounted on: migrations, web, nginx
|
|
||||||
- Regenerated during migrations via `collectstatic`
|
|
||||||
|
|
||||||
- **`postgres_data`** - PostgreSQL database
|
|
||||||
- Mounted on: db
|
|
||||||
- Persists across container restarts, updates, and image removals
|
|
||||||
|
|
||||||
**Important**: Use `docker compose down -v` to remove volumes (⚠️ causes data loss!)
|
|
||||||
|
|
||||||
## Benefits of New Architecture
|
|
||||||
|
|
||||||
1. **Better resource management** - Scale services independently
|
|
||||||
2. **Easier debugging** - Clear separation of concerns
|
|
||||||
3. **Faster restarts** - Restart only affected services
|
|
||||||
4. **Production-ready** - No file mounts, immutable images
|
|
||||||
5. **Standard Docker practices** - One process per container
|
|
||||||
6. **Clearer logs** - Each service has isolated logs, persistent storage
|
|
||||||
7. **Better health checks** - Per-service monitoring
|
|
||||||
8. **Data persistence** - media_files and logs survive all container operations
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
For issues or questions:
|
|
||||||
- GitHub Issues: https://github.com/mediacms-io/mediacms/issues
|
|
||||||
- Documentation: https://docs.mediacms.io
|
|
||||||
@@ -164,123 +164,53 @@ Database is stored on ../postgres_data/ and media_files on media_files/
|
|||||||
|
|
||||||
## 4. Docker Deployment options
|
## 4. Docker Deployment options
|
||||||
|
|
||||||
**⚠️ IMPORTANT**: MediaCMS 7.3 introduces a new Docker architecture. If you're upgrading from an earlier version, please see the [Migration Guide](DOCKER_V7.3_MIGRATION.md).
|
The mediacms image is built to use supervisord as the main process, which manages one or more services required to run mediacms. We can toggle which services are run in a given container by setting the environment variables below to `yes` or `no`:
|
||||||
|
|
||||||
### Architecture Overview
|
* ENABLE_UWSGI
|
||||||
|
* ENABLE_NGINX
|
||||||
|
* ENABLE_CELERY_BEAT
|
||||||
|
* ENABLE_CELERY_SHORT
|
||||||
|
* ENABLE_CELERY_LONG
|
||||||
|
* ENABLE_MIGRATIONS
|
||||||
|
|
||||||
MediaCMS 7.3+ uses a modern microservices architecture with dedicated containers:
|
By default, all these services are enabled, but in order to create a scaleable deployment, some of them can be disabled, splitting the service up into smaller services.
|
||||||
|
|
||||||
- **nginx** - Web server for static/media files and reverse proxy
|
Also see the `Dockerfile` for other environment variables which you may wish to override. Application settings, eg. `FRONTEND_HOST` can also be overridden by updating the `deploy/docker/local_settings.py` file.
|
||||||
- **web** - Django application (uWSGI)
|
|
||||||
- **celery_short** - Short-running background tasks
|
|
||||||
- **celery_long** - Long-running tasks (video encoding)
|
|
||||||
- **celery_beat** - Task scheduler
|
|
||||||
- **migrations** - Database migrations (runs on startup)
|
|
||||||
- **db** - PostgreSQL database
|
|
||||||
- **redis** - Cache and message broker
|
|
||||||
|
|
||||||
### Key Changes from Previous Versions
|
To run, update the configs above if necessary, build the image by running `docker compose build`, then run `docker compose run`
|
||||||
|
|
||||||
- ✅ **No supervisord** - Native Docker process management
|
### Simple Deployment, accessed as http://localhost
|
||||||
- ✅ **Dedicated images** per service
|
|
||||||
- ✅ **No ENABLE_* environment variables** - Services are separated into individual containers
|
|
||||||
- ✅ **Production images** don't mount source code (immutable)
|
|
||||||
- ✅ **config/** directory for centralized configuration
|
|
||||||
- ✅ **Separate celery workers** for short and long tasks
|
|
||||||
|
|
||||||
### Configuration
|
The main container runs migrations, mediacms_web, celery_beat, celery_workers (celery_short and celery_long services), exposed on port 80 supported by redis and postgres database.
|
||||||
|
|
||||||
Application settings can be overridden using environment variables in your docker-compose file or by building a custom image with a modified `cms/local_settings.py` file.
|
The FRONTEND_HOST in `deploy/docker/local_settings.py` is configured as http://localhost, on the docker host machine.
|
||||||
|
|
||||||
Key environment variables:
|
### Server with ssl certificate through letsencrypt service, accessed as https://my_domain.com
|
||||||
- `FRONTEND_HOST` - Your domain (e.g., `https://mediacms.example.com`)
|
Before trying this out make sure the ip points to my_domain.com.
|
||||||
- `PORTAL_NAME` - Portal name
|
|
||||||
- `SECRET_KEY` - Django secret key
|
|
||||||
- `DEBUG` - Enable debug mode (development only)
|
|
||||||
- Database and Redis connection settings
|
|
||||||
|
|
||||||
See the [Migration Guide](DOCKER_V7.3_MIGRATION.md) for detailed configuration options
|
With this method [this deployment](../docker-compose-letsencrypt.yaml) is used.
|
||||||
|
|
||||||
### Simple Deployment (HTTP)
|
Edit this file and set `VIRTUAL_HOST` as my_domain.com, `LETSENCRYPT_HOST` as my_domain.com, and your email on `LETSENCRYPT_EMAIL`
|
||||||
|
|
||||||
Use `docker-compose.yaml` for a standard HTTP deployment on port 80:
|
Edit `deploy/docker/local_settings.py` and set https://my_domain.com as `FRONTEND_HOST`
|
||||||
|
|
||||||
```bash
|
Now run `docker compose -f docker-compose-letsencrypt.yaml up`, when installation finishes you will be able to access https://my_domain.com using a valid Letsencrypt certificate!
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
This starts all services (nginx, web, celery workers, database, redis) with the nginx container exposed on port 80. Access at http://localhost or http://your-server-ip.
|
### Advanced Deployment, accessed as http://localhost:8000
|
||||||
|
|
||||||
**Features:**
|
Here we can run 1 mediacms_web instance, with the FRONTEND_HOST in `deploy/docker/local_settings.py` configured as http://localhost:8000. This is bootstrapped by a single migrations instance and supported by a single celery_beat instance and 1 or more celery_worker instances. Redis and postgres containers are also used for persistence. Clients can access the service on http://localhost:8000, on the docker host machine. This is similar to [this deployment](../docker-compose.yaml), with a `port` defined in FRONTEND_HOST.
|
||||||
- Production-ready with immutable images
|
|
||||||
- Named volumes for data persistence
|
|
||||||
- Separate containers for each service
|
|
||||||
|
|
||||||
### Production Deployment with HTTPS (Let's Encrypt)
|
### Advanced Deployment, with reverse proxy, accessed as http://mediacms.io
|
||||||
|
|
||||||
Use `docker-compose-cert.yaml` for automatic HTTPS with Let's Encrypt:
|
Here we can use `jwilder/nginx-proxy` to reverse proxy to 1 or more instances of mediacms_web supported by other services as mentioned in the previous deployment. The FRONTEND_HOST in `deploy/docker/local_settings.py` is configured as http://mediacms.io, nginx-proxy has port 80 exposed. Clients can access the service on http://mediacms.io (Assuming DNS or the hosts file is setup correctly to point to the IP of the nginx-proxy instance). This is similar to [this deployment](../docker-compose-http-proxy.yaml).
|
||||||
|
|
||||||
**Prerequisites:**
|
### Advanced Deployment, with reverse proxy, accessed as https://localhost
|
||||||
- Domain name pointing to your server
|
|
||||||
- Ports 80 and 443 open
|
|
||||||
|
|
||||||
**Setup:**
|
The reverse proxy (`jwilder/nginx-proxy`) can be configured to provide SSL termination using self-signed certificates, letsencrypt or CA signed certificates (see: https://hub.docker.com/r/jwilder/nginx-proxy or [LetsEncrypt Example](https://www.singularaspect.com/use-nginx-proxy-and-letsencrypt-companion-to-host-multiple-websites/) ). In this case the FRONTEND_HOST should be set to https://mediacms.io. This is similar to [this deployment](../docker-compose-http-proxy.yaml).
|
||||||
1. Edit `docker-compose-cert.yaml` and update:
|
|
||||||
- `VIRTUAL_HOST` - Your domain
|
|
||||||
- `LETSENCRYPT_HOST` - Your domain
|
|
||||||
- `LETSENCRYPT_EMAIL` - Your email
|
|
||||||
|
|
||||||
2. Run:
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose-cert.yaml up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
This uses `nginxproxy/nginx-proxy` with `acme-companion` for automatic HTTPS certificate management. Access at https://your-domain.com.
|
|
||||||
|
|
||||||
### Development Deployment
|
|
||||||
|
|
||||||
Use `docker-compose-dev.yaml` for development with live code reloading:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose-dev.yaml up
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Source code mounted for live editing
|
|
||||||
- Django debug mode enabled
|
|
||||||
- Frontend dev server on port 8088
|
|
||||||
- Direct Django access (no nginx) on port 80
|
|
||||||
|
|
||||||
### Scaling Workers
|
|
||||||
|
|
||||||
Scale celery workers independently based on load:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Scale short task workers to 3 instances
|
|
||||||
docker compose up -d --scale celery_short=3
|
|
||||||
|
|
||||||
# Scale long task workers to 2 instances
|
|
||||||
docker compose up -d --scale celery_long=2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using Extra Codecs (Full Image)
|
|
||||||
|
|
||||||
For advanced transcoding features (including Whisper for automatic subtitles), use the full worker image:
|
|
||||||
|
|
||||||
Edit your docker-compose file:
|
|
||||||
```yaml
|
|
||||||
celery_long:
|
|
||||||
image: mediacms/mediacms-worker:7.3-full # Changed from :7.3
|
|
||||||
```
|
|
||||||
|
|
||||||
Then restart:
|
|
||||||
```bash
|
|
||||||
docker compose up -d celery_long
|
|
||||||
```
|
|
||||||
|
|
||||||
### A Scaleable Deployment Architecture (Docker, Swarm, Kubernetes)
|
### A Scaleable Deployment Architecture (Docker, Swarm, Kubernetes)
|
||||||
|
|
||||||
The architecture below provides a conceptual design for deployments based on kubernetes and docker swarm. It allows for horizontal scaleability through the use of multiple web instances and celery workers. For large deployments, managed postgres, redis and storage may be adopted.
|
The architecture below generalises all the deployment scenarios above, and provides a conceptual design for other deployments based on kubernetes and docker swarm. It allows for horizontal scaleability through the use of multiple mediacms_web instances and celery_workers. For large deployments, managed postgres, redis and storage may be adopted.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -290,34 +220,22 @@ Several options are available on `cms/settings.py`, most of the things that are
|
|||||||
|
|
||||||
It is advisable to override any of them by adding it to `local_settings.py` .
|
It is advisable to override any of them by adding it to `local_settings.py` .
|
||||||
|
|
||||||
**Single server installation:** edit `cms/local_settings.py`, make changes and restart MediaCMS:
|
In case of a the single server installation, add to `cms/local_settings.py` .
|
||||||
|
|
||||||
|
In case of a docker compose installation, add to `deploy/docker/local_settings.py` . This will automatically overwrite `cms/local_settings.py` .
|
||||||
|
|
||||||
|
Any change needs restart of MediaCMS in order to take effect.
|
||||||
|
|
||||||
|
Single server installation: edit `cms/local_settings.py`, make a change and restart MediaCMS
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
systemctl restart mediacms celery_beat celery_short celery_long
|
#systemctl restart mediacms
|
||||||
```
|
```
|
||||||
|
|
||||||
**Docker installation:** Configuration can be done in two ways:
|
Docker Compose installation: edit `deploy/docker/local_settings.py`, make a change and restart MediaCMS containers
|
||||||
|
|
||||||
1. **Environment variables** (recommended for simple changes):
|
|
||||||
Add to your docker-compose file:
|
|
||||||
```yaml
|
|
||||||
environment:
|
|
||||||
FRONTEND_HOST: 'https://mediacms.example.com'
|
|
||||||
PORTAL_NAME: 'My MediaCMS'
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Custom image with local_settings.py** (for complex changes):
|
|
||||||
- Create a custom Dockerfile:
|
|
||||||
```dockerfile
|
|
||||||
FROM mediacms/mediacms:7.3
|
|
||||||
COPY my_custom_settings.py /home/mediacms.io/mediacms/cms/local_settings.py
|
|
||||||
```
|
|
||||||
- Build and use your custom image
|
|
||||||
|
|
||||||
After changes, restart the affected containers:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose restart web celery_short celery_long celery_beat
|
#docker compose restart web celery_worker celery_beat
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.1 Change portal logo
|
### 5.1 Change portal logo
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Before beginning, ensure the following:
|
|||||||
|
|
||||||
## Step 1: Configure MediaCMS for SAML
|
## Step 1: Configure MediaCMS for SAML
|
||||||
|
|
||||||
The first step in enabling SAML authentication is to modify the `local_settings.py` (for Docker: `./config/local_settings.py`) file of your MediaCMS deployment. Add the following configuration block to enable SAML support, role-based access control (RBAC), and enforce secure communication settings:
|
The first step in enabling SAML authentication is to modify the `local_settings.py` (for Docker: `./deploy/docker/local_settings.py`) file of your MediaCMS deployment. Add the following configuration block to enable SAML support, role-based access control (RBAC), and enforce secure communication settings:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
USE_RBAC = True
|
USE_RBAC = True
|
||||||
@@ -292,7 +292,7 @@ Another issue you might encounter is an **infinite redirect loop**. This can hap
|
|||||||
https://<MyDomainName>/accounts/saml/mediacms_entraid/login/
|
https://<MyDomainName>/accounts/saml/mediacms_entraid/login/
|
||||||
```
|
```
|
||||||
|
|
||||||
* Add the following line to `./config/local_settings.py`:
|
* Add the following line to `./deploy/docker/local_settings.py`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
LOGIN_URL = "/accounts/saml/mediacms_entraid/login/"
|
LOGIN_URL = "/accounts/saml/mediacms_entraid/login/"
|
||||||
|
|||||||
@@ -329,10 +329,17 @@ class Media(models.Model):
|
|||||||
|
|
||||||
if to_transcribe:
|
if to_transcribe:
|
||||||
TranscriptionRequest.objects.create(media=self, translate_to_english=False)
|
TranscriptionRequest.objects.create(media=self, translate_to_english=False)
|
||||||
tasks.whisper_transcribe.delay(self.friendly_token, translate_to_english=False)
|
tasks.whisper_transcribe.apply_async(
|
||||||
|
args=[self.friendly_token, False],
|
||||||
|
countdown=10,
|
||||||
|
)
|
||||||
|
|
||||||
if to_transcribe_and_translate:
|
if to_transcribe_and_translate:
|
||||||
TranscriptionRequest.objects.create(media=self, translate_to_english=True)
|
TranscriptionRequest.objects.create(media=self, translate_to_english=True)
|
||||||
tasks.whisper_transcribe.delay(self.friendly_token, translate_to_english=True)
|
tasks.whisper_transcribe.apply_async(
|
||||||
|
args=[self.friendly_token, True],
|
||||||
|
countdown=10,
|
||||||
|
)
|
||||||
|
|
||||||
def update_search_vector(self):
|
def update_search_vector(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -150,6 +150,11 @@ const App = () => {
|
|||||||
canRedo={historyPosition < history.length - 1}
|
canRedo={historyPosition < history.length - 1}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Timeline Header */}
|
||||||
|
<div className="timeline-header-container">
|
||||||
|
<h2 className="timeline-header-title">Add Chapters</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Timeline Controls */}
|
{/* Timeline Controls */}
|
||||||
<TimelineControls
|
<TimelineControls
|
||||||
currentTime={currentTime}
|
currentTime={currentTime}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const useVideoChapters = () => {
|
|||||||
// Sort by start time to find chronological position
|
// Sort by start time to find chronological position
|
||||||
const sortedSegments = allSegments.sort((a, b) => a.startTime - b.startTime);
|
const sortedSegments = allSegments.sort((a, b) => a.startTime - b.startTime);
|
||||||
// Find the index of our new segment
|
// Find the index of our new segment
|
||||||
const chapterIndex = sortedSegments.findIndex(seg => seg.startTime === newSegmentStartTime);
|
const chapterIndex = sortedSegments.findIndex((seg) => seg.startTime === newSegmentStartTime);
|
||||||
return `Chapter ${chapterIndex + 1}`;
|
return `Chapter ${chapterIndex + 1}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,10 +30,16 @@ const useVideoChapters = () => {
|
|||||||
const sortedSegments = [...segments].sort((a, b) => a.startTime - b.startTime);
|
const sortedSegments = [...segments].sort((a, b) => a.startTime - b.startTime);
|
||||||
|
|
||||||
// Renumber each segment based on its chronological position
|
// Renumber each segment based on its chronological position
|
||||||
return sortedSegments.map((segment, index) => ({
|
// Only update titles that follow the default "Chapter X" pattern to preserve custom titles
|
||||||
|
return sortedSegments.map((segment, index) => {
|
||||||
|
const currentTitle = segment.chapterTitle || '';
|
||||||
|
const isDefaultTitle = /^Chapter \d+$/.test(currentTitle);
|
||||||
|
|
||||||
|
return {
|
||||||
...segment,
|
...segment,
|
||||||
chapterTitle: `Chapter ${index + 1}`
|
chapterTitle: isDefaultTitle ? `Chapter ${index + 1}` : currentTitle,
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to parse time string (HH:MM:SS.mmm) to seconds
|
// Helper function to parse time string (HH:MM:SS.mmm) to seconds
|
||||||
@@ -124,9 +130,7 @@ const useVideoChapters = () => {
|
|||||||
let initialSegments: Segment[] = [];
|
let initialSegments: Segment[] = [];
|
||||||
|
|
||||||
// Check if we have existing chapters from the backend
|
// Check if we have existing chapters from the backend
|
||||||
const existingChapters =
|
const existingChapters = (typeof window !== 'undefined' && (window as any).MEDIA_DATA?.chapters) || [];
|
||||||
(typeof window !== 'undefined' && (window as any).MEDIA_DATA?.chapters) ||
|
|
||||||
[];
|
|
||||||
|
|
||||||
if (existingChapters.length > 0) {
|
if (existingChapters.length > 0) {
|
||||||
// Create segments from existing chapters
|
// Create segments from existing chapters
|
||||||
@@ -564,8 +568,11 @@ const useVideoChapters = () => {
|
|||||||
`Updating segments with action: ${actionType}, recordHistory: ${isSignificantChange ? 'true' : 'false'}`
|
`Updating segments with action: ${actionType}, recordHistory: ${isSignificantChange ? 'true' : 'false'}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Renumber all segments to ensure proper chronological naming
|
||||||
|
const renumberedSegments = renumberAllSegments(e.detail.segments);
|
||||||
|
|
||||||
// Update segment state immediately for UI feedback
|
// Update segment state immediately for UI feedback
|
||||||
setClipSegments(e.detail.segments);
|
setClipSegments(renumberedSegments);
|
||||||
|
|
||||||
// Always save state to history for non-intermediate actions
|
// Always save state to history for non-intermediate actions
|
||||||
if (isSignificantChange) {
|
if (isSignificantChange) {
|
||||||
@@ -573,7 +580,7 @@ const useVideoChapters = () => {
|
|||||||
// ensure we capture the state properly
|
// ensure we capture the state properly
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Deep clone to ensure state is captured correctly
|
// Deep clone to ensure state is captured correctly
|
||||||
const segmentsClone = JSON.parse(JSON.stringify(e.detail.segments));
|
const segmentsClone = JSON.parse(JSON.stringify(renumberedSegments));
|
||||||
|
|
||||||
// Create a complete state snapshot
|
// Create a complete state snapshot
|
||||||
const stateWithAction: EditorState = {
|
const stateWithAction: EditorState = {
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
#chapters-editor-root {
|
#chapters-editor-root {
|
||||||
|
.timeline-header-container {
|
||||||
|
margin-left: 1rem;
|
||||||
|
margin-top: -0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-header-title {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #059669;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.timeline-container-card {
|
.timeline-container-card {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
@@ -11,6 +23,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 2px solid rgba(16, 185, 129, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-title {
|
.timeline-title {
|
||||||
@@ -21,6 +35,8 @@
|
|||||||
|
|
||||||
.timeline-title-text {
|
.timeline-title-text {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
color: #059669;
|
||||||
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-time {
|
.current-time {
|
||||||
@@ -48,10 +64,11 @@
|
|||||||
.timeline-container {
|
.timeline-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
background-color: #fafbfc;
|
background-color: #E2EDE4;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
overflow: visible !important;
|
overflow: visible !important;
|
||||||
|
border: 1px solid rgba(16, 185, 129, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-marker {
|
.timeline-marker {
|
||||||
@@ -194,7 +211,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: 0.4rem;
|
padding: 0.4rem;
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
background-color: rgba(16, 185, 129, 0.6);
|
||||||
color: white;
|
color: white;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
@@ -202,15 +219,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment:hover .clip-segment-info {
|
.clip-segment:hover .clip-segment-info {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(16, 185, 129, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment.selected .clip-segment-info {
|
.clip-segment.selected .clip-segment-info {
|
||||||
background-color: rgba(59, 130, 246, 0.5);
|
background-color: rgba(5, 150, 105, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment.selected:hover .clip-segment-info {
|
.clip-segment.selected:hover .clip-segment-info {
|
||||||
background-color: rgba(59, 130, 246, 0.4);
|
background-color: rgba(5, 150, 105, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment-name {
|
.clip-segment-name {
|
||||||
|
|||||||
@@ -309,6 +309,11 @@ const App = () => {
|
|||||||
canRedo={historyPosition < history.length - 1}
|
canRedo={historyPosition < history.length - 1}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Timeline Header */}
|
||||||
|
<div className="timeline-header-container">
|
||||||
|
<h2 className="timeline-header-title">Trim or Split</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Timeline Controls */}
|
{/* Timeline Controls */}
|
||||||
<TimelineControls
|
<TimelineControls
|
||||||
currentTime={currentTime}
|
currentTime={currentTime}
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
#video-editor-trim-root {
|
#video-editor-trim-root {
|
||||||
|
.timeline-header-container {
|
||||||
|
margin-left: 1rem;
|
||||||
|
margin-top: -0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-header-title {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2563eb;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.timeline-container-card {
|
.timeline-container-card {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
@@ -11,6 +23,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 2px solid rgba(59, 130, 246, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-title {
|
.timeline-title {
|
||||||
@@ -21,6 +35,8 @@
|
|||||||
|
|
||||||
.timeline-title-text {
|
.timeline-title-text {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
color: #2563eb;
|
||||||
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-time {
|
.current-time {
|
||||||
@@ -48,10 +64,11 @@
|
|||||||
.timeline-container {
|
.timeline-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
background-color: #fafbfc;
|
background-color: #eff6ff;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
overflow: visible !important;
|
overflow: visible !important;
|
||||||
|
border: 1px solid rgba(59, 130, 246, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-marker {
|
.timeline-marker {
|
||||||
@@ -194,7 +211,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: 0.4rem;
|
padding: 0.4rem;
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
background-color: rgba(59, 130, 246, 0.6);
|
||||||
color: white;
|
color: white;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
@@ -202,15 +219,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment:hover .clip-segment-info {
|
.clip-segment:hover .clip-segment-info {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(59, 130, 246, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment.selected .clip-segment-info {
|
.clip-segment.selected .clip-segment-info {
|
||||||
background-color: rgba(59, 130, 246, 0.5);
|
background-color: rgba(37, 99, 235, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment.selected:hover .clip-segment-info {
|
.clip-segment.selected:hover .clip-segment-info {
|
||||||
background-color: rgba(59, 130, 246, 0.4);
|
background-color: rgba(37, 99, 235, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.clip-segment-name {
|
.clip-segment-name {
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "========================================="
|
|
||||||
echo "MediaCMS Migrations Starting..."
|
|
||||||
echo "========================================="
|
|
||||||
|
|
||||||
# Wait for database to be ready
|
|
||||||
until python manage.py migrate --check 2>/dev/null; do
|
|
||||||
echo "Waiting for database to be ready..."
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
|
|
||||||
# Run migrations
|
|
||||||
echo "Running database migrations..."
|
|
||||||
python manage.py migrate
|
|
||||||
|
|
||||||
# Check if this is a new installation
|
|
||||||
EXISTING_INSTALLATION=$(echo "from users.models import User; print(User.objects.exists())" | python manage.py shell)
|
|
||||||
|
|
||||||
if [ "$EXISTING_INSTALLATION" = "True" ]; then
|
|
||||||
echo "Existing installation detected, skipping initial data load"
|
|
||||||
else
|
|
||||||
echo "New installation detected, loading initial data..."
|
|
||||||
|
|
||||||
# Load fixtures
|
|
||||||
python manage.py loaddata fixtures/encoding_profiles.json
|
|
||||||
python manage.py loaddata fixtures/categories.json
|
|
||||||
|
|
||||||
# Create admin user
|
|
||||||
RANDOM_ADMIN_PASS=$(python -c "import secrets;chars = 'abcdefghijklmnopqrstuvwxyz0123456789';print(''.join(secrets.choice(chars) for i in range(10)))")
|
|
||||||
ADMIN_PASSWORD=${ADMIN_PASSWORD:-$RANDOM_ADMIN_PASS}
|
|
||||||
|
|
||||||
DJANGO_SUPERUSER_PASSWORD=$ADMIN_PASSWORD python manage.py createsuperuser \
|
|
||||||
--no-input \
|
|
||||||
--username=${ADMIN_USER:-admin} \
|
|
||||||
--email=${ADMIN_EMAIL:-admin@localhost} \
|
|
||||||
--database=default || true
|
|
||||||
|
|
||||||
echo "========================================="
|
|
||||||
echo "Admin user created with password: $ADMIN_PASSWORD"
|
|
||||||
echo "========================================="
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect static files
|
|
||||||
echo "Collecting static files..."
|
|
||||||
python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
echo "========================================="
|
|
||||||
echo "Migrations completed successfully!"
|
|
||||||
echo "========================================="
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user