ai-engine / Dockerfile
Severian's picture
Update Dockerfile
bcf12b3 verified
raw
history blame
7.67 kB
# Base image
FROM python:3.12-slim-bookworm AS base
# Set shared environment variables
ENV POETRY_VERSION=1.8.4 \
POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_CREATE=true \
POETRY_VIRTUALENVS_IN_PROJECT=true \
POETRY_CACHE_DIR=/tmp/poetry_cache \
PYTHONDONTWRITEBYTECODE=1 \
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
PORT=7860 \
NODE_ENV=production
# Create user first (HF Spaces requirement)
RUN useradd -m -u 1000 user
# Install system dependencies and set up locales
RUN apt-get update && apt-get install -y \
curl \
git \
gcc \
python3-dev \
libgmp-dev \
libmpfr-dev \
libmpc-dev \
nodejs \
npm \
postgresql \
postgresql-contrib \
locales \
nginx \
&& rm -rf /var/lib/apt/lists/* \
&& pip install --no-cache-dir "poetry==${POETRY_VERSION}" \
&& sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \
&& locale-gen
# Configure nginx
RUN rm /etc/nginx/sites-enabled/default || true
COPY <<EOF /etc/nginx/nginx.conf
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream frontend {
server 127.0.0.1:3000;
}
upstream backend {
server 127.0.0.1:5001;
}
server {
listen 7860;
server_name _;
client_max_body_size 100M;
location / {
proxy_pass http://frontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
}
EOF
RUN mkdir -p /var/log/nginx && \
chown -R user:user /var/log/nginx && \
touch /run/nginx.pid && \
chown -R user:user /run/nginx.pid && \
chown -R user:user /var/lib/nginx && \
chmod -R 755 /var/lib/nginx && \
chmod -R 755 /etc/nginx && \
chmod -R 777 /run
# Set up PostgreSQL directories with standard locations
RUN mkdir -p /var/run/postgresql /var/lib/postgresql/data /var/log/postgresql && \
chown -R user:user /var/run/postgresql /var/lib/postgresql/data /var/log/postgresql && \
chmod 700 /var/lib/postgresql/data
# Create application directories
RUN mkdir -p /app/api /app/web /data/storage && \
chown -R user:user /app /data && \
chmod 777 /data /app
# Switch to user for remaining operations
USER user
# Set environment for user
ENV HOME=/home/user \
PATH=/usr/lib/postgresql/15/bin:/home/user/.local/bin:$PATH \
PGDATA=/var/lib/postgresql/data
# Pull official images
FROM langgenius/dify-web:latest AS web
FROM langgenius/dify-api:latest AS api
# Final stage
FROM base
# Set up directory structure
WORKDIR /app
RUN mkdir -p api web /data/storage
# Copy from official images
COPY --from=web --chown=user:user /app/web /app/web/
COPY --from=api --chown=user:user /app/api /app/api/
# Install API dependencies using Poetry
WORKDIR /app/api
COPY --from=api --chown=user /app/api/pyproject.toml /app/api/poetry.lock /app/api/poetry.toml ./
RUN poetry install --no-root --no-dev
# Create symlink for persistent storage
RUN ln -s /data/storage /app/api/storage
# Set environment variables
ENV FLASK_APP=app.py \
EDITION=SELF_HOSTED \
DEPLOY_ENV=PRODUCTION \
MODE=api \
LOG_LEVEL=INFO \
DEBUG=false \
FLASK_DEBUG=false \
SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U \
CONSOLE_API_URL=https://${SPACE_ID}.hf.space \
CONSOLE_WEB_URL=https://${SPACE_ID}.hf.space \
SERVICE_API_URL=https://${SPACE_ID}.hf.space \
APP_WEB_URL=https://${SPACE_ID}.hf.space \
DIFY_PORT=5001 \
DIFY_BIND_ADDRESS=127.0.0.1 \
DB_USERNAME=user \
DB_PASSWORD=difyai123456 \
DB_HOST=localhost \
DB_PORT=5432 \
DB_DATABASE=dify \
PYTHONPATH=/app/api \
STORAGE_PATH=/data/storage
EXPOSE 7860
# Create startup script
RUN echo '#!/bin/bash\n\
set -e\n\
echo "===== Application Startup at $(date "+%Y-%m-%d %H:%M:%S") ====="\n\
\n\
# Initialize PostgreSQL database if not already initialized\n\
if [ ! -f "$PGDATA/PG_VERSION" ]; then\n\
echo "Initializing PostgreSQL database..."\n\
initdb --username=user --pwfile=<(echo "$DB_PASSWORD") --auth=md5 --encoding=UTF8\n\
\n\
# Configure PostgreSQL\n\
echo "local all all trust" > "$PGDATA/pg_hba.conf"\n\
echo "host all all 127.0.0.1/32 md5" >> "$PGDATA/pg_hba.conf"\n\
echo "host all all ::1/128 md5" >> "$PGDATA/pg_hba.conf"\n\
echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf"\n\
\n\
echo "listen_addresses = '\''*'\''" >> "$PGDATA/postgresql.conf"\n\
echo "max_connections = 100" >> "$PGDATA/postgresql.conf"\n\
echo "shared_buffers = 128MB" >> "$PGDATA/postgresql.conf"\n\
fi\n\
\n\
# Start PostgreSQL with detailed logging\n\
echo "Starting PostgreSQL server..."\n\
pg_ctl start -D "$PGDATA" -l /var/log/postgresql/postgresql.log -o "-c logging_collector=on -c log_directory='\''/var/log/postgresql'\'' -c log_filename='\''postgresql-%Y-%m-%d_%H%M%S.log'\'' -c log_statement='\''all'\''" -w\n\
\n\
# Wait for PostgreSQL to start and show logs if there are issues\n\
max_tries=30\n\
count=0\n\
echo "Checking database connection..."\n\
until pg_isready -h localhost -p 5432; do\n\
if [ $count -eq 0 ]; then\n\
echo "PostgreSQL logs:"\n\
tail -n 50 /var/log/postgresql/postgresql.log\n\
fi\n\
echo "Waiting for database connection... (${count}/${max_tries})"\n\
sleep 2\n\
count=$((count+1))\n\
if [ $count -gt $max_tries ]; then\n\
echo "Failed to connect to database after ${max_tries} attempts"\n\
echo "Last 100 lines of PostgreSQL logs:"\n\
tail -n 100 /var/log/postgresql/postgresql.log\n\
exit 1\n\
fi\n\
done\n\
\n\
# Create database if it doesn'\''t exist\n\
if ! psql -lqt | cut -d \| -f 1 | grep -qw dify; then\n\
echo "Creating database dify..."\n\
createdb -U user dify\n\
fi\n\
\n\
echo "Database connection successful"\n\
\n\
# Start application services\n\
cd /app/api && poetry run python -m flask db upgrade\n\
\n\
# Start API server\n\
cd /app/api && poetry run python -m gunicorn app:app \\\n\
--bind ${DIFY_BIND_ADDRESS:-127.0.0.1}:${DIFY_PORT:-5001} \\\n\
--worker-class gevent \\\n\
--workers 1 \\\n\
--timeout 300 \\\n\
--preload &\n\
\n\
# Start frontend server\n\
cd /app/web && PORT=3000 node server.js &\n\
\n\
# Wait for services to be ready\n\
echo "Waiting for services to be ready..."\n\
sleep 5\n\
\n\
# Start nginx\n\
nginx -g "daemon off;" &\n\
\n\
wait' > /app/entrypoint.sh && \
chmod +x /app/entrypoint.sh
WORKDIR /app
CMD ["./entrypoint.sh"]