first commit
This commit is contained in:
14
.dockerignore
Normal file
14
.dockerignore
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.dockerignore
|
||||||
|
**/Dockerfile
|
||||||
|
**/Makefile
|
||||||
|
**/docker-compose.yml
|
||||||
|
**/README.md
|
||||||
|
**/__pycache__
|
||||||
|
**/.venv
|
||||||
|
**/.env
|
||||||
|
**/*.pyc
|
||||||
|
**/*.pyo
|
||||||
|
**/*.pyd
|
||||||
|
guide.md
|
||||||
112
.gitignore
vendored
Normal file
112
.gitignore
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other info into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak
|
||||||
|
venv.bak
|
||||||
|
|
||||||
|
# IDE / Editor specific
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
.docker/
|
||||||
|
docker-compose.override.yml# AI-specific exclusions
|
||||||
|
.claude/
|
||||||
|
.gemini/
|
||||||
|
.geminiignore
|
||||||
|
*.log
|
||||||
7
DesktopPopOS
Normal file
7
DesktopPopOS
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
QyNTUxOQAAACD2Ngm3v/8gcw1+KQWA2RS8KW14lWN3WlFVQWOnkxt7ggAAAJhedgRjXnYE
|
||||||
|
YwAAAAtzc2gtZWQyNTUxOQAAACD2Ngm3v/8gcw1+KQWA2RS8KW14lWN3WlFVQWOnkxt7gg
|
||||||
|
AAAEDWLbOUG/mRh4cfxs16DNf01/f6MRWk5wAhyXTPMn98VPY2Cbe//yBzDX4pBYDZFLwp
|
||||||
|
bXiVY3daUVVBY6eTG3uCAAAAEXMud2lsa2Vuc0BnbXgubmV0AQIDBA==
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
||||||
1
DesktopPopOS.pub
Normal file
1
DesktopPopOS.pub
Normal file
@ -0,0 +1 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPY2Cbe//yBzDX4pBYDZFLwpbXiVY3daUVVBY6eTG3uC s.wilkens@gmx.net
|
||||||
41
Dockerfile
Normal file
41
Dockerfile
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# --- Builder Stage ---
|
||||||
|
# This stage installs all Python dependencies into a virtual environment.
|
||||||
|
FROM python:3.11 as builder
|
||||||
|
|
||||||
|
WORKDIR /opt/venv
|
||||||
|
|
||||||
|
# Create a virtual environment
|
||||||
|
RUN python -m venv .
|
||||||
|
|
||||||
|
# Activate the virtual environment and install dependencies
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN . /opt/venv/bin/activate && pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
|
||||||
|
# --- Runner Stage ---
|
||||||
|
# This stage creates the final, lean image.
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Create a non-privileged user for security
|
||||||
|
RUN useradd --create-home --shell /bin/bash appuser
|
||||||
|
|
||||||
|
WORKDIR /home/appuser/app
|
||||||
|
|
||||||
|
# Copy the virtual environment from the builder stage
|
||||||
|
COPY --from=builder /opt/venv /opt/venv
|
||||||
|
|
||||||
|
# Copy the application code
|
||||||
|
COPY app/ .
|
||||||
|
|
||||||
|
# Set the PATH to include the venv binaries
|
||||||
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
|
||||||
|
# Expose the port the app runs on
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Switch to the non-privileged user
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Command to run the application using Gunicorn
|
||||||
|
# This is a production-ready WSGI server.
|
||||||
|
CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-w", "2", "-b", "0.0.0.0:8000", "main:app"]
|
||||||
131
Makefile
Normal file
131
Makefile
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# Makefile for managing the Dockerized Python application
|
||||||
|
|
||||||
|
# --- Configuration ---
|
||||||
|
# Use the current directory name as the default image name
|
||||||
|
IMAGE_NAME := $(shell basename $(CURDIR))
|
||||||
|
# Default tag
|
||||||
|
TAG := latest
|
||||||
|
# Placeholder for a remote registry (e.g., your Docker Hub username or Gitea instance)
|
||||||
|
# For Gitea: REGISTRY ?= your-gitea-host:port/owner
|
||||||
|
# Example: REGISTRY ?= localhost:3000/myuser
|
||||||
|
REGISTRY ?= your-registry-username
|
||||||
|
|
||||||
|
# Default internal application port (exposed to Traefik)
|
||||||
|
PORT := 8000
|
||||||
|
|
||||||
|
|
||||||
|
# Function to find next free host port for the app and ask user
|
||||||
|
# This function will echo the chosen port if successful, or exit with an error.
|
||||||
|
define check_app_port_free
|
||||||
|
@local start_port=$(PORT); \
|
||||||
|
local found_port=$$start_port; \
|
||||||
|
local is_free=false; \
|
||||||
|
\
|
||||||
|
if ! ss -tulnp | grep ":$$start_port " > /dev/null; then \
|
||||||
|
echo "$$start_port"; \
|
||||||
|
exit 0; \
|
||||||
|
fi; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. Searching for a free port for the app..."; >&2; \
|
||||||
|
while ! $$is_free; do \
|
||||||
|
if ! ss -tulnp | grep ":$$found_port " > /dev/null; then \
|
||||||
|
is_free=true; \
|
||||||
|
else \
|
||||||
|
((found_port++)); \
|
||||||
|
if [ "$$found_port" -gt 65535 ]; then \
|
||||||
|
echo "ERROR: No free ports found up to 65535. Aborting." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. I found port $$found_port to be free for the app." >&2; \
|
||||||
|
read -p "Do you want to use port $$found_port for the app? (y/N): " choice; \
|
||||||
|
case "$$choice" in \
|
||||||
|
y|Y ) \
|
||||||
|
echo "$$found_port"; \
|
||||||
|
;; \
|
||||||
|
* ) \
|
||||||
|
echo "Operation cancelled by user." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
;; \
|
||||||
|
esac;
|
||||||
|
endef
|
||||||
|
|
||||||
|
# --- Docker Commands ---
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
@echo "Building Docker image: $(IMAGE_NAME):$(TAG)"
|
||||||
|
docker build -t $(IMAGE_NAME):$(TAG) .
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run:
|
||||||
|
@export SELECTED_HOST_PORT=$(shell bash -c 'func() { $(check_app_port_free) }; func') && \
|
||||||
|
echo "Using host port $$SELECTED_HOST_PORT for single app container" && \
|
||||||
|
docker run -d -p $$SELECTED_HOST_PORT:$(PORT) --name $(IMAGE_NAME) $(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: stop
|
||||||
|
stop:
|
||||||
|
@echo "Stopping Docker container: $(IMAGE_NAME)"
|
||||||
|
docker stop $(IMAGE_NAME) || true
|
||||||
|
docker rm $(IMAGE_NAME) || true
|
||||||
|
|
||||||
|
.PHONY: logs
|
||||||
|
logs:
|
||||||
|
@echo "Showing logs for container: $(IMAGE_NAME)"
|
||||||
|
docker logs -f $(IMAGE_NAME)
|
||||||
|
|
||||||
|
.PHONY: shell
|
||||||
|
shell:
|
||||||
|
@echo "Accessing shell in container: $(IMAGE_NAME)"
|
||||||
|
docker exec -it $(IMAGE_NAME) /bin/bash
|
||||||
|
|
||||||
|
# --- Docker Compose Commands ---
|
||||||
|
|
||||||
|
.PHONY: up
|
||||||
|
up:
|
||||||
|
@echo "Starting development environment with Docker Compose (integrating with external Traefik)..."
|
||||||
|
docker-compose up --build -d
|
||||||
|
|
||||||
|
.PHONY: down
|
||||||
|
down:
|
||||||
|
@echo "Stopping development environment with Docker Compose..."
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# --- Image Management ---
|
||||||
|
|
||||||
|
.PHONY: tag
|
||||||
|
tag:
|
||||||
|
@echo "Tagging image $(IMAGE_NAME):$(TAG) as $(REGISTRY)/$(IMAGE_NAME):$(TAG)"
|
||||||
|
docker tag $(IMAGE_NAME):$(TAG) $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: push
|
||||||
|
push: tag
|
||||||
|
@echo "Pushing image $(REGISTRY)/$(IMAGE_NAME):$(TAG) to registry..."
|
||||||
|
docker push $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
# --- Cleanup ---
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning up stopped containers and dangling images..."
|
||||||
|
docker container prune -f
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@echo "Available commands:"
|
||||||
|
@echo " build - Build the Docker image"
|
||||||
|
@echo " run - Run the Docker container"
|
||||||
|
@echo " stop - Stop and remove the Docker container"
|
||||||
|
@echo " logs - Follow the logs of the container"
|
||||||
|
@echo " shell - Get a shell inside the running container"
|
||||||
|
@echo " up - Start the dev environment with docker-compose (integrates with external Traefik)"
|
||||||
|
@echo " down - Stop the dev environment with docker-compose"
|
||||||
|
@echo " tag - Tag the image for a registry"
|
||||||
|
@echo " push - Push the image to a registry (after tagging)"
|
||||||
|
@echo " clean - Clean up unused containers and images"
|
||||||
|
@echo " help - Show this help message"
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
61
README.md
Normal file
61
README.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# ✨ Python Backend Containerization Guide ✨
|
||||||
|
|
||||||
|
## 🚀 Starte deine Python-Anwendung mit Docker!
|
||||||
|
|
||||||
|
Dieses Repository bietet dir eine **umfassende und praktische Anleitung**, um deine Python-Backend-Anwendungen effizient und professionell mit Docker zu containerisieren. Egal, ob du eine schnelle Entwicklungsumgebung oder einen robusten Produktions-Workflow suchst – hier bist du richtig!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🎉 Schnellstart – Deine App in wenigen Sekunden online!
|
||||||
|
|
||||||
|
Befolge diese Schritte, um die Beispiel-FastAPI-Anwendung sofort zum Laufen zu bringen:
|
||||||
|
|
||||||
|
1. **Stelle sicher, dass Docker läuft.**
|
||||||
|
*(Prüfe, ob Docker Desktop oder der Docker Daemon aktiv ist.)*
|
||||||
|
|
||||||
|
2. **Stelle sicher, dass Traefik läuft und das 'web'-Netzwerk bereitstellt.**
|
||||||
|
*(Die App integriert sich in eine **bestehende** Traefik-Instanz. Eine Beispiel-`docker-compose-traefik.yml` findest du in `guide.md`.)*
|
||||||
|
|
||||||
|
3. **Navigiere ins Projektverzeichnis:**
|
||||||
|
```bash
|
||||||
|
cd python-container-guide
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Starte die Entwicklungsumgebung (integriert sich in deinen Traefik-Router):**
|
||||||
|
```bash
|
||||||
|
make up
|
||||||
|
```
|
||||||
|
*💡 Dieser Befehl startet deine FastAPI-Anwendung und verbindet sie mit dem 'web'-Netzwerk deines laufenden Traefik. Die Portprüfung für Traefik selbst musst du extern vornehmen, da diese App Traefik nicht startet.*
|
||||||
|
|
||||||
|
5. **Greife auf deine Anwendung zu:**
|
||||||
|
Öffne deinen Webbrowser und besuche: `http://localhost`
|
||||||
|
*(Dein externer Traefik sollte die Anfrage automatisch zur FastAPI-Anwendung weiterleiten.)*
|
||||||
|
|
||||||
|
6. **Beende die Entwicklungsumgebung:**
|
||||||
|
```bash
|
||||||
|
make down
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🌟 Was du hier findest:
|
||||||
|
|
||||||
|
* **FastAPI Beispiel:** Eine einfache, aber vollständige Python-Webanwendung.
|
||||||
|
* **Optimales `Dockerfile`:** Für schnelle, kleine und sichere Docker-Images dank Multi-Stage-Builds.
|
||||||
|
* **`docker-compose.yml`:** Konfiguriert deine lokale Entwicklungsumgebung, um sich in einen **externen Traefik** zu integrieren und Hot-Reloading zu ermöglichen.
|
||||||
|
* **Integration in Traefik:** Zeigt, wie deine App sich in einen bestehenden Traefik Reverse Proxy einklinkt – ideal für Microservices und eine produktionsnahe lokale Umgebung.
|
||||||
|
* **`Makefile`:** Vereinfacht alle Docker-Befehle (`build`, `run`, `stop`, `push`) zu intuitiven Kommandos.
|
||||||
|
* **Interaktive Port-Wahl:** Bei Konflikten schlägt das System freie Ports vor – nie wieder Port-Chaos! (Besonders nützlich für `make run`, wenn du die App *ohne Traefik* starten willst).
|
||||||
|
* **Best Practices:** Sorgfältig konfigurierte `.gitignore` und `.dockerignore` für saubere Repositories und schlanke Images.
|
||||||
|
* **Umfassende Dokumentation:** Eine detaillierte `guide.md` erklärt jedes Konzept im Detail.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📚 Tauche tiefer ein:
|
||||||
|
|
||||||
|
Für alle Details, Best Practices und fortgeschrittene Themen empfehlen wir dir unsere Guides:
|
||||||
|
|
||||||
|
* **Der Haupt-Leitfaden:** `guide.md` – Hier findest du alles rund um die Containerisierung deiner Python-Anwendung.
|
||||||
|
* **Gitea Container Registry Guide:** `gitea-registry-guide.md` – Erfahre, wie du Gitea als deine private Docker Container Registry einrichtest und nutzt.
|
||||||
|
|
||||||
|
Viel Erfolg beim Containerisieren!
|
||||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
11
app/main.py
Normal file
11
app/main.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def read_root():
|
||||||
|
return {"message": "Hello World"}
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health_check():
|
||||||
|
return {"status": "ok"}
|
||||||
21
docker-compose.yml
Normal file
21
docker-compose.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./app:/home/appuser/app
|
||||||
|
command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# Define a router for the app service
|
||||||
|
- "traefik.http.routers.app-router.rule=Host(`localhost`)"
|
||||||
|
- "traefik.http.routers.app-router.entrypoints=web"
|
||||||
|
# Define the service port (internal to the container)
|
||||||
|
- "traefik.http.services.app-service.loadbalancer.server.port=8000"
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: true # This network is assumed to be created by a central Traefik instance
|
||||||
166
gitea-registry-guide.md
Normal file
166
gitea-registry-guide.md
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
# Anleitung: Gitea als Container Registry bereitstellen und konfigurieren
|
||||||
|
|
||||||
|
Diese Anleitung beschreibt, wie Sie eine Gitea-Instanz bereitstellen und so konfigurieren, dass sie auch als private Docker Container Registry funktioniert. Dies ist besonders nützlich für Teams oder Projekte, die eine integrierte Lösung für Code- und Image-Verwaltung suchen.
|
||||||
|
|
||||||
|
## 1. Einleitung
|
||||||
|
|
||||||
|
Gitea ist ein leichtgewichtiger, selbst gehosteter Git-Dienst, der auch Funktionen wie Issue Tracking, Code-Review und seit Version 1.12 eine integrierte Container Registry bietet. Die Verwendung einer Gitea-Registry ermöglicht es Ihnen, Ihre Docker-Images direkt neben Ihrem Quellcode zu hosten und zu verwalten.
|
||||||
|
|
||||||
|
## 2. Voraussetzungen
|
||||||
|
|
||||||
|
* **Docker und Docker Compose:** Für die einfache Bereitstellung von Gitea.
|
||||||
|
* **Domainname oder IP-Adresse:** Die unter der Gitea erreichbar sein soll.
|
||||||
|
* **Offener Port 3000 (HTTP) und optional 22 (SSH) und 443 (HTTPS) auf dem Host-System.**
|
||||||
|
|
||||||
|
## 3. Gitea mit Docker Compose bereitstellen
|
||||||
|
|
||||||
|
Wir verwenden Docker Compose, um Gitea zusammen mit einer PostgreSQL-Datenbank bereitzustellen. Erstellen Sie eine `docker-compose.yml` in einem neuen Verzeichnis (z.B. `gitea-setup`):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:1.21.11 # Aktuelle stabile Version verwenden
|
||||||
|
container_name: gitea
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
- GITEA__database__DB_TYPE=postgres
|
||||||
|
- GITEA__database__HOST=db:5432
|
||||||
|
- GITEA__database__NAME=gitea
|
||||||
|
- GITEA__database__USER=gitea
|
||||||
|
- GITEA__database__PASS=gitea_password # Starkes Passwort wählen!
|
||||||
|
- GITEA__server__ROOT_URL=http://your_gitea_domain_or_ip:3000/ # Wichtig: Anpassen!
|
||||||
|
- GITEA__server__SSH_DOMAIN=your_gitea_domain_or_ip # Optional, wenn SSH genutzt wird
|
||||||
|
- GITEA__server__DISABLE_SSH=false # Optional, wenn SSH genutzt wird
|
||||||
|
- GITEA__container_registry__ENABLED=true # Container Registry aktivieren
|
||||||
|
- GITEA__container_registry__MAX_TAGS_PER_REPOSITORY=10 # Optional: Anzahl Tags pro Repo begrenzen
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "3000:3000" # Gitea HTTP Port
|
||||||
|
- "2222:22" # Gitea SSH Port (intern 22, extern 2222)
|
||||||
|
volumes:
|
||||||
|
- ./gitea_data:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
networks:
|
||||||
|
- gitea_network
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:15
|
||||||
|
container_name: gitea_db
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=gitea
|
||||||
|
- POSTGRES_PASSWORD=gitea_password # Muss mit GITEA__database__PASS übereinstimmen
|
||||||
|
- POSTGRES_DB=gitea
|
||||||
|
volumes:
|
||||||
|
- ./postgres_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- gitea_network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gitea_network:
|
||||||
|
driver: bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
**Erste Schritte nach dem Start:**
|
||||||
|
|
||||||
|
1. Speichern Sie die Konfiguration als `docker-compose.yml`.
|
||||||
|
2. Starten Sie die Dienste im Verzeichnis der Datei: `docker-compose up -d`.
|
||||||
|
3. Öffnen Sie einen Browser und navigieren Sie zu `http://your_gitea_domain_or_ip:3000/`.
|
||||||
|
4. Folgen Sie dem Initialisierungsassistenten. Achten Sie darauf, dass die Datenbankeinstellungen korrekt sind (sollten aus den Umgebungsvariablen übernommen werden).
|
||||||
|
5. Erstellen Sie den ersten Administrator-Benutzer.
|
||||||
|
|
||||||
|
## 4. Container Registry Konfiguration (nachträglich)
|
||||||
|
|
||||||
|
Obwohl wir `GITEA__container_registry__ENABLED=true` in der `docker-compose.yml` gesetzt haben, kann es sein, dass die Registry nachträglich aktiviert oder angepasst werden muss, oder Sie Gitea ohne diese Einstellung bereitgestellt haben.
|
||||||
|
|
||||||
|
1. **Gitea-Konfigurationsdatei finden:**
|
||||||
|
Die Konfigurationsdatei von Gitea ist `app.ini`. Sie befindet sich normalerweise im `gitea_data`-Volume, das wir gemountet haben, unter `/data/gitea/conf/app.ini` *innerhalb des Gitea-Containers*.
|
||||||
|
|
||||||
|
Um die Datei zu bearbeiten, können Sie entweder:
|
||||||
|
* Den Gitea-Container stoppen, die Datei im gemounteten Volume (z.B. `./gitea_data/gitea/conf/app.ini`) auf Ihrem Host bearbeiten und Gitea neu starten.
|
||||||
|
* Über `docker exec` in den Container gehen und die Datei mit einem Editor wie `vi` oder `nano` (falls installiert) bearbeiten. Dies ist oft komplizierter.
|
||||||
|
|
||||||
|
2. **`app.ini` bearbeiten:**
|
||||||
|
Suchen Sie in der `app.ini` den Abschnitt `[container_registry]`. Falls er nicht existiert, fügen Sie ihn hinzu. Stellen Sie sicher, dass `ENABLED = true` gesetzt ist:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[container_registry]
|
||||||
|
ENABLED = true
|
||||||
|
# MAX_TAGS_PER_REPOSITORY = 10 # Optional: Begrenzt die Anzahl der Tags pro Repository
|
||||||
|
```
|
||||||
|
Weitere Optionen können hier konfiguriert werden, z.B. Speicherlimits oder Zugriffsrechte.
|
||||||
|
|
||||||
|
3. **Gitea neu starten:**
|
||||||
|
Nach Änderungen an der `app.ini` müssen Sie den Gitea-Container neu starten, damit die Änderungen wirksam werden:
|
||||||
|
```bash
|
||||||
|
docker-compose restart gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Nutzung der Gitea Container Registry
|
||||||
|
|
||||||
|
Sobald die Registry aktiviert ist, können Sie sie wie jede andere Docker Registry verwenden.
|
||||||
|
|
||||||
|
**Authentifizierung:**
|
||||||
|
|
||||||
|
Bevor Sie Images pushen oder pullen können, müssen Sie sich bei Ihrer Gitea Registry anmelden. Verwenden Sie dafür Ihre Gitea-Benutzerdaten:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker login your_gitea_domain_or_ip:3000
|
||||||
|
```
|
||||||
|
Ersetzen Sie `your_gitea_domain_or_ip:3000` durch die tatsächliche Adresse und Port Ihrer Gitea-Instanz.
|
||||||
|
|
||||||
|
**Image Tagging:**
|
||||||
|
|
||||||
|
Images müssen nach folgendem Muster getaggt werden:
|
||||||
|
`your_gitea_domain_or_ip:3000/benutzername/repository-name:tag`
|
||||||
|
|
||||||
|
* `your_gitea_domain_or_ip:3000`: Die Adresse Ihrer Gitea-Instanz.
|
||||||
|
* `benutzername`: Der Gitea-Benutzer oder die Organisation, unter der das Repository liegt.
|
||||||
|
* `repository-name`: Der Name des Gitea-Repositories, das mit dem Image verknüpft werden soll. Gitea erstellt automatisch ein Container-Image-Repository, wenn Sie das erste Image pushen.
|
||||||
|
* `tag`: Ein beliebiges Tag (z.B. `latest`, `v1.0.0`, ein Commit-Hash).
|
||||||
|
|
||||||
|
**Beispiel:**
|
||||||
|
|
||||||
|
Angenommen, Ihre Gitea ist unter `mygitea.com:3000` erreichbar, Ihr Benutzername ist `devuser`, und Sie haben ein Git-Repository namens `my-python-app`.
|
||||||
|
|
||||||
|
1. **Image bauen (wie in unserem Haupt-Leitfaden beschrieben):**
|
||||||
|
```bash
|
||||||
|
make build # Baut my-python-app:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Image taggen für Gitea:**
|
||||||
|
```bash
|
||||||
|
docker tag my-python-app:latest mygitea.com:3000/devuser/my-python-app:latest
|
||||||
|
```
|
||||||
|
Oder über den `make`-Befehl aus unserem Haupt-Leitfaden:
|
||||||
|
```bash
|
||||||
|
make tag REGISTRY=mygitea.com:3000/devuser
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Image pushen:**
|
||||||
|
```bash
|
||||||
|
docker push mygitea.com:3000/devuser/my-python-app:latest
|
||||||
|
```
|
||||||
|
Oder über den `make`-Befehl aus unserem Haupt-Leitfaden:
|
||||||
|
```bash
|
||||||
|
make push REGISTRY=mygitea.com:3000/devuser
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Image pullen:**
|
||||||
|
```bash
|
||||||
|
docker pull mygitea.com:3000/devuser/my-python-app:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Sicherheitsaspekte
|
||||||
|
|
||||||
|
* **HTTPS:** Für eine produktive Gitea-Instanz im Netzwerk wird dringend empfohlen, HTTPS zu konfigurieren. Dies schützt Ihre Anmeldeinformationen und Image-Daten während der Übertragung. Traefik kann hierfür auch verwendet werden, um HTTPS für Gitea zu terminieren.
|
||||||
|
* **Zugriffsrechte:** Verwalten Sie die Berechtigungen für Container-Image-Repositories in Gitea wie für Git-Repositories.
|
||||||
|
|
||||||
|
---
|
||||||
|
Dieser Leitfaden sollte Ihnen helfen, Gitea erfolgreich als Ihre private Container Registry zu nutzen.
|
||||||
300
guide.md
Normal file
300
guide.md
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
# Leitfaden: Best Practices zur Containerisierung von Python-Backends
|
||||||
|
|
||||||
|
Dieser Leitfaden zeigt einen professionellen Workflow zur Containerisierung einer Python-Backend-Anwendung mit Docker. Wir fokussieren uns auf die Integration in eine bereits bestehende Reverse-Proxy-Infrastruktur wie Traefik für die lokale Entwicklung. Wir verwenden eine minimale FastAPI-Anwendung als Beispiel.
|
||||||
|
|
||||||
|
Die vorgestellten Methoden umfassen:
|
||||||
|
- Optimierte, sichere Docker-Images durch Multi-Stage-Builds.
|
||||||
|
- Einen einfachen Workflow durch die Verwendung eines `Makefile`.
|
||||||
|
- Trennung von Entwicklungs- und Produktionsumgebungen.
|
||||||
|
- Korrekte Verwaltung von Code und Images mit Git und einer Container Registry.
|
||||||
|
- Integration in eine bestehende Traefik-Infrastruktur für dynamisches Routing.
|
||||||
|
|
||||||
|
## 1. Projektstruktur
|
||||||
|
|
||||||
|
Wir haben die folgende Struktur erstellt:
|
||||||
|
|
||||||
|
```
|
||||||
|
/
|
||||||
|
├── .dockerignore # Listet Dateien auf, die Docker ignorieren soll.
|
||||||
|
├── .gitignore # Listet Dateien auf, die Git ignorieren soll.
|
||||||
|
├── Dockerfile # Die Blaupause für unser produktives Docker-Image.
|
||||||
|
├── Makefile # Vereinfacht die Ausführung von Docker-Befehlen.
|
||||||
|
├── app/
|
||||||
|
│ ├── __init__.py # Macht 'app' zu einem Python-Paket.
|
||||||
|
│ └── main.py # Unser FastAPI-Anwendungscode.
|
||||||
|
├── docker-compose.yml # Definiert die lokale Entwicklungsumgebung (integriert sich in externen Traefik).
|
||||||
|
├── guide.md # Dieser Leitfaden.
|
||||||
|
└── requirements.txt # Liste der Python-Abhängigkeiten.
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Die Komponenten im Detail
|
||||||
|
|
||||||
|
### `requirements.txt`
|
||||||
|
Hier definieren wir die Python-Bibliotheken, die unser Projekt benötigt.
|
||||||
|
```
|
||||||
|
fastapi
|
||||||
|
uvicorn[standard]
|
||||||
|
gunicorn
|
||||||
|
```
|
||||||
|
- `fastapi`: Das Web-Framework.
|
||||||
|
- `uvicorn`: Ein schneller ASGI-Server, ideal für die Entwicklung.
|
||||||
|
- `gunicorn`: Ein robuster WSGI-Produktionsserver, der Uvicorn-Worker zur Ausführung unserer ASGI-Anwendung nutzt.
|
||||||
|
|
||||||
|
### `.gitignore` & `.dockerignore`
|
||||||
|
- **`.gitignore`**: Verhindert, dass sensible Daten (`.env`), temporäre Dateien (`__pycache__`) oder lokale Konfigurationen (`.vscode/`) in Git eingecheckt werden.
|
||||||
|
- **`.dockerignore`**: Verhindert, dass unnötige oder sensible Dateien in das Docker-Image kopiert werden. Dies hält das Image klein und sicher. Wir schließen z.B. das `.git`-Verzeichnis, das `Dockerfile` selbst und lokale Umgebungsdateien aus.
|
||||||
|
|
||||||
|
### `app/main.py`
|
||||||
|
Eine minimale FastAPI-Anwendung mit zwei Endpunkten.
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def read_root():
|
||||||
|
return {"message": "Hello World"}
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health_check():
|
||||||
|
return {"status": "ok"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Dockerfile` (Multi-Stage-Build)
|
||||||
|
Dies ist das Herzstück unserer Containerisierung. Ein Multi-Stage-Build trennt die Build-Umgebung von der Laufzeitumgebung.
|
||||||
|
|
||||||
|
**Stufe 1: `builder`**
|
||||||
|
```dockerfile
|
||||||
|
FROM python:3.11 as builder
|
||||||
|
WORKDIR /opt/venv
|
||||||
|
RUN python -m venv .
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN . /opt/venv/bin/activate && pip install --no-cache-dir -r requirements.txt
|
||||||
|
```
|
||||||
|
- Wir starten mit einem vollständigen Python-Image.
|
||||||
|
- Erstellen ein virtuelles Environment (`venv`) und installieren die Abhängigkeiten hinein.
|
||||||
|
- Das Ergebnis ist ein Ordner `/opt/venv` mit einer sauberen Python-Umgebung.
|
||||||
|
|
||||||
|
**Stufe 2: `runner` (Das finale Image)**
|
||||||
|
```dockerfile
|
||||||
|
FROM python:3.11-slim
|
||||||
|
RUN useradd --create-home --shell /bin/bash appuser
|
||||||
|
WORKDIR /home/appuser/app
|
||||||
|
COPY --from=builder /opt/venv /opt/venv
|
||||||
|
COPY app/ .
|
||||||
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
EXPOSE 8000
|
||||||
|
USER appuser
|
||||||
|
CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-w", "2", "-b", "0.0.0.0:8000", "main:app"]
|
||||||
|
```
|
||||||
|
- Wir starten mit einem minimalen `-slim`-Image.
|
||||||
|
- **Sicherheit**: Wir erstellen einen unprivilegierten Benutzer `appuser`. Die Anwendung wird als dieser Benutzer ausgeführt.
|
||||||
|
- Wir kopieren das `venv` aus der `builder`-Stufe und unseren App-Code.
|
||||||
|
- **Produktions-Server**: Wir starten die App mit `gunicorn` und 2 `uvicorn`-Workern. Dies ist ein stabiles Setup für die Produktion.
|
||||||
|
|
||||||
|
### `docker-compose.yml` (Für die lokale Entwicklung, Integration in externen Traefik)
|
||||||
|
Diese Datei definiert unsere lokale Entwicklungsumgebung für die Anwendung und integriert sie in eine **bereits bestehende und extern verwaltete Traefik-Instanz**.
|
||||||
|
|
||||||
|
**Konzept der Integration:**
|
||||||
|
Anstatt Traefik bei jedem Start der Anwendung neu zu deployen, gehen wir davon aus, dass Traefik bereits als zentraler Reverse Proxy auf dem Host-System oder in einem separaten `docker-compose`-Setup läuft. Unsere Anwendung verbindet sich einfach mit dem von Traefik bereitgestellten Docker-Netzwerk und Traefik erkennt die Anwendung über Labels.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./app:/home/appuser/app
|
||||||
|
command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# Definiert einen Router für den App-Dienst
|
||||||
|
- "traefik.http.routers.app-router.rule=Host(`localhost`)"
|
||||||
|
- "traefik.http.routers.app-router.entrypoints=web"
|
||||||
|
# Definiert den internen Port des Dienstes (im Container)
|
||||||
|
- "traefik.http.services.app-service.loadbalancer.server.port=8000"
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: true # Dieses Netzwerk wird von einer externen Traefik-Instanz bereitgestellt
|
||||||
|
```
|
||||||
|
- **`app` Service**: Konfiguriert unsere Anwendung. Die Labels sind entscheidend für die Erkennung durch Traefik:
|
||||||
|
- `traefik.enable=true`: Aktiviert die Erkennung durch Traefik.
|
||||||
|
- `traefik.http.routers.app-router.rule=Host('localhost')`: Sagt Traefik, dass Anfragen an den Host `localhost` an diesen Dienst geleitet werden sollen. Dies kann auf einen spezifischen Domainnamen angepasst werden, wenn Traefik entsprechend konfiguriert ist.
|
||||||
|
- `traefik.http.routers.app-router.entrypoints=web`: Verknüpft diesen Router mit dem `web`-Entrypoint von Traefik (üblicherweise Port 80).
|
||||||
|
- `traefik.http.services.app-service.loadbalancer.server.port=8000`: Informiert Traefik über den internen Port des FastAPI-Dienstes.
|
||||||
|
- **`networks: web`**: Deklariert ein **externes Netzwerk**. Das bedeutet, dass dieses Netzwerk nicht von diesem `docker-compose.yml` erstellt, sondern von einem anderen Dienst (in unserem Fall Traefik) bereitgestellt wird. Unsere Anwendung tritt diesem Netzwerk bei.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Beispiel für eine zentrale Traefik-Bereitstellung (separates `docker-compose.yml`)**
|
||||||
|
|
||||||
|
Damit die obige Konfiguration funktioniert, muss eine Traefik-Instanz laufen, die das `web`-Netzwerk bereitstellt. Hier ist ein Beispiel, wie eine solche zentrale Traefik-Instanz bereitgestellt werden könnte (dies ist ein *separates* `docker-compose.yml`, das an anderer Stelle ausgeführt wird):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose-traefik.yml (Beispiel für zentrale Traefik-Bereitstellung)
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: "traefik:v2.10"
|
||||||
|
container_name: traefik
|
||||||
|
command:
|
||||||
|
- "--api.dashboard=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false" # Nur Dienste mit traefik.enable=true exposen
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
- "--entrypoints.websecure.address=:443" # Optional: Für HTTPS
|
||||||
|
ports:
|
||||||
|
- "80:80" # HTTP
|
||||||
|
- "443:443" # Optional: HTTPS
|
||||||
|
- "8080:8080" # Traefik Dashboard
|
||||||
|
volumes:
|
||||||
|
- "/var/run/docker.sock:/var/run/docker.sock:ro" # Traefik braucht Zugriff auf den Docker-Daemon
|
||||||
|
# - "./traefik-certs:/etc/traefik/certs" # Optional: Für HTTPS Zertifikate
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: false # Dieses Netzwerk wird von dieser Traefik-Instanz erstellt und verwaltet
|
||||||
|
```
|
||||||
|
Dieses `docker-compose-traefik.yml` würde in einem eigenen Verzeichnis gestartet (`docker-compose up -d`) und würde das `web`-Netzwerk erzeugen, in das sich dann unsere Anwendungs-`docker-compose.yml` einklinken kann.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `Makefile` (Der Kommando-Runner)
|
||||||
|
Das `Makefile` gibt uns einfache Befehle für komplexe Aktionen. Es wurde angepasst, um die Integration in einen externen Traefik widerzuspiegeln. Die spezifischen Traefik-Port-Checks wurden entfernt, da diese außerhalb der Verantwortung dieser Anwendung liegen.
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
# --- Configuration ---
|
||||||
|
# Use the current directory name as the default image name
|
||||||
|
IMAGE_NAME := $(shell basename $(CURDIR))
|
||||||
|
# Default tag
|
||||||
|
TAG := latest
|
||||||
|
# Placeholder for a remote registry (e.g., your Docker Hub username or Gitea instance)
|
||||||
|
# For Gitea: REGISTRY ?= your-gitea-host:port/owner
|
||||||
|
# Example: REGISTRY ?= localhost:3000/myuser
|
||||||
|
REGISTRY ?= your-registry-username
|
||||||
|
|
||||||
|
# Default internal application port (exposed to Traefik)
|
||||||
|
PORT := 8000
|
||||||
|
|
||||||
|
# Function to find next free host port for the app and ask user
|
||||||
|
# This function will echo the chosen port if successful, or exit with an error.
|
||||||
|
define check_app_port_free
|
||||||
|
@local start_port=$(PORT); \
|
||||||
|
local found_port=$$start_port; \
|
||||||
|
local is_free=false; \
|
||||||
|
\
|
||||||
|
if ! ss -tulnp | grep ":$$start_port " > /dev/null; then \
|
||||||
|
echo "$$start_port"; \
|
||||||
|
exit 0; \
|
||||||
|
fi; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. Searching for a free port for the app..."; >&2; \
|
||||||
|
while ! $$is_free; do \
|
||||||
|
if ! ss -tulnp | grep ":$$found_port " > /dev/null; then \
|
||||||
|
is_free=true; \
|
||||||
|
else \
|
||||||
|
((found_port++)); \
|
||||||
|
if [ "$$found_port" -gt 65535 ]; then \
|
||||||
|
echo "ERROR: No free ports found up to 65535. Aborting." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. I found port $$found_port to be free for the app." >&2; \
|
||||||
|
read -p "Do you want to use port $$found_port for the app? (y/N): " choice; \
|
||||||
|
case "$$choice" in \
|
||||||
|
y|Y ) \
|
||||||
|
echo "$$found_port"; \
|
||||||
|
;; \
|
||||||
|
* ) \
|
||||||
|
echo "Operation cancelled by user." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
;; \
|
||||||
|
esac;
|
||||||
|
endef
|
||||||
|
|
||||||
|
# --- Docker Commands ---
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
@echo "Building Docker image: $(IMAGE_NAME):$(TAG)"
|
||||||
|
docker build -t $(IMAGE_NAME):$(TAG) .
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run:
|
||||||
|
@export SELECTED_HOST_PORT=$$(bash -c 'func() { $(check_app_port_free) }; func') && \
|
||||||
|
echo "Using host port $$SELECTED_HOST_PORT for single app container" && \
|
||||||
|
docker run -d -p $$SELECTED_HOST_PORT:$(PORT) --name $(IMAGE_NAME) $(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: stop
|
||||||
|
stop:
|
||||||
|
@echo "Stopping Docker container: $(IMAGE_NAME)"
|
||||||
|
docker stop $(IMAGE_NAME) || true
|
||||||
|
docker rm $(IMAGE_NAME) || true
|
||||||
|
|
||||||
|
.PHONY: logs
|
||||||
|
logs:
|
||||||
|
@echo "Showing logs for container: $(IMAGE_NAME)"
|
||||||
|
docker logs -f $(IMAGE_NAME)
|
||||||
|
|
||||||
|
.PHONY: shell
|
||||||
|
shell:
|
||||||
|
@echo "Accessing shell in container: $(IMAGE_NAME)"
|
||||||
|
docker exec -it $(IMAGE_NAME) /bin/bash
|
||||||
|
|
||||||
|
# --- Docker Compose Commands ---
|
||||||
|
|
||||||
|
.PHONY: up
|
||||||
|
up:
|
||||||
|
@echo "Starting development environment with Docker Compose (integrating with external Traefik)..."
|
||||||
|
docker-compose up --build -d
|
||||||
|
|
||||||
|
.PHONY: down
|
||||||
|
down:
|
||||||
|
@echo "Stopping development environment with Docker Compose..."
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# --- Image Management ---
|
||||||
|
|
||||||
|
.PHONY: tag
|
||||||
|
tag:
|
||||||
|
@echo "Tagging image $(IMAGE_NAME):$(TAG) as $(REGISTRY)/$(IMAGE_NAME):$(TAG)"
|
||||||
|
docker tag $(IMAGE_NAME):$(TAG) $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: push
|
||||||
|
push: tag
|
||||||
|
@echo "Pushing image $(REGISTRY)/$(IMAGE_NAME):$(TAG) to registry..."
|
||||||
|
docker push $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
# --- Cleanup ---
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning up stopped containers and dangling images..."
|
||||||
|
docker container prune -f
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@echo "Available commands:"
|
||||||
|
@echo " build - Build the Docker image"
|
||||||
|
@echo " run - Run the Docker container (single app, no Traefik)"
|
||||||
|
@echo " stop - Stop and remove the Docker container"
|
||||||
|
@echo " logs - Follow the logs of the container"
|
||||||
|
@echo " shell - Get a shell inside the running container"
|
||||||
|
@echo " up - Start the dev environment with docker-compose (integrates with external Traefik)"
|
||||||
|
@echo " down - Stop the dev environment with docker-compose"
|
||||||
|
@echo " tag - Tag the image for a registry"
|
||||||
|
@echo " push - Push the image to a registry (after tagging)"
|
||||||
|
@echo " clean - Clean up unused containers and images"
|
||||||
|
@echo " help - Show this help message"
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fastapi
|
||||||
|
uvicorn[standard]
|
||||||
|
gunicorn
|
||||||
Reference in New Issue
Block a user