Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/build-and-depoy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Build and Deploy to Azure

on:
push:
branches:
- master
- feature/containerization

jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write

steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Extract metadata
id: meta
run: |
VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml | head -1)
# Get the first 7 characters of the Git commit hash
SHA=${GITHUB_SHA:0:7}

# Save them to the GitHub Environment for later steps
echo "APP_VERSION=$VERSION" >> $GITHUB_ENV
echo "SHORT_SHA=$SHA" >> $GITHUB_ENV


- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set lowercase repository name
run: |
echo "IMAGE_ID=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV

- name: Build and Push Image
run: |
TAG_LATEST=${{ env.IMAGE_ID }}:latest
TAG_VERSION=${{ env.IMAGE_ID }}:${{ env.APP_VERSION }}
TAG_SHA=${{ env.IMAGE_ID }}:${{ env.SHORT_SHA }}

docker build . \
-t ${{ env.IMAGE_ID }}:latest \
-t ${{ env.IMAGE_ID }}:${{ env.APP_VERSION }} \
-t ${{ env.IMAGE_ID }}:${{ env.SHORT_SHA }}

docker push ${{ env.IMAGE_ID }} --all-tags

- name: Azure Login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Deploy to Container App
uses: azure/container-apps-deploy-action@v1
with:
imageToDeploy: ${{ env.IMAGE_ID }}:${{ env.SHORT_SHA }}
containerAppName: testbench-manager
resourceGroup: testbenchmanager-demo
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,6 @@ marimo/_lsp/
__marimo__/

# Streamlit
.streamlit/secrets.toml
.streamlit/secrets.toml

*.secret
61 changes: 25 additions & 36 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,51 +1,40 @@
# syntax=docker/dockerfile:1.7-labs

# --- Builder Stage ---
# Use a full Python image to install build dependencies
# --- Build Stage ---
FROM python:3.12-slim AS builder

RUN apt-get update \
&& apt-get install --no-install-recommends -y \
git \
openssh-client \
&& rm -rf /var/lib/apt/lists/*

RUN mkdir -p /root/.ssh && ssh-keyscan github.com >> /root/.ssh/known_hosts

RUN --mount=type=ssh ssh -vT git@github.com

# Set environment variables for Poetry
ENV POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_IN_PROJECT=1 \
POETRY_VIRTUALENVS_CREATE=1 \
POETRY_CACHE_DIR=/tmp/poetry_cache \
VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH"
# 1. Install git (Required for your 'epcomms' dependency)
RUN apt-get update && \
apt-get install -y --no-install-recommends git

WORKDIR /app

# Install Poetry itself
RUN pip install poetry==2.2.0
# 2. Create a dedicated virtual environment for Poetry tools
# This keeps Poetry's dependencies completely separate from your app's.
RUN python -m venv /opt/poetry-tools

# 3. Install Poetry + Plugin into that isolated tool venv
RUN /opt/poetry-tools/bin/pip install --no-cache-dir poetry poetry-plugin-bundle

# Copy pyproject.toml and poetry.lock to leverage Docker cache
COPY pyproject.toml poetry.lock ./
# 4. Copy project files
COPY pyproject.toml poetry.lock README.md ./
COPY src ./src

# Install project dependencies (excluding dev dependencies)
RUN --mount=type=ssh \
poetry install --no-root --only main
# 5. Run the bundle command using the ISOLATED poetry executable
# --python=/usr/local/bin/python ensures the bundled venv targets the main Docker python
RUN /opt/poetry-tools/bin/poetry bundle venv --only=main --python=/usr/local/bin/python /venv

# --- Runtime Stage ---
# Use a slim, secure image for the final deployment
FROM python:3.12-slim AS runtime

# Copy the virtual environment and source code from the builder stage
COPY --from=builder /app/.venv /app/.venv
COPY . /app
WORKDIR /app

# Set the PATH to include the virtual environment's bin directory
ENV VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH"
# 6. Copy the bundled environment
COPY --from=builder /venv /venv

WORKDIR /app
# 7. Verify the symlink (It should point to /usr/local/bin/python)
RUN ls -l /venv/bin/python

# 8. Entrypoint
ENTRYPOINT ["/venv/bin/python", "-m", "testbenchmanager.main"]

CMD ["python", "src/testbenchmanager/main.py"]
LABEL org.opencontainers.image.source=https://github.com/Esouder/testbenchmanager
28 changes: 28 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
volumes:
- ../TestbenchConfigs:/configs
command: ["--config-root", "/configs"]
restart: unless-stopped

tunnel:
image: cloudflare/cloudflared:latest
restart: unless-stopped
secrets:
- cloudflare_token
environment:
- TUNNEL_TOKEN_FILE=/run/secrets/cloudflare_token
command: tunnel --no-autoupdate run
depends_on:
- app



secrets:
cloudflare_token:
file: cloudflared.secret
Loading