Two questions come up in every LMS infrastructure conversation, usually in the wrong order. Teams ask "should we use Kubernetes?" long before they ask "what does this platform actually have to survive?" Here is how we answer both, including the part most vendors skip: when the answer is no.
Start with Docker, because the real win is not deployment
Containerising an LMS pays for itself before it ever reaches production. Learning platforms accumulate awkward dependencies — a PDF renderer, video transcoding, a specific Python version, media libraries that behave differently on someone's laptop. A container makes "works on my machine" mean something, and makes the environment a reviewable file instead of tribal knowledge.
The details that matter for an LMS specifically:
FROM python:3.12-slim
# Dependencies first — this layer caches and your rebuilds stay fast.
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
WORKDIR /app
# Never run as root. A learning platform accepts uploaded course
# packages — treat every SCORM zip as untrusted input.
RUN useradd -m -u 1001 app && chown -R app:app /app
USER app
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
That USER app line is not box-ticking. An LMS ingests zip archives from customers and unpacks them, which is a genuine attack surface — a malicious package should not meet a root process. And the layer ordering is deliberate: copy the dependency manifest before the source, or every one-line change reinstalls the world.
The bigger container lesson for learning platforms is that containers are ephemeral and course content is not. Uploaded SCORM packages, learner file submissions and generated certificates must live in a volume or object storage, never in the container filesystem. If your uploads vanish on redeploy, this is why — and it is the most common self-inflicted wound we are called in to fix.
Now the honest part: you probably do not need Kubernetes
A corporate LMS serving a few thousand learners, with usage that peaks when a compliance deadline lands and is otherwise flat, does not need a cluster. It needs a well-specified server, Docker, a managed Postgres, backups you have actually restored from, and a CDN for video. Kubernetes would add an entire discipline of failure modes to solve a scaling problem that this platform does not have.
We say this to clients who arrive asking for Kubernetes, and we mean it. The cost is not the cluster bill — it is that someone now has to understand ingress controllers, storage classes and cert rotation at 2am, and on a small team that person is your only backend developer.
Kubernetes earns its place when at least one of these is genuinely true:
- Bursty enrolment. A public course launch or an exam window takes you from hundreds to tens of thousands of concurrent learners within an hour, then back. Real autoscaling is worth real complexity.
- Multi-tenancy at scale. You run separate environments per institution and are provisioning them constantly.
- Independently scaling components. Video transcoding, a RAG AI tutor and the web app have completely different resource shapes — an embedding workload wants different hardware from a Django request. Scaling them separately is a real argument.
- You already run it. If your team has a cluster and knows it, the marginal cost of one more service is genuinely low.
If none of those are true, Docker on a good server and a boring deployment is not the amateur option — it is the correct engineering decision, and it is what we would recommend even though it bills less.
The probe that everyone gets wrong
If you do run Kubernetes, the LMS-specific trap is health checks. Liveness and readiness are not the same question, and conflating them causes the outage they were meant to prevent:
readinessProbe: # "can I serve traffic right now?"
httpGet:
path: /health/ready # checks DB connectivity
port: 8000
periodSeconds: 5
livenessProbe: # "am I broken and beyond saving?"
httpGet:
path: /health/live # process is up. Does NOT touch the DB.
port: 8000
periodSeconds: 20
failureThreshold: 3
The failure we see: a liveness probe that checks the database. Postgres has a brief hiccup, every pod's liveness fails at once, Kubernetes helpfully restarts every pod simultaneously, and a five-second blip becomes a full outage during an exam. Liveness asks "is this process wedged?" Readiness asks "should traffic come here?" A database problem is a readiness problem.
Two more LMS specifics: set terminationGracePeriodSeconds high enough that a learner's in-flight upload is not severed mid-deploy, and keep sessions out of pod memory — in Postgres or Redis — or every scale-down logs someone out mid-assessment.
What we actually recommend
Containerise everything, always. Then match the orchestration to the traffic you can demonstrate rather than the traffic in the pitch deck. Most learning platforms are steady-state systems with occasional spikes, and that shape is served well by simple infrastructure and a CDN. When a platform genuinely outgrows that, the container work you did on day one is what makes the move cheap.
This is the deployment thinking behind custom LMS development and the AI tutor workloads that sit beside it.
Trying to work out what your platform actually needs to run on? Book a free LMS consultation and we will tell you if the answer is "less than you think".
Sources & Further Reading:
Google Search Central Documentation ·
Moz SEO Blog ·
Search Engine Land
Turn this article into a practical action plan
If this topic affects your site, campaign, or LMS growth path, we can help translate it into changes that actually fit your current setup.
Discuss This TopicFollow the related journey
Use the article as one step, then move into the service, portfolio, or broader blog context around it.