From 0999721f9af501164ae784c57995cd459f82bb6a Mon Sep 17 00:00:00 2001 From: john Date: Sat, 28 Mar 2026 18:32:11 +0800 Subject: [PATCH] refactor: standardize helm charts and release flow --- .github/workflows/README.md | 248 ++------ .github/workflows/release.yml | 257 +++++---- README.md | 208 ++----- charts/README.md | 83 --- curvine-csi/Chart.yaml | 4 +- curvine-csi/README.md | 251 +++----- curvine-csi/templates/NOTES.txt | 44 +- curvine-csi/templates/_helpers.tpl | 6 +- curvine-csi/templates/deployment.yaml | 4 +- curvine-csi/values.schema.json | 191 ++++++ curvine-csi/values.yaml | 4 +- curvine-runtime/README.md | 544 ++++-------------- .../examples/values-baremetal.yaml | 52 +- curvine-runtime/examples/values-dev.yaml | 32 +- curvine-runtime/examples/values-prod.yaml | 58 +- curvine-runtime/templates/NOTES.txt | 80 +-- .../templates/pre-upgrade-hook.yaml | 57 -- curvine-runtime/values.schema.json | 446 ++++++++++++++ curvine-runtime/values.yaml | 27 +- 19 files changed, 1192 insertions(+), 1404 deletions(-) delete mode 100644 charts/README.md create mode 100644 curvine-csi/values.schema.json delete mode 100644 curvine-runtime/templates/pre-upgrade-hook.yaml create mode 100644 curvine-runtime/values.schema.json diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 82cae30..d63c0be 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,228 +1,82 @@ # Helm Chart Release Workflow -This document explains how to use the automated Helm chart release workflow. +This repository publishes chart packages from source directories and serves the public Helm index from `curvine-doc`. -## Overview +## Published Charts -The workflow supports two modes: -1. **Automatic trigger** (push events) - Updates curvine-helm repository only -2. **Manual trigger** (workflow_dispatch) - Optional sync to curvine-doc repository +| Source Directory | Published Chart Name | Package Pattern | +| --- | --- | --- | +| `curvine-runtime/` | `curvine` | `curvine-.tgz` | +| `curvine-csi/` | `curvine-csi` | `curvine-csi-.tgz` | ## Architecture -``` -┌─────────────────────────────────────────────────────────────┐ -│ curvine-helm Repository │ -│ │ -│ charts/ │ -│ ├── index.yaml ← Always updated │ -│ ├── curvine-csi-*.tgz ← All versions stored here │ -│ └── curvine-runtime-*.tgz │ -│ │ -│ Served via: https://curvineio.github.io/curvine-helm/charts│ -└─────────────────────────────────────────────────────────────┘ - │ - │ Optional sync (manual control) - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ curvine-doc Repository │ -│ │ -│ static/helm-charts/ │ -│ └── index.yaml ← Synced only when requested │ -│ │ -│ Served via: https://curvineio.github.io/curvine-doc/... │ -└─────────────────────────────────────────────────────────────┘ -``` - -## Usage - -### 1. Testing (Push to main branch) - -**Purpose**: Quick testing without version pollution - -```bash -git add . -git commit -m "test: some changes" -git push origin main -``` - -**Results**: -- ✅ Builds charts with fixed version `x.x.x-dev` -- ✅ Updates `curvine-helm/charts/` with packages and index.yaml -- ✅ Overwrites GitHub Release "latest" -- ❌ Does NOT sync to curvine-doc (testing only) - -**Version behavior**: -- Always uses the same version (e.g., `0.0.0-dev`) -- Each push overwrites the previous dev release -- Keeps version history clean - -### 2. Manual Build (with optional sync) - -**Purpose**: Build any branch/tag and optionally sync to curvine-doc - -**Steps**: -1. Go to GitHub Actions page -2. Select "Build and Release Helm Chart" -3. Click "Run workflow" -4. Fill in the form: - - **ref**: Branch or tag name (e.g., `main`, `v0.1.0`) - - **sync_to_doc**: Check this to sync index.yaml to curvine-doc - -**Results**: -- ✅ Builds charts from specified ref -- ✅ Updates `curvine-helm/charts/` (always) -- ✅ Syncs to `curvine-doc` (if checked) - -**Use cases**: -- Test a specific branch: ref=`feature-branch`, sync=unchecked -- Update production index: ref=`main`, sync=checked -- Release to both repos: ref=`v0.1.0`, sync=checked - -### 3. Version Release (Push tag) - -**Purpose**: Official version release - -```bash -# Tag the release -git tag v0.1.0 -git push origin v0.1.0 -``` - -**Results**: -- ✅ Builds charts with version `0.1.0` -- ✅ Updates `curvine-helm/charts/` -- ✅ Creates new GitHub Release "v0.1.0" -- ❌ Does NOT auto-sync (use manual trigger to sync) - -**To sync after tagging**: -```bash -# After tag is pushed, manually trigger workflow -# Go to Actions → Run workflow → Select tag → Check sync_to_doc -``` - -## Version Strategy - -| Trigger | Version Format | Example | Overwrites? | -|---------|----------------|---------|-------------| -| main branch | `{base}-dev` | `0.0.0-dev` | Yes (same version) | -| v* tag | `{tag without v}` | `0.1.0` | No (unique version) | -| Manual (main) | `{base}-dev` | `0.0.0-dev` | Yes (same version) | -| Manual (tag) | `{tag without v}` | `0.1.0` | No (unique version) | +- Chart source code lives in this repository. +- Packaged charts are uploaded to GitHub Releases. +- The public Helm index lives at `https://curvineio.github.io/curvine-doc/helm-charts/index.yaml`. +- The workflow does not commit packaged charts or `index.yaml` back into this repository. -## Sync Control +## Triggers -| Event Type | Auto Sync | Manual Sync | Notes | -|------------|-----------|-------------|-------| -| push (main) | ❌ | ❌ | Testing only, no inputs available | -| push (tag) | ❌ | ✅ | Use manual trigger after push | -| workflow_dispatch | ❌ | ✅ | Check "sync_to_doc" option | +### Push to `main` -## Best Practices +- Packages both charts with a fixed `-dev` chart version +- Updates the GitHub Release named `latest` +- Does not sync `index.yaml` to `curvine-doc` -### For Development +Use this for testing only. -```bash -# Frequent testing (doesn't pollute versions) -git push origin main +### Push a `v*` tag -# Result: 0.0.0-dev (always the same, gets overwritten) -``` +- Packages both charts with the tag version +- Creates or updates the matching GitHub Release +- Does not sync `index.yaml` automatically -### For Release Preparation +### Manual trigger -```bash -# 1. Create and push tag -git tag v0.2.0 -git push origin v0.2.0 +Inputs: -# 2. Verify the release in GitHub -# 3. Manually trigger workflow to sync: -# - ref: v0.2.0 -# - sync_to_doc: ✅ checked +- `ref`: branch or tag to build +- `sync_to_doc`: whether to sync the public `index.yaml` to `curvine-doc` for a version tag build -# Result: Both curvine-helm and curvine-doc are updated -``` - -### For Emergency Index Update - -```bash -# Use manual trigger: -# - ref: main (or any other ref) -# - sync_to_doc: ✅ checked +Behavior: -# This will sync the current index.yaml to curvine-doc -``` - -## File Locations - -### In curvine-helm repository - -``` -charts/ -├── index.yaml # Always updated -├── curvine-csi-0.0.0-dev.tgz # Dev version (overwritten) -├── curvine-csi-0.1.0.tgz # Release version -├── curvine-csi-0.2.0.tgz # Release version -├── curvine-runtime-0.0.0-dev.tgz # Dev version (overwritten) -├── curvine-runtime-0.1.0.tgz # Release version -└── curvine-runtime-0.2.0.tgz # Release version -``` +- A tag ref such as `v0.2.0` packages charts with version `0.2.0` +- A branch ref packages charts as the current base version plus `-dev` and updates the `latest` test release +- `sync_to_doc=true` is only valid when `ref` is a `v*` tag; the workflow fails fast for branch refs +- When `sync_to_doc` is enabled for a tag build, the workflow rebuilds `index.yaml` with release URLs and pushes it to `curvine-doc` -### In curvine-doc repository +## Versioning Rules -``` -static/helm-charts/ -└── index.yaml # Synced only when manually triggered with sync_to_doc=true -``` +| Trigger | Chart Version | +| --- | --- | +| `main` push | `-dev` | +| `v*` tag push | `` | +| Manual branch build | `-dev` | +| Manual tag build | `` | -## User Installation +## Operator Installation -End users can install charts from curvine-helm repository: +End users should install from the public Helm repository: ```bash -# Add repository -helm repo add curvineio https://curvineio.github.io/curvine-helm/charts - -# Update repository index +helm repo add curvineio https://curvineio.github.io/curvine-doc/helm-charts helm repo update -# Search available charts -helm search repo curvineio - -# Install a chart -helm install curvine curvineio/curvine-runtime -helm install curvine-csi curvineio/curvine-csi +helm upgrade --install curvine curvineio/curvine +helm upgrade --install curvine-csi curvineio/curvine-csi ``` -## Troubleshooting - -### Q: I pushed a tag but it's not in curvine-doc - -**A**: Tag pushes don't auto-sync. Use manual trigger with sync_to_doc checked. - -### Q: How to test without creating lots of versions? - -**A**: Push to main branch. It always uses the same dev version (e.g., `0.0.0-dev`). - -### Q: How to sync latest index.yaml to curvine-doc? - -**A**: Use manual trigger with: -- ref: main (or the branch/tag you want) -- sync_to_doc: ✅ checked - -### Q: Will frequent pushes to main create version pollution? - -**A**: No. Main branch always uses the same fixed dev version (e.g., `0.0.0-dev`), which gets overwritten each time. - -## Security +## Release Checklist -The workflow requires `CURVINE_DOC_TOKEN` secret to push to curvine-doc repository. This token should have: -- `repo` scope (full control of private repositories) +1. Update chart source and documentation. +2. Push to `main` if you need a test package in the `latest` release. +3. Create and push a `v*` tag for a versioned release. +4. Manually run the workflow with `ref=` and `sync_to_doc=true` when you are ready to publish the updated index. -To create the token: -1. GitHub Settings → Developer settings → Personal access tokens -2. Generate new token (classic) -3. Select `repo` scope -4. Copy and add to curvine-helm repository secrets as `CURVINE_DOC_TOKEN` +## Notes +- The runtime source directory is `curvine-runtime/`, but the published chart name is `curvine`. +- The public repository URL should always point to `curvine-doc`. +- GitHub Releases are the source of truth for chart package files. +- Manual branch builds are for release validation only and must not be synced into the public Helm index. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e5f87bb..b8c68bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,27 +14,54 @@ on: type: string default: 'main' sync_to_doc: - description: 'Sync index.yaml to curvine-doc repository' + description: 'Sync index.yaml to curvine-doc repository (v* tags only)' required: true type: boolean default: false jobs: + validate-inputs: + runs-on: ubuntu-latest + outputs: + manual_ref: ${{ steps.validate.outputs.manual_ref }} + steps: + - name: Validate manual workflow inputs + id: validate + run: | + if [[ "${{ github.event_name }}" != "workflow_dispatch" ]]; then + echo "manual_ref=" >> "$GITHUB_OUTPUT" + exit 0 + fi + + REF="${{ inputs.ref }}" + if [[ -z "$REF" ]]; then + REF="main" + fi + + if [[ "${{ inputs.sync_to_doc }}" == "true" && "$REF" != v* ]]; then + echo "::error title=Invalid sync target::sync_to_doc=true is only supported for version tags (v*). Received ref: $REF" + exit 1 + fi + + echo "manual_ref=$REF" >> "$GITHUB_OUTPUT" + echo "Validated manual ref: $REF" + build-charts: + needs: validate-inputs runs-on: ubuntu-latest strategy: matrix: chart: - name: curvine-csi path: curvine-csi - - name: curvine-runtime + - name: curvine path: curvine-runtime steps: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || '' }} + ref: ${{ github.event_name == 'workflow_dispatch' && needs.validate-inputs.outputs.manual_ref || github.ref }} fetch-depth: 0 - name: Set up Helm @@ -45,16 +72,27 @@ jobs: - name: Extract tag/version information id: tag run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + REF="${{ needs.validate-inputs.outputs.manual_ref }}" + if [[ "$REF" == v* ]]; then + TAG="$REF" + IS_TAG=true + IS_BRANCH_BUILD=false + else + TAG="latest" + IS_TAG=false + IS_BRANCH_BUILD=true + fi # Handle tag push - if [[ "$GITHUB_REF" == refs/tags/* ]]; then + elif [[ "$GITHUB_REF" == refs/tags/* ]]; then TAG=${GITHUB_REF#refs/tags/} IS_TAG=true - IS_MAIN_BRANCH=false + IS_BRANCH_BUILD=false # Handle main branch push elif [[ "$GITHUB_REF" == refs/heads/main ]]; then TAG="latest" IS_TAG=false - IS_MAIN_BRANCH=true + IS_BRANCH_BUILD=true else echo "Error: Unexpected ref: $GITHUB_REF" exit 1 @@ -63,8 +101,8 @@ jobs: # Extract version from tag (remove 'v' prefix if present) if [[ "$TAG" == v* ]]; then VERSION=${TAG#v} - elif [ "$IS_MAIN_BRANCH" == "true" ]; then - # For main branch, will be set in next step after reading Chart.yaml + elif [ "$IS_BRANCH_BUILD" == "true" ]; then + # For branch builds, version is set after reading Chart.yaml VERSION="" else VERSION=$TAG @@ -73,50 +111,29 @@ jobs: echo "tag=$TAG" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT echo "is_tag=$IS_TAG" >> $GITHUB_OUTPUT - echo "is_main_branch=$IS_MAIN_BRANCH" >> $GITHUB_OUTPUT + echo "is_branch_build=$IS_BRANCH_BUILD" >> $GITHUB_OUTPUT echo "Tag/Version: $TAG ($VERSION)" echo "Is Tag: $IS_TAG" - echo "Is Main Branch: $IS_MAIN_BRANCH" + echo "Is Branch Build: $IS_BRANCH_BUILD" - - name: Prepare pre-release version for main branch - if: steps.tag.outputs.is_main_branch == 'true' - id: prerelease + - name: Set chart version + id: version run: | - # Read current version from Chart.yaml CURRENT_VERSION=$(grep '^version:' ${{ matrix.chart.path }}/Chart.yaml | awk '{print $2}' | tr -d '"') echo "Current Chart version for ${{ matrix.chart.name }}: $CURRENT_VERSION" - - # Extract base version (remove any pre-release suffix like -alpha.1, -dev+abc123, etc.) - # Examples: 0.2.0 -> 0.2.0, 0.2.0-alpha.1 -> 0.2.0, 0.2.1-dev+abc123 -> 0.2.1 + BASE_VERSION=$(echo "$CURRENT_VERSION" | sed 's/-.*//') echo "Base version: $BASE_VERSION" - - # Generate FIXED pre-release version for testing: use base version + -dev suffix (NO commit hash) - # Format: BASE_VERSION-dev - # This ensures the same version is always used for main branch, allowing it to be overwritten - # Perfect for testing without polluting the version history - PRE_RELEASE_VERSION="${BASE_VERSION}-dev" - - echo "Pre-release version (fixed for testing): $PRE_RELEASE_VERSION" - echo "version=$PRE_RELEASE_VERSION" >> $GITHUB_OUTPUT - - # Update Chart.yaml with pre-release version - # GitHub Actions runs on Linux, so use Linux sed syntax - sed -i "s/^version:.*/version: $PRE_RELEASE_VERSION/" ${{ matrix.chart.path }}/Chart.yaml - - echo "Updated Chart.yaml version to: $PRE_RELEASE_VERSION" - cat ${{ matrix.chart.path }}/Chart.yaml - - - name: Set final version - id: version - run: | - if [ "${{ steps.tag.outputs.is_main_branch }}" == "true" ]; then - FINAL_VERSION="${{ steps.prerelease.outputs.version }}" + if [ "${{ steps.tag.outputs.is_branch_build }}" == "true" ]; then + FINAL_VERSION="${BASE_VERSION}-dev" else FINAL_VERSION="${{ steps.tag.outputs.version }}" fi + + sed -i "s/^version:.*/version: $FINAL_VERSION/" ${{ matrix.chart.path }}/Chart.yaml echo "version=$FINAL_VERSION" >> $GITHUB_OUTPUT - echo "Final Chart Version: $FINAL_VERSION" + echo "Updated Chart.yaml version to: $FINAL_VERSION" + cat ${{ matrix.chart.path }}/Chart.yaml - name: Validate Helm chart run: | @@ -160,7 +177,9 @@ jobs: echo "- **Digest (SHA256)**: ${{ steps.checksum.outputs.digest }}" >> $GITHUB_STEP_SUMMARY create-release: - needs: build-charts + needs: + - validate-inputs + - build-charts runs-on: ubuntu-latest permissions: contents: write @@ -169,21 +188,48 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: + ref: ${{ github.event_name == 'workflow_dispatch' && needs.validate-inputs.outputs.manual_ref || github.ref }} fetch-depth: 0 + - name: Resolve source metadata + id: source + run: | + SOURCE_SHA=$(git rev-parse HEAD) + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + SOURCE_REF="${{ needs.validate-inputs.outputs.manual_ref }}" + else + SOURCE_REF="${GITHUB_REF_NAME}" + fi + + echo "source_ref=$SOURCE_REF" >> "$GITHUB_OUTPUT" + echo "source_sha=$SOURCE_SHA" >> "$GITHUB_OUTPUT" + echo "Source ref: $SOURCE_REF" + echo "Source SHA: $SOURCE_SHA" + - name: Extract tag/version information id: tag run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + REF="${{ needs.validate-inputs.outputs.manual_ref }}" + if [[ "$REF" == v* ]]; then + TAG="$REF" + IS_TAG=true + IS_BRANCH_BUILD=false + else + TAG="latest" + IS_TAG=false + IS_BRANCH_BUILD=true + fi # Handle tag push - if [[ "$GITHUB_REF" == refs/tags/* ]]; then + elif [[ "$GITHUB_REF" == refs/tags/* ]]; then TAG=${GITHUB_REF#refs/tags/} IS_TAG=true - IS_MAIN_BRANCH=false + IS_BRANCH_BUILD=false # Handle main branch push elif [[ "$GITHUB_REF" == refs/heads/main ]]; then TAG="latest" IS_TAG=false - IS_MAIN_BRANCH=true + IS_BRANCH_BUILD=true else echo "Error: Unexpected ref: $GITHUB_REF" exit 1 @@ -191,10 +237,10 @@ jobs: echo "tag=$TAG" >> $GITHUB_OUTPUT echo "is_tag=$IS_TAG" >> $GITHUB_OUTPUT - echo "is_main_branch=$IS_MAIN_BRANCH" >> $GITHUB_OUTPUT + echo "is_branch_build=$IS_BRANCH_BUILD" >> $GITHUB_OUTPUT echo "Tag: $TAG" echo "Is Tag: $IS_TAG" - echo "Is Main Branch: $IS_MAIN_BRANCH" + echo "Is Branch Build: $IS_BRANCH_BUILD" - name: Download all chart artifacts uses: actions/download-artifact@v4 @@ -220,11 +266,11 @@ jobs: fi # v* tags create normal releases - # main branch updates create/update "latest" release + # branch builds create/update the "latest" testing release if [ "${{ steps.tag.outputs.is_tag }}" == "true" ] && [ "$IS_V_TAG" == "true" ]; then RELEASE_TYPE="tag" RELEASE_TAG="${{ steps.tag.outputs.tag }}" - elif [ "${{ steps.tag.outputs.is_main_branch }}" == "true" ]; then + elif [ "${{ steps.tag.outputs.is_branch_build }}" == "true" ]; then RELEASE_TYPE="latest" RELEASE_TAG="latest" else @@ -249,11 +295,11 @@ jobs: ### Chart Information - **Tag**: ${{ steps.release.outputs.release_tag }} - - **Commit**: ${{ github.sha }} + - **Commit**: ${{ steps.source.outputs.source_sha }} This release includes two Helm charts: - **curvine-csi**: CSI Driver for Curvine storage - - **curvine-runtime**: Curvine distributed cache system + - **curvine**: Curvine distributed cache system ### Installation @@ -261,19 +307,19 @@ jobs: ```bash helm repo add curvineio https://curvineio.github.io/curvine-doc/helm-charts helm repo update - helm install curvine curvineio/curvine-runtime + helm upgrade --install curvine curvineio/curvine ``` #### Curvine CSI Driver ```bash helm repo add curvineio https://curvineio.github.io/curvine-doc/helm-charts helm repo update - helm install curvine-csi curvineio/curvine-csi + helm upgrade --install curvine-csi curvineio/curvine-csi ``` ### Files - curvine-csi chart package - - curvine-runtime chart package + - curvine chart package - checksums.txt (SHA256 checksums for both charts) files: | dist/*.tgz @@ -283,30 +329,28 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Create/Update GitHub Release (main branch -> latest) + - name: Create/Update GitHub Release (branch build -> latest) if: steps.release.outputs.release_type == 'latest' uses: softprops/action-gh-release@v2 with: tag_name: latest - name: Latest Release (Testing - main branch) + name: Latest Release (Testing Branch Build) body: | ## Latest Helm Charts Release (For Testing Only) - ⚠️ **This is a testing release that is overwritten on every push to `main` branch.** + ⚠️ **This is a testing release that is overwritten by the latest branch build.** - Use this for development and testing purposes only - For production use, please use versioned releases (v*) - Chart versions are fixed (e.g., 0.0.0-dev) and overwrite previous builds ### Chart Information - - **Branch**: main - - **Commit**: ${{ github.sha }} - - **Commit Message**: ${{ github.event.head_commit.message }} - - **Build Time**: ${{ github.event.head_commit.timestamp }} + - **Ref**: ${{ steps.source.outputs.source_ref }} + - **Commit**: ${{ steps.source.outputs.source_sha }} This release includes two Helm charts: - **curvine-csi-dev**: CSI Driver for Curvine storage (testing version) - - **curvine-runtime-dev**: Curvine distributed cache system (testing version) + - **curvine-dev**: Curvine distributed cache system (testing version) ### Installation @@ -314,13 +358,13 @@ jobs: ```bash # Download specific chart - wget https://github.com/CurvineIO/curvine-helm/releases/download/latest/curvine-runtime-*.tgz - helm install curvine ./curvine-runtime-*.tgz + wget https://github.com/CurvineIO/curvine-helm/releases/download/latest/curvine-*.tgz + helm upgrade --install curvine ./curvine-*.tgz ``` ### Files - curvine-csi chart package (version: *-dev) - - curvine-runtime chart package (version: *-dev) + - curvine chart package (version: *-dev) - checksums.txt (SHA256 checksums for both charts) > **Note**: This release is automatically overwritten. Do not use in production! @@ -338,7 +382,7 @@ jobs: echo "- **Release Type**: ${{ steps.release.outputs.release_type }}" >> $GITHUB_STEP_SUMMARY echo "- **Release Tag**: ${{ steps.release.outputs.release_tag }}" >> $GITHUB_STEP_SUMMARY echo "- **Is Tag**: ${{ steps.tag.outputs.is_tag }}" >> $GITHUB_STEP_SUMMARY - echo "- **Is Main Branch**: ${{ steps.tag.outputs.is_main_branch }}" >> $GITHUB_STEP_SUMMARY + echo "- **Is Branch Build**: ${{ steps.tag.outputs.is_branch_build }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Packaged Charts" >> $GITHUB_STEP_SUMMARY ls -lh dist/*.tgz >> $GITHUB_STEP_SUMMARY @@ -347,14 +391,38 @@ jobs: cat dist/checksums.txt >> $GITHUB_STEP_SUMMARY sync-to-helm-repo: - needs: create-release - # Only sync when manually triggered with sync_to_doc=true + needs: + - validate-inputs + - create-release + # Only sync version-tag releases to the public curvine-doc Helm index if: always() && needs.create-release.result == 'success' && github.event_name == 'workflow_dispatch' && inputs.sync_to_doc == true runs-on: ubuntu-latest permissions: contents: write steps: + - name: Checkout source repository + uses: actions/checkout@v4 + with: + ref: ${{ needs.validate-inputs.outputs.manual_ref }} + path: source-repo + fetch-depth: 0 + + - name: Resolve sync source metadata + id: source + run: | + SOURCE_REF="${{ needs.validate-inputs.outputs.manual_ref }}" + SOURCE_SHA=$(git -C source-repo rev-parse HEAD) + TAG="$SOURCE_REF" + VERSION="${TAG#v}" + + echo "source_ref=$SOURCE_REF" >> "$GITHUB_OUTPUT" + echo "source_sha=$SOURCE_SHA" >> "$GITHUB_OUTPUT" + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Sync source ref: $SOURCE_REF" + echo "Sync source SHA: $SOURCE_SHA" + - name: Checkout curvine-doc repository uses: actions/checkout@v4 with: @@ -368,42 +436,6 @@ jobs: with: version: 'latest' - - name: Extract version/tag information - id: version - run: | - # Determine the release tag based on trigger type - if [[ "$GITHUB_REF" == refs/tags/* ]]; then - # For tag push: use the tag name - TAG=${GITHUB_REF#refs/tags/} - VERSION=${TAG#v} - elif [[ "$GITHUB_REF" == refs/heads/main ]]; then - # For main branch: use "latest" as release tag - TAG="latest" - VERSION="latest" - elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - # For manual trigger: determine from inputs.ref - REF="${{ inputs.ref }}" - if [[ "$REF" == v* ]]; then - TAG="$REF" - VERSION="${REF#v}" - elif [[ "$REF" == "main" ]] || [[ -z "$REF" ]]; then - TAG="latest" - VERSION="latest" - else - # For other branches, use latest - TAG="latest" - VERSION="latest" - fi - else - TAG="latest" - VERSION="latest" - fi - - echo "tag=$TAG" >> $GITHUB_OUTPUT - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Release tag: $TAG" - echo "Version: $VERSION" - - name: Download old index.yaml from curvine-doc run: | mkdir -p temp-charts @@ -427,7 +459,7 @@ jobs: run: | cd temp-charts - RELEASE_TAG="${{ steps.version.outputs.tag }}" + RELEASE_TAG="${{ steps.source.outputs.tag }}" echo "Downloading charts from release: $RELEASE_TAG" # Download using GitHub CLI @@ -444,7 +476,7 @@ jobs: run: | cd temp-charts - RELEASE_TAG="${{ steps.version.outputs.tag }}" + RELEASE_TAG="${{ steps.source.outputs.tag }}" # Check if old-index.yaml exists and is not empty if [ -s old-index.yaml ]; then @@ -487,11 +519,11 @@ jobs: if git diff --staged --quiet; then echo "No changes to index.yaml" else - COMMIT_MSG="chore(helm): update index.yaml from release ${{ steps.version.outputs.tag }} + COMMIT_MSG="chore(helm): update index.yaml from release ${{ steps.source.outputs.tag }} Auto-generated by GitHub Actions - Source: CurvineIO/curvine-helm@${{ github.sha }} - Release: ${{ steps.version.outputs.tag }} + Source: CurvineIO/curvine-helm@${{ steps.source.outputs.source_sha }} + Release: ${{ steps.source.outputs.tag }} This index.yaml includes all historical versions with URLs pointing to GitHub Releases." @@ -503,8 +535,9 @@ jobs: - name: Sync Summary run: | echo "## Helm Repository Sync Complete" >> $GITHUB_STEP_SUMMARY - echo "- **Version**: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **Release Tag**: ${{ steps.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **Version**: ${{ steps.source.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Release Tag**: ${{ steps.source.outputs.tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **Source Commit**: ${{ steps.source.outputs.source_sha }}" >> $GITHUB_STEP_SUMMARY echo "- **Status**: ✅ Synced successfully" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Architecture" >> $GITHUB_STEP_SUMMARY @@ -521,7 +554,5 @@ jobs: echo "helm repo add curvineio https://curvineio.github.io/curvine-doc/helm-charts" >> $GITHUB_STEP_SUMMARY echo "helm repo update" >> $GITHUB_STEP_SUMMARY echo "helm search repo curvineio" >> $GITHUB_STEP_SUMMARY - echo "helm install curvine curvineio/curvine-runtime" >> $GITHUB_STEP_SUMMARY + echo "helm upgrade --install curvine curvineio/curvine" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY - - diff --git a/README.md b/README.md index 6fc26d4..89a165e 100644 --- a/README.md +++ b/README.md @@ -1,193 +1,93 @@ # Curvine Helm Charts -Official Helm charts for Curvine projects. +Source repository for the Curvine Helm charts. -## Available Charts +## Published Helm Repository -- **curvine-csi**: CSI Driver for Curvine storage -- **curvine-runtime**: Curvine distributed multi-level cache system - -## Quick Start - -Add the Helm repository: +Public index: ```bash helm repo add curvineio https://curvineio.github.io/curvine-doc/helm-charts helm repo update ``` -Search available charts: - -```bash -helm search repo curvineio -``` - -Install charts: - -```bash -# Install Curvine Runtime -helm install curvine curvineio/curvine-runtime - -# Install Curvine CSI Driver -helm install curvine-csi curvineio/curvine-csi -``` - -## Architecture - -This repository uses a clean, efficient architecture: - -``` -┌──────────────────────────────────────────────┐ -│ curvine-helm Repository (main branch) │ -│ - Source code only │ -│ - curvine-csi/ (chart source) │ -│ - curvine-runtime/ (chart source) │ -└───────────────┬──────────────────────────────┘ - │ - ▼ -┌──────────────────────────────────────────────┐ -│ GitHub Actions Build & Release │ -│ - Builds charts from source │ -│ - Creates GitHub Releases │ -│ - Uploads .tgz packages to Releases │ -└───────────────┬──────────────────────────────┘ - │ - ├────────────┬──────────────────┐ - ▼ ▼ ▼ - ┌───────────────────┐ ┌────────────┐ ┌────────────┐ - │ GitHub Releases │ │ curvine-doc│ │ Users │ - │ Store .tgz files │ │ index.yaml │ │ Download │ - └───────────────────┘ └────────────┘ └────────────┘ -``` - -### Key Points - -1. **Chart Packages (.tgz)**: Stored in GitHub Releases - - URL: `https://github.com/CurvineIO/curvine-helm/releases/download/{tag}/` - - Each release (v0.1.0, v0.2.0, latest, etc.) contains chart packages - -2. **Index File (index.yaml)**: Stored in curvine-doc repository - - URL: `https://curvineio.github.io/curvine-doc/helm-charts/index.yaml` - - Contains metadata for all chart versions - - URLs point to GitHub Releases for downloads - -3. **main Branch**: Clean source code only - - No build artifacts - - No gh-pages branch needed +Published charts: -## Development +| Source Directory | Published Chart Name | Purpose | +| --- | --- | --- | +| `curvine-runtime/` | `curvine` | Curvine runtime cluster | +| `curvine-csi/` | `curvine-csi` | Curvine CSI driver | -### Building Charts Locally - -```bash -# Lint a chart -cd curvine-csi -helm lint . - -# Package a chart -helm package curvine-csi -``` - -### Automated Releases - -Charts are automatically built and published via GitHub Actions: +## Quick Start -#### 1. Testing (main branch) +Install a minimal runtime cluster: ```bash -git push origin main +helm upgrade --install curvine curvineio/curvine \ + -n curvine \ + --create-namespace ``` -**Result**: -- Builds fixed version `0.0.0-dev` (or similar) -- Updates GitHub Release "latest" (overwrites previous) -- Does NOT sync to curvine-doc by default -- Perfect for testing without polluting version history - -#### 2. Release (version tag) +Install the CSI driver: ```bash -git tag v0.1.0 -git push origin v0.1.0 +helm upgrade --install curvine-csi curvineio/curvine-csi \ + -n curvine-system \ + --create-namespace ``` -**Result**: -- Builds version `0.1.0` -- Creates new GitHub Release `v0.1.0` -- Does NOT sync to curvine-doc automatically - -**To publish to curvine-doc**: -- Use manual workflow trigger -- Select the tag -- Check "Sync to curvine-doc" - -#### 3. Manual Trigger +Install the CSI chart only after the Curvine runtime cluster is reachable and you are ready to create a `StorageClass`. -Go to GitHub Actions → "Build and Release Helm Chart" → "Run workflow" +Before you install the runtime chart, make sure one of these is true: -Options: -- **ref**: Branch or tag to build (e.g., `main`, `v0.1.0`) -- **Sync to curvine-doc**: Check this to update the public index +- Your cluster has a default `StorageClass` +- You pass explicit `storageClass` values +- You use a `hostPath`-based example on bare metal -**Use cases**: -- Test a specific branch without syncing -- Update production index after releasing a tag -- Re-sync index if needed +## Documentation -## Version Strategy +- Runtime chart: [curvine-runtime/README.md](./curvine-runtime/README.md) +- CSI chart: [curvine-csi/README.md](./curvine-csi/README.md) +- Release workflow: [.github/workflows/README.md](./.github/workflows/README.md) -| Trigger | Version Format | Example | Overwrites? | Syncs to curvine-doc? | -|---------|----------------|---------|-------------|-----------------------| -| main branch | `{base}-dev` | `0.0.0-dev` | Yes | No (manual only) | -| v* tag | `{tag without v}` | `0.1.0` | No | Manual only | -| Manual | Depends on ref | Varies | Depends | Optional (checkbox) | +## Repository Layout -## Chart Documentation - -- [Curvine CSI Documentation](./curvine-csi/README.md) -- [Curvine Runtime Documentation](./curvine-runtime/README.md) - -## Repository Structure - -``` +```text curvine-helm/ -├── .github/workflows/ # Automated CI/CD -│ └── release.yml -├── curvine-csi/ # CSI Driver chart source -│ ├── Chart.yaml -│ ├── values.yaml -│ └── templates/ -├── curvine-runtime/ # Runtime chart source -│ ├── Chart.yaml -│ ├── values.yaml -│ └── templates/ -└── README.md # This file +├── .github/workflows/ # Chart packaging and release workflow +├── curvine-runtime/ # Source for the published `curvine` chart +├── curvine-csi/ # Source for the published `curvine-csi` chart +└── README.md # Repository entrypoint ``` -**Note**: No `charts/` directory or `gh-pages` branch. All build artifacts are in GitHub Releases. +## Release Architecture -## How It Works +- This repository stores chart source code only. +- Chart packages are published to GitHub Releases. +- The public Helm index is served from `curvine-doc`. +- End users should install from `https://curvineio.github.io/curvine-doc/helm-charts`. -1. **Developer pushes code** (tag or main branch) -2. **GitHub Actions builds** charts and creates Release -3. **Manual trigger** (when ready to publish): - - Downloads current release's .tgz files - - Downloads existing index.yaml from curvine-doc - - Generates new index with `--merge` (updates same versions, adds new ones) - - URLs in index point to GitHub Releases - - Pushes updated index.yaml to curvine-doc -4. **Users install** from curvine-doc (index) + GitHub Releases (packages) +## Local Development -## Contributing +Lint and package from source directories: -Contributions are welcome! Please feel free to submit a Pull Request. +```bash +helm lint ./curvine-runtime +helm lint ./curvine-csi -## License +mkdir -p dist +helm package ./curvine-runtime --destination dist +helm package ./curvine-csi --destination dist +``` + +Install locally from source: -See [LICENSE](./LICENSE) file for details. +```bash +helm upgrade --install curvine ./curvine-runtime -n curvine --create-namespace +helm upgrade --install curvine-csi ./curvine-csi -n curvine-system --create-namespace +``` ## Links -- [Curvine Project](https://github.com/CurvineIO/curvine) -- [Helm Documentation](https://helm.sh/docs/) -- [Chart Repository Guide](https://helm.sh/docs/topics/chart_repository/) +- Curvine project: https://github.com/CurvineIO/curvine +- Helm documentation: https://helm.sh/docs/ diff --git a/charts/README.md b/charts/README.md deleted file mode 100644 index aab6531..0000000 --- a/charts/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# Curvine Helm Charts Repository - -This directory serves as the central storage for all Curvine Helm chart packages. - -## Available Charts - -- **curvine-csi**: CSI Driver for Curvine storage -- **curvine-runtime**: Curvine distributed multi-level cache system - -## Usage - -Add the Helm repository: - -```bash -helm repo add curvineio https://curvineio.github.io/curvine-helm/charts -helm repo update -``` - -Search available charts: - -```bash -helm search repo curvineio -``` - -Install charts: - -```bash -# Install Curvine Runtime -helm install curvine curvineio/curvine-runtime - -# Install Curvine CSI Driver -helm install curvine-csi curvineio/curvine-csi -``` - -## Architecture - -This repository uses a distributed architecture: - -- **Chart Packages (.tgz)**: Stored in this directory (`curvine-helm/charts/`) - - Served via GitHub Pages: `https://curvineio.github.io/curvine-helm/charts/` - -- **Index File (index.yaml)**: - - Generated in this directory - - Also synced to `curvine-doc/static/helm-charts/index.yaml` for redundancy - - Served via: `https://curvineio.github.io/curvine-doc/helm-charts/index.yaml` - -## Directory Structure - -``` -charts/ -├── README.md # This file -├── index.yaml # Helm repository index (auto-generated) -├── curvine-csi-*.tgz # CSI chart packages (all versions) -└── curvine-runtime-*.tgz # Runtime chart packages (all versions) -``` - -## Automated Updates - -This directory is automatically updated by GitHub Actions when a version tag (v*) is pushed. - -**Workflow:** -1. Developer pushes a version tag (e.g., `v0.1.0`) -2. GitHub Actions builds chart packages -3. Chart packages (.tgz) are stored in this directory -4. `index.yaml` is generated using `helm repo index` -5. `index.yaml` is synced to `curvine-doc` repository -6. Changes are committed with `[skip ci]` to prevent loops - -**DO NOT manually edit files in this directory.** - -All chart packages and the index.yaml are automatically generated and maintained by the CI/CD pipeline. - -## Source Code - -Chart source code is located in the repository root: -- `curvine-csi/` - CSI Driver chart source -- `curvine-runtime/` - Runtime chart source - -## More Information - -- [Curvine Documentation](https://github.com/CurvineIO/curvine) -- [Helm Documentation](https://helm.sh/docs/) - diff --git a/curvine-csi/Chart.yaml b/curvine-csi/Chart.yaml index 1689163..7a4fbc2 100644 --- a/curvine-csi/Chart.yaml +++ b/curvine-csi/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: curvine-csi description: A Helm chart for Curvine CSI Driver type: application -version: 0.0.0-latest +version: 0.2.0 appVersion: "latest" keywords: - storage @@ -14,4 +14,4 @@ sources: maintainers: - name: Barry Liu email: lzjqsdd@gmail.com - url: https://github.com/lzjqsdd \ No newline at end of file + url: https://github.com/lzjqsdd diff --git a/curvine-csi/README.md b/curvine-csi/README.md index f1b814a..5e4c169 100644 --- a/curvine-csi/README.md +++ b/curvine-csi/README.md @@ -1,102 +1,73 @@ -# Curvine CSI Driver Helm Chart +# Curvine CSI Helm Chart -This Helm chart deploys the Curvine CSI (Container Storage Interface) driver on a Kubernetes cluster. +Helm chart for deploying the Curvine CSI driver. + +## Naming + +- Source directory: `curvine-csi/` +- Published chart name: `curvine-csi` +- Recommended release name: `curvine-csi` +- Recommended namespace: `curvine-system` ## Prerequisites - Kubernetes 1.19+ -- Helm 3.0+ +- Helm 3.x +- A reachable Curvine runtime cluster +- Privileged node Pods and required kubelet host paths must be allowed -## Installation +The chart includes `values.schema.json` so invalid values can be rejected before rendering. -### Add Helm Repository (if available) +## Install + +### From The Public Helm Repository ```bash -helm repo add curvine https://curvineio.github.io/helm-charts +helm repo add curvineio https://curvineio.github.io/curvine-doc/helm-charts helm repo update + +helm upgrade --install curvine-csi curvineio/curvine-csi \ + --namespace curvine-system \ + --create-namespace ``` -### Install from Local Chart +### From Local Source ```bash -# Install with default values (uses default namespace or current context namespace) -helm install curvine-csi ./curvine-csi - -# Install with custom values -helm install curvine-csi ./curvine-csi -f custom-values.yaml - -# Install in specific namespace -helm install curvine-csi ./curvine-csi --namespace curvine-system --create-namespace +helm upgrade --install curvine-csi ./curvine-csi \ + --namespace curvine-system \ + --create-namespace ``` -## Configuration - -The following table lists the configurable parameters and their default values: - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `image.repository` | Curvine CSI image repository | `ghcr.io/curvineio/curvine-csi` | -| `image.tag` | Curvine CSI image tag | `latest` | -| `image.pullPolicy` | Image pull policy | `Always` | -| `csiDriver.name` | CSI driver name | `curvine` | -| `csiDriver.attachRequired` | Whether attach is required | `false` | -| `csiDriver.podInfoOnMount` | Whether pod info on mount | `false` | -| `controller.name` | Controller deployment name | `curvine-csi-controller` | -| `controller.replicas` | Number of controller replicas | `1` | -| `controller.priorityClassName` | Priority class for controller | `system-cluster-critical` | -| `node.name` | Node DaemonSet name | `curvine-csi-node` | -| `node.priorityClassName` | Priority class for node | `system-node-critical` | -| `node.dnsPolicy` | DNS policy for node | `ClusterFirstWithHostNet` | -| `node.fuseDebugEnabled` | Enable FUSE debug mode | `false` | -| `rbac.create` | Create RBAC resources | `true` | -| `serviceAccount.controller.name` | Controller service account name | `curvine-csi-controller-sa` | -| `serviceAccount.node.name` | Node service account name | `curvine-csi-node-sa` | - -**Note:** The chart uses `.Release.Namespace` internally, so resources will be deployed to the namespace specified by the `--namespace` flag during installation. +## Configuration Notes -## Customization +- Service account names are derived from the release name by default. +- You can override them with: + - `serviceAccount.controller.name` + - `serviceAccount.node.name` +- Standalone mount mode is enabled by default through `node.mountMode=standalone`. -### Custom Images +## Core Values -```yaml -image: - repository: ghcr.io/your-org/curvine-csi - tag: v0.1.0 - pullPolicy: IfNotPresent - -controller: - sidecars: - provisioner: - image: quay.io/k8scsi/csi-provisioner:v1.6.0 - attacher: - image: registry.k8s.io/sig-storage/csi-attacher:v4.5.0 - livenessProbe: - image: registry.k8s.io/sig-storage/livenessprobe:v2.11.0 - -node: - sidecars: - nodeDriverRegistrar: - image: quay.io/k8scsi/csi-node-driver-registrar:v2.1.0 - livenessProbe: - image: registry.k8s.io/sig-storage/livenessprobe:v2.11.0 -``` +| Key | Description | Default | +| --- | --- | --- | +| `image.repository` | CSI image repository | `ghcr.io/curvineio/curvine-csi` | +| `image.tag` | CSI image tag | `latest` | +| `csiDriver.name` | CSI driver name | `curvine` | +| `controller.replicas` | Controller replica count | `1` | +| `node.mountMode` | FUSE mount strategy | `standalone` | +| `node.priorityClassName` | Node DaemonSet priority class | `system-node-critical` | +| `rbac.create` | Create service accounts, cluster roles, and bindings | `true` | -### Node Tolerations +For the full values surface, inspect: -```yaml -node: - tolerations: - - key: "node-role.kubernetes.io/master" - operator: "Exists" - effect: "NoSchedule" - - key: "node-role.kubernetes.io/control-plane" - operator: "Exists" - effect: "NoSchedule" +```bash +helm show values curvineio/curvine-csi ``` -## Usage +## StorageClass Example -After installation, create a StorageClass with Curvine cluster configuration: +Create a StorageClass after the runtime cluster is available. ```yaml apiVersion: storage.k8s.io/v1 @@ -108,32 +79,14 @@ reclaimPolicy: Delete volumeBindingMode: Immediate allowVolumeExpansion: true parameters: - # Required: Curvine cluster connection information - master-addrs: "master1:8995,master2:8995,master3:8995" - - # Required: Filesystem path prefix for dynamic PV - # Each dynamic PV will create: fs-path + pv-name + master-addrs: "curvine-master-0.curvine-master.curvine.svc.cluster.local:8995" fs-path: "/data" - - # Optional: Path creation strategy - path-type: "DirectoryOrCreate" # "DirectoryOrCreate" or "Directory" - - # Optional: FUSE parameters - # io-threads: "4" - # worker-threads: "8" + path-type: "DirectoryOrCreate" ``` -### StorageClass Parameters - -| Parameter | Required | Description | Default | -|-----------|----------|-------------|---------| -| `master-addrs` | Yes | Curvine master node addresses, format: `host:port,host:port` | - | -| `fs-path` | Yes | Filesystem path prefix for PV. Each PV creates `fs-path + pv-name` | - | -| `path-type` | No | Path creation strategy: `DirectoryOrCreate` or `Directory` | `Directory` | -| `io-threads` | No | FUSE IO threads count | - | -| `worker-threads` | No | FUSE worker threads count | - | +If your runtime cluster has multiple masters, add them as a comma-separated list in `master-addrs`. -### Create a PersistentVolumeClaim +## PVC Example ```yaml apiVersion: v1 @@ -149,106 +102,40 @@ spec: storageClassName: curvine-sc ``` -### Use PVC in a Pod +## Verify -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: test-pod -spec: - containers: - - name: app - image: nginx - volumeMounts: - - mountPath: /data - name: curvine-volume - volumes: - - name: curvine-volume - persistentVolumeClaim: - claimName: test-pvc +```bash +kubectl get csidriver curvine +kubectl get deployment -n curvine-system -l app.kubernetes.io/instance=curvine-csi,app.kubernetes.io/component=controller +kubectl get daemonset -n curvine-system -l app.kubernetes.io/instance=curvine-csi,app.kubernetes.io/component=node +kubectl get pods -n curvine-system -l app.kubernetes.io/instance=curvine-csi ``` -## Uninstallation +To inspect RBAC and service accounts created by the chart: ```bash -# Uninstall the release (replace with your installation namespace) -helm uninstall curvine-csi --namespace - -# Example: if installed in curvine-system namespace -helm uninstall curvine-csi --namespace curvine-system - -# Optionally, delete the namespace -kubectl delete namespace +kubectl get sa -n curvine-system -l app.kubernetes.io/instance=curvine-csi +kubectl get clusterrole,clusterrolebinding -l app.kubernetes.io/instance=curvine-csi ``` -## Troubleshooting - -### Check CSI Driver Status +## Logs ```bash -# Check CSI driver registration -kubectl get csidriver curvine - -# Check controller pod (replace with your installation namespace) -kubectl get deployment -n curvine-csi-controller -kubectl get pods -n -l app=curvine-csi-controller - -# Check node pods -kubectl get daemonset -n curvine-csi-node -kubectl get pods -n -l app=curvine-csi-node +kubectl logs -n curvine-system -l app=curvine-csi-controller -c csi-plugin +kubectl logs -n curvine-system -l app=curvine-csi-controller -c csi-provisioner +kubectl logs -n curvine-system -l app=curvine-csi-node -c csi-plugin +kubectl logs -n curvine-system -l app=curvine-csi-node -c node-driver-registrar ``` -### Check Logs +## Uninstall ```bash -# Controller logs (replace with your installation namespace) -kubectl logs -n -l app=curvine-csi-controller -c csi-plugin - -# Node logs -kubectl logs -n -l app=curvine-csi-node -c csi-plugin - -# Check specific sidecar logs -kubectl logs -n -l app=curvine-csi-controller -c csi-provisioner -kubectl logs -n -l app=curvine-csi-controller -c csi-attacher -kubectl logs -n -l app=curvine-csi-node -c node-driver-registrar +helm uninstall curvine-csi --namespace curvine-system ``` -### Common Issues - -1. **CSI Driver not registered** - - Check if the node-driver-registrar sidecar is running - - Verify `/var/lib/kubelet/plugins_registry/` is accessible - ```bash - kubectl logs -n -l app=curvine-csi-node -c node-driver-registrar - ``` - -2. **Mount failures** - - Verify Curvine cluster connectivity by checking master-addrs in StorageClass - - Ensure the fs-path exists and is accessible - - Check FUSE mount status on the node - ```bash - kubectl logs -n -l app=curvine-csi-node -c csi-plugin - ``` - -3. **Permission issues** - - Ensure proper RBAC permissions are granted - - Verify ServiceAccounts are created correctly - ```bash - kubectl get clusterrole curvine-csi-controller-sa - kubectl get clusterrole curvine-csi-node-sa - ``` - -4. **Volume provisioning stuck** - - Check controller pod status and logs - - Verify StorageClass parameters (master-addrs, fs-path) - ```bash - kubectl describe pvc - kubectl logs -n -l app=curvine-csi-controller -c csi-provisioner - ``` +Delete the namespace only if no other resources still depend on it. ## Support -For support and documentation, visit: -- [Curvine Documentation](https://curvineio.github.io/docs/) -- [GitHub Issues](https://github.com/CurvineIO/curvine/issues) \ No newline at end of file +- Curvine project: https://github.com/CurvineIO/curvine +- Helm repo index: https://curvineio.github.io/curvine-doc/helm-charts/index.yaml diff --git a/curvine-csi/templates/NOTES.txt b/curvine-csi/templates/NOTES.txt index 5950657..caa6737 100644 --- a/curvine-csi/templates/NOTES.txt +++ b/curvine-csi/templates/NOTES.txt @@ -1,34 +1,18 @@ -1. Curvine CSI Driver has been successfully installed! +Curvine CSI has been installed. -2. Check the status of Curvine CSI Driver: - kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "curvine-csi.name" . }} +Release: + Name: {{ .Release.Name }} + Namespace: {{ .Release.Namespace }} + CSI Driver: {{ .Values.csiDriver.name }} -3. Check CSI Driver registration: - kubectl get csidriver {{ .Values.csiDriver.name }} +Verify the release: + kubectl get csidriver {{ .Values.csiDriver.name }} + kubectl get deployment -n {{ .Release.Namespace }} {{ .Values.controller.name }} + kubectl get daemonset -n {{ .Release.Namespace }} {{ .Values.node.name }} + kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} -4. Create a StorageClass to use Curvine CSI: - kubectl apply -f - <curvine-config
Contains: cluster config, master addrs, journal addrs"] - SA["ServiceAccount
curvine
For pod identity"] - RBAC["RBAC
Role + RoleBinding
Permissions: pods, configmaps, services, statefulsets"] - end - - subgraph MasterTier[" "] - direction TB - - MS["Master Service
Type: ClusterIP None - Headless
publishNotReadyAddresses: true
━━━━━━━━━━━━━━━━━━━━
Port 8995: RPC
Port 8996: Journal/Raft
Port 9000: Web UI
Port 9001: Web1"] - - M0["master-0
━━━━━━━━━━━━━━━━━━━━
RPC: 8995
Journal/Raft: 8996
Web: 9000/9001
━━━━━━━━━━━━━━━━━━━━
Role: Metadata Mgmt
Raft Node ID: 1"] - M1["master-1
━━━━━━━━━━━━━━━━━━━━
RPC: 8995
Journal/Raft: 8996
Web: 9000/9001
━━━━━━━━━━━━━━━━━━━━
Role: Metadata Mgmt
Raft Node ID: 2"] - M2["master-2
━━━━━━━━━━━━━━━━━━━━
RPC: 8995
Journal/Raft: 8996
Web: 9000/9001
━━━━━━━━━━━━━━━━━━━━
Role: Metadata Mgmt
Raft Node ID: 3"] - - PVC_M0["PVC: meta
Size: 10Gi
━━━━━━━━
PVC: journal
Size: 50Gi"] - PVC_M1["PVC: meta
Size: 10Gi
━━━━━━━━
PVC: journal
Size: 50Gi"] - PVC_M2["PVC: meta
Size: 10Gi
━━━━━━━━
PVC: journal
Size: 50Gi"] - end - - subgraph WorkerTier[" "] - direction TB - - WS["Worker Service
Type: ClusterIP None - Headless
publishNotReadyAddresses: true
━━━━━━━━━━━━━━━━━━━━
Port 8997: RPC
Port 9001: Web UI"] - - W0["worker-0
━━━━━━━━━━━━━━━━━━━━
RPC: 8997
Web: 9001
━━━━━━━━━━━━━━━━━━━━
Role: Data Storage
Privileged: true
Anti-Affinity: enabled"] - W1["worker-1
━━━━━━━━━━━━━━━━━━━━
RPC: 8997
Web: 9001
━━━━━━━━━━━━━━━━━━━━
Role: Data Storage
Privileged: true
Anti-Affinity: enabled"] - W2["worker-2
━━━━━━━━━━━━━━━━━━━━
RPC: 8997
Web: 9001
━━━━━━━━━━━━━━━━━━━━
Role: Data Storage
Privileged: true
Anti-Affinity: enabled"] - - PVC_W0["PVC: data1
Type: SSD
Size: 10Gi
Mount: /data/data1"] - PVC_W1["PVC: data1
Type: SSD
Size: 10Gi
Mount: /data/data1"] - PVC_W2["PVC: data1
Type: SSD
Size: 10Gi
Mount: /data/data1"] - end - end - - MS -.DNS Resolution.-> M0 - MS -.DNS Resolution.-> M1 - MS -.DNS Resolution.-> M2 - - WS -.DNS Resolution.-> W0 - WS -.DNS Resolution.-> W1 - WS -.DNS Resolution.-> W2 - - M0 <-->|Raft Consensus
Port 8996| M1 - M1 <-->|Raft Consensus
Port 8996| M2 - M2 <-->|Raft Consensus
Port 8996| M0 - - M0 -->|Manage Workers
RPC Port 8997| W0 - M0 -->|Manage Workers
RPC Port 8997| W1 - M0 -->|Manage Workers
RPC Port 8997| W2 - M1 -.Backup Management.-> W0 - M1 -.Backup Management.-> W1 - M1 -.Backup Management.-> W2 - - M0 -.Mount.-> PVC_M0 - M1 -.Mount.-> PVC_M1 - M2 -.Mount.-> PVC_M2 - - W0 -.Mount.-> PVC_W0 - W1 -.Mount.-> PVC_W1 - W2 -.Mount.-> PVC_W2 - - CM -.Config Mounted
/app/curvine/conf/.-> M0 - CM -.Config Mounted
/app/curvine/conf/.-> M1 - CM -.Config Mounted
/app/curvine/conf/.-> M2 - CM -.Config Mounted
/app/curvine/conf/.-> W0 - CM -.Config Mounted
/app/curvine/conf/.-> W1 - CM -.Config Mounted
/app/curvine/conf/.-> W2 - - SA -.Identity.-> M0 - SA -.Identity.-> M1 - SA -.Identity.-> M2 - SA -.Identity.-> W0 - SA -.Identity.-> W1 - SA -.Identity.-> W2 - - Client -->|Access Master
RPC Port 8995| MS - Client -->|Access Worker
RPC Port 8997| WS - Admin -->|Web UI
Port 9000| MS - Admin -->|Worker Monitor
Port 9001| WS - - style MS fill:#2196F3,stroke:#1976D2,stroke-width:3px,color:#fff - style WS fill:#2196F3,stroke:#1976D2,stroke-width:3px,color:#fff - style M0 fill:#4CAF50,stroke:#388E3C,stroke-width:2px,color:#fff - style M1 fill:#4CAF50,stroke:#388E3C,stroke-width:2px,color:#fff - style M2 fill:#4CAF50,stroke:#388E3C,stroke-width:2px,color:#fff - style W0 fill:#FF9800,stroke:#F57C00,stroke-width:2px,color:#fff - style W1 fill:#FF9800,stroke:#F57C00,stroke-width:2px,color:#fff - style W2 fill:#FF9800,stroke:#F57C00,stroke-width:2px,color:#fff - style Client fill:#9E9E9E,stroke:#616161,stroke-width:2px,color:#fff - style Admin fill:#9E9E9E,stroke:#616161,stroke-width:2px,color:#fff - style CM fill:#673AB7,stroke:#512DA8,stroke-width:2px,color:#fff - style SA fill:#673AB7,stroke:#512DA8,stroke-width:2px,color:#fff - style RBAC fill:#673AB7,stroke:#512DA8,stroke-width:2px,color:#fff - style PVC_M0 fill:#795548,stroke:#5D4037,stroke-width:2px,color:#fff - style PVC_M1 fill:#795548,stroke:#5D4037,stroke-width:2px,color:#fff - style PVC_M2 fill:#795548,stroke:#5D4037,stroke-width:2px,color:#fff - style PVC_W0 fill:#795548,stroke:#5D4037,stroke-width:2px,color:#fff - style PVC_W1 fill:#795548,stroke:#5D4037,stroke-width:2px,color:#fff - style PVC_W2 fill:#795548,stroke:#5D4037,stroke-width:2px,color:#fff -``` +# Curvine Runtime Helm Chart -### Key Components - -#### Master Nodes -- **Role**: Metadata management, cluster coordination, Raft consensus -- **Service**: Headless Service for stable DNS names -- **Ports**: - - `8995`: RPC for client/worker communication - - `8996`: Journal/Raft for consensus protocol - - `9000`: Web UI for cluster management - - `9001`: Additional web port -- **Storage**: Persistent volumes for metadata and journal data -- **HA**: Odd-numbered replicas (1, 3, 5...) for Raft quorum - -#### Worker Nodes -- **Role**: Data storage and processing -- **Service**: Headless Service for stable DNS names -- **Ports**: - - `8997`: RPC for data operations - - `9001`: Web UI for worker monitoring -- **Storage**: Persistent volumes for data storage (supports multiple data directories) -- **Scaling**: Horizontal scaling without downtime -- **Security**: Privileged mode for FUSE filesystem support - -#### Supporting Resources -- **ConfigMap**: Centralized configuration for all nodes -- **ServiceAccount**: Identity for pods to access Kubernetes API -- **RBAC**: Role-based access control for service account permissions -- **Anti-Affinity**: Spreads worker pods across nodes for high availability - -## Prerequisites +Helm chart for deploying a Curvine runtime cluster on Kubernetes. -- Kubernetes 1.20+ -- Helm 3.0+ -- PV provisioner (if using PVC storage) +## Naming -## Quick Start +- Source directory: `curvine-runtime/` +- Published chart name: `curvine` +- Recommended release name: `curvine` +- Recommended namespace: `curvine` -### 1. Add Helm Repository (Optional) +When installing from a Helm repository, use `curvineio/curvine`. When installing from this repository, use `./curvine-runtime`. -```bash -# If the chart is published to a repository -helm repo add curvine https://curvineio.github.io/helm/charts -helm repo update -``` +## Before You Install -### 2. Install the Chart +Confirm these prerequisites first: -#### Option A: From Helm Repository (Recommended) +- Kubernetes 1.20+ +- Helm 3.x +- One of these storage options: + - a default `StorageClass` + - explicit `storageClass` values in your values file + - `hostPath` storage on bare metal +- Enough cluster capacity for the requested CPU and memory +- If you use the production or bare-metal examples: + - node labels already exist + - required taints are tolerated + - privileged Pods and `hostNetwork` are allowed when applicable -```bash -# Install with default configuration -helm install curvine curvine/curvine -n curvine --create-namespace +The chart defaults are intentionally conservative so a first deployment is less likely to end in `Pending`. +The chart also includes `values.schema.json` so invalid values can be rejected before rendering. -# Install with custom replica counts -helm install curvine curvine/curvine -n curvine --create-namespace \ - --set master.replicas=5 \ - --set worker.replicas=10 +## Install -# Install using a custom values file -helm install curvine curvine/curvine -n curvine --create-namespace \ - -f https://curvineio.github.io/helm/charts/examples/values-prod.yaml -``` - -#### Option B: From Local Chart +### From The Public Helm Repository ```bash -# Install with default configuration -helm install curvine ./curvine -n curvine --create-namespace - -# Install with custom replica counts -helm install curvine ./curvine -n curvine --create-namespace \ - --set master.replicas=5 \ - --set worker.replicas=10 +helm repo add curvineio https://curvineio.github.io/curvine-doc/helm-charts +helm repo update -# Install using a custom values file -helm install curvine ./curvine -n curvine --create-namespace \ - -f examples/values-prod.yaml +helm upgrade --install curvine curvineio/curvine \ + -n curvine \ + --create-namespace ``` -### 3. Verify Deployment +### From Local Source ```bash -# Check Pod status -kubectl get pods -n curvine - -# View Services -kubectl get svc -n curvine - -# View PersistentVolumeClaims -kubectl get pvc -n curvine - -# Run Helm tests -helm test curvine -n curvine +helm upgrade --install curvine ./curvine-runtime \ + -n curvine \ + --create-namespace ``` -### 4. Access the Cluster +### With Example Values -```bash -# Port-forward to access Master Web UI -kubectl port-forward -n curvine svc/curvine-master 9000:9000 +Development: -# Visit http://localhost:9000 +```bash +helm upgrade --install curvine ./curvine-runtime \ + -n curvine \ + --create-namespace \ + -f ./curvine-runtime/examples/values-dev.yaml ``` -## Configuration - -### Core Parameters - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `cluster.id` | Cluster identifier | `curvine` | -| `master.replicas` | Number of Master replicas (must be odd) | `3` | -| `worker.replicas` | Number of Worker replicas | `3` | -| `image.repository` | Container image repository | `docker.io/curvine` | -| `image.tag` | Container image tag | `latest` | - -### Master Configuration - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `master.rpcPort` | RPC port | `8995` | -| `master.journalPort` | Journal/Raft port | `8996` | -| `master.webPort` | Web UI port | `9000` | -| `master.storage.meta.storageClass` | Storage class for metadata | `""` (default) | -| `master.storage.meta.size` | Metadata storage size | `10Gi` | -| `master.storage.journal.storageClass` | Storage class for journal | `""` (default) | -| `master.storage.journal.size` | Journal storage size | `50Gi` | - -### Worker Configuration - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `worker.rpcPort` | RPC port | `8997` | -| `worker.webPort` | Web UI port | `9001` | -| `worker.hostNetwork` | Use host network | `false` | -| `worker.privileged` | Privileged mode (required for FUSE) | `true` | -| `worker.s3Gateway.enabled` | Enable S3 gateway on workers | `false` | -| `worker.s3Gateway.listen` | Listen address for S3 gateway | `0.0.0.0:9900` | -| `worker.s3Gateway.service.type` | Service type for S3 gateway (ClusterIP/LoadBalancer/NodePort) | `ClusterIP` | -| `worker.antiAffinity.enabled` | Enable Pod anti-affinity | `true` | -| `worker.antiAffinity.type` | Anti-affinity type | `preferred` | - -For a complete list of parameters, see `values.yaml`. - -### View Current Configuration +Production: ```bash -# View all current values -helm get values curvine -n curvine - -# View values from a specific release -helm get values curvine -n curvine -o yaml - -# View the rendered manifest -helm get manifest curvine -n curvine - -# View the values.yaml from the chart -cat ./curvine/values.yaml - -# View specific parameter -helm get values curvine -n curvine | grep master.replicas +helm upgrade --install curvine ./curvine-runtime \ + -n curvine \ + --create-namespace \ + -f ./curvine-runtime/examples/values-prod.yaml ``` -## Configuration Examples - -### Development Environment (Minimal) +Bare metal: ```bash -# From Helm Repository -helm install curvine curvine/curvine -n curvine --create-namespace \ - --set master.replicas=1 \ - --set worker.replicas=1 - -# From Local Chart -helm install curvine ./curvine -n curvine --create-namespace \ - -f examples/values-dev.yaml +helm upgrade --install curvine ./curvine-runtime \ + -n curvine \ + --create-namespace \ + -f ./curvine-runtime/examples/values-baremetal.yaml ``` -### Production Environment (High Availability) +Do not use the production or bare-metal examples unchanged on a generic cluster. Edit storage classes, labels, and paths first. -```bash -# From Helm Repository -helm install curvine curvine/curvine -n curvine --create-namespace \ - --set master.replicas=5 \ - --set worker.replicas=10 \ - --set master.storage.meta.storageClass=fast-ssd \ - --set master.storage.journal.storageClass=fast-ssd - -# From Local Chart -helm install curvine ./curvine -n curvine --create-namespace \ - -f examples/values-prod.yaml -``` +## Verify -### Bare Metal Environment (Using hostPath) +Run these commands immediately after install or upgrade: ```bash -# From Local Chart -helm install curvine ./curvine -n curvine --create-namespace \ - -f examples/values-baremetal.yaml +helm status curvine -n curvine +kubectl get statefulset,pod,pvc -n curvine +kubectl get events -n curvine --sort-by='.lastTimestamp' ``` -### Custom Configuration +Access the master web UI: ```bash -# From Helm Repository -helm install curvine curvine/curvine -n curvine --create-namespace \ - --set master.replicas=5 \ - --set worker.replicas=10 \ - --set master.storage.meta.storageClass=fast-ssd \ - --set worker.storage.dataDirs[0].storageClass=fast-ssd \ - --set worker.storage.dataDirs[0].size=500Gi - -# From Local Chart -helm install curvine ./curvine -n curvine --create-namespace \ - --set master.replicas=5 \ - --set worker.replicas=10 \ - --set master.storage.meta.storageClass=fast-ssd \ - --set worker.storage.dataDirs[0].storageClass=fast-ssd \ - --set worker.storage.dataDirs[0].size=500Gi +kubectl port-forward -n curvine svc/curvine-master 9000:9000 ``` -## Storage Configuration - -### Using PVC (Recommended for Cloud) - -```yaml -master: - storage: - meta: - storageClass: "fast-ssd" - size: "20Gi" - journal: - storageClass: "fast-ssd" - size: "100Gi" - -worker: - storage: - dataDirs: - - name: "data1" - type: "SSD" - enabled: true - size: "100Gi" - storageClass: "fast-ssd" - mountPath: "/data/data1" -``` +## Standard Operator Workflows -### Using hostPath (Recommended for Bare Metal) - -```yaml -master: - storage: - meta: - storageClass: "" - hostPath: "/mnt/curvine/master/meta" - journal: - storageClass: "" - hostPath: "/mnt/curvine/master/journal" - -worker: - storage: - dataDirs: - - name: "data1" - type: "SSD" - enabled: true - size: "100Gi" - storageClass: "" - hostPath: "/mnt/nvme0n1/curvine" - mountPath: "/data/data1" -``` +### Upgrade In Place -### Using emptyDir (For Testing) - -```yaml -master: - storage: - meta: - storageClass: "" - hostPath: "" - journal: - storageClass: "" - hostPath: "" - -worker: - storage: - dataDirs: - - name: "data1" - storageClass: "" - hostPath: "" +```bash +helm upgrade --install curvine curvineio/curvine \ + -n curvine \ + -f values.yaml ``` -## Upgrading +Use this flow for: -### Update Configuration +- image changes +- resource tuning +- worker replica changes +- config changes -```bash -# Scale Worker replicas (From Helm Repository) -helm upgrade curvine curvine/curvine -n curvine \ - --set worker.replicas=15 +Do not change `master.replicas` during an in-place upgrade. -# Upgrade image version (From Helm Repository) -helm upgrade curvine curvine/curvine -n curvine \ - --set image.tag=v1.1.0 +### Roll Back -# Upgrade using a new values file (From Local Chart) -helm upgrade curvine ./curvine -n curvine \ - -f values-new.yaml +```bash +helm history curvine -n curvine +helm rollback curvine -n curvine ``` -> **Note**: Master replicas cannot be changed during upgrade. To modify Master replicas, delete and redeploy the cluster. +### Re-Deploy While Preserving Data -### View Release History +This path keeps StatefulSet PVCs: ```bash -helm history curvine -n curvine +helm uninstall curvine -n curvine + +helm upgrade --install curvine curvineio/curvine \ + -n curvine \ + --create-namespace \ + -f values.yaml ``` -### Rollback +Rules: -```bash -# Rollback to previous version -helm rollback curvine -n curvine +- reuse the same release name +- reuse the same namespace +- do not delete PVCs -# Rollback to specific version -helm rollback curvine 2 -n curvine -``` +If old PVCs were already unresolved, the re-deployed Pods may remain `Pending` for the same reason. + +### Destroy And Rebuild -## Uninstall +This path deletes data: ```bash -# Uninstall Chart (preserves PVCs) helm uninstall curvine -n curvine - -# Delete PersistentVolumeClaims kubectl delete pvc -n curvine -l app.kubernetes.io/instance=curvine - -# Delete namespace kubectl delete namespace curvine ``` -## Troubleshooting +Use this only when data loss is acceptable. + +## Values And Examples -### Check Pod Status +Inspect current defaults: ```bash -kubectl get pods -n curvine -kubectl describe pod -n curvine -kubectl logs -n curvine +helm show values curvineio/curvine ``` -### View ConfigMap +Or locally: ```bash -kubectl get configmap -n curvine -kubectl describe configmap curvine-config -n curvine +sed -n '1,220p' ./curvine-runtime/values.yaml ``` -### View Events +Included example files: + +- `examples/values-dev.yaml` +- `examples/values-prod.yaml` +- `examples/values-baremetal.yaml` + +## Troubleshooting + +If a Pod is `Pending`, start with: ```bash +kubectl describe pod -n curvine +kubectl describe pvc -n curvine +kubectl get storageclass +kubectl get nodes --show-labels kubectl get events -n curvine --sort-by='.lastTimestamp' ``` -### Common Issues - -1. **Master Replica Validation Failed** - - Error: `master.replicas must be an odd number` - - Solution: Ensure Master replicas is odd (1, 3, 5, 7...) - -2. **PVC Cannot Bind** - - Check if StorageClass exists - - Verify PV provisioner is working correctly +## Important Behavior Notes -3. **Pod Fails to Start** - - Verify container image exists - - Check resource quotas are sufficient - - Review Pod logs for details +- `helm uninstall` removes workloads but leaves StatefulSet PVCs behind +- `master.replicas` must stay stable across in-place upgrades +- Logs are often not useful for `Pending` Pods because containers may never start ## Support -For issues, questions, or contributions, please visit: -- GitHub: https://github.com/CurvineIO/curvine -- Documentation: https://curvineio.github.io/ +- Curvine project: https://github.com/CurvineIO/curvine +- Helm repo index: https://curvineio.github.io/curvine-doc/helm-charts/index.yaml diff --git a/curvine-runtime/examples/values-baremetal.yaml b/curvine-runtime/examples/values-baremetal.yaml index 9de53bb..a5f5da0 100644 --- a/curvine-runtime/examples/values-baremetal.yaml +++ b/curvine-runtime/examples/values-baremetal.yaml @@ -1,33 +1,31 @@ # Bare-metal environment configuration -# Using hostPath for local disk access +# Edit this file before use. +# Requirements: +# - Each hostPath must exist on every target node or be creatable by kubelet. +# - Nodes must already be labeled with the selectors below. +# - Privileged Pods and host networking must be allowed. cluster: id: "curvine-baremetal" -image: - repository: docker.io/curvine/curvine - tag: "v1.0.0" - pullPolicy: IfNotPresent - -# 3 masters using hostPath master: replicas: 3 - + storage: meta: enabled: true - storageClass: "" # Empty means use hostPath + storageClass: "" # Empty means hostPath is used size: "20Gi" - hostPath: "/mnt/curvine/master/meta" # Local disk path + hostPath: "/mnt/curvine/master/meta" # Replace with a real path on each master node mountPath: "/opt/curvine/data/meta" - + journal: enabled: true storageClass: "" size: "100Gi" - hostPath: "/mnt/curvine/master/journal" + hostPath: "/mnt/curvine/master/journal" # Replace with a real path on each master node mountPath: "/opt/curvine/data/journal" - + resources: requests: cpu: "2000m" @@ -35,19 +33,18 @@ master: limits: cpu: "4000m" memory: "8Gi" - - # Pin to specific nodes + + # Replace these labels with labels that already exist on your master nodes. nodeSelector: curvine-role: "master" -# 5 workers using local NVMe disks worker: replicas: 5 - - hostNetwork: true # Use host network for better performance + + hostNetwork: true dnsPolicy: "ClusterFirstWithHostNet" privileged: true - + storage: dataDirs: - name: "data1" @@ -55,17 +52,17 @@ worker: enabled: true size: "500Gi" storageClass: "" - hostPath: "/mnt/nvme0n1/curvine" # Local NVMe disk + hostPath: "/mnt/nvme0n1/curvine" # Replace with a real path on each worker node mountPath: "/data/data1" - + - name: "data2" type: "SSD" enabled: true size: "500Gi" storageClass: "" - hostPath: "/mnt/nvme1n1/curvine" # Second NVMe disk + hostPath: "/mnt/nvme1n1/curvine" # Replace with a real path on each worker node mountPath: "/data/data2" - + resources: requests: cpu: "4000m" @@ -73,15 +70,14 @@ worker: limits: cpu: "8000m" memory: "16Gi" - - # Pin to specific worker nodes + + # Replace these labels with labels that already exist on your worker nodes. nodeSelector: curvine-role: "worker" - - # Required anti-affinity to spread across nodes + antiAffinity: enabled: true - type: "required" + type: "preferred" config: log: diff --git a/curvine-runtime/examples/values-dev.yaml b/curvine-runtime/examples/values-dev.yaml index e8b76c0..271c350 100644 --- a/curvine-runtime/examples/values-dev.yaml +++ b/curvine-runtime/examples/values-dev.yaml @@ -1,34 +1,29 @@ # Development environment configuration -# Minimal resources for local testing +# Intended for local validation and small non-production clusters. +# Relies on the chart's default image settings. cluster: id: "curvine-dev" -image: - repository: docker.io/curvine - tag: "latest" - pullPolicy: IfNotPresent - # Single master for development master: replicas: 1 - + storage: meta: enabled: true - storageClass: "" # Use default or emptyDir + storageClass: "" # Requires a default StorageClass when hostPath is empty size: "5Gi" hostPath: "" mountPath: "/opt/curvine/data/meta" - + journal: enabled: true - storageClass: "" + storageClass: "" # Requires a default StorageClass when hostPath is empty size: "10Gi" hostPath: "" mountPath: "/opt/curvine/data/journal" - - # Minimal resources for development + resources: requests: cpu: "500m" @@ -37,24 +32,22 @@ master: cpu: "1000m" memory: "2Gi" -# Single worker for development worker: replicas: 1 - + hostNetwork: false privileged: true - + storage: dataDirs: - name: "data1" type: "SSD" enabled: true size: "20Gi" - storageClass: "" + storageClass: "" # Requires a default StorageClass when hostPath is empty hostPath: "" mountPath: "/data/data1" - - # Minimal resources for development + resources: requests: cpu: "500m" @@ -62,8 +55,7 @@ worker: limits: cpu: "1000m" memory: "2Gi" - - # Disable anti-affinity for single node testing + antiAffinity: enabled: false diff --git a/curvine-runtime/examples/values-prod.yaml b/curvine-runtime/examples/values-prod.yaml index b6eeb65..40bf624 100644 --- a/curvine-runtime/examples/values-prod.yaml +++ b/curvine-runtime/examples/values-prod.yaml @@ -1,33 +1,29 @@ # Production environment configuration -# High availability and performance +# Edit this file before use. +# Requirements: +# - StorageClasses named below must already exist. +# - Node labels and taints must match your cluster. +# - Switch anti-affinity to `required` only after you have enough worker nodes. cluster: id: "curvine-prod" -image: - repository: docker.io/curvine/curvine - tag: "v1.0.0" - pullPolicy: Always - pullSecrets: [] - -# 5 masters for high availability master: replicas: 5 - + storage: meta: enabled: true - storageClass: "fast-ssd" # Use high-performance storage class + storageClass: "fast-ssd" # Replace with a real StorageClass in your cluster size: "50Gi" mountPath: "/opt/curvine/data/meta" - + journal: enabled: true - storageClass: "fast-ssd" + storageClass: "fast-ssd" # Replace with a real StorageClass in your cluster size: "200Gi" mountPath: "/opt/curvine/data/journal" - - # Production-grade resources + resources: requests: cpu: "2000m" @@ -35,45 +31,42 @@ master: limits: cpu: "4000m" memory: "8Gi" - - # Node selector for dedicated master nodes + + # Replace these labels with the dedicated control-plane labels in your cluster. nodeSelector: node-role.kubernetes.io/master: "true" - - # Tolerate master taints + tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" - + labels: tier: "control-plane" env: "production" -# 10 workers for production workload worker: replicas: 10 - + hostNetwork: false privileged: true - + storage: dataDirs: - name: "data1" type: "SSD" enabled: true size: "500Gi" - storageClass: "fast-ssd" + storageClass: "fast-ssd" # Replace with a real StorageClass in your cluster mountPath: "/data/data1" - + - name: "data2" type: "HDD" enabled: true size: "2Ti" - storageClass: "standard-hdd" + storageClass: "standard-hdd" # Replace with a real StorageClass in your cluster mountPath: "/data/data2" - - # Production-grade resources + resources: requests: cpu: "4000m" @@ -81,16 +74,15 @@ worker: limits: cpu: "8000m" memory: "16Gi" - - # Node selector for dedicated worker nodes + + # Replace these labels with the dedicated worker labels in your cluster. nodeSelector: node-role.kubernetes.io/worker: "true" - - # Strong anti-affinity for high availability + antiAffinity: enabled: true - type: "required" - + type: "preferred" + labels: tier: "data-plane" env: "production" diff --git a/curvine-runtime/templates/NOTES.txt b/curvine-runtime/templates/NOTES.txt index 6cd2a59..f47c3f9 100644 --- a/curvine-runtime/templates/NOTES.txt +++ b/curvine-runtime/templates/NOTES.txt @@ -1,65 +1,27 @@ -🎉 Curvine cluster has been deployed successfully! +Curvine runtime has been installed. -Cluster Information: --------------------- - Cluster ID: {{ .Values.cluster.id }} - Namespace: {{ .Release.Namespace }} - Master Replicas: {{ .Values.master.replicas }} - Worker Replicas: {{ .Values.worker.replicas }} +Release: + Name: {{ .Release.Name }} + Namespace: {{ .Release.Namespace }} + Cluster ID: {{ .Values.cluster.id }} -Master Nodes: -------------- -{{- range $i := until (int .Values.master.replicas) }} - - {{ include "curvine.masterFullname" $ }}-{{ $i }}.{{ include "curvine.masterServiceName" $ }}.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }} -{{- end }} +Verify the release: + helm status {{ .Release.Name }} -n {{ .Release.Namespace }} + kubectl get statefulset,pod,pvc -n {{ .Release.Namespace }} + kubectl get events -n {{ .Release.Namespace }} --sort-by='.lastTimestamp' -Service Endpoints: ------------------- - Master RPC: {{ include "curvine.masterServiceName" . }}:{{ .Values.master.rpcPort }} - Master Web: {{ include "curvine.masterServiceName" . }}:{{ .Values.master.webPort }} - Worker RPC: {{ include "curvine.workerFullname" . }}:{{ .Values.worker.rpcPort }} +If a Pod is Pending: + kubectl describe pod -n {{ .Release.Namespace }} + kubectl describe pvc -n {{ .Release.Namespace }} + kubectl get storageclass + kubectl get nodes --show-labels -Quick Commands: ---------------- -1. Check cluster status: - kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} +Access the master web UI: + kubectl port-forward -n {{ .Release.Namespace }} svc/{{ include "curvine.masterServiceName" . }} {{ .Values.master.webPort }}:{{ .Values.master.webPort }} -2. View master logs: - kubectl logs -n {{ .Release.Namespace }} {{ include "curvine.masterFullname" . }}-0 -f +Upgrade in place: + helm upgrade --install {{ .Release.Name }} -n {{ .Release.Namespace }} -f values.yaml -3. View worker logs: - kubectl logs -n {{ .Release.Namespace }} {{ include "curvine.workerFullname" . }}-0 -f - -4. Access master web UI (port-forward): - kubectl port-forward -n {{ .Release.Namespace }} {{ include "curvine.masterFullname" . }}-0 {{ .Values.master.webPort }}:{{ .Values.master.webPort }} - Then visit: http://localhost:{{ .Values.master.webPort }} - -5. Execute commands in master pod: - kubectl exec -it -n {{ .Release.Namespace }} {{ include "curvine.masterFullname" . }}-0 -- bash - -Management: ------------ - Upgrade: helm upgrade {{ .Release.Name }} curvine -n {{ .Release.Namespace }} - Rollback: helm rollback {{ .Release.Name }} -n {{ .Release.Namespace }} - Status: helm status {{ .Release.Name }} -n {{ .Release.Namespace }} - History: helm history {{ .Release.Name }} -n {{ .Release.Namespace }} - -Configuration: --------------- - ConfigMap: {{ include "curvine.fullname" . }}-config - - View current config: - kubectl get configmap -n {{ .Release.Namespace }} {{ include "curvine.fullname" . }}-config -o yaml - -{{- if .Values.master.storage.meta.storageClass }} - -Persistent Storage: -------------------- - Master meta storage: {{ .Values.master.storage.meta.storageClass }} ({{ .Values.master.storage.meta.size }}) - Master journal storage: {{ .Values.master.storage.journal.storageClass }} ({{ .Values.master.storage.journal.size }}) - - View PVCs: - kubectl get pvc -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} -{{- end }} - -For more information, visit: https://github.com/CurvineIO/curvine.git +Important: + - Reuse the same release name and namespace when re-deploying with existing PVCs + - Do not change master.replicas during an in-place upgrade diff --git a/curvine-runtime/templates/pre-upgrade-hook.yaml b/curvine-runtime/templates/pre-upgrade-hook.yaml deleted file mode 100644 index c0aef42..0000000 --- a/curvine-runtime/templates/pre-upgrade-hook.yaml +++ /dev/null @@ -1,57 +0,0 @@ -{{- if .Release.IsUpgrade }} -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ include "curvine.fullname" . }}-pre-upgrade-check - namespace: {{ .Release.Namespace }} - labels: - {{- include "curvine.labels" . | nindent 4 }} - app.kubernetes.io/component: pre-upgrade-check - annotations: - "helm.sh/hook": pre-upgrade - "helm.sh/hook-weight": "-5" - "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded -spec: - backoffLimit: 1 - template: - metadata: - labels: - {{- include "curvine.labels" . | nindent 8 }} - app.kubernetes.io/component: pre-upgrade-check - spec: - serviceAccountName: {{ include "curvine.serviceAccountName" . }} - restartPolicy: Never - automountServiceAccountToken: true - containers: - - name: pre-upgrade-check - image: bitnami/kubectl:latest - imagePullPolicy: IfNotPresent - command: - - /bin/sh - - -c - - | - set -e - - # Get current master replicas from the existing StatefulSet - # kubectl automatically uses the Service Account token mounted in the Pod - CURRENT_REPLICAS=$(kubectl get statefulset {{ include "curvine.masterFullname" . }} \ - -n {{ .Release.Namespace }} \ - -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "0") - - # Get new master replicas from the upgrade values - NEW_REPLICAS={{ .Values.master.replicas }} - - echo "Current Master Replicas: $CURRENT_REPLICAS" - echo "New Master Replicas: $NEW_REPLICAS" - - # Check if master replicas are being changed - if [ "$CURRENT_REPLICAS" != "0" ] && [ "$CURRENT_REPLICAS" != "$NEW_REPLICAS" ]; then - echo "ERROR: Master replicas cannot be changed during upgrade!" - echo "Current: $CURRENT_REPLICAS, Requested: $NEW_REPLICAS" - echo "To change master replicas, you must delete and redeploy the cluster." - exit 1 - fi - - echo "Pre-upgrade check passed: Master replicas are not being changed" - exit 0 -{{- end }} diff --git a/curvine-runtime/values.schema.json b/curvine-runtime/values.schema.json new file mode 100644 index 0000000..49efbd2 --- /dev/null +++ b/curvine-runtime/values.schema.json @@ -0,0 +1,446 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "global": { + "type": "object", + "properties": { + "clusterDomain": { + "type": "string", + "minLength": 1 + } + }, + "additionalProperties": true + }, + "cluster": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "formatMaster": { + "type": "boolean" + }, + "formatWorker": { + "type": "boolean" + }, + "formatJournal": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "minLength": 1 + }, + "tag": { + "type": "string", + "minLength": 1 + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + }, + "pullSecrets": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "additionalProperties": true + }, + "master": { + "type": "object", + "properties": { + "replicas": { + "type": "integer", + "minimum": 1 + }, + "rpcPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "journalPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "webPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "web1Port": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "storage": { + "type": "object", + "properties": { + "meta": { + "$ref": "#/definitions/storageDir" + }, + "journal": { + "$ref": "#/definitions/storageDir" + } + }, + "additionalProperties": true + }, + "resources": { + "$ref": "#/definitions/resources" + }, + "nodeSelector": { + "type": "object" + }, + "tolerations": { + "type": "array" + }, + "affinity": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "annotations": { + "type": "object" + }, + "extraEnv": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + } + }, + "additionalProperties": true + }, + "worker": { + "type": "object", + "properties": { + "replicas": { + "type": "integer", + "minimum": 1 + }, + "rpcPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "webPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "hostNetwork": { + "type": "boolean" + }, + "dnsPolicy": { + "type": "string", + "minLength": 1 + }, + "privileged": { + "type": "boolean" + }, + "s3Gateway": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "listen": { + "type": "string", + "minLength": 1 + }, + "enableDistributedAuth": { + "type": "boolean" + }, + "service": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ClusterIP", + "LoadBalancer", + "NodePort" + ] + }, + "annotations": { + "type": "object" + }, + "nodePort": { + "type": [ + "integer", + "null" + ], + "minimum": 1, + "maximum": 65535 + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + }, + "storage": { + "type": "object", + "properties": { + "dataDirs": { + "type": "array", + "items": { + "allOf": [ + { + "$ref": "#/definitions/storageDir" + }, + { + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "type": { + "type": "string", + "minLength": 1 + } + } + } + ] + } + } + }, + "additionalProperties": true + }, + "resources": { + "$ref": "#/definitions/resources" + }, + "nodeSelector": { + "type": "object" + }, + "tolerations": { + "type": "array" + }, + "antiAffinity": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "preferred", + "required" + ] + } + }, + "additionalProperties": true + }, + "affinity": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "annotations": { + "type": "object" + }, + "extraEnv": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + } + }, + "additionalProperties": true + }, + "service": { + "type": "object", + "properties": { + "master": { + "$ref": "#/definitions/serviceConfig" + }, + "worker": { + "$ref": "#/definitions/serviceConfig" + }, + "masterExternal": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "ClusterIP", + "LoadBalancer", + "NodePort" + ] + }, + "annotations": { + "type": "object" + }, + "nodePort": { + "type": "object" + }, + "loadBalancerIP": { + "type": "string" + }, + "loadBalancerSourceRanges": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "annotations": { + "type": "object" + } + }, + "additionalProperties": true + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "config": { + "type": "object", + "properties": { + "master": { + "type": "object" + }, + "journal": { + "type": "object" + }, + "worker": { + "type": "object" + }, + "client": { + "type": "object" + }, + "log": { + "type": "object" + } + }, + "additionalProperties": true + }, + "configOverrides": { + "type": "object", + "properties": { + "master": { + "type": "object" + }, + "journal": { + "type": "object" + }, + "worker": { + "type": "object" + }, + "client": { + "type": "object" + }, + "log": { + "type": "object" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true, + "definitions": { + "resources": { + "type": "object", + "properties": { + "requests": { + "type": "object" + }, + "limits": { + "type": "object" + } + }, + "additionalProperties": true + }, + "storageDir": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "storageClass": { + "type": "string" + }, + "size": { + "type": "string", + "minLength": 1 + }, + "hostPath": { + "type": "string" + }, + "mountPath": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "additionalProperties": true + }, + "serviceConfig": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ClusterIP", + "NodePort", + "LoadBalancer" + ] + }, + "annotations": { + "type": "object" + } + }, + "additionalProperties": true + } + } +} diff --git a/curvine-runtime/values.yaml b/curvine-runtime/values.yaml index 40285f6..3223723 100644 --- a/curvine-runtime/values.yaml +++ b/curvine-runtime/values.yaml @@ -19,7 +19,8 @@ image: # Master node configuration master: # Number of master replicas (must be odd: 1, 3, 5, 7...) - replicas: 3 + # Default is intentionally minimal for first deployments. + replicas: 1 # Master RPC port rpcPort: 8995 @@ -38,25 +39,25 @@ master: meta: enabled: true storageClass: "" # Empty means use default StorageClass - size: "10Gi" + size: "5Gi" hostPath: "" # Use hostPath if storageClass is empty mountPath: "/opt/curvine/data/meta" journal: enabled: true storageClass: "" - size: "50Gi" + size: "10Gi" hostPath: "" mountPath: "/opt/curvine/data/journal" # Resource requests and limits resources: requests: + cpu: "500m" + memory: "1Gi" + limits: cpu: "1000m" memory: "2Gi" - limits: - cpu: "2000m" - memory: "4Gi" # Node selector nodeSelector: {} @@ -85,7 +86,8 @@ master: # Worker node configuration worker: # Number of worker replicas - replicas: 3 + # Default is intentionally minimal for first deployments. + replicas: 1 # Worker RPC port rpcPort: 8997 @@ -118,7 +120,7 @@ worker: - name: "data1" type: "SSD" enabled: true - size: "10Gi" + size: "20Gi" storageClass: "" # Empty means use default StorageClass hostPath: "" # Use hostPath if storageClass is empty mountPath: "/data/data1" @@ -135,11 +137,11 @@ worker: # Resource requests and limits resources: requests: - cpu: "2000m" - memory: "4Gi" + cpu: "500m" + memory: "1Gi" limits: - cpu: "4000m" - memory: "8Gi" + cpu: "1000m" + memory: "2Gi" # Node selector nodeSelector: {} @@ -219,6 +221,7 @@ config: # data_dir will be generated from worker.storage.dataDirs # Format: [TYPE:SIZE]PATH # Example: [SSD:100GB]/data/data1 + {} # Client configuration client: