Description
These are some ideas and notes to make it easier to track and solicit feedback. Please do not think this is a PR. This is sort of like requirements documentation. I'd like a little discussion on these before I make a file PR and work on it there. I've implemented most of this already, but it's not consumable by others... I'm grabbing some of the things that worked for me and putting them here. There's gonna be spelling errors and things that are seemingly misplaced or not make total sense because I'm pulling from several different prototypes I went through getting my successful deployment.
In short, to get a viable hardware encoding enabled multi-arch image consistently built while simultaneously supporting a number of different deployment patterns, we're gonna need an overhaul to the build system.
Make is already there, so I used it. I also used ArgoCD, and can make arguments for others as well. Personally, I find using this approach to make very convenient and handy at forcing better development habits for myself.
I'd love some thoughts and feedback.
MediaCMS Build Configurations
These are stored as build/[build-config].env
and contain variables that alter the build behavior and resulting image outputs.
Supported builds configurations include:
full
- Builds a typical full MediaCMS image runtime and frontend (not started)frontend
- Builds the NodeJS image needed for independent frontend development or generating static contentall-in-one
- Builds a "kitchen sink" deployment without the garbage disposal
MediaCMS Deployment Configurations
These are stored as deploy/[container-runtime]/[deployment-config].env
and contain variables that alter the deployment patterns behavior and resulting image outputs.
Supported deployment types are:
local_install
- no containers, only useful for python and node developmentsimple
- The main container runsmigrations
,web
,uwsgi
,celery_beat
,celery_workers
(celery_short
andcelery_long
services), exposed on port 80 supported byredis
andpostgres
database, accessed ashttp://localhost
simple-letsencrypt
-simple
with a ssl certificate through letsencrypt service, accessed ashttps://mediacms.io
advanced
- Separate containers runmigrations
,mediacms_web
(web
anduwsgi
),celery_beat
,celery_workers
(celery_short
andcelery_long
services), exposed on port 80 supported byredis
andpostgres
database, accessed ashttp://localhost
advanced-letsencrypt
-advanced
with a ssl certificate through letsencrypt service, accessed ashttps://mediacms.io
advanced-reverse-proxy
-advanced
with reverse proxy, accessed ashttp://mediacms.io
advanced-reverse-proxy-letsencrypt
-advanced-reverse-proxy
with a ssl certificate through letsencrypt service, accessed ashttps://mediacms.io
advanced-hardware-encoder
- Separate containers run migrations, web, uwsgi, celery_beat, celery_short, and celery_long services, exposed on port 80 supported byredis
andpostgres
database, accessed as http://localhost
It is common to copy one of the examples and customize the environment variables appropriately.
MediaCMS Services
-
SERVICES = db redis migration celery celery_workers celery_beat celery_long celery_short frontend uwsgi web
-
db
- PostgreSQL for most application components -
redis
- In memory cache for task queues migration celery_beat celery_long celery_short uwsgi frontend web -
migration
- is a Django container meant to handle database migration scripts to accomodate application changes and to collect static content, is typically one-shot started after the databases, but before the rest of the components. It can safely be run after all services on online, running and operational. -
celery
- Task executor service comprised of three different services listening to different queues: beat, long, short- Can be built, deployed and managed as a single unit,
celery_workers
but is actually broken intocelery_beat
,celery_short
,celery_long
- Can be built, deployed and managed as a single unit,
-
celery_beat
- Watches for heartbeats and other internal application messages posting to the beat queue, ideally always the first celery worker to start and last to stop -
celery_long
- Primarily pulls trancoding jobs from the long queue and performing the encoding -
celery_short
- Watches for short tasks, such as sending e-mail and other light transcoding needs -
frontend
- NodeJS application found in ./frontend/, it generates the front end application as static content or run as a server for development/debugging of the web interface -
uwsgi
- is mainly the backend service for the web front end handling API calls and typical web application needs -
web
- an nginx server that serves static content and proxies requests to the uwsgi service
NOTE: It should be common practice to run all of the celery workers in a single deployment container, however, scalable deployments would separate the workers accordingly
NOTE: Currently celery_long workers
are the only workers that will utilize hardware encoding, if specified hardware and the image supports it
MediaCMS Environment Variables
MediaCMS is managed either by a local_settings.py
file or set using one or more environment variables.
NOTE: mediacms/cms/settings.py
is configured to prioritize local_settings.py
however, ALL settings can be configured with MEDIACMS_*
environment variables.
A brief list environment variables is:
MEDIACMS_ACCOUNT_AUTHENTICATION_METHOD
MEDIACMS_ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS
MEDIACMS_ACCOUNT_EMAIL_REQUIRED
...
... a WHOLE bunch of them. all of them. from settings.py. all safe typed and have sane defaults. currently overridden by local_settings.py if present.
...
MEDIACMS_ADMINS_NOTIFICATIONS_MEDIA_ADDED
MEDIACMS_ADMINS_NOTIFICATIONS_MEDIA_ENCODED
MEDIACMS_ADMINS_NOTIFICATIONS_MEDIA_REPORTED
Directory Structure
./Makefile
: Main entry point../build/
:./build/Makefile.[component]
: Generic component makefiles../build/Makefile.[component].[runtime]
: Runtime-specific makefiles../build/[build-config].env
: Build environment files (e.g.,all-in-one
,full
,frontend
)../build/scripts/
:- Shell scripts (e.g.,
setup_env.sh
,setup_precommit.sh
).
- Shell scripts (e.g.,
./deploy/
:./deploy/kubectl/
: Deployments and runtime files for kubernetes based runtimes./deploy/kubectl/[deployment-config].env
: Deployment environment variables for full builds for kubernetes based runtimes (simple
,advanced
, etc)./deploy/docker/
: Deployments and runtime files for docker/podman based runtimes./deploy/docker/[deployment-config].env
: Deployment environment variables for simple builds for docker/podman based runtimes
./deploy/local_install/
: Configurations related to the local_install deployment./deploy/local_install/.env
: Deployment environment files for the local_install (not really supported)
Makefile Structure
- Indentation: Use tabs (not spaces) for indentation, as required by GNU Make.
- Component Makefiles: Organize targets into logically grouped files:
Makefile.admin
: Administrative tasks (e.g., shells, container operations).Makefile.build
: Build-related tasks (e.g., compiling, container images).Makefile.deploy
: Deployment tasks (e.g., service deployment).Makefile.development
: Development tools and workflows.Makefile.frontend
: Frontend Node.js application tasks.Makefile.manage
: Application management (e.g., Django static content, operations and python shell).Makefile.legacy
: Deprecated targets for backward compatibility.
- Container Runtime Variants: Include runtime-specific makefiles (e.g.,
Makefile.build.kubectl
,Makefile.build.docker
) where applicable.
Makefile Environment Variables (Makefile Format)
The important ones are:
CONTAINER_RUNTIME=kubectl
BUILD=full
DEPLOYMENT=simple
# Shared Configuration, represents start up order
CONTAINER_RUNTIME ?= kubectl
BUILD_DIR = build
DEPLOY_DIR = deploy/$(CONTAINER_RUNTIME)
# Can be full or simple
BUILDS = full all-in-one frontend
BUILD ?= full
BUILD_ENV ?= $(BUILD_DIR)/env/$(BUILD).env
BUILD_ENV_ALL_IN_ONE_DOCKERFILE ?= $(BUILD_DIR)/Dockerfile
BUILD_ENV_FRONTEND_DOCKERFILE ?= $(BUILD_DIR)/Dockerfile-multi-arch-frontend
BUILD_ENV_FULL_DOCKERFILE ?= $(BUILD_DIR)/Dockerfile-multi-arch
BUILD_ENV_DOCKERFILE ?= $(BUILD_ENV_FULL_DOCKERFILE)
# Can be advanced or simple
DEPLOYMENT_TYPES ?= simple simple-reverse-proxy advanced advanced-reverse-proxy advanced-hardware-encoding
DEPLOYMENT_TYPE ?= advanced
DEPLOYMENT_LOCAL_INSTALL ?= deploy/local_install/.env
DEPLOYMENT ?= $(DEPLOY_DIR)/.env.$(DEPLOYMENT_TYPE)
# Should be overriden by the deployment
SERVICES ?= db redis migration celery celery_beat celery_long celery_short uwsgi frontend web
# CLI Configuration
CLI_ENV = cli-tool/.env
# Kubectl
NAMESPACE = mediacms
KUBECTL = kubectl -n $(NAMESPACE)
K8S_DIR = $(BUILD_DIR)/$(CONTAINER_RUNTIME)
# Docker/Podman
COMPOSE_FILE = docker-compose-multi-arch.yaml
As a prototype of my thoughts, here is an initial just checked out now what example:
$ make
MediaCMS Build System
Usage: make [target]
Available Categories:
build - Build-related tasks
deploy - Deployment tasks
manage - Application management
development - Development tools and workflows
frontend - Frontend Node.js application tasks
admin - Administrative tasks
workflows - Show common workflow examples
legacy - Deprecated targets
Use 'make help-[category]' for details, e.g., 'make help-workflows'
$ make help-workflows
MediaCMS Workflows
Development Workflow:
make feature NAME=[name] - Create a feature branch
Ex: make feature NAME=new-feature
make bug NAME=[name] - Create a bug branch
Ex: make bug NAME=fix-login
make changed-from BRANCH=[branch] - Show changed files from a branch
Ex: make changed-from BRANCH=main
make diff BRANCH=[branch] - Show diff from a branch
Ex: make diff BRANCH=main
make squash BRANCH=[branch] - Squash commits into a new branch (WARNING: modifies git history)
Ex: make squash BRANCH=feat/new-feature
make report-bug - Print bug report template
make request-feature - Print feature request template
make submit-pr - Print pull request template
Build Workflow:
make build-[config] - Build the specified configuration
Ex: make build-full
Note: For kubectl, this creates a suspended build job. Use 'start-build' to resume it.
make start-build CONFIG=[config] - Start the build job (kubectl only)
Ex: make start-build CONFIG=full
make logs-build CONFIG=[config] - Monitor build logs
Ex: make logs-build CONFIG=full
make status-build CONFIG=[config] - Check build status
Ex: make status-build CONFIG=full
Deployment Workflow:
make setup-deploy TYPE=[type] - Configure deployment settings
Ex: make setup-deploy TYPE=production
make deploy-[config] - Deploy a specific configuration, (`simple`, `advanced`, etc)
Ex: make deploy-simple
make status-deploy CONFIG=[config] - Check deployment status
Ex: make status-deploy CONFIG=simple
make restart-[deployment] - Restart a deployment
Ex: make restart-advanced
make stop-[deployment] - Stop a deployment
Ex: make stop-advanced
Management Workflow:
make setup-cli - Configure the CLI tool
make migration - Run database migrations
make createsuperuser - Create a superuser
make collectstatic - Collect static files
make loaddata FILE=[file] - Load data from a JSON file
Ex: make loaddata FILE=fixtures/data.json
make logs-[service] - View logs for a service
Ex: make logs-web
make shell-[service] - Open a shell to a service
Ex: make shell-web
make shell-admin - Open a python shell to a service
Ex: make shell-admin SERVICE=web
Testing Workflow:
make test-all - Run all tests
make test-[test] - Run a specific test
Ex: make test-pytest
make test-pytest - Run tests for python runtime
make test-kubectl - Run tests for kubectl runtime
make test-docker - Run tests for docker runtime
make test-podman - Run tests for podman runtime
Convenience Targets:
make build-and-deploy - Build all configurations and deploy all services
make clean-all - Clean all build and deployment artifacts
Functionally I need this so I have more control over volume mounts... seems a long way around to get it.
LOL!
Looking forward to hearing some opinions.