Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ on:
- "docs/**"
- "**/*.md"
- "**/*.yaml"
- "**/*.yml"
- "CHANGELOG/**"
- "controllers/**"
- "service/**"
Expand All @@ -29,6 +30,7 @@ on:
- "CHANGELOG/**"
- "**/*.md"
- "**/*.yaml"
- "**/*.yml"
- "CHANGELOG/**"
- "controllers/**"
- "service/**"
Expand Down
113 changes: 91 additions & 22 deletions .github/workflows/frontends.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ jobs:
outputs:
modules: ${{ steps.set-matrix.outputs.modules }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3
id: filter
with:
filters: |
Expand Down Expand Up @@ -98,24 +98,44 @@ jobs:
- 'frontend/providers/dbprovider/**'
costcenter:
- 'frontend/providers/costcenter/**'
cloudserver:
- 'frontend/providers/cloudserver/**'
invite:
- 'frontend/providers/invite/**'
objectstorage:
- 'frontend/providers/objectstorage/**'
kubepanel:
- 'frontend/providers/kubepanel/**'
devbox:
- 'frontend/providers/devbox/**'
desktop:
- 'frontend/desktop/**'
- name: Generate build matrix
id: set-matrix
env:
EVENT_NAME: ${{ github.event_name }}
FILTER_AIPROXY: ${{ steps.filter.outputs.aiproxy }}
FILTER_APPLAUNCHPAD: ${{ steps.filter.outputs.applaunchpad }}
FILTER_CLOUDSERVER: ${{ steps.filter.outputs.cloudserver }}
FILTER_COSTCENTER: ${{ steps.filter.outputs.costcenter }}
FILTER_CRONJOB: ${{ steps.filter.outputs.cronjob }}
FILTER_DBPROVIDER: ${{ steps.filter.outputs.dbprovider }}
FILTER_DESKTOP: ${{ steps.filter.outputs.desktop }}
FILTER_INVITE: ${{ steps.filter.outputs.invite }}
FILTER_KUBEPANEL: ${{ steps.filter.outputs.kubepanel }}
FILTER_LICENSE: ${{ steps.filter.outputs.license }}
FILTER_OBJECTSTORAGE: ${{ steps.filter.outputs.objectstorage }}
FILTER_PACKAGES: ${{ steps.filter.outputs.packages }}
FILTER_ROOT_CONFIG: ${{ steps.filter.outputs.root-config }}
FILTER_TEMPLATE: ${{ steps.filter.outputs.template }}
FILTER_TERMINAL: ${{ steps.filter.outputs.terminal }}
FORCE_ALL: ${{ inputs.force_all }}
run: |
modules=()

# Check if we need to build all modules
if [[ "${{ steps.filter.outputs.packages }}" == "true" || \
"${{ steps.filter.outputs.root-config }}" == "true" || \
"${{ inputs.force_all }}" == "true" || \
"${{ github.event_name }}" == "workflow_dispatch" ]]; then
if [[ "${FILTER_PACKAGES}" == "true" || \
"${FILTER_ROOT_CONFIG}" == "true" || \
"${FORCE_ALL}" == "true" || \
"${EVENT_NAME}" == "workflow_dispatch" ]]; then
modules=(
"providers/aiproxy"
"providers/license"
Expand All @@ -125,25 +145,27 @@ jobs:
"providers/terminal"
"providers/dbprovider"
"providers/costcenter"
"providers/cloudserver"
"providers/invite"
"providers/objectstorage"
"providers/kubepanel"
"providers/devbox"
"desktop"
)
else
# Only build changed modules
[[ "${{ steps.filter.outputs.aiproxy }}" == "true" ]] && modules+=("providers/aiproxy")
[[ "${{ steps.filter.outputs.license }}" == "true" ]] && modules+=("providers/license")
[[ "${{ steps.filter.outputs.cronjob }}" == "true" ]] && modules+=("providers/cronjob")
[[ "${{ steps.filter.outputs.template }}" == "true" ]] && modules+=("providers/template")
[[ "${{ steps.filter.outputs.applaunchpad }}" == "true" ]] && modules+=("providers/applaunchpad")
[[ "${{ steps.filter.outputs.terminal }}" == "true" ]] && modules+=("providers/terminal")
[[ "${{ steps.filter.outputs.dbprovider }}" == "true" ]] && modules+=("providers/dbprovider")
[[ "${{ steps.filter.outputs.costcenter }}" == "true" ]] && modules+=("providers/costcenter")
[[ "${{ steps.filter.outputs.objectstorage }}" == "true" ]] && modules+=("providers/objectstorage")
[[ "${{ steps.filter.outputs.kubepanel }}" == "true" ]] && modules+=("providers/kubepanel")
[[ "${{ steps.filter.outputs.devbox }}" == "true" ]] && modules+=("providers/devbox")
[[ "${{ steps.filter.outputs.desktop }}" == "true" ]] && modules+=("desktop")
[[ "${FILTER_AIPROXY}" == "true" ]] && modules+=("providers/aiproxy")
[[ "${FILTER_LICENSE}" == "true" ]] && modules+=("providers/license")
[[ "${FILTER_CRONJOB}" == "true" ]] && modules+=("providers/cronjob")
[[ "${FILTER_TEMPLATE}" == "true" ]] && modules+=("providers/template")
[[ "${FILTER_APPLAUNCHPAD}" == "true" ]] && modules+=("providers/applaunchpad")
[[ "${FILTER_TERMINAL}" == "true" ]] && modules+=("providers/terminal")
[[ "${FILTER_DBPROVIDER}" == "true" ]] && modules+=("providers/dbprovider")
[[ "${FILTER_COSTCENTER}" == "true" ]] && modules+=("providers/costcenter")
[[ "${FILTER_CLOUDSERVER}" == "true" ]] && modules+=("providers/cloudserver")
[[ "${FILTER_INVITE}" == "true" ]] && modules+=("providers/invite")
[[ "${FILTER_OBJECTSTORAGE}" == "true" ]] && modules+=("providers/objectstorage")
[[ "${FILTER_KUBEPANEL}" == "true" ]] && modules+=("providers/kubepanel")
[[ "${FILTER_DESKTOP}" == "true" ]] && modules+=("desktop")
fi

# Convert to JSON array (compact format for GitHub Actions)
Expand All @@ -155,9 +177,56 @@ jobs:
echo "modules=$json_modules" >> $GITHUB_OUTPUT
echo "Building modules: $json_modules"

image-build:
helm-validate:
needs: detect-changes
if: needs.detect-changes.outputs.modules != '[]'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
module: ${{ fromJSON(needs.detect-changes.outputs.modules) }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
- name: Validate Helm charts
shell: bash
env:
MODULE: ${{ matrix.module }}
run: |
chart_root="frontend/${MODULE}/deploy/charts"
if [[ ! -d "${chart_root}" ]]; then
echo "No Helm chart found for ${MODULE}; skipping"
exit 0
fi

found=false
while IFS= read -r -d '' chart_file; do
found=true
chart_dir=$(dirname "${chart_file}")
chart_name=$(basename "${chart_dir}")
user_values=$(find "${chart_dir}" -maxdepth 1 -type f -name '*-values.yaml' -print -quit)

helm lint "${chart_dir}"
helm template "${chart_name}" "${chart_dir}" \
--namespace "${chart_name}" >/dev/null

if [[ -n "${user_values}" ]]; then
helm lint "${chart_dir}" --values "${user_values}"
helm template "${chart_name}" "${chart_dir}" \
--namespace "${chart_name}" \
--values "${user_values}" >/dev/null
fi
done < <(find "${chart_root}" -mindepth 2 -maxdepth 2 -name Chart.yaml -print0)

if [[ "${found}" == "false" ]]; then
echo "No Helm chart found for ${MODULE}; skipping"
fi

image-build:
needs:
- detect-changes
- helm-validate
if: needs.detect-changes.outputs.modules != '[]'
uses: ./.github/workflows/frontend.yml
permissions:
contents: read
Expand Down
3 changes: 0 additions & 3 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,6 @@ USER nextjs

# You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/$path/next.config.js ./$path/next.config.js
RUN if ["$name" = "objectstorage" ]; then \
COPY --from=builder /app/$path/next-i18next.config.js ./$path/next-i18next.config.js; \
fi
COPY --from=builder /app/$path/public ./$path/public
COPY --from=builder --chown=nextjs:nodejs /app/$path/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/$path/.next/static ./$path/.next/static
Expand Down
2 changes: 2 additions & 0 deletions frontend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ buildTargets := \
providers/costcenter \
providers/dbprovider \
providers/applaunchpad \
providers/cloudserver \
providers/invite \
providers/imagehub \
providers/template \
providers/cronjob \
Expand Down
32 changes: 23 additions & 9 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,31 @@ make image-push-<app> DOCKER_USERNAME=<your_account> IMAGE_TAG=<tag>
make push-images DOCKER_USERNAME=<your_account> IMAGE_TAG=<tag>
```

## new App
## Add a provider frontend

Refer to other apps to add some configuration.
Use an existing provider as the reference and keep these deployment surfaces in sync:

1. .github/workflows/frontends.yml
2. deploy/cloud/init.sh
3. deploy/cloud/scripts/init.sh
4. frontend/providers/app/deploy/manifests/appcr.yaml.tmpl
5. frontend/providers/app/deploy/manifests/deploy.yaml
6. frontend/providers/app/deploy/manifests/ingress.yaml.tmpl
7. makefile
1. `.github/workflows/frontends.yml` change detection and Helm validation
2. `frontend/Makefile` image build target
3. `frontend/providers/<app>/deploy/Kubefile`
4. `frontend/providers/<app>/deploy/<app>-frontend-entrypoint.sh`
5. `frontend/providers/<app>/deploy/charts/<release>/Chart.yaml`
6. Chart defaults in `values.yaml` and, when needed, user overrides in `<release>-values.yaml`
7. Chart templates for the App CR (where applicable), Deployment, Service, Ingress, probes, and `helm test`

Validate the defaults and any user values file before publishing an image:

```bash
helm lint frontend/providers/<app>/deploy/charts/<release>
helm template <release> frontend/providers/<app>/deploy/charts/<release> >/dev/null
# Run this pair only when <release>-values.yaml exists.
helm lint frontend/providers/<app>/deploy/charts/<release> \
-f frontend/providers/<app>/deploy/charts/<release>/<release>-values.yaml
helm template <release> frontend/providers/<app>/deploy/charts/<release> \
-f frontend/providers/<app>/deploy/charts/<release>/<release>-values.yaml >/dev/null
```

After deployment, run `helm test <release> -n <namespace> --logs` and smoke-test the rendered App CR URL. Deployment-only migrations must preserve existing application routing; route behavior changes belong in a separate application change.

## multiple namespaces

Expand Down
13 changes: 8 additions & 5 deletions frontend/desktop/deploy/HELM_VALUES_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ sealos run desktop-frontend:latest \
-e HELM_OPTIONS="--set-string desktopConfig.realNameReward=0"
```

### 方式 3: 结合环境变量使用
### 方式 3: 结合自动配置使用

环境变量优先级高于 `HELM_OPTIONS` 中的 `--set` 参数
`HELM_OPTIONS` 在自动配置之后追加,因此显式参数优先级更高

```bash
# 环境变量会覆盖 HELM_OPTIONS 中的值
# HELM_OPTIONS 会覆盖 sealos-config 中的自动配置值
sealos run desktop-frontend:latest \
-e HELM_OPTIONS="--set desktopConfig.cloudDomain=from-helm.com" \
-e CLOUD_DOMAIN=from-env.com # 这个值会生效
-e HELM_OPTIONS="--set desktopConfig.cloudDomain=from-helm.com"
```

## 配置项分类
Expand All @@ -47,6 +46,10 @@ desktopConfig:
desktopConfig:
databaseGlobalCockroachdbURI: 'postgres://user:pass@cockroachdb:26257'
databaseLocalCockroachdbURI: 'postgres://user:pass@cockroachdb-local:26257'

# 正常安装默认执行 Prisma migration;仅前端 smoke 时关闭。
databaseMigration:
enabled: true
```

### 3. 认证配置
Expand Down
13 changes: 8 additions & 5 deletions frontend/desktop/deploy/HELM_VALUES_GUIDE_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ sealos run desktop-frontend:latest \
-e HELM_OPTIONS="--set-string desktopConfig.realNameReward=0"
```

### 方式 3: 结合环境变量使用
### 方式 3: 结合自动配置使用

环境变量优先级高于 `HELM_OPTIONS` 中的 `--set` 参数
`HELM_OPTIONS` 在自动配置之后追加,因此显式参数优先级更高

```bash
# 环境变量会覆盖 HELM_OPTIONS 中的值
# HELM_OPTIONS 会覆盖 sealos-config 中的自动配置值
sealos run desktop-frontend:latest \
-e HELM_OPTIONS="--set desktopConfig.cloudDomain=from-helm.com" \
-e CLOUD_DOMAIN=from-env.com # 这个值会生效
-e HELM_OPTIONS="--set desktopConfig.cloudDomain=from-helm.com"
```

## 配置项分类
Expand All @@ -47,6 +46,10 @@ desktopConfig:
desktopConfig:
databaseGlobalCockroachdbURI: "postgres://user:pass@cockroachdb:26257"
databaseLocalCockroachdbURI: "postgres://user:pass@cockroachdb-local:26257"

# 正常安装默认执行 Prisma migration;仅前端 smoke 时关闭。
databaseMigration:
enabled: true
```

### 3. 认证配置
Expand Down
19 changes: 13 additions & 6 deletions frontend/desktop/deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ sealos run desktop-frontend:latest \

The Helm Chart uses two values files to manage configuration:

### 1. values-default.yaml
### 1. values.yaml

Contains default Helm Chart configurations that should not be modified.

Expand All @@ -37,9 +37,9 @@ Contains default Helm Chart configurations that should not be modified.

**Modification**: ❌ Do not modify

### 2. values-custom.yaml
### 2. desktop-frontend-values.yaml

Contains user-customizable configurations.
Contains the template for user-customizable configurations. On the first install it is copied to `/root/.sealos/cloud/values/core/desktop-values.yaml`; existing installs keep that persisted file.

**Content**:

Expand All @@ -53,9 +53,9 @@ Contains user-customizable configurations.

**Modification**: ✅ Modify as needed

**Note**: Auto-configured items in values-default.yaml (such as cloudDomain, jwtInternal, etc.) are automatically fetched by the entrypoint script from the `sealos-system/sealos-config` ConfigMap and will be overridden. To modify these values, edit the ConfigMap or use HELM_OPTIONS.
**Note**: The entrypoint applies values in this order: `values.yaml`, persisted user values, optional `global.yaml`, auto-configuration from `sealos-system/sealos-config`, then explicit `HELM_OPTIONS` / `HELM_OPTS`. Later sources win.

For detailed documentation, see [VALUES_FILES_GUIDE.md](./VALUES_FILES_GUIDE.md).
For detailed documentation, see [HELM_VALUES_GUIDE.md](./HELM_VALUES_GUIDE.md).

## Environment Variables

Expand Down Expand Up @@ -312,7 +312,7 @@ Desktop Frontend supports adding custom subdomains to the `allowedOrigins` list.

### Configuration

Add `additionalAllowedOriginsPrefixes` in `values-custom.yaml`:
Add `additionalAllowedOriginsPrefixes` in the persisted `desktop-values.yaml` user values file:

```yaml
desktopConfig:
Expand Down Expand Up @@ -376,6 +376,7 @@ For more details, see [ALLOWED_ORIGINS_USAGE.md](./ALLOWED_ORIGINS_USAGE.md).
| `serviceAccount.create` | Create service account | `true` |
| `serviceAccount.name` | Service account name | `desktop-frontend` |
| `service.port` | Service port | `3000` |
| `databaseMigration.enabled` | Run Prisma migrations on start | `true` |
| `resources.requests.cpu` | CPU request | `100m` |
| `resources.requests.memory` | Memory request | `128Mi` |
| `resources.limits.cpu` | CPU limit | `2000m` |
Expand Down Expand Up @@ -423,6 +424,10 @@ kubectl logs -n sealos -l app.kubernetes.io/name=desktop-frontend --tail=100 -f

- **Solution**: The script automatically adopts existing resources by adding Helm labels

**Issue**: A frontend-only smoke test must not write to the database

- **Solution**: Set `HELM_OPTIONS="--set databaseMigration.enabled=false"`. Normal installs keep the default `true`; disabling it removes only the `init-database` init container.

## Advanced Usage

### Using Helm Values for Custom Configuration
Expand Down Expand Up @@ -481,6 +486,8 @@ sealos run desktop-frontend:latest \
sealos run desktop-frontend:latest -e HELM_OPTIONS="--timeout 10m"
```

Explicit `HELM_OPTIONS` and `HELM_OPTS` are appended after auto-configuration, so they have the highest precedence.

### Override Namespace

```bash
Expand Down
Loading
Loading