add source code and readme
This commit is contained in:
95
build/piefed/piefed-base/Dockerfile
Normal file
95
build/piefed/piefed-base/Dockerfile
Normal file
@@ -0,0 +1,95 @@
|
||||
# Multi-stage build for smaller final image
|
||||
FROM python:3.11-alpine AS builder
|
||||
|
||||
# Use HTTP repositories to avoid SSL issues, then install dependencies
|
||||
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/main" > /etc/apk/repositories \
|
||||
&& echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/community" >> /etc/apk/repositories \
|
||||
&& apk update \
|
||||
&& apk add --no-cache \
|
||||
pkgconfig \
|
||||
gcc \
|
||||
python3-dev \
|
||||
musl-dev \
|
||||
postgresql-dev \
|
||||
linux-headers \
|
||||
bash \
|
||||
git \
|
||||
curl
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# v1.3.x
|
||||
ARG PIEFED_VERSION=main
|
||||
RUN git clone https://codeberg.org/rimu/pyfedi.git /app \
|
||||
&& cd /app \
|
||||
&& git checkout ${PIEFED_VERSION} \
|
||||
&& rm -rf .git
|
||||
|
||||
# Install Python dependencies to /app/venv
|
||||
RUN python -m venv /app/venv \
|
||||
&& source /app/venv/bin/activate \
|
||||
&& pip install --no-cache-dir -r requirements.txt \
|
||||
&& pip install --no-cache-dir uwsgi
|
||||
|
||||
# Runtime stage - much smaller
|
||||
FROM python:3.11-alpine AS runtime
|
||||
|
||||
# Set environment variables
|
||||
ENV TZ=UTC
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PATH="/app/venv/bin:$PATH"
|
||||
|
||||
# Install only runtime dependencies
|
||||
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/main" > /etc/apk/repositories \
|
||||
&& echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/community" >> /etc/apk/repositories \
|
||||
&& apk update \
|
||||
&& apk add --no-cache \
|
||||
ca-certificates \
|
||||
curl \
|
||||
su-exec \
|
||||
dcron \
|
||||
libpq \
|
||||
jpeg \
|
||||
freetype \
|
||||
lcms2 \
|
||||
openjpeg \
|
||||
tiff \
|
||||
nginx \
|
||||
supervisor \
|
||||
redis \
|
||||
bash \
|
||||
tesseract-ocr \
|
||||
tesseract-ocr-data-eng
|
||||
|
||||
# Create piefed user
|
||||
RUN addgroup -g 1000 piefed \
|
||||
&& adduser -u 1000 -G piefed -s /bin/sh -D piefed
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy application and virtual environment from builder
|
||||
COPY --from=builder /app /app
|
||||
COPY --from=builder /app/venv /app/venv
|
||||
|
||||
# Compile translations (matching official Dockerfile)
|
||||
RUN source /app/venv/bin/activate && \
|
||||
(pybabel compile -d app/translations || true)
|
||||
|
||||
# Set proper permissions - ensure logs directory is writable for dual logging
|
||||
RUN chown -R piefed:piefed /app \
|
||||
&& mkdir -p /app/logs /app/app/static/tmp /app/app/static/media \
|
||||
&& chown -R piefed:piefed /app/logs /app/app/static/tmp /app/app/static/media \
|
||||
&& chmod -R 755 /app/logs /app/app/static/tmp /app/app/static/media \
|
||||
&& chmod 777 /app/logs
|
||||
|
||||
# Copy shared entrypoint utilities
|
||||
COPY entrypoint-common.sh /usr/local/bin/entrypoint-common.sh
|
||||
COPY entrypoint-init.sh /usr/local/bin/entrypoint-init.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint-common.sh /usr/local/bin/entrypoint-init.sh
|
||||
|
||||
# Create directories for logs and runtime
|
||||
RUN mkdir -p /var/log/piefed /var/run/piefed \
|
||||
&& chown -R piefed:piefed /var/log/piefed /var/run/piefed
|
||||
83
build/piefed/piefed-base/entrypoint-common.sh
Normal file
83
build/piefed/piefed-base/entrypoint-common.sh
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Common initialization functions for PieFed containers
|
||||
|
||||
log() {
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
||||
}
|
||||
|
||||
# Wait for database to be available
|
||||
wait_for_db() {
|
||||
log "Waiting for database connection..."
|
||||
until python -c "
|
||||
import psycopg2
|
||||
import os
|
||||
from urllib.parse import urlparse
|
||||
|
||||
try:
|
||||
# Parse DATABASE_URL
|
||||
database_url = os.environ.get('DATABASE_URL', '')
|
||||
if not database_url:
|
||||
raise Exception('DATABASE_URL not set')
|
||||
|
||||
# Parse the URL to extract connection details
|
||||
parsed = urlparse(database_url)
|
||||
conn = psycopg2.connect(
|
||||
host=parsed.hostname,
|
||||
port=parsed.port or 5432,
|
||||
database=parsed.path[1:], # Remove leading slash
|
||||
user=parsed.username,
|
||||
password=parsed.password
|
||||
)
|
||||
conn.close()
|
||||
print('Database connection successful')
|
||||
except Exception as e:
|
||||
print(f'Database connection failed: {e}')
|
||||
exit(1)
|
||||
" 2>/dev/null; do
|
||||
log "Database not ready, waiting 2 seconds..."
|
||||
sleep 2
|
||||
done
|
||||
log "Database connection established"
|
||||
}
|
||||
|
||||
# Wait for Redis to be available
|
||||
wait_for_redis() {
|
||||
log "Waiting for Redis connection..."
|
||||
until python -c "
|
||||
import redis
|
||||
import os
|
||||
|
||||
try:
|
||||
cache_redis_url = os.environ.get('CACHE_REDIS_URL', '')
|
||||
if cache_redis_url:
|
||||
r = redis.from_url(cache_redis_url)
|
||||
else:
|
||||
# Fallback to separate host/port for backwards compatibility
|
||||
r = redis.Redis(host='redis', port=6379, password=os.environ.get('REDIS_PASSWORD', ''))
|
||||
r.ping()
|
||||
print('Redis connection successful')
|
||||
except Exception as e:
|
||||
print(f'Redis connection failed: {e}')
|
||||
exit(1)
|
||||
" 2>/dev/null; do
|
||||
log "Redis not ready, waiting 2 seconds..."
|
||||
sleep 2
|
||||
done
|
||||
log "Redis connection established"
|
||||
}
|
||||
|
||||
# Common startup sequence
|
||||
common_startup() {
|
||||
log "Starting PieFed common initialization..."
|
||||
|
||||
# Change to application directory
|
||||
cd /app
|
||||
|
||||
# Wait for dependencies
|
||||
wait_for_db
|
||||
wait_for_redis
|
||||
|
||||
log "Common initialization completed"
|
||||
}
|
||||
108
build/piefed/piefed-base/entrypoint-init.sh
Normal file
108
build/piefed/piefed-base/entrypoint-init.sh
Normal file
@@ -0,0 +1,108 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Database initialization entrypoint for PieFed
|
||||
# This script runs as a Kubernetes Job before web/worker pods start
|
||||
|
||||
log() {
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
||||
}
|
||||
|
||||
log "Starting PieFed database initialization..."
|
||||
|
||||
# Wait for database to be available
|
||||
wait_for_db() {
|
||||
log "Waiting for database connection..."
|
||||
until python -c "
|
||||
import psycopg2
|
||||
import os
|
||||
from urllib.parse import urlparse
|
||||
|
||||
try:
|
||||
# Parse DATABASE_URL
|
||||
database_url = os.environ.get('DATABASE_URL', '')
|
||||
if not database_url:
|
||||
raise Exception('DATABASE_URL not set')
|
||||
|
||||
# Parse the URL to extract connection details
|
||||
parsed = urlparse(database_url)
|
||||
conn = psycopg2.connect(
|
||||
host=parsed.hostname,
|
||||
port=parsed.port or 5432,
|
||||
database=parsed.path[1:], # Remove leading slash
|
||||
user=parsed.username,
|
||||
password=parsed.password
|
||||
)
|
||||
conn.close()
|
||||
print('Database connection successful')
|
||||
except Exception as e:
|
||||
print(f'Database connection failed: {e}')
|
||||
exit(1)
|
||||
" 2>/dev/null; do
|
||||
log "Database not ready, waiting 2 seconds..."
|
||||
sleep 2
|
||||
done
|
||||
log "Database connection established"
|
||||
}
|
||||
|
||||
# Wait for Redis to be available
|
||||
wait_for_redis() {
|
||||
log "Waiting for Redis connection..."
|
||||
until python -c "
|
||||
import redis
|
||||
import os
|
||||
|
||||
try:
|
||||
cache_redis_url = os.environ.get('CACHE_REDIS_URL', '')
|
||||
if cache_redis_url:
|
||||
r = redis.from_url(cache_redis_url)
|
||||
else:
|
||||
# Fallback to separate host/port for backwards compatibility
|
||||
r = redis.Redis(host='redis', port=6379, password=os.environ.get('REDIS_PASSWORD', ''))
|
||||
r.ping()
|
||||
print('Redis connection successful')
|
||||
except Exception as e:
|
||||
print(f'Redis connection failed: {e}')
|
||||
exit(1)
|
||||
" 2>/dev/null; do
|
||||
log "Redis not ready, waiting 2 seconds..."
|
||||
sleep 2
|
||||
done
|
||||
log "Redis connection established"
|
||||
}
|
||||
|
||||
# Main initialization sequence
|
||||
main() {
|
||||
# Change to application directory
|
||||
cd /app
|
||||
|
||||
# Wait for dependencies
|
||||
wait_for_db
|
||||
wait_for_redis
|
||||
|
||||
# Run database migrations
|
||||
log "Running database migrations..."
|
||||
export FLASK_APP=pyfedi.py
|
||||
|
||||
# Run Flask database migrations
|
||||
flask db upgrade
|
||||
log "Database migrations completed"
|
||||
|
||||
# Populate community search index
|
||||
log "Populating community search..."
|
||||
flask populate_community_search
|
||||
log "Community search populated"
|
||||
|
||||
# Ensure log files have correct ownership for dual logging (file + stdout)
|
||||
if [ -f /app/logs/pyfedi.log ]; then
|
||||
chown piefed:piefed /app/logs/pyfedi.log
|
||||
chmod 664 /app/logs/pyfedi.log
|
||||
log "Fixed log file ownership for piefed user"
|
||||
fi
|
||||
|
||||
log "Database initialization completed successfully!"
|
||||
}
|
||||
|
||||
# Run the main function
|
||||
main
|
||||
|
||||
Reference in New Issue
Block a user