From 3b1b4c234b1ef9c3982504f7bdcfff29c2c17309 Mon Sep 17 00:00:00 2001 From: shenlan Date: Sat, 11 Oct 2025 19:01:58 +0800 Subject: [PATCH] Add offline package builders for new AI tooling --- .../offline-package-autogen-studio.yaml | 159 +++++++++++++++ .github/workflows/offline-package-dify.yaml | 192 ++++++++++++++++++ .../workflows/offline-package-flowise.yaml | 159 +++++++++++++++ .github/workflows/offline-package-n8n.yaml | 177 ++++++++++++++++ .../workflows/offline-package-ragflow.yaml | 189 +++++++++++++++++ .../autogen-studio/deploy-autogen-studio.sh | 86 ++++++++ .../autogen-studio/docker-compose.yaml | 18 ++ gitops/scripts/dify/deploy-dify.sh | 86 ++++++++ gitops/scripts/dify/docker-compose.yaml | 72 +++++++ gitops/scripts/flowise/deploy-flowise.sh | 86 ++++++++ gitops/scripts/flowise/docker-compose.yaml | 19 ++ gitops/scripts/n8n/deploy-n8n.sh | 86 ++++++++ gitops/scripts/n8n/docker-compose.yaml | 37 ++++ gitops/scripts/ragflow/deploy-ragflow.sh | 86 ++++++++ gitops/scripts/ragflow/docker-compose.yaml | 37 ++++ 15 files changed, 1489 insertions(+) create mode 100644 .github/workflows/offline-package-autogen-studio.yaml create mode 100644 .github/workflows/offline-package-dify.yaml create mode 100644 .github/workflows/offline-package-flowise.yaml create mode 100644 .github/workflows/offline-package-n8n.yaml create mode 100644 .github/workflows/offline-package-ragflow.yaml create mode 100755 gitops/scripts/autogen-studio/deploy-autogen-studio.sh create mode 100644 gitops/scripts/autogen-studio/docker-compose.yaml create mode 100755 gitops/scripts/dify/deploy-dify.sh create mode 100644 gitops/scripts/dify/docker-compose.yaml create mode 100755 gitops/scripts/flowise/deploy-flowise.sh create mode 100644 gitops/scripts/flowise/docker-compose.yaml create mode 100755 gitops/scripts/n8n/deploy-n8n.sh create mode 100644 gitops/scripts/n8n/docker-compose.yaml create mode 100755 gitops/scripts/ragflow/deploy-ragflow.sh create mode 100644 gitops/scripts/ragflow/docker-compose.yaml diff --git a/.github/workflows/offline-package-autogen-studio.yaml b/.github/workflows/offline-package-autogen-studio.yaml new file mode 100644 index 0000000..a2a0ee1 --- /dev/null +++ b/.github/workflows/offline-package-autogen-studio.yaml @@ -0,0 +1,159 @@ +name: Build Offline AutoGen Studio Installer + +on: + push: + paths: + - 'gitops/scripts/autogen-studio/**' + - '.github/workflows/offline-package-autogen-studio.yaml' + workflow_dispatch: + inputs: + tag: + description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-autogen-studio-" + required: false + type: string + autogen_tag: + description: "AutoGen Studio container tag (default: latest)" + required: false + type: string + +permissions: + contents: write + +concurrency: + group: build-offline-autogen-studio + cancel-in-progress: false + +jobs: + build-offline-installer: + strategy: + matrix: + arch: [amd64, arm64] + runs-on: ubuntu-latest + outputs: + autogen_tag: ${{ steps.resolve.outputs.autogen_tag }} + steps: + - uses: actions/checkout@v4 + + - name: Resolve image tag + id: resolve + env: + INPUT_AUTOGEN_TAG: ${{ github.event.inputs.autogen_tag }} + run: | + set -euo pipefail + AUTOGEN_TAG=${INPUT_AUTOGEN_TAG:-latest} + echo "autogen_tag=${AUTOGEN_TAG}" >> "$GITHUB_OUTPUT" + + - name: Prepare directories + run: | + set -euo pipefail + rm -rf offline-installer + mkdir -p offline-installer/{images,scripts} + + - name: Stage compose file and scripts + env: + AUTOGEN_TAG: ${{ steps.resolve.outputs.autogen_tag }} + run: | + set -euo pipefail + cp gitops/scripts/autogen-studio/docker-compose.yaml offline-installer/docker-compose.yaml + sed -i "s/__AUTOGEN_TAG__/${AUTOGEN_TAG}/g" offline-installer/docker-compose.yaml + cp gitops/scripts/autogen-studio/deploy-autogen-studio.sh offline-installer/scripts/ + chmod +x offline-installer/scripts/deploy-autogen-studio.sh + cat <<'README' > offline-installer/README.md +# Offline AutoGen Studio Installer + +This archive contains container images and helper assets for deploying AutoGen Studio with Docker Compose. + +## Contents +- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images. +- `images/`: Pre-pulled container images saved as tar archives. +- `scripts/deploy-autogen-studio.sh`: Helper script to load the images and manage the compose stack. + +## Usage +1. Extract the archive on a host with Docker/nerdctl available. +2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-autogen-studio.sh load-images` to import the images with nerdctl. +3. Start the stack: `./scripts/deploy-autogen-studio.sh up`. +4. Access AutoGen Studio at http://localhost:9090. + +Adjust the compose file as needed before running the helper script. +README + + - name: Pull & export container images + env: + AUTOGEN_TAG: ${{ steps.resolve.outputs.autogen_tag }} + run: | + set -euo pipefail + image="autogenstudio/autogen-studio:${AUTOGEN_TAG}" + docker pull "$image" + safe=$(echo "$image" | tr '/:' '-_') + docker save "$image" -o "offline-installer/images/${safe}.tar" + + - name: Package offline installer + run: | + set -euo pipefail + tar -czf offline-package-autogen-studio-${{ matrix.arch }}.tar.gz -C offline-installer . + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: offline-package-autogen-studio-${{ matrix.arch }} + path: offline-package-autogen-studio-${{ matrix.arch }}.tar.gz + + test-offline-installer: + needs: build-offline-installer + strategy: + matrix: + arch: [amd64] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-autogen-studio-${{ matrix.arch }} + path: offline-test + + - name: Verify archive integrity + run: | + set -euo pipefail + cd offline-test + tar -tzf offline-package-autogen-studio-${{ matrix.arch }}.tar.gz > /dev/null + + publish-release: + needs: test-offline-installer + runs-on: ubuntu-latest + env: + TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-autogen-studio-{0}', github.run_number) }} + steps: + - uses: actions/checkout@v4 + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + release_name: Build ${{ env.TAG_NAME }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Download amd64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-autogen-studio-amd64 + path: release-artifacts/amd64 + + - name: Download arm64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-autogen-studio-arm64 + path: release-artifacts/arm64 + + - name: Upload offline installers to GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + files: | + release-artifacts/amd64/offline-package-autogen-studio-amd64.tar.gz + release-artifacts/arm64/offline-package-autogen-studio-arm64.tar.gz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/offline-package-dify.yaml b/.github/workflows/offline-package-dify.yaml new file mode 100644 index 0000000..86138ee --- /dev/null +++ b/.github/workflows/offline-package-dify.yaml @@ -0,0 +1,192 @@ +name: Build Offline Dify Installer + +on: + push: + paths: + - 'gitops/scripts/dify/**' + - '.github/workflows/offline-package-dify.yaml' + workflow_dispatch: + inputs: + tag: + description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-dify-" + required: false + type: string + dify_tag: + description: "Dify container tag (default: latest)" + required: false + type: string + postgres_tag: + description: "Postgres image tag (default: 15-alpine)" + required: false + type: string + redis_tag: + description: "Redis image tag (default: 7-alpine)" + required: false + type: string + +permissions: + contents: write + +concurrency: + group: build-offline-dify + cancel-in-progress: false + +jobs: + build-offline-installer: + strategy: + matrix: + arch: [amd64, arm64] + runs-on: ubuntu-latest + outputs: + dify_tag: ${{ steps.resolve.outputs.dify_tag }} + postgres_tag: ${{ steps.resolve.outputs.postgres_tag }} + redis_tag: ${{ steps.resolve.outputs.redis_tag }} + steps: + - uses: actions/checkout@v4 + + - name: Resolve image tags + id: resolve + env: + INPUT_DIFY_TAG: ${{ github.event.inputs.dify_tag }} + INPUT_POSTGRES_TAG: ${{ github.event.inputs.postgres_tag }} + INPUT_REDIS_TAG: ${{ github.event.inputs.redis_tag }} + run: | + set -euo pipefail + DIFY_TAG=${INPUT_DIFY_TAG:-latest} + POSTGRES_TAG=${INPUT_POSTGRES_TAG:-15-alpine} + REDIS_TAG=${INPUT_REDIS_TAG:-7-alpine} + { + echo "dify_tag=${DIFY_TAG}" + echo "postgres_tag=${POSTGRES_TAG}" + echo "redis_tag=${REDIS_TAG}" + } >> "$GITHUB_OUTPUT" + + - name: Prepare directories + run: | + set -euo pipefail + rm -rf offline-installer + mkdir -p offline-installer/{images,scripts} + + - name: Stage compose file and scripts + env: + DIFY_TAG: ${{ steps.resolve.outputs.dify_tag }} + POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }} + REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }} + run: | + set -euo pipefail + cp gitops/scripts/dify/docker-compose.yaml offline-installer/docker-compose.yaml + sed -i "s/__DIFY_TAG__/${DIFY_TAG}/g" offline-installer/docker-compose.yaml + sed -i "s/__POSTGRES_TAG__/${POSTGRES_TAG}/g" offline-installer/docker-compose.yaml + sed -i "s/__REDIS_TAG__/${REDIS_TAG}/g" offline-installer/docker-compose.yaml + cp gitops/scripts/dify/deploy-dify.sh offline-installer/scripts/ + chmod +x offline-installer/scripts/deploy-dify.sh + cat <<'README' > offline-installer/README.md +# Offline Dify Installer + +This archive contains container images and helper assets for deploying Dify with Docker Compose. + +## Contents +- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images. +- `images/`: Pre-pulled container images saved as tar archives. +- `scripts/deploy-dify.sh`: Helper script to load the images and manage the compose stack. + +## Usage +1. Extract the archive on a host with Docker/nerdctl available. +2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-dify.sh load-images` to import the images with nerdctl. +3. Start the stack: `./scripts/deploy-dify.sh up`. +4. Access the Dify web UI at http://localhost:8080. + +Adjust the compose file as needed before running the helper script. +README + + - name: Pull & export container images + env: + DIFY_TAG: ${{ steps.resolve.outputs.dify_tag }} + POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }} + REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }} + run: | + set -euo pipefail + images=( + "langgenius/dify-api:${DIFY_TAG}" + "langgenius/dify-worker:${DIFY_TAG}" + "langgenius/dify-web:${DIFY_TAG}" + "langgenius/dify-nginx:${DIFY_TAG}" + "postgres:${POSTGRES_TAG}" + "redis:${REDIS_TAG}" + ) + for image in "${images[@]}"; do + docker pull "$image" + safe=$(echo "$image" | tr '/:' '-_') + docker save "$image" -o "offline-installer/images/${safe}.tar" + done + + - name: Package offline installer + run: | + set -euo pipefail + tar -czf offline-package-dify-${{ matrix.arch }}.tar.gz -C offline-installer . + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: offline-package-dify-${{ matrix.arch }} + path: offline-package-dify-${{ matrix.arch }}.tar.gz + + test-offline-installer: + needs: build-offline-installer + strategy: + matrix: + arch: [amd64] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-dify-${{ matrix.arch }} + path: offline-test + + - name: Verify archive integrity + run: | + set -euo pipefail + cd offline-test + tar -tzf offline-package-dify-${{ matrix.arch }}.tar.gz > /dev/null + + publish-release: + needs: test-offline-installer + runs-on: ubuntu-latest + env: + TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-dify-{0}', github.run_number) }} + steps: + - uses: actions/checkout@v4 + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + release_name: Build ${{ env.TAG_NAME }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Download amd64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-dify-amd64 + path: release-artifacts/amd64 + + - name: Download arm64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-dify-arm64 + path: release-artifacts/arm64 + + - name: Upload offline installers to GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + files: | + release-artifacts/amd64/offline-package-dify-amd64.tar.gz + release-artifacts/arm64/offline-package-dify-arm64.tar.gz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/offline-package-flowise.yaml b/.github/workflows/offline-package-flowise.yaml new file mode 100644 index 0000000..b5493d2 --- /dev/null +++ b/.github/workflows/offline-package-flowise.yaml @@ -0,0 +1,159 @@ +name: Build Offline Flowise Installer + +on: + push: + paths: + - 'gitops/scripts/flowise/**' + - '.github/workflows/offline-package-flowise.yaml' + workflow_dispatch: + inputs: + tag: + description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-flowise-" + required: false + type: string + flowise_tag: + description: "Flowise container tag (default: latest)" + required: false + type: string + +permissions: + contents: write + +concurrency: + group: build-offline-flowise + cancel-in-progress: false + +jobs: + build-offline-installer: + strategy: + matrix: + arch: [amd64, arm64] + runs-on: ubuntu-latest + outputs: + flowise_tag: ${{ steps.resolve.outputs.flowise_tag }} + steps: + - uses: actions/checkout@v4 + + - name: Resolve image tag + id: resolve + env: + INPUT_FLOWISE_TAG: ${{ github.event.inputs.flowise_tag }} + run: | + set -euo pipefail + FLOWISE_TAG=${INPUT_FLOWISE_TAG:-latest} + echo "flowise_tag=${FLOWISE_TAG}" >> "$GITHUB_OUTPUT" + + - name: Prepare directories + run: | + set -euo pipefail + rm -rf offline-installer + mkdir -p offline-installer/{images,scripts} + + - name: Stage compose file and scripts + env: + FLOWISE_TAG: ${{ steps.resolve.outputs.flowise_tag }} + run: | + set -euo pipefail + cp gitops/scripts/flowise/docker-compose.yaml offline-installer/docker-compose.yaml + sed -i "s/__FLOWISE_TAG__/${FLOWISE_TAG}/g" offline-installer/docker-compose.yaml + cp gitops/scripts/flowise/deploy-flowise.sh offline-installer/scripts/ + chmod +x offline-installer/scripts/deploy-flowise.sh + cat <<'README' > offline-installer/README.md +# Offline Flowise Installer + +This archive contains container images and helper assets for deploying Flowise with Docker Compose. + +## Contents +- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images. +- `images/`: Pre-pulled container images saved as tar archives. +- `scripts/deploy-flowise.sh`: Helper script to load the images and manage the compose stack. + +## Usage +1. Extract the archive on a host with Docker/nerdctl available. +2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-flowise.sh load-images` to import the images with nerdctl. +3. Start the stack: `./scripts/deploy-flowise.sh up`. +4. Access the Flowise UI at http://localhost:3000. + +Adjust the compose file as needed before running the helper script. +README + + - name: Pull & export container images + env: + FLOWISE_TAG: ${{ steps.resolve.outputs.flowise_tag }} + run: | + set -euo pipefail + image="flowiseai/flowise:${FLOWISE_TAG}" + docker pull "$image" + safe=$(echo "$image" | tr '/:' '-_') + docker save "$image" -o "offline-installer/images/${safe}.tar" + + - name: Package offline installer + run: | + set -euo pipefail + tar -czf offline-package-flowise-${{ matrix.arch }}.tar.gz -C offline-installer . + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: offline-package-flowise-${{ matrix.arch }} + path: offline-package-flowise-${{ matrix.arch }}.tar.gz + + test-offline-installer: + needs: build-offline-installer + strategy: + matrix: + arch: [amd64] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-flowise-${{ matrix.arch }} + path: offline-test + + - name: Verify archive integrity + run: | + set -euo pipefail + cd offline-test + tar -tzf offline-package-flowise-${{ matrix.arch }}.tar.gz > /dev/null + + publish-release: + needs: test-offline-installer + runs-on: ubuntu-latest + env: + TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-flowise-{0}', github.run_number) }} + steps: + - uses: actions/checkout@v4 + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + release_name: Build ${{ env.TAG_NAME }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Download amd64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-flowise-amd64 + path: release-artifacts/amd64 + + - name: Download arm64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-flowise-arm64 + path: release-artifacts/arm64 + + - name: Upload offline installers to GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + files: | + release-artifacts/amd64/offline-package-flowise-amd64.tar.gz + release-artifacts/arm64/offline-package-flowise-arm64.tar.gz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/offline-package-n8n.yaml b/.github/workflows/offline-package-n8n.yaml new file mode 100644 index 0000000..89e5f7f --- /dev/null +++ b/.github/workflows/offline-package-n8n.yaml @@ -0,0 +1,177 @@ +name: Build Offline n8n Installer + +on: + push: + paths: + - 'gitops/scripts/n8n/**' + - '.github/workflows/offline-package-n8n.yaml' + workflow_dispatch: + inputs: + tag: + description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-n8n-" + required: false + type: string + n8n_tag: + description: "n8n container tag (default: latest)" + required: false + type: string + postgres_tag: + description: "Postgres image tag (default: 15-alpine)" + required: false + type: string + +permissions: + contents: write + +concurrency: + group: build-offline-n8n + cancel-in-progress: false + +jobs: + build-offline-installer: + strategy: + matrix: + arch: [amd64, arm64] + runs-on: ubuntu-latest + outputs: + n8n_tag: ${{ steps.resolve.outputs.n8n_tag }} + postgres_tag: ${{ steps.resolve.outputs.postgres_tag }} + steps: + - uses: actions/checkout@v4 + + - name: Resolve image tags + id: resolve + env: + INPUT_N8N_TAG: ${{ github.event.inputs.n8n_tag }} + INPUT_POSTGRES_TAG: ${{ github.event.inputs.postgres_tag }} + run: | + set -euo pipefail + N8N_TAG=${INPUT_N8N_TAG:-latest} + POSTGRES_TAG=${INPUT_POSTGRES_TAG:-15-alpine} + { + echo "n8n_tag=${N8N_TAG}" + echo "postgres_tag=${POSTGRES_TAG}" + } >> "$GITHUB_OUTPUT" + + - name: Prepare directories + run: | + set -euo pipefail + rm -rf offline-installer + mkdir -p offline-installer/{images,scripts} + + - name: Stage compose file and scripts + env: + N8N_TAG: ${{ steps.resolve.outputs.n8n_tag }} + POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }} + run: | + set -euo pipefail + cp gitops/scripts/n8n/docker-compose.yaml offline-installer/docker-compose.yaml + sed -i "s/__N8N_TAG__/${N8N_TAG}/g" offline-installer/docker-compose.yaml + sed -i "s/__POSTGRES_TAG__/${POSTGRES_TAG}/g" offline-installer/docker-compose.yaml + cp gitops/scripts/n8n/deploy-n8n.sh offline-installer/scripts/ + chmod +x offline-installer/scripts/deploy-n8n.sh + cat <<'README' > offline-installer/README.md +# Offline n8n Installer + +This archive contains container images and helper assets for deploying n8n with Docker Compose. + +## Contents +- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images. +- `images/`: Pre-pulled container images saved as tar archives. +- `scripts/deploy-n8n.sh`: Helper script to load the images and manage the compose stack. + +## Usage +1. Extract the archive on a host with Docker/nerdctl available. +2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-n8n.sh load-images` to import the images with nerdctl. +3. Start the stack: `./scripts/deploy-n8n.sh up`. +4. Access the n8n UI at http://localhost:5678. + +Adjust the compose file as needed before running the helper script. +README + + - name: Pull & export container images + env: + N8N_TAG: ${{ steps.resolve.outputs.n8n_tag }} + POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }} + run: | + set -euo pipefail + images=( + "n8nio/n8n:${N8N_TAG}" + "postgres:${POSTGRES_TAG}" + ) + for image in "${images[@]}"; do + docker pull "$image" + safe=$(echo "$image" | tr '/:' '-_') + docker save "$image" -o "offline-installer/images/${safe}.tar" + done + + - name: Package offline installer + run: | + set -euo pipefail + tar -czf offline-package-n8n-${{ matrix.arch }}.tar.gz -C offline-installer . + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: offline-package-n8n-${{ matrix.arch }} + path: offline-package-n8n-${{ matrix.arch }}.tar.gz + + test-offline-installer: + needs: build-offline-installer + strategy: + matrix: + arch: [amd64] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-n8n-${{ matrix.arch }} + path: offline-test + + - name: Verify archive integrity + run: | + set -euo pipefail + cd offline-test + tar -tzf offline-package-n8n-${{ matrix.arch }}.tar.gz > /dev/null + + publish-release: + needs: test-offline-installer + runs-on: ubuntu-latest + env: + TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-n8n-{0}', github.run_number) }} + steps: + - uses: actions/checkout@v4 + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + release_name: Build ${{ env.TAG_NAME }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Download amd64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-n8n-amd64 + path: release-artifacts/amd64 + + - name: Download arm64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-n8n-arm64 + path: release-artifacts/arm64 + + - name: Upload offline installers to GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + files: | + release-artifacts/amd64/offline-package-n8n-amd64.tar.gz + release-artifacts/arm64/offline-package-n8n-arm64.tar.gz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/offline-package-ragflow.yaml b/.github/workflows/offline-package-ragflow.yaml new file mode 100644 index 0000000..0892b08 --- /dev/null +++ b/.github/workflows/offline-package-ragflow.yaml @@ -0,0 +1,189 @@ +name: Build Offline RAGFlow Installer + +on: + push: + paths: + - 'gitops/scripts/ragflow/**' + - '.github/workflows/offline-package-ragflow.yaml' + workflow_dispatch: + inputs: + tag: + description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-ragflow-" + required: false + type: string + ragflow_tag: + description: "RAGFlow container tag (default: latest)" + required: false + type: string + postgres_tag: + description: "Postgres image tag (default: 15-alpine)" + required: false + type: string + redis_tag: + description: "Redis image tag (default: 7-alpine)" + required: false + type: string + +permissions: + contents: write + +concurrency: + group: build-offline-ragflow + cancel-in-progress: false + +jobs: + build-offline-installer: + strategy: + matrix: + arch: [amd64, arm64] + runs-on: ubuntu-latest + outputs: + ragflow_tag: ${{ steps.resolve.outputs.ragflow_tag }} + postgres_tag: ${{ steps.resolve.outputs.postgres_tag }} + redis_tag: ${{ steps.resolve.outputs.redis_tag }} + steps: + - uses: actions/checkout@v4 + + - name: Resolve image tags + id: resolve + env: + INPUT_RAGFLOW_TAG: ${{ github.event.inputs.ragflow_tag }} + INPUT_POSTGRES_TAG: ${{ github.event.inputs.postgres_tag }} + INPUT_REDIS_TAG: ${{ github.event.inputs.redis_tag }} + run: | + set -euo pipefail + RAGFLOW_TAG=${INPUT_RAGFLOW_TAG:-latest} + POSTGRES_TAG=${INPUT_POSTGRES_TAG:-15-alpine} + REDIS_TAG=${INPUT_REDIS_TAG:-7-alpine} + { + echo "ragflow_tag=${RAGFLOW_TAG}" + echo "postgres_tag=${POSTGRES_TAG}" + echo "redis_tag=${REDIS_TAG}" + } >> "$GITHUB_OUTPUT" + + - name: Prepare directories + run: | + set -euo pipefail + rm -rf offline-installer + mkdir -p offline-installer/{images,scripts} + + - name: Stage compose file and scripts + env: + RAGFLOW_TAG: ${{ steps.resolve.outputs.ragflow_tag }} + POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }} + REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }} + run: | + set -euo pipefail + cp gitops/scripts/ragflow/docker-compose.yaml offline-installer/docker-compose.yaml + sed -i "s/__RAGFLOW_TAG__/${RAGFLOW_TAG}/g" offline-installer/docker-compose.yaml + sed -i "s/__POSTGRES_TAG__/${POSTGRES_TAG}/g" offline-installer/docker-compose.yaml + sed -i "s/__REDIS_TAG__/${REDIS_TAG}/g" offline-installer/docker-compose.yaml + cp gitops/scripts/ragflow/deploy-ragflow.sh offline-installer/scripts/ + chmod +x offline-installer/scripts/deploy-ragflow.sh + cat <<'README' > offline-installer/README.md +# Offline RAGFlow Installer + +This archive contains container images and helper assets for deploying RAGFlow with Docker Compose. + +## Contents +- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images. +- `images/`: Pre-pulled container images saved as tar archives. +- `scripts/deploy-ragflow.sh`: Helper script to load the images and manage the compose stack. + +## Usage +1. Extract the archive on a host with Docker/nerdctl available. +2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-ragflow.sh load-images` to import the images with nerdctl. +3. Start the stack: `./scripts/deploy-ragflow.sh up`. +4. Access the RAGFlow UI at http://localhost:3001. + +Adjust the compose file as needed before running the helper script. Configure external vector stores or storage services as required by your deployment. +README + + - name: Pull & export container images + env: + RAGFLOW_TAG: ${{ steps.resolve.outputs.ragflow_tag }} + POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }} + REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }} + run: | + set -euo pipefail + images=( + "ragflow/ragflow:${RAGFLOW_TAG}" + "postgres:${POSTGRES_TAG}" + "redis:${REDIS_TAG}" + ) + for image in "${images[@]}"; do + docker pull "$image" + safe=$(echo "$image" | tr '/:' '-_') + docker save "$image" -o "offline-installer/images/${safe}.tar" + done + + - name: Package offline installer + run: | + set -euo pipefail + tar -czf offline-package-ragflow-${{ matrix.arch }}.tar.gz -C offline-installer . + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: offline-package-ragflow-${{ matrix.arch }} + path: offline-package-ragflow-${{ matrix.arch }}.tar.gz + + test-offline-installer: + needs: build-offline-installer + strategy: + matrix: + arch: [amd64] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-ragflow-${{ matrix.arch }} + path: offline-test + + - name: Verify archive integrity + run: | + set -euo pipefail + cd offline-test + tar -tzf offline-package-ragflow-${{ matrix.arch }}.tar.gz > /dev/null + + publish-release: + needs: test-offline-installer + runs-on: ubuntu-latest + env: + TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-ragflow-{0}', github.run_number) }} + steps: + - uses: actions/checkout@v4 + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + release_name: Build ${{ env.TAG_NAME }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Download amd64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-ragflow-amd64 + path: release-artifacts/amd64 + + - name: Download arm64 artifact + uses: actions/download-artifact@v4 + with: + name: offline-package-ragflow-arm64 + path: release-artifacts/arm64 + + - name: Upload offline installers to GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.TAG_NAME }} + files: | + release-artifacts/amd64/offline-package-ragflow-amd64.tar.gz + release-artifacts/arm64/offline-package-ragflow-arm64.tar.gz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/gitops/scripts/autogen-studio/deploy-autogen-studio.sh b/gitops/scripts/autogen-studio/deploy-autogen-studio.sh new file mode 100755 index 0000000..8b948c4 --- /dev/null +++ b/gitops/scripts/autogen-studio/deploy-autogen-studio.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="AutoGen Studio" + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) +COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml" +IMAGES_DIR="${OFFLINE_ROOT}/images" +IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}" + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +load_images() { + if ! command_exists "${IMAGE_LOAD_TOOL}"; then + echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2 + exit 1 + fi + + if [ ! -d "${IMAGES_DIR}" ]; then + echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2 + return + fi + + shopt -s nullglob + local tarball + for tarball in "${IMAGES_DIR}"/*.tar; do + echo "Loading container images from ${tarball}" + "${IMAGE_LOAD_TOOL}" load -i "${tarball}" + done + shopt -u nullglob +} + +compose() { + if command_exists docker && docker compose version >/dev/null 2>&1; then + docker compose "$@" + elif command_exists docker-compose; then + docker-compose "$@" + else + echo "Error: docker compose plugin or docker-compose binary is required" >&2 + exit 1 + fi +} + +usage() { + cat <&2 + usage + exit 1 + ;; +esac diff --git a/gitops/scripts/autogen-studio/docker-compose.yaml b/gitops/scripts/autogen-studio/docker-compose.yaml new file mode 100644 index 0000000..40ca3c2 --- /dev/null +++ b/gitops/scripts/autogen-studio/docker-compose.yaml @@ -0,0 +1,18 @@ +version: "3.8" + +services: + autogen-studio: + image: autogenstudio/autogen-studio:__AUTOGEN_TAG__ + container_name: autogen-studio + restart: unless-stopped + ports: + - "9090:9090" + environment: + AUTOGEN_STUDIO_HOST: 0.0.0.0 + AUTOGEN_STUDIO_PORT: 9090 + AUTOGEN_STUDIO_LOG_LEVEL: info + volumes: + - autogen-data:/data + +volumes: + autogen-data: diff --git a/gitops/scripts/dify/deploy-dify.sh b/gitops/scripts/dify/deploy-dify.sh new file mode 100755 index 0000000..0cf7e6f --- /dev/null +++ b/gitops/scripts/dify/deploy-dify.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="Dify" + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) +COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml" +IMAGES_DIR="${OFFLINE_ROOT}/images" +IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}" + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +load_images() { + if ! command_exists "${IMAGE_LOAD_TOOL}"; then + echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2 + exit 1 + fi + + if [ ! -d "${IMAGES_DIR}" ]; then + echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2 + return + fi + + shopt -s nullglob + local tarball + for tarball in "${IMAGES_DIR}"/*.tar; do + echo "Loading container images from ${tarball}" + "${IMAGE_LOAD_TOOL}" load -i "${tarball}" + done + shopt -u nullglob +} + +compose() { + if command_exists docker && docker compose version >/dev/null 2>&1; then + docker compose "$@" + elif command_exists docker-compose; then + docker-compose "$@" + else + echo "Error: docker compose plugin or docker-compose binary is required" >&2 + exit 1 + fi +} + +usage() { + cat <&2 + usage + exit 1 + ;; +esac diff --git a/gitops/scripts/dify/docker-compose.yaml b/gitops/scripts/dify/docker-compose.yaml new file mode 100644 index 0000000..9b80d1b --- /dev/null +++ b/gitops/scripts/dify/docker-compose.yaml @@ -0,0 +1,72 @@ +version: "3.8" + +services: + postgres: + image: postgres:__POSTGRES_TAG__ + container_name: dify-postgres + restart: unless-stopped + environment: + POSTGRES_DB: dify + POSTGRES_USER: dify + POSTGRES_PASSWORD: dify + volumes: + - dify-postgres:/var/lib/postgresql/data + redis: + image: redis:__REDIS_TAG__ + container_name: dify-redis + restart: unless-stopped + command: ["redis-server", "--appendonly", "yes"] + volumes: + - dify-redis:/data + dify-api: + image: langgenius/dify-api:__DIFY_TAG__ + container_name: dify-api + restart: unless-stopped + depends_on: + - postgres + - redis + environment: + DATABASE_URL: postgresql+psycopg://dify:dify@postgres:5432/dify + REDIS_URL: redis://redis:6379/0 + WEB_URL: http://localhost:8080 + WORKER_QUEUE_BROKER_URL: redis://redis:6379/1 + WORKER_QUEUE_BACKEND_URL: redis://redis:6379/2 + volumes: + - dify-storage:/app/storage + dify-worker: + image: langgenius/dify-worker:__DIFY_TAG__ + container_name: dify-worker + restart: unless-stopped + depends_on: + - redis + - dify-api + environment: + REDIS_URL: redis://redis:6379/1 + WORKER_QUEUE_BACKEND_URL: redis://redis:6379/2 + API_URL: http://dify-api:5001 + dify-web: + image: langgenius/dify-web:__DIFY_TAG__ + container_name: dify-web + restart: unless-stopped + depends_on: + - dify-api + environment: + VITE_API_URL: http://dify-nginx + VITE_APP_ENV: production + dify-nginx: + image: langgenius/dify-nginx:__DIFY_TAG__ + container_name: dify-nginx + restart: unless-stopped + ports: + - "8080:80" + depends_on: + - dify-api + - dify-web + environment: + API_HOST: dify-api:5001 + WEB_HOST: dify-web:3000 + +volumes: + dify-postgres: + dify-redis: + dify-storage: diff --git a/gitops/scripts/flowise/deploy-flowise.sh b/gitops/scripts/flowise/deploy-flowise.sh new file mode 100755 index 0000000..4e2e766 --- /dev/null +++ b/gitops/scripts/flowise/deploy-flowise.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="Flowise" + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) +COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml" +IMAGES_DIR="${OFFLINE_ROOT}/images" +IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}" + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +load_images() { + if ! command_exists "${IMAGE_LOAD_TOOL}"; then + echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2 + exit 1 + fi + + if [ ! -d "${IMAGES_DIR}" ]; then + echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2 + return + fi + + shopt -s nullglob + local tarball + for tarball in "${IMAGES_DIR}"/*.tar; do + echo "Loading container images from ${tarball}" + "${IMAGE_LOAD_TOOL}" load -i "${tarball}" + done + shopt -u nullglob +} + +compose() { + if command_exists docker && docker compose version >/dev/null 2>&1; then + docker compose "$@" + elif command_exists docker-compose; then + docker-compose "$@" + else + echo "Error: docker compose plugin or docker-compose binary is required" >&2 + exit 1 + fi +} + +usage() { + cat <&2 + usage + exit 1 + ;; +esac diff --git a/gitops/scripts/flowise/docker-compose.yaml b/gitops/scripts/flowise/docker-compose.yaml new file mode 100644 index 0000000..a1b1a45 --- /dev/null +++ b/gitops/scripts/flowise/docker-compose.yaml @@ -0,0 +1,19 @@ +version: "3.8" + +services: + flowise: + image: flowiseai/flowise:__FLOWISE_TAG__ + container_name: flowise-app + restart: unless-stopped + ports: + - "3000:3000" + environment: + PORT: 3000 + FLOWISE_USERNAME: admin + FLOWISE_PASSWORD: changeme + DATABASE_PATH: /data/flowise.sqlite + volumes: + - flowise-data:/data + +volumes: + flowise-data: diff --git a/gitops/scripts/n8n/deploy-n8n.sh b/gitops/scripts/n8n/deploy-n8n.sh new file mode 100755 index 0000000..163c34a --- /dev/null +++ b/gitops/scripts/n8n/deploy-n8n.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="n8n" + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) +COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml" +IMAGES_DIR="${OFFLINE_ROOT}/images" +IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}" + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +load_images() { + if ! command_exists "${IMAGE_LOAD_TOOL}"; then + echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2 + exit 1 + fi + + if [ ! -d "${IMAGES_DIR}" ]; then + echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2 + return + fi + + shopt -s nullglob + local tarball + for tarball in "${IMAGES_DIR}"/*.tar; do + echo "Loading container images from ${tarball}" + "${IMAGE_LOAD_TOOL}" load -i "${tarball}" + done + shopt -u nullglob +} + +compose() { + if command_exists docker && docker compose version >/dev/null 2>&1; then + docker compose "$@" + elif command_exists docker-compose; then + docker-compose "$@" + else + echo "Error: docker compose plugin or docker-compose binary is required" >&2 + exit 1 + fi +} + +usage() { + cat <&2 + usage + exit 1 + ;; +esac diff --git a/gitops/scripts/n8n/docker-compose.yaml b/gitops/scripts/n8n/docker-compose.yaml new file mode 100644 index 0000000..e4f0666 --- /dev/null +++ b/gitops/scripts/n8n/docker-compose.yaml @@ -0,0 +1,37 @@ +version: "3.8" + +services: + postgres: + image: postgres:__POSTGRES_TAG__ + container_name: n8n-postgres + restart: unless-stopped + environment: + POSTGRES_DB: n8n + POSTGRES_USER: n8n + POSTGRES_PASSWORD: n8n + volumes: + - n8n-postgres:/var/lib/postgresql/data + n8n: + image: n8nio/n8n:__N8N_TAG__ + container_name: n8n-app + restart: unless-stopped + depends_on: + - postgres + ports: + - "5678:5678" + environment: + DB_TYPE: postgresdb + DB_POSTGRESDB_HOST: postgres + DB_POSTGRESDB_PORT: 5432 + DB_POSTGRESDB_DATABASE: n8n + DB_POSTGRESDB_USER: n8n + DB_POSTGRESDB_PASSWORD: n8n + N8N_BASIC_AUTH_ACTIVE: "true" + N8N_BASIC_AUTH_USER: admin + N8N_BASIC_AUTH_PASSWORD: changeme + volumes: + - n8n-data:/home/node/.n8n + +volumes: + n8n-postgres: + n8n-data: diff --git a/gitops/scripts/ragflow/deploy-ragflow.sh b/gitops/scripts/ragflow/deploy-ragflow.sh new file mode 100755 index 0000000..ad41add --- /dev/null +++ b/gitops/scripts/ragflow/deploy-ragflow.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="RAGFlow" + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) +COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml" +IMAGES_DIR="${OFFLINE_ROOT}/images" +IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}" + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +load_images() { + if ! command_exists "${IMAGE_LOAD_TOOL}"; then + echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2 + exit 1 + fi + + if [ ! -d "${IMAGES_DIR}" ]; then + echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2 + return + fi + + shopt -s nullglob + local tarball + for tarball in "${IMAGES_DIR}"/*.tar; do + echo "Loading container images from ${tarball}" + "${IMAGE_LOAD_TOOL}" load -i "${tarball}" + done + shopt -u nullglob +} + +compose() { + if command_exists docker && docker compose version >/dev/null 2>&1; then + docker compose "$@" + elif command_exists docker-compose; then + docker-compose "$@" + else + echo "Error: docker compose plugin or docker-compose binary is required" >&2 + exit 1 + fi +} + +usage() { + cat <&2 + usage + exit 1 + ;; +esac diff --git a/gitops/scripts/ragflow/docker-compose.yaml b/gitops/scripts/ragflow/docker-compose.yaml new file mode 100644 index 0000000..94b6c34 --- /dev/null +++ b/gitops/scripts/ragflow/docker-compose.yaml @@ -0,0 +1,37 @@ +version: "3.8" + +services: + postgres: + image: postgres:__POSTGRES_TAG__ + container_name: ragflow-postgres + restart: unless-stopped + environment: + POSTGRES_DB: ragflow + POSTGRES_USER: ragflow + POSTGRES_PASSWORD: ragflow + volumes: + - ragflow-postgres:/var/lib/postgresql/data + redis: + image: redis:__REDIS_TAG__ + container_name: ragflow-redis + restart: unless-stopped + command: ["redis-server", "--appendonly", "yes"] + volumes: + - ragflow-redis:/data + ragflow: + image: ragflow/ragflow:__RAGFLOW_TAG__ + container_name: ragflow-app + restart: unless-stopped + depends_on: + - postgres + - redis + ports: + - "3001:3000" + environment: + DATABASE_URL: postgresql://ragflow:ragflow@postgres:5432/ragflow + REDIS_URL: redis://redis:6379/0 + SECRET_KEY: changeme + +volumes: + ragflow-postgres: + ragflow-redis: