refactor: Single image serving both API (8081) and Streamlit (3000)
All checks were successful
armco-org/visual-search-engine/pipeline/head This commit was not built
All checks were successful
armco-org/visual-search-engine/pipeline/head This commit was not built
- Combine API and Streamlit into single Dockerfile - Add entrypoint.sh to run both services in parallel - Reduces Harbor storage from 2.66GB to 1.33GB - Single build instead of two
This commit is contained in:
37
Dockerfile
37
Dockerfile
@@ -1,5 +1,5 @@
|
||||
# Reverse Image Search API
|
||||
# Multi-stage build for optimized image size
|
||||
# Visual Search Engine - API (8081) + Streamlit UI (3000)
|
||||
# Single image serving both endpoints
|
||||
|
||||
FROM python:3.11-slim as builder
|
||||
|
||||
@@ -19,12 +19,12 @@ FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime dependencies (libgomp for OpenMP parallelism)
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libgomp1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# FAISS uses OpenMP for parallel search - set threads for Xeon
|
||||
# FAISS OpenMP threads
|
||||
ENV OMP_NUM_THREADS=8
|
||||
|
||||
# Copy installed packages from builder
|
||||
@@ -36,29 +36,30 @@ COPY api/ ./api/
|
||||
COPY config.py .
|
||||
COPY reverse_icon_search.py .
|
||||
COPY run_api_server.py .
|
||||
COPY main_streamlit.py .
|
||||
COPY entrypoint.sh .
|
||||
|
||||
# Copy pre-built index and filenames for inference
|
||||
# Option 1: Bundle in image (~530 MB)
|
||||
# Copy pre-built index and filenames
|
||||
COPY index.faiss .
|
||||
COPY filenames.pkl .
|
||||
|
||||
# Option 2: Mount as volume at runtime (uncomment above, use docker run -v)
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p uploads logs
|
||||
# Create necessary directories and make entrypoint executable
|
||||
RUN mkdir -p uploads logs && chmod +x entrypoint.sh
|
||||
|
||||
# Environment variables
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV API_PORT=5002
|
||||
ENV API_PORT=8081
|
||||
ENV DEBUG=false
|
||||
ENV STREAMLIT_SERVER_PORT=3000
|
||||
ENV STREAMLIT_SERVER_ADDRESS=0.0.0.0
|
||||
|
||||
# Expose port
|
||||
EXPOSE 5002
|
||||
# Expose both ports
|
||||
EXPOSE 8081 3000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:5002/api/health')" || exit 1
|
||||
# Health check on API
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8081/api/health')" || exit 1
|
||||
|
||||
# Run the application
|
||||
CMD ["python", "run_api_server.py"]
|
||||
# Run both services
|
||||
CMD ["./entrypoint.sh"]
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# Reverse Image Search API
|
||||
# Uses pre-built base image with TensorFlow to avoid repeated downloads
|
||||
|
||||
FROM harbor.armco.dev/library/visualsearch-base:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy application code
|
||||
COPY api/ ./api/
|
||||
COPY config.py .
|
||||
COPY reverse_icon_search.py .
|
||||
COPY run_api_server.py .
|
||||
|
||||
# Copy pre-built index and filenames for inference
|
||||
COPY index.faiss .
|
||||
COPY filenames.pkl .
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p uploads logs
|
||||
|
||||
# Environment variables
|
||||
ENV API_PORT=8081
|
||||
ENV DEBUG=false
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8081
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8081/api/health')" || exit 1
|
||||
|
||||
# Run the application
|
||||
CMD ["python", "run_api_server.py"]
|
||||
@@ -1,26 +0,0 @@
|
||||
# Base image with TensorFlow and heavy dependencies pre-installed
|
||||
# Build once, reuse for API and Streamlit builds
|
||||
# Tag: harbor.armco.dev/library/visualsearch-base:latest
|
||||
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
libgomp1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy and install requirements
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# FAISS uses OpenMP for parallel search
|
||||
ENV OMP_NUM_THREADS=8
|
||||
ENV PATH=/root/.local/bin:$PATH
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Clean up build dependencies to reduce image size
|
||||
RUN apt-get purge -y build-essential && apt-get autoremove -y
|
||||
@@ -1,32 +0,0 @@
|
||||
# Reverse Image Search Streamlit UI
|
||||
# Uses pre-built base image with TensorFlow to avoid repeated downloads
|
||||
|
||||
FROM harbor.armco.dev/library/visualsearch-base:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy application code
|
||||
COPY config.py .
|
||||
COPY reverse_icon_search.py .
|
||||
COPY main_streamlit.py .
|
||||
|
||||
# Copy pre-built index and filenames for inference
|
||||
COPY index.faiss .
|
||||
COPY filenames.pkl .
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p uploads logs
|
||||
|
||||
# Environment variables
|
||||
ENV STREAMLIT_SERVER_PORT=3000
|
||||
ENV STREAMLIT_SERVER_ADDRESS=0.0.0.0
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:3000/_stcore/health')" || exit 1
|
||||
|
||||
# Run Streamlit
|
||||
CMD ["streamlit", "run", "main_streamlit.py", "--server.port=3000", "--server.address=0.0.0.0"]
|
||||
7
Jenkinsfile
vendored
7
Jenkinsfile
vendored
@@ -1,14 +1,11 @@
|
||||
@Library('jenkins-shared@main') _
|
||||
|
||||
// NOTE: Build base image first when requirements.txt changes:
|
||||
// [imageName: 'visualsearch-base', dockerfile: 'Dockerfile.base']
|
||||
// Then rebuild API and Streamlit images
|
||||
// Single image serves both API (8081) and Streamlit UI (3000)
|
||||
|
||||
kanikoPipeline(
|
||||
repoName: 'visual-search-engine',
|
||||
branch: env.BRANCH_NAME ?: 'main',
|
||||
builds: [
|
||||
[imageName: 'visualsearch', dockerfile: 'Dockerfile.api'],
|
||||
[imageName: 'visualsearch-stl', dockerfile: 'Dockerfile.streamlit']
|
||||
[imageName: 'visualsearch', dockerfile: 'Dockerfile']
|
||||
]
|
||||
)
|
||||
|
||||
17
entrypoint.sh
Normal file
17
entrypoint.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Run both API server (8081) and Streamlit UI (3000) in parallel
|
||||
|
||||
# Start API server in background
|
||||
python run_api_server.py &
|
||||
API_PID=$!
|
||||
|
||||
# Start Streamlit in background
|
||||
streamlit run main_streamlit.py --server.port=3000 --server.address=0.0.0.0 &
|
||||
STL_PID=$!
|
||||
|
||||
# Wait for either to exit
|
||||
wait -n $API_PID $STL_PID
|
||||
|
||||
# If one exits, kill the other and exit
|
||||
kill $API_PID $STL_PID 2>/dev/null
|
||||
exit 1
|
||||
Reference in New Issue
Block a user