-
Notifications
You must be signed in to change notification settings - Fork 20
fix: enable container deployment for Python Agent Framework sample #218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Python | ||
| __pycache__/ | ||
| *.py[cod] | ||
| *.pyo | ||
| .venv/ | ||
| venv/ | ||
| .pytest_cache/ | ||
| .mypy_cache/ | ||
| .ruff_cache/ | ||
| build/ | ||
| dist/ | ||
| *.egg-info/ | ||
|
|
||
| # IDE | ||
| .vscode/ | ||
| .idea/ | ||
|
|
||
| # Local files | ||
| .env | ||
| .env.local | ||
| *.log | ||
|
|
||
| # Git | ||
| .git/ | ||
| .gitignore | ||
|
|
||
| # Documentation | ||
| *.md | ||
| !README.md | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||||||||||||||||||||||||
| # Copyright (c) Microsoft Corporation. | ||||||||||||||||||||||||||||
| # Licensed under the MIT License. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Python Agent Framework - Container Deployment | ||||||||||||||||||||||||||||
| # Related to: https://github.com/microsoft/Agent365-Samples/pull/187 | ||||||||||||||||||||||||||||
| FROM python:3.12-slim | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| WORKDIR /app | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Suppress apt-get warnings in Docker | ||||||||||||||||||||||||||||
| ENV DEBIAN_FRONTEND=noninteractive | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Install system dependencies (gcc needed for some Python packages) | ||||||||||||||||||||||||||||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||||||||||||||||||||||||||||
| gcc \ | ||||||||||||||||||||||||||||
| curl \ | ||||||||||||||||||||||||||||
| && rm -rf /var/lib/apt/lists/* \ | ||||||||||||||||||||||||||||
| && apt-get clean | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Upgrade pip | ||||||||||||||||||||||||||||
| RUN pip install --no-cache-dir --upgrade pip | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Copy dependency metadata first for better layer caching | ||||||||||||||||||||||||||||
| COPY pyproject.toml . | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Install Python dependencies from pyproject.toml | ||||||||||||||||||||||||||||
| RUN pip install --no-cache-dir . | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Copy application code | ||||||||||||||||||||||||||||
| COPY . . | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create non-root user for security | ||||||||||||||||||||||||||||
| RUN useradd --create-home --shell /bin/bash agentuser \ | ||||||||||||||||||||||||||||
| && chown -R agentuser:agentuser /app | ||||||||||||||||||||||||||||
| USER agentuser | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
Comment on lines
29
to
36
|
||||||||||||||||||||||||||||
| # Copy application code | |
| COPY . . | |
| # Install Python dependencies from pyproject.toml | |
| RUN pip install --no-cache-dir --root-user-action=ignore . | |
| # Copy dependency metadata first for better caching | |
| COPY pyproject.toml . | |
| # Install Python dependencies from pyproject.toml | |
| RUN pip install --no-cache-dir --root-user-action=ignore . | |
| # Copy application code | |
| COPY . . |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,88 @@ To set up and test this agent, refer to the [Configure Agent Testing](https://le | |
|
|
||
| For a detailed explanation of the agent code and implementation, see the [Agent Code Walkthrough](AGENT-CODE-WALKTHROUGH.md). | ||
|
|
||
| ## Container Deployment | ||
|
|
||
| Container deployment is the recommended approach for production Agent 365 workloads. Here's why: | ||
|
|
||
| ### Why Container Deployment? | ||
|
|
||
| **Production Readiness** | ||
| - **Consistency**: Containers ensure identical behavior across development, staging, and production environments, eliminating "works on my machine" issues | ||
| - **Isolation**: Each agent runs in its own isolated environment with explicit dependencies, preventing conflicts with other services | ||
| - **Scalability**: Container orchestrators (Kubernetes, Azure Container Apps) can automatically scale agent instances based on demand | ||
|
|
||
| **Azure Integration** | ||
| - **Azure Container Apps**: Purpose-built for microservices and agents with built-in autoscaling, managed certificates, and seamless Azure service integration | ||
| - **Azure Kubernetes Service (AKS)**: Enterprise-grade orchestration for complex multi-agent deployments | ||
| - **Azure Container Registry**: Private registry for secure image storage with geo-replication | ||
|
|
||
| **Operational Benefits** | ||
| - **Health Checks**: Container runtimes monitor `/api/health` to automatically restart unhealthy agents | ||
| - **Rolling Updates**: Deploy new versions with zero downtime using blue-green or canary strategies | ||
| - **Resource Limits**: Define CPU/memory boundaries to prevent runaway processes | ||
|
|
||
| ### Network Binding Fix | ||
|
|
||
| This sample binds to `0.0.0.0` (all network interfaces) instead of `localhost`. This is **required** for container deployments because: | ||
|
|
||
| - `localhost` (127.0.0.1) only accepts connections from inside the container | ||
| - External traffic (Bot Framework messages, health checks) comes from outside the container network | ||
| - Binding to `0.0.0.0` allows the agent to receive requests on any network interface | ||
|
|
||
| **Symptoms if using localhost in containers:** | ||
| - Container starts but health checks fail with "Connection refused" | ||
| - Agent works locally but fails when deployed to Docker/Kubernetes/Container Apps | ||
| - Bot Framework cannot reach the `/api/messages` endpoint | ||
|
|
||
| ### Build and run with Docker | ||
|
|
||
| ```bash | ||
| # Navigate to the sample directory first | ||
| cd python/agent-framework/sample-agent | ||
|
|
||
| # Build the container image | ||
| docker build -t python-agent . | ||
|
|
||
| # Run with required environment variables | ||
| docker run -p 3978:3978 \ | ||
| -e AZURE_OPENAI_ENDPOINT=https://your-endpoint.openai.azure.com/ \ | ||
| -e AZURE_OPENAI_API_KEY=your-key \ | ||
| -e AZURE_OPENAI_DEPLOYMENT=gpt-4o \ | ||
| python-agent | ||
|
Comment on lines
63
to
75
|
||
| ``` | ||
|
|
||
| ### Azure Container Apps | ||
|
|
||
| ```bash | ||
| # Navigate to the sample directory | ||
| cd python/agent-framework/sample-agent | ||
|
|
||
| # Ensure you're logged in to Azure CLI | ||
| az login | ||
| az account set --subscription <your-subscription-id> | ||
|
|
||
| # Build and push to Azure Container Registry | ||
| az acr build --registry <your-acr> --image python-agent:latest . | ||
|
|
||
| # Create Container App with required environment variables | ||
| az containerapp create \ | ||
| --name python-agent \ | ||
| --resource-group <your-rg> \ | ||
| --environment <your-env> \ | ||
| --image <your-acr>.azurecr.io/python-agent:latest \ | ||
| --target-port 3978 \ | ||
| --ingress external \ | ||
| --env-vars \ | ||
| AZURE_OPENAI_ENDPOINT=https://your-endpoint.openai.azure.com/ \ | ||
| AZURE_OPENAI_API_KEY=secretref:openai-key \ | ||
| AZURE_OPENAI_DEPLOYMENT=gpt-4o | ||
|
|
||
| # Note: For production, use Azure Container Apps secrets for API keys: | ||
| # az containerapp secret set --name python-agent --resource-group <your-rg> \ | ||
| # --secrets openai-key=<your-actual-api-key> | ||
| ``` | ||
|
|
||
| ## Support | ||
|
|
||
| For issues, questions, or feedback: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| # Copyright (c) Microsoft. All rights reserved. | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| """Generic Agent Host Server - Hosts agents implementing AgentInterface""" | ||
|
|
||
|
|
@@ -332,12 +333,13 @@ async def anonymous_claims(request, handler): | |
| print(f"🏢 {self.agent_class.__name__}") | ||
| print("=" * 80) | ||
| print(f"🔒 Auth: {'Enabled' if auth_configuration else 'Anonymous'}") | ||
| print(f"🚀 Server: localhost:{port}") | ||
| print(f"📚 Endpoint: http://localhost:{port}/api/messages") | ||
| print(f"❤️ Health: http://localhost:{port}/api/health\n") | ||
| print(f"🚀 Server: 0.0.0.0:{port}") | ||
| print(f"📚 Endpoint: http://0.0.0.0:{port}/api/messages") | ||
| print(f"❤️ Health: http://0.0.0.0:{port}/api/health") | ||
| print(" (Use localhost:PORT for local testing)\n") | ||
|
|
||
| try: | ||
| run_app(app, host="localhost", port=port, handle_signals=True) | ||
| run_app(app, host="0.0.0.0", port=port, handle_signals=True) | ||
|
Comment on lines
341
to
+342
|
||
| except KeyboardInterrupt: | ||
| print("\n👋 Server stopped") | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding common Python build artifacts to .dockerignore (e.g., .pytest_cache/, .mypy_cache/, .ruff_cache/, build/, dist/, *.egg-info/). Excluding these helps avoid accidentally copying local build outputs into the image and improves build performance.