mirror of
https://github.com/labring/FastGPT.git
synced 2026-05-05 01:02:59 +08:00
V4.14.9 dev (#6566)
* sandbox-sync-agent (#6565) * action * action --------- Co-authored-by: Ryo <whoeverimf5@gmail.com>
This commit is contained in:
@@ -1,132 +0,0 @@
|
|||||||
name: Build Sandbox Server Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
description: 'Image tag (e.g., v1.0.0)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-sandbox-server-images:
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
archs:
|
|
||||||
- arch: amd64
|
|
||||||
- arch: arm64
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
runs-on: ${{ matrix.archs.runs-on || 'ubuntu-24.04' }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
with:
|
|
||||||
driver-opts: network=host
|
|
||||||
|
|
||||||
- name: Cache Docker layers
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: /tmp/.buildx-cache
|
|
||||||
key: ${{ runner.os }}-${{ matrix.archs.arch }}-sandbox-server-buildx-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-${{ matrix.archs.arch }}-sandbox-server-buildx-
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to Ali Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: registry.cn-hangzhou.aliyuncs.com
|
|
||||||
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
|
|
||||||
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
|
|
||||||
|
|
||||||
- name: Build for ${{ matrix.archs.arch }}
|
|
||||||
id: build
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: ./projects/sandbox_server
|
|
||||||
file: ./projects/sandbox_server/Dockerfile
|
|
||||||
platforms: linux/${{ matrix.archs.arch }}
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
|
||||||
org.opencontainers.image.description=FastGPT Sandbox Server image
|
|
||||||
outputs: type=image,"name=ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox-server,${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-sandbox-server",push-by-digest=true,push=true
|
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
|
||||||
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ runner.temp }}/digests/fastgpt-sandbox-server
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "${{ runner.temp }}/digests/fastgpt-sandbox-server/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: digests-fastgpt-sandbox-server-${{ github.sha }}-${{ matrix.archs.arch }}
|
|
||||||
path: ${{ runner.temp }}/digests/fastgpt-sandbox-server/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
release-sandbox-server-images:
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
needs: build-sandbox-server-images
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to Ali Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: registry.cn-hangzhou.aliyuncs.com
|
|
||||||
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
|
|
||||||
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
|
|
||||||
|
|
||||||
- name: Download digests
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/digests
|
|
||||||
pattern: digests-fastgpt-sandbox-server-${{ github.sha }}-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Create manifest list and push
|
|
||||||
working-directory: ${{ runner.temp }}/digests
|
|
||||||
run: |
|
|
||||||
TAGS=(
|
|
||||||
"ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox-server:${{ inputs.tag }}"
|
|
||||||
"ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox-server:latest"
|
|
||||||
"${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-sandbox-server:${{ inputs.tag }}"
|
|
||||||
"${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-sandbox-server:latest"
|
|
||||||
)
|
|
||||||
for TAG in "${TAGS[@]}"; do
|
|
||||||
docker buildx imagetools create -t $TAG \
|
|
||||||
$(printf 'ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox-server@sha256:%s ' *)
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
@@ -38,24 +38,13 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-sandbox-buildx-
|
${{ runner.os }}-sandbox-buildx-
|
||||||
|
|
||||||
# login docker
|
# login github
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Login to Ali Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: registry.cn-hangzhou.aliyuncs.com
|
|
||||||
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
|
|
||||||
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_HUB_NAME }}
|
|
||||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Build for ${{ matrix.arch }}
|
- name: Build for ${{ matrix.arch }}
|
||||||
id: build
|
id: build
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
name: Preview documents
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
paths:
|
|
||||||
- 'document/**'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-images:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
|
|
||||||
- name: Get current datetime
|
|
||||||
id: datetime
|
|
||||||
run: echo "datetime=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Docker meta
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
# list of Docker images to use as base name for tags
|
|
||||||
images: |
|
|
||||||
${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-docs
|
|
||||||
tags: |
|
|
||||||
${{ steps.datetime.outputs.datetime }}
|
|
||||||
flavor: latest=false
|
|
||||||
|
|
||||||
- name: Login to Aliyun
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: registry.cn-hangzhou.aliyuncs.com
|
|
||||||
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
|
|
||||||
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
|
|
||||||
|
|
||||||
- name: Build and push Docker images
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: ./document
|
|
||||||
file: ./document/Dockerfile
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
build-args: |
|
|
||||||
FASTGPT_HOME_DOMAIN=https://fastgpt.io
|
|
||||||
outputs:
|
|
||||||
tags: ${{ steps.datetime.outputs.datetime }}
|
|
||||||
|
|
||||||
update-images:
|
|
||||||
needs: build-images
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
|
|
||||||
# Add kubeconfig setup step to handle encoding issues
|
|
||||||
- name: Setup kubeconfig
|
|
||||||
run: |
|
|
||||||
mkdir -p $HOME/.kube
|
|
||||||
echo "${{ secrets.KUBE_CONFIG_CN }}" > $HOME/.kube/config
|
|
||||||
chmod 600 $HOME/.kube/config
|
|
||||||
|
|
||||||
- name: Update deployment image
|
|
||||||
run: |
|
|
||||||
kubectl set image deployment/fastgpt-docs-preview fastgpt-docs-preview=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-docs:${{ needs.build-images.outputs.tags }}
|
|
||||||
|
|
||||||
- name: Annotate deployment
|
|
||||||
run: |
|
|
||||||
kubectl annotate deployment/fastgpt-docs-preview originImageName="${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-docs:${{ needs.build-images.outputs.tags }}" --overwrite
|
|
||||||
|
|
||||||
- name: '@finleyge/github-tools'
|
|
||||||
uses: FinleyGe/github-tools@0.0.1
|
|
||||||
id: print-image-label
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
tool: issue-comment
|
|
||||||
title: 'Docs Preview:'
|
|
||||||
body: |
|
|
||||||
---
|
|
||||||
🚀 **FastGPT Document Preview Ready!**
|
|
||||||
|
|
||||||
🔗 [👀 Click here to visit preview](https://pueuoharpgcl.sealoshzh.site)
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
name: Build FastGPT images in Personal warehouse
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'projects/app/**'
|
|
||||||
- 'packages/**'
|
|
||||||
branches:
|
|
||||||
- 'main'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
get-vars:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
outputs:
|
|
||||||
docker_repo: ${{ steps.set_docker_repo.outputs.docker_repo }}
|
|
||||||
docker_tag: ${{ steps.set_docker_repo.outputs.docker_tag }}
|
|
||||||
steps:
|
|
||||||
- name: Set docker repository and tag
|
|
||||||
id: set_docker_repo
|
|
||||||
run: |
|
|
||||||
echo "docker_repo=ghcr.io/$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
|
|
||||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
|
||||||
echo "docker_tag=latest" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "docker_tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
build-fastgpt-images:
|
|
||||||
needs: get-vars
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
archs:
|
|
||||||
- arch: amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
- arch: arm64
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
runs-on: ${{ matrix.archs.runs-on || 'ubuntu-24.04' }}
|
|
||||||
if: github.repository != 'labring/FastGPT'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
with:
|
|
||||||
driver-opts: network=host
|
|
||||||
- name: Cache Docker layers
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: /tmp/.buildx-cache
|
|
||||||
key: ${{ runner.os }}-${{ matrix.archs.arch }}-buildx-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-${{ matrix.archs.arch }}-buildx-
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and push for ${{ matrix.archs.arch }}
|
|
||||||
id: build
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: projects/app/Dockerfile
|
|
||||||
platforms: linux/${{ matrix.archs.arch }}
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
|
||||||
org.opencontainers.image.description=fastgpt image
|
|
||||||
outputs: type=image,"name=${{ needs.get-vars.outputs.docker_repo }}",push-by-digest=true,push=true
|
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ runner.temp }}/digests
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: digests-${{ github.sha }}-${{ matrix.archs.arch }}
|
|
||||||
path: ${{ runner.temp }}/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
release-fastgpt-images:
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
needs: [get-vars, build-fastgpt-images]
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Download digests
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/digests
|
|
||||||
pattern: digests-${{ github.sha }}-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Set image name and tag
|
|
||||||
run: |
|
|
||||||
echo "Git_Tag=${{ needs.get-vars.outputs.docker_repo }}:${{ needs.get-vars.outputs.docker_tag }}" >> $GITHUB_ENV
|
|
||||||
echo "Git_Latest=${{ needs.get-vars.outputs.docker_repo }}:latest" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Create manifest list and push
|
|
||||||
working-directory: ${{ runner.temp }}/digests
|
|
||||||
run: |
|
|
||||||
TAGS="$(echo -e "${Git_Tag}\n${Git_Latest}")"
|
|
||||||
for TAG in $TAGS; do
|
|
||||||
docker buildx imagetools create -t $TAG \
|
|
||||||
$(printf '${{ needs.get-vars.outputs.docker_repo }}@sha256:%s ' *)
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
name: Build Docs Preview (Unprivileged)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'document/**'
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
pull_request_target:
|
||||||
|
paths:
|
||||||
|
- 'document/**'
|
||||||
|
types: [labeled]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-docs-image:
|
||||||
|
# 外部贡献者需要 'safe-to-build' 标签
|
||||||
|
if: |
|
||||||
|
(github.event_name == 'pull_request') ||
|
||||||
|
(github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'safe-to-build'))
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout PR code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# 对于 pull_request_target,检出 PR 的代码
|
||||||
|
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
- name: Get current datetime
|
||||||
|
id: datetime
|
||||||
|
run: echo "datetime=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: ./document
|
||||||
|
file: ./document/Dockerfile
|
||||||
|
push: false
|
||||||
|
tags: fastgpt-docs:${{ steps.datetime.outputs.datetime }}
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT
|
||||||
|
org.opencontainers.image.description=FastGPT Docs Preview
|
||||||
|
build-args: |
|
||||||
|
FASTGPT_HOME_DOMAIN=https://fastgpt.io
|
||||||
|
outputs: type=docker,dest=/tmp/fastgpt-docs-${{ steps.datetime.outputs.datetime }}.tar
|
||||||
|
|
||||||
|
- name: Upload image artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: fastgpt-docs-${{ steps.datetime.outputs.datetime }}
|
||||||
|
path: /tmp/fastgpt-docs-${{ steps.datetime.outputs.datetime }}.tar
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
- name: Comment build status
|
||||||
|
uses: FinleyGe/github-tools@0.0.1
|
||||||
|
if: success()
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tool: issue-comment
|
||||||
|
title: 'Docs Preview Build:'
|
||||||
|
body: |
|
||||||
|
Build completed. Waiting for deployment...
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
datetime: ${{ steps.datetime.outputs.datetime }}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
name: Deploy Docs Preview (Privileged)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["Build Docs Preview (Unprivileged)"]
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
push-and-deploy:
|
||||||
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Get PR information
|
||||||
|
id: pr
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { data: pullRequests } = await github.rest.pulls.list({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'open',
|
||||||
|
head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pullRequests.length === 0) {
|
||||||
|
core.setFailed('No open PR found for this branch');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pr = pullRequests[0];
|
||||||
|
core.setOutput('number', pr.number);
|
||||||
|
|
||||||
|
- name: Get workflow artifacts
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
id: artifacts
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
run_id: context.payload.workflow_run.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const artifact = artifacts.data.artifacts[0];
|
||||||
|
if (!artifact) {
|
||||||
|
core.setFailed('No artifact found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract datetime from artifact name
|
||||||
|
const datetime = artifact.name.replace('fastgpt-docs-', '');
|
||||||
|
core.setOutput('datetime', datetime);
|
||||||
|
core.setOutput('artifact_name', artifact.name);
|
||||||
|
|
||||||
|
- name: Download image artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ steps.artifacts.outputs.artifact_name }}
|
||||||
|
path: /tmp/
|
||||||
|
run-id: ${{ github.event.workflow_run.id }}
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Load Docker image
|
||||||
|
run: |
|
||||||
|
docker load -i /tmp/fastgpt-docs-${{ steps.artifacts.outputs.datetime }}.tar
|
||||||
|
|
||||||
|
- name: Login to Aliyun
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: registry.cn-hangzhou.aliyuncs.com
|
||||||
|
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
|
||||||
|
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
|
||||||
|
|
||||||
|
- name: Tag and push image
|
||||||
|
run: |
|
||||||
|
docker tag fastgpt-docs:${{ steps.artifacts.outputs.datetime }} \
|
||||||
|
${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-docs:${{ steps.artifacts.outputs.datetime }}
|
||||||
|
docker push ${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-docs:${{ steps.artifacts.outputs.datetime }}
|
||||||
|
|
||||||
|
- name: Setup kubeconfig
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/.kube
|
||||||
|
echo "${{ secrets.KUBE_CONFIG_CN }}" > $HOME/.kube/config
|
||||||
|
chmod 600 $HOME/.kube/config
|
||||||
|
|
||||||
|
- name: Update deployment image
|
||||||
|
run: |
|
||||||
|
kubectl set image deployment/fastgpt-docs-preview \
|
||||||
|
fastgpt-docs-preview=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-docs:${{ steps.artifacts.outputs.datetime }}
|
||||||
|
|
||||||
|
- name: Annotate deployment
|
||||||
|
run: |
|
||||||
|
kubectl annotate deployment/fastgpt-docs-preview \
|
||||||
|
originImageName="${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-docs:${{ steps.artifacts.outputs.datetime }}" --overwrite
|
||||||
|
|
||||||
|
- name: Comment deployment status
|
||||||
|
uses: FinleyGe/github-tools@0.0.1
|
||||||
|
if: success()
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tool: issue-comment
|
||||||
|
title: 'Docs Preview:'
|
||||||
|
body: |
|
||||||
|
---
|
||||||
|
🚀 **FastGPT Document Preview Ready!**
|
||||||
|
|
||||||
|
🔗 [👀 Click here to visit preview](https://pueuoharpgcl.sealoshzh.site)
|
||||||
|
|
||||||
|
- name: Comment on failure
|
||||||
|
uses: FinleyGe/github-tools@0.0.1
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tool: issue-comment
|
||||||
|
title: 'Docs Preview Deployment Failed'
|
||||||
|
body: |
|
||||||
|
Failed to deploy docs preview. Please check workflow logs.
|
||||||
+42
-32
@@ -1,15 +1,22 @@
|
|||||||
name: Preview FastGPT images
|
name: FastGPT Build (Unprivileged)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
pull_request:
|
||||||
|
# 支持所有分支
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
workflow_dispatch:
|
# 外部贡献者需要标签批准
|
||||||
|
types: [labeled]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
preview-fastgpt-images:
|
build-preview-images:
|
||||||
|
# 外部贡献者需要 'safe-to-build' 标签
|
||||||
|
if: |
|
||||||
|
(github.event_name == 'pull_request') ||
|
||||||
|
(github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'safe-to-build'))
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
@@ -19,21 +26,20 @@ jobs:
|
|||||||
fail-fast: false # 即使一个镜像构建失败,也继续构建其他镜像
|
fail-fast: false # 即使一个镜像构建失败,也继续构建其他镜像
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout PR code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.ref }}
|
# 对于 pull_request_target,检出 PR 的代码
|
||||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
with:
|
with:
|
||||||
driver-opts: network=host
|
driver-opts: network=host
|
||||||
|
|
||||||
- name: Cache Docker layers
|
- name: Cache Docker layers
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: /tmp/.buildx-cache
|
path: /tmp/.buildx-cache
|
||||||
key: ${{ runner.os }}-buildx-${{ github.sha }}-${{ matrix.image }}
|
key: ${{ runner.os }}-buildx-${{ github.sha }}-${{ matrix.image }}
|
||||||
@@ -41,50 +47,54 @@ jobs:
|
|||||||
${{ runner.os }}-buildx-${{ github.sha }}-
|
${{ runner.os }}-buildx-${{ github.sha }}-
|
||||||
${{ runner.os }}-buildx-
|
${{ runner.os }}-buildx-
|
||||||
|
|
||||||
- name: Login to Aliyun Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: registry.cn-hangzhou.aliyuncs.com
|
|
||||||
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
|
|
||||||
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
|
|
||||||
|
|
||||||
- name: Set image config
|
- name: Set image config
|
||||||
id: config
|
id: config
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{ matrix.image }}" == "fastgpt" ]]; then
|
if [[ "${{ matrix.image }}" == "fastgpt" ]]; then
|
||||||
echo "DOCKERFILE=projects/app/Dockerfile" >> $GITHUB_OUTPUT
|
echo "DOCKERFILE=projects/app/Dockerfile" >> $GITHUB_OUTPUT
|
||||||
echo "DESCRIPTION=fastgpt-pr image" >> $GITHUB_OUTPUT
|
echo "DESCRIPTION=fastgpt-pr image" >> $GITHUB_OUTPUT
|
||||||
echo "DOCKER_REPO_TAGGED=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-pr:fatsgpt_${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT
|
echo "IMAGE_NAME=fastgpt" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ matrix.image }}" == "sandbox" ]]; then
|
elif [[ "${{ matrix.image }}" == "sandbox" ]]; then
|
||||||
echo "DOCKERFILE=projects/sandbox/Dockerfile" >> $GITHUB_OUTPUT
|
echo "DOCKERFILE=projects/sandbox/Dockerfile" >> $GITHUB_OUTPUT
|
||||||
echo "DESCRIPTION=fastgpt-sandbox-pr image" >> $GITHUB_OUTPUT
|
echo "DESCRIPTION=fastgpt-sandbox-pr image" >> $GITHUB_OUTPUT
|
||||||
echo "DOCKER_REPO_TAGGED=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-pr:fatsgpt_sandbox_${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT
|
echo "IMAGE_NAME=fastgpt-sandbox" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ matrix.image }}" == "mcp_server" ]]; then
|
elif [[ "${{ matrix.image }}" == "mcp_server" ]]; then
|
||||||
echo "DOCKERFILE=projects/mcp_server/Dockerfile" >> $GITHUB_OUTPUT
|
echo "DOCKERFILE=projects/mcp_server/Dockerfile" >> $GITHUB_OUTPUT
|
||||||
echo "DESCRIPTION=fastgpt-mcp_server-pr image" >> $GITHUB_OUTPUT
|
echo "DESCRIPTION=fastgpt-mcp_server-pr image" >> $GITHUB_OUTPUT
|
||||||
echo "DOCKER_REPO_TAGGED=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-pr:fatsgpt_mcp_server_${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT
|
echo "IMAGE_NAME=fastgpt-mcp-server" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build ${{ matrix.image }} image for PR
|
- name: Build ${{ matrix.image }} image
|
||||||
run: |
|
run: |
|
||||||
docker buildx build \
|
docker buildx build \
|
||||||
-f ${{ steps.config.outputs.DOCKERFILE }} \
|
-f ${{ steps.config.outputs.DOCKERFILE }} \
|
||||||
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
|
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
|
||||||
--label "org.opencontainers.image.description=${{ steps.config.outputs.DESCRIPTION }}" \
|
--label "org.opencontainers.image.description=${{ steps.config.outputs.DESCRIPTION }}" \
|
||||||
--push \
|
--label "org.opencontainers.image.revision=${{ github.sha }}" \
|
||||||
--cache-from=type=local,src=/tmp/.buildx-cache \
|
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||||
-t ${{ steps.config.outputs.DOCKER_REPO_TAGGED }} \
|
--cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max \
|
||||||
|
--output type=docker,dest=/tmp/${{ steps.config.outputs.IMAGE_NAME }}-${{ github.sha }}.tar \
|
||||||
|
-t preview-image:${{ github.sha }} \
|
||||||
.
|
.
|
||||||
|
|
||||||
- name: '@finleyge/github-tools'
|
- name: Move cache
|
||||||
|
run: |
|
||||||
|
rm -rf /tmp/.buildx-cache
|
||||||
|
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||||
|
|
||||||
|
- name: Upload image artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ steps.config.outputs.IMAGE_NAME }}-${{ github.sha }}
|
||||||
|
path: /tmp/${{ steps.config.outputs.IMAGE_NAME }}-${{ github.sha }}.tar
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
- name: Comment build status
|
||||||
uses: FinleyGe/github-tools@0.0.1
|
uses: FinleyGe/github-tools@0.0.1
|
||||||
id: print-image-label
|
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tool: issue-comment
|
tool: issue-comment
|
||||||
title: 'Preview ${{ matrix.image }} Image:'
|
title: 'Preview ${{ matrix.image }} Image Built:'
|
||||||
body: |
|
body: |
|
||||||
```
|
Build completed. Waiting for push workflow...
|
||||||
${{ steps.config.outputs.DOCKER_REPO_TAGGED }}
|
|
||||||
```
|
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
name: FastGPT Push (Privileged)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["FastGPT Build (Unprivileged)"]
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
push-preview-images:
|
||||||
|
# 只在构建成功时运行
|
||||||
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
image: [fastgpt, sandbox, mcp_server]
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Get PR information
|
||||||
|
id: pr
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { data: pullRequests } = await github.rest.pulls.list({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'open',
|
||||||
|
head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pullRequests.length === 0) {
|
||||||
|
core.setFailed('No open PR found for this branch');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pr = pullRequests[0];
|
||||||
|
core.setOutput('number', pr.number);
|
||||||
|
core.setOutput('sha', context.payload.workflow_run.head_sha);
|
||||||
|
|
||||||
|
- name: Set image config
|
||||||
|
id: config
|
||||||
|
run: |
|
||||||
|
SHA="${{ steps.pr.outputs.sha }}"
|
||||||
|
|
||||||
|
if [[ "${{ matrix.image }}" == "fastgpt" ]]; then
|
||||||
|
echo "IMAGE_NAME=fastgpt" >> $GITHUB_OUTPUT
|
||||||
|
echo "DESCRIPTION=fastgpt-pr image" >> $GITHUB_OUTPUT
|
||||||
|
echo "DOCKER_REPO_TAGGED=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-pr:fastgpt_${SHA}" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ matrix.image }}" == "sandbox" ]]; then
|
||||||
|
echo "IMAGE_NAME=fastgpt-sandbox" >> $GITHUB_OUTPUT
|
||||||
|
echo "DESCRIPTION=fastgpt-sandbox-pr image" >> $GITHUB_OUTPUT
|
||||||
|
echo "DOCKER_REPO_TAGGED=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-pr:fastgpt_sandbox_${SHA}" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ matrix.image }}" == "mcp_server" ]]; then
|
||||||
|
echo "IMAGE_NAME=fastgpt-mcp-server" >> $GITHUB_OUTPUT
|
||||||
|
echo "DESCRIPTION=fastgpt-mcp_server-pr image" >> $GITHUB_OUTPUT
|
||||||
|
echo "DOCKER_REPO_TAGGED=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/fastgpt-pr:fastgpt_mcp_server_${SHA}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download image artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ steps.config.outputs.IMAGE_NAME }}-${{ steps.pr.outputs.sha }}
|
||||||
|
path: /tmp/
|
||||||
|
run-id: ${{ github.event.workflow_run.id }}
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Load Docker image
|
||||||
|
run: |
|
||||||
|
docker load -i /tmp/${{ steps.config.outputs.IMAGE_NAME }}-${{ steps.pr.outputs.sha }}.tar
|
||||||
|
|
||||||
|
- name: Scan image for vulnerabilities
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
# 安装 Trivy
|
||||||
|
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
|
||||||
|
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install trivy -y
|
||||||
|
|
||||||
|
# 扫描镜像
|
||||||
|
trivy image --severity HIGH,CRITICAL --exit-code 0 preview-image:${{ steps.pr.outputs.sha }}
|
||||||
|
|
||||||
|
- name: Login to Aliyun Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: registry.cn-hangzhou.aliyuncs.com
|
||||||
|
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
|
||||||
|
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
|
||||||
|
|
||||||
|
- name: Tag and push image
|
||||||
|
run: |
|
||||||
|
docker tag preview-image:${{ steps.pr.outputs.sha }} ${{ steps.config.outputs.DOCKER_REPO_TAGGED }}
|
||||||
|
docker push ${{ steps.config.outputs.DOCKER_REPO_TAGGED }}
|
||||||
|
|
||||||
|
- name: Comment push status
|
||||||
|
uses: FinleyGe/github-tools@0.0.1
|
||||||
|
if: success()
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tool: issue-comment
|
||||||
|
title: 'Preview ${{ matrix.image }} Image:'
|
||||||
|
body: |
|
||||||
|
```
|
||||||
|
${{ steps.config.outputs.DOCKER_REPO_TAGGED }}
|
||||||
|
```
|
||||||
|
|
||||||
|
- name: Comment on failure
|
||||||
|
uses: FinleyGe/github-tools@0.0.1
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tool: issue-comment
|
||||||
|
title: 'Preview ${{ matrix.image }} Image Push Failed'
|
||||||
|
body: |
|
||||||
|
Failed to push preview image. Please check workflow logs.
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apidevtools/json-schema-ref-parser": "^11.7.2",
|
"@apidevtools/json-schema-ref-parser": "^11.7.2",
|
||||||
"@fastgpt-sdk/sandbox-adapter": "^0.0.18",
|
"@fastgpt-sdk/sandbox-adapter": "^0.0.19",
|
||||||
"@fastgpt-sdk/storage": "catalog:",
|
"@fastgpt-sdk/storage": "catalog:",
|
||||||
"@fastgpt-sdk/logger": "catalog:",
|
"@fastgpt-sdk/logger": "catalog:",
|
||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
|
|||||||
Generated
+5
-5
@@ -247,8 +247,8 @@ importers:
|
|||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 0.1.2
|
version: 0.1.2
|
||||||
'@fastgpt-sdk/sandbox-adapter':
|
'@fastgpt-sdk/sandbox-adapter':
|
||||||
specifier: ^0.0.18
|
specifier: ^0.0.19
|
||||||
version: 0.0.18
|
version: 0.0.19
|
||||||
'@fastgpt-sdk/storage':
|
'@fastgpt-sdk/storage':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 0.6.15(@opentelemetry/api@1.9.0)(@types/node@24.0.13)(jiti@2.6.0)(lightningcss@1.30.1)(proxy-agent@6.5.0)(sass@1.85.1)(terser@5.39.0)(tsx@4.20.6)(yaml@2.8.1)
|
version: 0.6.15(@opentelemetry/api@1.9.0)(@types/node@24.0.13)(jiti@2.6.0)(lightningcss@1.30.1)(proxy-agent@6.5.0)(sass@1.85.1)(terser@5.39.0)(tsx@4.20.6)(yaml@2.8.1)
|
||||||
@@ -2640,8 +2640,8 @@ packages:
|
|||||||
'@fastgpt-sdk/plugin@0.3.8':
|
'@fastgpt-sdk/plugin@0.3.8':
|
||||||
resolution: {integrity: sha512-GjKrXMHxeF5UMkYGXawrUpzZjVRw3DICNYODeYwsUVOy+/ltu5zuwsqLkuuGQ7Arp/SBCmYRjG/MHmeNp4xxfw==}
|
resolution: {integrity: sha512-GjKrXMHxeF5UMkYGXawrUpzZjVRw3DICNYODeYwsUVOy+/ltu5zuwsqLkuuGQ7Arp/SBCmYRjG/MHmeNp4xxfw==}
|
||||||
|
|
||||||
'@fastgpt-sdk/sandbox-adapter@0.0.18':
|
'@fastgpt-sdk/sandbox-adapter@0.0.19':
|
||||||
resolution: {integrity: sha512-5xjBQzG9wHi7oRxAlMHz5Sz282QEHCmJnqaX4o0H0vfDgOwanBfglwejmF9bPlqy+HnIZi3rIJseCleE3MqH2g==}
|
resolution: {integrity: sha512-024C9Ljoic7/oQm1awyLMWVl7kk9NuOGgUa8NC3wOS4GQrCVZCPCHK8YwqkRbKX9T0Akczc6RFaZj+kRJd3m4Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@fastgpt-sdk/storage@0.6.15':
|
'@fastgpt-sdk/storage@0.6.15':
|
||||||
@@ -13433,7 +13433,7 @@ snapshots:
|
|||||||
'@fortaine/fetch-event-source': 3.0.6
|
'@fortaine/fetch-event-source': 3.0.6
|
||||||
zod: 4.1.12
|
zod: 4.1.12
|
||||||
|
|
||||||
'@fastgpt-sdk/sandbox-adapter@0.0.18':
|
'@fastgpt-sdk/sandbox-adapter@0.0.19':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@alibaba-group/opensandbox': 0.1.4
|
'@alibaba-group/opensandbox': 0.1.4
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# 基于 base/ 目录构建的 fastgpt-agent-sandbox:latest,在其基础上注入 Sync Agent
|
||||||
|
#
|
||||||
|
# 构建顺序:
|
||||||
|
# 1. cd base && docker build -t fastgpt-agent-sandbox:latest .
|
||||||
|
# 2. docker build -f Dockerfile -t fastgpt-agent-sandbox:k8s .
|
||||||
|
|
||||||
|
FROM fastgpt-agent-sandbox:latest
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
# 安装 Sync Agent 依赖
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
inotify-tools \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# 安装 MinIO Client (mc)
|
||||||
|
RUN curl -O https://dl.min.io/client/mc/release/linux-amd64/mc && \
|
||||||
|
chmod +x mc && \
|
||||||
|
mv mc /usr/local/bin/
|
||||||
|
|
||||||
|
COPY sync.sh /sync.sh
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
COPY http_server.py /http_server.py
|
||||||
|
|
||||||
|
RUN chmod +x /sync.sh /entrypoint.sh
|
||||||
|
|
||||||
|
# 8081: Sync Agent HTTP API(健康检查 / 手动触发同步)
|
||||||
|
EXPOSE 8081
|
||||||
|
|
||||||
|
USER sandbox
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Docker 双进程模式镜像
|
||||||
|
# 基于 base/ 目录构建的 fastgpt-agent-sandbox:latest,在其基础上注入 Sync Agent
|
||||||
|
#
|
||||||
|
# 构建顺序:
|
||||||
|
# 1. cd base && docker build -t fastgpt-agent-sandbox:latest .
|
||||||
|
# 2. docker build -f Dockerfile.docker-runtime -t fastgpt-agent-sandbox:docker .
|
||||||
|
FROM fastgpt-agent-sandbox:latest
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
# 安装 Sync Agent 依赖
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
inotify-tools \
|
||||||
|
supervisor \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# 安装 MinIO Client
|
||||||
|
RUN curl -O https://dl.min.io/client/mc/release/linux-amd64/mc && \
|
||||||
|
chmod +x mc && \
|
||||||
|
mv mc /usr/local/bin/
|
||||||
|
|
||||||
|
# 复制 Sync Agent 脚本
|
||||||
|
COPY sync.sh /opt/sync-agent/sync.sh
|
||||||
|
COPY http_server.py /opt/sync-agent/http_server.py
|
||||||
|
COPY docker-entrypoint.sh /opt/sync-agent/docker-entrypoint.sh
|
||||||
|
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
RUN chmod +x /opt/sync-agent/sync.sh \
|
||||||
|
/opt/sync-agent/docker-entrypoint.sh && \
|
||||||
|
mkdir -p /var/log/supervisor && \
|
||||||
|
chown -R sandbox:sandbox /var/log/supervisor
|
||||||
|
|
||||||
|
USER sandbox
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/sync-agent/docker-entrypoint.sh"]
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Skill Sandbox 基础镜像
|
||||||
|
# 提供 code-server 开发环境,供 K8s Sidecar 和 Docker 双进程两种运行时使用
|
||||||
|
#
|
||||||
|
# 构建:docker build -t fastgpt-agent-sandbox:latest .
|
||||||
|
# 产物:fastgpt-agent-sandbox:latest
|
||||||
|
FROM ubuntu:24.04
|
||||||
|
|
||||||
|
# Avoid prompts during installation
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
git \
|
||||||
|
jq \
|
||||||
|
ripgrep \
|
||||||
|
vim-tiny \
|
||||||
|
tree \
|
||||||
|
zip \
|
||||||
|
unzip \
|
||||||
|
curl \
|
||||||
|
ca-certificates
|
||||||
|
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
||||||
|
RUN apt install -y python3 nodejs
|
||||||
|
RUN rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install code-server using the official script
|
||||||
|
RUN curl -fsSL https://code-server.dev/install.sh | sh
|
||||||
|
|
||||||
|
# Create a non-root user for security
|
||||||
|
RUN useradd --create-home --shell /bin/bash sandbox
|
||||||
|
|
||||||
|
USER sandbox
|
||||||
|
WORKDIR /home/sandbox
|
||||||
|
|
||||||
|
# Copy VS Code settings
|
||||||
|
RUN mkdir -p /home/sandbox/.local/share/code-server/User
|
||||||
|
COPY --chown=sandbox:sandbox settings.json /home/sandbox/.local/share/code-server/User/settings.json
|
||||||
|
|
||||||
|
# Copy and configure entrypoint
|
||||||
|
COPY --chown=sandbox:sandbox entrypoint.sh /home/sandbox/entrypoint.sh
|
||||||
|
RUN chmod +x /home/sandbox/entrypoint.sh
|
||||||
|
|
||||||
|
# Expose code-server port
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
ENTRYPOINT ["/home/sandbox/entrypoint.sh"]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Set work directory from environment variable, default to /home/sandbox
|
||||||
|
WORKDIR="${FASTGPT_WORKDIR:-/home/sandbox}"
|
||||||
|
mkdir -p "${WORKDIR}"
|
||||||
|
|
||||||
|
# Start code-server
|
||||||
|
# --bind-addr 0.0.0.0:8080 allows access from outside the container
|
||||||
|
# --auth none removes password protection
|
||||||
|
exec code-server \
|
||||||
|
--bind-addr 0.0.0.0:8080 \
|
||||||
|
--auth none \
|
||||||
|
--disable-telemetry \
|
||||||
|
--disable-update-check \
|
||||||
|
--disable-workspace-trust \
|
||||||
|
--disable-getting-started-override \
|
||||||
|
--app-name "Skills" \
|
||||||
|
--user-data-dir /home/sandbox/.local/share/code-server \
|
||||||
|
"${WORKDIR}"
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"workbench.startupEditor": "none",
|
||||||
|
"workbench.welcomePage.tasks.showOnStart": false,
|
||||||
|
"telemetry.telemetryLevel": "off",
|
||||||
|
"editor.minimap.enabled": false,
|
||||||
|
"workbench.tips.enabled": false,
|
||||||
|
"extensions.autoCheckUpdates": false,
|
||||||
|
"extensions.autoUpdate": false,
|
||||||
|
"editor.accessibilitySupport": "off",
|
||||||
|
"editor.hover.enabled": "off",
|
||||||
|
"editor.hover.sticky": false,
|
||||||
|
"editor.acceptSuggestionOnCommitCharacter": false,
|
||||||
|
"editor.acceptSuggestionOnEnter": "off",
|
||||||
|
"editor.inlineSuggest.edits.allowCodeShifting": "never",
|
||||||
|
"editor.inlineSuggest.edits.renderSideBySide": "never",
|
||||||
|
"editor.inlineSuggest.edits.showLongDistanceHint": false,
|
||||||
|
"editor.inlineSuggest.enabled": false,
|
||||||
|
"editor.inlineSuggest.experimental.emptyResponseInformation": false,
|
||||||
|
"editor.inlineSuggest.showToolbar": "never",
|
||||||
|
"editor.inlineSuggest.suppressInSnippetMode": false,
|
||||||
|
"workbench.commandPalette.showAskInChat": false,
|
||||||
|
"workbench.commandPalette.experimental.enableNaturalLanguageSearch": false,
|
||||||
|
"workbench.tree.enableStickyScroll": false,
|
||||||
|
"chat.disableAIFeatures": true,
|
||||||
|
"workbench.activityBar.location": "hidden",
|
||||||
|
"workbench.statusBar.visible": false,
|
||||||
|
"workbench.editor.showTabs": "none",
|
||||||
|
"window.commandCenter": false,
|
||||||
|
"workbench.editor.editorActionsLocation": "hidden",
|
||||||
|
"workbench.layoutControl.enabled": false
|
||||||
|
}
|
||||||
Executable
+227
@@ -0,0 +1,227 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Build script for sandbox-sync-agent images.
|
||||||
|
# Usage: ./build.sh [OPTIONS]
|
||||||
|
#
|
||||||
|
# Images:
|
||||||
|
# base/Dockerfile -> fastgpt-agent-sandbox:latest (base image)
|
||||||
|
# Dockerfile -> fastgpt-agent-sandbox:k8s (K8s sidecar)
|
||||||
|
# Dockerfile.docker-runtime -> fastgpt-agent-sandbox:docker (Docker dual-process)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Defaults
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
REGISTRY=""
|
||||||
|
TAG="latest"
|
||||||
|
TARGET="all"
|
||||||
|
NO_CACHE=""
|
||||||
|
PLATFORM=""
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Parse arguments
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--registry)
|
||||||
|
REGISTRY="${2:?'--registry requires a value'}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--tag)
|
||||||
|
TAG="${2:?'--tag requires a value'}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--target)
|
||||||
|
TARGET="${2:?'--target requires a value (base|k8s|docker|all)'}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--no-cache)
|
||||||
|
NO_CACHE="--no-cache"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--platform)
|
||||||
|
PLATFORM="${2:?'--platform requires a value, e.g. linux/amd64'}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
echo "Usage: $0 [--registry <prefix>] [--tag <version>] [--target base|k8s|docker|all] [--no-cache] [--platform <platform>]"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Validate --target
|
||||||
|
case "$TARGET" in
|
||||||
|
base|k8s|docker|all) ;;
|
||||||
|
*)
|
||||||
|
echo "Error: --target must be one of: base, k8s, docker, all" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Always run from the directory that contains this script
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Helper: build a docker image name
|
||||||
|
# $1 = variant suffix (latest | k8s | docker)
|
||||||
|
# Returns the full image reference based on registry / tag settings.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
image_name() {
|
||||||
|
local suffix="$1"
|
||||||
|
local name="fastgpt-agent-sandbox:${suffix}"
|
||||||
|
|
||||||
|
# Override the tag portion when the user supplied --tag and suffix == "latest"
|
||||||
|
# (base image is always tagged :latest locally; remote tag uses user-supplied tag)
|
||||||
|
if [[ -n "$REGISTRY" ]]; then
|
||||||
|
if [[ "$suffix" == "latest" ]]; then
|
||||||
|
echo "${REGISTRY}/fastgpt-agent-sandbox:${TAG}"
|
||||||
|
else
|
||||||
|
echo "${REGISTRY}/fastgpt-agent-sandbox-${suffix}:${TAG}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$suffix" == "latest" && "$TAG" != "latest" ]]; then
|
||||||
|
echo "fastgpt-agent-sandbox:${TAG}"
|
||||||
|
else
|
||||||
|
echo "$name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Helper: build extra docker flags
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
extra_flags() {
|
||||||
|
local flags="$NO_CACHE"
|
||||||
|
if [[ -n "$PLATFORM" ]]; then
|
||||||
|
flags="$flags --platform $PLATFORM"
|
||||||
|
fi
|
||||||
|
echo "$flags"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Print a section header
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
section() {
|
||||||
|
echo ""
|
||||||
|
echo "========================================"
|
||||||
|
echo " $*"
|
||||||
|
echo "========================================"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Build base image
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
build_base() {
|
||||||
|
section "Building BASE image"
|
||||||
|
|
||||||
|
# The base/ subdirectory is the build context
|
||||||
|
local local_tag="fastgpt-agent-sandbox:latest"
|
||||||
|
# shellcheck disable=SC2046
|
||||||
|
docker build \
|
||||||
|
-t "$local_tag" \
|
||||||
|
$(extra_flags) \
|
||||||
|
base/
|
||||||
|
|
||||||
|
echo "Built: $local_tag"
|
||||||
|
|
||||||
|
# If a registry or non-default tag is requested, add the remote tag as well
|
||||||
|
if [[ -n "$REGISTRY" ]] || [[ "$TAG" != "latest" ]]; then
|
||||||
|
local remote_tag
|
||||||
|
remote_tag="$(image_name latest)"
|
||||||
|
if [[ "$remote_tag" != "$local_tag" ]]; then
|
||||||
|
docker tag "$local_tag" "$remote_tag"
|
||||||
|
echo "Tagged: $remote_tag"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Build K8s sidecar image
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
build_k8s() {
|
||||||
|
section "Building K8S image"
|
||||||
|
|
||||||
|
local tag
|
||||||
|
if [[ -n "$REGISTRY" ]]; then
|
||||||
|
tag="${REGISTRY}/fastgpt-agent-sandbox-k8s:${TAG}"
|
||||||
|
else
|
||||||
|
tag="fastgpt-agent-sandbox:k8s"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2046
|
||||||
|
docker build \
|
||||||
|
-f Dockerfile \
|
||||||
|
-t "$tag" \
|
||||||
|
$(extra_flags) \
|
||||||
|
.
|
||||||
|
|
||||||
|
echo "Built: $tag"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Build Docker dual-process image
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
build_docker() {
|
||||||
|
section "Building DOCKER-RUNTIME image"
|
||||||
|
|
||||||
|
local tag
|
||||||
|
if [[ -n "$REGISTRY" ]]; then
|
||||||
|
tag="${REGISTRY}/fastgpt-agent-sandbox-docker:${TAG}"
|
||||||
|
else
|
||||||
|
tag="fastgpt-agent-sandbox:docker"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2046
|
||||||
|
docker build \
|
||||||
|
-f Dockerfile.docker-runtime \
|
||||||
|
-t "$tag" \
|
||||||
|
$(extra_flags) \
|
||||||
|
.
|
||||||
|
|
||||||
|
echo "Built: $tag"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Print summary of built images
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
print_summary() {
|
||||||
|
section "Build Summary"
|
||||||
|
echo ""
|
||||||
|
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" \
|
||||||
|
| grep -E "REPOSITORY|fastgpt-agent-sandbox" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Main
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
echo "Target : $TARGET"
|
||||||
|
echo "Tag : $TAG"
|
||||||
|
echo "Registry: ${REGISTRY:-'(none)'}"
|
||||||
|
echo "Platform: ${PLATFORM:-'(default)'}"
|
||||||
|
echo "No-cache: ${NO_CACHE:-'(no)'}"
|
||||||
|
|
||||||
|
# base must be built before k8s / docker when building all
|
||||||
|
if [[ "$TARGET" == "all" || "$TARGET" == "base" ]]; then
|
||||||
|
build_base
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$TARGET" == "all" || "$TARGET" == "k8s" ]]; then
|
||||||
|
build_k8s
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$TARGET" == "all" || "$TARGET" == "docker" ]]; then
|
||||||
|
build_docker
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_summary
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done."
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 配置 MinIO Client
|
||||||
|
mc alias set minio ${FASTGPT_MINIO_ENDPOINT} ${FASTGPT_MINIO_ACCESS_KEY} ${FASTGPT_MINIO_SECRET_KEY} --api S3v4
|
||||||
|
|
||||||
|
# 确保 bucket 存在
|
||||||
|
mc mb minio/${FASTGPT_MINIO_BUCKET} --ignore-existing || true
|
||||||
|
|
||||||
|
# Prepare work directory with correct permissions
|
||||||
|
export FASTGPT_WORKDIR="${FASTGPT_WORKDIR:-/home/sandbox}"
|
||||||
|
mkdir -p "${FASTGPT_WORKDIR}"
|
||||||
|
|
||||||
|
# 是否启动 code-server(默认 true)
|
||||||
|
# 仅需文件同步时设置 FASTGPT_ENABLE_CODE_SERVER=false
|
||||||
|
export FASTGPT_ENABLE_CODE_SERVER=${FASTGPT_ENABLE_CODE_SERVER:-true}
|
||||||
|
|
||||||
|
# 使用 supervisord 启动进程
|
||||||
|
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 配置 MinIO Client
|
||||||
|
mc alias set minio ${FASTGPT_MINIO_ENDPOINT} ${FASTGPT_MINIO_ACCESS_KEY} ${FASTGPT_MINIO_SECRET_KEY} --api S3v4
|
||||||
|
|
||||||
|
# 确保 bucket 存在
|
||||||
|
mc mb minio/${FASTGPT_MINIO_BUCKET} --ignore-existing || true
|
||||||
|
|
||||||
|
# Pass FASTGPT_WORKDIR as FASTGPT_SYNC_PATH if FASTGPT_SYNC_PATH is not explicitly set
|
||||||
|
if [ -z "${FASTGPT_SYNC_PATH}" ] && [ -n "${FASTGPT_WORKDIR}" ]; then
|
||||||
|
export FASTGPT_SYNC_PATH="${FASTGPT_WORKDIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 启动 sync 服务
|
||||||
|
exec /sync.sh
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Sync Agent HTTP 服务
|
||||||
|
提供健康检查和手动触发同步接口,读取 sync.sh 写入的状态文件。
|
||||||
|
"""
|
||||||
|
import http.server
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
STATE_DIR = pathlib.Path(os.environ.get('STATE_DIR', '/tmp/sync-state'))
|
||||||
|
HTTP_PORT = int(os.environ.get('HTTP_PORT', '8081'))
|
||||||
|
|
||||||
|
|
||||||
|
class SyncAgentHandler(http.server.BaseHTTPRequestHandler):
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
pass # 抑制每次请求的访问日志
|
||||||
|
|
||||||
|
def _read_state(self):
|
||||||
|
try:
|
||||||
|
last_sync = (STATE_DIR / 'last_sync').read_text().strip()
|
||||||
|
except Exception:
|
||||||
|
last_sync = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
try:
|
||||||
|
pending = int((STATE_DIR / 'pending_count').read_text().strip())
|
||||||
|
except Exception:
|
||||||
|
pending = 0
|
||||||
|
return last_sync, pending
|
||||||
|
|
||||||
|
def _send_json(self, code, body):
|
||||||
|
data = json.dumps(body).encode()
|
||||||
|
self.send_response(code)
|
||||||
|
self.send_header('Content-Type', 'application/json')
|
||||||
|
self.send_header('Content-Length', str(len(data)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(data)
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == '/health':
|
||||||
|
last_sync, pending = self._read_state()
|
||||||
|
self._send_json(200, {
|
||||||
|
'status': 'healthy',
|
||||||
|
'lastSync': last_sync,
|
||||||
|
'pendingCount': pending
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
if self.path == '/sync':
|
||||||
|
STATE_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
(STATE_DIR / 'trigger').touch()
|
||||||
|
self._send_json(200, {'success': True})
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
STATE_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
server = http.server.HTTPServer(('', HTTP_PORT), SyncAgentHandler)
|
||||||
|
print(f'[Sync] HTTP server listening on :{HTTP_PORT}', flush=True)
|
||||||
|
server.serve_forever()
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
apiVersion: sandbox.opensandbox.io/v1alpha1
|
||||||
|
kind: Pool
|
||||||
|
metadata:
|
||||||
|
name: skill-sandbox-with-sync
|
||||||
|
namespace: opensandbox
|
||||||
|
labels:
|
||||||
|
app: skill-sandbox
|
||||||
|
component: sync-enabled
|
||||||
|
spec:
|
||||||
|
# 预热池大小
|
||||||
|
minReady: 2
|
||||||
|
maxSize: 20
|
||||||
|
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: skill-sandbox
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: workspace
|
||||||
|
emptyDir:
|
||||||
|
sizeLimit: 1Gi
|
||||||
|
|
||||||
|
containers:
|
||||||
|
# 主容器:Skill Sandbox(code-server 开发环境)
|
||||||
|
- name: sandbox
|
||||||
|
image: fastgpt-agent-sandbox:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
# FASTGPT_WORKDIR: the workspace directory opened by code-server.
|
||||||
|
# This is a subdirectory of the volume mountPath (/home/sandbox),
|
||||||
|
# keeping code under /home/sandbox/workspace separate from home files.
|
||||||
|
- name: FASTGPT_WORKDIR
|
||||||
|
value: "/home/sandbox/workspace"
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /home/sandbox
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
name: code-server
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: 2
|
||||||
|
memory: 2Gi
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
|
||||||
|
# Sidecar:Sync Agent(MinIO 文件同步)
|
||||||
|
- name: sync-agent
|
||||||
|
image: fastgpt-agent-sandbox:k8s
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: FASTGPT_MINIO_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: minio-credentials
|
||||||
|
key: endpoint
|
||||||
|
- name: FASTGPT_MINIO_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: minio-credentials
|
||||||
|
key: accessKey
|
||||||
|
- name: FASTGPT_MINIO_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: minio-credentials
|
||||||
|
key: secretKey
|
||||||
|
- name: FASTGPT_MINIO_BUCKET
|
||||||
|
value: "fastgpt-private"
|
||||||
|
- name: FASTGPT_SESSION_ID
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.labels['session-id']
|
||||||
|
- name: FASTGPT_SYNC_PATH
|
||||||
|
value: "/home/sandbox/workspace"
|
||||||
|
- name: SYNC_INTERVAL
|
||||||
|
value: "60"
|
||||||
|
- name: HTTP_PORT
|
||||||
|
value: "8081"
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /home/sandbox
|
||||||
|
ports:
|
||||||
|
- containerPort: 8081
|
||||||
|
name: sync-api
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 256Mi
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8081
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8081
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/var/log/supervisor/supervisord.log
|
||||||
|
pidfile=/tmp/supervisord.pid
|
||||||
|
|
||||||
|
# Sandbox 主进程(code-server)
|
||||||
|
# 通过环境变量 FASTGPT_ENABLE_CODE_SERVER=true|false 控制是否启动,默认 true
|
||||||
|
[program:code-server]
|
||||||
|
command=/home/sandbox/entrypoint.sh
|
||||||
|
user=sandbox
|
||||||
|
autostart=%(ENV_FASTGPT_ENABLE_CODE_SERVER)s
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/var/log/supervisor/code-server.log
|
||||||
|
stderr_logfile=/var/log/supervisor/code-server-error.log
|
||||||
|
|
||||||
|
# Sync Agent 后台进程(始终启动)
|
||||||
|
[program:sync-agent]
|
||||||
|
command=/opt/sync-agent/sync.sh
|
||||||
|
user=sandbox
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
environment=FASTGPT_SYNC_PATH="%(ENV_FASTGPT_WORKDIR)s",HTTP_SERVER_PATH="/opt/sync-agent/http_server.py"
|
||||||
|
stdout_logfile=/var/log/supervisor/sync-agent.log
|
||||||
|
stderr_logfile=/var/log/supervisor/sync-agent-error.log
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
SYNC_PATH=${FASTGPT_SYNC_PATH:-/home/sandbox}
|
||||||
|
BUCKET_PATH="minio/${FASTGPT_MINIO_BUCKET}/agent-sessions/${FASTGPT_SESSION_ID}"
|
||||||
|
SYNC_INTERVAL=${SYNC_INTERVAL:-60}
|
||||||
|
HTTP_PORT=${HTTP_PORT:-8081}
|
||||||
|
STATE_DIR="${STATE_DIR:-/tmp/sync-state}"
|
||||||
|
# K8s 模式默认 /http_server.py,Docker 模式通过 supervisord.conf 注入 /opt/sync-agent/http_server.py
|
||||||
|
HTTP_SERVER_PATH="${HTTP_SERVER_PATH:-/http_server.py}"
|
||||||
|
|
||||||
|
mkdir -p "${STATE_DIR}"
|
||||||
|
|
||||||
|
LAST_SYNC_FILE="${STATE_DIR}/last_sync"
|
||||||
|
PENDING_FILE="${STATE_DIR}/pending_count"
|
||||||
|
TRIGGER_FILE="${STATE_DIR}/trigger"
|
||||||
|
|
||||||
|
# 初始化状态
|
||||||
|
date -u +%Y-%m-%dT%H:%M:%SZ > "${LAST_SYNC_FILE}"
|
||||||
|
echo "0" > "${PENDING_FILE}"
|
||||||
|
|
||||||
|
# 1. 启动时下载历史文件
|
||||||
|
echo "[Sync] Downloading files from ${BUCKET_PATH}..."
|
||||||
|
mc mirror "${BUCKET_PATH}" "${SYNC_PATH}" --overwrite || true
|
||||||
|
date -u +%Y-%m-%dT%H:%M:%SZ > "${LAST_SYNC_FILE}"
|
||||||
|
|
||||||
|
# 2. 启动 HTTP 健康检查服务(后台)
|
||||||
|
echo "[Sync] Starting HTTP server on port ${HTTP_PORT}..."
|
||||||
|
python3 "${HTTP_SERVER_PATH}" &
|
||||||
|
|
||||||
|
# 3. 启动后台全量同步(定时 + 手动触发)
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
sleep "${SYNC_INTERVAL}"
|
||||||
|
|
||||||
|
# 检查手动触发
|
||||||
|
if [ -f "${TRIGGER_FILE}" ]; then
|
||||||
|
rm -f "${TRIGGER_FILE}"
|
||||||
|
echo "[Sync] Manual sync triggered via POST /sync"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[Sync] Periodic sync to MinIO..."
|
||||||
|
mc mirror "${SYNC_PATH}" "${BUCKET_PATH}" --overwrite
|
||||||
|
date -u +%Y-%m-%dT%H:%M:%SZ > "${LAST_SYNC_FILE}"
|
||||||
|
echo "0" > "${PENDING_FILE}"
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
|
||||||
|
# 4. 使用 inotify 监听实时变更(前台,保持进程存活)
|
||||||
|
echo "[Sync] Watching ${SYNC_PATH} for changes..."
|
||||||
|
inotifywait -m -r -e create,modify,move,delete --format '%w%f' "${SYNC_PATH}" | while read -r file; do
|
||||||
|
# 过滤临时文件(锚定行尾)
|
||||||
|
if echo "$file" | grep -qE '\.(tmp|swp|~)$'; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[Sync] Change detected: $file"
|
||||||
|
|
||||||
|
# 更新待同步计数
|
||||||
|
PENDING=$(cat "${PENDING_FILE}" 2>/dev/null || echo "0")
|
||||||
|
echo $((PENDING + 1)) > "${PENDING_FILE}"
|
||||||
|
|
||||||
|
# 计算相对路径
|
||||||
|
rel_path="${file#${SYNC_PATH}/}"
|
||||||
|
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
# 文件创建/修改:上传到 MinIO
|
||||||
|
mc cp "$file" "${BUCKET_PATH}/${rel_path}"
|
||||||
|
date -u +%Y-%m-%dT%H:%M:%SZ > "${LAST_SYNC_FILE}"
|
||||||
|
# 成功后将 pending 减 1
|
||||||
|
PENDING=$(cat "${PENDING_FILE}" 2>/dev/null || echo "1")
|
||||||
|
PENDING=$((PENDING - 1))
|
||||||
|
[ "${PENDING}" -lt 0 ] && PENDING=0
|
||||||
|
echo "${PENDING}" > "${PENDING_FILE}"
|
||||||
|
elif [ ! -e "$file" ]; then
|
||||||
|
# 文件删除
|
||||||
|
mc rm "${BUCKET_PATH}/${rel_path}" || true
|
||||||
|
date -u +%Y-%m-%dT%H:%M:%SZ > "${LAST_SYNC_FILE}"
|
||||||
|
PENDING=$(cat "${PENDING_FILE}" 2>/dev/null || echo "1")
|
||||||
|
PENDING=$((PENDING - 1))
|
||||||
|
[ "${PENDING}" -lt 0 ] && PENDING=0
|
||||||
|
echo "${PENDING}" > "${PENDING_FILE}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user