Improve Docker Build and Deployment for Arcade Worker (#205)
This PR enhances the Docker build and deployment process for the Arcade Worker by: - **Modularizing Docker Builds:** - Introduces a new `INSTALL_TOOLKITS` build argument in the `Dockerfile` to conditionally include toolkits. this enables the creation of a `arcadeai/worker-base` which can be used to build custom containers in a multi-stage build. an example of this is included in the example dir. - Adds `docker-base` Makefile target to build a lightweight base image without toolkits. - **Publishing to GitHub Container Registry (GHCR):** - Adds Makefile targets `publish-ghcr` and `gh-login` for pushing images to GHCR. - Supports publishing both base and full images with toolkits to GHCR. - **Docker Compose:** - Add Docker compose file and setup - Renames the `actor` service to `worker` - Adds an `nginx` service in `docker-compose.yml` to proxy requests to the Arcade Engine. - Introduces an `nginx.conf` file for the Nginx service. - **Streamlining Toolkit Installation:** - Moves toolkit installation from the `start.sh` script to the Docker build process. - Creates a `toolkits.txt` file to manage toolkit dependencies which can be edited easily when we want to add a new toolkit. Developers can also use this approach as shown in the example. - **Improving Configuration Files:** - Updates `docker.engine.yaml` and `env.example` to align with the new setup. TODO: - CI/CD needs to be adjusted so that images are pushed to ghcr on release. - AWS resources need to be renamed actor -> worker @EricGustin This can go in after the above two items are resolved. --------- Co-authored-by: Wils Dawson <wils@arcade-ai.com> Co-authored-by: Eric Gustin <34000337+EricGustin@users.noreply.github.com> Co-authored-by: sdreyer <sterling@arcade-ai.com> Co-authored-by: Sterling Dreyer <sdreyer21@gmail.com> Co-authored-by: Nate Barbettini <nathanaelb@gmail.com>
This commit is contained in:
parent
6d8e943c96
commit
09a0784cd5
16 changed files with 637 additions and 54 deletions
10
.github/workflows/release-containers.yml
vendored
10
.github/workflows/release-containers.yml
vendored
|
|
@ -100,11 +100,11 @@ jobs:
|
||||||
id: build
|
id: build
|
||||||
run: |
|
run: |
|
||||||
make docker VERSION=${{ needs.set-version.outputs.version }} ARCH=${{ matrix.arch }}
|
make docker VERSION=${{ needs.set-version.outputs.version }} ARCH=${{ matrix.arch }}
|
||||||
|
make docker-base VERSION=${{ needs.set-version.outputs.version }} ARCH=${{ matrix.arch }}
|
||||||
make publish-ecr VERSION=${{ needs.set-version.outputs.version }} ARCH=${{ matrix.arch }}
|
make publish-ecr VERSION=${{ needs.set-version.outputs.version }} ARCH=${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Push GHCR
|
- name: Push GHCR
|
||||||
if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/')
|
if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/')
|
||||||
working-directory: ./docker
|
|
||||||
run: |
|
run: |
|
||||||
make publish-ghcr VERSION=${{ needs.set-version.outputs.version }} ARCH=${{ matrix.arch }}
|
make publish-ghcr VERSION=${{ needs.set-version.outputs.version }} ARCH=${{ matrix.arch }}
|
||||||
|
|
||||||
|
|
@ -144,12 +144,16 @@ jobs:
|
||||||
|
|
||||||
- name: Push manifest to ECR
|
- name: Push manifest to ECR
|
||||||
working-directory: ./docker
|
working-directory: ./docker
|
||||||
run: make ecr-manifest VERSION=${{ needs.set-version.outputs.version }}
|
run: |
|
||||||
|
make ecr-manifest VERSION=${{ needs.set-version.outputs.version }}
|
||||||
|
make ecr-manifest INSTALL_TOOLKITS=false VERSION=${{ needs.set-version.outputs.version }}
|
||||||
|
|
||||||
- name: Push manifest to GHCR
|
- name: Push manifest to GHCR
|
||||||
if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/')
|
if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/')
|
||||||
working-directory: ./docker
|
working-directory: ./docker
|
||||||
run: make ghcr-manifest VERSION=${{ needs.set-version.outputs.version }}
|
run: |
|
||||||
|
make ghcr-manifest VERSION=${{ needs.set-version.outputs.version }}
|
||||||
|
make ghcr-manifest INSTALL_TOOLKITS=false VERSION=${{ needs.set-version.outputs.version }}
|
||||||
|
|
||||||
# Currently broken: workflow deploy requires all versions
|
# Currently broken: workflow deploy requires all versions
|
||||||
# deploy:
|
# deploy:
|
||||||
|
|
|
||||||
39
Makefile
39
Makefile
|
|
@ -91,15 +91,35 @@ build-and-publish: build publish ## Build and publish.
|
||||||
docker: ## Build and run the Docker container
|
docker: ## Build and run the Docker container
|
||||||
@echo "🚀 Building arcade and toolkit wheels..."
|
@echo "🚀 Building arcade and toolkit wheels..."
|
||||||
@make full-dist
|
@make full-dist
|
||||||
@echo "Writing extras [fastapi, evals] to requirements.txt"
|
@echo "Writing extras requirements.txt"
|
||||||
@cd arcade && poetry export --extras "fastapi evals" --output ../dist/requirements.txt
|
@cd arcade && poetry export --extras "fastapi" --output ../dist/requirements.txt
|
||||||
@echo "🚀 Building Docker image"
|
@echo "🚀 Building Docker image"
|
||||||
@cd docker && make docker-build
|
@cd docker && make docker-build
|
||||||
@cd docker && make docker-run
|
@cd docker && make docker-run
|
||||||
|
|
||||||
|
.PHONY: docker-base
|
||||||
|
docker-base: ## Build and run the Docker container
|
||||||
|
@echo "🚀 Building arcade and toolkit wheels..."
|
||||||
|
@make full-dist
|
||||||
|
@echo "Writing extras requirements.txt"
|
||||||
|
@cd arcade && poetry export --extras "fastapi" --output ../dist/requirements.txt
|
||||||
|
@echo "🚀 Building Docker image"
|
||||||
|
@cd docker && INSTALL_TOOLKITS=false make docker-build
|
||||||
|
@cd docker && INSTALL_TOOLKITS=false make docker-run
|
||||||
|
|
||||||
.PHONY: publish-ecr
|
.PHONY: publish-ecr
|
||||||
publish-ecr: ## Publish to the ECR
|
publish-ecr: ## Publish to the ECR
|
||||||
@cd docker && make publish-ecr
|
# Publish the base image - <ECR_ENDPOINT>/arcadeai/worker-base
|
||||||
|
@cd docker && INSTALL_TOOLKITS=false make publish-ecr
|
||||||
|
# Publish the image with toolkits - <ECR_ENDPOINT>/arcadeai/worker
|
||||||
|
@cd docker && INSTALL_TOOLKITS=true make publish-ecr
|
||||||
|
|
||||||
|
.PHONY: publish-ghcr
|
||||||
|
publish-ghcr: ## Publish to the GHCR
|
||||||
|
# Publish the base image - ghcr.io/arcadeai/worker-base
|
||||||
|
@cd docker && INSTALL_TOOLKITS=false make publish-ghcr
|
||||||
|
# Publish the image with toolkits - ghcr.io/arcadeai/worker
|
||||||
|
@cd docker && INSTALL_TOOLKITS=true make publish-ghcr
|
||||||
|
|
||||||
.PHONY: full-dist
|
.PHONY: full-dist
|
||||||
full-dist: clean-dist ## Build all projects and copy wheels to ./dist
|
full-dist: clean-dist ## Build all projects and copy wheels to ./dist
|
||||||
|
|
@ -121,19 +141,6 @@ full-dist: clean-dist ## Build all projects and copy wheels to ./dist
|
||||||
@echo "Reset version to default (0.1.0)"
|
@echo "Reset version to default (0.1.0)"
|
||||||
@make unset-version
|
@make unset-version
|
||||||
|
|
||||||
@echo "🛠️ Building all projects and copying wheels to ./dist"
|
|
||||||
# Build and copy wheels for each toolkit
|
|
||||||
# @for toolkit_dir in toolkits/*; do \
|
|
||||||
# if [ -d "$$toolkit_dir" ]; then \
|
|
||||||
# toolkit_name=$$(basename "$$toolkit_dir"); \
|
|
||||||
# echo "Building $$toolkit_name project..."; \
|
|
||||||
# poetry build; \
|
|
||||||
# cp dist/*.whl ../../dist/toolkits; \
|
|
||||||
# cd -; \
|
|
||||||
# fi; \
|
|
||||||
# done
|
|
||||||
|
|
||||||
@echo "✅ All toolkits built and wheels copied to ./dist"
|
|
||||||
|
|
||||||
.PHONY: clean-dist
|
.PHONY: clean-dist
|
||||||
clean-dist: ## Clean all built distributions
|
clean-dist: ## Clean all built distributions
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,20 @@
|
||||||
# Use a lightweight Python image
|
|
||||||
FROM python:3.10-slim
|
FROM python:3.10-slim
|
||||||
|
|
||||||
# Define build arguments with default values
|
# Define build arguments with default values
|
||||||
ARG PORT=8001
|
ARG PORT=8001
|
||||||
ARG HOST=0.0.0.0
|
ARG HOST=0.0.0.0
|
||||||
ARG VERSION=0.1.0
|
ARG VERSION=${VERSION:-0.1.0}
|
||||||
|
ARG INSTALL_TOOLKITS=true
|
||||||
|
|
||||||
# Set environment variables using the build arguments
|
# Set environment variables using the build arguments
|
||||||
ENV PORT=${PORT}
|
ENV PORT=${PORT}
|
||||||
ENV HOST=${HOST}
|
ENV HOST=${HOST}
|
||||||
ENV VERSION=${VERSION}
|
|
||||||
ENV OTEL_ENABLE=false
|
ENV OTEL_ENABLE=false
|
||||||
ENV ARCADE_WORK_DIR=/app
|
ENV ARCADE_WORK_DIR=/app
|
||||||
ENV TOOLKITS="arcade-code-sandbox,arcade-github,arcade-google,arcade-linkedin,arcade-math,arcade-search,arcade-slack,arcade-spotify,arcade-web,arcade-x,arcade-zoom"
|
|
||||||
|
|
||||||
# Install system dependencies
|
# Install system dependencies
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
apt-utils \
|
|
||||||
build-essential \
|
|
||||||
libssl-dev \
|
libssl-dev \
|
||||||
libffi-dev \
|
|
||||||
python3-dev \
|
python3-dev \
|
||||||
curl \
|
curl \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
|
|
@ -30,6 +25,12 @@ WORKDIR /app/arcade
|
||||||
# Copy the parent directory contents into the container
|
# Copy the parent directory contents into the container
|
||||||
COPY ./dist ./arcade /app/arcade/
|
COPY ./dist ./arcade /app/arcade/
|
||||||
|
|
||||||
|
# Copy the toolkits.txt file into the container
|
||||||
|
COPY ./docker/toolkits.txt /app/arcade/
|
||||||
|
|
||||||
|
# Expose the port
|
||||||
|
EXPOSE $PORT
|
||||||
|
|
||||||
# List files for debugging purposes
|
# List files for debugging purposes
|
||||||
RUN ls -la /app/arcade/
|
RUN ls -la /app/arcade/
|
||||||
|
|
||||||
|
|
@ -49,8 +50,10 @@ RUN if [ ! "$(echo ${VERSION} | grep -E '\.dev0$')" ]; then \
|
||||||
pip install .; \
|
pip install .; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Expose the port
|
# Conditionally install toolkits.txt dependencies
|
||||||
EXPOSE $PORT
|
RUN if [ "$INSTALL_TOOLKITS" = "true" ] ; then \
|
||||||
|
python -m pip install -r ./toolkits.txt ; \
|
||||||
|
fi
|
||||||
|
|
||||||
# Run the arcade workerup (hidden cli command)
|
# Run the arcade workerup (hidden cli command)
|
||||||
COPY docker/start.sh /app/start.sh
|
COPY docker/start.sh /app/start.sh
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,35 @@ VENDOR ?= ArcadeAI
|
||||||
PROJECT ?= ArcadeAI
|
PROJECT ?= ArcadeAI
|
||||||
SOURCE ?= https://github.com/ArcadeAI/arcade-ai
|
SOURCE ?= https://github.com/ArcadeAI/arcade-ai
|
||||||
LICENSE ?= MIT
|
LICENSE ?= MIT
|
||||||
DESCRIPTION ?= "Arcade AI for LLM Tool Serving"
|
DESCRIPTION ?= "Arcade Worker for LLM Tool Serving"
|
||||||
REPOSITORY ?= arcadeai/worker
|
REPOSITORY ?= arcadeai/worker
|
||||||
ECR_ENDPOINT ?= 471112909428.dkr.ecr.us-east-1.amazonaws.com
|
ECR_ENDPOINT ?= 471112909428.dkr.ecr.us-east-1.amazonaws.com
|
||||||
ARCH ?= arm64
|
ARCH ?= $(shell uname -m)
|
||||||
|
|
||||||
VERSION ?= 0.1.0.dev0
|
VERSION ?= 0.1.0.dev0
|
||||||
COMMIT ?= $(shell git describe --dirty --always --abbrev=15)
|
COMMIT ?= $(shell git describe --dirty --always --abbrev=15)
|
||||||
BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
|
BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
IMAGE_NAME ?= worker
|
IMAGE_NAME ?= worker
|
||||||
PORT ?= 8002
|
PORT ?= 8002
|
||||||
|
INSTALL_TOOLKITS ?= true
|
||||||
|
|
||||||
|
# If INSTALL_TOOLKITS is true, we are building the worker image with all toolkits
|
||||||
|
# Otherwise, we are building the worker image with no toolkits
|
||||||
|
ifeq ($(INSTALL_TOOLKITS), true)
|
||||||
|
REPOSITORY := $(REPOSITORY)
|
||||||
|
else
|
||||||
|
REPOSITORY := $(REPOSITORY)-base
|
||||||
|
endif
|
||||||
|
|
||||||
|
VERSION_TAG := $(VERSION)-$(ARCH)
|
||||||
|
|
||||||
.PHONY: docker-build
|
.PHONY: docker-build
|
||||||
docker-build: ## Build the Docker container
|
docker-build: ## Build the Docker container
|
||||||
@echo "🛠️ Building Docker image ($(VERSION)).."
|
@echo "🛠️ Building Docker image ($(VERSION_TAG)).."
|
||||||
@echo "- Commit: $(COMMIT)"
|
@echo "- Commit: $(COMMIT)"
|
||||||
@echo "- Build Date: $(BUILD_DATE)"
|
@echo "- Build Date: $(BUILD_DATE)"
|
||||||
@docker build --build-arg PORT=$(PORT) -f Dockerfile -t $(REPOSITORY):$(VERSION) .. \
|
@docker build --build-arg PORT=$(PORT) -f Dockerfile -t $(REPOSITORY):$(VERSION_TAG) \
|
||||||
|
--build-arg INSTALL_TOOLKITS=$(INSTALL_TOOLKITS) \
|
||||||
--build-arg PORT=$(PORT) \
|
--build-arg PORT=$(PORT) \
|
||||||
--build-arg VERSION="$(VERSION)" \
|
--build-arg VERSION="$(VERSION)" \
|
||||||
--build-arg COMMIT="$(COMMIT)" \
|
--build-arg COMMIT="$(COMMIT)" \
|
||||||
|
|
@ -27,14 +38,16 @@ docker-build: ## Build the Docker container
|
||||||
--label=org.opencontainers.image.vendor="$(VENDOR)" \
|
--label=org.opencontainers.image.vendor="$(VENDOR)" \
|
||||||
--label=org.opencontainers.image.title="$(PROJECT)" \
|
--label=org.opencontainers.image.title="$(PROJECT)" \
|
||||||
--label=org.opencontainers.image.revision="$(COMMIT)" \
|
--label=org.opencontainers.image.revision="$(COMMIT)" \
|
||||||
--label=org.opencontainers.image.version="$(VERSION)" \
|
--label=org.opencontainers.image.version="$(VERSION_TAG)" \
|
||||||
--label=org.opencontainers.image.created="$(BUILD_DATE)" \
|
--label=org.opencontainers.image.created="$(BUILD_DATE)" \
|
||||||
--label=org.opencontainers.image.source="$(SOURCE)" \
|
--label=org.opencontainers.image.source="$(SOURCE)" \
|
||||||
--label=org.opencontainers.image.licenses="$(LICENSE)" \
|
--label=org.opencontainers.image.licenses="$(LICENSE)" \
|
||||||
--label=org.opencontainers.image.description=$(DESCRIPTION)
|
--label=org.opencontainers.image.description=$(DESCRIPTION) \
|
||||||
|
..
|
||||||
|
|
||||||
|
|
||||||
ecr-manifest: ## Make a manifest file for the image
|
ecr-manifest: ## Make a manifest file for the image
|
||||||
@echo "🛠️ Build manifest file ($(VERSION)).."
|
@echo "🛠️ Build manifest file for $(REPOSITORY):$(VERSION).."
|
||||||
@echo "- Commit: $(COMMIT)"
|
@echo "- Commit: $(COMMIT)"
|
||||||
@echo "- Build Date: $(BUILD_DATE)"
|
@echo "- Build Date: $(BUILD_DATE)"
|
||||||
@export DOCKER_CLI_EXPERIMENTAL=enabled
|
@export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
|
|
@ -56,7 +69,7 @@ ecr-manifest: ## Make a manifest file for the image
|
||||||
@docker manifest push $(ECR_ENDPOINT)/$(REPOSITORY):latest
|
@docker manifest push $(ECR_ENDPOINT)/$(REPOSITORY):latest
|
||||||
|
|
||||||
ghcr-manifest: ## Make a manifest file for the image
|
ghcr-manifest: ## Make a manifest file for the image
|
||||||
@echo "🛠️ Build manifest file ($(VERSION)).."
|
@echo "🛠️ Build manifest file for $(REPOSITORY):$(VERSION).."
|
||||||
@echo "- Commit: $(COMMIT)"
|
@echo "- Commit: $(COMMIT)"
|
||||||
@echo "- Build Date: $(BUILD_DATE)"
|
@echo "- Build Date: $(BUILD_DATE)"
|
||||||
@export DOCKER_CLI_EXPERIMENTAL=enabled
|
@export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
|
|
@ -80,17 +93,16 @@ ghcr-manifest: ## Make a manifest file for the image
|
||||||
.PHONY: docker-run
|
.PHONY: docker-run
|
||||||
docker-run: ## Run the Docker container
|
docker-run: ## Run the Docker container
|
||||||
@echo "\n🚀 Run the container with the following ..."
|
@echo "\n🚀 Run the container with the following ..."
|
||||||
@echo ">>> docker run -d -p $(PORT):$(PORT) $(REPOSITORY):$(VERSION)"
|
@echo ">>> docker run -d -p $(PORT):$(PORT) $(REPOSITORY):$(VERSION_TAG)"
|
||||||
|
|
||||||
|
|
||||||
.PHONY: publish-ecr
|
.PHONY: publish-ecr
|
||||||
publish-ecr:
|
publish-ecr:
|
||||||
@echo "🚚 Pushing the Agent image to ECR.."
|
@echo "🚚 Pushing the Agent image to ECR.."
|
||||||
@docker tag $(REPOSITORY):$(VERSION) $(ECR_ENDPOINT)/$(REPOSITORY):$(VERSION)-$(ARCH)
|
@docker tag $(REPOSITORY):$(VERSION_TAG) $(ECR_ENDPOINT)/$(REPOSITORY):$(VERSION_TAG)
|
||||||
@echo "- pushing $(ECR_ENDPOINT)/$(REPOSITORY):$(VERSION)-$(ARCH)"
|
@echo "- pushing $(ECR_ENDPOINT)/$(REPOSITORY):$(VERSION_TAG)"
|
||||||
@docker push $(ECR_ENDPOINT)/$(REPOSITORY):$(VERSION)-$(ARCH)
|
@docker push $(ECR_ENDPOINT)/$(REPOSITORY):$(VERSION_TAG)
|
||||||
@echo $(VERSION) | grep -q $(RC_PART) || { \
|
@echo $(VERSION_TAG) | grep -q $(RC_PART) || { \
|
||||||
docker tag $(REPOSITORY):$(VERSION) $(ECR_ENDPOINT)/$(REPOSITORY):latest-$(ARCH); \
|
docker tag $(REPOSITORY):$(VERSION_TAG) $(ECR_ENDPOINT)/$(REPOSITORY):latest-$(ARCH); \
|
||||||
echo "- pushing $(ECR_ENDPOINT)/$(REPOSITORY):latest-$(ARCH)"; \
|
echo "- pushing $(ECR_ENDPOINT)/$(REPOSITORY):latest-$(ARCH)"; \
|
||||||
docker push $(ECR_ENDPOINT)/$(REPOSITORY):latest-$(ARCH); \
|
docker push $(ECR_ENDPOINT)/$(REPOSITORY):latest-$(ARCH); \
|
||||||
}
|
}
|
||||||
|
|
@ -98,20 +110,30 @@ publish-ecr:
|
||||||
.PHONY: publish-ghcr
|
.PHONY: publish-ghcr
|
||||||
publish-ghcr:
|
publish-ghcr:
|
||||||
@echo "🚚 Pushing the Agent image to GHCR.."
|
@echo "🚚 Pushing the Agent image to GHCR.."
|
||||||
@docker tag $(REPOSITORY):$(VERSION) ghcr.io/$(REPOSITORY):$(VERSION)-$(ARCH)
|
@docker tag $(REPOSITORY):$(VERSION_TAG) ghcr.io/$(REPOSITORY):$(VERSION_TAG)
|
||||||
@echo "- pushing ghcr.io/$(REPOSITORY):$(VERSION)-$(ARCH)"
|
@echo "- pushing ghcr.io/$(REPOSITORY):$(VERSION_TAG)"
|
||||||
@docker push ghcr.io/$(REPOSITORY):$(VERSION)-$(ARCH)
|
@docker push ghcr.io/$(REPOSITORY):$(VERSION_TAG)
|
||||||
@echo $(VERSION) | grep -q $(RC_PART) || { \
|
@echo $(VERSION) | grep -q $(RC_PART) || { \
|
||||||
docker tag $(REPOSITORY):$(VERSION) ghcr.io/$(REPOSITORY):latest-$(ARCH); \
|
docker tag $(REPOSITORY):$(VERSION_TAG) ghcr.io/$(REPOSITORY):latest-$(ARCH); \
|
||||||
echo "- pushing ghcr.io/$(REPOSITORY):latest-$(ARCH)"; \
|
echo "- pushing ghcr.io/$(REPOSITORY):latest-$(ARCH)"; \
|
||||||
docker push ghcr.io/$(REPOSITORY):latest-$(ARCH); \
|
docker push ghcr.io/$(REPOSITORY):latest-$(ARCH); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.PHONY: ecr-login
|
.PHONY: ecr-login
|
||||||
ecr-login: # Login to ECR
|
ecr-login: ## Login to ECR
|
||||||
@aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $(ECR_ENDPOINT)
|
@aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $(ECR_ENDPOINT)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: gh-login
|
||||||
|
gh-login: ## Login to GHCR
|
||||||
|
@echo "🚚 Logging in to GHCR..."
|
||||||
|
@if [ -z "$(GHCR_PAT)" ]; then \
|
||||||
|
echo "Error: GHCR_PAT environment variable is not set"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
@echo $(GHCR_PAT) | docker login ghcr.io -u arcadeai --password-stdin
|
||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
help:
|
help:
|
||||||
@echo "🛠️ Worker Docker Commands:\n"
|
@echo "🛠️ Worker Docker Commands:\n"
|
||||||
|
|
|
||||||
115
docker/README.md
Normal file
115
docker/README.md
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
# Arcade Docker Compose Guide
|
||||||
|
|
||||||
|
This guide provides detailed instructions on how to set up and run Arcade using Docker Compose.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Docker** installed on your system. [Install Docker](https://docs.docker.com/get-docker/)
|
||||||
|
- **Docker Compose** installed. It comes bundled with Docker Desktop on Windows and macOS. For Linux, follow the [Docker Compose installation guide](https://docs.docker.com/compose/install/).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### 1. Clone the Repository
|
||||||
|
|
||||||
|
Begin by cloning the Arcade repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ArcadeAI/arcade-ai.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Change to the `docker` directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd arcade-ai/docker
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Copy and Configure Environment Variables
|
||||||
|
|
||||||
|
Copy the example environment file to `.env`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Open the `.env` file in your preferred text editor and fill in the required values. At a minimum, you **must** provide the `OPENAI_API_KEY`:
|
||||||
|
|
||||||
|
```env:.env
|
||||||
|
### LLM ###
|
||||||
|
|
||||||
|
OPENAI_API_KEY=your_openai_api_key_here
|
||||||
|
```
|
||||||
|
|
||||||
|
If you plan to use other Large Language Model (LLM) providers, add their API keys as well:
|
||||||
|
|
||||||
|
```env:.env
|
||||||
|
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Run Docker Compose
|
||||||
|
|
||||||
|
Start the Arcade services using Docker Compose:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -p arcade
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will build and start all the services defined in the `docker-compose.yml` file and make their ports available to your host machine.
|
||||||
|
|
||||||
|
### 4. Verify the Engine is Running
|
||||||
|
|
||||||
|
In a separate terminal window, check if the engine is running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:9099/v1/health
|
||||||
|
```
|
||||||
|
|
||||||
|
You should receive a response indicating that the engine is healthy:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "status": "healthy" }
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also view the swagger docs at `http://localhost:9099/swagger/index.html`
|
||||||
|
|
||||||
|
## Adding Authentication Providers
|
||||||
|
|
||||||
|
Arcade supports various authentication providers. To add an auth provider, follow these steps:
|
||||||
|
|
||||||
|
### 1. Enable the Auth Provider in the Configuration
|
||||||
|
|
||||||
|
Edit the `docker.engine.yaml` file to enable the desired auth provider. For example, to enable Google authentication, modify the file as follows:
|
||||||
|
|
||||||
|
```yaml:docker.engine.yaml
|
||||||
|
auth:
|
||||||
|
providers:
|
||||||
|
- id: google
|
||||||
|
enabled: true # Change from false to true
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Add Client ID and Secret to the `.env` File
|
||||||
|
|
||||||
|
Obtain the client ID and client secret from your auth provider and add them to the `.env` file:
|
||||||
|
|
||||||
|
```env:.env
|
||||||
|
GOOGLE_CLIENT_ID="your_google_client_id"
|
||||||
|
GOOGLE_CLIENT_SECRET="your_google_client_secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
Repeat this step for any other auth providers you wish to enable.
|
||||||
|
|
||||||
|
### 3. Restart the Docker Compose Services
|
||||||
|
|
||||||
|
After making changes to the configuration, restart the services:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down
|
||||||
|
docker compose up -p arcade
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **Engine Health Check Fails**: Ensure that all environment variables are correctly set in the `.env` file and that the services have started without errors.
|
||||||
|
- **Port Conflicts**: If the default ports are already in use, modify the ports in the `docker-compose.yml` file.
|
||||||
|
- **Authentication Errors**: Double-check the client IDs and secrets provided for auth providers.
|
||||||
|
|
||||||
|
NOTE: `arcade login` will not work within a docker container, you must copy your credentials into the container if you would like to use it.
|
||||||
62
docker/docker-compose.yml
Normal file
62
docker/docker-compose.yml
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
engine:
|
||||||
|
image: ghcr.io/arcadeai/engine:latest
|
||||||
|
container_name: arcade-engine
|
||||||
|
volumes:
|
||||||
|
- ./docker.engine.yaml:/bin/engine.yaml
|
||||||
|
- ./.env:/bin/.env
|
||||||
|
- ./arcade-engine.sqlite3:/app/arcade-engine.sqlite3
|
||||||
|
ports:
|
||||||
|
- "9099:9099"
|
||||||
|
depends_on:
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
worker:
|
||||||
|
condition: service_started
|
||||||
|
networks:
|
||||||
|
arcade-network:
|
||||||
|
command: /bin/arcade-engine --config /bin/engine.yaml --env /bin/.env --migrate
|
||||||
|
|
||||||
|
worker:
|
||||||
|
# image: ghcr.io/arcadeai/arcade-ai:latest
|
||||||
|
image: arcade-worker:0.1.0
|
||||||
|
container_name: arcade-worker
|
||||||
|
ports:
|
||||||
|
- "8002:8002"
|
||||||
|
networks:
|
||||||
|
arcade-network:
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis/redis-stack:latest
|
||||||
|
container_name: arcade-redis
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
- "8004:8002"
|
||||||
|
depends_on:
|
||||||
|
worker:
|
||||||
|
condition: service_started
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD", "redis-cli", "ping" ]
|
||||||
|
interval: 3s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
arcade-network:
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:stable-alpine
|
||||||
|
container_name: arcade-nginx
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
depends_on:
|
||||||
|
- engine
|
||||||
|
networks:
|
||||||
|
- arcade-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
arcade-network:
|
||||||
|
driver: bridge
|
||||||
173
docker/docker.engine.yaml
Normal file
173
docker/docker.engine.yaml
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
telemetry:
|
||||||
|
environment: local
|
||||||
|
version: ${env:VERSION}
|
||||||
|
logging:
|
||||||
|
level: debug # debug, info, warn, error
|
||||||
|
encoding: console
|
||||||
|
|
||||||
|
api:
|
||||||
|
development: true
|
||||||
|
host: 0.0.0.0
|
||||||
|
port: 9099
|
||||||
|
analytics:
|
||||||
|
enabled: false
|
||||||
|
# Uncomment to enable rate limiter
|
||||||
|
# rate_limit:
|
||||||
|
# redis:
|
||||||
|
# addr: "localhost:6379"
|
||||||
|
# password: ""
|
||||||
|
# db: 2
|
||||||
|
# time_unit: m
|
||||||
|
# limit: 2
|
||||||
|
# write_timeout: 10
|
||||||
|
# read_timeout: 10
|
||||||
|
|
||||||
|
llm:
|
||||||
|
models:
|
||||||
|
- id: oai
|
||||||
|
openai:
|
||||||
|
api_key: ${env:OPENAI_API_KEY}
|
||||||
|
# - id: anthropic
|
||||||
|
# anthropic:
|
||||||
|
# api_key: ${env:ANTHROPIC_API_KEY}
|
||||||
|
# # model: "claude-3-5-sonnet-20240620"
|
||||||
|
#- id: ollama
|
||||||
|
# openai:
|
||||||
|
# base_url: "http://localhost:11434/v1"
|
||||||
|
# api_key: "ollama"
|
||||||
|
|
||||||
|
tools:
|
||||||
|
directors:
|
||||||
|
- id: default
|
||||||
|
enabled: true
|
||||||
|
workers:
|
||||||
|
- id: "localworker"
|
||||||
|
enabled: true
|
||||||
|
http:
|
||||||
|
uri: ${env:WORKER_URL}
|
||||||
|
timeout: 30
|
||||||
|
retry: 3
|
||||||
|
secret: ${env:ARCADE_WORKER_SECRET} # If not set, defaults to "dev" in development mode only
|
||||||
|
# Uncomment mock and comment http to start engine without live worker
|
||||||
|
# mock:
|
||||||
|
# enabled: true
|
||||||
|
|
||||||
|
security:
|
||||||
|
root_keys:
|
||||||
|
- id: key1
|
||||||
|
default: true
|
||||||
|
value: ${env:ROOT_KEY_1}
|
||||||
|
# - id: key2
|
||||||
|
# value: ${env:ROOT_KEY_2}
|
||||||
|
|
||||||
|
storage:
|
||||||
|
# postgres:
|
||||||
|
# user: postgres
|
||||||
|
# password: 123456
|
||||||
|
# host: localhost
|
||||||
|
# port: 5432
|
||||||
|
# db: arcade_engine
|
||||||
|
# sslmode: disable
|
||||||
|
sqlite: # Default for local development
|
||||||
|
connection_string: "/app/arcade-engine.sqlite3"
|
||||||
|
|
||||||
|
cache:
|
||||||
|
api_key_ttl: "10s"
|
||||||
|
redis:
|
||||||
|
addr: ${env:REDIS_HOST}:${env:REDIS_PORT}
|
||||||
|
password: ${env:REDIS_PASSWORD}
|
||||||
|
|
||||||
|
auth:
|
||||||
|
token_store:
|
||||||
|
redis:
|
||||||
|
addr: ${env:REDIS_HOST}:${env:REDIS_PORT}
|
||||||
|
password: ${env:REDIS_PASSWORD}
|
||||||
|
|
||||||
|
providers:
|
||||||
|
- id: default-atlassian
|
||||||
|
description: "The default Atlassian provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: atlassian
|
||||||
|
client_id: ${env:ATLASSIAN_CLIENT_ID}
|
||||||
|
client_secret: ${env:ATLASSIAN_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-discord
|
||||||
|
description: "The default Discord provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: discord
|
||||||
|
client_id: ${env:DISCORD_CLIENT_ID}
|
||||||
|
client_secret: ${env:DISCORD_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-dropbox
|
||||||
|
description: "The default Dropbox provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: dropbox
|
||||||
|
client_id: ${env:DROPBOX_CLIENT_ID}
|
||||||
|
client_secret: ${env:DROPBOX_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-github
|
||||||
|
description: "The default GitHub provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: github
|
||||||
|
client_id: ${env:GITHUB_CLIENT_ID}
|
||||||
|
client_secret: ${env:GITHUB_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-google
|
||||||
|
description: "The default Google provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: google
|
||||||
|
client_id: ${env:GOOGLE_CLIENT_ID}
|
||||||
|
client_secret: ${env:GOOGLE_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-linkedin
|
||||||
|
description: "The default LinkedIn provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: linkedin
|
||||||
|
client_id: ${env:LINKEDIN_CLIENT_ID}
|
||||||
|
client_secret: ${env:LINKEDIN_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-microsoft
|
||||||
|
description: "The default Microsoft provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: microsoft
|
||||||
|
client_id: ${env:MICROSOFT_CLIENT_ID}
|
||||||
|
client_secret: ${env:MICROSOFT_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-slack
|
||||||
|
description: "The default Slack provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: slack
|
||||||
|
client_id: ${env:SLACK_CLIENT_ID}
|
||||||
|
client_secret: ${env:SLACK_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-spotify
|
||||||
|
description: "The default Spotify provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: spotify
|
||||||
|
client_id: ${env:SPOTIFY_CLIENT_ID}
|
||||||
|
client_secret: ${env:SPOTIFY_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-x
|
||||||
|
description: "The default X provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: x
|
||||||
|
client_id: ${env:X_CLIENT_ID}
|
||||||
|
client_secret: ${env:X_CLIENT_SECRET}
|
||||||
|
|
||||||
|
- id: default-zoom
|
||||||
|
description: "The default Zoom provider"
|
||||||
|
enabled: false
|
||||||
|
type: oauth2
|
||||||
|
provider_id: zoom
|
||||||
|
client_id: ${env:ZOOM_CLIENT_ID}
|
||||||
|
client_secret: ${env:ZOOM_CLIENT_SECRET}
|
||||||
48
docker/env.example
Normal file
48
docker/env.example
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
### LLM ###
|
||||||
|
|
||||||
|
OPENAI_API_KEY=
|
||||||
|
ANTHROPIC_API_KEY=
|
||||||
|
|
||||||
|
### Auth providers ###
|
||||||
|
|
||||||
|
GITHUB_CLIENT_ID=
|
||||||
|
GITHUB_CLIENT_SECRET=
|
||||||
|
|
||||||
|
GOOGLE_CLIENT_ID=""
|
||||||
|
GOOGLE_CLIENT_SECRET=
|
||||||
|
|
||||||
|
LINKEDIN_CLIENT_ID=
|
||||||
|
LINKEDIN_CLIENT_SECRET=""
|
||||||
|
|
||||||
|
MICROSOFT_CLIENT_ID=
|
||||||
|
MICROSOFT_CLIENT_SECRET=""
|
||||||
|
|
||||||
|
SLACK_CLIENT_ID=""
|
||||||
|
SLACK_CLIENT_SECRET=
|
||||||
|
|
||||||
|
SPOTIFY_CLIENT_ID=
|
||||||
|
SPOTIFY_CLIENT_SECRET=
|
||||||
|
|
||||||
|
X_CLIENT_ID=
|
||||||
|
X_CLIENT_SECRET=
|
||||||
|
|
||||||
|
ZOOM_CLIENT_ID=
|
||||||
|
ZOOM_CLIENT_SECRET=
|
||||||
|
|
||||||
|
### WORKER ###
|
||||||
|
|
||||||
|
WORKER_URL="http://arcade-worker:8002"
|
||||||
|
|
||||||
|
### Redis ###
|
||||||
|
|
||||||
|
REDIS_HOST=arcade-redis
|
||||||
|
REDIS_PORT=6379
|
||||||
|
REDIS_PASSWORD=""
|
||||||
|
RATE_LIMIT_REQS_PER_MIN=100
|
||||||
|
|
||||||
|
### ARCADE ###
|
||||||
|
|
||||||
|
ARCADE_HOME=/app
|
||||||
|
ARCADE_WORKER_SECRET=dev
|
||||||
|
ROOT_KEY_1=supersecret
|
||||||
47
docker/nginx.conf
Normal file
47
docker/nginx.conf
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
pid /run/nginx.pid;
|
||||||
|
|
||||||
|
include /usr/share/nginx/modules/*.conf;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
sendfile on;
|
||||||
|
client_max_body_size 5M;
|
||||||
|
client_body_buffer_size 5M;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_comp_level 2;
|
||||||
|
gzip_types text/plain text/css text/javascript application/javascript application/xml image/jpeg image/gif image/png;
|
||||||
|
gzip_vary on;
|
||||||
|
|
||||||
|
keepalive_timeout 300;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
server_name arcade-engine:9099;
|
||||||
|
|
||||||
|
root /app;
|
||||||
|
client_max_body_size 10m;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://arcade-engine:9099;
|
||||||
|
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
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_connect_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo "Installing toolkits..."
|
|
||||||
for toolkit in $(echo $TOOLKITS | tr "," " "); do
|
|
||||||
echo "Installing $toolkit..."
|
|
||||||
pip install $toolkit
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Starting arcade..."
|
echo "Starting arcade..."
|
||||||
arcade workerup --host $HOST --port $PORT $([ "$OTEL_ENABLE" = "true" ] && echo "--otel-enable")
|
arcade workerup --host $HOST --port $PORT $([ "$OTEL_ENABLE" = "true" ] && echo "--otel-enable")
|
||||||
|
|
|
||||||
11
docker/toolkits.txt
Normal file
11
docker/toolkits.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
arcade-code-sandbox
|
||||||
|
arcade-github
|
||||||
|
arcade-google
|
||||||
|
arcade-linkedin
|
||||||
|
arcade-math
|
||||||
|
arcade-search
|
||||||
|
arcade-slack
|
||||||
|
arcade-spotify
|
||||||
|
arcade-web
|
||||||
|
arcade-x
|
||||||
|
arcade-zoom
|
||||||
10
examples/serving-tools/docker/Dockerfile
Normal file
10
examples/serving-tools/docker/Dockerfile
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
ARG VERSION=latest
|
||||||
|
|
||||||
|
# Base worker image
|
||||||
|
FROM ghcr.io/arcadeai/worker-base:${VERSION}
|
||||||
|
|
||||||
|
# Copy requirements and constraints
|
||||||
|
COPY toolkits.txt ./
|
||||||
|
|
||||||
|
# Install toolkits from file
|
||||||
|
RUN pip install -r toolkits.txt
|
||||||
30
examples/serving-tools/docker/README.md
Normal file
30
examples/serving-tools/docker/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
## Custom Worker Image
|
||||||
|
|
||||||
|
This example shows how to build a custom worker image with toolkits.
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Docker
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t custom-worker:0.1.0 .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -p 8002:8002 custom-worker:0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Change the Toolkits
|
||||||
|
|
||||||
|
To change the toolkits, edit the `toolkits.txt` file.
|
||||||
|
|
||||||
|
```
|
||||||
|
arcade-google==0.1.0
|
||||||
|
arcade-web==0.1.0
|
||||||
|
arcade-zoom==0.1.2
|
||||||
|
...
|
||||||
|
```
|
||||||
1
examples/serving-tools/docker/toolkits.txt
Normal file
1
examples/serving-tools/docker/toolkits.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
arcade-google
|
||||||
17
examples/serving-tools/modal/README.md
Normal file
17
examples/serving-tools/modal/README.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
## Deploy a Custom Arcade Worker on Modal
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Python 3.10+
|
||||||
|
- Modal CLI
|
||||||
|
|
||||||
|
### Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd examples/serving-tools
|
||||||
|
modal deploy run-arcade-worker.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Changing the Toolkits
|
||||||
|
|
||||||
|
To change the toolkits, edit the `toolkits` list in the `run-arcade-worker.py` file.
|
||||||
39
examples/serving-tools/modal/run-arcade-worker.py
Normal file
39
examples/serving-tools/modal/run-arcade-worker.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from modal import App, Image, asgi_app
|
||||||
|
|
||||||
|
# Define the FastAPI app
|
||||||
|
app = App("arcade-worker")
|
||||||
|
|
||||||
|
toolkits = ["arcade-google", "arcade-slack"]
|
||||||
|
|
||||||
|
image = (
|
||||||
|
Image.debian_slim()
|
||||||
|
.pip_install("arcade-ai[fastapi]")
|
||||||
|
.pip_install(toolkits)
|
||||||
|
.pip_install("fastapi>=0.115.3")
|
||||||
|
.pip_install("uvicorn>=0.24.0")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.function(image=image)
|
||||||
|
@asgi_app()
|
||||||
|
def fastapi_app():
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
from arcade.sdk import Toolkit
|
||||||
|
from arcade.worker.fastapi.worker import FastAPIWorker
|
||||||
|
|
||||||
|
web_app = FastAPI()
|
||||||
|
|
||||||
|
# Initialize app and Arcade FastAPIWorker
|
||||||
|
worker_secret = os.environ.get("ARCADE_WORKER_SECRET", "dev")
|
||||||
|
worker = FastAPIWorker(web_app, secret=worker_secret)
|
||||||
|
|
||||||
|
# Register toolkits we've installed
|
||||||
|
installed_toolkits = Toolkit.find_all_arcade_toolkits()
|
||||||
|
for toolkit in toolkits:
|
||||||
|
if toolkit in installed_toolkits:
|
||||||
|
worker.register_toolkit(toolkit)
|
||||||
|
|
||||||
|
return web_app
|
||||||
Loading…
Reference in a new issue