diff --git a/README.md b/README.md index 61eaa64..2e9e24b 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,22 @@ Zod. * Demonstrates implementation of UCP specifications for shopping, checkout, and order management using a Node.js stack. +### Docker + +Docker configurations for running UCP servers. Includes separate compose files +for each server. + +* **Docker Setup**: [Documentation](docker/README.md) + * Located in `docker/`. + * Includes `nodejs/docker-compose.yml` for Node.js server only. + * Includes `python/docker-compose.yml` for Python server only. + * Quick start option that doesn't require local Node.js or Python + installation. + ## Getting Started Please refer to the specific README files linked above for detailed instructions on how to set up, run, and test each sample. + +For the quickest start, consider using the [Docker setup](docker/README.md), +which allows you to run both servers without installing dependencies locally. diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..58e918e --- /dev/null +++ b/docker/README.md @@ -0,0 +1,45 @@ + + +# UCP Docker Examples + +This directory contains Docker configurations for running UCP reference +implementations. Docker provides a quick and consistent way to run the UCP servers +without needing to install Node.js, Python, or their dependencies locally. + +## Prerequisites + +* [Docker](https://www.docker.com/get-started) (version 20.10 or higher) +* [Docker Compose](https://docs.docker.com/compose/install/) (version 2.0 or + higher) + +## Available Services + +This directory provides two Docker Compose configurations: + +* **`nodejs/docker-compose.yml`** - Runs the Node.js server +* **`python/docker-compose.yml`** - Runs the Python server + +For detailed instructions on how to use each service, please refer to their respective documentation: + +* [Node.js Docker Setup](./nodejs/README.md) +* [Python Docker Setup](./python/README.md) + +## Additional Resources + +* [Node.js Server Documentation](../rest/nodejs/README.md) +* [Python Server Documentation](../rest/python/server/README.md) +* [UCP Documentation](https://ucp.dev) diff --git a/docker/nodejs/.dockerignore b/docker/nodejs/.dockerignore new file mode 100644 index 0000000..2fe86ff --- /dev/null +++ b/docker/nodejs/.dockerignore @@ -0,0 +1,9 @@ +node_modules +dist +databases/*.db +*.log +.DS_Store +.env +.git +.gitignore +*.md diff --git a/docker/nodejs/Dockerfile b/docker/nodejs/Dockerfile new file mode 100644 index 0000000..ce897fc --- /dev/null +++ b/docker/nodejs/Dockerfile @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM node:20-alpine + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy source files +COPY tsconfig.json ./ +COPY src ./src +COPY scripts ./scripts + +# Create databases directory +RUN mkdir -p databases + +# Expose port +EXPOSE 3000 + +# Start server using tsx (runs TypeScript directly, no build step needed) +CMD ["npx", "tsx", "src/index.ts"] diff --git a/docker/nodejs/README.md b/docker/nodejs/README.md new file mode 100644 index 0000000..66171d5 --- /dev/null +++ b/docker/nodejs/README.md @@ -0,0 +1,159 @@ + + +# Node.js Server Docker Setup + +This directory contains the Docker configuration for running the UCP Node.js server. + +## Quick Start + +To run the Node.js server: + +```bash +cd samples/docker/nodejs +docker-compose up +``` + +The Node.js server will be available at `http://localhost:3000`. + +## Building the Image + +To build the image without starting the container: + +```bash +docker-compose build +``` + +To rebuild from scratch (no cache): + +```bash +docker-compose build --no-cache +``` + +## Accessing the Service + +Once the service is running, you can access it at `http://localhost:3000`. + +For detailed information on how to test and interact with the server, please refer to the [Node.js Server README](../../rest/nodejs/README.md). + +## Data Persistence + +The Node.js server uses a Docker volume (`nodejs-databases`) to persist SQLite databases. Data persists across container restarts. + +To remove all data: + +```bash +docker-compose down -v +``` + +## Stopping the Service + +To stop the service: + +```bash +docker-compose down +``` + +To stop and remove volumes (this will delete all data): + +```bash +docker-compose down -v +``` + +## Viewing Logs + +To view logs from the service: + +```bash +docker-compose logs -f +``` + +## Running in Detached Mode + +To run the service in the background: + +```bash +docker-compose up -d +``` + +To stop the detached service: + +```bash +docker-compose stop +``` + +## Troubleshooting + +### Port Already in Use + +If port 3000 is already in use, you can change it in `docker-compose.yml`: + +```yaml +services: + nodejs-server: + ports: + - "3001:3000" # Change 3001 to your preferred port +``` + +### Build Failures + +If builds fail, try: + +1. Clean build: `docker-compose build --no-cache` +2. Check Docker has enough resources (memory, disk space) +3. Ensure you're in the correct directory (`samples/docker/nodejs`) + +### Container Health Checks + +The service includes health checks. Check status: + +```bash +docker-compose ps +``` + +### Orphan Containers and Network Issues + +If you see warnings about orphan containers or network errors: + +1. Stop all services and remove orphan containers: + ```bash + docker-compose down --remove-orphans + ``` + +2. If the issue persists, remove the container manually: + ```bash + docker rm -f ucp-nodejs-server + docker-compose up + ``` + +3. To clean up all Docker resources (containers, networks, volumes): + ```bash + docker-compose down -v --remove-orphans + ``` + +## Development + +For development, you may want to mount source code as volumes for live reloading. Modify `docker-compose.yml` to add volume mounts: + +```yaml +services: + nodejs-server: + volumes: + - nodejs-databases:/app/databases + - ../rest/nodejs/src:/app/src # Add for live reload +``` + +Note: Live reloading requires additional setup and is not included in the base configuration. diff --git a/docker/nodejs/docker-compose.yml b/docker/nodejs/docker-compose.yml new file mode 100644 index 0000000..6d5d355 --- /dev/null +++ b/docker/nodejs/docker-compose.yml @@ -0,0 +1,35 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + nodejs-server: + build: + context: ../../rest/nodejs + dockerfile: ../../docker/nodejs/Dockerfile + container_name: ucp-nodejs-server + ports: + - "3000:3000" + volumes: + - nodejs-databases:/app/databases + restart: unless-stopped + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/.well-known/ucp', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + +volumes: + nodejs-databases: + driver: local diff --git a/docker/python/.dockerignore b/docker/python/.dockerignore new file mode 100644 index 0000000..a7ff1fa --- /dev/null +++ b/docker/python/.dockerignore @@ -0,0 +1,19 @@ +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +*.so +*.egg +*.egg-info +dist +build +.venv +venv +.env +.git +.gitignore +.DS_Store +*.db +*.log +*.md diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile new file mode 100644 index 0000000..7c4ce57 --- /dev/null +++ b/docker/python/Dockerfile @@ -0,0 +1,47 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.11-slim + +# Install uv +RUN pip install --no-cache-dir uv + +WORKDIR /app + +# Copy SDK first (needed by server) +COPY sdk/python /app/sdk/python + +# Copy server files +COPY samples/rest/python/server /app/server + +# Copy test data +COPY samples/rest/python/test_data /app/test_data + +WORKDIR /app/server + +# Update pyproject.toml to use the copied SDK path +RUN python3 -c "import re; content = open('pyproject.toml').read(); content = re.sub(r'path = \"\.\.\/\.\.\/\.\.\/\.\.\/sdk\/python\/\"', 'path = \"/app/sdk/python/\"', content); open('pyproject.toml', 'w').write(content)" + +# Install dependencies using uv +RUN uv sync + +# Create data directory for databases +RUN mkdir -p /app/data + +# Expose port +EXPOSE 8182 + +# Default command: initialize database and start server +# Users can override this to run different commands +CMD ["sh", "-c", "uv run import_csv.py --products_db_path=/app/data/products.db --transactions_db_path=/app/data/transactions.db --data_dir=/app/test_data/flower_shop && uv run server.py --products_db_path=/app/data/products.db --transactions_db_path=/app/data/transactions.db --port=8182"] diff --git a/docker/python/README.md b/docker/python/README.md new file mode 100644 index 0000000..bfad336 --- /dev/null +++ b/docker/python/README.md @@ -0,0 +1,171 @@ + + +# Python Server Docker Setup + +This directory contains the Docker configuration for running the UCP Python server. + +## Quick Start + +To run the Python server: + +```bash +cd samples/docker/python +docker-compose up +``` + +The Python server will be available at `http://localhost:8182`. + +## Building the Image + +To build the image without starting the container: + +```bash +docker-compose build +``` + +To rebuild from scratch (no cache): + +```bash +docker-compose build --no-cache +``` + +## Accessing the Service + +Once the service is running, you can access it at `http://localhost:8182`. + +For detailed information on how to test and interact with the server, please refer to the [Python Server README](../../rest/python/server/README.md). + +## Data Persistence + +The Python server uses a Docker volume (`python-data`) to persist SQLite databases. Data persists across container restarts. + +To remove all data: + +```bash +docker-compose down -v +``` + +## Stopping the Service + +To stop the service: + +```bash +docker-compose down +``` + +To stop and remove volumes (this will delete all data): + +```bash +docker-compose down -v +``` + +## Viewing Logs + +To view logs from the service: + +```bash +docker-compose logs -f +``` + +## Running in Detached Mode + +To run the service in the background: + +```bash +docker-compose up -d +``` + +To stop the detached service: + +```bash +docker-compose stop +``` + +## Troubleshooting + +### Port Already in Use + +If port 8182 is already in use, you can change it in `docker-compose.yml`: + +```yaml +services: + python-server: + ports: + - "8183:8182" # Change 8183 to your preferred port +``` + +### Database Issues + +If the Python server fails to start due to database issues: + +1. Stop the service: `docker-compose down -v` +2. If the volume still exists, remove it manually: + ```bash + docker volume ls | grep python-data + docker volume rm + ``` +3. Start again: `docker-compose up` + +### Build Failures + +If builds fail, try: + +1. Clean build: `docker-compose build --no-cache` +2. Check Docker has enough resources (memory, disk space) +3. Ensure you're in the correct directory (`samples/docker/python`) + +### Container Health Checks + +The service includes health checks. Check status: + +```bash +docker-compose ps +``` + +### Orphan Containers and Network Issues + +If you see warnings about orphan containers or network errors: + +1. Stop all services and remove orphan containers: + ```bash + docker-compose down --remove-orphans + ``` + +2. If the issue persists, remove the container manually: + ```bash + docker rm -f ucp-python-server + docker-compose up + ``` + +3. To clean up all Docker resources (containers, networks, volumes): + ```bash + docker-compose down -v --remove-orphans + ``` + +## Development + +For development, you may want to mount source code as volumes for live reloading. Modify `docker-compose.yml` to add volume mounts: + +```yaml +services: + python-server: + volumes: + - python-data:/app/data + - ../rest/python/server:/app/server # Add for live reload +``` + +Note: Live reloading requires additional setup and is not included in the base configuration. diff --git a/docker/python/docker-compose.yml b/docker/python/docker-compose.yml new file mode 100644 index 0000000..3f4b2bd --- /dev/null +++ b/docker/python/docker-compose.yml @@ -0,0 +1,35 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + python-server: + build: + context: ../../.. + dockerfile: samples/docker/python/Dockerfile + container_name: ucp-python-server + ports: + - "8182:8182" + volumes: + - python-data:/app/data + restart: unless-stopped + healthcheck: + test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8182/.well-known/ucp'); exit(0)"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + +volumes: + python-data: + driver: local diff --git a/rest/nodejs/README.md b/rest/nodejs/README.md index 7209b58..6be1777 100644 --- a/rest/nodejs/README.md +++ b/rest/nodejs/README.md @@ -81,6 +81,20 @@ endpoint at: http://localhost:3000/.well-known/ucp ``` +## Running with Docker + +For a quick start without installing Node.js locally, you can use Docker: + +```bash +cd ../docker/nodejs +docker-compose up +``` + +This will build and start the Node.js server in a Docker container. The server +will be available at `http://localhost:3000`. + +For more details and options, see the [Docker documentation](../docker/README.md). + ## Running Conformance Tests To verify that this server implementation complies with the UCP specifications, diff --git a/rest/python/server/README.md b/rest/python/server/README.md index f6e7c73..e5a8539 100644 --- a/rest/python/server/README.md +++ b/rest/python/server/README.md @@ -87,6 +87,21 @@ SERVER_PID=$! Note: Keep the server running for the duration of running the client and the following experiments. +## Running with Docker + +For a quick start without installing Python or uv locally, you can use Docker: + +```bash +cd ../../docker/python +docker-compose up +``` + +This will build and start the Python server in a Docker container, automatically +initializing the database with sample data. The server will be available at +`http://localhost:8182`. + +For more details and options, see the [Docker documentation](../../docker/README.md). + ## Run a Simple Client Exercise a simple checkout path: Once the server is running, execute the simple