-
Notifications
You must be signed in to change notification settings - Fork 36
ADR: replace apache #506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
MikolajKasprzak
wants to merge
10
commits into
main
Choose a base branch
from
adr-0003
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+130
β0
Draft
ADR: replace apache #506
Changes from 2 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
7ff4a89
ADR: replace apache
MikolajKasprzak cc063a4
Merge branch 'main' into adr-0003
MikolajKasprzak af80c07
change adr number & fix lint issues
MikolajKasprzak de81aca
Address code review comment
saratpoluri 62e2d29
Merge branch 'main' into adr-0003
saratpoluri 6328a88
Merge branch 'main' into adr-0003
saratpoluri 0c34a94
Merge branch 'main' into adr-0003
ltalarcz 8c6cdd0
Merge branch 'main' into adr-0003
MikolajKasprzak 0914a3d
change status to accepted
MikolajKasprzak 839f488
Merge branch 'main' into adr-0003
saratpoluri File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| # ADR 3: Replace Apache with Nginx + Gunicorn for Manager Service | ||
|
|
||
| - **Author(s)**: [Mikolaj Kasprzak](https://github.com/MikolajKasprzak) | ||
| - **Date**: 2025-10-21 | ||
| - **Status**: Proposed | ||
|
|
||
| ## Context | ||
|
|
||
| The SceneScape Manager service was originally hosted using Apache with mod_wsgi, which introduced several operational and security challenges: | ||
|
|
||
| ### Key Problems: | ||
| 1. **Security vulnerabilities**: Apache required root privileges for initialization, creating unnecessary attack surface | ||
| 2. **Complex configuration**: Multi-layered Apache configuration with mod_wsgi, SSL termination, and proxy rules was difficult to maintain | ||
| 3. **Volume permission issues**: Dynamic UID/GID changes led to unreliable file system permissions | ||
| 4. **Deployment complexity**: Monolithic container with Apache + Django made scaling and debugging difficult | ||
| 5. **Resource overhead**: Apache's process model was heavier than needed for a Python web application | ||
|
|
||
| ### Technical Debt: | ||
| - Complex initialization scripts (`scenescape-init`, `webserver-init`) with root privilege requirements | ||
| - Dynamic user/group ID management causing permission denied errors | ||
| - Mixed responsibilities in single container (web server + application server) | ||
| - Legacy configuration files and unused dependencies | ||
|
|
||
| The system needed a more secure, maintainable, and cloud-native architectu re aligned with modern containerization best practices. | ||
|
|
||
| ## Decision | ||
|
|
||
| We will replace the Apache + mod_wsgi architecture with a **Nginx + Gunicorn** separation of concerns approach: | ||
|
|
||
| ### New Architecture: | ||
|
|
||
| #### Docker Compose Deployment: | ||
| 1. **Manager Container**: | ||
| - Runs Gunicorn WSGI server as unprivileged user | ||
| - Serves Django application on internal port 8000 | ||
| - Simplified entrypoint script without root privileges | ||
|
|
||
| 2. **Nginx Container**: | ||
| - Handles SSL/TLS termination (HTTPS on port 443) | ||
| - Serves static files efficiently | ||
| - Proxies dynamic requests to Gunicorn | ||
| - Manages WebSocket proxy for MQTT broker | ||
| - Runs as separate service for better isolation | ||
|
|
||
| #### Kubernetes Deployment: | ||
| 1. **Sidecar Pattern**: | ||
| - **Django Container**: Gunicorn WSGI server on port 8000 | ||
| - **Nginx Sidecar**: Static files and internal routing within Pod | ||
| - **Broker**: Kubernetes ingress should be sufficient no need for sidecar | ||
| - Shared volumes for static files and media between containers | ||
| - Communication over localhost within Pod | ||
|
|
||
| 2. **Kubernetes Ingress**: | ||
| - Handles external traffic routing and SSL/TLS termination | ||
| - Can manage certificate lifecycle with cert-manager | ||
| - Routes HTTP/HTTPS traffic to nginx sidecar | ||
| - Provides load balancing and high availability | ||
|
|
||
| 3. **Volume Management**: | ||
| - Init container sets proper permissions once at startup | ||
| - Fixed UID/GID (1000:1000) eliminates dynamic user changes | ||
| - Shared emptyDir volumes for static files within Pod | ||
|
|
||
| ### Configuration Changes: | ||
|
|
||
| #### Docker Compose: | ||
| - Replace complex Apache config with simple nginx.conf | ||
| - Eliminate `webserver-init` and `scenescape-init` scripts | ||
| - Use single `entrypoint.sh` for Django initialization | ||
| - Add CSRF trusted origins for reverse proxy setup | ||
|
|
||
| #### Kubernetes: | ||
| - Helm chart with sidecar nginx configuration | ||
| - Kubernetes Ingress resource for external access | ||
| - ConfigMaps for nginx configuration | ||
| - Init containers for static file collection | ||
| - Service mesh ready architecture (if there is requirement for TLS in internal network) | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| ### Option A: Nginx + Gunicorn with Kubernetes Sidecar (Selected) | ||
| - **Pros**: Industry standard, security best practices, clean separation, excellent performance, Kubernetes-native | ||
| - **Cons**: Requires container architecture changes, initial migration effort, slightly more complex Pod spec | ||
|
|
||
| ### Option B: Pure Kubernetes Ingress (Considered) | ||
| - **Pros**: Fully cloud-native, managed SSL, automatic scaling | ||
| - **Cons**: Complex static file handling, limited WebSocket support, MQTT proxy challenges | ||
|
|
||
| ### Option C: Use WhiteNoise | ||
| - **Pros**: Can be used on top of Option B, static files handled by Whitenoise, no need for nginx sidecar | ||
| - **Cons**: Manager code changes | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Positive | ||
|
|
||
| - **Enhanced Security**: No root privileges required in application container | ||
| - **Simplified Maintenance**: Clean separation of concerns | ||
| - **Improved Scalability**: Independent scaling of web server and application server | ||
| - **Reduced Attack Surface**: Minimal container with only necessary components | ||
| - **Easier Debugging**: Clear separation between infrastructure (nginx) and application (django) | ||
| - **Volume Reliability**: Fixed permissions eliminate dynamic UID/GID issues for manager and apache user | ||
| - **Kubernetes Native**: Sidecar pattern enables proper cloud-native deployment | ||
| - **TLS Management**: Kubernetes Ingress with cert-manager or different solution for automatic certificate lifecycle or we can stay with current approach | ||
|
|
||
| ### Negative | ||
|
|
||
| - **Migration Effort**: Requires updating deployment scripts and documentation | ||
| - **Two Containers**: Slightly more complex docker-compose setup | ||
| - **Initial Setup**: Need to configure nginx proxy rules and SSL certificates | ||
| - **Compatibility**: May require CSRF and WebSocket configuration adjustments | ||
|
|
||
|
|
||
| ## References | ||
|
|
||
| - [Nginx official documentation](https://nginx.org/en/docs/) | ||
| - [Gunicorn deployment guide](https://docs.gunicorn.org/en/stable/deploy.html) | ||
| - [Django production deployment best practices](https://docs.djangoproject.com/en/4.2/howto/deployment/) | ||
| - [Container security best practices](https://kubernetes.io/docs/concepts/security/overview/) | ||
| - [Kubernetes Sidecar pattern](https://kubernetes.io/docs/concepts/workloads/pods/) | ||
| - [Kubernetes Ingress controllers](https://kubernetes.io/docs/concepts/services-networking/ingress/) | ||
| - [Kubernetes Init Containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.