diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..13fa5d41 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: https://editorconfig.org + +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +max_line_length = 150 +tab_width = 2 + +[*.md] +max_line_length = 0 + +[values.schema.json] +indent_size = 4 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a3123570..0880ff69 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -56,6 +56,7 @@ body: - universal - clusterpirate - common + - etcd - ghost - keycloak - mariadb @@ -68,6 +69,7 @@ body: - redis - timescaledb - valkey + - wordpress - zookeeper validations: required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index d9447e43..41db4486 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -45,6 +45,7 @@ body: - universal - clusterpirate - common + - etcd - ghost - keycloak - mariadb @@ -57,4 +58,5 @@ body: - redis - timescaledb - valkey + - wordpress - zookeeper diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1821d8e9..ce3d8b29 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,6 +4,9 @@ - Describe the scope of your change - i.e. what the change does. - Describe any known limitations with your change. - Please run any tests or examples that can exercise your modified code. + - Labels are automatically applied when they are inside the square brackets of your PR title on opening. Examples: + - [redis]: adds `redis` label + - [redis, valkey] Adds `redis` and `valkey` labels Thank you for contributing! We will try to test and integrate the change as soon as we can. --> @@ -23,6 +26,7 @@ ### Applicable issues + - fixes # ### Additional information @@ -33,6 +37,6 @@ -- [ ] Chart version bumped in `Chart.yaml` according to [semver](http://semver.org/). This is *not necessary* when the changes only affect README.md files. +- [ ] Chart version bumped in `Chart.yaml` according to [semver](http://semver.org/). This is _not necessary_ when the changes only affect README.md files. - [ ] Variables are documented in the values.yaml and added to the `README.md` - [ ] Title of the pull request follows this pattern [] Descriptive title diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..7bdbf3ef --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "chore(deps)" + include: "scope" + open-pull-requests-limit: 10 + assignees: + - "CloudPirates-io/maintainers" + # Group all GitHub Actions updates into a single PR + groups: + github-actions: + patterns: + - "*" diff --git a/.github/workflows/auto-label.yaml b/.github/workflows/auto-label.yaml index 9530d41f..75b2a9ef 100644 --- a/.github/workflows/auto-label.yaml +++ b/.github/workflows/auto-label.yaml @@ -2,23 +2,45 @@ name: Auto-label issues on: issues: types: [opened] + pull_request: + types: [opened] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.issue.number }} + cancel-in-progress: true jobs: label: + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} runs-on: ubuntu-latest + timeout-minutes: 5 permissions: issues: write + pull-requests: write steps: - name: Apply labels - uses: actions/github-script@v7 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | - const labels = (context.payload.issue.body.split(/### Affected Helm charts/)[1] || "") + let content = ""; + if (context.payload.pull_request) { + const parsedTitle = context.payload.pull_request.title.match(/^\[([a-z_-]+(?:, [a-z_-]+)*)\].+$/); + content = parsedTitle ? parsedTitle[1] : ""; + } else { + content = context.payload.issue.body.split(/### Affected Helm charts/)[1] || ""; + } + const { data } = await github.rest.issues.listLabelsForRepo({ + ...context.repo, + per_page: 100, + }); + const existingLabels = new Set(data.map((label) => label.name)); + const labels = content .trim() .split(",") .map((s) => s.trim()) - .filter((s) => s && s !== "_No response_"); + .filter((s) => s && existingLabels.has(s)); if (labels.length) { + console.log(`Adding ${labels.length} labels: ${labels.join(', ')}`) await github.rest.issues.addLabels({ ...context.repo, issue_number: context.issue.number, diff --git a/.github/workflows/check-signed-commits.yaml b/.github/workflows/check-signed-commits.yaml new file mode 100644 index 00000000..950523ec --- /dev/null +++ b/.github/workflows/check-signed-commits.yaml @@ -0,0 +1,75 @@ +name: Check signed commits in PR +on: pull_request_target + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + check-signed-commits: + name: Check signed commits in PR + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: Check for bot commits + id: check-bots + run: | + # Get all commits in the PR + git fetch origin ${{ github.event.pull_request.base.ref }} + COMMITS=$(git log origin/${{ github.event.pull_request.base.ref }}..HEAD --format="%an") + + echo "Commits in PR:" + echo "$COMMITS" + + # Check if any commits are NOT from bots + # grep -v returns 0 (true) if it finds lines NOT matching the pattern + # grep -v returns 1 (false) if all lines match the pattern (all are bots) + if echo "$COMMITS" | grep -qv '\[bot\]'; then + echo "Found human commits" + echo "has_human_commits=true" >> $GITHUB_OUTPUT + else + echo "All commits are from bots" + echo "has_human_commits=false" >> $GITHUB_OUTPUT + fi + + - name: Check signed commits in PR + if: steps.check-bots.outputs.has_human_commits == 'true' + continue-on-error: true + uses: 1Password/check-signed-commits-action@ed2885f3ed2577a4f5d3c3fe895432a557d23d52 # v1.2.0 + with: + comment: | + ## โš ๏ธ Unsigned Commits Detected + + This pull request contains unsigned commits. + + ### What does this mean? + + Signed commits help ensure the authenticity and traceability of contributions. They allow us to verify that commits actually came from the stated author, even if GitHub accounts are deleted or modified in the future. + + ### Current Policy (Grace Period) + + **This is currently a warning only.** We are in a transition period to give all contributors time to set up commit signing. + + After this grace period, **all commits will be required to be signed** before PRs can be merged. + + ### How to sign your commits + + Please see our [Contributing Guide](../blob/main/CONTRIBUTING.md#setting-up-your-development-environment) for detailed instructions on setting up commit signing. + + ### Resources + + - [Contributing Guide: Development Setup](../blob/main/CONTRIBUTING.md#setting-up-your-development-environment) + - [GitHub Docs: About Commit Signature Verification](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) + + --- + + _This check will become mandatory in the future. Please start signing your commits now to avoid issues later._ diff --git a/.github/workflows/generate-schema.yaml b/.github/workflows/generate-schema.yaml new file mode 100644 index 00000000..f4bb4afb --- /dev/null +++ b/.github/workflows/generate-schema.yaml @@ -0,0 +1,317 @@ +name: "Generate values.schema.json" + +on: + push: + branches: + - main + paths: + - 'charts/**/values.yaml' + pull_request: + paths: + - 'charts/**/values.yaml' + workflow_dispatch: + inputs: + charts: + description: 'Specific charts to generate schema for (comma-separated, e.g., "nginx,redis"). Leave empty for all charts.' + required: false + type: string + force_regenerate: + description: 'Force regeneration even if values.yaml has not changed' + required: false + type: boolean + default: false + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + generate-schema: + runs-on: ubuntu-latest + timeout-minutes: 15 + # Skip if the commit was made by github-actions bot to prevent infinite loops + if: github.actor != 'github-actions[bot]' + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + token: ${{ secrets.CHANGELOG_PAT }} + + - name: Set up Python + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + with: + python-version: '3.11' + + - name: Set up Helm + uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 + with: + version: 'latest' + + - name: Install helm-schema plugin + run: | + set -e + # Check if plugin is already installed + if helm plugin list | grep -q "schema"; then + echo "Plugin already installed" + helm plugin list | grep "schema" + else + echo "Installing helm-values-schema-json plugin..." + helm plugin install https://github.com/losisin/helm-values-schema-json.git --version v1.9.2 + fi + + # Verify plugin installation + echo "Verifying plugin installation..." + helm plugin list + if ! helm plugin list | grep -q "schema"; then + echo "ERROR: Plugin installation failed" + exit 1 + fi + + echo "Plugin installed successfully" + + - name: Determine charts to process + id: determine-charts + run: | + set -e + + # Function to get all charts except 'common' + get_all_charts() { + find charts -mindepth 1 -maxdepth 1 -type d ! -name 'common' -exec basename {} \; | sort + } + + # For workflow_dispatch with specific charts + if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.charts }}" ]; then + echo "Manual trigger with specific charts: ${{ github.event.inputs.charts }}" + CHARTS="${{ github.event.inputs.charts }}" + echo "charts=$CHARTS" >> $GITHUB_OUTPUT + echo "mode=manual-specific" >> $GITHUB_OUTPUT + + # For workflow_dispatch with force regenerate all + elif [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.force_regenerate }}" = "true" ]; then + echo "Manual trigger: force regenerate all charts" + CHARTS=$(get_all_charts | tr '\n' ',' | sed 's/,$//') + echo "charts=$CHARTS" >> $GITHUB_OUTPUT + echo "mode=manual-all" >> $GITHUB_OUTPUT + + # For push/PR events - detect changed charts + else + echo "Detecting changed charts from git diff" + + if [ "${{ github.event_name }}" = "pull_request" ]; then + BASE_REF="${{ github.event.pull_request.base.sha }}" + else + BASE_REF="${{ github.event.before }}" + fi + + # Get changed values.yaml files + CHANGED_FILES=$(git diff --name-only "$BASE_REF" HEAD -- 'charts/**/values.yaml' || echo "") + + if [ -z "$CHANGED_FILES" ]; then + echo "No values.yaml files changed" + echo "charts=" >> $GITHUB_OUTPUT + echo "mode=none" >> $GITHUB_OUTPUT + else + echo "Changed values.yaml files:" + echo "$CHANGED_FILES" + + # Extract chart names from changed files + CHARTS=$(echo "$CHANGED_FILES" | grep -o 'charts/[^/]*' | cut -d/ -f2 | sort -u | grep -v '^common$' | tr '\n' ',' | sed 's/,$//') + + if [ -z "$CHARTS" ]; then + echo "Only common chart changed, skipping schema generation" + echo "charts=" >> $GITHUB_OUTPUT + echo "mode=none" >> $GITHUB_OUTPUT + else + echo "Charts to process: $CHARTS" + echo "charts=$CHARTS" >> $GITHUB_OUTPUT + echo "mode=auto" >> $GITHUB_OUTPUT + fi + fi + fi + + - name: Generate schema for charts + if: steps.determine-charts.outputs.charts != '' + run: | + set -e + + CHARTS="${{ steps.determine-charts.outputs.charts }}" + IFS=',' read -ra CHART_ARRAY <<< "$CHARTS" + + echo "Generating schemas for: ${CHART_ARRAY[*]}" + + SUCCESS_COUNT=0 + FAIL_COUNT=0 + FAILED_CHARTS="" + + for chart in "${CHART_ARRAY[@]}"; do + chart=$(echo "$chart" | xargs) # trim whitespace + + if [ -z "$chart" ]; then + continue + fi + + echo "Processing chart: $chart" + CHART_DIR="charts/$chart" + + if [ ! -d "$CHART_DIR" ]; then + echo "Warning: Chart directory not found: $CHART_DIR" + FAIL_COUNT=$((FAIL_COUNT + 1)) + FAILED_CHARTS="$FAILED_CHARTS $chart" + continue + fi + + if [ ! -f "$CHART_DIR/values.yaml" ]; then + echo "Warning: values.yaml not found in $CHART_DIR" + FAIL_COUNT=$((FAIL_COUNT + 1)) + FAILED_CHARTS="$FAILED_CHARTS $chart" + continue + fi + + echo "Generating schema for $chart..." + if helm schema -input "$CHART_DIR/values.yaml" -output "$CHART_DIR/values.schema.json" -draft 7; then + echo "Successfully generated schema for $chart" + SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) + else + echo "Failed to generate schema for $chart" + FAIL_COUNT=$((FAIL_COUNT + 1)) + FAILED_CHARTS="$FAILED_CHARTS $chart" + fi + done + + echo "" + echo "Summary:" + echo " Success: $SUCCESS_COUNT" + echo " Failed: $FAIL_COUNT" + + if [ $FAIL_COUNT -gt 0 ]; then + echo " Failed charts:$FAILED_CHARTS" + fi + + echo "success_count=$SUCCESS_COUNT" >> $GITHUB_ENV + echo "fail_count=$FAIL_COUNT" >> $GITHUB_ENV + + - name: Check for schema changes + if: steps.determine-charts.outputs.charts != '' + id: check-changes + run: | + if git status --porcelain | grep -q 'values.schema.json'; then + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "Schema files have been updated" + git status --porcelain | grep 'values.schema.json' + else + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "No schema changes detected" + fi + + - name: Debug commit conditions + if: steps.determine-charts.outputs.charts != '' + run: | + echo "Debug information for commit step:" + echo " github.event_name: ${{ github.event_name }}" + echo " github.ref: ${{ github.ref }}" + echo " has_changes: ${{ steps.check-changes.outputs.has_changes }}" + echo " Should commit to main: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' && steps.check-changes.outputs.has_changes == 'true' }}" + + - name: Create PR for schema updates (push to main) + if: | + (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && + github.ref == 'refs/heads/main' && + steps.check-changes.outputs.has_changes == 'true' + env: + GH_TOKEN: ${{ secrets.CHANGELOG_PAT }} + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + # Create a new branch for the schema updates + BRANCH_NAME="auto/schema-update-$(date +%s)" + git checkout -b "$BRANCH_NAME" + + git add charts/*/values.schema.json + + git commit -m "chore: auto-generate values.schema.json for updated charts" \ + -m "Automatically generated JSON schemas for Helm values files." \ + -m "" \ + -m "Signed-off-by: github-actions[bot] " + + # Push the branch + git push origin "$BRANCH_NAME" + + # Create a pull request + gh pr create \ + --title "chore: auto-generate values.schema.json" \ + --body "This PR contains automatically generated JSON schemas for Helm values files. + + ## Changes + - Auto-generated \`values.schema.json\` files for charts with updated \`values.yaml\` + + ## Notes + - This PR was automatically created by the schema generation workflow + - Please review and merge if the changes look correct + - The workflow will not run again on this bot's commits to prevent loops + + --- + ๐Ÿค– Generated by [generate-schema workflow](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" \ + --base main \ + --head "$BRANCH_NAME" + + - name: Commit schema updates to PR branch + if: | + github.event_name == 'pull_request' && + steps.check-changes.outputs.has_changes == 'true' + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + git add charts/*/values.schema.json + + git commit -m "chore: auto-generate values.schema.json" \ + -m "Signed-off-by: github-actions[bot] " || echo "No changes to commit" + + # Push to PR branch + git push origin HEAD:${{ github.head_ref }} + + - name: Commit schema updates to current branch (workflow_dispatch on non-main) + if: | + github.event_name == 'workflow_dispatch' && + github.ref != 'refs/heads/main' && + steps.check-changes.outputs.has_changes == 'true' + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + git add charts/*/values.schema.json + + git commit -m "chore: auto-generate values.schema.json" \ + -m "Signed-off-by: github-actions[bot] " + + # Push to current branch + git push origin HEAD:${{ github.ref }} + + - name: Generate job summary + if: steps.determine-charts.outputs.charts != '' + run: | + echo "## ๐Ÿ“‹ Schema Generation Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ steps.determine-charts.outputs.mode }}" = "none" ]; then + echo "No charts required schema generation." >> $GITHUB_STEP_SUMMARY + else + echo "**Mode:** ${{ steps.determine-charts.outputs.mode }}" >> $GITHUB_STEP_SUMMARY + echo "**Charts processed:** ${{ steps.determine-charts.outputs.charts }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Results:**" >> $GITHUB_STEP_SUMMARY + echo "- โœ… Success: ${success_count}" >> $GITHUB_STEP_SUMMARY + echo "- โŒ Failed: ${fail_count}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ steps.check-changes.outputs.has_changes }}" = "true" ]; then + echo "**Status:** Schema files updated and committed" >> $GITHUB_STEP_SUMMARY + else + echo "**Status:** No schema changes detected" >> $GITHUB_STEP_SUMMARY + fi + fi \ No newline at end of file diff --git a/.github/workflows/post-merge.yaml b/.github/workflows/post-merge.yaml new file mode 100644 index 00000000..8c528ae8 --- /dev/null +++ b/.github/workflows/post-merge.yaml @@ -0,0 +1,272 @@ +name: "Post-Merge Changelog Update" + +on: + push: + branches: + - main + paths: + - 'charts/**' + workflow_dispatch: # Manual trigger + inputs: + update_all_charts: + description: 'Update all charts (not just changed ones)' + required: false + type: boolean + default: false + clean_start: + description: 'Delete existing CHANGELOG.md files and start fresh' + required: false + type: boolean + default: false + custom_message: + description: 'Custom changelog message (optional)' + required: false + type: string + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + update-changelog: + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: write + steps: + - name: Checkout main branch + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + token: ${{ secrets.CHANGELOG_PAT || secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + - name: Fetch all tags + run: | + git fetch --tags --force + echo "Available tags:" + git tag -l | head -20 + + - name: Install yq + run: | + sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 + sudo chmod +x /usr/local/bin/yq + + - name: Determine charts to update + id: charts-to-update + run: | + # For manual trigger with update_all_charts enabled + if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.update_all_charts }}" = "true" ]; then + echo "Manual trigger: updating all charts" + all_charts=$(find charts -mindepth 1 -maxdepth 1 -type d | sed 's|^charts/||' | tr '\n' ' ') + echo "All charts: $all_charts" + echo "changed=true" >> $GITHUB_OUTPUT + echo "changedCharts=$all_charts" >> $GITHUB_OUTPUT + echo "update_mode=all" >> $GITHUB_OUTPUT + # For manual trigger without update_all_charts (default behavior - changed charts only) + elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "Manual trigger: finding changed charts from last commit" + # Use the same logic as push event to find changed charts + BEFORE_SHA=$(git rev-parse HEAD~1) + changed_files=$(git diff --name-only "${BEFORE_SHA}" HEAD -- 'charts/**') + + if [[ -n "$changed_files" ]]; then + changed_charts=$(echo "$changed_files" | grep '^charts/' | cut -d/ -f1-2 | sort -u | tr '\n' ' ') + if [[ -n "$changed_charts" ]]; then + echo "Changed charts: $changed_charts" + echo "changed=true" >> $GITHUB_OUTPUT + echo "changedCharts=${changed_charts}" >> $GITHUB_OUTPUT + echo "update_mode=changed" >> $GITHUB_OUTPUT + else + echo "No chart changes detected in last commit" + echo "changed=false" >> $GITHUB_OUTPUT + fi + else + echo "No chart changes detected in last commit" + echo "changed=false" >> $GITHUB_OUTPUT + fi + # For push event (original behavior) + else + echo "Push event: finding changed charts from merge commit" + BEFORE_SHA="${{ github.event.before }}" + changed_files=$(git diff --name-only "${BEFORE_SHA}" HEAD -- 'charts/**') + + if [[ -n "$changed_files" ]]; then + changed_charts=$(echo "$changed_files" | grep '^charts/' | cut -d/ -f1-2 | sort -u | tr '\n' ' ') + if [[ -n "$changed_charts" ]]; then + echo "Changed charts: $changed_charts" + echo "changed=true" >> $GITHUB_OUTPUT + echo "changedCharts=${changed_charts}" >> $GITHUB_OUTPUT + echo "update_mode=changed" >> $GITHUB_OUTPUT + else + echo "No chart changes detected" + echo "changed=false" >> $GITHUB_OUTPUT + fi + else + echo "No chart changes detected" + echo "changed=false" >> $GITHUB_OUTPUT + fi + fi + + - name: Clean start - Delete existing CHANGELOG.md files + if: github.event_name == 'workflow_dispatch' && github.event.inputs.clean_start == 'true' && steps.charts-to-update.outputs.changed == 'true' + run: | + echo "Clean start enabled - deleting existing CHANGELOG.md files" + CHANGED_CHARTS="${{ steps.charts-to-update.outputs.changedCharts }}" + + for chart_directory in $CHANGED_CHARTS; do + CHART_NAME=${chart_directory#charts/} + CHANGELOG_FILE="charts/${CHART_NAME}/CHANGELOG.md" + + if [ -f "$CHANGELOG_FILE" ]; then + echo "Deleting $CHANGELOG_FILE" + rm "$CHANGELOG_FILE" + + # Check if directory is empty except for ignored files + if [ -z "$(ls -A "charts/${CHART_NAME}" | grep -vE '^(Chart\.yaml|values\.yaml|\.helmignore|templates|crds|\.gitkeep)$')" ]; then + echo "Directory charts/${CHART_NAME} would be empty after deletion, but keeping it" + fi + else + echo "No CHANGELOG.md found at $CHANGELOG_FILE" + fi + done + + # Commit the deletions if any files were removed + if git status --porcelain | grep -q 'CHANGELOG.md'; then + echo "CHANGELOG.md files deleted successfully" + git add charts/*/CHANGELOG.md + git commit -m "chore: remove existing CHANGELOG.md files for clean start" \ + -m "Signed-off-by: github-actions[bot] " + echo "clean_start_completed=true" >> $GITHUB_ENV + else + echo "No CHANGELOG.md files to delete" + echo "clean_start_completed=false" >> $GITHUB_ENV + fi + + - name: Get PR information for push events + id: pr-info-push + if: github.event_name == 'push' && steps.charts-to-update.outputs.changed == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const commit = context.payload.head_commit; + const commitSha = commit.id; + + // Find the PR that was merged + const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + owner: context.repo.owner, + repo: context.repo.repo, + commit_sha: commitSha + }); + + const mergedPR = prs.find(pr => pr.merged_at); + + if (mergedPR) { + core.setOutput('pr_number', mergedPR.number); + core.setOutput('pr_title', mergedPR.title); + core.setOutput('pr_url', mergedPR.html_url); + console.log(`Found merged PR #${mergedPR.number}: ${mergedPR.title}`); + } else { + console.log('No merged PR found for this commit'); + core.setOutput('pr_number', ''); + core.setOutput('pr_title', commit.message.split('\n')[0]); + core.setOutput('pr_url', ''); + } + + - name: Set manual trigger info + id: manual-info + if: github.event_name == 'workflow_dispatch' && steps.charts-to-update.outputs.changed == 'true' + run: | + if [ -n "${{ github.event.inputs.custom_message }}" ]; then + PR_TITLE="${{ github.event.inputs.custom_message }}" + else + if [ "${{ github.event.inputs.clean_start }}" = "true" ]; then + PR_TITLE="Manual changelog update with clean start" + else + PR_TITLE="Manual changelog update triggered via workflow_dispatch" + fi + fi + + echo "pr_number=manual" >> $GITHUB_OUTPUT + echo "pr_title=${PR_TITLE}" >> $GITHUB_OUTPUT + echo "pr_url=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT + + - name: Generate changelog + id: generate-changelog + if: steps.charts-to-update.outputs.changed == 'true' + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + GITHUB_REPOSITORY: "${{ github.repository }}" + GITHUB_REPOSITORY_URL: "${{ github.server_url }}/${{ github.repository }}" + PR_NUMBER: ${{ github.event_name == 'push' && steps.pr-info-push.outputs.pr_number || steps.manual-info.outputs.pr_number }} + PR_TITLE: ${{ github.event_name == 'push' && steps.pr-info-push.outputs.pr_title || steps.manual-info.outputs.pr_title }} + PR_URL: ${{ github.event_name == 'push' && steps.pr-info-push.outputs.pr_url || steps.manual-info.outputs.pr_url }} + UPDATE_MODE: ${{ steps.charts-to-update.outputs.update_mode }} + CLEAN_START: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.clean_start || 'false' }} + run: | + set -e + + CHANGED_CHARTS="${{ steps.charts-to-update.outputs.changedCharts }}" + + echo "Update mode: $UPDATE_MODE" + echo "Clean start: $CLEAN_START" + echo "Processing charts: $CHANGED_CHARTS" + + # Process each chart individually + for chart_directory in $CHANGED_CHARTS; do + CHART_NAME=${chart_directory#charts/} + echo "Processing chart: $CHART_NAME" + + # Run the changelog script for this specific chart + ./generate-changelog.sh \ + --chart "$CHART_NAME" \ + --pr-title "${PR_TITLE}" \ + --pr-number "${PR_NUMBER}" \ + --pr-url "${PR_URL}" + done + + # Check if there are changes + if git status --porcelain | grep -q 'CHANGELOG.md'; then + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "Changelog changes detected" + git status --porcelain + else + echo "No CHANGELOG changes" + echo "has_changes=false" >> $GITHUB_OUTPUT + fi + + - name: Update appVersion in Chart.yaml files + if: steps.generate-changelog.outputs.has_changes == 'true' && env.clean_start_completed != 'true' + run: ./update-appversion.sh --all + + - name: Commit and push changelog and chart updates + if: steps.generate-changelog.outputs.has_changes == 'true' && env.clean_start_completed != 'true' + run: | + git add charts/*/CHANGELOG.md + git add charts/*/Chart.yaml + + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + COMMIT_MSG="chore: update CHANGELOG.md via manual trigger" + if [ "${{ github.event.inputs.update_all_charts }}" = "true" ]; then + COMMIT_MSG="chore: update CHANGELOG.md for all charts via manual trigger" + fi + if [ "${{ github.event.inputs.clean_start }}" = "true" ]; then + COMMIT_MSG="chore: regenerate CHANGELOG.md with clean start" + fi + else + COMMIT_MSG="chore: update CHANGELOG.md for merged changes" + fi + + git commit -m "$COMMIT_MSG" \ + -m "Signed-off-by: github-actions[bot] " + + # Pull latest changes and rebase our commit on top + git pull --rebase origin main + + # Push the changes + git push origin main diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 09052118..34993e03 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -8,32 +8,48 @@ on: branches: - main +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: lint-test: runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read outputs: changed: ${{ steps.list-changed.outputs.changed }} changedCharts: ${{ steps.list-changed.outputs.changedCharts }} steps: - name: Setup Helm - uses: Azure/setup-helm@v4.3.1 + uses: Azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 - name: Checkout pull request branch - uses: actions/checkout@v5.0.0 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ github.head_ref }} repository: ${{github.event.pull_request.head.repo.full_name}} fetch-depth: 0 + - name: Fetch upstream main branch + run: | + # Fetch the base repository's target branch and update origin/main to point to it + git remote set-url origin https://github.com/CloudPirates-io/helm-charts.git + git fetch origin ${{ github.event.repository.default_branch }} + # Re-add the fork as a remote and checkout the PR branch + git remote add fork https://github.com/${{ github.event.pull_request.head.repo.full_name }}.git || true + git fetch fork ${{ github.head_ref }} + # Python is required because `ct lint` runs Yamale (https://github.com/23andMe/Yamale) and # yamllint (https://github.com/adrienverge/yamllint) which require Python - name: Set up Python - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: - python-version: 3.x + python-version: 3.11 - name: Set up chart-testing-action - uses: helm/chart-testing-action@v2.7.0 + uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0 - name: Get changed charts id: list-changed @@ -50,97 +66,97 @@ jobs: echo "No chart changes detected" fi + - name: Cache Helm plugins + if: steps.list-changed.outputs.changed == 'true' + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.local/share/helm/plugins + key: ${{ runner.os }}-helm-plugins-${{ hashFiles('**/plugin.yaml') }} + restore-keys: | + ${{ runner.os }}-helm-plugins- + - name: Installing plugin helm-unittest if: steps.list-changed.outputs.changed == 'true' - run: helm plugin install https://github.com/helm-unittest/helm-unittest >/dev/null + run: | + if ! helm plugin list | grep -q unittest; then + helm plugin install https://github.com/helm-unittest/helm-unittest + else + echo "helm-unittest plugin already installed" + fi - name: Run chart testing (lint & unittest) if: steps.list-changed.outputs.changed == 'true' - run: ct lint --target-branch ${{ github.event.repository.default_branch }} --validate-maintainers=false --additional-commands "helm unittest {{ .Path }}" + run: | + ct lint --target-branch ${{ github.event.repository.default_branch }} --validate-maintainers=false --additional-commands 'helm unittest {{ .Path }}' - update-changelog: + integration-test: runs-on: ubuntu-latest - needs: [lint-test] - name: Automatically update CHANGELOG + timeout-minutes: 30 permissions: - contents: write + contents: read + needs: [lint-test] if: needs.lint-test.outputs.changed == 'true' steps: - name: Checkout pull request branch - uses: actions/checkout@v5.0.0 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ github.head_ref }} repository: ${{github.event.pull_request.head.repo.full_name}} fetch-depth: 0 - - name: Configure Git - run: | - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' + - name: Setup Helm + uses: Azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 - - name: Fetch tags - run: | - git fetch --tags + - name: Setup kubectl + uses: azure/setup-kubectl@776406bce94f63e41d621b960d78ee25c8b76ede # v4.0.1 - - name: Install conventional-changelog-cli - run: npm install -g conventional-changelog-cli + - name: Login to Docker Hub to avoid rate limits + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + with: + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} - - name: Generate changelog - id: generate-changelog + - name: Create kind cluster + uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab # v1.13.0 + with: + cluster_name: helm-chart-test + wait: 300s + + - name: Cache Helm plugins + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.local/share/helm/plugins + key: ${{ runner.os }}-helm-plugins-${{ hashFiles('**/plugin.yaml') }} + restore-keys: | + ${{ runner.os }}-helm-plugins- + + - name: Installing plugin helm-unittest + run: | + if ! helm plugin list | grep -q unittest; then + helm plugin install https://github.com/helm-unittest/helm-unittest + else + echo "helm-unittest plugin already installed" + fi + + - name: Run integration tests env: - PULL_REQUEST_NUMBER: "${{ github.event.pull_request.number }}" - PULL_REQUEST_URL: "${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.number }}" - GITHUB_TOKEN: "${{ github.token }}" CHANGED_CHARTS: ${{ needs.lint-test.outputs.changedCharts }} run: | - PR_TITLE="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PULL_REQUEST_NUMBER}" | jq -r '.title')" + # Make script executable + chmod +x ./test-charts.sh + + # Test each changed chart for chart_directory in ${CHANGED_CHARTS}; do CHART_NAME=${chart_directory#charts/} - echo "Updating CHANGELOG for chart $CHART_NAME" - - # Extract version from Chart.yaml - CHART_VERSION=$(yq eval '.version' "${GITHUB_WORKSPACE}/charts/${CHART_NAME}/Chart.yaml") - CHANGELOG_FILE="${GITHUB_WORKSPACE}/charts/${CHART_NAME}/CHANGELOG.md" - CHANGELOG_TMP_FILE="${GITHUB_WORKSPACE}/charts/${CHART_NAME}/CHANGELOG.md.tmp" - - touch "$CHANGELOG_FILE" - - # Generate new CHANGELOG.md - npx conventional-changelog-cli -i "$CHANGELOG_FILE" -s -t "${CHART_NAME}-" -r 0 --commit-path "charts/${CHART_NAME}" - - # Remove unreleased section (includes all intermediate commits in the branch) and create future entry based on PR title - # The unreleased section looks like this "## (YYYY-MM-DD)" whereas a released section looks like this "## 0.0.1 (YYYY-MM-DD)" - # So we only need to find a released section to start printing in the awk script below - awk '/^##[^(]*[0-9]/ {flag=1} flag {print}' "$CHANGELOG_FILE" > "$CHANGELOG_TMP_FILE" - - # Remove chart name prefixes from commit messages - sed -i -E "s/\* \[${CHART_NAME}\] /\* /gi" "$CHANGELOG_TMP_FILE" - sed -i -E "s/\* \[$(echo ${CHART_NAME} | tr '[:lower:]' '[:upper:]')\] /\* /g" "$CHANGELOG_TMP_FILE" - - # Remove extra newlines so the changelog file passes the markdown linter - sed -i -E -e '/^$/d' "$CHANGELOG_TMP_FILE" && sed -i -E -e 's/(##.*)/\n\1\n/g' "$CHANGELOG_TMP_FILE" - - # Include h1 heading and add entry for the current version. There is no tag for the current version (this will be created once merged), so we need to manually add it. - # We know the final squashed commit title, which will be the PR title. We cannot add a link to the commit in the main branch because it has not been - # merged yet (this will be corrected once a new version regenerates the changelog). Instead, we add the PR url which contains the exact same information. - echo -e -n "# Changelog\n\n## $CHART_VERSION ($(date +'%Y-%m-%d'))\n\n* ${PR_TITLE} ([#${PULL_REQUEST_NUMBER}](${PULL_REQUEST_URL}))\n" > "$CHANGELOG_FILE" - - cat "$CHANGELOG_TMP_FILE" >> "$CHANGELOG_FILE" - rm "$CHANGELOG_TMP_FILE" - - # Commit all changes, if any - if git status -s | grep "charts/${CHART_NAME}/CHANGELOG.md"; then - git add "charts/${CHART_NAME}/CHANGELOG.md" - git commit -m "Update CHANGELOG.md" --signoff + echo "Testing chart: $CHART_NAME" + + # Check if integration test is disabled for this chart + if [ -f "${chart_directory}/.disable-unittest" ]; then + echo "โฉ Skipping integration test for $CHART_NAME (.disable-unittest found)" + continue fi - done - - name: Push all changes - run: | - cd $GITHUB_WORKSPACE/charts - # Push all the new commits, if any - if [[ $(git cherry -v) ]]; then - git push - else - echo "No changed CHANGELOGS, skip push" - fi + # Run test script without cluster creation (kind-action already created it) + # and without cleanup (let GitHub Actions handle it) + ./test-charts.sh "$CHART_NAME" --no-cleanup + done diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b6d834c0..b4f130a9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,6 +4,17 @@ on: push: branches: - main + workflow_dispatch: + inputs: + dry_run: + description: 'Dry run (skip actual release)' + required: false + type: boolean + default: false + +concurrency: + group: release + cancel-in-progress: true jobs: release: @@ -11,9 +22,10 @@ jobs: contents: write packages: write runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout - uses: actions/checkout@v5.0.0 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 @@ -23,14 +35,14 @@ jobs: git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - name: Login to Registry - uses: docker/login-action@v3 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: ${{ vars.REGISTRY }} username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_PASSWORD }} - name: Login to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -38,18 +50,18 @@ jobs: - name: Run chart-releaser id: chart-releaser - uses: helm/chart-releaser-action@v1.7.0 + uses: helm/chart-releaser-action@cae68fefc6b5f367a0275617c9f83181ba54714f # v1.7.0 with: skip_existing: true env: CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - name: Install cosign - uses: sigstore/cosign-installer@v3.9.2 + uses: sigstore/cosign-installer@v3.10.0 if: ${{ steps.chart-releaser.outputs.changed_charts }} - id: github-repo-owner-name - uses: ASzc/change-string-case-action@v6 + uses: ASzc/change-string-case-action@d0603cd0a7dd490be678164909f65c7737470a7f # v6 with: string: ${{ github.repository_owner }} @@ -61,13 +73,38 @@ jobs: COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} REGISTRY_USER: ${{ secrets.REGISTRY_USER }} run: | - CHANGED_CHARTS="${{ steps.chart-releaser.outputs.changed_charts }}" + set -euo pipefail - # Login to primary registry - helm registry login --username $REGISTRY_USER --password ${{ secrets.REGISTRY_PASSWORD }} https://${{ vars.REGISTRY }} + CHANGED_CHARTS="${{ steps.chart-releaser.outputs.changed_charts }}" - # Login to GHCR - helm registry login --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} https://ghcr.io + # Retry function for network operations + retry() { + local max_attempts=3 + local attempt=1 + local delay=5 + + while [ $attempt -le $max_attempts ]; do + if "$@"; then + return 0 + else + echo "Attempt $attempt failed. Retrying in ${delay}s..." + sleep $delay + delay=$((delay * 2)) + attempt=$((attempt + 1)) + fi + done + + echo "ERROR: All $max_attempts attempts failed" + return 1 + } + + # Login to primary registry with retry + echo "Logging into primary registry..." + retry helm registry login --username $REGISTRY_USER --password ${{ secrets.REGISTRY_PASSWORD }} https://${{ vars.REGISTRY }} + + # Login to GHCR with retry + echo "Logging into GHCR..." + retry helm registry login --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} https://ghcr.io RELEASED_CHARTS="" for chart_directory in ${CHANGED_CHARTS//,/ }; do @@ -79,33 +116,63 @@ jobs: CHART_VERSION=$(yq eval '.version' "Chart.yaml") APP_VERSION=$(yq eval '.appVersion' "Chart.yaml") - # Push to primary registry (Docker Hub) + # Push to primary registry (Docker Hub) with retry echo "Pushing Helm chart $CHART_NAME-$CHART_VERSION.tgz to oci://${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}" - if helm push ${{ github.workspace }}/.cr-release-packages/${CHART_NAME}-${CHART_VERSION}.tgz oci://${{ vars.REGISTRY }}/${{ vars.REPOSITORY }} 2>&1 | tee ${CHART_NAME}-output.log; then + if retry helm push ${{ github.workspace }}/.cr-release-packages/${CHART_NAME}-${CHART_VERSION}.tgz oci://${{ vars.REGISTRY }}/${{ vars.REPOSITORY }} 2>&1 | tee ${CHART_NAME}-output.log; then # Extract digest and sign chart - DIGEST=$(cat ${CHART_NAME}-output.log | awk -F '[, ]+' '/Digest/{print $NF}') - cosign sign -y --key env://COSIGN_KEY ${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}/${CHART_NAME}:${CHART_VERSION}@$DIGEST + # More robust parsing: looks for "Digest: sha256:..." pattern + DIGEST=$(grep -oP 'Digest:\s*\K(sha256:[a-f0-9]+)' ${CHART_NAME}-output.log || echo "") + + if [ -z "$DIGEST" ]; then + echo "ERROR: Failed to extract digest from helm push output" + echo "Output was:" + cat ${CHART_NAME}-output.log + exit 1 + fi + + echo "Extracted digest: $DIGEST" + echo "Signing chart at ${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}/${CHART_NAME}:${CHART_VERSION}@$DIGEST" + + if ! cosign sign -y --upload=true --key env://COSIGN_KEY ${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}/${CHART_NAME}:${CHART_VERSION}@$DIGEST; then + echo "ERROR: Failed to sign chart" + exit 1 + fi RELEASED_CHARTS="$RELEASED_CHARTS ${CHART_NAME}" echo "Successfully released $CHART_NAME-$CHART_VERSION to primary registry" else - echo "Failed to push $CHART_NAME-$CHART_VERSION to primary registry" + echo "ERROR: Failed to push $CHART_NAME-$CHART_VERSION to primary registry" cat ${CHART_NAME}-output.log exit 1 fi - # Push to GHCR + # Push to GHCR with retry echo "Pushing Helm chart $CHART_NAME-$CHART_VERSION.tgz to oci://ghcr.io/${{ steps.github-repo-owner-name.outputs.lowercase }}/helm-charts" - if helm push ${{ github.workspace }}/.cr-release-packages/${CHART_NAME}-${CHART_VERSION}.tgz oci://ghcr.io/${{ steps.github-repo-owner-name.outputs.lowercase }}/helm-charts 2>&1 | tee ${CHART_NAME}-ghcr-output.log; then + if retry helm push ${{ github.workspace }}/.cr-release-packages/${CHART_NAME}-${CHART_VERSION}.tgz oci://ghcr.io/${{ steps.github-repo-owner-name.outputs.lowercase }}/helm-charts 2>&1 | tee ${CHART_NAME}-ghcr-output.log; then # Extract digest and sign GHCR chart - GHCR_DIGEST=$(cat ${CHART_NAME}-ghcr-output.log | awk -F '[, ]+' '/Digest/{print $NF}') - cosign sign -y --key env://COSIGN_KEY ghcr.io/${{ steps.github-repo-owner-name.outputs.lowercase }}/helm-charts/${CHART_NAME}:${CHART_VERSION}@$GHCR_DIGEST + # More robust parsing: looks for "Digest: sha256:..." pattern + GHCR_DIGEST=$(grep -oP 'Digest:\s*\K(sha256:[a-f0-9]+)' ${CHART_NAME}-ghcr-output.log || echo "") + + if [ -z "$GHCR_DIGEST" ]; then + echo "ERROR: Failed to extract digest from helm push output" + echo "Output was:" + cat ${CHART_NAME}-ghcr-output.log + exit 1 + fi + + echo "Extracted digest: $GHCR_DIGEST" + echo "Signing chart at ghcr.io/${{ steps.github-repo-owner-name.outputs.lowercase }}/helm-charts/${CHART_NAME}:${CHART_VERSION}@$GHCR_DIGEST" + + if ! cosign sign -y --upload=true --key env://COSIGN_KEY ghcr.io/${{ steps.github-repo-owner-name.outputs.lowercase }}/helm-charts/${CHART_NAME}:${CHART_VERSION}@$GHCR_DIGEST; then + echo "ERROR: Failed to sign chart" + exit 1 + fi echo "Successfully released $CHART_NAME-$CHART_VERSION to GHCR" else - echo "Failed to push $CHART_NAME-$CHART_VERSION to GHCR" + echo "ERROR: Failed to push $CHART_NAME-$CHART_VERSION to GHCR" cat ${CHART_NAME}-ghcr-output.log exit 1 fi @@ -113,3 +180,16 @@ jobs: cd ${{ github.workspace }} done echo "released_charts=$RELEASED_CHARTS" >> "$GITHUB_OUTPUT" + + # Generate job summary + echo "## ๐Ÿ“ฆ Helm Charts Released" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Successfully released the following charts:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + for chart in $RELEASED_CHARTS; do + echo "- โœ… **$chart**" >> $GITHUB_STEP_SUMMARY + done + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿ“ Registries" >> $GITHUB_STEP_SUMMARY + echo "- Primary: \`${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}\`" >> $GITHUB_STEP_SUMMARY + echo "- GHCR: \`ghcr.io/${{ steps.github-repo-owner-name.outputs.lowercase }}/helm-charts\`" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 00000000..386aac17 --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,70 @@ +name: "Close stale issues and PRs" + +on: + schedule: + # Run daily at 00:00 UTC + - cron: "0 0 * * *" + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Close stale issues and PRs + uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0 + with: + # Issue settings + stale-issue-message: | + This issue has been automatically marked as stale because it has not had any activity for 14 days. + + It will be closed in 7 days if no further activity occurs. + + If this issue is still relevant, please comment to keep it open. + + Thank you for your contributions! + close-issue-message: | + This issue has been automatically closed due to inactivity. + + If you believe this issue is still relevant, please reopen it or create a new issue with updated information. + + Thank you for your understanding! + days-before-issue-stale: 14 + days-before-issue-close: 7 + stale-issue-label: "stale" + exempt-issue-labels: "pinned,security,bug,enhancement,no-stale" + + # PR settings + stale-pr-message: | + This pull request has been automatically marked as stale because it has not had any activity for 14 days. + + It will be closed in 7 days if no further activity occurs. + + If this PR is still relevant, please: + - Rebase against the latest main branch + - Resolve any conflicts + - Address any review comments + - Comment on this PR to keep it open + + Thank you for your contributions! + close-pr-message: | + This pull request has been automatically closed due to inactivity. + + If you would like to continue with these changes, please: + 1. Rebase your branch against the latest main + 2. Open a new pull request + + Thank you for your understanding! + days-before-pr-stale: 14 + days-before-pr-close: 7 + stale-pr-label: "stale" + exempt-pr-labels: "pinned,security,work-in-progress,wip,no-stale" + + # General settings + operations-per-run: 100 + remove-stale-when-updated: true + ascending: true diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 993d1fce..00000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,218 +0,0 @@ -stages: - - test - - release - - sign - -variables: - CHART_REPO_PREFIX: cloudpirates - REGISTRY: $DOCKER_REGISTRY - REGISTRY_USER: $DOCKER_USER - REGISTRY_PASSWORD: $DOCKER_PASSWORD - -test-charts: - stage: test - image: alpine/helm:latest - before_script: - - apk add --no-cache git - - helm plugin install https://github.com/helm-unittest/helm-unittest - script: - - | - echo "Discovering helm charts with tests..." - - FAILED_CHARTS="" - PASSED_CHARTS="" - TESTED_CHARTS="" - - # Find all chart directories with Chart.yaml and tests directory - for chart_dir in charts/*/; do - if [[ -f "${chart_dir}Chart.yaml" ]]; then - chart_name=$(basename "$chart_dir") - - # Check if chart has a tests directory - if [[ -d "${chart_dir}tests" ]]; then - echo "================================" - echo "Testing chart: $chart_name" - echo "Chart path: $chart_dir" - echo "Tests directory found: ${chart_dir}tests" - echo "================================" - - TESTED_CHARTS="$TESTED_CHARTS $chart_name" - - # Update dependencies if Chart.yaml contains dependencies - cd "$chart_dir" - if grep -q "dependencies:" Chart.yaml; then - echo "Updating dependencies for $chart_name" - helm dependency update - fi - cd - > /dev/null - - if helm unittest "$chart_dir" --strict; then - echo "$chart_name PASSED" - PASSED_CHARTS="$PASSED_CHARTS $chart_name" - else - echo "$chart_name FAILED" - FAILED_CHARTS="$FAILED_CHARTS $chart_name" - fi - echo "" - else - echo "Skipping $chart_name (no tests directory found)" - fi - fi - done - - echo "================================" - echo "TEST SUMMARY" - echo "================================" - echo "Charts with tests:$TESTED_CHARTS" - echo "Passed charts:$PASSED_CHARTS" - - if [[ -z "$TESTED_CHARTS" ]]; then - echo "No charts with tests found" - exit 0 - elif [[ -n "$FAILED_CHARTS" ]]; then - echo "Failed charts:$FAILED_CHARTS" - echo "Some tests failed!" - exit 1 - else - echo "All charts with tests passed!" - fi - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - changes: - - charts/**/* - - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - changes: - - charts/**/* - -release-charts: - stage: release - image: alpine/helm:latest - before_script: - - apk add --no-cache git yq - - helm registry login --username ${REGISTRY_USER} --password ${REGISTRY_PASSWORD} ${REGISTRY} - needs: - - test-charts - script: - - | - echo "Detecting changed charts..." - - # Get list of changed files in the last commit - CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD || git ls-files charts/) - echo "Changed files: $CHANGED_FILES" - - # Find unique chart directories that have changes - CHANGED_CHARTS="" - for file in $CHANGED_FILES; do - if [[ "$file" == charts/* ]]; then - CHART_DIR=$(echo "$file" | cut -d'/' -f1-2) - if [[ -f "$CHART_DIR/Chart.yaml" ]]; then - CHANGED_CHARTS="$CHANGED_CHARTS $CHART_DIR" - fi - fi - done - - # Remove duplicates - CHANGED_CHARTS=$(echo "$CHANGED_CHARTS" | tr ' ' '\n' | sort -u | tr '\n' ' ') - - echo "Changed charts: $CHANGED_CHARTS" - - # Process each changed chart - RELEASED_CHARTS="" - for chart_path in $CHANGED_CHARTS; do - if [[ -n "$chart_path" && -f "$chart_path/Chart.yaml" ]]; then - chart_name=$(basename "$chart_path") - - echo "Processing chart: $chart_name at $chart_path" - cd "$chart_path" - - # Extract version and appVersion from Chart.yaml - CHART_VERSION=$(yq eval '.version' Chart.yaml) - APP_VERSION=$(yq eval '.appVersion' Chart.yaml) - - echo "Chart: $chart_name, Version: $CHART_VERSION, App Version: $APP_VERSION" - - # Update dependencies if Chart.yaml contains dependencies - if grep -q "dependencies:" Chart.yaml; then - echo "Updating dependencies for $chart_name" - helm dependency update - fi - - # Package the chart - echo "Packaging Helm chart $chart_name version $CHART_VERSION" - helm package . --version=$CHART_VERSION --app-version=$APP_VERSION - - # Push the chart to dynamic repository - CHART_REPO="${CHART_REPO_PREFIX}" - echo "Pushing Helm chart $chart_name-$CHART_VERSION.tgz to oci://$REGISTRY/$CHART_REPO" - - if helm push ${chart_name}-${CHART_VERSION}.tgz oci://${REGISTRY}/${CHART_REPO} 2>&1 | tee $CI_PROJECT_DIR/${chart_name}-output.log; then - # Extract digest for signing - DIGEST=$(cat $CI_PROJECT_DIR/${chart_name}-output.log | awk -F '[, ]+' '/Digest/{print $NF}') - echo "${chart_name}_VERSION=$CHART_VERSION" >> $CI_PROJECT_DIR/digest.env - echo "${chart_name}_DIGEST=$DIGEST" >> $CI_PROJECT_DIR/digest.env - - RELEASED_CHARTS="$RELEASED_CHARTS $chart_name" - echo "Successfully released $chart_name:$CHART_VERSION" - else - echo "Failed to push $chart_name:$CHART_VERSION" - cat $CI_PROJECT_DIR/${chart_name}-output.log - exit 1 - fi - - cd - > /dev/null - fi - done - - echo "RELEASED_CHARTS=$RELEASED_CHARTS" >> $CI_PROJECT_DIR/digest.env - - if [[ -z "$RELEASED_CHARTS" ]]; then - echo "No charts were released" - else - echo "Released charts: $RELEASED_CHARTS" - fi - artifacts: - expire_in: 24h - reports: - dotenv: digest.env - rules: - - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - changes: - - charts/**/Chart.yaml - -sign-charts: - stage: sign - image: harbor.cloudpirates.io/public/cosign:v2.4.2@sha256:4731b7f62d0a98236769dbb6f97543a66e25e46d5a35d46111248e7c0d628230 - variables: - GIT_STRATEGY: none - before_script: - - mkdir -p ~/.docker - - echo "{\"auths\":{\"$REGISTRY\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json - script: - - | - if [[ -z "$RELEASED_CHARTS" ]]; then - echo "No charts were released, nothing to sign" - exit 0 - fi - - echo "Signing charts: $RELEASED_CHARTS" - for chart_name in $RELEASED_CHARTS; do - VERSION_VAR="${chart_name}_VERSION" - DIGEST_VAR="${chart_name}_DIGEST" - - CHART_VERSION=$(eval echo \$$VERSION_VAR) - DIGEST=$(eval echo \$$DIGEST_VAR) - - if [[ -n "$DIGEST" && -n "$CHART_VERSION" ]]; then - CHART_REPO="${CHART_REPO_PREFIX}" - echo "Signing chart: $chart_name:$CHART_VERSION with digest: $DIGEST" - cosign sign --key env://COSIGN_KEY --tlog-upload=false ${REGISTRY}/${CHART_REPO}/${chart_name}:${CHART_VERSION}@$DIGEST - else - echo "Missing version or digest for chart: $chart_name (version: $CHART_VERSION, digest: $DIGEST)" - fi - done - needs: - - release-charts - rules: - - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - changes: - - charts/**/Chart.yaml \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df6176ef..db883d62 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,11 +6,23 @@ Hi there! We are thrilled that you'd like to contribute to this project. It's pe - [Code of Conduct](#code-of-conduct) - [How Can I Contribute?](#how-can-i-contribute) + - [Reporting Bugs](#reporting-bugs) + - [Suggesting Enhancements](#suggesting-enhancements) + - [Types of Contributions We're Looking For](#types-of-contributions-were-looking-for) - [Development Setup](#development-setup) + - [Prerequisites](#prerequisites) + - [Setting Up Your Development Environment](#setting-up-your-development-environment) - [Contributing Guidelines](#contributing-guidelines) -- [Chart Development Standards](#chart-development-standards) + - [Chart Development Standards](#chart-development-standards) + - [Chart Structure](#chart-structure) + - [Documentation Requirements](#documentation-requirements) + - [Versioning](#versioning) - [Testing](#testing) + - [Running Tests](#running-tests) + - [Test Requirements](#test-requirements) + - [Manual Testing](#manual-testing) - [Pull Request Process](#pull-request-process) + - [Pull Request Checklist](#pull-request-checklist) ## Code of Conduct @@ -22,21 +34,21 @@ This project and everyone participating in it is governed by our [Code of Conduc Before creating bug reports, please check the existing issues as you might find out that you don't need to create one. When you are creating a bug report, please include as many details as possible: -- **Use a clear and descriptive title** -- **Describe the exact steps to reproduce the problem** -- **Provide specific examples to demonstrate the steps** -- **Describe the behavior you observed and what behavior you expected** -- **Include details about your configuration and environment** +- Use a **clear and descriptive title** +- Describe the **exact steps to reproduce** the problem +- Provide **specific examples** to demonstrate the steps +- Describe the **behavior you observed** and what **behavior you expected** +- Include details about **your configuration and environment** ### Suggesting Enhancements Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion, please include: -- **Use a clear and descriptive title** -- **Provide a step-by-step description of the suggested enhancement** -- **Provide specific examples to demonstrate the steps** -- **Describe the current behavior and explain which behavior you expected to see** -- **Explain why this enhancement would be useful** +- Use a **clear and descriptive title** +- Provide a **step-by-step description** of the suggested enhancement +- Provide **specific examples** to demonstrate the steps +- Describe the **current behavior** and explain which **behavior you expected** to see +- Explain **why this enhancement would be useful** ### Types of Contributions We're Looking For @@ -52,21 +64,39 @@ Enhancement suggestions are tracked as GitHub issues. When creating an enhanceme - Kubernetes 1.24+ - Helm 3.2.0+ - [helm-unittest](https://github.com/helm-unittest/helm-unittest) plugin +- Commits verified by signature ### Setting Up Your Development Environment 1. Fork the repository on GitHub 2. Clone your fork locally: + ```bash git clone https://github.com/your-username/helm-charts.git cd helm-charts ``` 3. Install the helm-unittest plugin: + ```bash helm plugin install https://github.com/helm-unittest/helm-unittest ``` +4. Make sure to sign your commits + + ```bash + git config gpg.format ssh + git config user.signingkey + git config commit.gpgsign true + git config tag.gpgsign true + ``` + + Replace `` with the path to your public ssh key file, e.g. `~/.ssh/id_ed25519.pub`, wich you use to push to GitHub. + Alternatively, a signing ssh key can be used instead. + If you want to sign commits in every repository, not just this one, add the `--global` parameter. + + > More information: [GitHub docs](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) + ## Contributing Guidelines ### Chart Development Standards @@ -74,18 +104,21 @@ Enhancement suggestions are tracked as GitHub issues. When creating an enhanceme All charts in this repository must follow these standards: #### Security First + - Implement read-only root filesystems where possible - Drop unnecessary Linux capabilities - Configure security contexts properly - Never hardcode credentials #### Production Ready + - Include comprehensive health checks (liveness, readiness, startup probes) - Support resource requests and limits - Provide persistent storage configurations - Include health check endpoints #### Highly Configurable + - Provide extensive `values.yaml` with detailed documentation - Support existing secrets and ConfigMaps - Offer flexible ingress configurations @@ -144,7 +177,7 @@ All charts must include comprehensive tests. Run tests using: ```bash # Test all charts -./test-all-charts.sh +./test-charts.sh # Test individual chart helm dependency update charts/your-chart @@ -154,6 +187,7 @@ helm unittest charts/your-chart ### Test Requirements Your tests should cover: + - Template rendering with default values - Template rendering with custom values - Required value validation @@ -181,6 +215,7 @@ kubectl get all -n test ## Pull Request Process 1. **Branch**: Create a feature branch from `main` + ```bash git checkout -b feature/your-chart-improvement ``` @@ -188,14 +223,16 @@ kubectl get all -n test 2. **Development**: Make your changes following the guidelines above 3. **Testing**: Run all tests and ensure they pass + ```bash - ./test-all-charts.sh + ./test-charts.sh helm lint ./charts/your-chart ``` 4. **Documentation**: Update documentation as needed 5. **Commit**: Use clear, descriptive commit messages + ```bash git commit -m "[chart-name] Add support for custom annotations" ``` diff --git a/README.md b/README.md index 5d7b817c..3987662f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ + + + + + +

# CloudPirates Open Source Helm Charts @@ -11,23 +17,25 @@ This repository provides secure, well-documented, and configurable Helm charts f ## Available Charts -| Chart | Description | -| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -| [ClusterPirate](charts/clusterpirate/) | Client agent for the CloudPirates Managed Observability Platform to connect your Kubernetes cluster to our infrastructure | -| [Common](charts/common/) | A library chart for common templates and helper functions | -| [Ghost](charts/ghost/) | A simple, powerful publishing platform that allows you to share your stories with the world. | -| [Keycloak](charts/keycloak/) | Open Source Identity and Access Management solution | -| [MariaDB](charts/mariadb/) | High-performance, open-source relational database server that is a drop-in replacement for MySQL | -| [Memcached](charts/memcached/) | High-performance, distributed memory object caching system | -| [MinIO](charts/minio/) | High-Performance Object Storage compatible with Amazon S3 APIs | -| [MongoDB](charts/mongodb/) | MongoDB a flexible NoSQL database for scalable, real-time data management | -| [Nginx](charts/nginx/) | High-performance HTTP server and reverse proxy | -| [PostgreSQL](charts/postgres/) | The World's Most Advanced Open Source Relational Database | -| [RabbitMQ](charts/rabbitmq/) | A messaging broker that implements the Advanced Message Queuing Protocol (AMQP) | -| [Redis](charts/redis/) | In-memory data structure store, used as a database, cache, and message broker | -| [TimescaleDB](charts/timescaledb/) | TimescaleDB is a PostgreSQL extension for high-performance real-time analytics on time-series and event data | -| [Valkey](charts/valkey/) | High-performance in-memory data structure store, fork of Redis | -| [Zookeeper](charts/zookeeper/) | Centralized service for maintaining configuration information, naming, providing distributed synchronization, and group services | +| Chart | Description | Version | +| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [ClusterPirate](charts/clusterpirate/) | Client agent for the CloudPirates Managed Observability Platform to connect your Kubernetes cluster to our infrastructure | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/clusterpirate/Chart.yaml&label=&query=version&prefix=v) | +| [Common](charts/common/) | A library chart for common templates and helper functions | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/common/Chart.yaml&label=&query=version&prefix=v) | +| [Etcd](charts/etcd/) | A distributed reliable key-value store | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/etcd/Chart.yaml&label=&query=version&prefix=v) | +| [Ghost](charts/ghost/) | A simple, powerful publishing platform that allows you to share your stories with the world. | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/ghost/Chart.yaml&label=&query=version&prefix=v) | +| [Keycloak](charts/keycloak/) | Open Source Identity and Access Management solution | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/keycloak/Chart.yaml&label=&query=version&prefix=v) | +| [MariaDB](charts/mariadb/) | High-performance, open-source relational database server that is a drop-in replacement for MySQL | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/mariadb/Chart.yaml&label=&query=version&prefix=v) | +| [Memcached](charts/memcached/) | High-performance, distributed memory object caching system | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/memcached/Chart.yaml&label=&query=version&prefix=v) | +| [MinIO](charts/minio/) | High-Performance Object Storage compatible with Amazon S3 APIs | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/minio/Chart.yaml&label=&query=version&prefix=v) | +| [MongoDB](charts/mongodb/) | MongoDB a flexible NoSQL database for scalable, real-time data management | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/mongodb/Chart.yaml&label=&query=version&prefix=v) | +| [Nginx](charts/nginx/) | High-performance HTTP server and reverse proxy | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/nginx/Chart.yaml&label=&query=version&prefix=v) | +| [PostgreSQL](charts/postgres/) | The World's Most Advanced Open Source Relational Database | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/postgres/Chart.yaml&label=&query=version&prefix=v) | +| [RabbitMQ](charts/rabbitmq/) | A messaging broker that implements the Advanced Message Queuing Protocol (AMQP) | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/rabbitmq/Chart.yaml&label=&query=version&prefix=v) | +| [Redis](charts/redis/) | In-memory data structure store, used as a database, cache, and message broker | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/redis/Chart.yaml&label=&query=version&prefix=v) | +| [RustFS](charts/rustfs/) | High-performance distributed object storage with S3-compatible API (MinIO alternative) [ALPHA] | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/rustfs/Chart.yaml&label=&query=version&prefix=v) | +| [TimescaleDB](charts/timescaledb/) | TimescaleDB is a PostgreSQL extension for high-performance real-time analytics on time-series and event data | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/timescaledb/Chart.yaml&label=&query=version&prefix=v) | +| [Valkey](charts/valkey/) | High-performance in-memory data structure store, fork of Redis | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/valkey/Chart.yaml&label=&query=version&prefix=v) | +| [Zookeeper](charts/zookeeper/) | Centralized service for maintaining configuration information, naming, providing distributed synchronization, and group services | ![Version](https://img.shields.io/badge/dynamic/yaml?url=https://raw.githubusercontent.com/CloudPirates-io/helm-charts/main/charts/zookeeper/Chart.yaml&label=&query=version&prefix=v) | ## Quick Start @@ -54,7 +62,7 @@ helm install my-release ./charts/ All charts in this repository provide: -### ๐Ÿ”’ **Security First** +### **Security First** - **Cryptographically Signed**: All charts are signed with [Cosign](COSIGN.md) for supply chain security - Non-root containers by default @@ -63,7 +71,7 @@ All charts in this repository provide: - Security contexts configured - No hardcoded credentials -### ๐Ÿ“Š **Production Ready** +### **Production Ready** - Comprehensive health checks (liveness, readiness, startup probes) - Resource requests and limits support @@ -71,7 +79,7 @@ All charts in this repository provide: - Rolling update strategies - Health check endpoints -### ๐ŸŽ›๏ธ **Highly Configurable** +### **Highly Configurable** - Extensive values.yaml with detailed documentation - Support for existing secrets and ConfigMaps @@ -91,9 +99,16 @@ Each chart provides extensive configuration options through `values.yaml`. Key c Refer to individual chart READMEs for detailed configuration options. -## Contributing +## Get Involved + +Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. + +If you want to open a PR, read our [contributing guidelines](CONTRIBUTING.md) for information about setting up your environment and instructions on the signature verification that we require. + +Chat with us and the community on our [Discord server](https://discord.gg/XUn9Kt5dsy)!\ +Everyone is welcome, wether you have a question, need help with a chart, want to contribute, know what's coming next or just have a talk with us. -Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. If you want to open a pull request, please read the [contributing guidelines](CONTRIBUTING.md). +[![Discord](https://img.shields.io/discord/1426189195285762150?logo=discord&label=Discord)](https://discord.gg/XUn9Kt5dsy) **This project is built and maintained by our growing community of contributors!** diff --git a/TESTING.md b/TESTING.md index c596ad8c..acc9da31 100644 --- a/TESTING.md +++ b/TESTING.md @@ -17,7 +17,7 @@ helm plugin install https://github.com/helm-unittest/helm-unittest Use the provided test runner script to run tests for all charts: ```bash -./test-all-charts.sh +./test-charts.sh ``` This script will: diff --git a/charts/clusterpirate/.disable-unittest b/charts/clusterpirate/.disable-unittest new file mode 100644 index 00000000..aa617f45 --- /dev/null +++ b/charts/clusterpirate/.disable-unittest @@ -0,0 +1,2 @@ +# This file disables helm unittest for this chart +# The clusterpirate service depends on external services that are not reachable during testing diff --git a/charts/clusterpirate/CHANGELOG.md b/charts/clusterpirate/CHANGELOG.md index c067e73c..07dbac59 100644 --- a/charts/clusterpirate/CHANGELOG.md +++ b/charts/clusterpirate/CHANGELOG.md @@ -1,25 +1,95 @@ # Changelog -## 1.0.7 (2025-08-27) - -* Add logo and fix OCI reference for installation ([1e8bb7a](https://github.com/CloudPirates-io/helm-charts/commit/1e8bb7a)) -* add new helm chart ([65b66d8](https://github.com/CloudPirates-io/helm-charts/commit/65b66d8)) -* Fix README.md ([bc2bdea](https://github.com/CloudPirates-io/helm-charts/commit/bc2bdea)) -* Release version 1.0.1 ([2b46314](https://github.com/CloudPirates-io/helm-charts/commit/2b46314)) -* Trigger Release ([414545d](https://github.com/CloudPirates-io/helm-charts/commit/414545d)) -* Update default values ([ac5e69b](https://github.com/CloudPirates-io/helm-charts/commit/ac5e69b)) -* Update README and Chart.yaml descriptions ([5afa09c](https://github.com/CloudPirates-io/helm-charts/commit/5afa09c)) -* Update valkey dependency ([d430fe5](https://github.com/CloudPirates-io/helm-charts/commit/d430fe5)) -* Add ArtifactHub Badges to all Charts ([08b855b](https://github.com/CloudPirates-io/helm-charts/commit/08b855b)) -* Add ArtifactHub repo config ([15180a8](https://github.com/CloudPirates-io/helm-charts/commit/15180a8)) -* Add cosign signature READMEs ([5f82e7f](https://github.com/CloudPirates-io/helm-charts/commit/5f82e7f)) -* Add extensive chart testing ([a46efac](https://github.com/CloudPirates-io/helm-charts/commit/a46efac)) -* Add generated values.schema.json files from values.yaml ([aa79ac3](https://github.com/CloudPirates-io/helm-charts/commit/aa79ac3)) -* Add release pipeline ([ebd7277](https://github.com/CloudPirates-io/helm-charts/commit/ebd7277)) -* Fix image tag/digest handling ([a5c982b](https://github.com/CloudPirates-io/helm-charts/commit/a5c982b)) -* Fix imagePullSecrets format and pull always ([ce0d301](https://github.com/CloudPirates-io/helm-charts/commit/ce0d301)) -* Format README files ([04aacab](https://github.com/CloudPirates-io/helm-charts/commit/04aacab)) -* Release new chart versions / update sources ([dbb0e45](https://github.com/CloudPirates-io/helm-charts/commit/dbb0e45)) -* Remove leading $ from code blocks ([836b2e3](https://github.com/CloudPirates-io/helm-charts/commit/836b2e3)) -* Test Release of ClusterPirate ([b217adc](https://github.com/CloudPirates-io/helm-charts/commit/b217adc)) -* Update valkey Docker tag to v0.1.5 ([d3fd18d](https://github.com/CloudPirates-io/helm-charts/commit/d3fd18d)) + +## 1.2.9 (2025-11-04) + +* chore: update CHANGELOG.md for merged changes ([5cc4e82](https://github.com/CloudPirates-io/helm-charts/commit/5cc4e82)) +* chore: update CHANGELOG.md for merged changes ([8138b4a](https://github.com/CloudPirates-io/helm-charts/commit/8138b4a)) + +## 1.2.8 (2025-11-03) + + +## 1.2.7 (2025-10-31) + +* chore: update CHANGELOG.md for merged changes ([5686ce7](https://github.com/CloudPirates-io/helm-charts/commit/5686ce7)) +* chore: update CHANGELOG.md for merged changes ([20c99bd](https://github.com/CloudPirates-io/helm-charts/commit/20c99bd)) +* chore: update CHANGELOG.md for merged changes ([08e6bc1](https://github.com/CloudPirates-io/helm-charts/commit/08e6bc1)) +* chore: update CHANGELOG.md for merged changes ([5f5500a](https://github.com/CloudPirates-io/helm-charts/commit/5f5500a)) + +## 1.2.6 (2025-10-29) + +* chore: update CHANGELOG.md for merged changes ([82bee53](https://github.com/CloudPirates-io/helm-charts/commit/82bee53)) +* chore: update CHANGELOG.md for merged changes ([0a732be](https://github.com/CloudPirates-io/helm-charts/commit/0a732be)) +* chore: update CHANGELOG.md for merged changes ([4abe8c4](https://github.com/CloudPirates-io/helm-charts/commit/4abe8c4)) + +## 1.2.5 (2025-10-26) + +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 1.2.4 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([1053460](https://github.com/CloudPirates-io/helm-charts/commit/1053460)) +* chore: update CHANGELOG.md for merged changes ([6230965](https://github.com/CloudPirates-io/helm-charts/commit/6230965)) + +## 1.2.3 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 1.2.2 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([5187c4d](https://github.com/CloudPirates-io/helm-charts/commit/5187c4d)) +* chore: update CHANGELOG.md for merged changes ([bb0b090](https://github.com/CloudPirates-io/helm-charts/commit/bb0b090)) + +## 1.2.1 (2025-10-17) + +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([bf2e3b2](https://github.com/CloudPirates-io/helm-charts/commit/bf2e3b2)) +* chore: update CHANGELOG.md for merged changes ([2f87d0e](https://github.com/CloudPirates-io/helm-charts/commit/2f87d0e)) + +## 1.2.0 (2025-10-14) + +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 1.1.4 (2025-10-13) + +* chore: update CHANGELOG.md for merged changes ([9bfae89](https://github.com/CloudPirates-io/helm-charts/commit/9bfae89)) +* chore: update CHANGELOG.md for merged changes ([dc7faee](https://github.com/CloudPirates-io/helm-charts/commit/dc7faee)) + +## 1.1.3 (2025-10-13) + +* Fix clusterpirate (#372) ([e659f51](https://github.com/CloudPirates-io/helm-charts/commit/e659f51)) + +## 1.1.2 (2025-10-13) + +* Fix formatting (#371) ([cf4670a](https://github.com/CloudPirates-io/helm-charts/commit/cf4670a)) +* Bugfix/lint workflow (#365) ([adeac21](https://github.com/CloudPirates-io/helm-charts/commit/adeac21)) + +## 1.1.1 (2025-10-13) + +* Bugfix/lint workflow (#363) ([ce5c550](https://github.com/CloudPirates-io/helm-charts/commit/ce5c550)) +* Bugfix/lint workflow (#362) ([bbf7bd5](https://github.com/CloudPirates-io/helm-charts/commit/bbf7bd5)) + +## 1.1.0 (2025-10-13) + +* Bump dependencies (#357) ([c2909cd](https://github.com/CloudPirates-io/helm-charts/commit/c2909cd)) + +## 1.0.7 (2025-08-27) + +* Fix linting for values.yaml ([504ac61](https://github.com/CloudPirates-io/helm-charts/commit/504ac61)) +* Fix values.yaml / Chart.yaml linting issues ([043c7e0](https://github.com/CloudPirates-io/helm-charts/commit/043c7e0)) +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 1.0.6 (2025-08-26) + +* Initial tagged release diff --git a/charts/clusterpirate/Chart.lock b/charts/clusterpirate/Chart.lock index 48503674..67c2ff24 100644 --- a/charts/clusterpirate/Chart.lock +++ b/charts/clusterpirate/Chart.lock @@ -1,9 +1,9 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.0.0 + version: 2.0.0 - name: valkey repository: oci://registry-1.docker.io/cloudpirates - version: 0.1.5 -digest: sha256:20b766f851e5333f32bae40eb761424ec9e43e02141127defd9037e3c112cb2c -generated: "2025-08-14T11:33:42.043028181Z" + version: 0.9.2 +digest: sha256:f2091174754807696e0633286f5498061b7816d8084e3161bcbb19d05b455ef6 +generated: "2025-11-04T10:17:14.827792567Z" diff --git a/charts/clusterpirate/Chart.yaml b/charts/clusterpirate/Chart.yaml index f1dc0010..f6ef6a4f 100644 --- a/charts/clusterpirate/Chart.yaml +++ b/charts/clusterpirate/Chart.yaml @@ -2,29 +2,42 @@ apiVersion: v2 name: clusterpirate description: Client agent for the CloudPirates Managed Observability Platform to connect your Kubernetes cluster to our infrastructure type: application -version: 1.0.7 +version: 1.2.9 appVersion: "1.0.1" - keywords: - kubernetes - clusterpirate - cloudpirates - observability - agent - home: https://www.cloudpirates.io - +sources: + - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/clusterpirate maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io - dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates - name: valkey - version: "0.1.5" + version: "0.9.2" repository: oci://registry-1.docker.io/cloudpirates condition: valkey.enabled - icon: https://a.storyblok.com/f/143071/512x512/88dc07809a/cluster-pirate-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: monitoring-logging + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/clusterpirate + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Chart updated" diff --git a/charts/clusterpirate/ci/default-values.yaml b/charts/clusterpirate/ci/default-values.yaml new file mode 100644 index 00000000..10f03ce7 --- /dev/null +++ b/charts/clusterpirate/ci/default-values.yaml @@ -0,0 +1,17 @@ +# CI test values for clusterpirate chart +# This file provides minimal required configuration for chart testing + +auth: + # Provide a test access token for CI testing + accessToken: "test-token-for-ci-only" + +# Disable Valkey dependency for faster CI testing +valkey: + enabled: false + +# Configure cache to not require Valkey +clusterPirate: + metrics: + cache: + host: "localhost" + password: "" diff --git a/charts/clusterpirate/templates/_helpers.tpl b/charts/clusterpirate/templates/_helpers.tpl index ec338207..7dae35ae 100644 --- a/charts/clusterpirate/templates/_helpers.tpl +++ b/charts/clusterpirate/templates/_helpers.tpl @@ -2,7 +2,7 @@ Expand the name of the chart. */}} {{- define "clusterpirate.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* @@ -11,35 +11,35 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "clusterpirate.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Common labels */}} {{- define "clusterpirate.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Common annotations */}} {{- define "clusterpirate.annotations" -}} -{{- include "common.annotations" . }} +{{- include "cloudpirates.annotations" . }} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "clusterpirate.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* Selector labels */}} {{- define "clusterpirate.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* @@ -62,5 +62,5 @@ release: {{ .Release.Name }} Return the proper ClusterPirate image name */}} {{- define "clusterpirate.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} \ No newline at end of file diff --git a/charts/clusterpirate/templates/deployment.yaml b/charts/clusterpirate/templates/deployment.yaml index b0f140a7..b093d278 100644 --- a/charts/clusterpirate/templates/deployment.yaml +++ b/charts/clusterpirate/templates/deployment.yaml @@ -29,7 +29,7 @@ spec: containers: - name: {{ include "clusterpirate.fullname" . }} image: {{ include "clusterpirate.image" . }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} resources: {{ toYaml .Values.deployment.resources | indent 10 }} {{- if .Values.deployment.probes.livenessProbe.enabled }} @@ -98,6 +98,7 @@ spec: configMapKeyRef: name: {{ include "clusterpirate.fullname" . }} key: valkeyTtl + {{- if or .Values.valkey.enabled .Values.clusterPirate.metrics.cache.password }} - name: VALKEY_PASSWORD valueFrom: secretKeyRef: @@ -107,13 +108,17 @@ spec: key: password {{- else if .Values.valkey.auth.existingSecret }} # Use existing secret specified for Valkey - name: {{ .Values.valkey.auth.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.valkey.auth.existingSecret "context" .) }} key: {{ .Values.valkey.auth.existingSecretPasswordKey | default "password" }} {{- else if .Values.clusterPirate.metrics.cache.password }} # Use password from ClusterPirate cache config (external Valkey) name: {{ include "clusterpirate.fullname" . }} key: valkeyPassword {{- end }} + {{- else }} + - name: VALKEY_PASSWORD + value: "" + {{- end }} - name: MONITORING_RESOURCE_EVENTS_ENABLED valueFrom: configMapKeyRef: @@ -133,7 +138,7 @@ spec: valueFrom: secretKeyRef: {{- if .Values.auth.existingSecret }} - name: {{ .Values.auth.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) }} key: {{ .Values.auth.existingSecretAccessTokenKey | default "accessToken" }} {{- else }} name: {{ include "clusterpirate.fullname" . }} diff --git a/charts/clusterpirate/values.schema.json b/charts/clusterpirate/values.schema.json index 536e64ec..1ee14e11 100644 --- a/charts/clusterpirate/values.schema.json +++ b/charts/clusterpirate/values.schema.json @@ -1,458 +1,253 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "ClusterPirate Helm Chart Values Schema", - "description": "Schema for ClusterPirate Helm chart values", - "properties": { - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Common labels applied to all resources", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Common annotations applied to all resources", - "additionalProperties": { - "type": "string" - } - }, - "imagePullSecrets": { - "type": "array", - "title": "Image Pull Secrets", - "description": "Registry secret names as an array of objects", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - }, - "image": { - "type": "object", - "title": "ClusterPirate Image Configuration", - "description": "Container image settings for ClusterPirate", - "properties": { - "registry": { - "type": "string", - "title": "Image Registry", - "description": "ClusterPirate image registry" - }, - "repository": { - "type": "string", - "title": "Image Repository", - "description": "ClusterPirate image repository" - }, - "tag": { - "type": "string", - "title": "Image Tag", - "description": "ClusterPirate image tag with digest" - }, - "imagePullPolicy": { - "type": "string", - "title": "Image Pull Policy", - "description": "ClusterPirate image pull policy", - "enum": [ - "Always", - "Never", - "IfNotPresent" - ] - } - } - }, - "deployment": { - "type": "object", - "title": "Deployment Configuration", - "description": "Configuration for the ClusterPirate deployment", - "properties": { - "resources": { - "type": "object", - "title": "Pod Resource Configuration", - "description": "Pod resource limits and requests", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ], - "title": "CPU Limit", - "description": "CPU resource limit" + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "auth": { + "type": "object", + "properties": { + "accessToken": { + "type": "string" }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" - } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ], - "title": "CPU Request", - "description": "CPU resource request" + "existingSecret": { + "type": "string" }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + "existingSecretAccessTokenKey": { + "type": "string" } - } } - } }, - "extraEnvVars": { - "type": "array", - "title": "Extra Environment Variables", - "description": "Additional environment variables", - "items": { + "cloudpiratesApi": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Variable Name", - "description": "Environment variable name" - }, - "value": { - "type": "string", - "title": "Variable Value", - "description": "Environment variable value" - }, - "valueFrom": { - "type": "object", - "title": "Value From", - "description": "Source for the environment variable value" - } - }, - "required": [ - "name" - ] - } + "registerEndpoint": { + "type": "string" + } + } }, - "probes": { - "type": "object", - "title": "Health Probe Configuration", - "description": "Health probe settings", - "properties": { - "livenessProbe": { - "type": "object", - "title": "Liveness Probe", - "description": "Liveness probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable liveness probe" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for liveness probe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for liveness probe", - "minimum": 1 + "clusterPirate": { + "type": "object", + "properties": { + "healthPort": { + "type": "integer" }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for liveness probe", - "minimum": 1 + "logLevel": { + "type": "string" }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for liveness probe", - "minimum": 1 + "metrics": { + "type": "object", + "properties": { + "cache": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "password": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "ttl": { + "type": "integer" + } + } + }, + "enabled": { + "type": "boolean" + }, + "updateIntervalSeconds": { + "type": "integer" + } + } }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for liveness probe", - "minimum": 1 + "monitoring": { + "type": "object", + "properties": { + "resourceEventsEnabled": { + "type": "boolean" + }, + "systemEventsEnabled": { + "type": "boolean" + } + } } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe", - "description": "Readiness probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readiness probe" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for readiness probe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for readiness probe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for readiness probe", - "minimum": 1 + } + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "deployment": { + "type": "object", + "properties": { + "extraEnvVars": { + "type": "array" }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for readiness probe", - "minimum": 1 + "probes": { + "type": "object", + "properties": { + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + } + } }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for readiness probe", - "minimum": 1 + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } } - } } - } - } - } - }, - "clusterPirate": { - "type": "object", - "title": "ClusterPirate Application Configuration", - "description": "ClusterPirate specific configuration", - "properties": { - "logLevel": { - "type": "string", - "title": "Log Level", - "description": "Application logging level", - "enum": [ - "debug", - "info", - "warn", - "error", - "fatal" - ] }, - "healthPort": { - "type": "integer", - "title": "Health Port", - "description": "Health check server port", - "minimum": 1, - "maximum": 65535 + "fullnameOverride": { + "type": "string" }, - "metrics": { - "type": "object", - "title": "Metrics Configuration", - "description": "Metrics collection configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Metrics", - "description": "Enable/disable metrics collection" - }, - "updateIntervalSeconds": { - "type": "integer", - "title": "Update Interval", - "description": "Interval in seconds for metrics updates", - "minimum": 1 - }, - "cache": { - "type": "object", - "title": "Cache Configuration", - "description": "Metrics caching configuration using Valkey", - "properties": { - "host": { - "type": "string", - "title": "Valkey Host", - "description": "Valkey server hostname or IP address" - }, - "port": { - "type": "integer", - "title": "Valkey Port", - "description": "Valkey server port", - "minimum": 1, - "maximum": 65535 - }, - "password": { - "type": "string", - "title": "Valkey Password", - "description": "Valkey authentication password" + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" }, - "ttl": { - "type": "integer", - "title": "Cache TTL", - "description": "Time-to-live for cached metrics in seconds", - "minimum": 1 + "imageRegistry": { + "type": "string" } - } } - } }, - "monitoring": { - "type": "object", - "title": "Monitoring Configuration", - "description": "Kubernetes resource monitoring configuration", - "properties": { - "resourceEventsEnabled": { - "type": "boolean", - "title": "Enable Resource Events", - "description": "Enable monitoring of Kubernetes resources" - }, - "systemEventsEnabled": { - "type": "boolean", - "title": "Enable System Events", - "description": "Enable monitoring of Kubernetes system events" + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } } - } - } - } - }, - "cloudpiratesApi": { - "type": "object", - "title": "CloudPirates API Configuration", - "description": "CloudPirates API settings", - "properties": { - "registerEndpoint": { - "type": "string", - "title": "Register Endpoint", - "description": "API endpoint for cluster registration", - "format": "uri" - } - } - }, - "auth": { - "type": "object", - "title": "Authentication Configuration", - "description": "Authentication settings", - "properties": { - "accessToken": { - "type": "string", - "title": "Access Token", - "description": "Inline access token" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret containing the access token" }, - "existingSecretAccessTokenKey": { - "type": "string", - "title": "Existing Secret Access Token Key", - "description": "Key within the existing secret that contains the access token" - } - } - }, - "rbac": { - "type": "object", - "title": "RBAC Configuration", - "description": "RBAC settings", - "properties": { - "create": { - "type": "boolean", - "title": "Create RBAC", - "description": "Whether to create RBAC resources" - } - } - }, - "serviceAccount": { - "type": "object", - "title": "Service Account Configuration", - "description": "Service account settings", - "properties": { - "create": { - "type": "boolean", - "title": "Create Service Account", - "description": "Whether to create a service account" + "nameOverride": { + "type": "string" }, - "name": { - "type": "string", - "title": "Service Account Name", - "description": "Name of the service account to create or use" - } - } - }, - "valkey": { - "type": "object", - "title": "Valkey Configuration", - "description": "Valkey dependency configuration", - "additionalProperties": true, - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Valkey", - "description": "Enable/disable Valkey installation as a dependency" + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + } + } }, - "persistence": { - "type": "object", - "title": "Valkey persistence settings", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable persistence" + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } } - } }, - "auth": { - "type": "object", - "title": "Valkey Authentication", - "description": "Valkey authentication configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Auth", - "description": "Enable/disable password authentication for Valkey" - }, - "password": { - "type": "string", - "title": "Password", - "description": "Valkey password" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret containing the Valkey password" - }, - "existingSecretPasswordKey": { - "type": "string", - "title": "Existing Secret Password Key", - "description": "Key within the existing secret that contains the password" + "valkey": { + "type": "object", + "properties": { + "auth": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "existingSecretPasswordKey": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "enabled": { + "type": "boolean" + }, + "persistence": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + } } - } } - } } - } -} \ No newline at end of file +} diff --git a/charts/common/CHANGELOG.md b/charts/common/CHANGELOG.md index 53edbc01..90cf3fd5 100644 --- a/charts/common/CHANGELOG.md +++ b/charts/common/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog -## 1.1.1 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +## 2.0.0 (2025-10-14) + +* rename templates from common.* to cloudpirates.* to prevent collisions (#377) ([07c6560](https://github.com/CloudPirates-io/helm-charts/commit/07c6560)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) + +## 1.1.2 (2025-10-10) + +* feat: add "common.namespace", defaults to .Release.Namespaceโ€ฆ (#323) ([951745c](https://github.com/CloudPirates-io/helm-charts/commit/951745c)) + +## 1.1.1 (2025-09-26) + +* apply intend where the helper is used (#168) ([efafd32](https://github.com/CloudPirates-io/helm-charts/commit/efafd32)) + +## 1.1.0 (2025-09-26) + +* Fix/set securitycontext based on targetplatform to comply with openshift clusters (#166) ([f1bb75e](https://github.com/CloudPirates-io/helm-charts/commit/f1bb75e)) + +## 1.0.0 (2025-08-26) + +* Initial tagged release diff --git a/charts/common/Chart.yaml b/charts/common/Chart.yaml index 7993fc38..214e4c76 100644 --- a/charts/common/Chart.yaml +++ b/charts/common/Chart.yaml @@ -2,14 +2,14 @@ apiVersion: v2 name: common description: A library chart for common templates and helper functions type: library -version: 1.1.1 -appVersion: "1.0.0" - +version: 2.0.0 +appVersion: "2.0.0" home: https://www.cloudpirates.io - sources: - - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mariadb - + - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/common maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io +annotations: + license: Apache-2.0 \ No newline at end of file diff --git a/charts/common/templates/_helpers.tpl b/charts/common/templates/_helpers.tpl index 4a37405a..005b0778 100644 --- a/charts/common/templates/_helpers.tpl +++ b/charts/common/templates/_helpers.tpl @@ -1,7 +1,7 @@ {{/* Expand the name of the chart. */}} -{{- define "common.name" -}} +{{- define "cloudpirates.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} @@ -10,7 +10,7 @@ Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} -{{- define "common.fullname" -}} +{{- define "cloudpirates.fullname" -}} {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} {{- else }} @@ -23,19 +23,28 @@ If release name contains chart name it will be used as a full name. {{- end }} {{- end }} +{{/* +Return the namespace to use for resources. +Defaults to .Release.Namespace but can be overridden via .Values.namespaceOverride. +Useful for multi-namespace deployments in combined charts. +*/}} +{{- define "cloudpirates.namespace" -}} +{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + {{/* Create chart name and version as used by the chart label. */}} -{{- define "common.chart" -}} +{{- define "cloudpirates.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Common labels */}} -{{- define "common.labels" -}} -helm.sh/chart: {{ include "common.chart" . }} -{{ include "common.selectorLabels" . }} +{{- define "cloudpirates.labels" -}} +helm.sh/chart: {{ include "cloudpirates.chart" . }} +{{ include "cloudpirates.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} @@ -48,15 +57,15 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} {{/* Selector labels */}} -{{- define "common.selectorLabels" -}} -app.kubernetes.io/name: {{ include "common.name" . }} +{{- define "cloudpirates.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cloudpirates.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* Common annotations */}} -{{- define "common.annotations" -}} +{{- define "cloudpirates.annotations" -}} {{- with .Values.commonAnnotations }} {{ toYaml . }} {{- end }} @@ -65,7 +74,7 @@ Common annotations {{/* Return the proper image name with registry and tag (tag includes digest if present) */}} -{{- define "common.image" -}} +{{- define "cloudpirates.image" -}} {{- $registryName := .image.registry -}} {{- $repositoryName := .image.repository -}} {{- $tag := .image.tag | toString -}} @@ -84,14 +93,14 @@ Return the proper image name with registry and tag (tag includes digest if prese {{/* Return the proper image pull policy */}} -{{- define "common.imagePullPolicy" -}} +{{- define "cloudpirates.imagePullPolicy" -}} {{- .image.imagePullPolicy | default .image.pullPolicy | default "Always" -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} -{{- define "common.imagePullSecrets" -}} +{{- define "cloudpirates.imagePullSecrets" -}} {{- $pullSecrets := list }} {{- if .global }} @@ -127,7 +136,7 @@ imagePullSecrets: {{/* Validate required fields */}} -{{- define "common.validateRequired" -}} +{{- define "cloudpirates.validateRequired" -}} {{- $context := index . 0 -}} {{- $field := index . 1 -}} {{- $message := index . 2 -}} @@ -139,7 +148,7 @@ Validate required fields {{/* Return a soft nodeAffinity definition */}} -{{- define "common.affinities.nodes.soft" -}} +{{- define "cloudpirates.affinities.nodes.soft" -}} {{- $key := index . 0 -}} {{- $values := index . 1 -}} preferredDuringSchedulingIgnoredDuringExecution: @@ -157,7 +166,7 @@ preferredDuringSchedulingIgnoredDuringExecution: {{/* Return a hard nodeAffinity definition */}} -{{- define "common.affinities.nodes.hard" -}} +{{- define "cloudpirates.affinities.nodes.hard" -}} {{- $key := index . 0 -}} {{- $values := index . 1 -}} requiredDuringSchedulingIgnoredDuringExecution: @@ -174,13 +183,13 @@ requiredDuringSchedulingIgnoredDuringExecution: {{/* Return a soft podAffinity/podAntiAffinity definition */}} -{{- define "common.affinities.pods.soft" -}} +{{- define "cloudpirates.affinities.pods.soft" -}} {{- $component := index . 0 -}} {{- $context := index . 1 -}} preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: - matchLabels: {{- (include "common.selectorLabels" $context) | nindent 10 }} + matchLabels: {{- (include "cloudpirates.selectorLabels" $context) | nindent 10 }} {{- if $component }} app.kubernetes.io/component: {{ $component }} {{- end }} @@ -191,12 +200,12 @@ preferredDuringSchedulingIgnoredDuringExecution: {{/* Return a hard podAffinity/podAntiAffinity definition */}} -{{- define "common.affinities.pods.hard" -}} +{{- define "cloudpirates.affinities.pods.hard" -}} {{- $component := index . 0 -}} {{- $context := index . 1 -}} requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: - matchLabels: {{- (include "common.selectorLabels" $context) | nindent 8 }} + matchLabels: {{- (include "cloudpirates.selectorLabels" $context) | nindent 8 }} {{- if $component }} app.kubernetes.io/component: {{ $component }} {{- end }} @@ -206,7 +215,7 @@ requiredDuringSchedulingIgnoredDuringExecution: {{/* Render a value that contains template perhaps */}} -{{- define "common.tplvalues.render" -}} +{{- define "cloudpirates.tplvalues.render" -}} {{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }} {{- if contains "{{" (toString $value) }} {{- tpl $value .context }} @@ -217,26 +226,26 @@ Render a value that contains template perhaps {{/* Return the proper Docker Image Registry Secret Names evaluating values as templates -{{ include "common.images.renderPullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "context" $) }} +{{ include "cloudpirates.images.renderPullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "context" $) }} */}} -{{- define "common.images.renderPullSecrets" -}} +{{- define "cloudpirates.images.renderPullSecrets" -}} {{- $pullSecrets := list }} {{- $context := .context }} {{- range (($context.Values.global).imagePullSecrets) -}} {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} + {{- $pullSecrets = append $pullSecrets (include "cloudpirates.tplvalues.render" (dict "value" .name "context" $context)) -}} {{- else -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- $pullSecrets = append $pullSecrets (include "cloudpirates.tplvalues.render" (dict "value" . "context" $context)) -}} {{- end -}} {{- end -}} {{- range .images -}} {{- range .pullSecrets -}} {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} + {{- $pullSecrets = append $pullSecrets (include "cloudpirates.tplvalues.render" (dict "value" .name "context" $context)) -}} {{- else -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- $pullSecrets = append $pullSecrets (include "cloudpirates.tplvalues.render" (dict "value" . "context" $context)) -}} {{- end -}} {{- end -}} {{- end -}} @@ -251,9 +260,9 @@ imagePullSecrets: {{/* Detect if the target platform is OpenShift (via .Values.targetPlatform or API group). -Usage: {{ include "common.isOpenshift" . }} +Usage: {{ include "cloudpirates.isOpenshift" . }} */}} -{{- define "common.isOpenshift" -}} +{{- define "cloudpirates.isOpenshift" -}} {{- if or (eq (lower (default "" .Values.targetPlatform)) "openshift") (.Capabilities.APIVersions.Has "route.openshift.io/v1") -}} true {{- else -}} @@ -263,10 +272,10 @@ false {{/* Render podSecurityContext, omitting runAsUser, runAsGroup, fsGroup, and seLinuxOptions if OpenShift is detected. -Usage: {{ include "common.renderPodSecurityContext" . }} +Usage: {{ include "cloudpirates.renderPodSecurityContext" . }} */}} -{{- define "common.renderPodSecurityContext" -}} -{{- $isOpenshift := include "common.isOpenshift" . | trim }} +{{- define "cloudpirates.renderPodSecurityContext" -}} +{{- $isOpenshift := include "cloudpirates.isOpenshift" . | trim }} {{- if eq $isOpenshift "true" }} {{- omit .Values.podSecurityContext "runAsUser" "runAsGroup" "fsGroup" "seLinuxOptions" | toYaml }} {{- else }} @@ -276,10 +285,10 @@ Usage: {{ include "common.renderPodSecurityContext" . }} {{/* Render containerSecurityContext, omitting runAsUser, runAsGroup, and seLinuxOptions if OpenShift is detected. -Usage: {{ include "common.renderContainerSecurityContext" . }} +Usage: {{ include "cloudpirates.renderContainerSecurityContext" . }} */}} -{{- define "common.renderContainerSecurityContext" -}} -{{- $isOpenshift := include "common.isOpenshift" . | trim }} +{{- define "cloudpirates.renderContainerSecurityContext" -}} +{{- $isOpenshift := include "cloudpirates.isOpenshift" . | trim }} {{- if eq $isOpenshift "true" }} {{- omit .Values.containerSecurityContext "runAsUser" "runAsGroup" "seLinuxOptions" | toYaml }} {{- else }} diff --git a/charts/etcd/CHANGELOG.md b/charts/etcd/CHANGELOG.md new file mode 100644 index 00000000..24884370 --- /dev/null +++ b/charts/etcd/CHANGELOG.md @@ -0,0 +1,58 @@ +# Changelog + + +## 0.3.1 (2025-10-28) + +* [etcd, rabbitmq, redis, zookeeper] add signature verification documentation to readme (#476) ([91c7310](https://github.com/CloudPirates-io/helm-charts/commit/91c7310)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.3.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.2.3 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.2.2 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([c80ea42](https://github.com/CloudPirates-io/helm-charts/commit/c80ea42)) +* chore: update CHANGELOG.md for merged changes ([8ccb4bb](https://github.com/CloudPirates-io/helm-charts/commit/8ccb4bb)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.2.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.1.3 (2025-10-13) + + +## 0.1.2 (2025-10-13) + +* update helm-chart icon (#360) ([6544ddf](https://github.com/CloudPirates-io/helm-charts/commit/6544ddf)) + +## 0.1.1 (2025-10-10) + +* artifact hub repository id (#333) ([36ca7c7](https://github.com/CloudPirates-io/helm-charts/commit/36ca7c7)) +* [etcd]: Invalid repo used (#331) ([92617cf](https://github.com/CloudPirates-io/helm-charts/commit/92617cf)) + +## 0.1.0 (2025-10-10) + +* Initial tagged release diff --git a/charts/etcd/Chart.lock b/charts/etcd/Chart.lock new file mode 100644 index 00000000..5658cae6 --- /dev/null +++ b/charts/etcd/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: oci://registry-1.docker.io/cloudpirates + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:03.850244+02:00" diff --git a/charts/etcd/Chart.yaml b/charts/etcd/Chart.yaml new file mode 100644 index 00000000..ba6e8cf2 --- /dev/null +++ b/charts/etcd/Chart.yaml @@ -0,0 +1,47 @@ +apiVersion: v2 +name: etcd +description: etcd is a distributed reliable key-value store for the most critical data of a distributed system +type: application +version: 0.3.1 +appVersion: "3.6.5" +keywords: + - etcd + - distributed + - key-value + - consensus + - raft +home: https://etcd.io/ +sources: + - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mariadb + - https://github.com/etcd-io/etcd +maintainers: + - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io + url: https://www.cloudpirates.io +dependencies: + - name: common + version: "2.x.x" + repository: oci://registry-1.docker.io/cloudpirates +icon: https://a.storyblok.com/f/143071/513x513/36b7a72378/etcd-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: etcd + url: https://etcd.io/ + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mariadb + - name: Application + url: https://github.com/etcd-io/etcd + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "[etcd, rabbitmq, redis, zookeeper] add signature verification documentation to readme (#476)" + links: + - name: "Commit 91c7310" + url: "https://github.com/CloudPirates-io/helm-charts/commit/91c7310" diff --git a/charts/etcd/LICENSE b/charts/etcd/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/charts/etcd/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/etcd/README.md b/charts/etcd/README.md new file mode 100644 index 00000000..ec71a223 --- /dev/null +++ b/charts/etcd/README.md @@ -0,0 +1,284 @@ +

+ +

+ +# etcd Helm Chart + +etcd is a distributed reliable key-value store for the most critical data of a distributed system, with a focus on being simple, secure, fast, and reliable. + +## Quick Start + +### Prerequisites + +- Kubernetes 1.24+ +- Helm 3.2.0+ +- PV provisioner support in the underlying infrastructure (if persistence is enabled) + +### Installation + +To install the chart with the release name `my-etcd`: + +```bash +helm install my-etcd oci://registry-1.docker.io/cloudpirates/etcd +``` + +To install with custom values: + +```bash +helm install my-etcd oci://registry-1.docker.io/cloudpirates/etcd -f my-values.yaml +``` + +Or install directly from the local chart: + +```bash +helm install my-etcd ./charts/etcd +``` + +### Getting Started + +1. Check the status of your etcd cluster: + +```bash +kubectl exec -it my-etcd-0 -- etcdctl \ + --endpoints=my-etcd:2379 \ + endpoint health +``` + +2. Connect to etcd from inside the cluster: + +```bash +kubectl run etcd-client --rm --tty -i --restart='Never' \ + --image gcr.io/etcd-development/etcd:v3.6.0-alpha.0 -- bash + +# Inside the pod: +etcdctl --endpoints=my-etcd:2379 endpoint status --write-out=table +``` + +## Security & Signature Verification + +This Helm chart is cryptographically signed with Cosign to ensure authenticity and prevent tampering. + +**Public Key:** + +``` +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7BgqFgKdPtHdXz6OfYBklYwJgGWQ +mZzYz8qJ9r6QhF3NxK8rD2oG7Bk6nHJz7qWXhQoU2JvJdI3Zx9HGpLfKvw== +-----END PUBLIC KEY----- +``` + +To verify the helm chart before installation, copy the public key to the file `cosign.pub` and run cosign: + +```bash +cosign verify --key cosign.pub registry-1.docker.io/cloudpirates/etcd: +``` + +## Configuration + +### Image Configuration + +| Parameter | Description | Default | +| ------------------------- | ------------------------------------- | ----------------------- | +| `image.registry` | etcd image registry | `gcr.io` | +| `image.repository` | etcd image repository | `etcd-development/etcd` | +| `image.tag` | etcd image tag | `v3.6.0-alpha.0` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `global.imageRegistry` | Global Docker image registry override | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names | `[]` | + +### Common Parameters + +| Parameter | Description | Default | +| ------------------- | ----------------------------------------------- | ------- | +| `nameOverride` | String to partially override etcd.fullname | `""` | +| `fullnameOverride` | String to fully override etcd.fullname | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `replicaCount` | Number of etcd replicas to deploy (must be odd) | `3` | +| `podLabels` | Additional labels for etcd pods | `{}` | +| `podAnnotations` | Additional annotations for etcd pods | `{}` | + +### Service Configuration + +| Parameter | Description | Default | +| --------------------- | ----------------------- | ----------- | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.annotations` | Service annotations | `{}` | +| `service.clientPort` | etcd client port | `2379` | +| `service.peerPort` | etcd peer port | `2380` | +| `service.metricsPort` | etcd metrics port | `2381` | + +### Authentication and Security + +| Parameter | Description | Default | +| -------------------------- | ------------------------------------------------------ | ------- | +| `auth.enabled` | Enable client-to-server TLS authentication | `false` | +| `auth.existingSecret` | Name of existing secret containing client certificates | `""` | +| `auth.peer.enabled` | Enable peer-to-peer TLS authentication | `false` | +| `auth.peer.existingSecret` | Name of existing secret containing peer certificates | `""` | + +### etcd Configuration + +| Parameter | Description | Default | +| -------------------------------- | -------------------------------------------------- | -------------- | +| `config.initialClusterState` | Initial cluster state (new or existing) | `new` | +| `config.autoCompactionMode` | Auto compaction mode (periodic or revision) | `periodic` | +| `config.autoCompactionRetention` | Auto compaction retention | `1` | +| `config.snapshotCount` | Number of transactions to trigger a snapshot | `10000` | +| `config.quotaBackendBytes` | Backend storage quota in bytes (2GB) | `2147483648` | +| `config.maxRequestBytes` | Maximum client request size in bytes | `1572864` | +| `config.logLevel` | Log level (debug, info, warn, error, panic, fatal) | `info` | +| `config.initialClusterToken` | Initial cluster token | `etcd-cluster` | +| `config.heartbeatInterval` | Heartbeat interval in milliseconds | `100` | +| `config.electionTimeout` | Election timeout in milliseconds | `1000` | +| `config.maxSnapshots` | Maximum number of snapshot files to retain | `5` | +| `config.maxWals` | Maximum number of WAL files to retain | `5` | +| `config.listenPeerIp` | IP address to bind for peer traffic | `0.0.0.0` | +| `config.listenClientIp` | IP address to bind for client traffic | `0.0.0.0` | + +### Persistence + +| Parameter | Description | Default | +| -------------------------- | ------------------------------ | ----------------- | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.storageClass` | Storage class of backing PVC | `""` | +| `persistence.annotations` | Annotations for the PVC | `{}` | +| `persistence.size` | Size of data volume | `8Gi` | +| `persistence.accessModes` | Persistent Volume Access Modes | `[ReadWriteOnce]` | +| `persistence.mountPath` | Mount path for data volume | `/var/run/etcd` | + +### Resources + +| Parameter | Description | Default | +| ----------- | ----------------------------------- | ------- | +| `resources` | CPU/Memory resource requests/limits | `{}` | + +### StatefulSet Configuration + +| Parameter | Description | Default | +| --------------------- | --------------------------- | --------------- | +| `updateStrategy.type` | StatefulSet update strategy | `RollingUpdate` | + +### Metrics Configuration + +| Parameter | Description | Default | +| ------------------------------------------ | --------------------------------------------- | ------- | +| `metrics.enabled` | Enable Prometheus metrics | `true` | +| `metrics.serviceMonitor.enabled` | Create ServiceMonitor for Prometheus Operator | `false` | +| `metrics.serviceMonitor.namespace` | Namespace for ServiceMonitor | `""` | +| `metrics.serviceMonitor.interval` | Scrape interval | `30s` | +| `metrics.serviceMonitor.scrapeTimeout` | Scrape timeout | `""` | +| `metrics.serviceMonitor.relabelings` | Relabel configurations | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | Metric relabel configurations | `[]` | +| `metrics.serviceMonitor.labels` | Additional labels for ServiceMonitor | `{}` | +| `metrics.serviceMonitor.honorLabels` | Honor labels from metrics | `false` | + +### High Availability + +| Parameter | Description | Default | +| ------------------------------------ | ---------------------------------- | ------- | +| `podDisruptionBudget.enabled` | Enable PodDisruptionBudget | `false` | +| `podDisruptionBudget.minAvailable` | Minimum number of available pods | `""` | +| `podDisruptionBudget.maxUnavailable` | Maximum number of unavailable pods | `1` | + +### Service Account + +| Parameter | Description | Default | +| --------------------------------------------- | ------------------------------- | ------- | +| `serviceAccount.create` | Create service account | `true` | +| `serviceAccount.name` | Service account name | `""` | +| `serviceAccount.annotations` | Service account annotations | `{}` | +| `serviceAccount.automountServiceAccountToken` | Automount service account token | `false` | + +### Network Policy + +| Parameter | Description | Default | +| ----------------------------- | ------------------------ | ------- | +| `networkPolicy.enabled` | Enable NetworkPolicy | `false` | +| `networkPolicy.allowExternal` | Allow external traffic | `true` | +| `networkPolicy.extraIngress` | Additional ingress rules | `[]` | +| `networkPolicy.extraEgress` | Additional egress rules | `[]` | + +### Security Context + +| Parameter | Description | Default | +| --------------------------------------------------- | ---------------------------------- | ------- | +| `containerSecurityContext.runAsUser` | User ID to run the container | `1000` | +| `containerSecurityContext.runAsGroup` | Group ID to run the container | `1000` | +| `containerSecurityContext.runAsNonRoot` | Run as non-root user | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | Allow privilege escalation | `false` | +| `containerSecurityContext.readOnlyRootFilesystem` | Mount root filesystem as read-only | `true` | +| `containerSecurityContext.capabilities.drop` | Linux capabilities to drop | `[ALL]` | +| `podSecurityContext.fsGroup` | Group ID for the volumes | `1000` | + +### Probes + +| Parameter | Description | Default | +| ------------------------------------ | ------------------------------------- | ------- | +| `startupProbe.enabled` | Enable startup probe | `true` | +| `startupProbe.initialDelaySeconds` | Initial delay for startup probe | `0` | +| `startupProbe.periodSeconds` | Period for startup probe | `10` | +| `startupProbe.timeoutSeconds` | Timeout for startup probe | `5` | +| `startupProbe.failureThreshold` | Failure threshold for startup probe | `30` | +| `livenessProbe.enabled` | Enable liveness probe | `true` | +| `livenessProbe.initialDelaySeconds` | Initial delay for liveness probe | `10` | +| `livenessProbe.periodSeconds` | Period for liveness probe | `10` | +| `livenessProbe.timeoutSeconds` | Timeout for liveness probe | `5` | +| `livenessProbe.failureThreshold` | Failure threshold for liveness probe | `3` | +| `readinessProbe.enabled` | Enable readiness probe | `true` | +| `readinessProbe.initialDelaySeconds` | Initial delay for readiness probe | `5` | +| `readinessProbe.periodSeconds` | Period for readiness probe | `10` | +| `readinessProbe.timeoutSeconds` | Timeout for readiness probe | `5` | +| `readinessProbe.failureThreshold` | Failure threshold for readiness probe | `3` | + +### Scheduling + +| Parameter | Description | Default | +| --------------------------- | ------------------------------------ | ------- | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `affinity` | Affinity rules for pod assignment | `{}` | +| `topologySpreadConstraints` | Topology Spread Constraints | `[]` | +| `priorityClassName` | Priority class name for pod eviction | `""` | + +### Extra Configuration + +| Parameter | Description | Default | +| ------------------- | ------------------------------------------------- | ------- | +| `extraArgs` | Additional etcd command line arguments | `[]` | +| `extraEnvVars` | Additional environment variables | `[]` | +| `extraVolumes` | Additional volumes to add to the pod | `[]` | +| `extraVolumeMounts` | Additional volume mounts for etcd container | `[]` | +| `extraObjects` | Array of extra objects to deploy with the release | `[]` | + +## Upgrading + +To upgrade your release: + +```bash +helm upgrade my-etcd oci://registry-1.docker.io/cloudpirates/etcd +``` + +## Uninstalling + +To uninstall/delete the `my-etcd` deployment: + +```bash +helm delete my-etcd +``` + +## License + +Copyright ยฉ 2024 CloudPirates GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/charts/etcd/artifacthub-repo.yml b/charts/etcd/artifacthub-repo.yml new file mode 100644 index 00000000..3b8407ed --- /dev/null +++ b/charts/etcd/artifacthub-repo.yml @@ -0,0 +1 @@ +repositoryID: 229cfa80-872a-4900-ad74-d9d1252e8214 \ No newline at end of file diff --git a/charts/etcd/templates/_helpers.tpl b/charts/etcd/templates/_helpers.tpl new file mode 100644 index 00000000..cf373e9f --- /dev/null +++ b/charts/etcd/templates/_helpers.tpl @@ -0,0 +1,93 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "etcd.name" -}} +{{- include "cloudpirates.name" . -}} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "etcd.fullname" -}} +{{- include "cloudpirates.fullname" . -}} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "etcd.chart" -}} +{{- include "cloudpirates.chart" . -}} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "etcd.labels" -}} +{{- include "cloudpirates.labels" . }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "etcd.selectorLabels" -}} +{{- include "cloudpirates.selectorLabels" . -}} +{{- end }} + +{{/* +Common annotations +*/}} +{{- define "etcd.annotations" -}} +{{- include "cloudpirates.annotations" . -}} +{{- end }} + +{{/* +Return the proper etcd image name +*/}} +{{- define "etcd.image" -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- end }} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "etcd.imagePullSecrets" -}} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "etcd.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "etcd.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Validate etcd values +*/}} +{{- define "etcd.validateValues" -}} +{{- $replicaCount := int .Values.replicaCount }} +{{- if and (gt $replicaCount 1) (eq (mod $replicaCount 2) 0) }} +{{- fail (printf "etcd: Invalid replica count. etcd requires an odd number of replicas for quorum (e.g., 1, 3, 5, 7). Current value: %d" $replicaCount) }} +{{- end }} +{{- end }} + +{{/* +Generate etcd initial cluster string +*/}} +{{- define "etcd.initialCluster" -}} +{{- $namespace := .Release.Namespace }} +{{- $name := include "etcd.fullname" . -}} +{{- $peerPort := .Values.service.peerPort -}} +{{- $replicaCount := int .Values.replicaCount }} +{{- $protocol := "http" }} +{{- if .Values.auth.peer.enabled }} +{{- $protocol = "https" }} +{{- end }} +{{- range $i := until $replicaCount }} +{{- if $i }},{{ end -}}{{ $name }}-{{ $i }}={{ $protocol }}://{{ $name }}-{{ $i }}.{{ $name }}-headless.{{ $namespace }}.svc.cluster.local:{{ $peerPort }} +{{- end }} +{{- end }} diff --git a/charts/etcd/templates/extraobjects.yaml b/charts/etcd/templates/extraobjects.yaml new file mode 100644 index 00000000..d12e6cc6 --- /dev/null +++ b/charts/etcd/templates/extraobjects.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraObjects }} +--- +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/charts/etcd/templates/networkpolicy.yaml b/charts/etcd/templates/networkpolicy.yaml new file mode 100644 index 00000000..01809f68 --- /dev/null +++ b/charts/etcd/templates/networkpolicy.yaml @@ -0,0 +1,72 @@ +{{- if .Values.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "etcd.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "etcd.labels" . | nindent 4 }} + {{- with (include "etcd.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "etcd.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + # Allow client connections + - ports: + - port: {{ .Values.service.clientPort }} + protocol: TCP + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: {} + {{- end }} + # Allow peer connections + - ports: + - port: {{ .Values.service.peerPort }} + protocol: TCP + from: + - podSelector: + matchLabels: + {{- include "etcd.selectorLabels" . | nindent 14 }} + {{- if .Values.metrics.enabled }} + # Allow metrics scraping + - ports: + - port: {{ .Values.service.metricsPort }} + protocol: TCP + {{- if not .Values.networkPolicy.allowExternal }} + from: + - namespaceSelector: {} + podSelector: + matchLabels: + app.kubernetes.io/name: prometheus + {{- end }} + {{- end }} + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + # Allow DNS resolution + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + # Allow etcd peer communication + - ports: + - port: {{ .Values.service.peerPort }} + protocol: TCP + to: + - podSelector: + matchLabels: + {{- include "etcd.selectorLabels" . | nindent 14 }} + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/etcd/templates/poddisruptionbudget.yaml b/charts/etcd/templates/poddisruptionbudget.yaml new file mode 100644 index 00000000..fd8b6f80 --- /dev/null +++ b/charts/etcd/templates/poddisruptionbudget.yaml @@ -0,0 +1,23 @@ +{{- if .Values.podDisruptionBudget.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "etcd.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "etcd.labels" . | nindent 4 }} + {{- with (include "etcd.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} +spec: + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable | quote }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- include "etcd.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/charts/etcd/templates/service.yaml b/charts/etcd/templates/service.yaml new file mode 100644 index 00000000..bcb2ace0 --- /dev/null +++ b/charts/etcd/templates/service.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "etcd.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "etcd.labels" . | nindent 4 }} + {{- if or (include "etcd.annotations" .) .Values.service.annotations }} + annotations: +{{- (include "etcd.annotations" .) | indent 4 }} +{{- if .Values.service.annotations }} +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.clientPort | default 2379 }} + targetPort: client + protocol: TCP + name: client + {{- if .Values.metrics.enabled }} + - port: {{ .Values.service.metricsPort | default 2381 }} + targetPort: metrics + protocol: TCP + name: metrics + {{- end }} + selector: + {{- include "etcd.selectorLabels" . | nindent 4 }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "etcd.fullname" . }}-headless + namespace: {{ .Release.Namespace }} + labels: + {{- include "etcd.labels" . | nindent 4 }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: true + ports: + - port: {{ .Values.service.clientPort | default 2379 }} + targetPort: client + protocol: TCP + name: client + - port: {{ .Values.service.peerPort | default 2380 }} + targetPort: peer + protocol: TCP + name: peer + selector: + {{- include "etcd.selectorLabels" . | nindent 4 }} diff --git a/charts/etcd/templates/serviceaccount.yaml b/charts/etcd/templates/serviceaccount.yaml new file mode 100644 index 00000000..12c30577 --- /dev/null +++ b/charts/etcd/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "etcd.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "etcd.labels" . | nindent 4 }} + {{- if or (include "etcd.annotations" .) .Values.serviceAccount.annotations }} + annotations: +{{- (include "etcd.annotations" .) | indent 4 }} +{{- if .Values.serviceAccount.annotations }} +{{- toYaml .Values.serviceAccount.annotations | nindent 4 }} +{{- end }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/charts/etcd/templates/servicemonitor.yaml b/charts/etcd/templates/servicemonitor.yaml new file mode 100644 index 00000000..6a45ab30 --- /dev/null +++ b/charts/etcd/templates/servicemonitor.yaml @@ -0,0 +1,42 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "etcd.fullname" . }} + namespace: {{ default .Release.Namespace .Values.metrics.serviceMonitor.namespace }} + labels: + {{- include "etcd.labels" . | nindent 4 }} + {{- with .Values.metrics.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with (include "etcd.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "etcd.selectorLabels" . | nindent 6 }} + endpoints: + - port: metrics + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} +{{- end }} diff --git a/charts/etcd/templates/statefulset.yaml b/charts/etcd/templates/statefulset.yaml new file mode 100644 index 00000000..67d97881 --- /dev/null +++ b/charts/etcd/templates/statefulset.yaml @@ -0,0 +1,241 @@ +{{- include "etcd.validateValues" . }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "etcd.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "etcd.labels" . | nindent 4 }} + {{- with (include "etcd.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ include "etcd.fullname" . }}-headless + replicas: {{ .Values.replicaCount }} + podManagementPolicy: Parallel + {{- if .Values.updateStrategy }} + updateStrategy: {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "etcd.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "etcd.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or (include "etcd.annotations" .) .Values.podAnnotations }} + annotations: + {{- with (include "etcd.annotations" .) }} + {{- . | nindent 8 }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + spec: +{{- with (include "etcd.imagePullSecrets" .) }} +{{ . | nindent 6 }} +{{- end }} + serviceAccountName: {{ include "etcd.serviceAccountName" . }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + image: {{ include "etcd.image" . | quote }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "IfNotPresent" | quote }} + command: + - /usr/local/bin/etcd + args: + - --name=$(POD_NAME) + - --listen-peer-urls={{ if .Values.auth.peer.enabled }}https{{ else }}http{{ end }}://{{ .Values.config.listenPeerIp }}:{{ .Values.service.peerPort }} + - --listen-client-urls={{ if .Values.auth.enabled }}https{{ else }}http{{ end }}://{{ .Values.config.listenClientIp }}:{{ .Values.service.clientPort }} + - --advertise-client-urls={{ if .Values.auth.enabled }}https{{ else }}http{{ end }}://$(POD_NAME).{{ include "etcd.fullname" . }}-headless.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.clientPort }} + - --initial-advertise-peer-urls={{ if .Values.auth.peer.enabled }}https{{ else }}http{{ end }}://$(POD_NAME).{{ include "etcd.fullname" . }}-headless.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.peerPort }} + - --initial-cluster={{ include "etcd.initialCluster" . }} + - --initial-cluster-token={{ .Values.config.initialClusterToken }} + - --initial-cluster-state={{ .Values.config.initialClusterState }} + - --data-dir={{ .Values.persistence.mountPath }}/default.etcd + - --auto-compaction-mode={{ .Values.config.autoCompactionMode }} + - --auto-compaction-retention={{ .Values.config.autoCompactionRetention }} + - --snapshot-count={{ .Values.config.snapshotCount | int64 }} + - --quota-backend-bytes={{ .Values.config.quotaBackendBytes | int64 }} + - --max-request-bytes={{ .Values.config.maxRequestBytes | int64 }} + - --heartbeat-interval={{ .Values.config.heartbeatInterval }} + - --election-timeout={{ .Values.config.electionTimeout }} + - --max-snapshots={{ .Values.config.maxSnapshots }} + - --max-wals={{ .Values.config.maxWals }} + - --log-level={{ .Values.config.logLevel }} + {{- if .Values.auth.enabled }} + - --client-cert-auth + - --trusted-ca-file=/etc/etcd/certs/client/ca.crt + - --cert-file=/etc/etcd/certs/client/tls.crt + - --key-file=/etc/etcd/certs/client/tls.key + {{- end }} + {{- if .Values.auth.peer.enabled }} + - --peer-client-cert-auth + - --peer-trusted-ca-file=/etc/etcd/certs/peer/ca.crt + - --peer-cert-file=/etc/etcd/certs/peer/tls.crt + - --peer-key-file=/etc/etcd/certs/peer/tls.key + {{- end }} + {{- if .Values.metrics.enabled }} + - --listen-metrics-urls=http://{{ .Values.config.listenClientIp }}:{{ .Values.service.metricsPort }} + {{- end }} + {{- range .Values.extraArgs }} + - {{ . }} + {{- end }} + ports: + - name: client + containerPort: {{ .Values.service.clientPort | default 2379 }} + protocol: TCP + - name: peer + containerPort: {{ .Values.service.peerPort | default 2380 }} + protocol: TCP + {{- if .Values.metrics.enabled }} + - name: metrics + containerPort: {{ .Values.service.metricsPort | default 2381 }} + protocol: TCP + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + {{- with .Values.extraEnvVars }} +{{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.startupProbe.enabled }} + startupProbe: + httpGet: + path: /health + port: client + {{- if .Values.auth.enabled }} + scheme: HTTPS + {{- else }} + scheme: HTTP + {{- end }} + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + successThreshold: {{ .Values.startupProbe.successThreshold }} + {{- end }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /health + port: client + {{- if .Values.auth.enabled }} + scheme: HTTPS + {{- else }} + scheme: HTTP + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /health?serializable=true + port: client + {{- if .Values.auth.enabled }} + scheme: HTTPS + {{- else }} + scheme: HTTP + {{- end }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + {{- end }} + resources: {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + {{- if .Values.containerSecurityContext.readOnlyRootFilesystem }} + - name: tmp + mountPath: /tmp + {{- end }} + {{- if .Values.auth.enabled }} + - name: client-certs + mountPath: /etc/etcd/certs/client + readOnly: true + {{- end }} + {{- if .Values.auth.peer.enabled }} + - name: peer-certs + mountPath: /etc/etcd/certs/peer + readOnly: true + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + volumes: + {{- if not .Values.persistence.enabled }} + - name: data + emptyDir: {} + {{- end }} + {{- if .Values.containerSecurityContext.readOnlyRootFilesystem }} + - name: tmp + emptyDir: {} + {{- end }} + {{- if .Values.auth.enabled }} + - name: client-certs + secret: + secretName: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) }} + defaultMode: 0400 + {{- end }} + {{- if .Values.auth.peer.enabled }} + - name: peer-certs + secret: + secretName: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.peer.existingSecret "context" .) }} + defaultMode: 0400 + {{- end }} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- with .Values.persistence.accessModes }} + {{- toYaml . | nindent 10 }} + {{- end}} + {{- if .Values.persistence.storageClass }} + storageClassName: {{ .Values.persistence.storageClass | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- end }} diff --git a/charts/etcd/tests/common-parameters_test.yaml b/charts/etcd/tests/common-parameters_test.yaml new file mode 100644 index 00000000..ea73fca5 --- /dev/null +++ b/charts/etcd/tests/common-parameters_test.yaml @@ -0,0 +1,210 @@ +suite: test etcd common parameters +templates: + - statefulset.yaml +set: + image: + tag: v3.6.0-alpha.0 +tests: + - it: should use default values when nothing is overridden + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-etcd + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: etcd + - equal: + path: metadata.labels["app.kubernetes.io/instance"] + value: RELEASE-NAME + - equal: + path: spec.template.spec.containers[0].image + value: quay.io/coreos/etcd:v3.6.0-alpha.0 + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + + - it: should respect global.imageRegistry override + set: + global: + imageRegistry: "my-registry.com" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: my-registry.com/coreos/etcd:v3.6.0-alpha.0 + + - it: should respect global.imagePullSecrets + set: + global: + imagePullSecrets: + - name: my-secret-1 + - name: my-secret-2 + asserts: + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: my-secret-1 + - equal: + path: spec.template.spec.imagePullSecrets[1].name + value: my-secret-2 + + - it: should respect nameOverride + set: + nameOverride: "custom-name" + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-custom-name + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: custom-name + + - it: should respect fullnameOverride + set: + fullnameOverride: "completely-custom-name" + asserts: + - equal: + path: metadata.name + value: completely-custom-name + + - it: should add commonLabels to all resources + set: + commonLabels: + environment: "test" + team: "platform" + asserts: + - equal: + path: metadata.labels.environment + value: test + - equal: + path: metadata.labels.team + value: platform + + - it: should add commonAnnotations to all resources + set: + commonAnnotations: + deployment.kubernetes.io/revision: "1" + prometheus.io/scrape: "true" + asserts: + - equal: + path: metadata.annotations["deployment.kubernetes.io/revision"] + value: "1" + - equal: + path: metadata.annotations["prometheus.io/scrape"] + value: "true" + + - it: should respect image.registry override + set: + image: + registry: "custom-registry.io" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: custom-registry.io/coreos/etcd:v3.6.0-alpha.0 + + - it: should respect image.repository override + set: + image: + repository: "custom/etcd" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: quay.io/custom/etcd:v3.6.0-alpha.0 + + - it: should respect image.tag override + set: + image: + tag: "v3.5.0" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: quay.io/coreos/etcd:v3.5.0 + + - it: should respect image.pullPolicy override + set: + image: + pullPolicy: "Always" + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + + - it: should prioritize global.imageRegistry over image.registry + set: + global: + imageRegistry: "global-registry.com" + image: + registry: "image-registry.com" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: global-registry.com/coreos/etcd:v3.6.0-alpha.0 + + - it: should add podLabels to pod template + set: + podLabels: + custom: "label" + foo: "bar" + asserts: + - equal: + path: spec.template.metadata.labels.custom + value: label + - equal: + path: spec.template.metadata.labels.foo + value: bar + + - it: should add podAnnotations to pod template + set: + podAnnotations: + custom: "annotation" + foo: "bar" + asserts: + - equal: + path: spec.template.metadata.annotations.custom + value: annotation + - equal: + path: spec.template.metadata.annotations.foo + value: bar + + - it: should combine all overrides correctly + set: + global: + imageRegistry: "global-reg.io" + imagePullSecrets: + - name: global-secret + nameOverride: "custom-etcd" + commonLabels: + env: "prod" + commonAnnotations: + version: "v1.0.0" + podLabels: + pod-label: "value" + podAnnotations: + pod-annotation: "value" + image: + repository: "custom/etcd" + tag: "v3.5.0" + pullPolicy: "Never" + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-custom-etcd + - equal: + path: metadata.labels.env + value: prod + - equal: + path: metadata.annotations.version + value: v1.0.0 + - equal: + path: spec.template.metadata.labels.pod-label + value: value + - equal: + path: spec.template.metadata.annotations.pod-annotation + value: value + - equal: + path: spec.template.spec.containers[0].image + value: global-reg.io/custom/etcd:v3.5.0 + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Never + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: global-secret diff --git a/charts/etcd/tests/etcd-functionality_test.yaml b/charts/etcd/tests/etcd-functionality_test.yaml new file mode 100644 index 00000000..6a3b749f --- /dev/null +++ b/charts/etcd/tests/etcd-functionality_test.yaml @@ -0,0 +1,258 @@ +suite: test etcd functionality +templates: + - statefulset.yaml + - service.yaml + - poddisruptionbudget.yaml + - servicemonitor.yaml + - networkpolicy.yaml +set: + image: + tag: v3.6.0-alpha.0 +tests: + # Replica count validation + - it: should fail with even replica count + template: statefulset.yaml + set: + replicaCount: 2 + asserts: + - failedTemplate: {} + + - it: should succeed with odd replica count + template: statefulset.yaml + set: + replicaCount: 5 + asserts: + - equal: + path: spec.replicas + value: 5 + + # etcd configuration + - it: should configure initial cluster state + template: statefulset.yaml + set: + config: + initialClusterState: "existing" + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--initial-cluster-state=existing" + + - it: should configure heartbeat and election timeout + template: statefulset.yaml + set: + config: + heartbeatInterval: 200 + electionTimeout: 2000 + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--heartbeat-interval=200" + - contains: + path: spec.template.spec.containers[0].args + content: "--election-timeout=2000" + + - it: should configure listen IPs + template: statefulset.yaml + set: + config: + listenPeerIp: "127.0.0.1" + listenClientIp: "127.0.0.1" + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--listen-peer-urls=http://127.0.0.1:2380" + - contains: + path: spec.template.spec.containers[0].args + content: "--listen-client-urls=http://127.0.0.1:2379" + + - it: should add extraArgs + template: statefulset.yaml + set: + extraArgs: + - "--max-txn-ops=128" + - "--grpc-keepalive-min-time=5s" + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--max-txn-ops=128" + - contains: + path: spec.template.spec.containers[0].args + content: "--grpc-keepalive-min-time=5s" + + # TLS configuration + - it: should enable client TLS + template: statefulset.yaml + set: + auth: + enabled: true + existingSecret: "etcd-client-certs" + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--client-cert-auth" + - contains: + path: spec.template.spec.containers[0].args + content: "--listen-client-urls=https://0.0.0.0:2379" + + - it: should enable peer TLS + template: statefulset.yaml + set: + auth: + peer: + enabled: true + existingSecret: "etcd-peer-certs" + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--peer-client-cert-auth" + - contains: + path: spec.template.spec.containers[0].args + content: "--listen-peer-urls=https://0.0.0.0:2380" + + # Metrics configuration + - it: should expose metrics port when enabled + template: statefulset.yaml + set: + metrics: + enabled: true + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--listen-metrics-urls=http://0.0.0.0:2381" + - contains: + path: spec.template.spec.containers[0].ports + content: + name: metrics + containerPort: 2381 + protocol: TCP + + - it: should not expose metrics port when disabled + template: statefulset.yaml + set: + metrics: + enabled: false + asserts: + - notContains: + path: spec.template.spec.containers[0].args + content: "--listen-metrics-urls=http://0.0.0.0:2381" + + - it: should create ServiceMonitor when enabled + template: servicemonitor.yaml + set: + metrics: + enabled: true + serviceMonitor: + enabled: true + asserts: + - hasDocuments: + count: 1 + - isKind: + of: ServiceMonitor + + - it: should not create ServiceMonitor when disabled + template: servicemonitor.yaml + set: + metrics: + enabled: true + serviceMonitor: + enabled: false + asserts: + - hasDocuments: + count: 0 + + # Service configuration + - it: should add service annotations + template: service.yaml + set: + service: + annotations: + key1: "value1" + key2: "value2" + asserts: + - equal: + path: metadata.annotations.key1 + value: value1 + documentIndex: 0 + - equal: + path: metadata.annotations.key2 + value: value2 + documentIndex: 0 + + - it: should expose metrics port in service + template: service.yaml + set: + metrics: + enabled: true + asserts: + - contains: + path: spec.ports + content: + name: metrics + port: 2381 + targetPort: metrics + protocol: TCP + documentIndex: 0 + + # PodDisruptionBudget + - it: should create PDB when enabled + template: poddisruptionbudget.yaml + set: + podDisruptionBudget: + enabled: true + asserts: + - hasDocuments: + count: 1 + - isKind: + of: PodDisruptionBudget + + - it: should not create PDB when disabled + template: poddisruptionbudget.yaml + set: + podDisruptionBudget: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should set minAvailable in PDB + template: poddisruptionbudget.yaml + set: + podDisruptionBudget: + enabled: true + minAvailable: "2" + asserts: + - equal: + path: spec.minAvailable + value: "2" + + # NetworkPolicy + - it: should create NetworkPolicy when enabled + template: networkpolicy.yaml + set: + networkPolicy: + enabled: true + asserts: + - hasDocuments: + count: 1 + - isKind: + of: NetworkPolicy + + - it: should not create NetworkPolicy when disabled + template: networkpolicy.yaml + set: + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + # UpdateStrategy + - it: should configure update strategy + template: statefulset.yaml + set: + updateStrategy: + type: "OnDelete" + asserts: + - equal: + path: spec.updateStrategy.type + value: OnDelete diff --git a/charts/etcd/tests/service-account_test.yaml b/charts/etcd/tests/service-account_test.yaml new file mode 100644 index 00000000..22388d09 --- /dev/null +++ b/charts/etcd/tests/service-account_test.yaml @@ -0,0 +1,58 @@ +suite: test etcd service account parameters +templates: + - serviceaccount.yaml +set: + serviceAccount: + create: true +tests: + - it: should use default labels for the manifest + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-etcd + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: etcd + - equal: + path: metadata.labels["app.kubernetes.io/instance"] + value: RELEASE-NAME + + - it: should respect serviceAccount.name override + set: + serviceAccount: + name: "my-service-account" + asserts: + - equal: + path: metadata.name + value: my-service-account + + - it: should respect serviceAccount.annotations override + set: + serviceAccount: + annotations: + key1: "value1" + key2: "value2" + asserts: + - equal: + path: metadata.annotations.key1 + value: value1 + - equal: + path: metadata.annotations.key2 + value: value2 + + - it: should respect serviceAccount.automountServiceAccountToken + set: + serviceAccount: + automountServiceAccountToken: true + asserts: + - equal: + path: automountServiceAccountToken + value: true + + - it: should not render when create is false + set: + serviceAccount: + create: false + asserts: + - hasDocuments: + count: 0 diff --git a/charts/etcd/values.schema.json b/charts/etcd/values.schema.json new file mode 100644 index 00000000..b130b16f --- /dev/null +++ b/charts/etcd/values.schema.json @@ -0,0 +1,404 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "auth": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "peer": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + } + } + } + } + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { + "type": "object", + "properties": { + "autoCompactionMode": { + "type": "string" + }, + "autoCompactionRetention": { + "type": "string" + }, + "electionTimeout": { + "type": "integer" + }, + "heartbeatInterval": { + "type": "integer" + }, + "initialClusterState": { + "type": "string" + }, + "initialClusterToken": { + "type": "string" + }, + "listenClientIp": { + "type": "string" + }, + "listenPeerIp": { + "type": "string" + }, + "logLevel": { + "type": "string" + }, + "maxRequestBytes": { + "type": "integer" + }, + "maxSnapshots": { + "type": "integer" + }, + "maxWals": { + "type": "integer" + }, + "quotaBackendBytes": { + "type": "integer" + }, + "snapshotCount": { + "type": "integer" + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } + } + }, + "extraArgs": { + "type": "array" + }, + "extraEnvVars": { + "type": "array" + }, + "extraObjects": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "labels": { + "type": "object" + }, + "metricRelabelings": { + "type": "array" + }, + "namespace": { + "type": "string" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + } + } + } + } + }, + "nameOverride": { + "type": "string" + }, + "networkPolicy": { + "type": "object", + "properties": { + "allowExternal": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "extraEgress": { + "type": "array" + }, + "extraIngress": { + "type": "array" + } + } + }, + "nodeSelector": { + "type": "object" + }, + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podDisruptionBudget": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxUnavailable": { + "type": "integer" + }, + "minAvailable": { + "type": "string" + } + } + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "priorityClassName": { + "type": "string" + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "clientPort": { + "type": "integer" + }, + "metricsPort": { + "type": "integer" + }, + "peerPort": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "tolerations": { + "type": "array" + }, + "topologySpreadConstraints": { + "type": "array" + }, + "updateStrategy": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + } + } +} diff --git a/charts/etcd/values.yaml b/charts/etcd/values.yaml new file mode 100644 index 00000000..6d888ae7 --- /dev/null +++ b/charts/etcd/values.yaml @@ -0,0 +1,276 @@ +## @section Global parameters +global: + ## @param global.imageRegistry Global Docker Image registry + imageRegistry: "" + ## @param global.imagePullSecrets Global Docker registry secret names as an array + imagePullSecrets: [] + +## @section Common parameters +## @param nameOverride String to partially override etcd.fullname +nameOverride: "" +## @param fullnameOverride String to fully override etcd.fullname +fullnameOverride: "" +## @param commonLabels Labels to add to all deployed objects +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +commonAnnotations: {} + +## @section etcd image parameters +image: + ## @param image.registry etcd image registry + registry: quay.io + ## @param image.repository etcd image repository + repository: coreos/etcd + ## @param image.tag etcd image tag + tag: "v3.6.5@sha256:3397341272b9e0a6f44d7e3fc7c321c6efe6cbe82ce866b9b01d0c704bfc5bf3" + ## @param image.pullPolicy etcd image pull policy + pullPolicy: IfNotPresent + +## @param replicaCount Number of etcd replicas to deploy (must be odd number for quorum) +replicaCount: 3 + +## @param podLabels Additional labels for etcd pods +podLabels: {} + +## @param podAnnotations Additional annotations for etcd pods +podAnnotations: {} + +## @section Service configuration +service: + ## @param service.type Kubernetes service type + type: ClusterIP + ## @param service.annotations Service annotations + annotations: {} + ## @param service.clientPort etcd client service port + clientPort: 2379 + ## @param service.peerPort etcd peer service port + peerPort: 2380 + ## @param service.metricsPort etcd metrics service port + metricsPort: 2381 + +auth: + ## @param auth.enabled Enable client-to-server authentication + enabled: false + ## @param auth.existingSecret Name of existing secret containing client certificates + existingSecret: "" + peer: + ## @param auth.peer.enabled Enable peer-to-peer authentication + enabled: false + ## @param auth.peer.existingSecret Name of existing secret containing peer certificates + existingSecret: "" + +## @section etcd configuration +config: + ## @param config.initialClusterState Initial cluster state (new or existing) + initialClusterState: new + ## @param config.autoCompactionMode Auto compaction mode (periodic or revision) + autoCompactionMode: periodic + ## @param config.autoCompactionRetention Auto compaction retention (1 hour for periodic mode) + autoCompactionRetention: "1" + ## @param config.snapshotCount Number of committed transactions to trigger a snapshot + snapshotCount: 10000 + ## @param config.quotaBackendBytes Backend storage quota in bytes (default 2GB) + quotaBackendBytes: 2147483648 + ## @param config.maxRequestBytes Maximum client request size in bytes + maxRequestBytes: 1572864 + ## @param config.logLevel Log level (debug, info, warn, error, panic, fatal) + logLevel: info + ## @param config.initialClusterToken Initial cluster token for the etcd cluster + initialClusterToken: etcd-cluster + ## @param config.heartbeatInterval Time (in milliseconds) of a heartbeat interval + heartbeatInterval: 100 + ## @param config.electionTimeout Time (in milliseconds) for an election to timeout + electionTimeout: 1000 + ## @param config.maxSnapshots Maximum number of snapshot files to retain + maxSnapshots: 5 + ## @param config.maxWals Maximum number of wal files to retain + maxWals: 5 + ## @param config.listenPeerIp IP address to listen on for peer traffic (default 0.0.0.0) + listenPeerIp: 0.0.0.0 + ## @param config.listenClientIp IP address to listen on for client traffic (default 0.0.0.0) + listenClientIp: 0.0.0.0 + +## @section Persistence +persistence: + ## @param persistence.enabled Enable persistence using Persistent Volume Claims + enabled: true + ## @param persistence.storageClass Persistent Volume storage class + storageClass: "" + ## @param persistence.annotations Persistent Volume Claim annotations + annotations: {} + ## @param persistence.size Persistent Volume size + size: 8Gi + ## @param persistence.accessModes Persistent Volume access modes + accessModes: + - ReadWriteOnce + ## @param persistence.mountPath The path where to mount the data volume + mountPath: /var/run/etcd + +## @param resources Resource limits and requests for etcd pod +resources: {} + # limits: + # memory: 512Mi + # requests: + # cpu: 250m + # memory: 256Mi + +## @section StatefulSet configuration +## @param updateStrategy.type StatefulSet update strategy type +updateStrategy: + type: RollingUpdate + +## @section Metrics configuration +metrics: + ## @param metrics.enabled Enable Prometheus metrics + enabled: true + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource for scraping metrics using PrometheusOperator + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace which Prometheus is running in + namespace: "" + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped + interval: 30s + ## @param metrics.serviceMonitor.scrapeTimeout Specify the timeout after which the scrape is ended + scrapeTimeout: "" + ## @param metrics.serviceMonitor.relabelings RelabelConfigs to apply to samples before scraping + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion + metricRelabelings: [] + ## @param metrics.serviceMonitor.labels Additional labels that can be used so ServiceMonitor will be discovered by Prometheus + labels: {} + ## @param metrics.serviceMonitor.honorLabels honorLabels chooses the metric's labels on collisions with target labels + honorLabels: false + +## @section High Availability +podDisruptionBudget: + ## @param podDisruptionBudget.enabled Enable Pod Disruption Budget + enabled: false + ## @param podDisruptionBudget.minAvailable Minimum number of available pods + minAvailable: "" + ## @param podDisruptionBudget.maxUnavailable Maximum number of unavailable pods + maxUnavailable: 1 + +## @section Service Account +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for etcd pod + create: true + ## @param serviceAccount.name Name of the created serviceAccount + name: "" + ## @param serviceAccount.annotations Annotations for service account + annotations: {} + ## @param serviceAccount.automountServiceAccountToken Auto-mount the service account token in the pod + automountServiceAccountToken: false + +## @section Network Policy +networkPolicy: + ## @param networkPolicy.enabled Enable NetworkPolicy + enabled: false + ## @param networkPolicy.allowExternal Allow external traffic + allowExternal: true + ## @param networkPolicy.extraIngress Additional ingress rules + extraIngress: [] + ## @param networkPolicy.extraEgress Additional egress rules + extraEgress: [] + +## @param extraArgs Additional etcd command line arguments as array +extraArgs: [] +# - --max-txn-ops=128 +# - --grpc-keepalive-min-time=5s + +## @param nodeSelector Node selector for pod assignment +nodeSelector: {} + +## @param priorityClassName for pod eviction +priorityClassName: "" + +## @param tolerations Tolerations for pod assignment +tolerations: [] + +## @param affinity Affinity rules for pod assignment +affinity: {} + +## @param topologySpreadConstraints Topology Spread Constraints for pod assignment +topologySpreadConstraints: [] + +containerSecurityContext: + ## @param containerSecurityContext.runAsUser User ID to run the container + runAsUser: 1000 + ## @param containerSecurityContext.runAsGroup Group ID to run the container + runAsGroup: 1000 + ## @param containerSecurityContext.runAsNonRoot Run as non-root user + runAsNonRoot: true + ## @param containerSecurityContext.allowPrivilegeEscalation Set etcd container's privilege escalation + allowPrivilegeEscalation: false + ## @param containerSecurityContext.readOnlyRootFilesystem Mount container root filesystem as read-only + readOnlyRootFilesystem: true + ## @param containerSecurityContext.capabilities.drop Linux capabilities to drop + capabilities: + drop: + - ALL + +## @param podSecurityContext Security context for the pod +podSecurityContext: + ## @param podSecurityContext.fsGroup Set etcd pod's Security Context fsGroup + fsGroup: 1000 + +## @section Liveness and readiness probes +livenessProbe: + ## @param livenessProbe.enabled Enable livenessProbe on etcd containers + enabled: true + ## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + initialDelaySeconds: 10 + ## @param livenessProbe.periodSeconds Period seconds for livenessProbe + periodSeconds: 10 + ## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + timeoutSeconds: 5 + ## @param livenessProbe.failureThreshold Failure threshold for livenessProbe + failureThreshold: 3 + ## @param livenessProbe.successThreshold Success threshold for livenessProbe + successThreshold: 1 + +readinessProbe: + ## @param readinessProbe.enabled Enable readinessProbe on etcd containers + enabled: true + ## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + initialDelaySeconds: 5 + ## @param readinessProbe.periodSeconds Period seconds for readinessProbe + periodSeconds: 10 + ## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + timeoutSeconds: 5 + ## @param readinessProbe.failureThreshold Failure threshold for readinessProbe + failureThreshold: 3 + ## @param readinessProbe.successThreshold Success threshold for readinessProbe + successThreshold: 1 + +startupProbe: + ## @param startupProbe.enabled Enable startupProbe on etcd containers + enabled: true + ## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + initialDelaySeconds: 0 + ## @param startupProbe.periodSeconds Period seconds for startupProbe + periodSeconds: 10 + ## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe + timeoutSeconds: 5 + ## @param startupProbe.failureThreshold Failure threshold for startupProbe + failureThreshold: 30 + ## @param startupProbe.successThreshold Success threshold for startupProbe + successThreshold: 1 + +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key + +## @param extraVolumes Additional volumes to add to the pod +extraVolumes: [] + +## @param extraVolumeMounts Additional volume mounts to add to the etcd container +extraVolumeMounts: [] + +## @param extraObjects Array of extra objects to deploy with the release +extraObjects: [] diff --git a/charts/ghost/CHANGELOG.md b/charts/ghost/CHANGELOG.md index f9d6b2b0..a94f139a 100644 --- a/charts/ghost/CHANGELOG.md +++ b/charts/ghost/CHANGELOG.md @@ -1,5 +1,108 @@ # Changelog + +## 0.4.3 (2025-11-04) + +* Update charts/ghost/values.yaml ghost (#542) ([6d66d19](https://github.com/CloudPirates-io/helm-charts/commit/6d66d19)) +* chore: update CHANGELOG.md for merged changes ([58cb775](https://github.com/CloudPirates-io/helm-charts/commit/58cb775)) +* chore: update CHANGELOG.md for merged changes ([6daf183](https://github.com/CloudPirates-io/helm-charts/commit/6daf183)) + +## 0.4.2 (2025-11-04) + +* Update charts/ghost/values.yaml ghost to v6.6.0 (minor) (#539) ([fda6611](https://github.com/CloudPirates-io/helm-charts/commit/fda6611)) +* chore: update CHANGELOG.md for merged changes ([232d617](https://github.com/CloudPirates-io/helm-charts/commit/232d617)) +* chore: update CHANGELOG.md for merged changes ([630b637](https://github.com/CloudPirates-io/helm-charts/commit/630b637)) + +## 0.4.1 (2025-10-30) + +* Update charts/ghost/values.yaml ghost (#502) ([5767f7f](https://github.com/CloudPirates-io/helm-charts/commit/5767f7f)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.4.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([a968aa7](https://github.com/CloudPirates-io/helm-charts/commit/a968aa7)) +* chore: update CHANGELOG.md for merged changes ([74ee453](https://github.com/CloudPirates-io/helm-charts/commit/74ee453)) + +## 0.3.6 (2025-10-25) + +* Update charts/ghost/values.yaml ghost to v6.5.3 (patch) (#456) ([3bf647a](https://github.com/CloudPirates-io/helm-charts/commit/3bf647a)) +* chore: update CHANGELOG.md for merged changes ([4cee2f2](https://github.com/CloudPirates-io/helm-charts/commit/4cee2f2)) +* chore: update CHANGELOG.md for merged changes ([2cec192](https://github.com/CloudPirates-io/helm-charts/commit/2cec192)) +* Update charts/ghost/values.yaml ghost (#452) ([4406c00](https://github.com/CloudPirates-io/helm-charts/commit/4406c00)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.3.5 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([844a243](https://github.com/CloudPirates-io/helm-charts/commit/844a243)) +* chore: update CHANGELOG.md for merged changes ([ad40303](https://github.com/CloudPirates-io/helm-charts/commit/ad40303)) + +## 0.3.4 (2025-10-23) + +* Update charts/ghost/values.yaml ghost to v6.5.0 (minor) (#450) ([10e9958](https://github.com/CloudPirates-io/helm-charts/commit/10e9958)) +* chore: update CHANGELOG.md for merged changes ([787c4fb](https://github.com/CloudPirates-io/helm-charts/commit/787c4fb)) +* chore: update CHANGELOG.md for merged changes ([997f383](https://github.com/CloudPirates-io/helm-charts/commit/997f383)) + +## 0.3.3 (2025-10-23) + +* Update charts/ghost/values.yaml ghost (#447) ([881ef3b](https://github.com/CloudPirates-io/helm-charts/commit/881ef3b)) +* chore: update CHANGELOG.md for merged changes ([6af7d8e](https://github.com/CloudPirates-io/helm-charts/commit/6af7d8e)) +* chore: update CHANGELOG.md for merged changes ([0ba351a](https://github.com/CloudPirates-io/helm-charts/commit/0ba351a)) + +## 0.3.2 (2025-10-22) + +* Update charts/ghost/values.yaml ghost (#433) ([6463206](https://github.com/CloudPirates-io/helm-charts/commit/6463206)) +* chore: update CHANGELOG.md for merged changes ([5b3746e](https://github.com/CloudPirates-io/helm-charts/commit/5b3746e)) +* chore: update CHANGELOG.md for merged changes ([523c7da](https://github.com/CloudPirates-io/helm-charts/commit/523c7da)) + +## 0.3.1 (2025-10-19) + +* Update charts/ghost/values.yaml ghost to v6.4.0 (minor) (#414) ([05b099b](https://github.com/CloudPirates-io/helm-charts/commit/05b099b)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([4b02e57](https://github.com/CloudPirates-io/helm-charts/commit/4b02e57)) +* chore: update CHANGELOG.md for merged changes ([bf2e3b2](https://github.com/CloudPirates-io/helm-charts/commit/bf2e3b2)) +* chore: update CHANGELOG.md for merged changes ([2f87d0e](https://github.com/CloudPirates-io/helm-charts/commit/2f87d0e)) + +## 0.3.0 (2025-10-14) + +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* Update charts/ghost/values.yaml ghost to v6.3.1 (patch) (#349) ([7111469](https://github.com/CloudPirates-io/helm-charts/commit/7111469)) + +## 0.2.6 (2025-10-10) + +* Update charts/ghost/values.yaml ghost to v6.3.0 (minor) (#327) ([e74a03d](https://github.com/CloudPirates-io/helm-charts/commit/e74a03d)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + ## 0.2.5 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* Update charts/ghost/values.yaml ghost to v6.2.0 (minor) (#268) ([c8d3f80](https://github.com/CloudPirates-io/helm-charts/commit/c8d3f80)) + +## 0.2.4 (2025-10-09) + +* Update charts/ghost/values.yaml ghost to v6.0.10 (patch) (#259) ([c9b9b8b](https://github.com/CloudPirates-io/helm-charts/commit/c9b9b8b)) + +## 0.2.3 (2025-10-06) + + +## 0.2.2 (2025-10-01) + +* use png as icon (#200) ([359e88f](https://github.com/CloudPirates-io/helm-charts/commit/359e88f)) + +## 0.2.1 (2025-10-01) + +* switch helm-chart icon to a new svg (#199) ([44e4d0d](https://github.com/CloudPirates-io/helm-charts/commit/44e4d0d)) + +## 0.2.0 (2025-10-01) + +* make ghost run on openshift (#195) ([93762d4](https://github.com/CloudPirates-io/helm-charts/commit/93762d4)) +* Update CHANGELOG.md ([dc9fbd8](https://github.com/CloudPirates-io/helm-charts/commit/dc9fbd8)) +* Update CHANGELOG.md ([1bee7fe](https://github.com/CloudPirates-io/helm-charts/commit/1bee7fe)) + +## 0.1.0 (2025-09-23) + +* Initial tagged release diff --git a/charts/ghost/Chart.lock b/charts/ghost/Chart.lock index 23227805..ec87894e 100644 --- a/charts/ghost/Chart.lock +++ b/charts/ghost/Chart.lock @@ -1,9 +1,9 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 + version: 2.0.0 - name: mariadb repository: oci://registry-1.docker.io/cloudpirates - version: 0.3.0 -digest: sha256:4e89daee4a04df25da46810f73b277003ebff8ca938c308ed55214e9a8893183 -generated: "2025-09-30T22:09:51.820397+02:00" + version: 0.4.0 +digest: sha256:732fadaa4290d7bcd69b8c7b2b05a75552ac82f188fd0c7b42bf3718bd68c7a1 +generated: "2025-10-14T12:59:56.216526+02:00" diff --git a/charts/ghost/Chart.yaml b/charts/ghost/Chart.yaml index 48b23658..a948b87e 100644 --- a/charts/ghost/Chart.yaml +++ b/charts/ghost/Chart.yaml @@ -2,27 +2,50 @@ apiVersion: v2 name: ghost description: A simple, powerful publishing platform that allows you to share your stories with the world. type: application -version: 0.2.5 -appVersion: "6.0.9" +version: 0.4.3 +appVersion: "6.6.0" keywords: - ghost - blogging - content management -home: https://www.cloudpirates.io +home: https://ghost.org sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/ghost + - https://github.com/TryGhost/Ghost maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io - name: Gianni Carafa email: gianni.carafa@srf.ch url: https://www.srf.ch dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates - name: mariadb - version: "0.3.x" + version: "0.4.x" repository: oci://registry-1.docker.io/cloudpirates condition: mariadb.enabled icon: https://a.storyblok.com/f/143071/512x512/3a5c1cb0c5/ghost-logo.png +annotations: + license: Apache-2.0 + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: Ghost + url: https://ghost.org + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/ghost + - name: Application + url: https://github.com/TryGhost/Ghost + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Update charts/ghost/values.yaml ghost (#542)" + links: + - name: "Commit 6d66d19" + url: "https://github.com/CloudPirates-io/helm-charts/commit/6d66d19" diff --git a/charts/ghost/README.md b/charts/ghost/README.md index 407ef7b4..dcaa06cc 100644 --- a/charts/ghost/README.md +++ b/charts/ghost/README.md @@ -88,111 +88,111 @@ The following tables list the configurable parameters of the Ghost chart organiz ### Global & Common Parameters -| Parameter | Description | Default | -|--------------------------|-----------------------------------------------|-----------------| -| `global.imageRegistry` | Global Docker image registry | `""` | -| `global.imagePullSecrets`| Global Docker registry secret names as array | `[]` | -| `nameOverride` | String to partially override ghost.fullname | `""` | -| `fullnameOverride` | String to fully override ghost.fullname | `""` | -| `commonLabels` | Labels to add to all deployed objects | `{}` | -| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| Parameter | Description | Default | +| ------------------------- | -------------------------------------------- | ------- | +| `global.imageRegistry` | Global Docker image registry | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names as array | `[]` | +| `nameOverride` | String to partially override ghost.fullname | `""` | +| `fullnameOverride` | String to fully override ghost.fullname | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | ### Image Parameters -| Parameter | Description | Default | -|--------------------------|-----------------------------------------------|-----------------| -| `image.registry` | Ghost image registry | `docker.io` | -| `image.repository` | Ghost image repository | `ghost` | -| `image.tag` | Ghost image tag | `6.0.9` | -| `image.pullPolicy` | Ghost image pull policy | `Always` | -| `replicaCount` | Number of Ghost replicas to deploy | `1` | +| Parameter | Description | Default | +| ------------------ | ---------------------------------- | ----------- | +| `image.registry` | Ghost image registry | `docker.io` | +| `image.repository` | Ghost image repository | `ghost` | +| `image.tag` | Ghost image tag | `6.0.9` | +| `image.pullPolicy` | Ghost image pull policy | `Always` | +| `replicaCount` | Number of Ghost replicas to deploy | `1` | ### Network Parameters -| Parameter | Description | Default | -|--------------------------|-----------------------------------------------|-----------------| -| `containerPorts` | List of container ports | `[{name: http, containerPort: 2368}]` | -| `service.type` | Kubernetes service type | `ClusterIP` | -| `service.ports` | List of service ports | `[{port: 80, targetPort: http}]` | -| `ingress.enabled` | Enable ingress record generation | `true` | -| `ingress.className` | IngressClass for the ingress record | `""` | -| `ingress.annotations` | Additional ingress annotations | `{}` | -| `ingress.hosts` | List of ingress hosts | `[{host: ghost.localhost, paths:[{path: /, pathType: Prefix}]}, {host: admin.ghost.localhost, paths:[{path: /ghost, pathType: Prefix}]}]` | -| `ingress.tls` | TLS configuration for ingress | `[]` | +| Parameter | Description | Default | +| --------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `containerPorts` | List of container ports | `[{name: http, containerPort: 2368}]` | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.ports` | List of service ports | `[{port: 80, targetPort: http}]` | +| `ingress.enabled` | Enable ingress record generation | `true` | +| `ingress.className` | IngressClass for the ingress record | `""` | +| `ingress.annotations` | Additional ingress annotations | `{}` | +| `ingress.hosts` | List of ingress hosts | `[{host: ghost.localhost, paths:[{path: /, pathType: Prefix}]}, {host: admin.ghost.localhost, paths:[{path: /ghost, pathType: Prefix}]}]` | +| `ingress.tls` | TLS configuration for ingress | `[]` | ### Persistence Parameters -| Parameter | Description | Default | -|-----------------------------|--------------------------------------------|-----------------| -| `persistence.enabled` | Enable persistence using PVC | `true` | -| `persistence.annotations` | Annotations for PVC | `{}` | -| `persistence.existingClaim` | Use an existing PVC | `""` | -| `persistence.storageClass` | Storage class of backing PVC | `""` | -| `persistence.accessModes` | PVC access modes | `[ReadWriteOnce]` | -| `persistence.size` | Size of persistent volume claim | `8Gi` | +| Parameter | Description | Default | +| --------------------------- | ------------------------------- | ----------------- | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.annotations` | Annotations for PVC | `{}` | +| `persistence.existingClaim` | Use an existing PVC | `""` | +| `persistence.storageClass` | Storage class of backing PVC | `""` | +| `persistence.accessModes` | PVC access modes | `[ReadWriteOnce]` | +| `persistence.size` | Size of persistent volume claim | `8Gi` | ### Database Parameters -| Parameter | Description | Default | -|------------------------------|-------------------------------------------|-----------------| -| `mariadb.enabled` | Deploy MariaDB as dependency | `true` | -| `mariadb.auth.database` | MariaDB database name | `ghost` | -| `mariadb.auth.username` | MariaDB username | `ghost` | -| `mariadb.auth.password` | MariaDB password | `changeme` | -| `mariadb.auth.existingSecret`| Existing secret with MariaDB credentials | `""` | -| `mariadb.auth.allowEmptyRootPassword` | Allow empty root password | `false` | +| Parameter | Description | Default | +| ------------------------------------- | ---------------------------------------- | ---------- | +| `mariadb.enabled` | Deploy MariaDB as dependency | `true` | +| `mariadb.auth.database` | MariaDB database name | `ghost` | +| `mariadb.auth.username` | MariaDB username | `ghost` | +| `mariadb.auth.password` | MariaDB password | `changeme` | +| `mariadb.auth.existingSecret` | Existing secret with MariaDB credentials | `""` | +| `mariadb.auth.allowEmptyRootPassword` | Allow empty root password | `false` | ### Pod Parameters -| Parameter | Description | Default | -|------------------------------|-------------------------------------------|-----------------| -| `resources` | Resource limits and requests for pod | `{}` | -| `nodeSelector` | Node selector for pod assignment | `{}` | -| `tolerations` | Tolerations for pod assignment | `[]` | -| `affinity` | Affinity for pod assignment | `{}` | -| `podSecurityContext.fsGroup` | Set pod's Security Context fsGroup | `1000` | -| `containerSecurityContext.runAsUser` | Set container's Security Context runAsUser | `1000` | -| `containerSecurityContext.runAsNonRoot` | Run as non-root user | `true` | -| `containerSecurityContext.allowPrivilegeEscalation` | Allow privilege escalation | `false` | +| Parameter | Description | Default | +| --------------------------------------------------- | ------------------------------------------ | ------- | +| `resources` | Resource limits and requests for pod | `{}` | +| `nodeSelector` | Node selector for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `affinity` | Affinity for pod assignment | `{}` | +| `podSecurityContext.fsGroup` | Set pod's Security Context fsGroup | `1000` | +| `containerSecurityContext.runAsUser` | Set container's Security Context runAsUser | `1000` | +| `containerSecurityContext.runAsNonRoot` | Run as non-root user | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | Allow privilege escalation | `false` | ### Health Check Parameters -| Parameter | Description | Default | -|--------------------------------------|-------------------------------------|-----------------| -| `livenessProbe.enabled` | Enable liveness probe | `true` | -| `livenessProbe.type` | Probe type (tcpSocket or httpGet) | `tcpSocket` | -| `livenessProbe.initialDelaySeconds` | Initial delay seconds | `30` | -| `livenessProbe.periodSeconds` | Period seconds | `10` | -| `readinessProbe.enabled` | Enable readiness probe | `true` | -| `readinessProbe.type` | Probe type (tcpSocket or httpGet) | `tcpSocket` | -| `readinessProbe.initialDelaySeconds` | Initial delay seconds | `5` | -| `readinessProbe.periodSeconds` | Period seconds | `12` | +| Parameter | Description | Default | +| ------------------------------------ | --------------------------------- | ----------- | +| `livenessProbe.enabled` | Enable liveness probe | `true` | +| `livenessProbe.type` | Probe type (tcpSocket or httpGet) | `tcpSocket` | +| `livenessProbe.initialDelaySeconds` | Initial delay seconds | `30` | +| `livenessProbe.periodSeconds` | Period seconds | `10` | +| `readinessProbe.enabled` | Enable readiness probe | `true` | +| `readinessProbe.type` | Probe type (tcpSocket or httpGet) | `tcpSocket` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds | `5` | +| `readinessProbe.periodSeconds` | Period seconds | `12` | ### Init Container Parameters -| Parameter | Description | Default | -|----------------------------------------|-------------------------------------|-----------------| -| `initContainers.waitForMariadb.image` | MariaDB init container image | `mariadb:12.0.2`| +| Parameter | Description | Default | +| ------------------------------------- | ---------------------------- | ---------------- | +| `initContainers.waitForMariadb.image` | MariaDB init container image | `mariadb:12.0.2` | ### Autoscaling Parameters -| Parameter | Description | Default | -|-----------------------------------------|----------------------------------|-----------------| -| `autoscaling.enabled` | Enable autoscaling | `false` | -| `autoscaling.minReplicas` | Minimum number of replicas | `""` | -| `autoscaling.maxReplicas` | Maximum number of replicas | `""` | -| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization | `""` | -| `autoscaling.targetMemoryUtilizationPercentage` | Target memory utilization| `""` | +| Parameter | Description | Default | +| ----------------------------------------------- | -------------------------- | ------- | +| `autoscaling.enabled` | Enable autoscaling | `false` | +| `autoscaling.minReplicas` | Minimum number of replicas | `""` | +| `autoscaling.maxReplicas` | Maximum number of replicas | `""` | +| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization | `""` | +| `autoscaling.targetMemoryUtilizationPercentage` | Target memory utilization | `""` | ### Additional Configuration -| Parameter | Description | Default | -|---------------------|---------------------------------------------------|-----------------| -| `extraEnv` | Additional environment variables | `[]` | -| `extraVolumes` | Additional volumes | `[]` | -| `extraVolumeMounts` | Additional volume mounts | `[]` | -| `extraObjects` | Extra Kubernetes objects to deploy | `[]` | -| `config` | Ghost configuration (database, mail, etc.) | See values.yaml | +| Parameter | Description | Default | +| ------------------- | ------------------------------------------ | --------------- | +| `extraEnvVars` | Additional environment variables | `[]` | +| `extraVolumes` | Additional volumes | `[]` | +| `extraVolumeMounts` | Additional volume mounts | `[]` | +| `extraObjects` | Extra Kubernetes objects to deploy | `[]` | +| `config` | Ghost configuration (database, mail, etc.) | See values.yaml | ## Example: Custom Ghost Configuration diff --git a/charts/ghost/ci/test-values.yaml b/charts/ghost/ci/test-values.yaml new file mode 100644 index 00000000..25fa0f33 --- /dev/null +++ b/charts/ghost/ci/test-values.yaml @@ -0,0 +1,72 @@ +# CI test values for ghost chart +# Optimized for faster testing in kind clusters and GitHub Actions + +image: + # Use IfNotPresent to avoid repeated pulls + pullPolicy: IfNotPresent + # Use simple tag without digest for better caching + tag: "6.4.0" + +# Disable ingress for CI tests +ingress: + enabled: false + +# Lenient probes for slow CI environments +readinessProbe: + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 30 + +livenessProbe: + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 5 + failureThreshold: 10 + +# Minimal resources for kind cluster +resources: + limits: + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + +# Disable persistence for faster CI tests +persistence: + enabled: false + +# MariaDB configuration for CI +mariadb: + enabled: true + + auth: + database: ghost + username: ghost + password: ghost-test-password + rootPassword: root-test-password + + image: + pullPolicy: IfNotPresent + + primary: + persistence: + enabled: false + + resources: + limits: + memory: 256Mi + requests: + cpu: 50m + memory: 128Mi + +# Override database connection to use the correct service name +config: + database: + client: "mysql" + connection: + host: "test-ghost-mariadb" + port: 3306 + user: "ghost" + password: "ghost-test-password" + database: "ghost" diff --git a/charts/ghost/templates/_helpers.tpl b/charts/ghost/templates/_helpers.tpl index e14445ce..116cccda 100644 --- a/charts/ghost/templates/_helpers.tpl +++ b/charts/ghost/templates/_helpers.tpl @@ -2,56 +2,56 @@ Expand the name of the chart. */}} {{- define "ghost.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "ghost.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "ghost.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "ghost.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Selector labels */}} {{- define "ghost.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Common annotations */}} {{- define "ghost.annotations" -}} -{{- include "common.annotations" . -}} +{{- include "cloudpirates.annotations" . -}} {{- end }} {{/* Return the proper Ghost image name */}} {{- define "ghost.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "ghost.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* diff --git a/charts/ghost/templates/configmap.yaml b/charts/ghost/templates/configmap.yaml index 00e465ed..8479a508 100644 --- a/charts/ghost/templates/configmap.yaml +++ b/charts/ghost/templates/configmap.yaml @@ -5,6 +5,10 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "ghost.labels" . | nindent 4 }} + {{- with (include "ghost.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} data: config.production.json: |- { diff --git a/charts/ghost/templates/deployment.yaml b/charts/ghost/templates/deployment.yaml index efd0eff5..f1bd4e93 100644 --- a/charts/ghost/templates/deployment.yaml +++ b/charts/ghost/templates/deployment.yaml @@ -32,7 +32,7 @@ spec: {{ . | nindent 6 }} {{- end }} serviceAccountName: {{ include "ghost.serviceAccountName" . }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} {{- if .Values.mariadb.enabled }} initContainers: - name: wait-for-mariadb @@ -43,10 +43,10 @@ spec: - > retries=0; max_retries=15; - until [ $retries -ge $max_retries ] || mariadb-admin ping -h {{ include "ghost.name" . }}-mariadb - -P {{ .Values.mariadb.service.port }} - -u{{ .Values.mariadb.auth.username }} - -p{{ .Values.mariadb.auth.password }} + until [ $retries -ge $max_retries ] || mariadb-admin ping -h {{ include "ghost.fullname" . }}-mariadb + -P {{ .Values.mariadb.service.port }} + -u{{ .Values.mariadb.auth.username }} + -p{{ .Values.mariadb.auth.password }} --silent; do retries=$((retries+1)); echo "Waiting for MariaDB to become ready... (Attempt: $retries/$max_retries)"; @@ -56,13 +56,13 @@ spec: fi; sleep 2; done; - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} {{- end }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "ghost.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} #command: ["tail", "-f", "/dev/null"] ports: {{- range .Values.containerPorts }} @@ -70,11 +70,10 @@ spec: containerPort: {{ .containerPort }} protocol: {{ .protocol | default "TCP" }} {{- end }} - {{- if .Values.extraEnv }} + {{- if .Values.extraEnvVars }} env: - {{- range .Values.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} + {{- with .Values.extraEnvVars }} +{{- toYaml . | nindent 12 }} {{- end }} {{- end }} {{- if .Values.livenessProbe.enabled }} diff --git a/charts/ghost/templates/extraobjects.yaml b/charts/ghost/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/ghost/templates/extraobjects.yaml +++ b/charts/ghost/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/ghost/templates/service.yaml b/charts/ghost/templates/service.yaml index d29f9d6d..a7536786 100644 --- a/charts/ghost/templates/service.yaml +++ b/charts/ghost/templates/service.yaml @@ -5,6 +5,10 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "ghost.labels" . | nindent 4 }} + {{- with (include "ghost.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} ports: diff --git a/charts/ghost/values.schema.json b/charts/ghost/values.schema.json index 6895104f..d44bec84 100644 --- a/charts/ghost/values.schema.json +++ b/charts/ghost/values.schema.json @@ -1,388 +1,674 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "Ghost Helm Chart Values Schema", - "description": "Schema for Ghost Helm chart values", - "properties": { - "global": { - "type": "object", - "properties": { - "imageRegistry": { "type": "string" }, - "imagePullSecrets": { - "type": "array", - "items": { - "type": ["string", "object"], + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "autoscaling": { + "type": "object", "properties": { - "name": { "type": "string" } - }, - "required": ["name"] - } - } - } - }, - "nameOverride": { "type": "string" }, - "fullnameOverride": { "type": "string" }, - "commonLabels": { "type": "object", "additionalProperties": { "type": "string" } }, - "commonAnnotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "image": { - "type": "object", - "properties": { - "registry": { "type": "string" }, - "repository": { "type": "string" }, - "tag": { "type": "string" }, - "pullPolicy": { "type": "string", "enum": ["Always", "IfNotPresent", "Never"] } - } - }, - "replicaCount": { "type": "integer", "minimum": 1 }, - "containerPort": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "containerPorts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "containerPort": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "protocol": { "type": "string", "enum": ["TCP", "UDP"], "default": "TCP" } + "enabled": { + "type": "boolean" + }, + "maxReplicas": { + "type": "string" + }, + "minReplicas": { + "type": "string" + }, + "targetCPUUtilizationPercentage": { + "type": "string" + }, + "targetMemoryUtilizationPercentage": { + "type": "string" + } + } + }, + "commonAnnotations": { + "type": "object" }, - "required": ["name", "containerPort"] - } - }, - "service": { - "type": "object", - "properties": { - "type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer"] }, - "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "ports": { - "type": "array", - "items": { + "commonLabels": { + "type": "object" + }, + "config": { "type": "object", "properties": { - "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "targetPort": { "type": "string" }, - "protocol": { "type": "string", "enum": ["TCP", "UDP"], "default": "TCP" }, - "name": { "type": "string" } - }, - "required": ["port", "targetPort", "name"] - } - } - } - }, - "ingress": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "className": { "type": "string" }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "hosts": { - "type": "array", - "items": { + "adapters": { + "type": "object", + "properties": { + "cache": { + "type": "object", + "properties": { + "imageSizes": { + "type": "object", + "properties": { + "adapter": { + "type": "string" + }, + "keyPrefix": { + "type": "string" + }, + "ttl": { + "type": "integer" + } + } + } + } + } + } + }, + "caching": { + "type": "object", + "properties": { + "contentAPI": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "cors": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "customRedirects": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "frontend": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "publicAssets": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "robotstxt": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "sitemap": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "sitemapXSL": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "threeHundredOne": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + }, + "wellKnown": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer" + } + } + } + } + }, + "comments": { + "type": "object", + "properties": { + "styles": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "compress": { + "type": "boolean" + }, + "database": { + "type": "object", + "properties": { + "client": { + "type": "string" + }, + "externalConnection": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "host": { + "type": "string" + }, + "password": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "user": { + "type": "string" + } + } + }, + "pool": { + "type": "object", + "properties": { + "max": { + "type": "integer" + }, + "min": { + "type": "integer" + } + } + } + } + }, + "imageOptimization": { + "type": "object", + "properties": { + "resize": { + "type": "boolean" + } + } + }, + "logging": { + "type": "object", + "properties": { + "level": { + "type": "string" + }, + "path": { + "type": "string" + }, + "rotation": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "period": { + "type": "string" + } + } + }, + "transports": { + "type": "array", + "items": { + "type": "string" + } + }, + "useLocalTime": { + "type": "boolean" + } + } + }, + "mail": { + "type": "object", + "properties": { + "from": { + "type": "string" + }, + "options": { + "type": "object", + "properties": { + "auth": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "user": { + "type": "string" + } + } + }, + "host": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "secure": { + "type": "boolean" + }, + "service": { + "type": "string" + } + } + }, + "transport": { + "type": "string" + } + } + }, + "paths": { + "type": "object", + "properties": { + "contentPath": { + "type": "string" + } + } + }, + "portal": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, + "privacy": { + "type": "object", + "properties": { + "useGravatar": { + "type": "boolean" + }, + "useRpcPing": { + "type": "boolean" + }, + "useStructuredData": { + "type": "boolean" + }, + "useUpdateCheck": { + "type": "boolean" + } + } + }, + "referrerPolicy": { + "type": "string" + }, + "security": { + "type": "object", + "properties": { + "staffDeviceVerification": { + "type": "boolean" + } + } + }, + "server": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "port": { + "type": "integer" + } + } + }, + "sodoSearch": { + "type": "object", + "properties": { + "styles": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "storage": { + "type": "object", + "properties": { + "active": { + "type": "string" + } + } + } + } + }, + "containerPorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "containerPort": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "type": "string" + } + } + } + }, + "containerSecurityContext": { "type": "object", "properties": { - "host": { "type": "string" }, - "paths": { - "type": "array", - "items": { - "type": "object", - "properties": { - "path": { "type": "string" }, - "pathType": { "type": "string" } - }, - "required": ["path", "pathType"] + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" } - } - }, - "required": ["host", "paths"] - } + } + }, + "extraEnvVars": { + "type": "array" }, - "tls": { - "type": "array", - "items": { + "extraObjects": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "global": { "type": "object", "properties": { - "hosts": { "type": "array", "items": { "type": "string" } }, - "secretName": { "type": "string" } + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } } - } - } - } - }, - "serviceAccount": { - "type": "object", - "properties": { - "create": { "type": "boolean" }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "name": { "type": "string" }, - "automountServiceAccountToken": { "type": "boolean" } - } - }, - "autoscaling": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "minReplicas": { "type": ["integer", "string"] }, - "maxReplicas": { "type": ["integer", "string"] }, - "targetCPUUtilizationPercentage": { "type": ["integer", "string"] }, - "targetMemoryUtilizationPercentage": { "type": ["integer", "string"] } - } - }, - "resources": { "type": "object" }, - "nodeSelector": { "type": "object", "additionalProperties": { "type": "string" } }, - "tolerations": { "type": "array", "items": { "type": "object" } }, - "affinity": { "type": "object" }, - "containerSecurityContext": { - "type": "object", - "properties": { - "runAsUser": { "type": "integer" }, - "runAsNonRoot": { "type": "boolean" }, - "allowPrivilegeEscalation": { "type": "boolean" } - } - }, - "podSecurityContext": { - "type": "object", - "properties": { - "fsGroup": { "type": "integer" } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "type": { "type": "string", "enum": ["tcpSocket", "httpGet"], "default": "tcpSocket" }, - "path": { "type": "string", "default": "/" }, - "initialDelaySeconds": { "type": "integer" }, - "periodSeconds": { "type": "integer" }, - "timeoutSeconds": { "type": "integer" }, - "failureThreshold": { "type": "integer" }, - "successThreshold": { "type": "integer" } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "type": { "type": "string", "enum": ["tcpSocket", "httpGet"], "default": "tcpSocket" }, - "path": { "type": "string", "default": "/" }, - "initialDelaySeconds": { "type": "integer" }, - "periodSeconds": { "type": "integer" }, - "timeoutSeconds": { "type": "integer" }, - "failureThreshold": { "type": "integer" }, - "successThreshold": { "type": "integer" } - } - }, - "extraEnv": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "value": { "type": "string" } }, - "required": ["name", "value"] - } - }, - "extraVolumes": { "type": "array", "items": { "type": "object" } }, - "extraVolumeMounts": { "type": "array", "items": { "type": "object" } }, - "extraObjects": { "type": "array", "items": { "type": "object" } }, - "persistence": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "existingClaim": { "type": "string" }, - "storageClass": { "type": "string" }, - "accessModes": { "type": "array", "items": { "type": "string" } }, - "size": { "type": "string" } - } - }, - "initContainers": { - "type": "object", - "properties": { - "waitForMariadb": { - "type": "object", - "properties": { - "image": { "type": "string" } - } - } - } - }, - "config": { - "type": "object", - "properties": { - "database": { - "type": "object", - "properties": { - "client": { "type": "string" }, - "externalConnection": { - "type": "object", - "properties": { - "host": { "type": "string" }, - "port": { "type": "integer" }, - "user": { "type": "string" }, - "password": { "type": "string" }, - "database": { "type": "string" } - } - }, - "pool": { - "type": "object", - "properties": { - "min": { "type": "integer" }, - "max": { "type": "integer" } - } + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } } - } }, - "mail": { - "type": "object", - "properties": { - "transport": { "type": "string" }, - "options": { - "type": "object", - "properties": { - "service": { "type": "string" }, - "host": { "type": "string" }, - "port": { "type": "integer" }, - "secure": { "type": "boolean" }, - "auth": { - "type": "object", - "properties": { - "user": { "type": "string" }, - "pass": { "type": "string" } - } + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" } - } - }, - "from": { "type": "string" } - } + } }, - "server": { - "type": "object", - "properties": { - "host": { "type": "string" }, - "port": { "type": "integer" } - } + "initContainers": { + "type": "object", + "properties": { + "waitForMariadb": { + "type": "object", + "properties": { + "image": { + "type": "string" + } + } + } + } }, - "privacy": { - "type": "object", - "properties": { - "useUpdateCheck": { "type": "boolean" }, - "useGravatar": { "type": "boolean" }, - "useRpcPing": { "type": "boolean" }, - "useStructuredData": { "type": "boolean" } - } + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + }, + "type": { + "type": "string" + } + } }, - "security": { - "type": "object", - "properties": { - "staffDeviceVerification": { "type": "boolean" } - } + "mariadb": { + "type": "object", + "properties": { + "auth": { + "type": "object", + "properties": { + "allowEmptyRootPassword": { + "type": "boolean" + }, + "database": { + "type": "string" + }, + "existingSecret": { + "type": "string" + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "enabled": { + "type": "boolean" + }, + "service": { + "type": "object", + "properties": { + "port": { + "type": "integer" + } + } + } + } }, - "paths": { - "type": "object", - "properties": { - "contentPath": { "type": "string" } - } + "nameOverride": { + "type": "string" }, - "referrerPolicy": { "type": "string" }, - "logging": { - "type": "object", - "properties": { - "path": { "type": "string" }, - "useLocalTime": { "type": "boolean" }, - "level": { "type": "string" }, - "rotation": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "count": { "type": "integer" }, - "period": { "type": "string" } - } - }, - "transports": { "type": "array", "items": { "type": "string" } } - } + "nodeSelector": { + "type": "object" }, - "caching": { - "type": "object", - "additionalProperties": { - "type": ["object", "integer"], + "persistence": { + "type": "object", "properties": { - "maxAge": { "type": "integer" } + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } } - } - }, - "compress": { "type": "boolean" }, - "imageOptimization": { - "type": "object", - "properties": { - "resize": { "type": "boolean" } - } }, - "storage": { - "type": "object", - "properties": { - "active": { "type": "string" } - } - }, - "adapters": { - "type": "object", - "properties": { - "cache": { - "type": "object", - "properties": { - "imageSizes": { - "type": "object", - "properties": { - "adapter": { "type": "string" }, - "ttl": { "type": "integer" }, - "keyPrefix": { "type": "string" } - } + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" } - } } - } }, - "portal": { - "type": "object", - "properties": { - "url": { "type": "string" } - } + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + }, + "type": { + "type": "string" + } + } }, - "sodoSearch": { - "type": "object", - "properties": { - "url": { "type": "string" }, - "styles": { "type": "string" } - } + "replicaCount": { + "type": "integer" }, - "comments": { - "type": "object", - "properties": { - "url": { "type": "string" }, - "styles": { "type": "string" } - } - } - } - }, - "mariadb": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "auth": { - "type": "object", - "properties": { - "database": { "type": "string" }, - "username": { "type": "string" }, - "password": { "type": "string" }, - "existingSecret": { "type": "string" }, - "allowEmptyRootPassword": { "type": "boolean" } - } + "resources": { + "type": "object" }, "service": { - "type": "object", - "properties": { - "port": { "type": "integer" } - } + "type": "object", + "properties": { + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "targetPort": { + "type": "string" + } + } + } + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "tolerations": { + "type": "array" } - } } - } -} \ No newline at end of file +} diff --git a/charts/ghost/values.yaml b/charts/ghost/values.yaml index 2decfdf5..6e13933e 100644 --- a/charts/ghost/values.yaml +++ b/charts/ghost/values.yaml @@ -22,7 +22,7 @@ image: ## @param image.repository Nginx image repository repository: ghost ## @param image.tag Nginx image tag - tag: "6.2.0@sha256:ffc213a6f2db7210b69396dc4330b4a9c5e27c8b044ae453854d53bd3937a6ec" + tag: "6.6.0@sha256:d49be5129610c38e9c785478344943d910c141866bb91cbe17b6d451370f03e1" ## @param image.pullPolicy Nginx image pull policy pullPolicy: Always @@ -175,10 +175,15 @@ readinessProbe: ## @param readinessProbe.successThreshold Number of successes to mark probe as successful successThreshold: 1 -## @param extraEnv Additional environment variables to set -extraEnv: [] -# - name: EXTRA_VAR -# value: "extra_value" +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraVolumes Additional volumes to add to the pod extraVolumes: [] diff --git a/charts/keycloak/CHANGELOG.md b/charts/keycloak/CHANGELOG.md index e3571349..79acbb02 100644 --- a/charts/keycloak/CHANGELOG.md +++ b/charts/keycloak/CHANGELOG.md @@ -1,5 +1,195 @@ # Changelog + +## 0.8.2 (2025-11-05) + +* [keycloak]: Fix mariadb configuration (#544) ([6cec40c](https://github.com/CloudPirates-io/helm-charts/commit/6cec40c)) +* chore: update CHANGELOG.md for merged changes ([72853a9](https://github.com/CloudPirates-io/helm-charts/commit/72853a9)) +* chore: update CHANGELOG.md for merged changes ([cd5cd19](https://github.com/CloudPirates-io/helm-charts/commit/cd5cd19)) + +## 0.8.1 (2025-11-02) + +* [keycloak]: Fix https settings in keycloak when disabling http (#530) ([b0c34f6](https://github.com/CloudPirates-io/helm-charts/commit/b0c34f6)) +* chore: update CHANGELOG.md for merged changes ([3062545](https://github.com/CloudPirates-io/helm-charts/commit/3062545)) +* chore: update CHANGELOG.md for merged changes ([19b8107](https://github.com/CloudPirates-io/helm-charts/commit/19b8107)) + +## 0.8.0 (2025-10-30) + +* Provide empty mounts for themes and providers (#504) ([4d2f107](https://github.com/CloudPirates-io/helm-charts/commit/4d2f107)) +* chore: update CHANGELOG.md for merged changes ([385f22b](https://github.com/CloudPirates-io/helm-charts/commit/385f22b)) +* chore: update CHANGELOG.md for merged changes ([488fba4](https://github.com/CloudPirates-io/helm-charts/commit/488fba4)) + +## 0.7.1 (2025-10-29) + +* fix: use metrics service targetPort configuration (#493) ([bd3cc53](https://github.com/CloudPirates-io/helm-charts/commit/bd3cc53)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.7.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([aec2fd6](https://github.com/CloudPirates-io/helm-charts/commit/aec2fd6)) +* chore: update CHANGELOG.md for merged changes ([8e4ff4a](https://github.com/CloudPirates-io/helm-charts/commit/8e4ff4a)) +* chore: auto-generate values.schema.json (#473) ([d9a38d4](https://github.com/CloudPirates-io/helm-charts/commit/d9a38d4)) +* chore: update CHANGELOG.md for merged changes ([293ae00](https://github.com/CloudPirates-io/helm-charts/commit/293ae00)) +* chore: update CHANGELOG.md for merged changes ([ae9c37b](https://github.com/CloudPirates-io/helm-charts/commit/ae9c37b)) + +## 0.6.8 (2025-10-27) + +* add mssql support (#469) ([11cdbfb](https://github.com/CloudPirates-io/helm-charts/commit/11cdbfb)) +* chore: update CHANGELOG.md for merged changes ([6813d85](https://github.com/CloudPirates-io/helm-charts/commit/6813d85)) +* chore: update CHANGELOG.md for merged changes ([2e40f13](https://github.com/CloudPirates-io/helm-charts/commit/2e40f13)) + +## 0.6.7 (2025-10-26) + +* [keycloak/keycloak] Update charts/keycloak/values.yaml keycloak/keycloak to v26.4.2 (patch) (#453) ([52a01c8](https://github.com/CloudPirates-io/helm-charts/commit/52a01c8)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.6.6 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.6.5 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([c80ea42](https://github.com/CloudPirates-io/helm-charts/commit/c80ea42)) +* chore: update CHANGELOG.md for merged changes ([8ccb4bb](https://github.com/CloudPirates-io/helm-charts/commit/8ccb4bb)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b06a24e](https://github.com/CloudPirates-io/helm-charts/commit/b06a24e)) +* chore: update CHANGELOG.md for merged changes ([b70f02c](https://github.com/CloudPirates-io/helm-charts/commit/b70f02c)) +* chore: update CHANGELOG.md for merged changes ([94c7881](https://github.com/CloudPirates-io/helm-charts/commit/94c7881)) + +## 0.6.4 (2025-10-17) + +* realm import (#402) ([4257b8b](https://github.com/CloudPirates-io/helm-charts/commit/4257b8b)) +* chore: update CHANGELOG.md for merged changes ([1184994](https://github.com/CloudPirates-io/helm-charts/commit/1184994)) +* chore: update CHANGELOG.md for merged changes ([8b0e613](https://github.com/CloudPirates-io/helm-charts/commit/8b0e613)) + +## 0.6.3 (2025-10-17) + +* [keycloak/keycloak] Update charts/keycloak/values.yaml keycloak/keycloak to v26.4.1 (patch) (#400) ([c6f2ca2](https://github.com/CloudPirates-io/helm-charts/commit/c6f2ca2)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([48c9191](https://github.com/CloudPirates-io/helm-charts/commit/48c9191)) +* chore: update CHANGELOG.md for merged changes ([46b32bf](https://github.com/CloudPirates-io/helm-charts/commit/46b32bf)) + +## 0.6.2 (2025-10-14) + +* Add support for templating hostname and hostnameAdmin (#390) ([133f4d5](https://github.com/CloudPirates-io/helm-charts/commit/133f4d5)) +* chore: update CHANGELOG.md for merged changes ([848e965](https://github.com/CloudPirates-io/helm-charts/commit/848e965)) +* chore: update CHANGELOG.md for merged changes ([353c0fc](https://github.com/CloudPirates-io/helm-charts/commit/353c0fc)) + +## 0.6.1 (2025-10-14) + +* [keycloak]: Implement TLS in keycloak (#373) ([04abaee](https://github.com/CloudPirates-io/helm-charts/commit/04abaee)) +* chore: update CHANGELOG.md for merged changes ([4b02e57](https://github.com/CloudPirates-io/helm-charts/commit/4b02e57)) +* chore: update CHANGELOG.md for merged changes ([bf2e3b2](https://github.com/CloudPirates-io/helm-charts/commit/bf2e3b2)) +* chore: update CHANGELOG.md for merged changes ([2f87d0e](https://github.com/CloudPirates-io/helm-charts/commit/2f87d0e)) + +## 0.6.0 (2025-10-14) + +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.5.1 (2025-10-13) + +* chore: update CHANGELOG.md for merged changes ([a67d12a](https://github.com/CloudPirates-io/helm-charts/commit/a67d12a)) +* chore: update CHANGELOG.md for merged changes ([a4bd5ac](https://github.com/CloudPirates-io/helm-charts/commit/a4bd5ac)) + +## 0.5.0 (2025-10-13) + +* feat: add metrics (#368) ([cf5aba0](https://github.com/CloudPirates-io/helm-charts/commit/cf5aba0)) + +## 0.4.0 (2025-10-10) + +* Import realm (#219) ([f7ff0cf](https://github.com/CloudPirates-io/helm-charts/commit/f7ff0cf)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) +* [keycloak]: Fix invalid documentation (#283) ([59f3d3c](https://github.com/CloudPirates-io/helm-charts/commit/59f3d3c)) + ## 0.3.2 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* [keycloak/keycloak] Update charts/keycloak/values.yaml keycloak/keycloak to v26.4.0 (minor) (#270) ([b107e1b](https://github.com/CloudPirates-io/helm-charts/commit/b107e1b)) + +## 0.3.1 (2025-10-09) + +* [keycloak/keycloak] Update charts/keycloak/values.yaml keycloak/keycloak to v26.3.5 (patch) (#261) ([360de40](https://github.com/CloudPirates-io/helm-charts/commit/360de40)) + +## 0.3.0 (2025-10-08) + +* make keycloak run on openshift (#225) ([9b4f896](https://github.com/CloudPirates-io/helm-charts/commit/9b4f896)) + +## 0.2.1 (2025-10-07) + +* default http relative path to '/' to fix argocd deployment (#221) ([bdb1946](https://github.com/CloudPirates-io/helm-charts/commit/bdb1946)) + +## 0.2.0 (2025-10-06) + +* Add support for extra volumes, volumeMounts and initContainers (#215) ([16afcfe](https://github.com/CloudPirates-io/helm-charts/commit/16afcfe)) + +## 0.1.12 (2025-10-06) + + +## 0.1.11 (2025-10-06) + +* Allow keycloak to have a relative path (#216) ([0237457](https://github.com/CloudPirates-io/helm-charts/commit/0237457)) + +## 0.1.10 (2025-10-02) + + +## 0.1.9 (2025-10-02) + +* add topologySpreadConstraints and trafficDistribution optiโ€ฆ (#209) ([c777fca](https://github.com/CloudPirates-io/helm-charts/commit/c777fca)) + +## 0.1.8 (2025-09-30) + +* Feature/command customize (#186) ([a458e15](https://github.com/CloudPirates-io/helm-charts/commit/a458e15)) + +## 0.1.7 (2025-09-29) + +* replace deprecated 'proxy' with new proxy parameters (#183) ([d850b7b](https://github.com/CloudPirates-io/helm-charts/commit/d850b7b)) + +## 0.1.6 (2025-09-26) + + +## 0.1.5 (2025-09-25) + +* add support for extra env vars from an existing secret (#158) ([263604f](https://github.com/CloudPirates-io/helm-charts/commit/263604f)) +* Update CHANGELOG.md ([b7572a8](https://github.com/CloudPirates-io/helm-charts/commit/b7572a8)) +* Update CHANGELOG.md ([245f9b6](https://github.com/CloudPirates-io/helm-charts/commit/245f9b6)) +* Update CHANGELOG.md ([0bf9f75](https://github.com/CloudPirates-io/helm-charts/commit/0bf9f75)) + +## 0.1.4 (2025-09-24) + +* Update CHANGELOG.md ([03d476e](https://github.com/CloudPirates-io/helm-charts/commit/03d476e)) +* Bump the correct thing ([35e7901](https://github.com/CloudPirates-io/helm-charts/commit/35e7901)) +* Update CHANGELOG.md ([20c19bb](https://github.com/CloudPirates-io/helm-charts/commit/20c19bb)) + +## 0.1.3 (2025-09-23) + +* Update CHANGELOG.md ([68435aa](https://github.com/CloudPirates-io/helm-charts/commit/68435aa)) +* Fix resolving template expressions in extraobjects ([12a1cb5](https://github.com/CloudPirates-io/helm-charts/commit/12a1cb5)) + +## 0.1.2 (2025-09-22) + +* Update CHANGELOG.md ([b8adca8](https://github.com/CloudPirates-io/helm-charts/commit/b8adca8)) +* Fix chart version bump ([aae07b1](https://github.com/CloudPirates-io/helm-charts/commit/aae07b1)) +* Fix deprecated env vars warning ([50d9fa0](https://github.com/CloudPirates-io/helm-charts/commit/50d9fa0)) + +## 0.1.1 (2025-09-19) + +* Update CHANGELOG.md ([62e51b9](https://github.com/CloudPirates-io/helm-charts/commit/62e51b9)) +* add readme documentation and values.schema.json ([369448b](https://github.com/CloudPirates-io/helm-charts/commit/369448b)) +* Update CHANGELOG.md ([54f725e](https://github.com/CloudPirates-io/helm-charts/commit/54f725e)) +* chore: fix changelog ([bd9f1a8](https://github.com/CloudPirates-io/helm-charts/commit/bd9f1a8)) +* Update CHANGELOG.md ([2ed9b3f](https://github.com/CloudPirates-io/helm-charts/commit/2ed9b3f)) +* Update CHANGELOG.md ([2178148](https://github.com/CloudPirates-io/helm-charts/commit/2178148)) + +## 0.1.0 (2025-09-17) + +* Initial tagged release diff --git a/charts/keycloak/Chart.lock b/charts/keycloak/Chart.lock index 85b2f901..0cd60f93 100644 --- a/charts/keycloak/Chart.lock +++ b/charts/keycloak/Chart.lock @@ -1,12 +1,12 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 + version: 2.0.0 - name: postgres repository: oci://registry-1.docker.io/cloudpirates - version: 0.7.2 + version: 0.9.0 - name: mariadb repository: oci://registry-1.docker.io/cloudpirates - version: 0.3.2 -digest: sha256:886649f9f78f7bf1f296dabcca5eb8cd0dbd9d0fdb540a327e6a299817fd4b53 -generated: "2025-10-07T21:13:04.453964+02:00" + version: 0.4.0 +digest: sha256:463f4ba9998938275a7f067fe0d027654755735c164f48285ebc219f025d28b9 +generated: "2025-10-14T13:20:51.905266+02:00" diff --git a/charts/keycloak/Chart.yaml b/charts/keycloak/Chart.yaml index 2e61bbc7..54442212 100644 --- a/charts/keycloak/Chart.yaml +++ b/charts/keycloak/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: keycloak description: Open Source Identity and Access Management Solution type: application -version: 0.3.2 -appVersion: "26.3.4" +version: 0.8.2 +appVersion: "26.4.2" keywords: - keycloak - identity @@ -13,22 +13,46 @@ keywords: - oauth - openid-connect - saml -home: https://www.cloudpirates.io +home: https://www.keycloak.org sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/keycloak + - https://github.com/keycloak/keycloak maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates - name: postgres - version: "0.x.x" + version: "0.9.x" repository: oci://registry-1.docker.io/cloudpirates condition: postgres.enabled - name: mariadb - version: "0.x.x" + version: "0.4.x" repository: oci://registry-1.docker.io/cloudpirates condition: mariadb.enabled icon: https://a.storyblok.com/f/143071/512x512/6a85e594b2/keycloak-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: security + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: Keycloak + url: https://www.keycloak.org + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/keycloak + - name: Application + url: https://github.com/keycloak/keycloak + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "[keycloak]: Fix mariadb configuration (#544)" + links: + - name: "Commit 6cec40c" + url: "https://github.com/CloudPirates-io/helm-charts/commit/6cec40c" diff --git a/charts/keycloak/LICENSE b/charts/keycloak/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/charts/keycloak/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/keycloak/README.md b/charts/keycloak/README.md index 10372ca3..872bf10d 100644 --- a/charts/keycloak/README.md +++ b/charts/keycloak/README.md @@ -108,9 +108,9 @@ The following table lists the configurable parameters of the Keycloak chart and ### Extra init containers for Keycloak pod -| Parameter | Description | Default | -| --------------------- | ----------------------------------------------------- | ------- | -| `extraInitContainers` | Array of initContainer to add to the keycloak pod | `[]` | +| Parameter | Description | Default | +| --------------------- | ------------------------------------------------- | ------- | +| `extraInitContainers` | Array of initContainer to add to the keycloak pod | `[]` | ### Security @@ -144,21 +144,49 @@ The following table lists the configurable parameters of the Keycloak chart and | `keycloak.proxyTrustedAddresses` | A comma separated list of trusted proxy addresses | `""` | | `keycloak.production` | Enable production mode | `false` | | `keycloak.httpRelativePath` | Set relative path for serving resources; must start with a / | `""` | +| `keycloak.extraArgs` | Additional arguments to pass to the Keycloak startup command | `[]` | + +### TLS Configuration + +| Parameter | Description | Default | +| --------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------- | +| `tls.enabled` | Enable TLS/HTTPS support using custom certificates | `false` | +| `tls.existingSecret` | Name of existing secret containing TLS certificate and key (PEM format, keys: tls.crt, tls.key) | `""` | +| `tls.certificateFile` | Path where the TLS certificate file will be mounted (internal) | `"/opt/keycloak/certs/tls.crt"` | +| `tls.certificateKeyFile` | Path where the TLS certificate key file will be mounted (internal) | `"/opt/keycloak/certs/tls.key"` | +| `tls.certManager.enabled` | Enable cert-manager integration for automatic certificate provisioning | `false` | +| `tls.certManager.issuerRef.name` | Name of the cert-manager Issuer or ClusterIssuer | `""` | +| `tls.certManager.issuerRef.kind` | Kind of the cert-manager issuer (Issuer or ClusterIssuer) | `ClusterIssuer` | +| `tls.certManager.issuerRef.group` | Group of the cert-manager issuer | `cert-manager.io` | +| `tls.certManager.duration` | Certificate duration (e.g., 2160h for 90 days) | `""` | +| `tls.certManager.renewBefore` | Time before expiry to renew certificate (e.g., 360h for 15 days) | `""` | +| `tls.certManager.commonName` | Certificate common name (defaults to first dnsName if not specified) | `""` | +| `tls.certManager.dnsNames` | List of DNS names for the certificate (uses ingress.hosts if not specified) | `[]` | +| `tls.certManager.ipAddresses` | List of IP addresses for the certificate | `[]` | +| `tls.certManager.secretName` | Name for the generated secret (defaults to `-tls`) | `""` | +| `tls.certManager.usages` | Certificate key usages | `["digital signature", "key encipherment"]` | +| `tls.certManager.annotations` | Additional annotations for the Certificate resource | `{}` | +| `tls.truststoreEnabled` | Enable truststore for client certificate validation or outgoing HTTPS requests | `false` | +| `tls.truststoreExistingSecret` | Name of existing secret containing truststore file (Java Keystore format, key: truststore.jks) | `""` | +| `tls.truststorePassword` | Password for the truststore (use with caution - consider using existing secret) | `""` | +| `tls.truststoreFile` | Path where the truststore file will be mounted (internal) | `"/opt/keycloak/truststore/truststore.jks"` | ### Database Configuration -| Parameter | Description | Default | -| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | --------------- | -| `database.type` | Database type (postgres, mysql, mariadb). Note: H2 databases are not supported due to readonly filesystem restrictions | `postgres` | -| `database.host` | Database host (only used when not using embedded database) | `""` | -| `database.port` | Database port (only used when not using embedded database, defaults: postgres=5432, mysql/mariadb=3306) | `""` | -| `database.name` | Database name (only used when not using embedded database) | `keycloak` | -| `database.username` | Database username (only used when not using embedded database) | `keycloak` | -| `database.password` | Database password (only used when not using embedded database) | `""` | -| `database.existingSecret` | Name of existing secret for database credentials (only used when not using embedded database) | `""` | -| `database.secretKeys.passwordKey` | Name of key in existing secret for database password | `"db-password"` | -| `database.secretKeys.usernameKey` | Name of key in existing secret for database username | `"db-username"` | -| `database.jdbcParams` | Additional JDBC parameters | `""` | +| Parameter | Description | Default | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------- | +| `database.type` | Database type (postgres, mysql, mariadb, mssql). Note: H2 databases are not supported due to readonly filesystem restrictions | `postgres` | +| `database.host` | Database host (only used when not using embedded database) | `""` | +| `database.port` | Database port (only used when not using embedded database, defaults: postgres=5432, mysql/mariadb=3306, mssql=1433) | `""` | +| `database.schema` | Database schema | `""` | +| `database.urlProperties` | Additional database url properties | `""` | +| `database.name` | Database name (only used when not using embedded database) | `keycloak` | +| `database.username` | Database username (only used when not using embedded database) | `keycloak` | +| `database.password` | Database password (only used when not using embedded database) | `""` | +| `database.existingSecret` | Name of existing secret for database credentials (only used when not using embedded database) | `""` | +| `database.secretKeys.passwordKey` | Name of key in existing secret for database password | `"db-password"` | +| `database.secretKeys.usernameKey` | Name of key in existing secret for database username | `"db-username"` | +| `database.jdbcParams` | Additional JDBC parameters | `""` | ### Cache Configuration @@ -167,6 +195,13 @@ The following table lists the configurable parameters of the Keycloak chart and | `cache.stack` | Cache stack (local, ispn, default) | `local` | | `cache.configFile` | Custom cache configuration file | `""` | +### Realm Configuration + +| Parameter | Description | Default | +| ------------------ | -------------------------------------------------------------------------------------- | ------- | +| `realm.import` | Enable import of realms from /opt/keycloak/data/import (production mode must be false) | `false` | +| `realm.configFile` | Json config for initial realm configuration, mounted in /opt/keycloak/data/import | `""` | + ### Features Configuration | Parameter | Description | Default | @@ -215,6 +250,27 @@ The following table lists the configurable parameters of the Keycloak chart and | `persistence.accessModes` | Persistent Volume access modes | `["ReadWriteOnce"]` | | `persistence.existingClaim` | The name of an existing PVC to use for persistence | `""` | +### Metrics + +| Parameter | Description | Default | +| ------------------------------------------ | -------------------------------------------------------------------------------- | -------------- | +| `metrics.enabled` | Enable metrics endpoint on Keycloak | `false` | +| `metrics.service.type` | Metrics service type | `ClusterIP` | +| `metrics.service.port` | Metrics service port | `9000` | +| `metrics.service.targetPort` | Metrics service target port | `http-metrics` | +| `metrics.service.annotations` | Additional annotations for metrics service | `{}` | +| `metrics.service.labels` | Additional labels for metrics service | `{}` | +| `metrics.serviceMonitor.enabled` | Create ServiceMonitor resource for scraping metrics using PrometheusOperator | `false` | +| `metrics.serviceMonitor.namespace` | Namespace in which ServiceMonitor is created | `""` | +| `metrics.serviceMonitor.interval` | Interval at which metrics should be scraped | `30s` | +| `metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `""` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels for ServiceMonitor | `{}` | +| `metrics.serviceMonitor.annotations` | Additional annotations for ServiceMonitor | `{}` | +| `metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | MetricRelabelConfigs to apply to samples before ingestion | `[]` | +| `metrics.serviceMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | +| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in Prometheus | `""` | + ### Liveness and readiness probes | Parameter | Description | Default | @@ -260,7 +316,7 @@ The following table lists the configurable parameters of the Keycloak chart and | Parameter | Description | Default | | -------------------- | ---------------------------------------------------------------------- | ------- | -| `extraEnv` | Additional environment variables from key-value pairs | `{}` | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraEnvVarsSecret` | Name of an existing secret containing additional environment variables | `` | ### Extra Configuration Parameters @@ -460,6 +516,171 @@ kubectl create secret generic keycloak-db-credentials \ --from-literal=db-username=keycloak ``` +### Realm import + +```yaml +realm: + import: true + configFile: | + { + "realm": "my-realm", + "enabled": true + } +``` + +### Using Custom Themes and Providers + +The Keycloak deployment automatically mounts empty directories at `/opt/keycloak/themes` and `/opt/keycloak/providers`. You can use initContainers to copy custom themes and providers into these directories. + +**Example: Adding custom themes and providers with an initContainer** + +```yaml +# values-custom-themes.yaml +extraInitContainers: + - name: add-custom-themes + image: your-registry/keycloak-themes:latest + imagePullPolicy: Always + command: + - sh + - -c + - | + cp -r /themes/* /opt/keycloak/themes/ + cp -r /providers/* /opt/keycloak/providers/ + volumeMounts: + - name: keycloak-themes + mountPath: /opt/keycloak/themes + - name: keycloak-providers + mountPath: /opt/keycloak/providers +``` + +In this example: +- Create a Docker image containing your custom themes in `/themes` and providers in `/providers` +- The initContainer copies these files to the mounted volumes +- Keycloak will automatically detect and use them on startup + +You can also use this approach to download themes/providers from external sources: + +```yaml +extraInitContainers: + - name: download-themes + image: curlimages/curl:latest + command: + - sh + - -c + - | + curl -L -o /tmp/theme.zip https://example.com/theme.zip + unzip /tmp/theme.zip -d /opt/keycloak/themes/ + volumeMounts: + - name: keycloak-themes + mountPath: /opt/keycloak/themes +``` + +### Using Custom TLS Certificates + +#### Option 1: Using cert-manager (Recommended) + +Automatically provision and renew certificates using cert-manager: + +```yaml +# values-tls-certmanager.yaml +tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: "letsencrypt-prod" + kind: ClusterIssuer + # dnsNames will be automatically populated from ingress.hosts if not specified + dnsNames: + - auth.yourdomain.com + +keycloak: + httpEnabled: false # Disable HTTP when using TLS + production: true + hostname: "auth.yourdomain.com" + +ingress: + enabled: true + className: "nginx" + hosts: + - host: auth.yourdomain.com + paths: + - path: / + pathType: Prefix +``` + +**Prerequisites:** +- cert-manager must be installed in your cluster +- A ClusterIssuer or Issuer must be configured (e.g., Let's Encrypt) + +Install cert-manager if not already installed: + +```bash +kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml +``` + +Create a ClusterIssuer for Let's Encrypt: + +```yaml +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: your-email@example.com + privateKeySecretRef: + name: letsencrypt-prod + solvers: + - http01: + ingress: + class: nginx +``` + +#### Option 2: Using Existing TLS Certificates + +Use pre-existing certificates: + +```yaml +# values-tls.yaml +tls: + enabled: true + existingSecret: "keycloak-tls-certs" + +keycloak: + httpEnabled: false # Disable HTTP when using TLS + production: true + hostname: "auth.yourdomain.com" +``` + +Create the TLS secret first with your certificate and key in PEM format: + +```bash +kubectl create secret tls keycloak-tls-certs \ + --cert=/path/to/certificate.pem \ + --key=/path/to/private-key.pem +``` + +#### Using Truststore for Client Certificates or Outgoing HTTPS + +```yaml +# values-tls-truststore.yaml +tls: + enabled: true + existingSecret: "keycloak-tls-certs" + truststoreEnabled: true + truststoreExistingSecret: "keycloak-truststore" + truststorePassword: "changeit" +``` + +Create the truststore secret: + +```bash +kubectl create secret generic keycloak-truststore \ + --from-file=truststore.jks=/path/to/truststore.jks +``` + ### High Availability Setup ```yaml @@ -594,4 +815,4 @@ For issues related to this Helm chart, please check: - [Keycloak Documentation](https://www.keycloak.org/documentation) - [Keycloak Server Administration Guide](https://www.keycloak.org/docs/latest/server_admin/) - [Kubernetes Documentation](https://kubernetes.io/docs/) -- Chart repository issues +- Chart repository issues \ No newline at end of file diff --git a/charts/keycloak/templates/_helpers.tpl b/charts/keycloak/templates/_helpers.tpl index 4b26f025..7b64ba9a 100644 --- a/charts/keycloak/templates/_helpers.tpl +++ b/charts/keycloak/templates/_helpers.tpl @@ -2,7 +2,7 @@ Expand the name of the chart. */}} {{- define "keycloak.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* @@ -11,21 +11,21 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "keycloak.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "keycloak.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "keycloak.labels" -}} -{{- include "common.labels" . -}} +{{- include "cloudpirates.labels" . -}} {{- end }} {{/* @@ -41,14 +41,14 @@ Common annotations Selector labels */}} {{- define "keycloak.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Return the proper Keycloak image name */}} {{- define "keycloak.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* @@ -56,7 +56,7 @@ Return Keycloak admin credentials secret name */}} {{- define "keycloak.secretName" -}} {{- if .Values.keycloak.existingSecret -}} - {{- .Values.keycloak.existingSecret -}} + {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.keycloak.existingSecret "context" .) -}} {{- else -}} {{- include "keycloak.fullname" . -}} {{- end -}} @@ -110,7 +110,7 @@ db-username Return the proper Docker Image Registry Secret Names */}} {{- define "keycloak.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* @@ -129,7 +129,7 @@ Return the Keycloak hostname */}} {{- define "keycloak.hostname" -}} {{- if .Values.keycloak.hostname -}} -{{- .Values.keycloak.hostname -}} +{{- tpl (.Values.keycloak.hostname | toString) $ -}} {{- else if .Values.ingress.enabled -}} {{- (index .Values.ingress.hosts 0).host -}} {{- else -}} @@ -142,7 +142,7 @@ Return the Keycloak admin hostname */}} {{- define "keycloak.hostnameAdmin" -}} {{- if .Values.keycloak.hostnameAdmin -}} -{{- .Values.keycloak.hostnameAdmin -}} +{{- tpl (.Values.keycloak.hostnameAdmin | toString) $ -}} {{- else -}} {{- include "keycloak.hostname" . -}} {{- end -}} @@ -175,10 +175,12 @@ Return the database JDBC URL {{- end -}} {{- else if or (eq .Values.database.type "mysql") (eq .Values.database.type "mariadb") -}} {{- if .Values.mariadb.enabled -}} -{{- printf "jdbc:mysql://%s-mariadb:%s/%s%s" .Release.Name "3306" (default "keycloak" .Values.mariadb.auth.database) (ternary (printf "?%s" .Values.database.jdbcParams) "" (ne .Values.database.jdbcParams "")) -}} +{{- printf "jdbc:%s://%s-mariadb:%s/%s%s" .Values.database.type .Release.Name "3306" (default "keycloak" .Values.mariadb.auth.database) (ternary (printf "?%s" .Values.database.jdbcParams) "" (ne .Values.database.jdbcParams "")) -}} {{- else -}} -{{- printf "jdbc:mysql://%s:%s/%s%s" .Values.database.host (default "3306" (.Values.database.port | toString)) .Values.database.name (ternary (printf "?%s" .Values.database.jdbcParams) "" (ne .Values.database.jdbcParams "")) -}} +{{- printf "jdbc:%s://%s:%s/%s%s" .Values.database.type .Values.database.host (default "3306" (.Values.database.port | toString)) .Values.database.name (ternary (printf "?%s" .Values.database.jdbcParams) "" (ne .Values.database.jdbcParams "")) -}} {{- end -}} +{{- else if eq .Values.database.type "mssql" -}} +{{- printf "jdbc:mssql://%s:%s/%s%s" .Values.database.host (default "1433" (.Values.database.port | toString)) .Values.database.name (ternary (printf "?%s" .Values.database.jdbcParams) "" (ne .Values.database.jdbcParams "")) -}} {{- end -}} {{- end }} @@ -191,4 +193,45 @@ Return the url to use for probes {{- else -}} {{- printf "%s/realms/master" .Values.keycloak.httpRelativePath -}} {{- end -}} -{{- end }} \ No newline at end of file +{{- end }} + +{{/* +Return TLS certificate secret name +*/}} +{{- define "keycloak.tlsSecretName" -}} +{{- if .Values.tls.certManager.enabled -}} + {{- .Values.tls.certManager.secretName | default (printf "%s-tls" (include "keycloak.fullname" .)) -}} +{{- else if .Values.tls.existingSecret -}} + {{- .Values.tls.existingSecret -}} +{{- else -}} + {{- printf "%s-tls" (include "keycloak.fullname" .) -}} +{{- end -}} +{{- end }} + +{{/* +Return TLS truststore secret name +*/}} +{{- define "keycloak.truststoreSecretName" -}} +{{- if .Values.tls.truststoreExistingSecret -}} + {{- .Values.tls.truststoreExistingSecret -}} +{{- else -}} + {{- printf "%s-truststore" (include "keycloak.fullname" .) -}} +{{- end -}} +{{- end }} + +{{/* +Return metrics service name +*/}} +{{- define "keycloak.metrics.fullname" -}} +{{- printf "%s-metrics" (include "keycloak.fullname" .) -}} +{{- end -}} + +{{/* +Return ServiceMonitor labels +*/}} +{{- define "keycloak.metrics.serviceMonitor.labels" -}} +{{- include "keycloak.labels" . }} +{{- with .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml . }} +{{- end }} +{{- end -}} diff --git a/charts/keycloak/templates/certificate.yaml b/charts/keycloak/templates/certificate.yaml new file mode 100644 index 00000000..d06a13b3 --- /dev/null +++ b/charts/keycloak/templates/certificate.yaml @@ -0,0 +1,55 @@ +{{- if and .Values.tls.enabled .Values.tls.certManager.enabled }} +{{- $fullName := include "keycloak.fullname" . -}} +{{- $secretName := .Values.tls.certManager.secretName | default (printf "%s-tls" $fullName) -}} +{{- $dnsNames := .Values.tls.certManager.dnsNames -}} +{{- if and (not $dnsNames) .Values.ingress.enabled }} + {{- $dnsNames = list }} + {{- range .Values.ingress.hosts }} + {{- $dnsNames = append $dnsNames .host }} + {{- end }} +{{- end }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ $fullName }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "keycloak.labels" . | nindent 4 }} + {{- with .Values.tls.certManager.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + secretName: {{ $secretName }} + {{- if .Values.tls.certManager.duration }} + duration: {{ .Values.tls.certManager.duration }} + {{- end }} + {{- if .Values.tls.certManager.renewBefore }} + renewBefore: {{ .Values.tls.certManager.renewBefore }} + {{- end }} + issuerRef: + name: {{ .Values.tls.certManager.issuerRef.name | required "tls.certManager.issuerRef.name is required when cert-manager is enabled" }} + kind: {{ .Values.tls.certManager.issuerRef.kind }} + {{- if .Values.tls.certManager.issuerRef.group }} + group: {{ .Values.tls.certManager.issuerRef.group }} + {{- end }} + {{- if .Values.tls.certManager.commonName }} + commonName: {{ .Values.tls.certManager.commonName }} + {{- else if $dnsNames }} + commonName: {{ index $dnsNames 0 }} + {{- end }} + {{- if $dnsNames }} + dnsNames: + {{- range $dnsNames }} + - {{ . }} + {{- end }} + {{- end }} + {{- with .Values.tls.certManager.ipAddresses }} + ipAddresses: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.tls.certManager.usages }} + usages: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/keycloak/templates/configmap.yaml b/charts/keycloak/templates/configmap.yaml index 34160321..dd18c08a 100644 --- a/charts/keycloak/templates/configmap.yaml +++ b/charts/keycloak/templates/configmap.yaml @@ -13,4 +13,21 @@ metadata: data: cache-ispn.xml: | {{- .Values.cache.configFile | nindent 4 }} -{{- end }} \ No newline at end of file +{{- end }} +{{- if .Values.realm.configFile }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ include "keycloak.fullname" . }}-realm + namespace: {{ .Release.Namespace }} + labels: + {{- include "keycloak.labels" . | nindent 4 }} + {{- with (include "keycloak.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +data: + realm.json: | + {{ .Values.realm.configFile | nindent 4 }} +{{- end }} diff --git a/charts/keycloak/templates/deployment.yaml b/charts/keycloak/templates/deployment.yaml index 6c309346..c8d2865c 100644 --- a/charts/keycloak/templates/deployment.yaml +++ b/charts/keycloak/templates/deployment.yaml @@ -29,12 +29,12 @@ spec: serviceAccountName: {{ include "keycloak.serviceAccountName" . }} automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} {{- with (include "keycloak.imagePullSecrets" .) }} -{{ . | nindent 6 }} +{{- . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} initContainers: - name: copy-quarkus-lib - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "keycloak.image" . }} imagePullPolicy: {{ .Values.image.imagePullPolicy }} command: ["sh", "-c", "cp -r /opt/keycloak/lib/quarkus/* /shared-quarkus/"] @@ -43,21 +43,21 @@ spec: mountPath: /shared-quarkus {{- if .Values.postgres.enabled }} - name: wait-for-postgres - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ .Values.initContainers.waitForPostgres.image }} command: ["sh", "-c", "until pg_isready -h {{ .Release.Name }}-postgres -p 5432 -U postgres; do echo waiting for database; sleep 2; done;"] {{- else if .Values.mariadb.enabled }} - name: wait-for-mariadb - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ .Values.initContainers.waitForMariadb.image }} - command: ["sh", "-c", "until mysqladmin ping -h {{ .Release.Name }}-mariadb -P 3306 --silent; do echo waiting for database; sleep 2; done;"] + command: ["sh", "-c", "until mariadb-admin ping -h {{ .Release.Name }}-mariadb -P 3306 --silent; do echo waiting for database; sleep 2; done;"] {{- end }} {{- if .Values.extraInitContainers }} {{- toYaml .Values.extraInitContainers | nindent 8 }} {{- end }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "keycloak.image" . }} imagePullPolicy: {{ .Values.image.imagePullPolicy }} command: @@ -67,6 +67,9 @@ spec: - start {{- else }} - start-dev + {{- if .Values.realm.import }} + - --import-realm + {{- end }} {{- end }} {{- if .Values.keycloak.httpEnabled }} - --http-enabled=true @@ -109,6 +112,22 @@ spec: {{- if .Values.features.disabled }} - --features-disabled={{ join "," .Values.features.disabled }} {{- end }} + {{- if .Values.metrics.enabled }} + - --metrics-enabled=true + {{- end }} + {{- with .Values.keycloak.extraArgs }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.tls.enabled }} + - --https-certificate-file={{ .Values.tls.certificateFile }} + - --https-certificate-key-file={{ .Values.tls.certificateKeyFile }} + {{- end }} + {{- if .Values.tls.truststoreEnabled }} + - --https-trust-store-file={{ .Values.tls.truststoreFile }} + {{- if .Values.tls.truststorePassword }} + - --https-trust-store-password={{ .Values.tls.truststorePassword }} + {{- end }} + {{- end }} env: - name: KC_HTTP_RELATIVE_PATH value: {{ .Values.keycloak.httpRelativePath | quote | default "/" }} @@ -119,6 +138,18 @@ spec: secretKeyRef: name: {{ include "keycloak.secretName" . }} key: {{ include "keycloak.adminPasswordKey" . }} + {{- if .Values.database.type }} + - name: KC_DB + value: {{ .Values.database.type }} + {{- end }} + {{- if .Values.database.schema }} + - name: KC_DB_SCHEMA + value: {{ .Values.database.schema }} + {{- end }} + {{- if .Values.database.urlProperties }} + - name: KC_DB_URL_PROPERTIES + value: {{ .Values.database.urlProperties | quote }} + {{- end }} {{- if or (eq .Values.database.type "postgres") (eq .Values.database.type "mysql") (eq .Values.database.type "mariadb") }} - name: KC_DB_USERNAME {{- if and (eq .Values.database.type "postgres") .Values.postgres.enabled }} @@ -149,9 +180,8 @@ spec: key: {{ include "keycloak.databasePasswordKey" . }} {{- end }} {{- end }} - {{- range $key, $value := .Values.extraEnv }} - - name: {{ $key }} - value: {{ $value | quote }} + {{- with .Values.extraEnvVars }} +{{- toYaml . | nindent 12 }} {{- end }} {{- if .Values.extraEnvVarsSecret }} envFrom: @@ -159,20 +189,31 @@ spec: name: {{ .Values.extraEnvVarsSecret }} {{- end }} ports: + {{- if .Values.keycloak.httpEnabled }} - name: http containerPort: {{ .Values.keycloak.httpPort }} protocol: TCP - {{- if .Values.keycloak.httpsPort }} + {{- else }} - name: https containerPort: {{ .Values.keycloak.httpsPort }} protocol: TCP {{- end }} + {{- if .Values.metrics.enabled }} + - name: {{ .Values.metrics.service.targetPort }} + containerPort: {{ .Values.metrics.service.port }} + protocol: TCP + {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: httpGet: path: {{ include "keycloak.probeUrl" . }} + {{- if .Values.keycloak.httpEnabled }} port: http scheme: HTTP + {{- else }} + port: https + scheme: HTTPS + {{- end }} initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} @@ -183,8 +224,13 @@ spec: readinessProbe: httpGet: path: {{ include "keycloak.probeUrl" . }} + {{- if .Values.keycloak.httpEnabled }} port: http scheme: HTTP + {{- else }} + port: https + scheme: HTTPS + {{- end }} initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} @@ -195,8 +241,13 @@ spec: startupProbe: httpGet: path: {{ include "keycloak.probeUrl" . }} + {{- if .Values.keycloak.httpEnabled }} port: http scheme: HTTP + {{- else }} + port: https + scheme: HTTPS + {{- end }} initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} periodSeconds: {{ .Values.startupProbe.periodSeconds }} timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} @@ -220,10 +271,28 @@ spec: mountPath: /opt/keycloak/work - name: keycloak-lib-quarkus mountPath: /opt/keycloak/lib/quarkus + - name: keycloak-themes + mountPath: /opt/keycloak/themes + - name: keycloak-providers + mountPath: /opt/keycloak/providers + {{- if .Values.realm.configFile }} + - name: realm-config + mountPath: /opt/keycloak/data/import + readOnly: true + {{- end }} + {{- if .Values.tls.enabled }} + - name: tls-certs + mountPath: /opt/keycloak/certs + readOnly: true + {{- end }} + {{- if .Values.tls.truststoreEnabled }} + - name: tls-truststore + mountPath: /opt/keycloak/truststore + readOnly: true + {{- end }} {{- if .Values.extraVolumeMounts }} {{- toYaml .Values.extraVolumeMounts | nindent 12}} {{- end }} - volumes: {{- if .Values.persistence.enabled }} - name: data @@ -244,9 +313,36 @@ spec: emptyDir: {} - name: keycloak-lib-quarkus emptyDir: {} - {{- if .Values.extraVolumes }} - {{- toYaml .Values.extraVolumes | nindent 8 }} - {{- end }} + - name: keycloak-themes + emptyDir: {} + - name: keycloak-providers + emptyDir: {} + {{- if .Values.realm.configFile }} + - name: realm-config + configMap: + name: {{ include "keycloak.fullname" . }}-realm + {{- end }} + {{- if .Values.tls.enabled }} + - name: tls-certs + secret: + secretName: {{ include "keycloak.tlsSecretName" . }} + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + {{- end }} + {{- if .Values.tls.truststoreEnabled }} + - name: tls-truststore + secret: + secretName: {{ .Values.tls.truststoreExistingSecret }} + items: + - key: truststore.jks + path: truststore.jks + {{- end }} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/keycloak/templates/extraobjects.yaml b/charts/keycloak/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/keycloak/templates/extraobjects.yaml +++ b/charts/keycloak/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/keycloak/templates/ingress.yaml b/charts/keycloak/templates/ingress.yaml index 7fee0bd1..04dfce8b 100644 --- a/charts/keycloak/templates/ingress.yaml +++ b/charts/keycloak/templates/ingress.yaml @@ -1,6 +1,7 @@ {{- if .Values.ingress.enabled -}} {{- $fullName := include "keycloak.fullname" . -}} {{- $httpPort := .Values.service.httpPort -}} +{{- $httpsPort := .Values.service.httpsPort -}} {{- if and .Values.ingress.className (not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class")) }} {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} {{- end }} @@ -11,9 +12,13 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "keycloak.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} + {{- $annotations := merge .Values.ingress.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} + {{- if not $.Values.keycloak.httpEnabled }} + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + {{- end }} {{- end }} spec: {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} @@ -44,10 +49,18 @@ spec: service: name: {{ $fullName }} port: + {{- if $.Values.keycloak.httpEnabled }} number: {{ $httpPort }} + {{- else }} + number: {{ $httpsPort }} + {{- end }} {{- else }} serviceName: {{ $fullName }} + {{- if $.Values.keycloak.httpEnabled }} servicePort: {{ $httpPort }} + {{- else }} + servicePort: {{ $httpsPort }} + {{- end }} {{- end }} {{- end }} {{- end }} diff --git a/charts/keycloak/templates/metrics-service.yaml b/charts/keycloak/templates/metrics-service.yaml new file mode 100644 index 00000000..7245452a --- /dev/null +++ b/charts/keycloak/templates/metrics-service.yaml @@ -0,0 +1,27 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "keycloak.metrics.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "keycloak.labels" . | nindent 4 }} + app.kubernetes.io/component: metrics + {{- with .Values.metrics.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- $annotations := merge .Values.metrics.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.metrics.service.type }} + ports: + - port: {{ .Values.metrics.service.port }} + targetPort: {{ .Values.metrics.service.targetPort }} + protocol: TCP + name: {{ .Values.metrics.service.targetPort }} + selector: + {{- include "keycloak.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/keycloak/templates/metrics-servicemonitor.yaml b/charts/keycloak/templates/metrics-servicemonitor.yaml new file mode 100644 index 00000000..71b71531 --- /dev/null +++ b/charts/keycloak/templates/metrics-servicemonitor.yaml @@ -0,0 +1,49 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "keycloak.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace | quote }} + {{- else }} + namespace: {{ .Release.Namespace | quote }} + {{- end }} + labels: + {{- include "keycloak.metrics.serviceMonitor.labels" . | nindent 4 }} + {{- $annotations := merge .Values.metrics.serviceMonitor.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.metrics.serviceMonitor.jobLabel }} + jobLabel: {{ .Values.metrics.serviceMonitor.jobLabel }} + {{- end }} + selector: + matchLabels: + {{- include "keycloak.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: metrics + namespaceSelector: + matchNames: + - {{ .Release.Namespace | quote }} + endpoints: + - port: {{ .Values.metrics.service.targetPort }} + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- end }} + path: /metrics + {{- with .Values.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/keycloak/templates/pvc.yaml b/charts/keycloak/templates/pvc.yaml index 7facd396..a614af17 100644 --- a/charts/keycloak/templates/pvc.yaml +++ b/charts/keycloak/templates/pvc.yaml @@ -6,7 +6,8 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "keycloak.labels" . | nindent 4 }} - {{- with .Values.persistence.annotations }} + {{- $annotations := merge .Values.persistence.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/keycloak/templates/service.yaml b/charts/keycloak/templates/service.yaml index ce4cafb4..a5e541cf 100644 --- a/charts/keycloak/templates/service.yaml +++ b/charts/keycloak/templates/service.yaml @@ -5,18 +5,20 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "keycloak.labels" . | nindent 4 }} - {{- with .Values.service.annotations }} + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} spec: type: {{ .Values.service.type }} ports: + {{- if .Values.keycloak.httpEnabled }} - port: {{ .Values.service.httpPort }} targetPort: {{ .Values.service.httpTargetPort }} protocol: TCP name: http - {{- if .Values.keycloak.httpsPort }} + {{- else }} - port: {{ .Values.service.httpsPort }} targetPort: {{ .Values.service.httpsTargetPort }} protocol: TCP diff --git a/charts/keycloak/templates/serviceaccount.yaml b/charts/keycloak/templates/serviceaccount.yaml index 63749406..faa06329 100644 --- a/charts/keycloak/templates/serviceaccount.yaml +++ b/charts/keycloak/templates/serviceaccount.yaml @@ -6,7 +6,8 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "keycloak.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} + {{- $annotations := merge .Values.serviceAccount.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/keycloak/tests/common-parameters_test.yaml b/charts/keycloak/tests/common-parameters_test.yaml index 7bebee84..17cd7b90 100644 --- a/charts/keycloak/tests/common-parameters_test.yaml +++ b/charts/keycloak/tests/common-parameters_test.yaml @@ -22,7 +22,7 @@ tests: template: templates/deployment.yaml - equal: path: spec.template.spec.containers[0].image - value: docker.io/keycloak/keycloak:26.4.0@sha256:5f3fb534cde6bf006d79f5912473e5d2c828c707cdfc52e16972803aca9d43dd + value: docker.io/keycloak/keycloak:26.4.2@sha256:3617b09bb4b7510a8d8d9b9fc5707399e2d70688dbcc2f8fb013a144829be1b9 template: templates/deployment.yaml - it: should render custom name and fullname overrides @@ -62,7 +62,7 @@ tests: asserts: - equal: path: spec.template.spec.containers[0].image - value: custom-registry.io/keycloak/keycloak:26.4.0@sha256:5f3fb534cde6bf006d79f5912473e5d2c828c707cdfc52e16972803aca9d43dd + value: custom-registry.io/keycloak/keycloak:26.4.2@sha256:3617b09bb4b7510a8d8d9b9fc5707399e2d70688dbcc2f8fb013a144829be1b9 template: templates/deployment.yaml - it: should render custom replica count diff --git a/charts/keycloak/tests/deployment-parameters_test.yaml b/charts/keycloak/tests/deployment-parameters_test.yaml index 4261ae6f..4c1f869a 100644 --- a/charts/keycloak/tests/deployment-parameters_test.yaml +++ b/charts/keycloak/tests/deployment-parameters_test.yaml @@ -14,4 +14,38 @@ tests: asserts: - equal: path: spec.template.spec.containers[0].readinessProbe.httpGet.path - value: /auth/realms/master \ No newline at end of file + value: /auth/realms/master + - it: hostname explicitly set should be unchanged + set: + keycloak: + hostname: keycloak.example.com + asserts: + - equal: + path: spec.template.spec.containers[0].args[2] + value: --hostname=keycloak.example.com + - it: hostname with template should be rendered + set: + keycloak: + hostname: keycloak.{{ .Values.myDomain }} + myDomain: mydomain.com + asserts: + - equal: + path: spec.template.spec.containers[0].args[2] + value: --hostname=keycloak.mydomain.com + - it: hostnameAdmin explicitly set should be unchanged + set: + keycloak: + hostnameAdmin: keycloak.example.com + asserts: + - equal: + path: spec.template.spec.containers[0].args[2] + value: --hostname-admin=keycloak.example.com + - it: hostname with template should be rendered + set: + keycloak: + hostnameAdmin: keycloak.{{ .Values.myDomain }} + myDomain: mydomain.com + asserts: + - equal: + path: spec.template.spec.containers[0].args[2] + value: --hostname-admin=keycloak.mydomain.com \ No newline at end of file diff --git a/charts/keycloak/tests/tls-certmanager_test.yaml b/charts/keycloak/tests/tls-certmanager_test.yaml new file mode 100644 index 00000000..dd317ffe --- /dev/null +++ b/charts/keycloak/tests/tls-certmanager_test.yaml @@ -0,0 +1,265 @@ +suite: test cert-manager integration +templates: + - certificate.yaml + - deployment.yaml +tests: + - it: should create Certificate when cert-manager is enabled + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - keycloak.example.com + template: certificate.yaml + asserts: + - isKind: + of: Certificate + - equal: + path: metadata.name + value: RELEASE-NAME-keycloak + - equal: + path: spec.secretName + value: RELEASE-NAME-keycloak-tls + - equal: + path: spec.issuerRef.name + value: letsencrypt-prod + - equal: + path: spec.issuerRef.kind + value: ClusterIssuer + - equal: + path: spec.dnsNames[0] + value: keycloak.example.com + - equal: + path: spec.commonName + value: keycloak.example.com + + - it: should not create Certificate when cert-manager is disabled + set: + tls: + enabled: true + certManager: + enabled: false + existingSecret: my-tls-secret + template: certificate.yaml + asserts: + - hasDocuments: + count: 0 + + - it: should not create Certificate when tls is disabled + set: + tls: + enabled: false + certManager: + enabled: true + template: certificate.yaml + asserts: + - hasDocuments: + count: 0 + + - it: should use custom secretName when specified + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: my-issuer + kind: Issuer + secretName: custom-secret-name + dnsNames: + - auth.example.com + template: certificate.yaml + asserts: + - equal: + path: spec.secretName + value: custom-secret-name + + - it: should populate dnsNames from ingress.hosts when not specified + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + ingress: + enabled: true + hosts: + - host: auth.example.com + paths: + - path: / + pathType: Prefix + - host: auth2.example.com + paths: + - path: / + pathType: Prefix + template: certificate.yaml + asserts: + - equal: + path: spec.dnsNames[0] + value: auth.example.com + - equal: + path: spec.dnsNames[1] + value: auth2.example.com + - equal: + path: spec.commonName + value: auth.example.com + + - it: should set duration and renewBefore when specified + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + duration: 2160h + renewBefore: 360h + dnsNames: + - auth.example.com + template: certificate.yaml + asserts: + - equal: + path: spec.duration + value: 2160h + - equal: + path: spec.renewBefore + value: 360h + + - it: should set custom commonName when specified + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + commonName: custom.example.com + dnsNames: + - auth.example.com + - auth2.example.com + template: certificate.yaml + asserts: + - equal: + path: spec.commonName + value: custom.example.com + + - it: should set ipAddresses when specified + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - auth.example.com + ipAddresses: + - 192.168.1.100 + - 10.0.0.1 + template: certificate.yaml + asserts: + - equal: + path: spec.ipAddresses[0] + value: 192.168.1.100 + - equal: + path: spec.ipAddresses[1] + value: 10.0.0.1 + + - it: should set custom usages when specified + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - auth.example.com + usages: + - server auth + - client auth + template: certificate.yaml + asserts: + - equal: + path: spec.usages[0] + value: server auth + - equal: + path: spec.usages[1] + value: client auth + + - it: should add annotations when specified + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - auth.example.com + annotations: + custom.annotation/key: value + template: certificate.yaml + asserts: + - equal: + path: metadata.annotations["custom.annotation/key"] + value: value + + - it: deployment should use cert-manager generated secret + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - auth.example.com + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.volumes[?(@.name=="tls-certs")].secret.secretName + value: RELEASE-NAME-keycloak-tls + + - it: deployment should use custom cert-manager secret name + set: + tls: + enabled: true + certManager: + enabled: true + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + secretName: my-custom-secret + dnsNames: + - auth.example.com + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.volumes[?(@.name=="tls-certs")].secret.secretName + value: my-custom-secret + + - it: should fail when issuerRef.name is not provided + set: + tls: + enabled: true + certManager: + enabled: true + dnsNames: + - auth.example.com + template: certificate.yaml + asserts: + - failedTemplate: + errorMessage: "tls.certManager.issuerRef.name is required when cert-manager is enabled" diff --git a/charts/keycloak/values.schema.json b/charts/keycloak/values.schema.json index 19e86a41..16f01347 100644 --- a/charts/keycloak/values.schema.json +++ b/charts/keycloak/values.schema.json @@ -1,686 +1,659 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "global": { - "type": "object", - "properties": { - "imageRegistry": { - "type": "string", - "description": "Global Docker Image registry" - }, - "imagePullSecrets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Global Docker registry secret names as an array" - } - } - }, - "nameOverride": { - "type": "string", - "description": "String to partially override keycloak.fullname" - }, - "fullnameOverride": { - "type": "string", - "description": "String to fully override keycloak.fullname" - }, - "commonLabels": { - "type": "object", - "description": "Labels to add to all deployed objects" - }, - "commonAnnotations": { - "type": "object", - "description": "Annotations to add to all deployed objects" - }, - "image": { - "type": "object", - "properties": { - "registry": { - "type": "string", - "description": "Keycloak image registry" - }, - "repository": { - "type": "string", - "description": "Keycloak image repository" - }, - "tag": { - "type": "string", - "description": "Keycloak image tag (immutable tags are recommended)" - }, - "command": { - "type": "string", - "description": "Keycloak container startup command" - }, - "imagePullPolicy": { - "type": "string", - "enum": ["Always", "IfNotPresent", "Never"], - "description": "Keycloak image pull policy" - } - } - }, - "replicaCount": { - "type": "integer", - "minimum": 1, - "description": "Number of Keycloak replicas to deploy" - }, - "podAnnotations": { - "type": "object", - "description": "Map of annotations to add to the pods" - }, - "podLabels": { - "type": "object", - "description": "Map of labels to add to the pods" - }, - "extraVolumes": { - "type": "array", - "items": { - "type": "object" - }, - "description": "Array of Volume to add to the keycloak pod" - }, - "extraVolumeMounts": { - "type": "array", - "items": { - "type": "object" - }, - "description": "Array of VolumeMount to add to the keycloak container" - }, - "extraInitContainers": { - "type": "array", - "items": { - "type": "object" - }, - "description": "Array of initContainer to add to the keycloak pod" - }, - "podSecurityContext": { - "type": "object", - "properties": { - "fsGroup": { - "type": "integer", - "description": "Group ID for the volumes of the pod" - } - } - }, - "containerSecurityContext": { - "type": "object", - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean", - "description": "Enable container privilege escalation" - }, - "runAsNonRoot": { - "type": "boolean", - "description": "Configure the container to run as a non-root user" - }, - "runAsUser": { - "type": "integer", - "description": "User ID for the Keycloak container" - }, - "runAsGroup": { - "type": "integer", - "description": "Group ID for the Keycloak container" - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "description": "Mount container root filesystem as read-only" - }, - "capabilities": { - "type": "object", - "properties": { - "drop": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Linux capabilities to be dropped" + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "cache": { + "type": "object", + "properties": { + "configFile": { + "type": "string" + }, + "stack": { + "type": "string" + } } - } - } - } - }, - "keycloak": { - "type": "object", - "properties": { - "adminUser": { - "type": "string", - "description": "Keycloak admin username" - }, - "adminPassword": { - "type": "string", - "description": "Keycloak admin password" - }, - "existingSecret": { - "type": "string", - "description": "Name of existing secret to use for Keycloak admin credentials" - }, - "secretKeys": { - "type": "object", - "properties": { - "adminPasswordKey": { - "type": "string", - "description": "Secret key for admin password" + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } } - } - }, - "hostname": { - "type": "string", - "description": "Keycloak hostname" - }, - "hostnameAdmin": { - "type": "string", - "description": "Keycloak admin hostname" - }, - "hostnameStrict": { - "type": "boolean", - "description": "Enable strict hostname resolution" - }, - "hostnameBackchannel": { - "type": "string", - "description": "Keycloak backchannel hostname" - }, - "httpEnabled": { - "type": "boolean", - "description": "Enable HTTP listener" - }, - "httpPort": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "HTTP port" - }, - "httpsPort": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "HTTPS port" - }, - "proxyHeaders": { - "type": "string", - "enum": ["", "forwarded", "xforwarded"], - "description": "The proxy headers that should be accepted by the server. (forwarded, xforwarded)" - }, - "proxyProtocolEnabled": { - "type": "boolean", - "description": "Whether the server should use the HA PROXY protocol when serving requests from behind a proxy." - }, - "proxyTrustedAddresses": { - "type": "string", - "description": "A comma separated list of trusted proxy addresses" - }, - "production": { - "type": "boolean", - "description": "Enable production mode" - }, - "httpRelativePath": { - "type": "string", - "description": "Set relative path for serving resources; must start with a /" - } - } - }, - "database": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["postgres", "mysql", "mariadb"], - "description": "Database type (postgres, mysql, mariadb)" - }, - "host": { - "type": "string", - "description": "Database host (only used when not using embedded database)" - }, - "port": { - "type": "string", - "description": "Database port (only used when not using embedded database)" - }, - "name": { - "type": "string", - "description": "Database name (only used when not using embedded database)" - }, - "username": { - "type": "string", - "description": "Database username (only used when not using embedded database)" - }, - "password": { - "type": "string", - "description": "Database password (only used when not using embedded database)" - }, - "existingSecret": { - "type": "string", - "description": "Name of existing secret for database credentials" - }, - "secretKeys": { - "type": "object", - "properties": { - "passwordKey": { - "type": "string", - "description": "Secret key for database password" - }, - "usernameKey": { - "type": "string", - "description": "Secret key for database username" + }, + "database": { + "type": "object", + "properties": { + "existingSecret": { + "type": "string" + }, + "host": { + "type": "string" + }, + "jdbcParams": { + "type": "string" + }, + "name": { + "type": "string" + }, + "password": { + "type": "string" + }, + "port": { + "type": "string" + }, + "schema": { + "type": "string" + }, + "secretKeys": { + "type": "object", + "properties": { + "passwordKey": { + "type": "string" + }, + "usernameKey": { + "type": "string" + } + } + }, + "type": { + "type": "string" + }, + "urlProperties": { + "type": "string" + }, + "username": { + "type": "string" + } } - } }, - "jdbcParams": { - "type": "string", - "description": "Additional JDBC parameters" - } - } - }, - "cache": { - "type": "object", - "properties": { - "stack": { - "type": "string", - "enum": ["local", "ispn", "default"], - "description": "Cache stack (local, ispn, default)" - }, - "configFile": { - "type": "string", - "description": "Custom cache configuration file" - } - } - }, - "features": { - "type": "object", - "properties": { - "enabled": { - "type": "array", - "items": { + "extraEnvVars": { + "type": "array" + }, + "extraEnvVarsSecret": { "type": "string" - }, - "description": "List of enabled features" }, - "disabled": { - "type": "array", - "items": { + "extraInitContainers": { + "type": "array" + }, + "extraObjects": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "features": { + "type": "object", + "properties": { + "disabled": { + "type": "array" + }, + "enabled": { + "type": "array" + } + } + }, + "fullnameOverride": { "type": "string" - }, - "description": "List of disabled features" - } - } - }, - "service": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"], - "description": "Keycloak service type" - }, - "httpPort": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "Keycloak HTTP service port" - }, - "httpsPort": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "Keycloak HTTPS service port" - }, - "httpTargetPort": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "Keycloak HTTP container port" - }, - "httpsTargetPort": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "Keycloak HTTPS container port" - }, - "annotations": { - "type": "object", - "description": "Service annotations" - }, - "trafficDistribution": { - "type": "string", - "description": "Traffic distribution policy" - } - } - }, - "ingress": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable ingress record generation for Keycloak" - }, - "className": { - "type": "string", - "description": "IngressClass that will be used to implement the Ingress" - }, - "annotations": { - "type": "object", - "description": "Additional annotations for the Ingress resource" - }, - "hosts": { - "type": "array", - "items": { + }, + "global": { "type": "object", "properties": { - "host": { - "type": "string", - "description": "Hostname for Keycloak ingress" - }, - "paths": { - "type": "array", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "description": "Path for Keycloak ingress" - }, - "pathType": { - "type": "string", - "enum": ["Exact", "Prefix", "ImplementationSpecific"], - "description": "Path type for Keycloak ingress" + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } } - } + }, + "tls": { + "type": "array" } - } } - } }, - "tls": { - "type": "array", - "items": { + "initContainers": { "type": "object", "properties": { - "secretName": { - "type": "string" - }, - "hosts": { - "type": "array", - "items": { - "type": "string" + "waitForMariadb": { + "type": "object", + "properties": { + "image": { + "type": "string" + } + } + }, + "waitForPostgres": { + "type": "object", + "properties": { + "image": { + "type": "string" + } + } } - } } - }, - "description": "TLS configuration for Keycloak ingress" - } - } - }, - "resources": { - "type": "object", - "description": "Resource limits and requests for the container" - }, - "persistence": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable persistence using Persistent Volume Claims" - }, - "storageClass": { - "type": "string", - "description": "Persistent Volume storage class" - }, - "annotations": { - "type": "object", - "description": "Persistent Volume Claim annotations" - }, - "size": { - "type": "string", - "description": "Persistent Volume size" - }, - "accessModes": { - "type": "array", - "items": { - "type": "string", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany"] - }, - "description": "Persistent Volume access modes" - }, - "existingClaim": { - "type": "string", - "description": "The name of an existing PVC to use for persistence" - } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable livenessProbe on Keycloak containers" - }, - "initialDelaySeconds": { - "type": "integer", - "minimum": 0, - "description": "Initial delay seconds for livenessProbe" - }, - "periodSeconds": { - "type": "integer", - "minimum": 1, - "description": "Period seconds for livenessProbe" - }, - "timeoutSeconds": { - "type": "integer", - "minimum": 1, - "description": "Timeout seconds for livenessProbe" - }, - "failureThreshold": { - "type": "integer", - "minimum": 1, - "description": "Failure threshold for livenessProbe" - }, - "successThreshold": { - "type": "integer", - "minimum": 1, - "description": "Success threshold for livenessProbe" - } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable readinessProbe on Keycloak containers" - }, - "initialDelaySeconds": { - "type": "integer", - "minimum": 0, - "description": "Initial delay seconds for readinessProbe" - }, - "periodSeconds": { - "type": "integer", - "minimum": 1, - "description": "Period seconds for readinessProbe" - }, - "timeoutSeconds": { - "type": "integer", - "minimum": 1, - "description": "Timeout seconds for readinessProbe" - }, - "failureThreshold": { - "type": "integer", - "minimum": 1, - "description": "Failure threshold for readinessProbe" - }, - "successThreshold": { - "type": "integer", - "minimum": 1, - "description": "Success threshold for readinessProbe" - } - } - }, - "startupProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable startupProbe on Keycloak containers" - }, - "initialDelaySeconds": { - "type": "integer", - "minimum": 0, - "description": "Initial delay seconds for startupProbe" - }, - "periodSeconds": { - "type": "integer", - "minimum": 1, - "description": "Period seconds for startupProbe" - }, - "timeoutSeconds": { - "type": "integer", - "minimum": 1, - "description": "Timeout seconds for startupProbe" - }, - "failureThreshold": { - "type": "integer", - "minimum": 1, - "description": "Failure threshold for startupProbe" - }, - "successThreshold": { - "type": "integer", - "minimum": 1, - "description": "Success threshold for startupProbe" - } - } - }, - "nodeSelector": { - "type": "object", - "description": "Node labels for pod assignment" - }, - "tolerations": { - "type": "array", - "description": "Toleration labels for pod assignment" - }, - "affinity": { - "type": "object", - "description": "Affinity settings for pod assignment" - }, - "topologySpreadConstraints": { - "type": "array", - "description": "Topology Spread Constraints for pod assignment" - }, - "serviceAccount": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Specifies whether a service account should be created" - }, - "annotations": { - "type": "object", - "description": "Annotations to add to the service account" - }, - "name": { - "type": "string", - "description": "The name of the service account to use" - }, - "automountServiceAccountToken": { - "type": "boolean", - "description": "Whether to automount the SA token inside the pod" - } - } - }, - "extraEnv": { - "type": "object", - "description": "Additional environment variables from key-value pairs" - }, - "extraEnvVarsSecret": { - "type": "string", - "title": "Extra Environment Secret", - "description": "Name of an existing Secret containing additional environment variables" - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } - }, - "initContainers": { - "type": "object", - "properties": { - "waitForPostgres": { - "type": "object", - "properties": { - "image": { - "type": "string", - "description": "PostgreSQL init container image for waiting" + }, + "keycloak": { + "type": "object", + "properties": { + "adminPassword": { + "type": "string" + }, + "adminUser": { + "type": "string" + }, + "existingSecret": { + "type": "string" + }, + "extraArgs": { + "type": "array" + }, + "hostname": { + "type": "string" + }, + "hostnameAdmin": { + "type": "string" + }, + "hostnameBackchannel": { + "type": "string" + }, + "hostnameStrict": { + "type": "boolean" + }, + "httpEnabled": { + "type": "boolean" + }, + "httpPort": { + "type": "integer" + }, + "httpRelativePath": { + "type": "string" + }, + "httpsPort": { + "type": "integer" + }, + "production": { + "type": "boolean" + }, + "proxyHeaders": { + "type": "string" + }, + "proxyProtocolEnabled": { + "type": "boolean" + }, + "proxyTrustedAddresses": { + "type": "string" + }, + "secretKeys": { + "type": "object", + "properties": { + "adminPasswordKey": { + "type": "string" + } + } + } } - } - }, - "waitForMariadb": { - "type": "object", - "properties": { - "image": { - "type": "string", - "description": "MariaDB init container image for waiting" + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } } - } - } - } - }, - "postgres": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable embedded PostgreSQL database" - }, - "auth": { - "type": "object", - "properties": { - "database": { - "type": "string", - "description": "PostgreSQL database name" - }, - "username": { - "type": "string", - "description": "PostgreSQL database user (leave empty for default 'postgres')" - }, - "password": { - "type": "string", - "description": "PostgreSQL database password" + }, + "mariadb": { + "type": "object", + "properties": { + "auth": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "password": { + "type": "string" + }, + "rootPassword": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "enabled": { + "type": "boolean" + } } - } - } - } - }, - "mariadb": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable embedded MariaDB database (set to false when using postgres)" - }, - "auth": { - "type": "object", - "properties": { - "database": { - "type": "string", - "description": "MariaDB database name" - }, - "username": { - "type": "string", - "description": "MariaDB database user (leave empty for root user)" - }, - "password": { - "type": "string", - "description": "MariaDB database password" - }, - "rootPassword": { - "type": "string", - "description": "MariaDB root password" + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "additionalLabels": { + "type": "object" + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "jobLabel": { + "type": "string" + }, + "metricRelabelings": { + "type": "array" + }, + "namespace": { + "type": "string" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + } + } + } + } + }, + "nameOverride": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "postgres": { + "type": "object", + "properties": { + "auth": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "enabled": { + "type": "boolean" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "realm": { + "type": "object", + "properties": { + "configFile": { + "type": "string" + }, + "import": { + "type": "boolean" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "httpPort": { + "type": "integer" + }, + "httpTargetPort": { + "type": "integer" + }, + "httpsPort": { + "type": "integer" + }, + "httpsTargetPort": { + "type": "integer" + }, + "trafficDistribution": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } } - } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "tls": { + "type": "object", + "properties": { + "certManager": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "commonName": { + "type": "string" + }, + "dnsNames": { + "type": "array" + }, + "duration": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "ipAddresses": { + "type": "array" + }, + "issuerRef": { + "type": "object", + "properties": { + "group": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "renewBefore": { + "type": "string" + }, + "secretName": { + "type": "string" + }, + "usages": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "certificateFile": { + "type": "string" + }, + "certificateKeyFile": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "truststoreEnabled": { + "type": "boolean" + }, + "truststoreExistingSecret": { + "type": "string" + }, + "truststoreFile": { + "type": "string" + }, + "truststorePassword": { + "type": "string" + } + } + }, + "tolerations": { + "type": "array" + }, + "topologySpreadConstraints": { + "type": "array" } - } } - } } diff --git a/charts/keycloak/values.yaml b/charts/keycloak/values.yaml index 6b2799d5..b56fe7dc 100644 --- a/charts/keycloak/values.yaml +++ b/charts/keycloak/values.yaml @@ -22,7 +22,7 @@ image: ## @param image.repository Keycloak image repository repository: keycloak/keycloak ## @param image.tag Keycloak image tag (immutable tags are recommended) - tag: "26.4.0@sha256:5f3fb534cde6bf006d79f5912473e5d2c828c707cdfc52e16972803aca9d43dd" + tag: "26.4.2@sha256:3617b09bb4b7510a8d8d9b9fc5707399e2d70688dbcc2f8fb013a144829be1b9" ## @param image.imagePullPolicy Keycloak image pull policy imagePullPolicy: Always ## @param image.command Keycloak container command @@ -110,17 +110,78 @@ keycloak: production: false ## @param keycloak.httpRelativePath Set relative path for serving resources; must start with a / httpRelativePath: / + ## @param keycloak.extraArgs Additional arguments to pass to the Keycloak startup command + extraArgs: [] + +## @section TLS Configuration +tls: + ## @param tls.enabled Enable TLS/HTTPS support using custom certificates + enabled: false + ## @param tls.existingSecret Name of existing secret containing TLS certificate and key (PEM format) + ## The secret should contain 'tls.crt' and 'tls.key' keys + ## Note: If certManager.enabled is true, this will be auto-generated + existingSecret: "" + ## @param tls.certificateFile Path where the TLS certificate file will be mounted (internal) + certificateFile: "/opt/keycloak/certs/tls.crt" + ## @param tls.certificateKeyFile Path where the TLS certificate key file will be mounted (internal) + certificateKeyFile: "/opt/keycloak/certs/tls.key" + ## @section cert-manager Configuration + ## @descriptionStart + ## Configure cert-manager to automatically provision and renew TLS certificates + ## Requires cert-manager to be installed in the cluster + ## @descriptionEnd + certManager: + ## @param tls.certManager.enabled Enable cert-manager integration for automatic certificate provisioning + enabled: false + ## @param tls.certManager.issuerRef.name Name of the cert-manager Issuer or ClusterIssuer + ## @param tls.certManager.issuerRef.kind Kind of the cert-manager issuer (Issuer or ClusterIssuer) + ## @param tls.certManager.issuerRef.group Group of the cert-manager issuer (default: cert-manager.io) + issuerRef: + name: "" + kind: ClusterIssuer + group: cert-manager.io + ## @param tls.certManager.duration Certificate duration (default: 2160h - 90 days) + duration: "" + ## @param tls.certManager.renewBefore Time before expiry to renew certificate (default: 360h - 15 days) + renewBefore: "" + ## @param tls.certManager.commonName Certificate common name (defaults to first dnsName if not specified) + commonName: "" + ## @param tls.certManager.dnsNames List of DNS names for the certificate (uses ingress.hosts if not specified) + dnsNames: [] + ## @param tls.certManager.ipAddresses List of IP addresses for the certificate + ipAddresses: [] + ## @param tls.certManager.secretName Name for the generated secret (defaults to -tls) + secretName: "" + ## @param tls.certManager.usages Certificate key usages + usages: + - digital signature + - key encipherment + ## @param tls.certManager.annotations Additional annotations for the Certificate resource + annotations: {} + ## @param tls.truststoreEnabled Enable truststore for client certificate validation or outgoing HTTPS requests + truststoreEnabled: false + ## @param tls.truststoreExistingSecret Name of existing secret containing truststore file (Java Keystore format) + ## The secret should contain 'truststore.jks' key + truststoreExistingSecret: "" + ## @param tls.truststorePassword Password for the truststore (use with caution - consider using existingSecret) + truststorePassword: "" + ## @param tls.truststoreFile Path where the truststore file will be mounted (internal) + truststoreFile: "/opt/keycloak/truststore/truststore.jks" ## @section Database Configuration database: - ## @param database.type Database type (postgres, mysql, mariadb) + ## @param database.type Database type (postgres, mysql, mariadb, mssql) ## Note: H2 databases (h2-file, h2-mem) are not supported due to readonly filesystem restrictions ## Use embedded postgres or mariadb instead type: postgres ## @param database.host Database host (only used when not using embedded database) host: "" - ## @param database.port Database port (only used when not using embedded database, defaults: postgres=5432, mysql/mariadb=3306) + ## @param database.port Database port (only used when not using embedded database, defaults: postgres=5432, mysql/mariadb=3306, mssql=1443) port: "" + ## @param database.schema Database schema + schema: "" + ## @param database.urlProperties Additional database url properties + urlProperties: "" ## @param database.name Database name (only used when not using embedded database) name: keycloak ## @param database.username Database username (only used when not using embedded database) @@ -143,6 +204,13 @@ cache: ## @param cache.configFile Custom cache configuration file configFile: "" +## @section Realm Configuration +realm: + ## @param realm.import Enable import of realms from /opt/keycloak/data/import (production mode must be false) + import: false + ## @param realm.configFile Json config for initial realm configuration, mounted in /opt/keycloak/data/import + configFile: "" + ## @section Features Configuration features: ## @param features.enabled List of enabled features @@ -174,8 +242,7 @@ ingress: ## @param ingress.className IngressClass that will be used to implement the Ingress className: "" ## @param ingress.annotations Additional annotations for the Ingress resource - annotations: - {} + annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" # nginx.ingress.kubernetes.io/backend-protocol: "HTTP" @@ -194,8 +261,7 @@ ingress: # - keycloak.local ## @section Resources -resources: - {} +resources: {} ## We usually recommend not to specify default resources and to leave this as a conscious ## choice for the user. This also increases chances charts run on environments with little ## resources, such as Minikube. If you do want to specify resources, uncomment the following @@ -223,6 +289,45 @@ persistence: ## @param persistence.existingClaim The name of an existing PVC to use for persistence existingClaim: "" +## @section Metrics Configuration +metrics: + ## @param metrics.enabled Enable metrics endpoint on Keycloak + enabled: false + ## @section Metrics service parameters + service: + ## @param metrics.service.type Metrics service type + type: ClusterIP + ## @param metrics.service.port Metrics service port + port: 9000 + ## @param metrics.service.targetPort Metrics service target port + targetPort: http-metrics + ## @param metrics.service.annotations Additional annotations for metrics service + annotations: {} + ## @param metrics.service.labels Additional labels for metrics service + labels: {} + ## @section ServiceMonitor parameters + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource for scraping metrics using PrometheusOperator + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace in which ServiceMonitor is created + namespace: "" + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped + interval: 30s + ## @param metrics.serviceMonitor.scrapeTimeout Timeout after which the scrape is ended + scrapeTimeout: "" + ## @param metrics.serviceMonitor.additionalLabels Additional labels for ServiceMonitor + additionalLabels: {} + ## @param metrics.serviceMonitor.annotations Additional annotations for ServiceMonitor + annotations: {} + ## @param metrics.serviceMonitor.relabelings RelabelConfigs to apply to samples before scraping + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion + metricRelabelings: [] + ## @param metrics.serviceMonitor.honorLabels Specify honorLabels parameter to add the scrape endpoint + honorLabels: false + ## @param metrics.serviceMonitor.jobLabel The name of the label on the target service to use as the job name in prometheus + jobLabel: "" + ## @section Liveness and readiness probes livenessProbe: ## @param livenessProbe.enabled Enable livenessProbe on Keycloak containers @@ -290,10 +395,15 @@ serviceAccount: ## @param serviceAccount.automountServiceAccountToken whether to automount the SA token inside the pod automountServiceAccountToken: false -## @param extraEnv Additional environment variables from key-value pairs -extraEnv: {} -# VARNAME1: value1 -# VARNAME2: value2 +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraEnvVarsSecret Name of a secret containing additional environment variables extraEnvVarsSecret: "" diff --git a/charts/mariadb/CHANGELOG.md b/charts/mariadb/CHANGELOG.md index 6893a4ce..ed2b5c23 100644 --- a/charts/mariadb/CHANGELOG.md +++ b/charts/mariadb/CHANGELOG.md @@ -1,5 +1,135 @@ # Changelog -## 0.3.3 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +## 0.6.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.5.4 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.5.3 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([3974b19](https://github.com/CloudPirates-io/helm-charts/commit/3974b19)) +* chore: update CHANGELOG.md for merged changes ([db075e4](https://github.com/CloudPirates-io/helm-charts/commit/db075e4)) + +## 0.5.2 (2025-10-21) + +* enhance stateful set with extra mounts (#420) ([d0bae40](https://github.com/CloudPirates-io/helm-charts/commit/d0bae40)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([949de2b](https://github.com/CloudPirates-io/helm-charts/commit/949de2b)) +* chore: update CHANGELOG.md for merged changes ([388263e](https://github.com/CloudPirates-io/helm-charts/commit/388263e)) + +## 0.5.1 (2025-10-15) + +* Bugfix/redis non cloudpirates prefix (#394) ([02e03ed](https://github.com/CloudPirates-io/helm-charts/commit/02e03ed)) +* chore: update CHANGELOG.md for merged changes ([2ed8b75](https://github.com/CloudPirates-io/helm-charts/commit/2ed8b75)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) + +## 0.5.0 (2025-10-14) + +* add galera cluster support for mariadb (#348) ([b7a63ee](https://github.com/CloudPirates-io/helm-charts/commit/b7a63ee)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.4.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.3.5 (2025-10-13) + + +## 0.3.4 (2025-10-10) + +* Update charts/mariadb/values.yaml mariadb (#315) ([07101fe](https://github.com/CloudPirates-io/helm-charts/commit/07101fe)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) +* Hotfix schemas.json (#247) ([0900f81](https://github.com/CloudPirates-io/helm-charts/commit/0900f81)) + +## 0.3.3 (2025-10-08) + +* Add support for readOnlyRootFilesystem (#228) ([cdb58b2](https://github.com/CloudPirates-io/helm-charts/commit/cdb58b2)) + +## 0.3.2 (2025-10-06) + +* chore(deps): update docker.io/mariadb:12.0.2 Docker digest to 03a03a6 (#207) ([e51e995](https://github.com/CloudPirates-io/helm-charts/commit/e51e995)) + +## 0.3.1 (2025-10-06) + +* use tpl to return existingConfigMap (#217) ([c7c2f4c](https://github.com/CloudPirates-io/helm-charts/commit/c7c2f4c)) + +## 0.3.0 (2025-09-29) + +* make mariadb run on openshift (#176) ([e2c3afb](https://github.com/CloudPirates-io/helm-charts/commit/e2c3afb)) + +## 0.2.7 (2025-09-16) + +* Update CHANGELOG.md ([bb96d54](https://github.com/CloudPirates-io/helm-charts/commit/bb96d54)) +* Bump chart version ([ea85028](https://github.com/CloudPirates-io/helm-charts/commit/ea85028)) +* chore(deps): update docker.io/mariadb:12.0.2 Docker digest to 8a061ef ([ba48f7a](https://github.com/CloudPirates-io/helm-charts/commit/ba48f7a)) + +## 0.2.6 (2025-09-15) + +* Update CHANGELOG.md ([858838d](https://github.com/CloudPirates-io/helm-charts/commit/858838d)) +* fix pvc-labels ([aaf1b20](https://github.com/CloudPirates-io/helm-charts/commit/aaf1b20)) +* bump version to 0.2.6 ([51bcd26](https://github.com/CloudPirates-io/helm-charts/commit/51bcd26)) +* change statefulset pvc-template labels to not use common.labels ([780386b](https://github.com/CloudPirates-io/helm-charts/commit/780386b)) + +## 0.2.5 (2025-09-15) + +* Update CHANGELOG.md ([e5c8efd](https://github.com/CloudPirates-io/helm-charts/commit/e5c8efd)) +* fix statefulset pvc template ([b600627](https://github.com/CloudPirates-io/helm-charts/commit/b600627)) + +## 0.2.4 (2025-09-09) + +* Update CHANGELOG.md ([79570ff](https://github.com/CloudPirates-io/helm-charts/commit/79570ff)) +* Implement init script ([4b6ee98](https://github.com/CloudPirates-io/helm-charts/commit/4b6ee98)) +* Reverse version bump ([379dbfe](https://github.com/CloudPirates-io/helm-charts/commit/379dbfe)) + +## 0.2.3 (2025-09-09) + +* Update CHANGELOG.md ([7517a21](https://github.com/CloudPirates-io/helm-charts/commit/7517a21)) +* Bump MariaDB chart version to 0.2.3 ([10b1b7d](https://github.com/CloudPirates-io/helm-charts/commit/10b1b7d)) +* Bump chart version ([d2863aa](https://github.com/CloudPirates-io/helm-charts/commit/d2863aa)) +* Update docker.io/mariadb:12.0.2 Docker digest to a5af517 ([6322f06](https://github.com/CloudPirates-io/helm-charts/commit/6322f06)) + +## 0.2.2 (2025-09-08) + +* updated chart version ([f7b6496](https://github.com/CloudPirates-io/helm-charts/commit/f7b6496)) +* mariadb now respects full custom container security context settings memcached readme fixed, this option was not available ([770ea69](https://github.com/CloudPirates-io/helm-charts/commit/770ea69)) + +## 0.2.1 (2025-09-04) + +* Update CHANGELOG.md ([bcd1d8a](https://github.com/CloudPirates-io/helm-charts/commit/bcd1d8a)) +* add empty linting rule ([8be9283](https://github.com/CloudPirates-io/helm-charts/commit/8be9283)) +* Fix helpers.tpl ([201ecc7](https://github.com/CloudPirates-io/helm-charts/commit/201ecc7)) +* Update CHANGELOG.md ([9af2905](https://github.com/CloudPirates-io/helm-charts/commit/9af2905)) +* Implement default password ([c858a6b](https://github.com/CloudPirates-io/helm-charts/commit/c858a6b)) + +## 0.2.0 (2025-09-02) + +* bump all chart versions for new extraObjects feature ([aaa57f9](https://github.com/CloudPirates-io/helm-charts/commit/aaa57f9)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.1.6 (2025-08-27) + +* Fix linting for values.yaml ([504ac61](https://github.com/CloudPirates-io/helm-charts/commit/504ac61)) +* Fix values.yaml / Chart.yaml linting issues ([043c7e0](https://github.com/CloudPirates-io/helm-charts/commit/043c7e0)) +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.1.5 (2025-08-26) + +* Initial tagged release diff --git a/charts/mariadb/Chart.lock b/charts/mariadb/Chart.lock index 902221bd..283cb703 100644 --- a/charts/mariadb/Chart.lock +++ b/charts/mariadb/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-09-28T21:12:26.682987+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:19.520784+02:00" diff --git a/charts/mariadb/Chart.yaml b/charts/mariadb/Chart.yaml index c1344435..d588c04c 100644 --- a/charts/mariadb/Chart.yaml +++ b/charts/mariadb/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 name: mariadb -description: MariaDB is a high-performance, open-source relational database server that is a drop-in replacement for MySQL +description: MariaDB is a high-performance, open-source relational database server that is a drop-in replacement for MySQL. Supports both single-node and Galera Cluster deployments. type: application -version: 0.3.3 +version: 0.6.0 appVersion: "12.0.2" keywords: - mariadb @@ -10,18 +10,46 @@ keywords: - database - sql - relational -home: https://www.cloudpirates.io - + - galera + - cluster + - replication +home: https://mariadb.org sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mariadb - + - https://github.com/MariaDB/server + - https://github.com/MariaDB/mariadb-docker maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io - + - name: Gianni Carafa + email: gianni.carafa@srf.ch + url: https://www.srf.ch dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates - icon: https://a.storyblok.com/f/143071/512x512/6512dd22ee/mariadb-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: MariaDB + url: https://mariadb.org + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mariadb + - name: Application + url: https://github.com/MariaDB/server + - name: Docker Image + url: https://github.com/MariaDB/mariadb-docker + - name: Galera Cluster + url: https://galeracluster.com + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Chart updated" diff --git a/charts/mariadb/README.md b/charts/mariadb/README.md index 51401aa3..b141c4d6 100644 --- a/charts/mariadb/README.md +++ b/charts/mariadb/README.md @@ -4,7 +4,9 @@ # MariaDB -MariaDB is a high-performance, open-source relational database server that is a drop-in replacement for MySQL. This Helm chart deploys MariaDB as a StatefulSet on Kubernetes with comprehensive configuration options for development and production environments, providing stable network identities and persistent storage. +MariaDB is a high-performance, open-source relational database server that is a drop-in replacement for MySQL. This Helm chart deploys MariaDB as a StatefulSet on Kubernetes with comprehensive configuration options for development and production environments, providing stable network identities and persistent storage. + +The chart supports both single-node deployments and multi-node Galera cluster configurations for high availability and automatic failover. ## Installing the Chart @@ -127,6 +129,41 @@ The following table lists the configurable parameters of the MariaDB chart and t | `config.customConfiguration` | Custom configuration for MariaDB | `""` | | `config.existingConfigMap` | Name of existing ConfigMap with MariaDB configuration | `""` | +### Galera Cluster Parameters + +For a detailed explanation of Galera parameters and usage, see [README_GALERA.md](README_GALERA.md). + +> [!WARNING] +> You must migrate from a standalone MariaDB to Galera carefully. Do not enable Galera on an existing standalone database without following proper migration steps. + +| Parameter | Description | Default | +| ----------------------------------- | ------------------------------------------------------------------- | ---------------------------------- | +| `galera.enabled` | Enable Galera Cluster mode | `false` | +| `galera.name` | Galera cluster name | `"galera"` | +| `galera.bootstrap.enabled` | Enable bootstrap mode for the first node in the cluster | `true` | +| `galera.replicaCount` | Number of nodes in the Galera cluster | `3` | +| `galera.wsrepProvider` | Path to wsrep provider library | `/usr/lib/galera/libgalera_smm.so` | +| `galera.wsrepMethod` | Method for state snapshot transfers (mariabackup, mysqldump, rsync) | `mariabackup` | +| `galera.forceSafeToBootstrap` | Force safe_to_bootstrap=1 in grastate.dat | `false` | +| `galera.wsrepSlaveThreads` | Number of slave threads for applying writesets | `1` | +| `galera.wsrepCertifyNonPK` | Require primary key for replication | `true` | +| `galera.wsrepMaxWsRows` | Maximum number of rows in writeset | `0` | +| `galera.wsrepMaxWsSize` | Maximum size of writeset in bytes | `1073741824` | +| `galera.wsrepDebug` | Enable wsrep debugging | `false` | +| `galera.wsrepRetryAutocommit` | Number of times to retry autocommit | `1` | +| `galera.wsrepAutoIncrementControl` | Enable auto increment control | `true` | +| `galera.wsrepDrupalHack` | Enable Drupal compatibility hack | `false` | +| `galera.wsrepLogConflicts` | Log conflicts to error log | `false` | +| `galera.innodb.flushLogAtTrxCommit` | InnoDB flush log at transaction commit | `0` | +| `galera.innodb.bufferPoolSize` | InnoDB buffer pool size | `"128M"` | +| `galera.sst.user` | SST user for authentication | `"sstuser"` | +| `galera.sst.password` | SST password for authentication | `""` | +| `galera.sst.existingSecret` | Existing secret containing SST credentials | `""` | +| `galera.sst.secretKeys.userKey` | Secret key for SST user | `sst-user` | +| `galera.sst.secretKeys.passwordKey` | Secret key for SST password | `sst-password` | +| `galera.recovery.enabled` | Enable automatic recovery | `true` | +| `galera.recovery.clusterBootstrap` | Enable cluster bootstrap in recovery | `true` | + ### Service Parameters | Parameter | Description | Default | @@ -169,7 +206,7 @@ The following table lists the configurable parameters of the MariaDB chart and t | Parameter | Description | Default | | -------------- | -------------------------------------------------------------------------------- | ------- | -| `env` | A list of additional environment variables | `[]` | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraSecrets` | A list of additional existing secrets that will be mounted into the container | `[]` | | `extraConfigs` | A list of additional existing configMaps that will be mounted into the container | `[]` | | `extraVolumes` | A list of additional existing volumes that will be mounted into the container | `[]` | @@ -351,7 +388,7 @@ config: ```yaml # Additional environment variables -env: +extraEnvVars: - name: MYSQL_INIT_ONLY value: "0" - name: MARIADB_AUTO_UPGRADE @@ -376,27 +413,6 @@ extraVolumes: pvcName: mariadb-backup-pvc ``` -### With Ingress (for development only) - -**Note**: MariaDB ingress should only be used for development purposes. In production, use direct service connections. - -```yaml -ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/tcp-services-configmap: "default/tcp-services" - hosts: - - host: mariadb.local - paths: - - path: / - pathType: Prefix - -service: - type: NodePort - nodePort: 30306 -``` - ## Troubleshooting ### Connection Issues diff --git a/charts/mariadb/README_GALERA.md b/charts/mariadb/README_GALERA.md new file mode 100644 index 00000000..78bbd3bd --- /dev/null +++ b/charts/mariadb/README_GALERA.md @@ -0,0 +1,238 @@ +# Galera Cluster with MariaDB + +This document provides detailed instructions and best practices for deploying and managing a MariaDB Galera Cluster using the Helm chart available in this repository. Galera Cluster is a synchronous multi-master replication solution for MariaDB, providing high availability and scalability. + +```mermaid +architecture-beta + group api[MariaDB Galera Cluster Statefulset] + + service db1(database)[Node1] in api + service db2(database)[Node2] in api + service db3(database)[Node3] in api + + service gateway(internet)[Service Loadbalancer] + service app(internet)[Application] + + junction junctionCenter in api + junction junctionRight in api + junction junctionLeft in api + + db1:T -- B:junctionRight + db2:T -- B:junctionCenter + db3:T -- B:junctionLeft + + junctionRight:L -- R:junctionCenter + junctionLeft:R -- L:junctionCenter + junctionCenter:T -- B:gateway + gateway:T -- B:app +``` + + + +### Galera Cluster Setup + +#### Basic Galera Cluster + +Deploy a 3-node Galera cluster with automatic bootstrap: + +```yaml +galera: + enabled: true + name: "mycluster" + replicaCount: 3 + bootstrap: + enabled: true + +auth: + rootPassword: "mySecurePassword" + database: "mydatabase" + username: "myuser" + password: "myUserPassword" +``` + +#### Production Galera Setup + +```yaml +galera: + enabled: true + name: "production-cluster" + replicaCount: 3 + wsrepSlaveThreads: 4 + sst: + user: "sstuser" + password: "secureSST_Password" + innodb: + flushLogAtTrxCommit: 2 + bufferPoolSize: "2G" + +auth: + rootPassword: "verySecureRootPassword" + database: "production_db" + username: "app_user" + password: "secureUserPassword" + +# Pod anti-affinity for spreading nodes across different hosts +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: mariadb + topologyKey: kubernetes.io/hostname +``` + +#### Galera with Existing SST Secret + +```yaml +galera: + enabled: true + name: "secure-cluster" + replicaCount: 3 + sst: + existingSecret: "galera-sst-credentials" + secretKeys: + userKey: "sst-user" + passwordKey: "sst-password" + +# Create the secret separately: +# kubectl create secret generic galera-sst-credentials \ +# --from-literal=sst-user=sstuser \ +# --from-literal=sst-password=your-secure-password +``` + +#### Cluster Recovery + +For cluster recovery scenarios, you may need to force bootstrap: + +```yaml +galera: + enabled: true + forceSafeToBootstrap: true # Use only in recovery scenarios + recovery: + enabled: true + clusterBootstrap: true +``` + +#### Connecting to Galera Cluster + +Connect to the cluster through the main service (load balanced): + +```bash +kubectl exec -it pod/mdb-mariadb-0 -- mariadb -uroot -p$MARIADB_ROOT_PASSWORD -e \"SHOW GLOBAL STATUS LIKE 'wsrep_cluster%'\" +``` + + +#### Galera Cluster Monitoring + +Check cluster status inside the database: + +```sql +SHOW STATUS LIKE 'wsrep_ready'; +SHOW STATUS LIKE 'wsrep_cluster_size'; +SHOW STATUS LIKE 'wsrep_local_state_comment'; +``` + +Key status variables to monitor: +- `wsrep_cluster_size`: Number of nodes in cluster +- `wsrep_local_state_comment`: Should be "Synced" for healthy nodes +- `wsrep_ready`: Should be "ON" for ready nodes + +### Galera Cluster Troubleshooting + +#### Check Cluster Status + +1. **Verify all nodes are running**: + ```bash + kubectl get pods -l app.kubernetes.io/name=mariadb + kubectl get statefulset -l app.kubernetes.io/name=mariadb + ``` + +2. **Check cluster status from database**: + ```bash + kubectl exec -it -- mysql -uroot -p -e "SHOW STATUS LIKE 'wsrep_%'" + ``` + +3. **Check individual node status**: + ```sql + SHOW STATUS LIKE 'wsrep_local_state_comment'; -- Should show "Synced" + SHOW STATUS LIKE 'wsrep_cluster_size'; -- Should show total node count + SHOW STATUS LIKE 'wsrep_ready'; -- Should be "ON" + ``` + +4. **Check logs for errors**: + ```bash + kubectl exec -- tail -n 300 /var/lib/mysql/mariabackup.backup.log + ``` + +5. **Check SST user permissions**: + ```bash + SHOW GRANTS FOR 'sstuser'@'%'; grep wsrep_sst_auth + ``` + + expected output: + ```sql + GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'sstuser'@'%'; + GRANT ALL PRIVILEGES ON *.* TO 'sstuser'@'localhost'; + ``` + +#### Common Issues and Solutions + +1. **Cluster won't start (split-brain scenario)**: + ```bash + # Check grastate.dat on all nodes + kubectl exec -- cat /var/lib/mysql/grastate.dat + + # Force bootstrap on the most advanced node + helm upgrade charts/mariadb --set galera.forceSafeToBootstrap=true + # After cluster starts, disable force bootstrap + helm upgrade charts/mariadb --set galera.forceSafeToBootstrap=false + ``` + +2. **Node stuck in joining state**: + ```bash + # Check SST logs + kubectl logs | grep -i sst + + # Verify SST user credentials + kubectl get secret -mariadb-galera -o yaml + ``` + +3. **Slow state transfers**: + ```yaml + galera: + wsrepMethod: "mariabackup" # Faster than mysqldump + innodb: + bufferPoolSize: "2G" # Increase buffer pool + ``` + +4. **Network connectivity issues**: + ```bash + # Test connectivity between pods + kubectl exec -- nc -zv 4567 + kubectl exec -- nc -zv 4568 + kubectl exec -- nc -zv 4444 + ``` + +5. **Recovery from complete cluster shutdown**: + ```bash + # Find the most advanced node (highest seqno) + kubectl exec -- cat /var/lib/mysql/grastate.dat + + # Set safe_to_bootstrap=1 on the most advanced node + kubectl exec -- sed -i 's/safe_to_bootstrap: 0/safe_to_bootstrap: 1/' /var/lib/mysql/grastate.dat + + # Or use force bootstrap flag + helm upgrade charts/mariadb --set galera.forceSafeToBootstrap=true + ``` + +#### Galera Best Practices + +- **Always use odd number of nodes** (3, 5, 7) to avoid split-brain +- **Enable pod anti-affinity** to spread nodes across different hosts +- **Monitor cluster size** regularly to detect node failures +- **Use dedicated storage** with good I/O performance +- **Configure proper resource limits** based on your workload +- **Regular backups** are essential even with clustering +- **Test recovery procedures** in non-production environments \ No newline at end of file diff --git a/charts/mariadb/templates/_helpers.tpl b/charts/mariadb/templates/_helpers.tpl index c3994c85..ce9c7f30 100644 --- a/charts/mariadb/templates/_helpers.tpl +++ b/charts/mariadb/templates/_helpers.tpl @@ -2,7 +2,7 @@ Expand the name of the chart. */}} {{- define "mariadb.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* @@ -11,49 +11,49 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "mariadb.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "mariadb.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "mariadb.labels" -}} -{{- include "common.labels" . -}} +{{- include "cloudpirates.labels" . -}} {{- end }} {{/* Selector labels */}} {{- define "mariadb.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Return the proper MariaDB image name */}} {{- define "mariadb.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "mariadb.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* Get the secret name for MariaDB root password */}} {{- define "mariadb.secretName" -}} {{- if .Values.auth.existingSecret }} -{{- .Values.auth.existingSecret }} +{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) }} {{- else }} {{- include "mariadb.fullname" . }} {{- end }} @@ -77,3 +77,48 @@ Return the MariaDB ConfigMap Name {{- end }} {{- end }} +{{/* +Get the secret name for Galera SST authentication +*/}} +{{- define "mariadb.galeraSecretName" -}} +{{- if .Values.galera.sst.existingSecret }} +{{- .Values.galera.sst.existingSecret }} +{{- else }} +{{- printf "%s-galera" (include "mariadb.fullname" .) }} +{{- end }} +{{- end }} + +{{/* +Generate Galera cluster address list +*/}} +{{- define "mariadb.galeraClusterAddress" -}} +{{- $fullname := include "mariadb.fullname" . -}} +{{- $replicaCount := int .Values.galera.replicaCount -}} +{{- $namespace := .Release.Namespace -}} +{{- $addresses := list -}} +{{- range $i := until $replicaCount -}} +{{- $addresses = append $addresses (printf "%s-%d.%s.%s.svc.cluster.local:4567" $fullname $i $fullname $namespace) -}} +{{- end -}} +{{- join "," $addresses -}} +{{- end }} + +{{/* +Generate Galera cluster name with release context +*/}} +{{- define "mariadb.galeraClusterName" -}} +{{- printf "%s-%s" .Release.Name .Values.galera.name -}} +{{- end }} + +{{/* +Generate Galera node name with pod name +*/}} +{{- define "mariadb.galeraNodeName" -}} +{{- printf "%s-%s" (include "mariadb.fullname" .) "REPLICA_NUM" -}} +{{- end }} + +{{/* +Generate Galera node address +*/}} +{{- define "mariadb.galeraNodeAddress" -}} +{{- printf "%s-%s.%s.%s.svc.cluster.local" (include "mariadb.fullname" .) "REPLICA_NUM" (include "mariadb.fullname" .) .Release.Namespace -}} +{{- end }} diff --git a/charts/mariadb/templates/configmap.yaml b/charts/mariadb/templates/configmap.yaml index faeaaaa7..9559ebc6 100644 --- a/charts/mariadb/templates/configmap.yaml +++ b/charts/mariadb/templates/configmap.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.config.customConfiguration (not .Values.config.existingConfigMap) }} +{{- if and (or .Values.config.customConfiguration .Values.galera.enabled) (not .Values.config.existingConfigMap) }} apiVersion: v1 kind: ConfigMap metadata: @@ -11,6 +11,12 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} data: + {{- if .Values.config.customConfiguration }} my.cnf: | {{ .Values.config.customConfiguration | nindent 4 }} + {{- end }} + {{- if .Values.galera.enabled }} + 00-galera.cnf: | + !include /etc/mysql/galera.cnf + {{- end }} {{- end }} \ No newline at end of file diff --git a/charts/mariadb/templates/extraobjects.yaml b/charts/mariadb/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/mariadb/templates/extraobjects.yaml +++ b/charts/mariadb/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/mariadb/templates/galera/configmap.yaml b/charts/mariadb/templates/galera/configmap.yaml new file mode 100644 index 00000000..ad603eb9 --- /dev/null +++ b/charts/mariadb/templates/galera/configmap.yaml @@ -0,0 +1,58 @@ +{{- if .Values.galera.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "mariadb.fullname" . }}-galera + namespace: {{ .Release.Namespace }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + galera.cnf: | + [galera] + # Galera Provider Configuration + wsrep_on=ON + wsrep_provider={{ .Values.galera.wsrepProvider }} + wsrep_cluster_name={{ include "mariadb.galeraClusterName" . }} + wsrep_cluster_address=gcomm://{{ include "mariadb.galeraClusterAddress" . }} + wsrep_node_name={{ include "mariadb.galeraNodeName" . }} + wsrep_node_address={{ include "mariadb.galeraNodeAddress" . }} + + # Replication settings + binlog_format=ROW + default_storage_engine=InnoDB + innodb_autoinc_lock_mode=2 + + # InnoDB settings for Galera + innodb_flush_log_at_trx_commit={{ .Values.galera.innodb.flushLogAtTrxCommit }} + innodb_buffer_pool_size={{ .Values.galera.innodb.bufferPoolSize }} + + # Galera performance tuning + wsrep_slave_threads={{ .Values.galera.wsrepSlaveThreads }} + wsrep_certify_nonPK={{ .Values.galera.wsrepCertifyNonPK }} + wsrep_max_ws_rows={{ .Values.galera.wsrepMaxWsRows }} + wsrep_max_ws_size={{ .Values.galera.wsrepMaxWsSize }} + wsrep_retry_autocommit={{ .Values.galera.wsrepRetryAutocommit }} + wsrep_auto_increment_control={{ .Values.galera.wsrepAutoIncrementControl }} + wsrep_drupal_282555_workaround={{ .Values.galera.wsrepDrupalHack }} + wsrep_log_conflicts={{ .Values.galera.wsrepLogConflicts }} + + # State Snapshot Transfer (SST) settings + wsrep_sst_method={{ .Values.galera.wsrepMethod }} + {{- if .Values.galera.sst.user }} + wsrep_sst_auth={{ .Values.galera.sst.user }}:{{ .Values.galera.sst.password }} + {{- end }} + + {{- if .Values.galera.wsrepDebug }} + # Debug settings + wsrep_debug=ON + {{- end }} + + # Additional settings for cluster consistency + innodb_doublewrite=1 + query_cache_type=0 + query_cache_size=0 +{{- end }} \ No newline at end of file diff --git a/charts/mariadb/templates/galera/scripts-configmap.yaml b/charts/mariadb/templates/galera/scripts-configmap.yaml new file mode 100644 index 00000000..d6bb70d5 --- /dev/null +++ b/charts/mariadb/templates/galera/scripts-configmap.yaml @@ -0,0 +1,104 @@ +{{- if .Values.galera.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "mariadb.fullname" . }}-galera-scripts + namespace: {{ .Release.Namespace }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + galera-entrypoint.sh: | + #!/bin/bash + set -eo pipefail + + # Galera entrypoint script for MariaDB + + echo "Starting Galera cluster initialization..." + + # Check if this is the bootstrap node (first replica) + HOSTNAME=$(hostname) + echo "Current hostname: $HOSTNAME" + + # Extract replica number from hostname + REPLICA_NUM=$(echo $HOSTNAME | grep -o '[0-9]*$') + echo "Replica number: $REPLICA_NUM" + + # Check if data directory exists and is empty + DATA_DIR="/var/lib/mysql" + if [ ! -d "$DATA_DIR/mysql" ]; then + echo "Data directory is empty, this is a new installation" + NEW_CLUSTER=true + else + echo "Data directory exists, checking cluster state" + NEW_CLUSTER=false + fi + + # Check grastate.dat for cluster state + GRASTATE_FILE="$DATA_DIR/grastate.dat" + SAFE_TO_BOOTSTRAP=false + + if [ -f "$GRASTATE_FILE" ]; then + echo "Found grastate.dat file" + if grep -q "safe_to_bootstrap: 1" "$GRASTATE_FILE"; then + SAFE_TO_BOOTSTRAP=true + echo "Node is safe to bootstrap" + fi + fi + + # Determine if we should bootstrap or join + BOOTSTRAP_CLUSTER=false + + if [ "$NEW_CLUSTER" = true ] && [ "$REPLICA_NUM" = "0" ]; then + echo "First node in new cluster - will bootstrap" + BOOTSTRAP_CLUSTER=true + elif [ "$MARIADB_GALERA_FORCE_SAFETOBOOTSTRAP" = "true" ]; then + echo "Force bootstrap enabled" + BOOTSTRAP_CLUSTER=true + # Set safe_to_bootstrap=1 in grastate.dat + if [ -f "$GRASTATE_FILE" ]; then + sed -i 's/safe_to_bootstrap: 0/safe_to_bootstrap: 1/' "$GRASTATE_FILE" + fi + elif [ "$SAFE_TO_BOOTSTRAP" = true ]; then + echo "Node is safe to bootstrap based on grastate.dat" + BOOTSTRAP_CLUSTER=true + fi + + # Start MariaDB with appropriate options + if [ "$BOOTSTRAP_CLUSTER" = true ]; then + echo "Bootstrapping new Galera cluster..." + #exec mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + #mariadb-install-db + #sleep 3 + #exec mariadbd --wsrep-new-cluster "$@" + exec /usr/local/bin/docker-entrypoint.sh --wsrep-new-cluster "$@" + + else + echo "Joining existing Galera cluster..." + exec mariadbd "$@" + #exec /usr/local/bin/docker-entrypoint.sh "$@" + fi + + galera-recovery.sh: | + #!/bin/bash + set -eo pipefail + + # Galera recovery script + echo "Starting Galera recovery process..." + + DATA_DIR="/var/lib/mysql" + GRASTATE_FILE="$DATA_DIR/grastate.dat" + + if [ ! -f "$GRASTATE_FILE" ]; then + echo "No grastate.dat found, nothing to recover" + exit 0 + fi + + echo "Checking cluster state..." + mariadbd --wsrep-recover + + echo "Recovery completed" +{{- end }} \ No newline at end of file diff --git a/charts/mariadb/templates/galera/secret.yaml b/charts/mariadb/templates/galera/secret.yaml new file mode 100644 index 00000000..000dfcf5 --- /dev/null +++ b/charts/mariadb/templates/galera/secret.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.galera.enabled .Values.galera.sst.password (not .Values.galera.sst.existingSecret) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "mariadb.fullname" . }}-galera + namespace: {{ .Release.Namespace }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: Opaque +data: + {{- if .Values.galera.sst.user }} + {{ .Values.galera.sst.secretKeys.userKey }}: {{ .Values.galera.sst.user | b64enc | quote }} + {{- end }} + {{ .Values.galera.sst.secretKeys.passwordKey }}: {{ .Values.galera.sst.password | b64enc | quote }} +{{- end }} \ No newline at end of file diff --git a/charts/mariadb/templates/galera/service.yaml b/charts/mariadb/templates/galera/service.yaml new file mode 100644 index 00000000..91427f61 --- /dev/null +++ b/charts/mariadb/templates/galera/service.yaml @@ -0,0 +1,38 @@ + +{{- if .Values.galera.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mariadb.fullname" . }}-headless + namespace: {{ .Release.Namespace }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} + app.kubernetes.io/component: headless + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: true + ports: + - port: {{ .Values.service.port }} + targetPort: mysql + protocol: TCP + name: mysql + - port: 4567 + targetPort: galera-repl + protocol: TCP + name: galera-repl + - port: 4568 + targetPort: galera-ist + protocol: TCP + name: galera-ist + - port: 4444 + targetPort: galera-sst + protocol: TCP + name: galera-sst + selector: + {{- include "mariadb.selectorLabels" . | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/charts/mariadb/templates/pvc.yaml b/charts/mariadb/templates/pvc.yaml index ccc96a24..03545c07 100644 --- a/charts/mariadb/templates/pvc.yaml +++ b/charts/mariadb/templates/pvc.yaml @@ -10,7 +10,8 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "mariadb.labels" . | nindent 4 }} - {{- with .Values.persistence.annotations }} + {{- $annotations := merge .Values.persistence.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/mariadb/templates/service.yaml b/charts/mariadb/templates/service.yaml index e532912f..374803b6 100644 --- a/charts/mariadb/templates/service.yaml +++ b/charts/mariadb/templates/service.yaml @@ -23,5 +23,19 @@ spec: {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePort }} nodePort: {{ .Values.service.nodePort }} {{- end }} + {{- if .Values.galera.enabled }} + - port: 4567 + targetPort: galera-repl + protocol: TCP + name: galera-repl + - port: 4568 + targetPort: galera-ist + protocol: TCP + name: galera-ist + - port: 4444 + targetPort: galera-sst + protocol: TCP + name: galera-sst + {{- end }} selector: - {{- include "mariadb.selectorLabels" . | nindent 4 }} \ No newline at end of file + {{- include "mariadb.selectorLabels" . | nindent 4 }} diff --git a/charts/mariadb/templates/statefulset.yaml b/charts/mariadb/templates/statefulset.yaml index 9d900946..56ffd714 100644 --- a/charts/mariadb/templates/statefulset.yaml +++ b/charts/mariadb/templates/statefulset.yaml @@ -11,7 +11,11 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} spec: + {{- if .Values.galera.enabled }} + replicas: {{ .Values.galera.replicaCount }} + {{- else }} replicas: 1 + {{- end }} serviceName: {{ include "mariadb.fullname" . }} selector: matchLabels: @@ -31,13 +35,42 @@ spec: {{- with (include "mariadb.imagePullSecrets" .) }} {{- . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} + {{- if .Values.galera.enabled }} + initContainers: + - name: galera-config-init + image: {{ include "mariadb.image" . }} + imagePullPolicy: {{ .Values.image.imagePullPolicy }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + command: + - /bin/bash + - -c + - | + REPLICA_NUM=$(echo $HOSTNAME | grep -o '[0-9]*$') + cp /tmp/galera-config-ro/galera.cnf /tmp/galera-config-rw/galera.cnf + sed -i "s/REPLICA_NUM/$REPLICA_NUM/g" /tmp/galera-config-rw/galera.cnf + chmod 644 /tmp/galera-config-rw/galera.cnf + volumeMounts: + - mountPath: /tmp + name: tmp-volume + - name: galera-config + mountPath: /tmp/galera-config-ro + readOnly: true + - name: galera-config-rw + mountPath: /tmp/galera-config-rw + {{- end }} containers: - name: mariadb image: {{ include "mariadb.image" . }} imagePullPolicy: {{ .Values.image.imagePullPolicy }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} - {{- if or .Values.auth.enabled .Values.auth.database .Values.auth.username .Values.auth.allowEmptyRootPassword .Values.env }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + {{- if .Values.galera.enabled }} + command: + - /bin/bash + - -c + - source /usr/local/bin/galera-entrypoint.sh + {{- end }} + {{- if or .Values.auth.enabled .Values.auth.database .Values.auth.username .Values.auth.allowEmptyRootPassword .Values.extraEnvVars .Values.galera.enabled }} env: {{- if and .Values.auth.enabled }} - name: MARIADB_ROOT_PASSWORD @@ -63,7 +96,32 @@ spec: - name: MARIADB_ALLOW_EMPTY_ROOT_PASSWORD value: "1" {{- end }} - {{- with .Values.env }} + {{- if .Values.galera.enabled }} + - name: MARIADB_GALERA_CLUSTER + value: "true" + - name: MARIADB_GALERA_CLUSTER_NAME + value: {{ .Values.galera.name | quote }} + - name: MARIADB_GALERA_NODE_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MARIADB_GALERA_NODE_ADDRESS + valueFrom: + fieldRef: + fieldPath: status.podIP + {{- if .Values.galera.sst.password }} + - name: MARIADB_GALERA_SST_USER + value: {{ .Values.galera.sst.user | quote }} + - name: MARIADB_GALERA_SST_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mariadb.galeraSecretName" . }} + key: {{ .Values.galera.sst.secretKeys.passwordKey }} + {{- end }} + - name: MARIADB_GALERA_FORCE_SAFETOBOOTSTRAP + value: {{ .Values.galera.forceSafeToBootstrap | quote }} + {{- end }} + {{- with .Values.extraEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} {{- end }} @@ -71,20 +129,43 @@ spec: - name: mysql containerPort: 3306 protocol: TCP + {{- if .Values.galera.enabled }} + - name: galera-repl + containerPort: 4567 + protocol: TCP + - name: galera-ist + containerPort: 4568 + protocol: TCP + - name: galera-sst + containerPort: 4444 + protocol: TCP + {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: exec: command: - bash - -c + {{- if and .Values.galera.enabled .Values.auth.enabled }} + - | + if mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" -e "SHOW STATUS LIKE 'wsrep_ready'" | grep -q ON; then + exit 0 + else + mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" -e "SHOW STATUS LIKE 'wsrep_local_state_comment'" + mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" -e "SHOW STATUS LIKE 'wsrep_ready'" + echo "healthcheck failed: Galera not alive" + exit 1 + fi + {{- else }} - healthcheck.sh --connect --innodb_initialized + {{- end }} initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} successThreshold: {{ .Values.livenessProbe.successThreshold }} failureThreshold: {{ .Values.livenessProbe.failureThreshold }} {{- end }} - {{- if .Values.readinessProbe.enabled }} + {{- if and .Values.readinessProbe.enabled (not .Values.galera.enabled)}} readinessProbe: exec: command: @@ -97,7 +178,7 @@ spec: successThreshold: {{ .Values.readinessProbe.successThreshold }} failureThreshold: {{ .Values.readinessProbe.failureThreshold }} {{- end }} - {{- if .Values.startupProbe.enabled }} + {{- if and .Values.startupProbe.enabled (not .Values.galera.enabled)}} startupProbe: exec: command: @@ -119,10 +200,18 @@ spec: mountPath: /var/lib/mysql - mountPath: /tmp name: tmp-volume - {{- if or .Values.config.customConfiguration .Values.config.existingConfigMap }} + {{- if or .Values.config.customConfiguration .Values.config.existingConfigMap .Values.galera.enabled }} - name: config mountPath: /etc/mysql/conf.d {{- end }} + {{- if .Values.galera.enabled }} + - name: galera-config-rw + mountPath: /etc/mysql/mariadb.conf.d/60-galera.cnf + subPath: galera.cnf + - name: galera-scripts + mountPath: /usr/local/bin/galera-entrypoint.sh + subPath: galera-entrypoint.sh + {{- end }} {{- if .Values.initdbScriptsConfigMap }} - name: custom-init-scripts mountPath: /docker-entrypoint-initdb.d @@ -131,6 +220,18 @@ spec: - name: run mountPath: /var/run/mysqld/ {{- end }} + {{- range $secret := .Values.extraSecrets }} + - name: {{ $secret.name }} + mountPath: {{ $secret.mountPath }} + {{- end }} + {{- range $config := .Values.extraConfigs }} + - name: {{ $config.name }} + mountPath: {{ $config.mountPath }} + {{- end }} + {{- range $storage := .Values.extraVolumes }} + - name: {{ $storage.name }} + mountPath: {{ $storage.mountPath }} + {{- end }} volumes: - name: tmp-volume emptyDir: {} @@ -142,11 +243,22 @@ spec: - name: run emptyDir: {} {{- end }} - {{- if or .Values.config.customConfiguration .Values.config.existingConfigMap }} + {{- if or .Values.config.customConfiguration .Values.config.existingConfigMap .Values.galera.enabled }} - name: config configMap: name: {{ include "mariadb.configMapName" . }} {{- end }} + {{- if .Values.galera.enabled }} + - name: galera-config + configMap: + name: {{ include "mariadb.fullname" . }}-galera + - name: galera-config-rw + emptyDir: {} + - name: galera-scripts + configMap: + name: {{ include "mariadb.fullname" . }}-galera-scripts + defaultMode: 0755 + {{- end }} {{- if .Values.initdbScriptsConfigMap }} - name: custom-init-scripts configMap: diff --git a/charts/mariadb/values.schema.json b/charts/mariadb/values.schema.json index 529f9720..ae2b2c81 100644 --- a/charts/mariadb/values.schema.json +++ b/charts/mariadb/values.schema.json @@ -1,736 +1,453 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "MariaDB Helm Chart Values Schema", - "description": "Schema for MariaDB Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global Parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker Image registry" + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override mariadb.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override mariadb.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "image": { - "type": "object", - "title": "MariaDB Image Configuration", - "description": "MariaDB container image parameters", - "properties": { - "registry": { - "type": "string", - "title": "MariaDB Image Registry", - "description": "MariaDB image registry" - }, - "repository": { - "type": "string", - "title": "MariaDB Image Repository", - "description": "MariaDB image repository" + "allowEmptyRootPassword": { + "type": "string" + }, + "database": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "password": { + "type": "string" + }, + "rootPassword": { + "type": "string" + }, + "secretKeys": { + "type": "object", + "properties": { + "rootPasswordKey": { + "type": "string" + }, + "userPasswordKey": { + "type": "string" + } + } + }, + "username": { + "type": "string" + } + } }, - "tag": { - "type": "string", - "title": "MariaDB Image Tag", - "description": "MariaDB image tag with digest" + "commonAnnotations": { + "type": "object" }, - "imagePullPolicy": { - "type": "string", - "title": "MariaDB Image Pull Policy", - "description": "MariaDB image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] + "commonLabels": { + "type": "object" }, - "pullSecrets": { - "type": "array", - "title": "MariaDB Image Pull Secrets", - "description": "MariaDB image pull secrets", - "items": { + "config": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "auth": { - "type": "object", - "title": "MariaDB Authentication", - "description": "Authentication parameters", - "properties": { - "rootPassword": { - "type": "string", - "title": "MariaDB Root Password", - "description": "MariaDB root password" - }, - "database": { - "type": "string", - "title": "MariaDB Custom Database", - "description": "MariaDB custom database" - }, - "username": { - "type": "string", - "title": "MariaDB Custom Username", - "description": "MariaDB custom user name" - }, - "password": { - "type": "string", - "title": "MariaDB Custom Password", - "description": "MariaDB custom user password" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret to use for MariaDB credentials" - }, - "secretKeys": { - "type": "object", - "title": "Secret Keys", - "description": "Keys in existing secret", - "properties": { - "rootPasswordKey": { - "type": "string", - "title": "Root Password Key", - "description": "Name of key in existing secret to use for root password" - }, - "userPasswordKey": { - "type": "string", - "title": "User Password Key", - "description": "Name of key in existing secret to use for user password" + "customConfiguration": { + "type": "string" + }, + "existingConfigMap": { + "type": "string" + } } - } - } - } - }, - "config": { - "type": "object", - "title": "MariaDB Configuration", - "description": "MariaDB configuration parameters", - "properties": { - "customConfiguration": { - "type": "string", - "title": "Custom Configuration", - "description": "Custom configuration for MariaDB" - }, - "existingConfigMap": { - "type": "string", - "title": "Existing ConfigMap", - "description": "Name of existing ConfigMap with MariaDB configuration" - } - } - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "MariaDB service parameters", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "MariaDB service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "MariaDB service port", - "minimum": 1, - "maximum": 65535 }, - "nodePort": { - "type": "string", - "title": "Node Port", - "description": "Node port for MariaDB service" - }, - "clusterIP": { - "type": "string", - "title": "Cluster IP", - "description": "Static cluster IP or None for headless service" + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } + } }, - "annotations": { - "type": "object", - "title": "Service Annotations", - "description": "Additional custom annotations for MariaDB service", - "additionalProperties": { - "type": "string" - } - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "Persistence parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable MariaDB data persistence using PVC" + "extraConfigs": { + "type": "array" }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "PVC Storage Class for MariaDB data volume" + "extraEnvVars": { + "type": "array" }, - "accessModes": { - "type": "array", - "title": "Access Modes", - "description": "PVC Access modes", - "items": { - "type": "string", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] - } + "extraObjects": { + "type": "array" }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "PVC Storage Request for MariaDB data volume", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" + "extraSecrets": { + "type": "array" }, - "annotations": { - "type": "object", - "title": "PVC Annotations", - "description": "Additional custom annotations for the PVC", - "additionalProperties": { - "type": "string" - } + "extraVolumes": { + "type": "array" }, - "selector": { - "type": "object", - "title": "PVC Selector", - "description": "Additional labels for the PVC", - "additionalProperties": { + "fullnameOverride": { "type": "string" - } - } - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "MariaDB Pod Security Context", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Pod Security Context", - "description": "Enabled MariaDB pod Security Context" }, - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Set MariaDB pod's Security Context fsGroup", - "minimum": 0 - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "Container Security Context", - "description": "MariaDB Container Security Context", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Container Security Context", - "description": "Enabled MariaDB container's Security Context" - }, - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "Set MariaDB container's Security Context runAsUser", - "minimum": 0 - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Set MariaDB container's Security Context runAsNonRoot" + "galera": { + "type": "object", + "properties": { + "bootstrap": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "enabled": { + "type": "boolean" + }, + "forceSafeToBootstrap": { + "type": "boolean" + }, + "innodb": { + "type": "object", + "properties": { + "bufferPoolSize": { + "type": "string" + }, + "flushLogAtTrxCommit": { + "type": "integer" + } + } + }, + "name": { + "type": "string" + }, + "recovery": { + "type": "object", + "properties": { + "clusterBootstrap": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "sst": { + "type": "object", + "properties": { + "existingSecret": { + "type": "string" + }, + "password": { + "type": "string" + }, + "secretKeys": { + "type": "object", + "properties": { + "passwordKey": { + "type": "string" + }, + "userKey": { + "type": "string" + } + } + }, + "user": { + "type": "string" + } + } + }, + "wsrepAutoIncrementControl": { + "type": "boolean" + }, + "wsrepCertifyNonPK": { + "type": "boolean" + }, + "wsrepDebug": { + "type": "boolean" + }, + "wsrepDrupalHack": { + "type": "boolean" + }, + "wsrepLogConflicts": { + "type": "boolean" + }, + "wsrepMaxWsRows": { + "type": "integer" + }, + "wsrepMaxWsSize": { + "type": "string" + }, + "wsrepMethod": { + "type": "string" + }, + "wsrepProvider": { + "type": "string" + }, + "wsrepRetryAutocommit": { + "type": "integer" + }, + "wsrepSlaveThreads": { + "type": "integer" + } + } }, - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Set MariaDB container's privilege escalation" + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } }, - "readOnlyRootFilesystem": { - "type": "boolean", - "title": "Read-Only root filesystem", - "description": "Set MariaDB container's Security Context readOnlyRootFilesystem" - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resources parameters", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "The resources limits for the MariaDB containers", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } } - } }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "The requested resources for the MariaDB containers", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "properties": { + "kubernetes.io/hostname": { + "type": "string" + } + } + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } } - } - } - } - }, - "env": { - "type": "array", - "title": "Environment Variables", - "description": "A list of additional environment Variables", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Variable Name", - "description": "Environment variable name" - }, - "value": { - "type": "string", - "title": "Variable Value", - "description": "Environment variable value" - } }, - "required": ["name"] - } - }, - "extraSecrets": { - "type": "array", - "title": "Extra Secrets", - "description": "A list of additional existing secrets that will be mounted into the container", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "defaultMode": { - "type": "integer" - }, - "mountPath": { - "type": "string" - } - } - } - }, - "extraConfigs": { - "type": "array", - "title": "Extra Configs", - "description": "A list of additional existing configMaps that will be mounted into the container", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "defaultMode": { - "type": "integer" - }, - "mountPath": { + "initdbScriptsConfigMap": { "type": "string" - } - } - } - }, - "extraVolumes": { - "type": "array", - "title": "Extra Volumes", - "description": "A list of additional existing volumes that will be mounted into the container", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "mountPath": { - "type": "string" - }, - "pvcName": { - "type": "string" - } - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "MariaDB container's liveness probe parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable livenessProbe on MariaDB containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for livenessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for livenessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for livenessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for livenessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for livenessProbe", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "MariaDB container's readiness probe parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readinessProbe on MariaDB containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for readinessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for readinessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for readinessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for readinessProbe", - "minimum": 1 }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for readinessProbe", - "minimum": 1 - } - } - }, - "startupProbe": { - "type": "object", - "title": "Startup Probe Configuration", - "description": "MariaDB container's startup probe parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Startup Probe", - "description": "Enable startupProbe on MariaDB containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for startupProbe", - "minimum": 0 + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for startupProbe", - "minimum": 1 + "nameOverride": { + "type": "string" }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for startupProbe", - "minimum": 1 + "networkPolicy": { + "type": "object", + "properties": { + "allowExternal": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "ingressNSMatchLabels": { + "type": "object" + }, + "ingressNSPodMatchLabels": { + "type": "object" + } + } }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for startupProbe", - "minimum": 1 + "nodeSelector": { + "type": "object" }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for startupProbe", - "minimum": 1 - } - } - }, - "podDisruptionBudget": { - "type": "object", - "title": "Pod Disruption Budget Configuration", - "description": "Pod Disruption Budget configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Pod Disruption Budget", - "description": "Enable a Pod Disruption Budget creation" + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "selector": { + "type": "object" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } }, - "minAvailable": { - "oneOf": [ - {"type": "integer", "minimum": 0}, - {"type": "string"} - ], - "title": "Min Available", - "description": "Min number of pods that must still be available after the eviction" + "podAnnotations": { + "type": "object" }, - "maxUnavailable": { - "oneOf": [ - {"type": "integer", "minimum": 0}, - {"type": "string"} - ], - "title": "Max Unavailable", - "description": "Max number of pods that can be unavailable after the eviction" - } - } - }, - "ingress": { - "type": "object", - "title": "Ingress Configuration", - "description": "Ingress parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Ingress", - "description": "Enable ingress record generation for MariaDB" + "podDisruptionBudget": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxUnavailable": { + "type": "string" + }, + "minAvailable": { + "type": "integer" + } + } }, - "className": { - "type": "string", - "title": "Ingress Class Name", - "description": "IngressClass that will be used to implement the Ingress" + "podLabels": { + "type": "object" }, - "annotations": { - "type": "object", - "title": "Ingress Annotations", - "description": "Additional annotations for the Ingress resource", - "additionalProperties": { - "type": "string" - } + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } }, - "hosts": { - "type": "array", - "title": "Ingress Hosts", - "description": "An array with hosts and paths", - "items": { + "readinessProbe": { "type": "object", "properties": { - "host": { - "type": "string", - "title": "Host", - "description": "Hostname for the ingress" - }, - "paths": { - "type": "array", - "title": "Paths", - "description": "Paths configuration for the host", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "title": "Path", - "description": "Path for the ingress" - }, - "pathType": { - "type": "string", - "title": "Path Type", - "description": "Path type for the ingress", - "enum": ["Exact", "Prefix", "ImplementationSpecific"] - } - } + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" } - } } - } }, - "tls": { - "type": "array", - "title": "TLS Configuration", - "description": "TLS configuration for the Ingress", - "items": { + "resources": { "type": "object" - } - } - } - }, - "networkPolicy": { - "type": "object", - "title": "Network Policy Configuration", - "description": "Network Policy configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Network Policy", - "description": "Specifies whether a NetworkPolicy should be created" }, - "allowExternal": { - "type": "boolean", - "title": "Allow External", - "description": "Don't require client label for connections" + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "clusterIP": { + "type": "string" + }, + "nodePort": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } }, - "ingressNSMatchLabels": { - "type": "object", - "title": "Ingress Namespace Match Labels", - "description": "Labels to match to allow traffic from other namespaces", - "additionalProperties": { - "type": "string" - } + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "ingressNSPodMatchLabels": { - "type": "object", - "title": "Ingress Namespace Pod Match Labels", - "description": "Pod labels to match to allow traffic from other namespaces", - "additionalProperties": { - "type": "string" - } + "tolerations": { + "type": "array" } - } - }, - "podAnnotations": { - "type": "object", - "title": "Pod Annotations", - "description": "Pod configuration annotations", - "additionalProperties": { - "type": "string" - } - }, - "podLabels": { - "type": "object", - "title": "Pod Labels", - "description": "Pod configuration labels", - "additionalProperties": { - "type": "string" - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node selector for pod assignment", - "additionalProperties": { - "type": "string" - } - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Tolerations for pod assignment", - "items": { - "type": "object" - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity settings for pod assignment" - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } -} \ No newline at end of file +} diff --git a/charts/mariadb/values.yaml b/charts/mariadb/values.yaml index c2bcf586..6c60abcf 100644 --- a/charts/mariadb/values.yaml +++ b/charts/mariadb/values.yaml @@ -22,7 +22,7 @@ image: ## @param image.repository MariaDB image repository repository: mariadb ## @param image.tag MariaDB image tag (immutable tags are recommended) - tag: "12.0.2@sha256:03a03a6817bb9eaa21e5aed1b734d432ec3f80021f5a2de1795475f158217545" + tag: "12.0.2@sha256:5b6a1eac15b85b981a61afb89aea2a22bf76b5f58809d05f0bcc13ab6ec44cb8" ## @param image.pullPolicy MariaDB image pull policy imagePullPolicy: Always @@ -55,6 +55,67 @@ config: ## @param config.existingConfigMap Name of existing ConfigMap with MariaDB configuration existingConfigMap: "" +## @section Galera Cluster parameters +galera: + ## @param galera.enabled Enable Galera Cluster mode + enabled: false + ## @param galera.name Galera cluster name + name: "galera" + ## @param galera.bootstrap.enabled Enable bootstrap mode for the first node in the cluster + bootstrap: + enabled: true + ## @param galera.replicaCount Number of nodes in the Galera cluster + replicaCount: 3 + ## @param galera.wsrepProvider Path to wsrep provider library + wsrepProvider: "/usr/lib/galera/libgalera_smm.so" + ## @param galera.wsrepMethod Method for state snapshot transfers + ## Options: mariabackup, mysqldump, rsync + wsrepMethod: "mariabackup" + ## @param galera.forceSafeToBootstrap Force safe_to_bootstrap=1 in grastate.dat + forceSafeToBootstrap: false + ## @param galera.wsrepSlaveThreads Number of slave threads for applying writesets + wsrepSlaveThreads: 1 + ## @param galera.wsrepCertifyNonPK Require primary key for replication + wsrepCertifyNonPK: true + ## @param galera.wsrepMaxWsRows Maximum number of rows in writeset + wsrepMaxWsRows: 0 + ## @param galera.wsrepMaxWsSize Maximum size of writeset in bytes + wsrepMaxWsSize: "1073741824" + ## @param galera.wsrepDebug Enable wsrep debugging + wsrepDebug: false + ## @param galera.wsrepRetryAutocommit Number of times to retry autocommit + wsrepRetryAutocommit: 1 + ## @param galera.wsrepAutoIncrementControl Enable auto increment control + wsrepAutoIncrementControl: true + ## @param galera.wsrepDrupalHack Enable Drupal compatibility hack + wsrepDrupalHack: false + ## @param galera.wsrepLogConflicts Log conflicts to error log + wsrepLogConflicts: false + ## @param galera.innodb.flushLogAtTrxCommit InnoDB flush log at transaction commit + innodb: + flushLogAtTrxCommit: 0 + ## @param galera.innodb.bufferPoolSize InnoDB buffer pool size + bufferPoolSize: "128M" + ## @param galera.sst SST specific configuration + sst: + ## @param galera.sst.user SST user for authentication + user: "" + ## @param galera.sst.password SST password for authentication + password: "" + ## @param galera.sst.existingSecret Existing secret containing SST credentials + existingSecret: "" + ## @param galera.sst.secretKeys.userKey Secret key for SST user + ## @param galera.sst.secretKeys.passwordKey Secret key for SST password + secretKeys: + userKey: sst-user + passwordKey: sst-password + ## @param galera.recovery Enable Galera recovery options + recovery: + ## @param galera.recovery.enabled Enable automatic recovery + enabled: true + ## @param galera.recovery.clusterBootstrap Enable cluster bootstrap in recovery + clusterBootstrap: true + ## @section MariaDB service parameters service: ## @param service.type MariaDB service type @@ -112,10 +173,15 @@ resources: ## cpu: 100m ## @section Extra Configs -## @param env A list of additional environment Variables -env: [] -## - name: ENV_VARIABLE -## value: "value" +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraSecrets A list of additional existing secrets that will be mounted into the container extraSecrets: [] ## - name: secret diff --git a/charts/memcached/CHANGELOG.md b/charts/memcached/CHANGELOG.md index 54e971e4..8cb1da34 100644 --- a/charts/memcached/CHANGELOG.md +++ b/charts/memcached/CHANGELOG.md @@ -1,5 +1,123 @@ # Changelog -## 0.2.1 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +## 0.5.3 (2025-11-05) + +* Add support for pod labels (#550) ([6071930](https://github.com/CloudPirates-io/helm-charts/commit/6071930)) +* chore: update CHANGELOG.md for merged changes ([d944483](https://github.com/CloudPirates-io/helm-charts/commit/d944483)) +* chore: update CHANGELOG.md for merged changes ([6038560](https://github.com/CloudPirates-io/helm-charts/commit/6038560)) + +## 0.5.2 (2025-11-04) + +* Update charts/memcached/values.yaml memcached (#543) ([8653b45](https://github.com/CloudPirates-io/helm-charts/commit/8653b45)) +* chore: update CHANGELOG.md for merged changes ([b1b5bea](https://github.com/CloudPirates-io/helm-charts/commit/b1b5bea)) +* chore: update CHANGELOG.md for merged changes ([09264e3](https://github.com/CloudPirates-io/helm-charts/commit/09264e3)) + +## 0.5.1 (2025-11-04) + +* Update charts/memcached/values.yaml memcached (#540) ([80a134a](https://github.com/CloudPirates-io/helm-charts/commit/80a134a)) +* chore: update CHANGELOG.md for merged changes ([a45d016](https://github.com/CloudPirates-io/helm-charts/commit/a45d016)) +* chore: update CHANGELOG.md for merged changes ([c8a10d1](https://github.com/CloudPirates-io/helm-charts/commit/c8a10d1)) +* chore: auto-generate values.schema.json (#525) ([82bb370](https://github.com/CloudPirates-io/helm-charts/commit/82bb370)) +* chore: update CHANGELOG.md for merged changes ([d897e41](https://github.com/CloudPirates-io/helm-charts/commit/d897e41)) +* chore: update CHANGELOG.md for merged changes ([1a540b0](https://github.com/CloudPirates-io/helm-charts/commit/1a540b0)) + +## 0.5.0 (2025-11-02) + +* Add metrics support (#512) ([5ea2397](https://github.com/CloudPirates-io/helm-charts/commit/5ea2397)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.4.0 (2025-10-28) + +* chore: auto-generate values.schema.json for updated charts (#455) ([aec6840](https://github.com/CloudPirates-io/helm-charts/commit/aec6840)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.3.4 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([95d9741](https://github.com/CloudPirates-io/helm-charts/commit/95d9741)) +* chore: update CHANGELOG.md for merged changes ([ceb2770](https://github.com/CloudPirates-io/helm-charts/commit/ceb2770)) + +## 0.3.3 (2025-10-22) + +* Update charts/memcached/values.yaml memcached (#425) ([de0a4a1](https://github.com/CloudPirates-io/helm-charts/commit/de0a4a1)) + +## 0.3.2 (2025-10-21) + +* Update charts/memcached/values.yaml memcached (#424) ([304f6bd](https://github.com/CloudPirates-io/helm-charts/commit/304f6bd)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([6d3bd93](https://github.com/CloudPirates-io/helm-charts/commit/6d3bd93)) + +## 0.3.1 (2025-10-15) + +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* [memcached]: add missing automountServiceAccountToken key to deployment spec (#395) ([93fee01](https://github.com/CloudPirates-io/helm-charts/commit/93fee01)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.3.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.2.3 (2025-10-13) + + +## 0.2.2 (2025-10-10) + +* [memcached]: Implement PDB (#295) ([b974e8a](https://github.com/CloudPirates-io/helm-charts/commit/b974e8a)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + +## 0.2.1 (2025-10-02) + +* chore(deps): update docker.io/memcached:1.6.39 Docker digest to 157c563 (#185) ([d55b428](https://github.com/CloudPirates-io/helm-charts/commit/d55b428)) + +## 0.2.0 (2025-10-01) + +* make memcached run on openshift (#194) ([87ffbbf](https://github.com/CloudPirates-io/helm-charts/commit/87ffbbf)) +* Update CHANGELOG.md ([7a828fa](https://github.com/CloudPirates-io/helm-charts/commit/7a828fa)) +* Update CHANGELOG.md ([f9df296](https://github.com/CloudPirates-io/helm-charts/commit/f9df296)) +* Update CHANGELOG.md ([0c85529](https://github.com/CloudPirates-io/helm-charts/commit/0c85529)) + +## 0.1.3 (2025-09-23) + +* Update CHANGELOG.md ([0e5b657](https://github.com/CloudPirates-io/helm-charts/commit/0e5b657)) +* cast verbosity to int before passing to repeat ([518b602](https://github.com/CloudPirates-io/helm-charts/commit/518b602)) + +## 0.1.2 (2025-09-10) + +* Update CHANGELOG.md ([dcabcee](https://github.com/CloudPirates-io/helm-charts/commit/dcabcee)) +* bump version ([884f4ab](https://github.com/CloudPirates-io/helm-charts/commit/884f4ab)) +* chore(deps): update docker.io/memcached:1.6.39 Docker digest to 68c1185 ([3c6ec49](https://github.com/CloudPirates-io/helm-charts/commit/3c6ec49)) + +## 0.1.1 (2025-09-09) + +* Update CHANGELOG.md ([812bd46](https://github.com/CloudPirates-io/helm-charts/commit/812bd46)) +* Bump chart version ([1661d8d](https://github.com/CloudPirates-io/helm-charts/commit/1661d8d)) +* Update docker.io/memcached:1.6.39 Docker digest to 4404f32 ([454eea5](https://github.com/CloudPirates-io/helm-charts/commit/454eea5)) +* mariadb now respects full custom container security context settings memcached readme fixed, this option was not available ([770ea69](https://github.com/CloudPirates-io/helm-charts/commit/770ea69)) + +## 0.1.0 (2025-09-02) + +* bump all chart versions for new extraObjects feature ([aaa57f9](https://github.com/CloudPirates-io/helm-charts/commit/aaa57f9)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.0.2 (2025-08-27) + +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.0.1 (2025-08-26) + +* Initial tagged release diff --git a/charts/memcached/Chart.lock b/charts/memcached/Chart.lock index c79512b3..81b28fe5 100644 --- a/charts/memcached/Chart.lock +++ b/charts/memcached/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-09-30T21:16:48.901325+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:25.445997+02:00" diff --git a/charts/memcached/Chart.yaml b/charts/memcached/Chart.yaml index c56e7df5..e315ed21 100644 --- a/charts/memcached/Chart.yaml +++ b/charts/memcached/Chart.yaml @@ -2,29 +2,44 @@ apiVersion: v2 name: memcached description: Memcached is an in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering. type: application - -version: 0.2.1 +version: 0.5.3 appVersion: "1.6.39" - keywords: - memcached - cache - in-memory - key-value - distributed - -home: https://www.cloudpirates.io - +home: https://memcached.org sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/memcached - + - https://github.com/memcached/memcached maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io - dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates - icon: https://a.storyblok.com/f/143071/512x512/0faa83eb34/memcached-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: Memcached + url: https://memcached.org + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/memcached + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Add support for pod labels (#550)" + links: + - name: "Commit 6071930" + url: "https://github.com/CloudPirates-io/helm-charts/commit/6071930" diff --git a/charts/memcached/README.md b/charts/memcached/README.md index 32cc5445..47845537 100644 --- a/charts/memcached/README.md +++ b/charts/memcached/README.md @@ -62,12 +62,14 @@ The following table lists the configurable parameters of the Memcached chart and ### Common Parameters -| Parameter | Description | Default | -| ------------------- | ----------------------------------------------- | ------- | -| `nameOverride` | String to partially override memcached.fullname | `""` | -| `fullnameOverride` | String to fully override memcached.fullname | `""` | -| `commonLabels` | Labels to add to all deployed objects | `{}` | -| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| Parameter | Description | Default | +|---------------------|----------------------------------------------------------| ------- | +| `nameOverride` | String to partially override memcached.fullname | `""` | +| `fullnameOverride` | String to fully override memcached.fullname | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `podAnnotations` | Annotations to add to the pods created by the deployment | `{}` | +| `podLabels` | Labels to add to the pods created by the deployment | `{}` | ### Memcached Image Parameters @@ -158,11 +160,19 @@ The following table lists the configurable parameters of the Memcached chart and | `ingress.hosts` | An array with hosts and paths | `[{"host": "memcached.local", "paths": [{"path": "/", "pathType": "ImplementationSpecific"}]}]` | | `ingress.tls` | TLS configuration for the Ingress | `[]` | +### Pod Disruption Budget Parameters + +| Parameter | Description | Default | +| -------------------- | -------------------------------------------------------------- | ------- | +| `pdb.create` | Enable/disable a Pod Disruption Budget creation | `false` | +| `pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | +| `pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable | `""` | + ### Extra Configuration Parameters | Parameter | Description | Default | | ------------------- | ----------------------------------------------------------------------------------- | ------- | -| `extraEnv` | A list of additional environment variables | `[]` | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraVolumes` | A list of additional existing volumes that will be mounted into the container | `[]` | | `extraVolumeMounts` | A list of additional existing volume mounts that will be mounted into the container | `[]` | | `extraObjects` | A list of additional Kubernetes objects to deploy alongside the release | `[]` | @@ -213,6 +223,34 @@ All objects in `extraObjects` will be rendered and deployed with the release. Yo | `tolerations` | Tolerations for pod assignment | `[]` | | `affinity` | Affinity for pod assignment | `{}` | +### Metrics + +| Parameter | Description | Default | +|--------------------------------------------|----------------------------------------------------------------------------------------|----------------------------| +| `metrics.enabled` | Start a sidecar Prometheus exporter to expose Memcached metrics | `false` | +| `metrics.image.registry` | Memcached exporter image registry | `docker.io` | +| `metrics.image.repository` | Memcached exporter image repository | `prom/memcached-exporter` | +| `metrics.image.tag` | Memcached exporter image tag | See values.yaml | +| `metrics.image.pullPolicy` | Memcached exporter image pull policy | `Always` | +| `metrics.resources.requests.cpu` | CPU request for the metrics container | `50m` | +| `metrics.resources.requests.memory` | Memory request for the metrics container | `64Mi` | +| `metrics.resources.limits.cpu` | CPU limit for the metrics container | `nil` | +| `metrics.resources.limits.memory` | Memory limit for the metrics container | `64Mi` | +| `metrics.extraArgs` | Extra arguments for Memcached exporter (e.g. `--log.level=debug`, `--log.format=json`) | `[]` | +| `metrics.service.type` | Metrics service type | `ClusterIP` | +| `metrics.service.port` | Metrics service port | `9150` | +| `metrics.service.annotations` | Additional custom annotations for Metrics service | `{}` | +| `metrics.serviceMonitor.enabled` | Create ServiceMonitor resource for scraping metrics using Prometheus Operator | `false` | +| `metrics.serviceMonitor.interval` | Interval at which metrics should be scraped | `30s` | +| `metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `""` | +| `metrics.serviceMonitor.relabelings` | Relabeling rules to apply the targetโ€™s metadata labels before scraping. | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | Relabeling rules to apply to the samples before ingestion. | `[]` | +| `metrics.serviceMonitor.honorLabels` | Honor metrics labels when they collide with Prometheus target labels | `false` | +| `metrics.serviceMonitor.labels` | Additional service monitor labels | `{}` | +| `metrics.serviceMonitor.annotations` | Additional custom annotations for the ServiceMonitor | `{}` | +| `metrics.serviceMonitor.namespaceSelector` | Which namespace(s) Prometheus should discover the services in. | `{}` | + + ## Examples ### Basic Installation @@ -258,6 +296,11 @@ resources: service: type: ClusterIP +# Enable Pod Disruption Budget for high availability +pdb: + create: true + minAvailable: 1 + # Use anti-affinity to spread pods across nodes affinity: podAntiAffinity: diff --git a/charts/memcached/templates/_helpers.tpl b/charts/memcached/templates/_helpers.tpl index 1ca02689..829e341c 100644 --- a/charts/memcached/templates/_helpers.tpl +++ b/charts/memcached/templates/_helpers.tpl @@ -2,56 +2,63 @@ Expand the name of the chart. */}} {{- define "memcached.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "memcached.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "memcached.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "memcached.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Selector labels */}} {{- define "memcached.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Common annotations */}} {{- define "memcached.annotations" -}} -{{- include "common.annotations" . -}} +{{- include "cloudpirates.annotations" . -}} {{- end }} {{/* Return the proper Memcached image name */}} {{- define "memcached.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- end }} + +{{/* +Return the proper Memcached metrics image name +*/}} +{{- define "memcached.metrics.image" -}} +{{- include "cloudpirates.image" (dict "image" .Values.metrics.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "memcached.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* @@ -63,4 +70,4 @@ Create the name of the service account to use {{- else }} {{- default "default" .Values.serviceAccount.name }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/memcached/templates/configmap.yaml b/charts/memcached/templates/configmap.yaml index b50f030f..6c5d319a 100644 --- a/charts/memcached/templates/configmap.yaml +++ b/charts/memcached/templates/configmap.yaml @@ -6,6 +6,10 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "memcached.labels" . | nindent 4 }} + {{- with (include "memcached.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} data: {{- if .Values.configMap.data }} {{- toYaml .Values.configMap.data | nindent 2 }} diff --git a/charts/memcached/templates/deployment.yaml b/charts/memcached/templates/deployment.yaml index 11488aa9..ae3fafd8 100644 --- a/charts/memcached/templates/deployment.yaml +++ b/charts/memcached/templates/deployment.yaml @@ -18,17 +18,25 @@ spec: metadata: labels: {{- include "memcached.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} spec: {{- with (include "memcached.imagePullSecrets" .) }} {{ . | nindent 6 }} {{- end }} + automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} serviceAccountName: {{ include "memcached.serviceAccountName" . }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "memcached.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} args: {{- if .Values.config.memoryLimit }} - "-m" @@ -48,12 +56,9 @@ spec: - name: memcached containerPort: 11211 protocol: TCP - {{- if .Values.extraEnv }} + {{- with .Values.extraEnvVars }} env: - {{- range .Values.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} - {{- end }} +{{- toYaml . | nindent 12 }} {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: @@ -80,6 +85,40 @@ spec: volumeMounts: {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: {{ include "memcached.metrics.image" . | quote }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.metrics.image) }} + args: + - "--memcached.address=localhost:{{ .Values.service.port }}" + - "--web.listen-address=:{{ .Values.metrics.service.port }}" + {{- range .Values.metrics.extraArgs }} + - {{ . }} + {{- end }} + ports: + - name: metrics + containerPort: {{ .Values.metrics.service.port }} + protocol: TCP + livenessProbe: + httpGet: + path: / + port: metrics + initialDelaySeconds: 15 + periodSeconds: 15 + timeoutSeconds: 5 + failureThreshold: 3 + successThreshold: 1 + readinessProbe: + httpGet: + path: / + port: metrics + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + resources: {{ toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} {{- if .Values.extraVolumes }} volumes: {{- toYaml .Values.extraVolumes | nindent 8 }} @@ -95,4 +134,4 @@ spec: {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file + {{- end }} diff --git a/charts/memcached/templates/extraobjects.yaml b/charts/memcached/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/memcached/templates/extraobjects.yaml +++ b/charts/memcached/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/memcached/templates/pdb.yaml b/charts/memcached/templates/pdb.yaml new file mode 100644 index 00000000..c12b91f0 --- /dev/null +++ b/charts/memcached/templates/pdb.yaml @@ -0,0 +1,22 @@ +{{- if .Values.pdb.create }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ template "memcached.fullname" . }}-pdb + namespace: {{ .Release.Namespace }} + labels: {{- include "memcached.labels" . | nindent 4 }} + {{- with (include "memcached.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.pdb.minAvailable }} + minAvailable: {{ .Values.pdb.minAvailable }} + {{- end }} + {{- if or .Values.pdb.maxUnavailable (not .Values.pdb.minAvailable) }} + maxUnavailable: {{ .Values.pdb.maxUnavailable | default 1 }} + {{- end }} + selector: + matchLabels: + {{- include "memcached.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/charts/memcached/templates/service.yaml b/charts/memcached/templates/service.yaml index 1aae169a..b17e5ee2 100644 --- a/charts/memcached/templates/service.yaml +++ b/charts/memcached/templates/service.yaml @@ -2,9 +2,12 @@ apiVersion: v1 kind: Service metadata: name: {{ include "memcached.fullname" . }} - namespace: {{ .Release.Namespace | quote }} labels: {{- include "memcached.labels" . | nindent 4 }} + {{- with (include "memcached.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} ports: @@ -13,4 +16,28 @@ spec: protocol: TCP name: memcached selector: - {{- include "memcached.selectorLabels" . | nindent 4 }} \ No newline at end of file + {{- include "memcached.selectorLabels" . | nindent 4 }} +{{- if .Values.metrics.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "memcached.fullname" . }}-metrics + labels: + {{- include "memcached.labels" . | nindent 4 }} + app.kubernetes.io/component: metrics + {{- $annotations := merge .Values.metrics.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.metrics.service.type }} + ports: + - port: {{ .Values.metrics.service.port }} + targetPort: metrics + protocol: TCP + name: metrics + selector: + {{- include "memcached.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/memcached/templates/serviceaccount.yaml b/charts/memcached/templates/serviceaccount.yaml index 71f31ee2..37194275 100644 --- a/charts/memcached/templates/serviceaccount.yaml +++ b/charts/memcached/templates/serviceaccount.yaml @@ -6,7 +6,8 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "memcached.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} + {{- $annotations := merge .Values.serviceAccount.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/memcached/templates/servicemonitor.yaml b/charts/memcached/templates/servicemonitor.yaml new file mode 100644 index 00000000..f5abdf24 --- /dev/null +++ b/charts/memcached/templates/servicemonitor.yaml @@ -0,0 +1,46 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "memcached.fullname" . }} + labels: + {{- include "memcached.labels" . | nindent 4 }} + app.kubernetes.io/component: metrics + {{- with .Values.metrics.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ include "memcached.fullname" . }} + selector: + matchLabels: + {{- include "memcached.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics + {{- with .Values.metrics.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + path: /metrics + {{- with .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ . }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.namespaceSelector }} + namespaceSelector: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/memcached/tests/metrics_test.yaml b/charts/memcached/tests/metrics_test.yaml new file mode 100644 index 00000000..54c061f8 --- /dev/null +++ b/charts/memcached/tests/metrics_test.yaml @@ -0,0 +1,84 @@ +suite: test Memcached metrics +templates: + - deployment.yaml +set: + metrics.enabled: true + +tests: + - it: should use default values when nothing is overridden + asserts: + - equal: + path: spec.template.spec.containers[1].image + value: docker.io/prom/memcached-exporter:v0.15.4@sha256:b6763ecb3c47f2408e0398518851b7f8c5fc46232b2649f8c78a321130c54266 + - equal: + path: spec.template.spec.containers[1].imagePullPolicy + value: Always + - equal: + path: spec.template.spec.containers[1].args + value: + - --memcached.address=localhost:11211 + - --web.listen-address=:9150 + - equal: + path: spec.template.spec.containers[1].ports[0].containerPort + value: 9150 + - equal: + path: spec.template.spec.containers[1].resources + value: + limits: + memory: 64Mi + requests: + cpu: 50m + memory: 64Mi + + - it: should respect config change + set: + metrics.image.registry: my-registry.com + metrics.image.repository: prefix/prom/memcached-exporter + metrics.image.tag: 1.6.31@sha256:testdigest123 + metrics.image.pullPolicy: IfNotPresent + metrics.resources: + limits: + cpu: 150m + memory: 128Mi + requests: + cpu: 25m + memory: 32Mi + metrics.extraArgs: + - --log.level=debug + - --log.format=json + metrics.service.port: 9151 + asserts: + - equal: + path: spec.template.spec.containers[1].image + value: my-registry.com/prefix/prom/memcached-exporter:1.6.31@sha256:testdigest123 + - equal: + path: spec.template.spec.containers[1].imagePullPolicy + value: IfNotPresent + - equal: + path: spec.template.spec.containers[1].imagePullPolicy + value: IfNotPresent + - equal: + path: spec.template.spec.containers[1].resources + value: + limits: + cpu: 150m + memory: 128Mi + requests: + cpu: 25m + memory: 32Mi + - equal: + path: spec.template.spec.containers[1].resources + value: + limits: + cpu: 150m + memory: 128Mi + requests: + cpu: 25m + memory: 32Mi + - equal: + path: spec.template.spec.containers[1].args + value: + - --memcached.address=localhost:11211 + - --web.listen-address=:9151 + - --log.level=debug + - --log.format=json diff --git a/charts/memcached/tests/service_test.yaml b/charts/memcached/tests/service_test.yaml new file mode 100644 index 00000000..ac292fd0 --- /dev/null +++ b/charts/memcached/tests/service_test.yaml @@ -0,0 +1,102 @@ +suite: test Memcached services +templates: + - service.yaml +release: + name: release-name + +tests: + - it: should be a Service + asserts: + - isKind: + of: Service + - hasDocuments: + count: 1 + - equal: + path: metadata.name + value: release-name-memcached + + - it: should use default values when nothing is overridden + asserts: + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.ports[0].port + value: 11211 + + - it: should respect config change + set: + service: + type: NodePort + port: 11222 + asserts: + - equal: + path: spec.type + value: NodePort + - equal: + path: spec.ports[0].port + value: 11222 + + - it: should have a service for metrics when enabled + set: + metrics.enabled: true + asserts: + - isKind: + of: Service + - hasDocuments: + count: 2 + - equal: + path: metadata.name + value: release-name-memcached-metrics + documentIndex: 1 + + - it: should use default metrics values when nothing is overridden + set: + metrics.enabled: true + documentSelector: + path: metadata.name + value: release-name-memcached-metrics + asserts: + - equal: + path: metadata.labels["app.kubernetes.io/component"] + value: metrics + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.ports[0].port + value: 9150 + - equal: + path: spec.ports[0].name + value: metrics + + - it: should respect config change in metrics + set: + metrics.enabled: true + metrics.service: + type: LoadBalancer + port: 8080 + annotations: + service.beta.kubernetes.io/aws-load-balancer-type: "nlb" + service.beta.kubernetes.io/aws-load-balancer-internal: "true" + service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "8080" + commonAnnotations: + kubernetes.io/test: "true" + + documentSelector: + path: metadata.name + value: release-name-memcached-metrics + asserts: + - equal: + path: spec.type + value: LoadBalancer + - equal: + path: spec.ports[0].port + value: 8080 + - equal: + path: metadata.annotations + value: + service.beta.kubernetes.io/aws-load-balancer-type: "nlb" + service.beta.kubernetes.io/aws-load-balancer-internal: "true" + service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "8080" + kubernetes.io/test: "true" diff --git a/charts/memcached/tests/servicemonitor_test.yaml b/charts/memcached/tests/servicemonitor_test.yaml new file mode 100644 index 00000000..7d7f123b --- /dev/null +++ b/charts/memcached/tests/servicemonitor_test.yaml @@ -0,0 +1,110 @@ +suite: test Memcached service monitor +templates: + - servicemonitor.yaml +release: + name: release-name +set: + metrics.enabled: true + metrics.serviceMonitor.enabled: true + +tests: + - it: should be a ServiceMonitor + asserts: + - isKind: + of: ServiceMonitor + - isAPIVersion: + of: monitoring.coreos.com/v1 + - hasDocuments: + count: 1 + - equal: + path: metadata.name + value: release-name-memcached + - equal: + path: metadata.labels["app.kubernetes.io/component"] + value: metrics + + - it: should use default values when nothing is overridden + asserts: + - equal: + path: spec.jobLabel + value: release-name-memcached + - equal: + path: spec.selector.matchLabels + value: + app.kubernetes.io/name: memcached + app.kubernetes.io/instance: release-name + app.kubernetes.io/component: metrics + - contains: + path: spec.endpoints + content: + port: metrics + interval: 30s + path: /metrics + + - it: should respect config change + set: + metrics.serviceMonitor: + interval: 60s + ## @param metrics.serviceMonitor.scrapeTimeout Timeout after which the scrape is ended + scrapeTimeout: 1s + relabelings: + - sourceLabels: [ one, two ] + metricRelabelings: + - targetLabel: something + honorLabels: true + labels: + kubernetes.io/test-1: "true" + kubernetes.io/test-2: "true" + annotations: + kubernetes.io/test-annotation-1: "true" + kubernetes.io/test-annotation-2: "true" + namespaceSelector: + matchNames: + - one + - two + asserts: + - equal: + path: metadata.labels["app.kubernetes.io/instance"] + value: release-name + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: memcached + - equal: + path: metadata.labels["app.kubernetes.io/component"] + value: metrics + - equal: + path: metadata.labels["kubernetes.io/test-1"] + value: "true" + - equal: + path: metadata.labels["kubernetes.io/test-2"] + value: "true" + - equal: + path: metadata.annotations + value: + kubernetes.io/test-annotation-1: "true" + kubernetes.io/test-annotation-2: "true" + - equal: + path: spec.endpoints[0].interval + value: 60s + - equal: + path: spec.endpoints[0].scrapeTimeout + value: 1s + - equal: + path: spec.endpoints[0].honorLabels + value: true + - equal: + path: spec.endpoints[0].relabelings + value: + - sourceLabels: + - one + - two + - equal: + path: spec.endpoints[0].metricRelabelings + value: + - targetLabel: something + - equal: + path: spec.namespaceSelector + value: + matchNames: + - one + - two diff --git a/charts/memcached/values.schema.json b/charts/memcached/values.schema.json index 460acfe7..8a042301 100644 --- a/charts/memcached/values.schema.json +++ b/charts/memcached/values.schema.json @@ -1,148 +1,357 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "Memcached Helm Chart Values Schema", - "description": "Schema for Memcached Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker image registry" - }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": [ - "name" - ] - } - } - } - }, - "image": { - "type": "object", - "title": "Memcached image configuration", - "description": "Configuration for Memcached container image", - "properties": { - "registry": { - "type": "string", - "title": "Memcached Image Registry", - "description": "Memcached image registry" - }, - "repository": { - "type": "string", - "title": "Memcached Image Repository", - "description": "Memcached image repository" - }, - "tag": { - "type": "string", - "title": "Memcached Image Tag", - "description": "Memcached image tag" - }, - "pullPolicy": { - "type": "string", - "title": "Image Pull Policy", - "description": "Image pull policy", - "enum": [ - "Always", - "IfNotPresent", - "Never" - ] - } - } - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of Memcached replicas", - "minimum": 1 - }, - "service": { - "type": "object", - "title": "Service configuration", - "description": "Kubernetes service configuration", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "Kubernetes service type", - "enum": [ - "ClusterIP", - "NodePort", - "LoadBalancer" - ] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "Service port", - "minimum": 1, - "maximum": 65535 - } - } - }, - "config": { - "type": "object", - "title": "Memcached configuration", - "description": "Memcached configuration options", - "properties": { - "memoryLimit": { - "type": "integer", - "title": "Memory Limit", - "description": "Maximum amount of memory to use for cache (in MB)", - "minimum": 1 - }, - "maxConnections": { - "type": "integer", - "title": "Max Connections", - "description": "Maximum number of simultaneous connections", - "minimum": 1 - }, - "verbosity": { - "type": "integer", - "title": "Verbosity", - "description": "Verbosity level", - "minimum": 0, - "maximum": 2 - }, - "extraArgs": { - "type": "array", - "title": "Extra Arguments", - "description": "Additional command-line arguments", - "items": { + "extraArgs": { + "type": "array" + }, + "maxConnections": { + "type": "integer" + }, + "memoryLimit": { + "type": "integer" + }, + "verbosity": { + "type": "integer" + } + } + }, + "configMap": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "data": { + "type": "object" + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } + } + }, + "extraEnvVars": { + "type": "array" + }, + "extraObjects": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "fullnameOverride": { "type": "string" - } + }, + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "extraArgs": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "labels": { + "type": "object" + }, + "metricRelabelings": { + "type": "array" + }, + "namespaceSelector": { + "type": "object" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + } + } + } + } + }, + "nameOverride": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "pdb": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "maxUnavailable": { + "type": "string" + }, + "minAvailable": { + "type": "string" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "tolerations": { + "type": "array" } - } - }, - "resources": { - "type": "object", - "title": "Resource configuration", - "description": "Pod resource configuration" - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } -} \ No newline at end of file +} diff --git a/charts/memcached/values.yaml b/charts/memcached/values.yaml index bf2429d1..7360ae7e 100644 --- a/charts/memcached/values.yaml +++ b/charts/memcached/values.yaml @@ -15,6 +15,12 @@ commonLabels: {} ## @param commonAnnotations Annotations to add to all deployed objects commonAnnotations: {} +## @param podAnnotations Annotations to add to the pods created by the deployment +podAnnotations: {} + +## @param podLabels Labels to add to the pods created by the deployment +podLabels: {} + ## @section Memcached image parameters image: ## @param image.registry Memcached image registry @@ -22,7 +28,7 @@ image: ## @param image.repository Memcached image repository repository: memcached ## @param image.tag Memcached image tag - tag: "1.6.39@sha256:157c563eef6954ac0bc583c36def96d8ed2d3b3c5b37214f27d210ac53942386" + tag: "1.6.39@sha256:050de63e6c082df85f93ffed9c388004b3c6257a06f1904e8628a6f87658eb99" ## @param image.pullPolicy Memcached image pull policy pullPolicy: Always @@ -103,6 +109,15 @@ tolerations: [] ## @param affinity Affinity rules for pod assignment affinity: {} +## @section Pod Disruption Budget parameters +pdb: + ## @param pdb.create Enable/disable a Pod Disruption Budget creation + create: false + ## @param pdb.minAvailable Minimum number/percentage of pods that should remain scheduled + minAvailable: "" + ## @param pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. + maxUnavailable: "" + containerSecurityContext: ## @param containerSecurityContext.runAsUser User ID to run the container runAsUser: 11211 @@ -144,10 +159,15 @@ readinessProbe: ## @param readinessProbe.successThreshold Number of successes to mark probe as successful successThreshold: 1 -## @param extraEnv Additional environment variables to set -extraEnv: [] -# - name: EXTRA_VAR -# value: "extra_value" +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraVolumes Additional volumes to add to the pod extraVolumes: [] @@ -157,3 +177,59 @@ extraVolumeMounts: [] ## @param extraObjects Array of extra objects to deploy with the release extraObjects: [] + + +## @section Metrics parameters +## Prometheus metrics configuration +metrics: + ## @param metrics.enabled Start a sidecar prometheus exporter to expose Memcached metrics + enabled: false + ## @param metrics.image.registry Memcached exporter image registry + ## @param metrics.image.repository Memcached exporter image repository + ## @param metrics.image.tag Memcached exporter image tag + ## @param metrics.image.pullPolicy Memcached exporter image pull policy + image: + registry: docker.io + repository: prom/memcached-exporter + tag: "v0.15.4@sha256:b6763ecb3c47f2408e0398518851b7f8c5fc46232b2649f8c78a321130c54266" + pullPolicy: Always + ## @param metrics.resources Resource limits and requests for metrics container + resources: + limits: + memory: 64Mi + requests: + cpu: 50m + memory: 64Mi + ## @param metrics.extraArgs Extra arguments for Memcached exporter, for example: + ## extraArgs: + ## - --log.level=debug + ## - --log.format=json + extraArgs: [] + ## Metrics service configuration + service: + ## @param metrics.service.type Metrics service type + type: ClusterIP + ## @param metrics.service.port Metrics service port + port: 9150 + ## @param metrics.service.annotations Additional custom annotations for Metrics service + annotations: {} + ## Prometheus ServiceMonitor configuration + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator + enabled: false + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped + interval: 30s + ## @param metrics.serviceMonitor.scrapeTimeout Timeout after which the scrape is ended + scrapeTimeout: "" + ## @param metrics.serviceMonitor.relabelings Specify additional relabeling of metrics + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings Specify additional metric relabeling of metrics + metricRelabelings: [] + ## @param metrics.serviceMonitor.honorLabels Honor metrics labels + honorLabels: false + ## @param metrics.serviceMonitor.labels Additional service monitor labels + labels: {} + ## @param metrics.serviceMonitor.annotations Additional custom annotations for the ServiceMonitor + annotations: {} + ## @param metrics.serviceMonitor.namespaceSelector Namespace selector for ServiceMonitor + namespaceSelector: {} diff --git a/charts/minio/CHANGELOG.md b/charts/minio/CHANGELOG.md index 9299a528..a8d90baf 100644 --- a/charts/minio/CHANGELOG.md +++ b/charts/minio/CHANGELOG.md @@ -1,5 +1,104 @@ # Changelog -## 0.3.0 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) \ No newline at end of file +## 0.5.5 (2025-11-02) + +* Add NodePort support for API and Console in Service configuration (#527) ([57b84d8](https://github.com/CloudPirates-io/helm-charts/commit/57b84d8)) +* chore: update CHANGELOG.md for merged changes ([c593bd8](https://github.com/CloudPirates-io/helm-charts/commit/c593bd8)) +* chore: update CHANGELOG.md for merged changes ([5cd1a41](https://github.com/CloudPirates-io/helm-charts/commit/5cd1a41)) + +## 0.5.4 (2025-10-27) + +* Remove securitycontext on empty obejct (#474) ([3c288c8](https://github.com/CloudPirates-io/helm-charts/commit/3c288c8)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.5.3 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.5.2 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([9af0a8e](https://github.com/CloudPirates-io/helm-charts/commit/9af0a8e)) +* chore: update CHANGELOG.md for merged changes ([de994a7](https://github.com/CloudPirates-io/helm-charts/commit/de994a7)) + +## 0.5.1 (2025-10-17) + +* [minio] Fix bucketname trimming whitespaces in MinIO post-job configuration script. (#406) ([bf250e2](https://github.com/CloudPirates-io/helm-charts/commit/bf250e2)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.5.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.4.1 (2025-10-13) + + +## 0.4.0 (2025-10-09) + +* add auto bucket creation through k8s job and option to create ServiceAccount for Deployment (#288) ([47d3947](https://github.com/CloudPirates-io/helm-charts/commit/47d3947)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) +* [minio, mongodb, postgres, timescaledb] Update securityContext to containerSecurityContext in the values schema (#213) ([8a4003f](https://github.com/CloudPirates-io/helm-charts/commit/8a4003f)) + +## 0.3.0 (2025-10-02) + +* make minio run on openshift (#203) ([18c7be5](https://github.com/CloudPirates-io/helm-charts/commit/18c7be5)) + +## 0.2.4 (2025-09-30) + +* add more configuration options for the minio server (#189) ([8066d07](https://github.com/CloudPirates-io/helm-charts/commit/8066d07)) + +## 0.2.3 (2025-09-15) + +* Update CHANGELOG.md ([55a987f](https://github.com/CloudPirates-io/helm-charts/commit/55a987f)) +* bump verion to 0.2.3 ([af6beca](https://github.com/CloudPirates-io/helm-charts/commit/af6beca)) +* set strategy to recreate in deployment ([6e01f97](https://github.com/CloudPirates-io/helm-charts/commit/6e01f97)) + +## 0.2.2 (2025-09-15) + +* Update CHANGELOG.md ([f31d5a5](https://github.com/CloudPirates-io/helm-charts/commit/f31d5a5)) +* update minio README.md ([cbca20c](https://github.com/CloudPirates-io/helm-charts/commit/cbca20c)) +* bump version to 0.2.2 ([afaf2d1](https://github.com/CloudPirates-io/helm-charts/commit/afaf2d1)) +* add option to use cpu-v1 image ([91bfd29](https://github.com/CloudPirates-io/helm-charts/commit/91bfd29)) + +## 0.2.1 (2025-09-08) + +* Update CHANGELOG.md ([bb8e730](https://github.com/CloudPirates-io/helm-charts/commit/bb8e730)) +* Update appVersion ([5c23cb1](https://github.com/CloudPirates-io/helm-charts/commit/5c23cb1)) +* Update CHANGELOG.md ([82fe11f](https://github.com/CloudPirates-io/helm-charts/commit/82fe11f)) +* Upgrade minio to latest stable ([94ab830](https://github.com/CloudPirates-io/helm-charts/commit/94ab830)) +* revert 3 ([d8ced5c](https://github.com/CloudPirates-io/helm-charts/commit/d8ced5c)) +* revert 2 ([b64c81d](https://github.com/CloudPirates-io/helm-charts/commit/b64c81d)) +* Update CHANGELOG.md ([808cae0](https://github.com/CloudPirates-io/helm-charts/commit/808cae0)) +* revert ([ba71354](https://github.com/CloudPirates-io/helm-charts/commit/ba71354)) +* Upgrade minio to latest stable ([b199ea4](https://github.com/CloudPirates-io/helm-charts/commit/b199ea4)) + +## 0.2.0 (2025-09-02) + +* bump all chart versions for new extraObjects feature ([aaa57f9](https://github.com/CloudPirates-io/helm-charts/commit/aaa57f9)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.1.8 (2025-08-27) + +* Fix values.yaml / Chart.yaml linting issues ([043c7e0](https://github.com/CloudPirates-io/helm-charts/commit/043c7e0)) +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.1.7 (2025-08-26) + +* Initial tagged release diff --git a/charts/minio/Chart.lock b/charts/minio/Chart.lock index e0e6255f..cb566e2d 100644 --- a/charts/minio/Chart.lock +++ b/charts/minio/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-10-01T22:07:26.882147+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:31.45206+02:00" diff --git a/charts/minio/Chart.yaml b/charts/minio/Chart.yaml index 936ea106..4577de09 100644 --- a/charts/minio/Chart.yaml +++ b/charts/minio/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: minio description: High Performance Object Storage compatible with Amazon S3 APIs type: application -version: 0.4.0 +version: 0.5.5 appVersion: "2025.09.07" keywords: - minio @@ -10,14 +10,38 @@ keywords: - s3 - storage - cloud-native -home: https://www.cloudpirates.io +home: https://min.io sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/minio + - https://github.com/minio/minio maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/5d3310f00d/minio-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: storage + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: MinIO + url: https://min.io + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/minio + - name: Application + url: https://github.com/minio/minio + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Add NodePort support for API and Console in Service configuration (#527)" + links: + - name: "Commit 57b84d8" + url: "https://github.com/CloudPirates-io/helm-charts/commit/57b84d8" diff --git a/charts/minio/README.md b/charts/minio/README.md index e42954ab..b8dabc00 100644 --- a/charts/minio/README.md +++ b/charts/minio/README.md @@ -4,7 +4,8 @@ # MinIO -A Helm chart for MinIO - High Performance Object Storage compatible with Amazon S3 APIs. MinIO is a high-performance, distributed object storage server designed for large-scale data infrastructure. +A Helm chart for MinIO - High Performance Object Storage compatible with Amazon S3 APIs. MinIO is a high-performance, +distributed object storage server designed for large-scale data infrastructure. ## Prerequisites @@ -32,7 +33,8 @@ Or install directly from the local chart: helm install my-minio ./charts/minio ``` -The command deploys MinIO on the Kubernetes cluster in the default configuration. The [Configuration](#configuration) section lists the parameters that can be configured during installation. +The command deploys MinIO on the Kubernetes cluster in the default configuration. The [Configuration](#configuration) +section lists the parameters that can be configured during installation. ## Uninstalling the Chart @@ -70,14 +72,14 @@ The following table lists the configurable parameters of the MinIO chart and the ### Global parameters | Parameter | Description | Default | -| ------------------------- | ----------------------------------------------- | ------- | +|---------------------------|-------------------------------------------------|---------| | `global.imageRegistry` | Global Docker image registry | `""` | | `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | ### MinIO image configuration | Parameter | Description | Default | -| ----------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +|-------------------------|-----------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------| | `image.registry` | MinIO image registry | `docker.io` | | `image.repository` | MinIO image repository | `minio/minio` | | `image.tag` | MinIO image tag (immutable tags are recommended) | `"RELEASE.2024-08-17T01-24-54Z"` | @@ -88,7 +90,7 @@ The following table lists the configurable parameters of the MinIO chart and the ### MinIO Authentication | Parameter | Description | Default | -| -------------------------------- | -------------------------------------------------------------------- | ------------ | +|----------------------------------|----------------------------------------------------------------------|--------------| | `auth.rootUser` | MinIO root username | `"admin"` | | `auth.rootPassword` | MinIO root password. If not set, a random password will be generated | `""` | | `auth.existingSecret` | Name of existing secret containing MinIO credentials | `""` | @@ -98,7 +100,7 @@ The following table lists the configurable parameters of the MinIO chart and the ### MinIO configuration | Parameter | Description | Default | -| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +|------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------| | `config.region` | MinIO server default region | `""` | | `config.browserEnabled` | Enable MinIO web browser | `true` | | `config.domain` | MinIO server domain | `""` | @@ -116,7 +118,7 @@ The following table lists the configurable parameters of the MinIO chart and the ### Deployment configuration | Parameter | Description | Default | -| ------------------ | ------------------------------------------- | ------- | +|--------------------|---------------------------------------------|---------| | `replicaCount` | Number of MinIO replicas to deploy | `1` | | `nameOverride` | String to partially override minio.fullname | `""` | | `fullnameOverride` | String to fully override minio.fullname | `""` | @@ -124,15 +126,15 @@ The following table lists the configurable parameters of the MinIO chart and the ### Pod annotations and labels | Parameter | Description | Default | -| ---------------- | ------------------------------------- | ------- | +|------------------|---------------------------------------|---------| | `podAnnotations` | Map of annotations to add to the pods | `{}` | | `podLabels` | Map of labels to add to the pods | `{}` | ### Security Context -| Parameter | Description | Default | -| ------------------------------------------ | ------------------------------------------------- | --------- | -| `podSecurityContext.fsGroup` | Group ID for the volumes of the pod | `1000` | +| Parameter | Description | Default | +|-----------------------------------------------------|---------------------------------------------------|-----------| +| `podSecurityContext.fsGroup` | Group ID for the volumes of the pod | `1000` | | `containerSecurityContext.allowPrivilegeEscalation` | Enable container privilege escalation | `false` | | `containerSecurityContext.runAsNonRoot` | Configure the container to run as a non-root user | `true` | | `containerSecurityContext.runAsUser` | User ID for the MinIO container | `1000` | @@ -142,17 +144,19 @@ The following table lists the configurable parameters of the MinIO chart and the ### Service configuration -| Parameter | Description | Default | -| --------------------- | -------------------------- | ----------- | -| `service.type` | MinIO service type | `ClusterIP` | -| `service.port` | MinIO service port | `9000` | -| `service.consolePort` | MinIO console service port | `9090` | -| `service.annotations` | Service annotations | `{}` | +| Parameter | Description | Default | +|-----------------------------|----------------------------|-------------| +| `service.type` | MinIO service type | `ClusterIP` | +| `service.port` | MinIO service port | `9000` | +| `service.consolePort` | MinIO console service port | `9090` | +| `service.annotations` | Service annotations | `{}` | +| `service.nodePorts.api` | Service api node port | `""` | +| `service.nodePorts.console` | Service console node port | `""` | ### Ingress configuration | Parameter | Description | Default | -| ------------------------------------ | ------------------------------------------------------- | ------------- | +|--------------------------------------|---------------------------------------------------------|---------------| | `ingress.enabled` | Enable ingress record generation for MinIO | `false` | | `ingress.className` | IngressClass that will be used to implement the Ingress | `""` | | `ingress.annotations` | Additional annotations for the Ingress resource | `{}` | @@ -164,7 +168,7 @@ The following table lists the configurable parameters of the MinIO chart and the ### Console Ingress configuration | Parameter | Description | Default | -| ------------------------------------------- | ------------------------------------------------------- | --------------------- | +|---------------------------------------------|---------------------------------------------------------|-----------------------| | `consoleIngress.enabled` | Enable ingress record generation for MinIO Console | `false` | | `consoleIngress.className` | IngressClass that will be used to implement the Ingress | `""` | | `consoleIngress.annotations` | Additional annotations for the Console Ingress resource | `{}` | @@ -176,13 +180,13 @@ The following table lists the configurable parameters of the MinIO chart and the ### Resources | Parameter | Description | Default | -| ----------- | ------------------------------------------- | ------- | +|-------------|---------------------------------------------|---------| | `resources` | The resources to allocate for the container | `{}` | ### Persistence | Parameter | Description | Default | -| --------------------------- | -------------------------------------------------- | ------------------- | +|-----------------------------|----------------------------------------------------|---------------------| | `persistence.enabled` | Enable persistence using Persistent Volume Claims | `true` | | `persistence.storageClass` | Persistent Volume storage class | `""` | | `persistence.annotations` | Persistent Volume Claim annotations | `{}` | @@ -193,7 +197,7 @@ The following table lists the configurable parameters of the MinIO chart and the ### Liveness and readiness probes | Parameter | Description | Default | -| ------------------------------------ | ----------------------------------------- | ------- | +|--------------------------------------|-------------------------------------------|---------| | `livenessProbe.enabled` | Enable livenessProbe on MinIO containers | `true` | | `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `30` | | `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | @@ -216,7 +220,7 @@ The following table lists the configurable parameters of the MinIO chart and the ### Node Selection | Parameter | Description | Default | -| -------------- | ------------------------------------ | ------- | +|----------------|--------------------------------------|---------| | `nodeSelector` | Node labels for pod assignment | `{}` | | `tolerations` | Toleration labels for pod assignment | `[]` | | `affinity` | Affinity settings for pod assignment | `{}` | @@ -224,14 +228,17 @@ The following table lists the configurable parameters of the MinIO chart and the ### Extra Configuration Parameters | Parameter | Description | Default | -| -------------- | ----------------------------------------------------------------------- | ------- | +|----------------|-------------------------------------------------------------------------|---------| | `extraObjects` | A list of additional Kubernetes objects to deploy alongside the release | `[]` | #### Extra Objects -You can use the `extraObjects` array to deploy additional Kubernetes resources (such as NetworkPolicies, ConfigMaps, etc.) alongside the release. This is useful for customizing your deployment with extra manifests that are not covered by the default chart options. +You can use the `extraObjects` array to deploy additional Kubernetes resources (such as NetworkPolicies, ConfigMaps, +etc.) alongside the release. This is useful for customizing your deployment with extra manifests that are not covered by +the default chart options. -**Helm templating is supported in any field, but all template expressions must be quoted.** For example, to use the release namespace, write `namespace: "{{ .Release.Namespace }}"`. +**Helm templating is supported in any field, but all template expressions must be quoted.** For example, to use the +release namespace, write `namespace: "{{ .Release.Namespace }}"`. **Example: Deploy a NetworkPolicy with templating** @@ -243,7 +250,7 @@ extraObjects: name: allow-dns namespace: "{{ .Release.Namespace }}" spec: - podSelector: {} + podSelector: { } policyTypes: - Egress egress: @@ -261,7 +268,8 @@ extraObjects: protocol: TCP ``` -All objects in `extraObjects` will be rendered and deployed with the release. You can use any valid Kubernetes manifest, and reference Helm values or built-in objects as needed (just remember to quote template expressions). +All objects in `extraObjects` will be rendered and deployed with the release. You can use any valid Kubernetes manifest, +and reference Helm values or built-in objects as needed (just remember to quote template expressions). ## Examples @@ -329,14 +337,17 @@ helm install my-minio ./charts/minio -f values-production.yaml ### Exposing a Bucket Publicly (โ€œCDN Serverโ€ Setup) -You can make a MinIO bucket publicly accessible (e.g. as a CDN endpoint) using Ingress and MinIO's CLI tool (`mc`). Below is an example configuration +You can make a MinIO bucket publicly accessible (e.g. as a CDN endpoint) using Ingress and MinIO's CLI tool (`mc`). +Below is an example configuration and the commands needed to set this up. #### 1. Install the Helm Chart with Public Ingress -Ensure the **Ingress controller** (like [ingress-nginx](https://kubernetes.github.io/ingress-nginx/)) is deployed in your cluster. +Ensure the **Ingress controller** (like [ingress-nginx](https://kubernetes.github.io/ingress-nginx/)) is deployed in +your cluster. -Example `values.yaml` snippet for Helm install (replace `cdn.my-domain.local` and `my-bucket-name` with your own values): +Example `values.yaml` snippet for Helm install (replace `cdn.my-domain.local` and `my-bucket-name` with your own +values): ```yaml ingress: @@ -369,7 +380,8 @@ helm install my-minio -f values.yaml #### 2. Configure Your Bucket for Public Access -You need the [MinIO Client (`mc`)](https://min.io/docs/minio/linux/reference/minio-mc.html) to manage bucket policies. You can access `mc` directly in the MinIO pod: +You need the [MinIO Client (`mc`)](https://min.io/docs/minio/linux/reference/minio-mc.html) to manage bucket policies. +You can access `mc` directly in the MinIO pod: ```bash kubectl exec -it -n -- bash @@ -389,7 +401,8 @@ Inside the pod, configure as follows (replace `my-bucket-name` as needed): mc mb local/my-bucket-name ``` -3. Create a custom policy in `/tmp/policy.json` to only allow `GetObject`, alternatively use the predefined `download` policy: +3. Create a custom policy in `/tmp/policy.json` to only allow `GetObject`, alternatively use the predefined `download` + policy: ```bash echo ' { @@ -423,8 +436,8 @@ Inside the pod, configure as follows (replace `my-bucket-name` as needed): ``` **Summary:** -After these steps, your bucket (`my-bucket-name`) will be accessible via `https://cdn.my-domain.local/` (if using TLS), and is publicly readable. - +After these steps, your bucket (`my-bucket-name`) will be accessible via `https://cdn.my-domain.local/` (if +using TLS), and is publicly readable. ### Using Existing Secret for Credentials @@ -473,19 +486,19 @@ kubectl get secret my-minio -o jsonpath="{.data.root-password}" | base64 --decod 1. **Pod fails to start with permission errors** - - Ensure your storage class supports the required access modes - - Check if security contexts are compatible with your cluster policies + - Ensure your storage class supports the required access modes + - Check if security contexts are compatible with your cluster policies 2. **Cannot access MinIO console** - - Verify the console service is running: `kubectl get svc` - - Check if ingress is properly configured - - Ensure firewall rules allow access to port 9090 + - Verify the console service is running: `kubectl get svc` + - Check if ingress is properly configured + - Ensure firewall rules allow access to port 9090 3. **Persistent volume not mounting** - - Verify storage class exists: `kubectl get storageclass` - - Check PVC status: `kubectl get pvc` - - Review pod events: `kubectl describe pod ` + - Verify storage class exists: `kubectl get storageclass` + - Check PVC status: `kubectl get pvc` + - Review pod events: `kubectl describe pod ` ### Getting Support diff --git a/charts/minio/templates/_helpers.tpl b/charts/minio/templates/_helpers.tpl index 776c36d0..705293c6 100644 --- a/charts/minio/templates/_helpers.tpl +++ b/charts/minio/templates/_helpers.tpl @@ -2,7 +2,7 @@ Expand the name of the chart. */}} {{- define "minio.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* @@ -11,21 +11,21 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "minio.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "minio.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "minio.labels" -}} -{{- include "common.labels" . -}} +{{- include "cloudpirates.labels" . -}} {{- end }} {{/* @@ -41,7 +41,7 @@ Common annotations Selector labels */}} {{- define "minio.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* @@ -63,7 +63,7 @@ Return the proper MinIO image name {{- printf "%s:%s" $repositoryName $tag -}} {{- end -}} {{- else }} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{- end }} @@ -71,7 +71,7 @@ Return the proper MinIO image name Return the proper Docker Image Registry Secret Names */}} {{- define "minio.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* @@ -79,7 +79,7 @@ Return MinIO credentials secret name */}} {{- define "minio.secretName" -}} {{- if .Values.auth.existingSecret -}} - {{- .Values.auth.existingSecret -}} + {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) -}} {{- else -}} {{- include "minio.fullname" . -}} {{- end -}} diff --git a/charts/minio/templates/deployment.yaml b/charts/minio/templates/deployment.yaml index 781a301d..a04d3d5c 100644 --- a/charts/minio/templates/deployment.yaml +++ b/charts/minio/templates/deployment.yaml @@ -33,10 +33,14 @@ spec: {{ . | nindent 6 }} {{- end }} serviceAccountName: {{ template "minio.serviceAccountName" . }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + {{- if .Values.podSecurityContext }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} + {{- end }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + {{- if .Values.containerSecurityContext }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + {{- end }} image: {{ include "minio.image" . }} imagePullPolicy: {{ .Values.image.imagePullPolicy }} command: ["/bin/sh"] diff --git a/charts/minio/templates/extraobjects.yaml b/charts/minio/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/minio/templates/extraobjects.yaml +++ b/charts/minio/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/minio/templates/post-job-configmap.yaml b/charts/minio/templates/post-job-configmap.yaml index 55c9daf6..947d6030 100644 --- a/charts/minio/templates/post-job-configmap.yaml +++ b/charts/minio/templates/post-job-configmap.yaml @@ -52,6 +52,7 @@ data: return 1 fi echo "MinIO is ready!" + sleep 2 } ######################## @@ -77,8 +78,10 @@ data: bucket_name=$(echo "$b" | cut -d':' -f1) bucket_policy=$(echo "$b" | cut -s -d':' -f2) - bucket_name=$(echo "$bucket_name" | xargs) - + # trim whitespaces (xargs and sed are not installed) + set -- $bucket_name + bucket_name="$1" + if [ -z "$bucket_name" ]; then continue fi diff --git a/charts/minio/templates/post-job.yaml b/charts/minio/templates/post-job.yaml index 97b65862..0c3c4778 100644 --- a/charts/minio/templates/post-job.yaml +++ b/charts/minio/templates/post-job.yaml @@ -6,10 +6,10 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "minio.labels" . | nindent 4 }} - annotations: - {{- if .Values.commonAnnotations }} - {{- include "minio.annotations" . | nindent 4 }} - {{- end }} + {{- with (include "minio.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} spec: ttlSecondsAfterFinished: 600 activeDeadlineSeconds: 300 @@ -26,7 +26,7 @@ spec: {{ . | nindent 6 }} {{- end }} restartPolicy: OnFailure - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} containers: - name: post-job image: {{ include "minio.image" . }} @@ -49,7 +49,7 @@ spec: - name: tmp mountPath: /tmp securityContext: - {{- $securityContext := include "common.renderContainerSecurityContext" . | fromYaml }} + {{- $securityContext := include "cloudpirates.renderContainerSecurityContext" . | fromYaml }} {{- $_ := set $securityContext "readOnlyRootFilesystem" false }} {{- toYaml $securityContext | nindent 12 }} volumes: diff --git a/charts/minio/templates/service.yaml b/charts/minio/templates/service.yaml index e40dad2a..33e80f49 100644 --- a/charts/minio/templates/service.yaml +++ b/charts/minio/templates/service.yaml @@ -16,8 +16,18 @@ spec: - port: {{ .Values.service.port }} protocol: TCP name: minio + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.api)) }} + nodePort: {{ .Values.service.nodePorts.api }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} - port: {{ .Values.service.consolePort }} protocol: TCP name: console + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.console)) }} + nodePort: {{ .Values.service.nodePorts.console }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} selector: - {{- include "minio.selectorLabels" . | nindent 4 }} \ No newline at end of file + {{- include "minio.selectorLabels" . | nindent 4 }} diff --git a/charts/minio/values.schema.json b/charts/minio/values.schema.json index 2a62f7bf..27f0db37 100644 --- a/charts/minio/values.schema.json +++ b/charts/minio/values.schema.json @@ -1,752 +1,409 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "MinIO Helm Chart Values Schema", - "description": "Schema for MinIO Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global Parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker image registry" + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "image": { - "type": "object", - "title": "MinIO Image Configuration", - "description": "MinIO container image configuration", - "properties": { - "registry": { - "type": "string", - "title": "MinIO Image Registry", - "description": "MinIO image registry" - }, - "repository": { - "type": "string", - "title": "MinIO Image Repository", - "description": "MinIO image repository" - }, - "tag": { - "type": "string", - "title": "MinIO Image Tag", - "description": "MinIO image tag with digest" - }, - "imagePullPolicy": { - "type": "string", - "title": "MinIO Image Pull Policy", - "description": "MinIO image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] - } - } - }, - "auth": { - "type": "object", - "title": "MinIO Authentication", - "description": "MinIO Authentication configuration", - "properties": { - "rootUser": { - "type": "string", - "title": "MinIO Root Username", - "description": "MinIO root username" - }, - "rootPassword": { - "type": "string", - "title": "MinIO Root Password", - "description": "MinIO root password. If not set, a random password will be generated" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret containing MinIO credentials" - }, - "existingSecretUserKey": { - "type": "string", - "title": "Existing Secret User Key", - "description": "Key in existing secret containing username" - }, - "existingSecretPasswordKey": { - "type": "string", - "title": "Existing Secret Password Key", - "description": "Key in existing secret containing password" - } - } - }, - "config": { - "type": "object", - "title": "MinIO Configuration", - "description": "MinIO configuration parameters", - "properties": { - "region": { - "type": "string", - "title": "MinIO Server Region", - "description": "MinIO server default region" - }, - "browserEnabled": { - "type": "boolean", - "title": "Browser Enabled", - "description": "Enable MinIO web browser" - }, - "domain": { - "type": "string", - "title": "MinIO Server Domain", - "description": "MinIO server domain" - }, - "serverUrl": { - "type": "string", - "title": "MinIO Server URL", - "description": "MinIO server URL for console" - }, - "minioOpts": { - "type": "string", - "title": "MinIO Server Options", - "description": "String of parameteres to use when starting the MinIO Server" - }, - "minioVolumes": { - "type": "string", - "title": "MinIO Volume directories", - "description": "The directories or drives the minio server uses as the storage backend" - }, - "minioConfigEnvFile": { - "type": "string", - "title": "MinIO Config Environment File", - "description": "Path to environment file for MinIO to load variables from" - }, - "minioScannerSpeed": { - "type": "string", - "enum": ["fastest", "fast", "default", "slow", "slowest", ""], - "title": "MinIO Scanner Speed", - "description": "Manage the maximum wait period for the scanner when balancing MinIO read/write performance to scanner processes" - }, - "minioCompressionEnabled": { - "type": "string", - "enum": ["on", "off", ""], - "title": "MinIO Compression Enabled", - "description": "Set to on to enable data compression for new objects" - }, - "minioCompressionAllowEncryption": { - "type": "string", - "enum": ["on", "off", ""], - "title": "MinIO Compression Allow Encryption", - "description": "Set to on to encrypt objects after compressing them" + "existingSecret": { + "type": "string" + }, + "existingSecretPasswordKey": { + "type": "string" + }, + "existingSecretUserKey": { + "type": "string" + }, + "rootPassword": { + "type": "string" + }, + "rootUser": { + "type": "string" + } + } }, - "minioCompressionExtensions": { - "type": "string", - "title": "MinIO Compression Extentions", - "description": "Comma-separated list of the file extensions to compress" + "commonAnnotations": { + "type": "object" }, - "minioCompressionMimeTypes": { - "type": "string", - "title": "MinIO Compression MimeTypes", - "description": "Comma-separated list of the MIME types to compress" + "commonLabels": { + "type": "object" }, - "extraEnvVars": { - "type": "array", - "title": "Extra Environment Variables", - "description": "Extra environment variables to be set on MinIO containers", - "items": { + "config": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Variable Name", - "description": "Environment variable name" - }, - "value": { - "type": "string", - "title": "Variable Value", - "description": "Environment variable value" - } - }, - "required": ["name"] - } - } - } - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of MinIO replicas to deploy", - "minimum": 1 - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override minio.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override minio.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "podAnnotations": { - "type": "object", - "title": "Pod Annotations", - "description": "Pod annotations and labels", - "additionalProperties": { - "type": "string" - } - }, - "podLabels": { - "type": "object", - "title": "Pod Labels", - "description": "Pod labels", - "additionalProperties": { - "type": "string" - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "Security Context configuration", - "properties": { - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Group ID for the volumes of the pod", - "minimum": 0 - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "Security Context", - "description": "Container security context", - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Enable container privilege escalation" - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Configure the container to run as a non-root user" - }, - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID for the MinIO container", - "minimum": 0 - }, - "runAsGroup": { - "type": "integer", - "title": "Run As Group", - "description": "Group ID for the MinIO container", - "minimum": 0 - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "title": "Read-Only Root Filesystem", - "description": "Mount container root filesystem as read-only" - }, - "capabilities": { - "type": "object", - "title": "Capabilities", - "description": "Linux capabilities configuration", - "properties": { - "drop": { - "type": "array", - "title": "Drop Capabilities", - "description": "Linux capabilities to be dropped", - "items": { - "type": "string" - } + "browserEnabled": { + "type": "boolean" + }, + "domain": { + "type": "string" + }, + "extraEnvVars": { + "type": "array" + }, + "minioCompressionAllowEncryption": { + "type": "string" + }, + "minioCompressionEnabled": { + "type": "string" + }, + "minioCompressionExtensions": { + "type": "string" + }, + "minioCompressionMimeTypes": { + "type": "string" + }, + "minioConfigEnvFile": { + "type": "string" + }, + "minioOpts": { + "type": "string" + }, + "minioScannerSpeed": { + "type": "string" + }, + "minioVolumes": { + "type": "string" + }, + "region": { + "type": "string" + }, + "serverUrl": { + "type": "string" + } } - } - } - } - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "Service configuration parameters", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "MinIO service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "MinIO service port", - "minimum": 1, - "maximum": 65535 }, - "consolePort": { - "type": "integer", - "title": "Console Service Port", - "description": "MinIO console service port", - "minimum": 1, - "maximum": 65535 - }, - "annotations": { - "type": "object", - "title": "Service Annotations", - "description": "Service annotations", - "additionalProperties": { - "type": "string" - } - } - } - }, - "ingress": { - "type": "object", - "title": "Ingress Configuration", - "description": "Ingress configuration parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Ingress", - "description": "Enable ingress record generation for MinIO" - }, - "className": { - "type": "string", - "title": "Ingress Class Name", - "description": "IngressClass that will be used to implement the Ingress" - }, - "annotations": { - "type": "object", - "title": "Ingress Annotations", - "description": "Additional annotations for the Ingress resource", - "additionalProperties": { - "type": "string" - } + "consoleIngress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } + } }, - "hosts": { - "type": "array", - "title": "Ingress Hosts", - "description": "Ingress hosts configuration", - "items": { + "containerSecurityContext": { "type": "object", "properties": { - "host": { - "type": "string", - "title": "Host", - "description": "Hostname for MinIO ingress" - }, - "paths": { - "type": "array", - "title": "Paths", - "description": "Paths configuration for the host", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "title": "Path", - "description": "Path for MinIO ingress" - }, - "pathType": { - "type": "string", - "title": "Path Type", - "description": "Path type for MinIO ingress", - "enum": ["Exact", "Prefix", "ImplementationSpecific"] + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } } - } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" } - } } - } }, - "tls": { - "type": "array", - "title": "TLS Configuration", - "description": "TLS configuration for MinIO ingress", - "items": { - "type": "object" - } - } - } - }, - "consoleIngress": { - "type": "object", - "title": "Console Ingress Configuration", - "description": "Console Ingress configuration parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Console Ingress", - "description": "Enable ingress record generation for MinIO Console" + "defaultBuckets": { + "type": "string" }, - "className": { - "type": "string", - "title": "Console Ingress Class Name", - "description": "IngressClass that will be used to implement the Console Ingress" + "extraObjects": { + "type": "array" }, - "annotations": { - "type": "object", - "title": "Console Ingress Annotations", - "description": "Additional annotations for the Console Ingress resource", - "additionalProperties": { + "fullnameOverride": { "type": "string" - } }, - "hosts": { - "type": "array", - "title": "Console Ingress Hosts", - "description": "Console ingress hosts configuration", - "items": { + "global": { "type": "object", "properties": { - "host": { - "type": "string", - "title": "Host", - "description": "Hostname for MinIO Console ingress" - }, - "paths": { - "type": "array", - "title": "Paths", - "description": "Paths configuration for the host", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "title": "Path", - "description": "Path for MinIO Console ingress" - }, - "pathType": { - "type": "string", - "title": "Path Type", - "description": "Path type for MinIO Console ingress", - "enum": ["Exact", "Prefix", "ImplementationSpecific"] - } - } + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" } - } } - } }, - "tls": { - "type": "array", - "title": "Console TLS Configuration", - "description": "TLS configuration for MinIO Console ingress", - "items": { - "type": "object" - } - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource configuration parameters", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "tagCpuV1": { + "type": "string" + }, + "useCpuV1": { + "type": "boolean" + } } - } }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } } - } - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "Persistence configuration parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable persistence using Persistent Volume Claims" - }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "Persistent Volume storage class" - }, - "annotations": { - "type": "object", - "title": "PVC Annotations", - "description": "Persistent Volume Claim annotations", - "additionalProperties": { - "type": "string" - } - }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "Persistent Volume size", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" }, - "accessModes": { - "type": "array", - "title": "Access Modes", - "description": "Persistent Volume access modes", - "items": { - "type": "string", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] - } - }, - "existingClaim": { - "type": "string", - "title": "Existing Claim", - "description": "The name of an existing PVC to use for persistence" - } - } - }, - "serviceAccount": { - "type": "object", - "title": "Service Account Configuration", - "description": "Service Account configuration parameters", - "properties": { - "create": { - "type": "boolean", - "title": "Create Service Account", - "description": "Enable the creation of a ServiceAccount for MinIO", - "default": true - }, - "name": { - "type": "string", - "title": "Service Account Name", - "description": "Name of the created ServiceAccount. If not set and create is true, a name is generated using the common.names.fullname template", - "default": "" - }, - "automountServiceAccountToken": { - "type": "boolean", - "title": "Automount Service Account Token", - "description": "Enable/disable auto mounting of the service account token", - "default": false + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "annotations": { - "type": "object", - "title": "Service Account Annotations", - "description": "Custom annotations for MinIO serviceAccount", - "additionalProperties": { + "nameOverride": { "type": "string" - }, - "default": {} - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "Liveness and readiness probes configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable livenessProbe on MinIO containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for livenessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for livenessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for livenessProbe", - "minimum": 1 }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for livenessProbe", - "minimum": 1 + "nodeSelector": { + "type": "object" }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for livenessProbe", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "Readiness probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readinessProbe on MinIO containers" + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for readinessProbe", - "minimum": 0 + "podAnnotations": { + "type": "object" }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for readinessProbe", - "minimum": 1 + "podLabels": { + "type": "object" }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for readinessProbe", - "minimum": 1 + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for readinessProbe", - "minimum": 1 + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for readinessProbe", - "minimum": 1 - } - } - }, - "startupProbe": { - "type": "object", - "title": "Startup Probe Configuration", - "description": "Startup probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Startup Probe", - "description": "Enable startupProbe on MinIO containers" + "replicaCount": { + "type": "integer" }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for startupProbe", - "minimum": 0 + "resources": { + "type": "object" }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for startupProbe", - "minimum": 1 + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "consolePort": { + "type": "integer" + }, + "nodePorts": { + "type": "object", + "properties": { + "api": { + "type": "string" + }, + "console": { + "type": "string" + } + } + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for startupProbe", - "minimum": 1 + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for startupProbe", - "minimum": 1 + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for startupProbe", - "minimum": 1 + "tolerations": { + "type": "array" } - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node Selection configuration", - "additionalProperties": { - "type": "string" - } - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Tolerations for pod assignment", - "items": { - "type": "object" - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity settings for pod assignment" - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } -} \ No newline at end of file +} diff --git a/charts/minio/values.yaml b/charts/minio/values.yaml index eab8b877..4608bc2d 100644 --- a/charts/minio/values.yaml +++ b/charts/minio/values.yaml @@ -117,6 +117,12 @@ service: consolePort: 9090 ## @param service.annotations Service annotations annotations: {} + ## @param service.nodePorts Service node ports + nodePorts: + ## @param service.nodePorts.api Service api node port + api: "" + ## @param service.nodePorts.api Service console node port + console: "" ## @section Ingress configuration ingress: diff --git a/charts/mongodb/CHANGELOG.md b/charts/mongodb/CHANGELOG.md index 9dd7167d..3c5717b7 100644 --- a/charts/mongodb/CHANGELOG.md +++ b/charts/mongodb/CHANGELOG.md @@ -1,5 +1,124 @@ # Changelog + +## 0.6.1 (2025-10-29) + +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.6.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([5bf8d10](https://github.com/CloudPirates-io/helm-charts/commit/5bf8d10)) +* chore: update CHANGELOG.md for merged changes ([64bc0ac](https://github.com/CloudPirates-io/helm-charts/commit/64bc0ac)) +* Update README.md (#468) ([26c7a1c](https://github.com/CloudPirates-io/helm-charts/commit/26c7a1c)) +* chore: update CHANGELOG.md for merged changes ([cbf613f](https://github.com/CloudPirates-io/helm-charts/commit/cbf613f)) +* chore: update CHANGELOG.md for merged changes ([48e61e6](https://github.com/CloudPirates-io/helm-charts/commit/48e61e6)) + +## 0.5.6 (2025-10-26) + + +## 0.5.5 (2025-10-24) + +* chore: update CHANGELOG.md for merged changes ([b2b84ce](https://github.com/CloudPirates-io/helm-charts/commit/b2b84ce)) +* chore: update CHANGELOG.md for merged changes ([b1f47df](https://github.com/CloudPirates-io/helm-charts/commit/b1f47df)) +* Allow to set custom command and args (#457) ([06d8f66](https://github.com/CloudPirates-io/helm-charts/commit/06d8f66)) +* chore: auto-generate values.schema.json for updated charts (#455) ([aec6840](https://github.com/CloudPirates-io/helm-charts/commit/aec6840)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.5.4 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([4587534](https://github.com/CloudPirates-io/helm-charts/commit/4587534)) +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.5.3 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([bd36e6d](https://github.com/CloudPirates-io/helm-charts/commit/bd36e6d)) +* chore: update CHANGELOG.md for merged changes ([fc6b177](https://github.com/CloudPirates-io/helm-charts/commit/fc6b177)) + +## 0.5.2 (2025-10-22) + +* Fix no auth error in init script (#440) ([54b7221](https://github.com/CloudPirates-io/helm-charts/commit/54b7221)) +* chore: update CHANGELOG.md for merged changes ([c80ea42](https://github.com/CloudPirates-io/helm-charts/commit/c80ea42)) +* chore: update CHANGELOG.md for merged changes ([8ccb4bb](https://github.com/CloudPirates-io/helm-charts/commit/8ccb4bb)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([c76aa29](https://github.com/CloudPirates-io/helm-charts/commit/c76aa29)) +* chore: update CHANGELOG.md for merged changes ([77e0793](https://github.com/CloudPirates-io/helm-charts/commit/77e0793)) + +## 0.5.1 (2025-10-15) + +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.5.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) + +## 0.4.2 (2025-10-10) + + +## 0.4.1 (2025-10-09) + +* fix: newline between mongo labels and additional labels (#301) ([ea7937f](https://github.com/CloudPirates-io/helm-charts/commit/ea7937f)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + ## 0.4.0 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* feat: add metrics exporter (#243) ([c931978](https://github.com/CloudPirates-io/helm-charts/commit/c931978)) + +## 0.3.3 (2025-10-09) + +* makes configmap name dynamic (#279) ([6dd10a9](https://github.com/CloudPirates-io/helm-charts/commit/6dd10a9)) + +## 0.3.2 (2025-10-09) + + +## 0.3.1 (2025-10-08) + +* update values.schema.json (#242) ([f973e47](https://github.com/CloudPirates-io/helm-charts/commit/f973e47)) +* [minio, mongodb, postgres, timescaledb] Update securityContext to containerSecurityContext in the values schema (#213) ([8a4003f](https://github.com/CloudPirates-io/helm-charts/commit/8a4003f)) + +## 0.3.0 (2025-10-02) + +* make mongodb run on openshift (#202) ([b654629](https://github.com/CloudPirates-io/helm-charts/commit/b654629)) + +## 0.2.0 (2025-09-25) + +* add custom user creation at initialization (#153) ([772d18f](https://github.com/CloudPirates-io/helm-charts/commit/772d18f)) + +## 0.1.9 (2025-09-16) + +* Update CHANGELOG.md ([72601e5](https://github.com/CloudPirates-io/helm-charts/commit/72601e5)) +* Bump chart version ([77f76af](https://github.com/CloudPirates-io/helm-charts/commit/77f76af)) + +## 0.1.8 (2025-09-11) + +* Update CHANGELOG.md ([5c9f4d0](https://github.com/CloudPirates-io/helm-charts/commit/5c9f4d0)) +* Bump chart version ([159ba82](https://github.com/CloudPirates-io/helm-charts/commit/159ba82)) + +## 0.1.7 (2025-09-09) + +* Update CHANGELOG.md ([3174cb2](https://github.com/CloudPirates-io/helm-charts/commit/3174cb2)) +* Bump chart version ([98d3ee6](https://github.com/CloudPirates-io/helm-charts/commit/98d3ee6)) +* Update docker.io/mongo:8.0.13 Docker digest to c750922 ([cbd41d9](https://github.com/CloudPirates-io/helm-charts/commit/cbd41d9)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.1.6 (2025-08-27) + +* Fix values.yaml / Chart.yaml linting issues ([043c7e0](https://github.com/CloudPirates-io/helm-charts/commit/043c7e0)) +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.1.5 (2025-08-26) + +* Initial tagged release diff --git a/charts/mongodb/Chart.lock b/charts/mongodb/Chart.lock index b4eeace9..899e5878 100644 --- a/charts/mongodb/Chart.lock +++ b/charts/mongodb/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-10-01T21:57:12.890603+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:37.353262+02:00" diff --git a/charts/mongodb/Chart.yaml b/charts/mongodb/Chart.yaml index 2dfde7f7..1a590a70 100644 --- a/charts/mongodb/Chart.yaml +++ b/charts/mongodb/Chart.yaml @@ -2,20 +2,41 @@ apiVersion: v2 name: mongodb description: MongoDB a flexible NoSQL database for scalable, real-time data management type: application -version: 0.4.0 -appVersion: "8.0.13" +version: 0.6.1 +appVersion: "8.2.1" keywords: - mongodb - database - nosql -home: https://www.cloudpirates.io +home: https://www.mongodb.com sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mongodb + - https://github.com/mongodb/mongo maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/5d228988dc/mongodb-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: MongoDB + url: https://www.mongodb.com + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mongodb + - name: Application + url: https://github.com/mongodb/mongo + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Chart updated" diff --git a/charts/mongodb/README.md b/charts/mongodb/README.md index 701dc37a..2b96c3f8 100644 --- a/charts/mongodb/README.md +++ b/charts/mongodb/README.md @@ -68,29 +68,46 @@ The following table lists the configurable parameters of the MongoDB chart and t ### Global Parameters -| Parameter | Description | Default | -| ------------------ | --------------------------------------------- | ------- | -| `replicaCount` | Number of MongoDB replicas to deploy | `1` | -| `nameOverride` | String to partially override mongodb.fullname | `""` | -| `fullnameOverride` | String to fully override mongodb.fullname | `""` | +| Parameter | Description | Default | +| ------------------------- | ----------------------------------------------- | ------- | +| `global.imageRegistry` | Global Docker Image registry | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | -### Image Parameters +### Common Parameters -| Parameter | Description | Default | -| ------------------ | ------------------------------- | --------------------------------------------------------------------------- | -| `image.repository` | MongoDB Docker image repository | `mongo` | -| `image.tag` | MongoDB Docker image tag | `"8.0.12"` | -| `image.digest` | MongoDB Docker image digest | `"sha256:a6bda40d00e56682aeaa1bfc88e024b7dd755782c575c02760104fe02010f94f"` | -| `image.pullPolicy` | MongoDB image pull policy | `IfNotPresent` | +| Parameter | Description | Default | +| ------------------- | -------------------------------------------------------- | ------- | +| `nameOverride` | String to partially override mongodb.fullname | `""` | +| `fullnameOverride` | String to fully override mongodb.fullname | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `podAnnotations` | Annotations to add to the pod created by the statefulset | `{}` | +| `podLabels` | Labels to add to the pod created by the statefulset | `{}` | + +### MongoDB Image Parameters + +| Parameter | Description | Default | +| ------------------ | ------------------------- | ---------------------------------------------------------------------------------- | +| `image.registry` | MongoDB image registry | `docker.io` | +| `image.repository` | MongoDB image repository | `mongo` | +| `image.tag` | MongoDB image tag | `"8.0.15@sha256:d0d76261e7a19aee701e890a9e835ba369a12b8733e7d39cd89a923ed97f247c"` | +| `image.pullPolicy` | MongoDB image pull policy | `Always` | + +### Replica Configuration + +| Parameter | Description | Default | +| -------------- | ------------------------------------ | ------- | +| `replicaCount` | Number of MongoDB replicas to deploy | `1` | ### Service Parameters -| Parameter | Description | Default | -| -------------- | ----------------------- | ----------- | -| `service.type` | Kubernetes service type | `ClusterIP` | -| `service.port` | MongoDB service port | `27017` | +| Parameter | Description | Default | +| --------------------- | ----------------------------------------- | ----------- | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.port` | MongoDB service port | `27017` | +| `service.annotations` | Annotations to add to the mongodb service | `{}` | -### MongoDB Configuration Parameters +### MongoDB Authentication Parameters | Parameter | Description | Default | | -------------------------------- | ------------------------------------------------------------------- | ------- | @@ -99,17 +116,27 @@ The following table lists the configurable parameters of the MongoDB chart and t | `auth.rootPassword` | MongoDB root password (if empty, random password will be generated) | `""` | | `auth.existingSecret` | Name of existing secret containing MongoDB password | `""` | | `auth.existingSecretPasswordKey` | Key in existing secret containing MongoDB password | `""` | -| `config` | MongoDB configuration options | `{}` | + +### MongoDB Configuration Parameters + +| Parameter | Description | Default | +| ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------- | +| `config.mountPath` | MongoDB configuration options | `/etc/mongo` | +| `config.content` | Include your custom MongoDB configurations here as string | `systemLog:\n quiet: true\n verbosity: 0\nnet:\n bindIpAll: true` | +| `config.existingConfigmap` | Name of an existing Configmap to use instead of creating one | `""` | +| `config.existingConfigmapKey` | Name of the key in the Configmap that should be used | `""` | ### Custom User Configuration -| Parameter | Description | Default | -| --------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------- | -| `customUser` | Optional user to be created at initialisation with a custom password and database | `{}` | -| `customUser.name` | Name of the custom user to be created | `""` | -| `customUser.database` | Name of the database to be created | `""` | -| `customUser.password` | Password to be used for the custom user | `""` | -| `customUser.existingSecret` | Existing secret, in which username, password and database name are saved | `""` | -| `customUser.secretKeys` | Name of keys in existing secret to use the custom user name, password and database | `{name: "", database: "", password: ""}` | + +| Parameter | Description | Default | +| -------------------------------- | ------------------------------------------------------------------------ | ------- | +| `customUser.name` | Name of the custom user to be created | `""` | +| `customUser.database` | Name of the database to be created | `""` | +| `customUser.password` | Password to be used for the custom user | `""` | +| `customUser.existingSecret` | Existing secret, in which username, password and database name are saved | `""` | +| `customUser.secretKeys.name` | Name of key in existing secret containing username | `""` | +| `customUser.secretKeys.password` | Name of key in existing secret containing password | `""` | +| `customUser.secretKeys.database` | Name of key in existing secret containing database | `""` | ### Persistence Parameters @@ -124,21 +151,21 @@ The following table lists the configurable parameters of the MongoDB chart and t ### Resource Parameters -| Parameter | Description | Default | -| -------------- | -------------------------------------------- | ------- | -| `resources` | Resource limits and requests for MongoDB pod | `{}` | -| `nodeSelector` | Node selector for pod assignment | `{}` | -| `tolerations` | Tolerations for pod assignment | `[]` | -| `affinity` | Affinity rules for pod assignment | `{}` | +| Parameter | Description | Default | +| -------------- | -------------------------------------------- | -------------------------------------------------------------- | +| `resources` | Resource limits and requests for MongoDB pod | `limits: {memory: 512Mi}, requests: {cpu: 50m, memory: 512Mi}` | +| `nodeSelector` | Node selector for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `affinity` | Affinity rules for pod assignment | `{}` | ### Security Parameters -| Parameter | Description | Default | -| ------------------------------ | --------------------------------- | ------- | -| `securityContext.fsGroup` | Group ID for filesystem ownership | `999` | -| `securityContext.runAsUser` | User ID to run the container | `999` | -| `securityContext.runAsNonRoot` | Run as non-root user | `true` | -| `podSecurityContext` | Security context for the pod | `{}` | +| Parameter | Description | Default | +| --------------------------------------------------- | -------------------------------------------- | ------- | +| `containerSecurityContext.runAsUser` | User ID to run the container | `999` | +| `containerSecurityContext.runAsNonRoot` | Run as non-root user | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | Set MongoDB container's privilege escalation | `false` | +| `podSecurityContext.fsGroup` | Set MongoDB pod's Security Context fsGroup | `999` | ### Health Check Parameters @@ -157,6 +184,15 @@ The following table lists the configurable parameters of the MongoDB chart and t | `readinessProbe.failureThreshold` | Number of failures before pod is marked unready | `6` | | `readinessProbe.successThreshold` | Number of successes to mark probe as successful | `1` | +### Additional Parameters + +| Parameter | Description | Default | +| ------------------- | -------------------------------------------------------- | ------- | +| `extraEnvVars` | Additional environment variables to set | `[]` | +| `extraVolumes` | Additional volumes to add to the pod | `[]` | +| `extraVolumeMounts` | Additional volume mounts to add to the MongoDB container | `[]` | +| `extraObjects` | Array of extra objects to deploy with the release | `[]` | + ### Network Policy Parameters | Parameter | Description | Default | @@ -226,20 +262,10 @@ The following table lists the configurable parameters of the MongoDB chart and t ### Metrics Additional Parameters -| Parameter | Description | Default | -| ------------------- | ------------------------------------------------------ | ------- | -| `metrics.extraEnv` | Additional environment variables for metrics container | `[]` | -| `metrics.extraArgs` | Additional command line arguments for MongoDB Exporter | `[]` | - - -### Additional Parameters - -| Parameter | Description | Default | -| ------------------- | -------------------------------------------------------- | ------- | -| `extraEnv` | Additional environment variables to set | `[]` | -| `extraVolumes` | Additional volumes to add to the pod | `[]` | -| `extraVolumeMounts` | Additional volume mounts to add to the MongoDB container | `[]` | -| `extraObjects` | Additional Kubernetes objects to deploy | `[]` | +| Parameter | Description | Default | +| ---------------------- | ------------------------------------------------------ | ------- | +| `metrics.extraEnvVars` | Additional environment variables for metrics container | `[]` | +| `metrics.extraArgs` | Additional command line arguments for MongoDB Exporter | `[]` | #### Extra Objects @@ -282,11 +308,10 @@ All objects in `extraObjects` will be rendered and deployed with the release. Yo ### Basic Installation with Authentication ```yaml -mongodb: - auth: - enabled: true - rootUsername: admin - rootPassword: "mySecretPassword" +auth: + enabled: true + rootUsername: admin + rootPassword: "mySecretPassword" persistence: enabled: true @@ -311,12 +336,11 @@ persistence: storageClass: "default" size: 100Gi -mongodb: - auth: - enabled: true - rootUsername: admin - existingSecret: mongodb-credentials - existingSecretPasswordKey: password +auth: + enabled: true + rootUsername: admin + existingSecret: mongodb-credentials + existingSecretPasswordKey: password ``` ### Development Setup (No Persistence) @@ -325,9 +349,8 @@ mongodb: persistence: enabled: false -mongodb: - auth: - enabled: false +auth: + enabled: false resources: limits: diff --git a/charts/mongodb/templates/_helpers.tpl b/charts/mongodb/templates/_helpers.tpl index 507631f5..8b0be4d0 100644 --- a/charts/mongodb/templates/_helpers.tpl +++ b/charts/mongodb/templates/_helpers.tpl @@ -2,42 +2,42 @@ Expand the name of the chart. */}} {{- define "mongodb.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "mongodb.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "mongodb.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "mongodb.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Selector labels */}} {{- define "mongodb.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Common annotations */}} {{- define "mongodb.annotations" -}} -{{- include "common.annotations" . -}} +{{- include "cloudpirates.annotations" . -}} {{- end }} {{/* @@ -45,7 +45,7 @@ Get the secret name for MongoDB root password */}} {{- define "mongodb.secretName" -}} {{- if .Values.auth.existingSecret }} -{{- .Values.auth.existingSecret }} +{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) }} {{- else }} {{- include "mongodb.fullname" . }} {{- end }} @@ -65,14 +65,14 @@ Get the secret key for MongoDB root password Return the proper MongoDB image name */}} {{- define "mongodb.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "mongodb.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{- define "mongodb.configFullName" -}} @@ -87,7 +87,7 @@ Return the proper Docker Image Registry Secret Names Return the proper MongoDB Exporter image name */}} {{- define "mongodb.metrics.image" -}} -{{- include "common.image" (dict "image" .Values.metrics.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.metrics.image "global" .Values.global) -}} {{- end }} {{/* @@ -106,7 +106,7 @@ Get the secret name for MongoDB metrics user */}} {{- define "mongodb.metrics.secretName" -}} {{- if .Values.auth.existingSecret }} -{{- .Values.auth.existingSecret }} +{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) }} {{- else if and .Values.metrics.username .Values.metrics.enabled }} {{- printf "%s-metrics" (include "mongodb.fullname" .) }} {{- else }} @@ -127,6 +127,6 @@ Return ServiceMonitor labels {{- define "mongodb.metrics.serviceMonitor.labels" -}} {{- include "mongodb.labels" . }} {{- with .Values.metrics.serviceMonitor.additionalLabels }} -{{- toYaml . }} +{{ toYaml . }} {{- end }} {{- end -}} diff --git a/charts/mongodb/templates/configmap.yaml b/charts/mongodb/templates/configmap.yaml index 0f915753..04e3768e 100644 --- a/charts/mongodb/templates/configmap.yaml +++ b/charts/mongodb/templates/configmap.yaml @@ -4,6 +4,10 @@ kind: ConfigMap metadata: name: {{ include "mongodb.fullname" . }}-config namespace: {{ .Release.Namespace | quote }} + {{- with (include "mongodb.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} labels: {{- include "mongodb.labels" . | nindent 4 }} data: diff --git a/charts/mongodb/templates/custom-user-secret.yaml b/charts/mongodb/templates/custom-user-secret.yaml index d2f5d9f7..bc372b71 100644 --- a/charts/mongodb/templates/custom-user-secret.yaml +++ b/charts/mongodb/templates/custom-user-secret.yaml @@ -6,9 +6,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "mongodb.labels" . | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: - {{- include "mongodb.annotations" . | nindent 4 }} + {{- with (include "mongodb.annotations" .) }} + annotations: +{{- . | indent 4 }} {{- end }} type: Opaque data: diff --git a/charts/mongodb/templates/extraobjects.yaml b/charts/mongodb/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/mongodb/templates/extraobjects.yaml +++ b/charts/mongodb/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/mongodb/templates/init-scripts.yaml b/charts/mongodb/templates/init-scripts.yaml index ff6e9ca9..078f3724 100644 --- a/charts/mongodb/templates/init-scripts.yaml +++ b/charts/mongodb/templates/init-scripts.yaml @@ -1,8 +1,13 @@ +{{- if or (and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret)) (and .Values.metrics.enabled .Values.auth.enabled .Values.metrics.username) }} apiVersion: v1 kind: ConfigMap metadata: name: {{ include "mongodb.fullname" . }}-init-scripts namespace: {{ .Release.Namespace }} + {{- with (include "mongodb.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} labels: {{- include "mongodb.labels" . | nindent 4 }} data: @@ -45,3 +50,4 @@ data: } " {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/mongodb/templates/metrics-networkpolicy.yaml b/charts/mongodb/templates/metrics-networkpolicy.yaml index bf3ec3f3..012431d7 100644 --- a/charts/mongodb/templates/metrics-networkpolicy.yaml +++ b/charts/mongodb/templates/metrics-networkpolicy.yaml @@ -8,6 +8,10 @@ metadata: labels: {{- include "mongodb.labels" . | nindent 4 }} app.kubernetes.io/component: metrics + {{- with (include "mongodb.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} spec: podSelector: matchLabels: diff --git a/charts/mongodb/templates/metrics-secret.yaml b/charts/mongodb/templates/metrics-secret.yaml index d5a5130b..753abe5b 100644 --- a/charts/mongodb/templates/metrics-secret.yaml +++ b/charts/mongodb/templates/metrics-secret.yaml @@ -8,6 +8,10 @@ metadata: labels: {{- include "mongodb.labels" . | nindent 4 }} app.kubernetes.io/component: metrics + {{- with (include "mongodb.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} type: Opaque data: {{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-metrics" (include "mongodb.fullname" .))) }} diff --git a/charts/mongodb/templates/metrics-service.yaml b/charts/mongodb/templates/metrics-service.yaml index 494810a3..2103784b 100644 --- a/charts/mongodb/templates/metrics-service.yaml +++ b/charts/mongodb/templates/metrics-service.yaml @@ -10,9 +10,10 @@ metadata: {{- with .Values.metrics.service.labels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.metrics.service.annotations }} - annotations: - {{- toYaml . | nindent 4 }} + {{- if or (include "mongodb.annotations" .) .Values.metrics.service.annotations }} + annotations: +{{- (include "mongodb.annotations" .) | indent 4 }} +{{- toYaml .Values.metrics.service.annotations | nindent 4 }} {{- end }} spec: type: {{ .Values.metrics.service.type }} diff --git a/charts/mongodb/templates/metrics-servicemonitor.yaml b/charts/mongodb/templates/metrics-servicemonitor.yaml index 1f0592e9..10b80253 100644 --- a/charts/mongodb/templates/metrics-servicemonitor.yaml +++ b/charts/mongodb/templates/metrics-servicemonitor.yaml @@ -10,10 +10,10 @@ metadata: {{- end }} labels: {{- include "mongodb.metrics.serviceMonitor.labels" . | nindent 4 }} - release: {{ .Release.Name }} {{- with .Values.metrics.serviceMonitor.annotations }} annotations: {{- toYaml . | nindent 4 }} + {{- include "mongodb.annotations" . }} {{- end }} spec: {{- if .Values.metrics.serviceMonitor.jobLabel }} diff --git a/charts/mongodb/templates/secret.yaml b/charts/mongodb/templates/secret.yaml index d85bc873..271d3824 100644 --- a/charts/mongodb/templates/secret.yaml +++ b/charts/mongodb/templates/secret.yaml @@ -7,6 +7,10 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "mongodb.labels" . | nindent 4 }} + {{- with (include "mongodb.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} type: Opaque data: {{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace (include "mongodb.fullname" .)) }} diff --git a/charts/mongodb/templates/service.yaml b/charts/mongodb/templates/service.yaml index a2918acf..34d66f38 100644 --- a/charts/mongodb/templates/service.yaml +++ b/charts/mongodb/templates/service.yaml @@ -5,6 +5,13 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "mongodb.labels" . | nindent 4 }} + {{- if or (include "mongodb.annotations" .) .Values.service.annotations }} + annotations: +{{- (include "mongodb.annotations" .) | indent 4 }} + {{- if .Values.service.annotations }} +{{ toYaml .Values.service.annotations | indent 4 }} + {{- end }} + {{- end }} spec: type: {{ .Values.service.type }} ports: diff --git a/charts/mongodb/templates/statefulset.yaml b/charts/mongodb/templates/statefulset.yaml index 9aec208e..62f69fdf 100644 --- a/charts/mongodb/templates/statefulset.yaml +++ b/charts/mongodb/templates/statefulset.yaml @@ -6,8 +6,8 @@ metadata: labels: {{- include "mongodb.labels" . | nindent 4 }} {{- with (include "mongodb.annotations" .) }} - annotations: - {{- . | nindent 4 }} + annotations: +{{- . | indent 4 }} {{- end }} spec: serviceName: {{ include "mongodb.fullname" . }} @@ -19,19 +19,34 @@ spec: metadata: labels: {{- include "mongodb.selectorLabels" . | nindent 8 }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} + {{- end }} + {{- if or (include "mongodb.annotations" .) .Values.podAnnotations }} + annotations: +{{- include "mongodb.annotations" . | indent 8 }} + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + {{- end }} spec: {{- with (include "mongodb.imagePullSecrets" .) }} {{ . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "mongodb.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} - {{- if or .Values.config.content .Values.config.existingConfigmap }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} + {{- if .Values.image.command }} + command: {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.image.command "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.image.args }} + args: {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.image.args "context" $) | nindent 12 }} + {{- else if or .Values.config.content .Values.config.existingConfigmap }} args: - - "-f" + - "--config" - {{ include "mongodb.configFullName" . | quote }} {{- end }} ports: @@ -53,7 +68,7 @@ spec: valueFrom: secretKeyRef: {{- if .Values.customUser.existingSecret }} - name: {{ .Values.customUser.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.customUser.existingSecret "context" $) }} {{- else }} name: {{ include "mongodb.fullname" . }}-custom-user-secret {{- end }} @@ -66,7 +81,7 @@ spec: valueFrom: secretKeyRef: {{- if .Values.customUser.existingSecret }} - name: {{ .Values.customUser.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.customUser.existingSecret "context" $) }} {{- else }} name: {{ include "mongodb.fullname" . }}-custom-user-secret {{- end }} @@ -79,7 +94,7 @@ spec: valueFrom: secretKeyRef: {{- if .Values.customUser.existingSecret }} - name: {{ .Values.customUser.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.customUser.existingSecret "context" $) }} {{- else }} name: {{ include "mongodb.fullname" . }}-custom-user-secret {{- end }} @@ -98,9 +113,8 @@ spec: name: {{ include "mongodb.metrics.secretName" . }} key: {{ include "mongodb.secretPasswordKey" . }} {{- end }} - {{- range .Values.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: @@ -132,8 +146,10 @@ spec: volumeMounts: - name: data mountPath: {{ .Values.persistence.mountPath }} + {{- if or (and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret)) (and .Values.metrics.enabled .Values.auth.enabled .Values.metrics.username) }} - name: init-scripts mountPath: /docker-entrypoint-initdb.d/ + {{- end }} {{- if or .Values.config.content .Values.config.existingConfigmap }} - name: config mountPath: /etc/mongo @@ -163,9 +179,8 @@ spec: secretKeyRef: name: {{ include "mongodb.metrics.secretName" . }} key: {{ include "mongodb.secretPasswordKey" . }} - {{- range .Values.metrics.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} + {{- with .Values.metrics.extraEnvVars }} +{{ toYaml . | indent 12}} {{- end }} {{- else }} env: @@ -207,9 +222,11 @@ spec: - name: data emptyDir: {} {{- end }} + {{- if or (and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret)) (and .Values.metrics.enabled .Values.auth.enabled .Values.metrics.username) }} - name: init-scripts configMap: name: {{ include "mongodb.fullname" . }}-init-scripts + {{- end }} {{- if or .Values.config.content .Values.config.existingConfigmap }} - name: config configMap: diff --git a/charts/mongodb/tests/container-override_test.yaml b/charts/mongodb/tests/container-override_test.yaml new file mode 100644 index 00000000..0f92c3dc --- /dev/null +++ b/charts/mongodb/tests/container-override_test.yaml @@ -0,0 +1,265 @@ +suite: test container command and args overrides +templates: + - statefulset.yaml +set: + image: + tag: 8.0.12@sha256:a6bda40d00e56682aeaa1bfc88e024b7dd755782c575c02760104fe02010f94f +tests: + - it: should not have command field when image.command is not set + asserts: + - isNull: + path: spec.template.spec.containers[0].command + + - it: should not have args field when image.args is not set and no config is provided + set: + config: + content: "" + asserts: + - isNull: + path: spec.template.spec.containers[0].args + + - it: should have default args when config.content is provided + set: + config: + content: | + systemLog: + quiet: true + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "--config" + - equal: + path: spec.template.spec.containers[0].args[1] + value: "/etc/mongo/mongod.conf" + + - it: should have default args when config.existingConfigmap is provided + set: + config: + content: "" + existingConfigmap: "my-custom-configmap" + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "--config" + - equal: + path: spec.template.spec.containers[0].args[1] + value: "/etc/mongo/mongod.conf" + + - it: should have custom config path when config.existingConfigmapKey is provided + set: + config: + content: "" + existingConfigmap: "my-custom-configmap" + existingConfigmapKey: "custom-mongod.conf" + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "--config" + - equal: + path: spec.template.spec.containers[0].args[1] + value: "/etc/mongo/custom-mongod.conf" + + - it: should override with custom command when image.command is set + set: + image: + command: + - "/bin/bash" + - "-c" + asserts: + - equal: + path: spec.template.spec.containers[0].command[0] + value: "/bin/bash" + - equal: + path: spec.template.spec.containers[0].command[1] + value: "-c" + + - it: should override with custom args when image.args is set + set: + image: + args: + - "mongod" + - "--bind_ip_all" + - "--port" + - "27017" + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "mongod" + - equal: + path: spec.template.spec.containers[0].args[1] + value: "--bind_ip_all" + - equal: + path: spec.template.spec.containers[0].args[2] + value: "--port" + - equal: + path: spec.template.spec.containers[0].args[3] + value: "27017" + + - it: should prioritize image.args over default config args + set: + config: + content: | + systemLog: + quiet: true + image: + args: + - "mongod" + - "--replSet" + - "rs0" + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "mongod" + - equal: + path: spec.template.spec.containers[0].args[1] + value: "--replSet" + - equal: + path: spec.template.spec.containers[0].args[2] + value: "rs0" + + - it: should use both custom command and custom args when both are set + set: + image: + command: + - "/custom/entrypoint.sh" + args: + - "--debug" + - "--verbose" + asserts: + - equal: + path: spec.template.spec.containers[0].command[0] + value: "/custom/entrypoint.sh" + - equal: + path: spec.template.spec.containers[0].args[0] + value: "--debug" + - equal: + path: spec.template.spec.containers[0].args[1] + value: "--verbose" + + - it: should support single command entry + set: + image: + command: + - "mongod" + asserts: + - equal: + path: spec.template.spec.containers[0].command[0] + value: "mongod" + + - it: should support single args entry + set: + image: + args: + - "--help" + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "--help" + + - it: should handle empty command array + set: + image: + command: [] + asserts: + - isNull: + path: spec.template.spec.containers[0].command + + - it: should handle empty args array + set: + config: + content: "" + image: + args: [] + asserts: + - isNull: + path: spec.template.spec.containers[0].args + + - it: should support template rendering in command + set: + image: + command: + - "/bin/sh" + - "-c" + - "echo 'Starting {{ .Chart.Name }}'" + asserts: + - equal: + path: spec.template.spec.containers[0].command[0] + value: "/bin/sh" + - equal: + path: spec.template.spec.containers[0].command[1] + value: "-c" + - equal: + path: spec.template.spec.containers[0].command[2] + value: "echo 'Starting mongodb'" + + - it: should support template rendering in args + set: + image: + args: + - "mongod" + - "--dbpath" + - "{{ .Values.persistence.mountPath }}" + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "mongod" + - equal: + path: spec.template.spec.containers[0].args[1] + value: "--dbpath" + - equal: + path: spec.template.spec.containers[0].args[2] + value: "/data/db" + + - it: should work with complex command for debugging + set: + image: + command: + - "/bin/bash" + - "-c" + - | + set -e + echo "Starting MongoDB with debug mode" + exec mongod --bind_ip_all + asserts: + - equal: + path: spec.template.spec.containers[0].command[0] + value: "/bin/bash" + - equal: + path: spec.template.spec.containers[0].command[1] + value: "-c" + - matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: ".*Starting MongoDB with debug mode.*" + + - it: should not affect other container properties when command is set + set: + image: + command: + - "mongod" + pullPolicy: IfNotPresent + asserts: + - equal: + path: spec.template.spec.containers[0].command[0] + value: "mongod" + - equal: + path: spec.template.spec.containers[0].image + value: docker.io/mongo:8.0.12@sha256:a6bda40d00e56682aeaa1bfc88e024b7dd755782c575c02760104fe02010f94f + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + + - it: should not affect other container properties when args is set + set: + image: + args: + - "mongod" + resources: + limits: + memory: 1Gi + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "mongod" + - equal: + path: spec.template.spec.containers[0].resources.limits.memory + value: 1Gi diff --git a/charts/mongodb/values.schema.json b/charts/mongodb/values.schema.json index c9209b48..35b99693 100644 --- a/charts/mongodb/values.schema.json +++ b/charts/mongodb/values.schema.json @@ -1,500 +1,449 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "MongoDB Helm Chart Values Schema", - "description": "Schema for MongoDB Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker image registry" + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of MongoDB replicas to deploy", - "minimum": 1 - }, - "image": { - "type": "object", - "title": "MongoDB Image Configuration", - "description": "MongoDB container image configuration", - "properties": { - "registry": { - "type": "string", - "title": "MongoDB Image Registry", - "description": "MongoDB Docker image registry" - }, - "repository": { - "type": "string", - "title": "MongoDB Image Repository", - "description": "MongoDB Docker image repository" - }, - "tag": { - "type": "string", - "title": "MongoDB Image Tag", - "description": "MongoDB image tag" - }, - "pullPolicy": { - "type": "string", - "title": "MongoDB Image Pull Policy", - "description": "MongoDB image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] - } - } - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override mongodb.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override mongodb.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "Kubernetes service configuration", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "Kubernetes service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "MongoDB service port", - "minimum": 1, - "maximum": 65535 - } - } - }, - "auth": { - "type": "object", - "title": "MongoDB Authentication", - "description": "MongoDB authentication configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Authentication", - "description": "Enable MongoDB authentication" + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "existingSecretPasswordKey": { + "type": "string" + }, + "rootPassword": { + "type": "string" + }, + "rootUsername": { + "type": "string" + } + } }, - "rootUsername": { - "type": "string", - "title": "MongoDB Root Username", - "description": "MongoDB root username" + "commonAnnotations": { + "type": "object" }, - "rootPassword": { - "type": "string", - "title": "MongoDB Root Password", - "description": "MongoDB root password (if empty, random password will be generated)" + "commonLabels": { + "type": "object" }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret containing MongoDB password" + "config": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "existingConfigmap": { + "type": "string" + }, + "existingConfigmapKey": { + "type": "string" + }, + "mountPath": { + "type": "string" + } + } }, - "existingSecretPasswordKey": { - "type": "string", - "title": "Existing Secret Password Key", - "description": "Key in existing secret containing MongoDB password" - } - } - }, - "config": { - "type": "object", - "title": "MongoDB Configuration", - "description": "MongoDB configuration options", - "properties": { - "mountPath": { - "type": "string", - "title": "Config Mount Path", - "description": "MongoDB configuration options" + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } + } }, - "content": { - "type": "string", - "title": "Config Content", - "description": "Include your custom MongoDB configurations here as string" + "customUser": { + "type": "object" }, - "existingConfigmap": { - "type": "string", - "title": "Existing ConfigMap", - "description": "Name of an existing Configmap to use instead of creating one" + "extraEnvVars": { + "type": "array" }, - "existingConfigmapKey": { - "type": "string", - "title": "Existing ConfigMap Key", - "description": "Name of the key in the Configmap that should be used" - } - } - }, - "customUser": { - "type": "object", - "title": "Custom User", - "description": "Optional user to be created at initialisation with a custom password and database", - "properties": { - "name": { - "type": "string", - "title": "Custom User Name", - "description": "Name of the custom user to be created" + "extraObjects": { + "type": "array" }, - "database": { - "type": "string", - "title": "Custom User Database", - "description": "Name of the database to be created" + "extraVolumeMounts": { + "type": "array" }, - "password": { - "type": "string", - "title": "Custom User Password", - "description": "Password to be used for the custom user" + "extraVolumes": { + "type": "array" }, - "existingSecret": { - "type": "string", - "title": "Custom User Existing Secret", - "description": "Existing secret, in which username, password and database name are saved" + "fullnameOverride": { + "type": "string" }, - "secretKeys": { - "type": "object", - "title": "Custom User Secret Keys", - "description": "Name of keys in existing secret to use the custom user name, password and database", - "properties": { - "name": { - "type": "string", - "title": "Secret Key for User Name", - "description": "Key name in the secret for username" - }, - "password": { - "type": "string", - "title": "Secret Key for Password", - "description": "Key name in the secret for password" - }, - "database": { - "type": "string", - "title": "Secret Key for Database", - "description": "Key name in the secret for database name" + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } } - } - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "MongoDB persistence configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable persistent storage" - }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "Storage class to use for persistent volume" }, - "accessMode": { - "type": "string", - "title": "Access Mode", - "description": "Access mode for persistent volume", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] - }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "Size of persistent volume", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" - }, - "mountPath": { - "type": "string", - "title": "Mount Path", - "description": "Mount path for MongoDB data" + "image": { + "type": "object", + "properties": { + "args": { + "type": "array" + }, + "command": { + "type": "array" + }, + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } }, - "annotations": { - "type": "object", - "title": "Persistence Annotations", - "description": "Annotations for persistent volume claims", - "additionalProperties": { - "type": "string" - } - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource limits and requests for MongoDB pod", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } } - } }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + "metrics": { + "type": "object", + "properties": { + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } + } + }, + "enabled": { + "type": "boolean" + }, + "extraArgs": { + "type": "array" + }, + "extraEnvVars": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "additionalLabels": { + "type": "object" + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "jobLabel": { + "type": "string" + }, + "metricRelabelings": { + "type": "array" + }, + "namespace": { + "type": "string" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + } + } + }, + "username": { + "type": "string" + } } - } - } - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node selector for pod assignment", - "additionalProperties": { - "type": "string" - } - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Tolerations for pod assignment", - "items": { - "type": "object" - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity rules for pod assignment" - }, - "containerSecurityContext": { - "type": "object", - "title": "Container Security Context", - "description": "Security context configuration", - "properties": { - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID to run the container", - "minimum": 0 }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Run as non-root user" + "nameOverride": { + "type": "string" }, - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Set MongoDB container's privilege escalation" - } - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "Security context for the pod", - "properties": { - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Set MongoDB pod's Security Context fsGroup", - "minimum": 0 - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "MongoDB liveness probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable liveness probe" + "networkPolicy": { + "type": "object", + "properties": { + "allowedSources": { + "type": "array" + }, + "enabled": { + "type": "boolean" + } + } }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay before starting probes", - "minimum": 0 + "nodeSelector": { + "type": "object" }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "How often to perform the probe", - "minimum": 1 + "persistence": { + "type": "object", + "properties": { + "accessMode": { + "type": "string" + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout for each probe attempt", - "minimum": 1 + "podAnnotations": { + "type": "object" }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Number of failures before pod is restarted", - "minimum": 1 + "podLabels": { + "type": "object" }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Number of successes to mark probe as successful", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "MongoDB readiness probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readiness probe" + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay before starting probes", - "minimum": 0 + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "How often to perform the probe", - "minimum": 1 + "replicaCount": { + "type": "integer" }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout for each probe attempt", - "minimum": 1 + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Number of failures before pod is marked unready", - "minimum": 1 + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Number of successes to mark probe as successful", - "minimum": 1 + "tolerations": { + "type": "array" } - } - }, - "extraEnv": { - "type": "array", - "title": "Extra Environment Variables", - "description": "Additional environment variables to set", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Variable Name", - "description": "Environment variable name" - }, - "value": { - "type": "string", - "title": "Variable Value", - "description": "Environment variable value" - } - }, - "required": ["name"] - } - }, - "extraVolumes": { - "type": "array", - "title": "Extra Volumes", - "description": "Additional volumes to add to the pod", - "items": { - "type": "object" - } - }, - "extraVolumeMounts": { - "type": "array", - "title": "Extra Volume Mounts", - "description": "Additional volume mounts to add to the MongoDB container", - "items": { - "type": "object" - } - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } -} \ No newline at end of file +} diff --git a/charts/mongodb/values.yaml b/charts/mongodb/values.yaml index 5078e5a2..4fa7c4ba 100644 --- a/charts/mongodb/values.yaml +++ b/charts/mongodb/values.yaml @@ -15,6 +15,11 @@ commonLabels: {} ## @param commonAnnotations Annotations to add to all deployed objects commonAnnotations: {} +## @param podAnnotations Annotations to add to the pod created by the statefulset +podAnnotations: {} +## @param podLabels Labels to add to the pod created by the statefulset +podLabels: {} + ## @section MongoDB image parameters image: ## @param image.registry MongoDB image registry @@ -22,9 +27,13 @@ image: ## @param image.repository MongoDB image repository repository: mongo ## @param image.tag MongoDB image tag - tag: "8.0.15@sha256:41e48e703c413df7befc6aa9f3ac93583d17bc770fe8dd8ea848ef7136c3327f" + tag: "8.2.1@sha256:86835e8da0f94efd61334decb320fa43e8a60027688cbd856bf29d065b470338" ## @param image.pullPolicy MongoDB image pull policy pullPolicy: Always + ## @param image.command Override default container command (useful when using custom images) + command: [] + ## @param image.args Override default container args (useful when using custom images) + args: [] ## @param replicaCount Number of MongoDB replicas to deploy replicaCount: 1 @@ -34,6 +43,8 @@ service: type: ClusterIP ## @param service.port MongoDB service port port: 27017 + ## @param serivce.annotations Annotations to add to the mongodb service + annotations: {} auth: ## @param auth.enabled Enable MongoDB authentication @@ -151,8 +162,15 @@ readinessProbe: ## @param readinessProbe.successThreshold Number of successes to mark probe as successful successThreshold: 1 -## @param extraEnv Additional environment variables to set -extraEnv: [] +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraVolumes Additional volumes to add to the pod extraVolumes: [] @@ -267,7 +285,14 @@ metrics: timeoutSeconds: 5 failureThreshold: 3 successThreshold: 1 - ## @param metrics.extraEnv Additional environment variables for metrics container - extraEnv: [] + ## @param metrics.extraEnvVars Additional environment variables for metrics container + extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param metrics.extraArgs Additional command line arguments for MongoDB Exporter extraArgs: [] diff --git a/charts/nginx/CHANGELOG.md b/charts/nginx/CHANGELOG.md index 75d31268..f4d2d359 100644 --- a/charts/nginx/CHANGELOG.md +++ b/charts/nginx/CHANGELOG.md @@ -1,5 +1,144 @@ # Changelog + +## 0.4.1 (2025-11-07) + +* [nginx]: Add podLabels ([b8d8410](https://github.com/CloudPirates-io/helm-charts/commit/b8d8410)) +* chore: update CHANGELOG.md for merged changes ([40efff1](https://github.com/CloudPirates-io/helm-charts/commit/40efff1)) +* chore: update CHANGELOG.md for merged changes ([e1c0077](https://github.com/CloudPirates-io/helm-charts/commit/e1c0077)) +* chore: auto-generate values.schema.json (#549) ([ac12418](https://github.com/CloudPirates-io/helm-charts/commit/ac12418)) +* chore: update CHANGELOG.md for merged changes ([05acd68](https://github.com/CloudPirates-io/helm-charts/commit/05acd68)) +* chore: update CHANGELOG.md for merged changes ([d909109](https://github.com/CloudPirates-io/helm-charts/commit/d909109)) + +## 0.4.0 (2025-11-04) + +* extraInitContainers (#548) ([686e3e0](https://github.com/CloudPirates-io/helm-charts/commit/686e3e0)) +* chore: update CHANGELOG.md for merged changes ([8dbbdd1](https://github.com/CloudPirates-io/helm-charts/commit/8dbbdd1)) +* chore: update CHANGELOG.md for merged changes ([5d68f20](https://github.com/CloudPirates-io/helm-charts/commit/5d68f20)) +* chore: auto-generate values.schema.json (#529) ([a09c8b1](https://github.com/CloudPirates-io/helm-charts/commit/a09c8b1)) +* chore: update CHANGELOG.md for merged changes ([b9cc0d3](https://github.com/CloudPirates-io/helm-charts/commit/b9cc0d3)) +* chore: update CHANGELOG.md for merged changes ([8d930bc](https://github.com/CloudPirates-io/helm-charts/commit/8d930bc)) + +## 0.3.3 (2025-11-02) + +* [nginx]: Add priorityClassName support (#526) ([e77747f](https://github.com/CloudPirates-io/helm-charts/commit/e77747f)) + +## 0.3.2 (2025-10-30) + +* chore: update CHANGELOG.md for merged changes ([5c6a9eb](https://github.com/CloudPirates-io/helm-charts/commit/5c6a9eb)) +* chore: update CHANGELOG.md for merged changes ([597f2b0](https://github.com/CloudPirates-io/helm-charts/commit/597f2b0)) +* Update charts/nginx/values.yaml nginx (#508) ([60891a1](https://github.com/CloudPirates-io/helm-charts/commit/60891a1)) +* chore: update CHANGELOG.md for merged changes ([28332c1](https://github.com/CloudPirates-io/helm-charts/commit/28332c1)) +* chore: update CHANGELOG.md for merged changes ([16071aa](https://github.com/CloudPirates-io/helm-charts/commit/16071aa)) + +## 0.3.1 (2025-10-29) + +* Update charts/nginx/values.yaml nginx to v1.29.3 (patch) (#490) ([a23c2db](https://github.com/CloudPirates-io/helm-charts/commit/a23c2db)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.3.0 (2025-10-28) + +* chore: auto-generate values.schema.json for updated charts (#455) ([aec6840](https://github.com/CloudPirates-io/helm-charts/commit/aec6840)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.2.1 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([c80ea42](https://github.com/CloudPirates-io/helm-charts/commit/c80ea42)) +* chore: update CHANGELOG.md for merged changes ([8ccb4bb](https://github.com/CloudPirates-io/helm-charts/commit/8ccb4bb)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) + +## 0.2.0 (2025-10-14) + +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* Update charts/nginx/values.yaml nginx (#351) ([d73ca94](https://github.com/CloudPirates-io/helm-charts/commit/d73ca94)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + ## 0.1.14 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* Update charts/nginx/values.yaml nginx to v1.29.2 (patch) (#263) ([b607e10](https://github.com/CloudPirates-io/helm-charts/commit/b607e10)) + +## 0.1.13 (2025-10-08) + +* [nginx/nginx-prometheus-exporter] Update nginx/nginx-prometheus-exporter to v1.5 (#234) ([9f7f1e8](https://github.com/CloudPirates-io/helm-charts/commit/9f7f1e8)) + +## 0.1.12 (2025-10-07) + +* Add prometheus nginx metrics exporter (#224) ([5bf615a](https://github.com/CloudPirates-io/helm-charts/commit/5bf615a)) + +## 0.1.11 (2025-10-01) + +* update containerport documentation (#198) ([f20d6d4](https://github.com/CloudPirates-io/helm-charts/commit/f20d6d4)) +* Changed README.md due to bug (wrong description) (#197) ([84fd116](https://github.com/CloudPirates-io/helm-charts/commit/84fd116)) + +## 0.1.10 (2025-09-30) + +* Fix/nginx used ingress backend port (#190) ([096725e](https://github.com/CloudPirates-io/helm-charts/commit/096725e)) + +## 0.1.9 (2025-09-30) + +* [Zookeeper] [Nginx] Change nginx and zookeeper security-context to use helper-function (#169) ([b581bc7](https://github.com/CloudPirates-io/helm-charts/commit/b581bc7)) + +## 0.1.8 (2025-09-26) + + +## 0.1.7 (2025-09-25) + +* add predefined configmaps (#154) ([82c4bb6](https://github.com/CloudPirates-io/helm-charts/commit/82c4bb6)) + +## 0.1.6 (2025-09-11) + +* Remove redundant single port configurations ([570075b](https://github.com/CloudPirates-io/helm-charts/commit/570075b)) +* default disable cloneStaticSiteFromGit ([3913640](https://github.com/CloudPirates-io/helm-charts/commit/3913640)) +* Fix multi port scenario ([29d3811](https://github.com/CloudPirates-io/helm-charts/commit/29d3811)) +* Update CHANGELOG.md ([72f4eb9](https://github.com/CloudPirates-io/helm-charts/commit/72f4eb9)) +* Bump chart version ([b322d47](https://github.com/CloudPirates-io/helm-charts/commit/b322d47)) +* Implement fix ([7467d22](https://github.com/CloudPirates-io/helm-charts/commit/7467d22)) + +## 0.1.5 (2025-09-10) + +* Update CHANGELOG.md ([84c70d6](https://github.com/CloudPirates-io/helm-charts/commit/84c70d6)) +* Bump chart version ([3e4be77](https://github.com/CloudPirates-io/helm-charts/commit/3e4be77)) +* Update CHANGELOG.md ([32fd09c](https://github.com/CloudPirates-io/helm-charts/commit/32fd09c)) +* Implement static website git clone ([e081eab](https://github.com/CloudPirates-io/helm-charts/commit/e081eab)) + +## 0.1.4 (2025-09-10) + +* Update CHANGELOG.md ([a337490](https://github.com/CloudPirates-io/helm-charts/commit/a337490)) +* fix artifacthub-repo id ([e7a98fc](https://github.com/CloudPirates-io/helm-charts/commit/e7a98fc)) + +## 0.1.3 (2025-09-08) + +* Update CHANGELOG.md ([d0f0153](https://github.com/CloudPirates-io/helm-charts/commit/d0f0153)) +* Update appVersion ([933ba01](https://github.com/CloudPirates-io/helm-charts/commit/933ba01)) +* Update CHANGELOG.md ([4ff2bbc](https://github.com/CloudPirates-io/helm-charts/commit/4ff2bbc)) +* Bump nginx to latest version + alpine ([8b0fc57](https://github.com/CloudPirates-io/helm-charts/commit/8b0fc57)) + +## 0.1.2 (2025-09-08) + +* update chart-icon ([7ed7c8e](https://github.com/CloudPirates-io/helm-charts/commit/7ed7c8e)) +* Update CHANGELOG.md ([a13f40d](https://github.com/CloudPirates-io/helm-charts/commit/a13f40d)) +* bump version to 0.1.2 ([f75a781](https://github.com/CloudPirates-io/helm-charts/commit/f75a781)) +* fix containerport and change ingress host-pathtype ([60e3223](https://github.com/CloudPirates-io/helm-charts/commit/60e3223)) + +## 0.1.1 (2025-09-08) + +* Update CHANGELOG.md ([19e5317](https://github.com/CloudPirates-io/helm-charts/commit/19e5317)) +* add artifacthub-repo id ([ee4f192](https://github.com/CloudPirates-io/helm-charts/commit/ee4f192)) + +## 0.1.0 (2025-09-08) + +* Initial tagged release diff --git a/charts/nginx/Chart.lock b/charts/nginx/Chart.lock index 0193a710..c87029da 100644 --- a/charts/nginx/Chart.lock +++ b/charts/nginx/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-09-26T20:24:47.53804+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:43.283573+02:00" diff --git a/charts/nginx/Chart.yaml b/charts/nginx/Chart.yaml index 75c59b0e..1044e6f8 100644 --- a/charts/nginx/Chart.yaml +++ b/charts/nginx/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: nginx description: Nginx is a high-performance HTTP server and reverse proxy. type: application -version: 0.1.14 -appVersion: "1.29.1" +version: 0.4.1 +appVersion: "1.29.3" keywords: - nginx - web server @@ -11,14 +11,38 @@ keywords: - reverse proxy - load balancer - proxy -home: https://www.cloudpirates.io +home: https://www.nginx.com sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/nginx + - https://github.com/nginx/nginx maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/9fcd98c061/nginx-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: networking + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: Nginx + url: https://www.nginx.com + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/nginx + - name: Application + url: https://github.com/nginx/nginx + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "[nginx]: Add podLabels" + links: + - name: "Commit b8d8410" + url: "https://github.com/CloudPirates-io/helm-charts/commit/b8d8410" diff --git a/charts/nginx/README.md b/charts/nginx/README.md index 5f34019a..30a6dc19 100644 --- a/charts/nginx/README.md +++ b/charts/nginx/README.md @@ -204,6 +204,7 @@ containerPorts: | ---------------- | ---------------------------------------------------------- | ----------- | | `service.type` | Nginx service type | `ClusterIP` | | `service.ports` | Array of service ports (advanced configuration) - see examples | `[]` | +| `service.annotations` | Additional annotations to add to the service | `{}` | #### Service Ports Examples @@ -348,12 +349,13 @@ location /stub_status { ### Extra Configuration Parameters -| Parameter | Description | Default | -| ------------------- | ----------------------------------------------------------------------------------- | ------- | -| `extraEnv` | Additional environment variables to set | `[]` | -| `extraVolumes` | Additional volumes to add to the pod | `[]` | -| `extraVolumeMounts` | Additional volume mounts to add to the Nginx container | `[]` | -| `extraObjects` | Array of extra objects to deploy with the release | `[]` | +| Parameter | Description | Default | +| ---------------------------| ----------------------------------------------------------------------------------- | ------- | +| `extraEnvVars` | Additional environment variables to set | `[]` | +| `extraVolumes` | Additional volumes to add to the pod | `[]` | +| `extraVolumeMounts` | Additional volume mounts to add to the Nginx container | `[]` | +| `extraObjects` | Array of extra objects to deploy with the release | `[]` | +| `extrainitContainers` | Array of extra objects to deploy with the release | `[]` | #### Extra Objects @@ -394,11 +396,12 @@ All objects in `extraObjects` will be rendered and deployed with the release. Yo ### Pod Configuration Parameters -| Parameter | Description | Default | -| ---------------- | ------------------------------ | ------- | -| `nodeSelector` | Node selector for pod assignment| `{}` | -| `tolerations` | Tolerations for pod assignment | `[]` | -| `affinity` | Affinity rules for pod assignment| `{}` | +| Parameter | Description | Default | +| ---------------- | ------------------------------ | ------- | +| `nodeSelector` | Node selector for pod assignment | `{}` | +| `priorityClassName` | Priority class for pod eviction | `""` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `affinity` | Affinity rules for pod assignment | `{}` | ## Examples diff --git a/charts/nginx/ci/test-values.yaml b/charts/nginx/ci/test-values.yaml new file mode 100644 index 00000000..42ed5de8 --- /dev/null +++ b/charts/nginx/ci/test-values.yaml @@ -0,0 +1,62 @@ +# CI test values for nginx chart +# Optimized for faster testing in kind clusters and GitHub Actions + +image: + # Use IfNotPresent to avoid repeated pulls + pullPolicy: IfNotPresent + # Use simple tag without digest for better caching + tag: "1.29.2-alpine" + +# Use non-privileged port for CI environment +containerPorts: + - name: http + containerPort: 8080 + protocol: TCP + +service: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + +# Run as nginx user (101) - non-root +containerSecurityContext: + runAsUser: 101 + runAsNonRoot: true + allowPrivilegeEscalation: false + +podSecurityContext: + fsGroup: 101 + +# Reduce probe delays for faster readiness in tests +readinessProbe: + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 6 + +livenessProbe: + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 6 + +# Minimal resources for kind cluster +resources: + limits: + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + +# Configure nginx to listen on non-privileged port +serverConfig: |- + server { + listen 8080; + server_name _; + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + } diff --git a/charts/nginx/templates/_helpers.tpl b/charts/nginx/templates/_helpers.tpl index f49af7a0..119cc66f 100644 --- a/charts/nginx/templates/_helpers.tpl +++ b/charts/nginx/templates/_helpers.tpl @@ -2,56 +2,56 @@ Expand the name of the chart. */}} {{- define "nginx.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "nginx.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "nginx.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "nginx.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Selector labels */}} {{- define "nginx.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Common annotations */}} {{- define "nginx.annotations" -}} -{{- include "common.annotations" . -}} +{{- include "cloudpirates.annotations" . -}} {{- end }} {{/* Return the proper Nginx image name */}} {{- define "nginx.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "nginx.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* @@ -73,7 +73,7 @@ Return the custom NGINX config configmap. {{- if .Values.existingConfigConfigmap -}} {{- printf "%s" (tpl .Values.existingConfigConfigmap $) -}} {{- else -}} - {{- include "common.fullname" . -}} + {{- include "cloudpirates.fullname" . -}} {{- end -}} {{- end -}} @@ -84,7 +84,7 @@ Return the custom NGINX server config configmap. {{- if .Values.existingServerConfigConfigmap -}} {{- printf "%s" (tpl .Values.existingServerConfigConfigmap $) -}} {{- else -}} - {{- include "common.fullname" . -}} + {{- include "cloudpirates.fullname" . -}} {{- end -}} {{- end -}} @@ -95,7 +95,7 @@ Return the custom NGINX stream server config configmap. {{- if .Values.existingStreamServerConfigConfigmap -}} {{- printf "%s" (tpl .Values.existingStreamServerConfigConfigmap $) -}} {{- else -}} - {{- include "common.fullname" . -}} + {{- include "cloudpirates.fullname" . -}} {{- end -}} {{- end -}} @@ -103,5 +103,5 @@ Return the custom NGINX stream server config configmap. Return the proper Nginx metrics image name */}} {{- define "nginx.metrics.image" -}} -{{- include "common.image" (dict "image" .Values.metrics.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.metrics.image "global" .Values.global) -}} {{- end }} diff --git a/charts/nginx/templates/configmap.yaml b/charts/nginx/templates/configmap.yaml index ea61dc87..737e76a2 100644 --- a/charts/nginx/templates/configmap.yaml +++ b/charts/nginx/templates/configmap.yaml @@ -6,6 +6,10 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "nginx.labels" . | nindent 4 }} + {{- with (include "nginx.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} data: {{- if .Values.config }} nginx.conf: |- diff --git a/charts/nginx/templates/deployment.yaml b/charts/nginx/templates/deployment.yaml index 2e8ecb85..65a7b2a5 100644 --- a/charts/nginx/templates/deployment.yaml +++ b/charts/nginx/templates/deployment.yaml @@ -20,6 +20,10 @@ spec: metadata: labels: {{- include "nginx.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.serverConfig .Values.streamServerConfig (include "nginx.annotations" .) }} annotations: {{- with (include "nginx.annotations" .) }} {{- . | nindent 8 }} @@ -27,14 +31,20 @@ spec: {{- if or .Values.serverConfig .Values.streamServerConfig }} checksum/server-configuration: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} {{- end }} + {{- end }} spec: {{- with (include "nginx.imagePullSecrets" .) }} {{ . | nindent 6 }} {{- end }} serviceAccountName: {{ include "nginx.serviceAccountName" . }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} - {{- if .Values.cloneStaticSiteFromGit.enabled }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} + {{- if or .Values.extraInitContainers .Values.cloneStaticSiteFromGit.enabled }} initContainers: + {{- with .Values.extraInitContainers }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.cloneStaticSiteFromGit.enabled }} - name: git-clone-repository image: "{{ .Values.cloneStaticSiteFromGit.image.registry }}/{{ .Values.cloneStaticSiteFromGit.image.repository }}:{{ .Values.cloneStaticSiteFromGit.image.tag }}" imagePullPolicy: {{ .Values.cloneStaticSiteFromGit.image.pullPolicy }} @@ -72,21 +82,18 @@ spec: {{- end }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "nginx.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} ports: {{- range .Values.containerPorts }} - name: {{ .name }} containerPort: {{ .containerPort }} protocol: {{ .protocol | default "TCP" }} {{- end }} - {{- if .Values.extraEnv }} + {{- with .Values.extraEnvVars }} env: - {{- range .Values.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} - {{- end }} +{{ toYaml . | indent 12 }} {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: @@ -204,9 +211,9 @@ spec: {{- end }} {{- if .Values.metrics.enabled }} - name: metrics - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "nginx.metrics.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.metrics.image) }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.metrics.image) }} command: - nginx-prometheus-exporter - --nginx.scrape-uri=http://localhost:8080/stub_status @@ -302,6 +309,9 @@ spec: affinity: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} diff --git a/charts/nginx/templates/extraobjects.yaml b/charts/nginx/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/nginx/templates/extraobjects.yaml +++ b/charts/nginx/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/nginx/templates/metrics-service.yaml b/charts/nginx/templates/metrics-service.yaml index f30f2f89..d9b9bd89 100644 --- a/charts/nginx/templates/metrics-service.yaml +++ b/charts/nginx/templates/metrics-service.yaml @@ -7,7 +7,8 @@ metadata: labels: {{- include "nginx.labels" . | nindent 4 }} app.kubernetes.io/component: metrics - {{- with .Values.metrics.service.annotations }} + {{- $annotations := merge .Values.metrics.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/nginx/templates/service.yaml b/charts/nginx/templates/service.yaml index 1c3a5a59..207addab 100644 --- a/charts/nginx/templates/service.yaml +++ b/charts/nginx/templates/service.yaml @@ -5,6 +5,11 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "nginx.labels" . | nindent 4 }} + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} ports: diff --git a/charts/nginx/templates/serviceaccount.yaml b/charts/nginx/templates/serviceaccount.yaml index e153c80c..9f4213da 100644 --- a/charts/nginx/templates/serviceaccount.yaml +++ b/charts/nginx/templates/serviceaccount.yaml @@ -6,7 +6,8 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "nginx.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} + {{- $annotations := merge .Values.serviceAccount.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/nginx/templates/servicemonitor.yaml b/charts/nginx/templates/servicemonitor.yaml index 8ae13e8e..45ed11be 100644 --- a/charts/nginx/templates/servicemonitor.yaml +++ b/charts/nginx/templates/servicemonitor.yaml @@ -10,7 +10,8 @@ metadata: {{- with .Values.metrics.serviceMonitor.selector }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.metrics.serviceMonitor.annotations }} + {{- $annotations := merge .Values.metrics.serviceMonitor.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/nginx/values.schema.json b/charts/nginx/values.schema.json index 3b3f44bb..02d5e213 100644 --- a/charts/nginx/values.schema.json +++ b/charts/nginx/values.schema.json @@ -1,316 +1,497 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "Nginx Helm Chart Values Schema", - "description": "Schema for Nginx Helm chart values", - "properties": { - "global": { - "type": "object", - "properties": { - "imageRegistry": { "type": "string" }, - "imagePullSecrets": { - "type": "array", - "items": { - "type": ["string", "object"], + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "autoscaling": { + "type": "object", "properties": { - "name": { "type": "string" } - }, - "required": ["name"] - } - } - } - }, - "nameOverride": { "type": "string" }, - "fullnameOverride": { "type": "string" }, - "commonLabels": { "type": "object", "additionalProperties": { "type": "string" } }, - "commonAnnotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "image": { - "type": "object", - "description": "NGINX image configuration", - "properties": { - "registry": { "type": "string" }, - "repository": { "type": "string" }, - "tag": { "type": "string" }, - "pullPolicy": { "type": "string", "enum": ["Always", "IfNotPresent", "Never"] } - } - }, - "replicaCount": { "type": "integer", "minimum": 1 }, - "containerPort": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "containerPorts": { - "type": "array", - "description": "List of container ports", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "containerPort": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "protocol": { "type": "string", "enum": ["TCP", "UDP"], "default": "TCP" } - }, - "required": ["name", "containerPort"] - } - }, - "service": { - "type": "object", - "properties": { - "type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer"] }, - "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "ports": { - "type": "array", - "items": { + "enabled": { + "type": "boolean" + }, + "maxReplicas": { + "type": "string" + }, + "minReplicas": { + "type": "string" + }, + "targetCPUUtilizationPercentage": { + "type": "string" + }, + "targetMemoryUtilizationPercentage": { + "type": "string" + } + } + }, + "cloneStaticSiteFromGit": { "type": "object", "properties": { - "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "targetPort": { "type": "string" }, - "protocol": { "type": "string", "enum": ["TCP", "UDP"], "default": "TCP" }, - "name": { "type": "string" } - }, - "required": ["port", "targetPort", "name"] - } - } - } - }, - "ingress": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "className": { "type": "string" }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "hosts": { - "type": "array", - "items": { + "branch": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "extraEnvVars": { + "type": "array" + }, + "extraEnvVarsSecret": { + "type": "string" + }, + "extraVolumeMounts": { + "type": "array" + }, + "gitClone": { + "type": "object", + "properties": { + "args": { + "type": "array" + }, + "command": { + "type": "array" + } + } + }, + "gitSync": { + "type": "object", + "properties": { + "args": { + "type": "array" + }, + "command": { + "type": "array" + }, + "resources": { + "type": "object" + }, + "resourcesPreset": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "digest": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + }, + "pullSecrets": { + "type": "array" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "interval": { + "type": "integer" + }, + "repository": { + "type": "string" + } + } + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { + "type": "string" + }, + "containerPorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "containerPort": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "type": "string" + } + } + } + }, + "containerSecurityContext": { "type": "object", "properties": { - "host": { "type": "string" }, - "paths": { - "type": "array", - "items": { - "type": "object", - "properties": { - "path": { "type": "string" }, - "pathType": { "type": "string" } - }, - "required": ["path", "pathType"] + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" } - } - }, - "required": ["host", "paths"] - } - }, - "tls": { - "type": "array", - "items": { + } + }, + "existingConfigConfigmap": { + "type": "string" + }, + "existingServerConfigConfigmap": { + "type": "string" + }, + "existingStreamServerConfigConfigmap": { + "type": "string" + }, + "extraEnvVars": { + "type": "array" + }, + "extraInitContainers": { + "type": "array" + }, + "extraObjects": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "global": { "type": "object", "properties": { - "hosts": { "type": "array", "items": { "type": "string" } }, - "secretName": { "type": "string" } + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } } - } - } - } - }, - "serviceAccount": { - "type": "object", - "properties": { - "create": { "type": "boolean" }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "name": { "type": "string" }, - "automountServiceAccountToken": { "type": "boolean" } - } - }, - "autoscaling": { - "type": "object", - "description": "Autoscaling configuration", - "properties": { - "enabled": { "type": "boolean" }, - "minReplicas": { "type": ["integer", "string"] }, - "maxReplicas": { "type": ["integer", "string"] }, - "targetCPUUtilizationPercentage": { "type": ["integer", "string"] }, - "targetMemoryUtilizationPercentage": { "type": ["integer", "string"] } - } - }, - "resources": { - "type": "object", - "description": "Resource requests and limits" - }, - "nodeSelector": { - "type": "object", - "description": "Node selector for pod scheduling", - "additionalProperties": { "type": "string" } - }, - "tolerations": { - "type": "array", - "description": "Tolerations for pod scheduling", - "items": { "type": "object" } - }, - "affinity": { - "type": "object", - "description": "Affinity rules for pod scheduling" - }, - "containerSecurityContext": { - "type": "object", - "description": "Container-level security context settings", - "properties": { - "runAsUser": { "type": "integer" }, - "runAsNonRoot": { "type": "boolean" }, - "allowPrivilegeEscalation": { "type": "boolean" } - } - }, - "podSecurityContext": { - "type": "object", - "description": "Pod-level security context settings", - "properties": { - "fsGroup": { "type": "integer" } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "type": { "type": "string", "enum": ["tcpSocket", "httpGet"], "default": "tcpSocket" }, - "path": { "type": "string", "default": "/" }, - "initialDelaySeconds": { "type": "integer" }, - "periodSeconds": { "type": "integer" }, - "timeoutSeconds": { "type": "integer" }, - "failureThreshold": { "type": "integer" }, - "successThreshold": { "type": "integer" } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "type": { "type": "string", "enum": ["tcpSocket", "httpGet"], "default": "tcpSocket" }, - "path": { "type": "string", "default": "/" }, - "initialDelaySeconds": { "type": "integer" }, - "periodSeconds": { "type": "integer" }, - "timeoutSeconds": { "type": "integer" }, - "failureThreshold": { "type": "integer" }, - "successThreshold": { "type": "integer" } - } - }, - "extraEnv": { - "type": "array", - "description": "Extra environment variables", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "value": { "type": "string" } - }, - "required": ["name", "value"] - } - }, - "extraVolumes": { - "type": "array", - "description": "Additional volumes", - "items": { "type": "object" } - }, - "extraVolumeMounts": { - "type": "array", - "description": "Additional volume mounts", - "items": { "type": "object" } - }, - "extraObjects": { "type": "array", "items": { "type": "object" } }, - "config": { - "type": "string", - "description": "Custom NGINX configuration" - }, - "existingConfigConfigmap": { - "type": "string", - "description": "Name of existing ConfigMap for NGINX config" - }, - "serverConfig": { - "type": "string", - "description": "Custom server configuration" - }, - "existingServerConfigConfigmap": { - "type": "string", - "description": "Name of existing ConfigMap for server config" - }, - "streamServerConfig": { - "type": "string", - "description": "Custom stream server configuration" - }, - "existingStreamServerConfigmap": { - "type": "string", - "description": "Name of existing ConfigMap for stream server config" - }, - "serviceAccountName": { - "type": "string", - "description": "Service account name for the pod" - }, - "metrics": { - "type": "object", - "description": "Prometheus metrics configuration", - "properties": { - "enabled": { - "type": "boolean", - "description": "Start a sidecar prometheus exporter to expose Nginx metrics" }, "image": { - "type": "object", - "description": "Nginx exporter image configuration", - "properties": { - "registry": { "type": "string" }, - "repository": { "type": "string" }, - "tag": { "type": "string" }, - "pullPolicy": { "type": "string" } - } + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } }, - "resources": { - "type": "object", - "description": "Resource limits and requests for metrics container", - "properties": { - "limits": { - "type": "object", - "properties": { - "memory": { "type": "string" } - } - }, - "requests": { - "type": "object", - "properties": { - "cpu": { "type": "string" }, - "memory": { "type": "string" } - } + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } } - } }, - "extraArgs": { - "type": "array", - "description": "Extra arguments for nginx exporter", - "items": { "type": "string" } + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "extraArgs": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "clusterIP": { + "type": "string" + }, + "loadBalancerIP": { + "type": "string" + }, + "loadBalancerSourceRanges": { + "type": "array" + }, + "nodePort": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "metricRelabelings": { + "type": "array" + }, + "namespace": { + "type": "string" + }, + "namespaceSelector": { + "type": "object" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + }, + "selector": { + "type": "object" + } + } + } + } + }, + "nameOverride": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "priorityClassName": { + "type": "string" + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "serverConfig": { + "type": "string" }, "service": { - "type": "object", - "description": "Metrics service configuration", - "properties": { - "type": { "type": "string" }, - "port": { "type": "integer" }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "loadBalancerIP": { "type": "string" }, - "loadBalancerSourceRanges": { "type": "array", "items": { "type": "string" } }, - "clusterIP": { "type": "string" }, - "nodePort": { "type": "string" } - } - }, - "serviceMonitor": { - "type": "object", - "description": "Prometheus ServiceMonitor configuration", - "properties": { - "enabled": { "type": "boolean" }, - "namespace": { "type": "string" }, - "interval": { "type": "string" }, - "scrapeTimeout": { "type": "string" }, - "relabelings": { "type": "array", "items": { "type": "object" } }, - "metricRelabelings": { "type": "array", "items": { "type": "object" } }, - "honorLabels": { "type": "boolean" }, - "selector": { "type": "object", "additionalProperties": { "type": "string" } }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "namespaceSelector": { "type": "object", "additionalProperties": { "type": "string" } } - } + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "targetPort": { + "type": "string" + } + } + } + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "streamServerConfig": { + "type": "string" + }, + "tolerations": { + "type": "array" } - } } - } } diff --git a/charts/nginx/values.yaml b/charts/nginx/values.yaml index c4d2093c..87319db3 100644 --- a/charts/nginx/values.yaml +++ b/charts/nginx/values.yaml @@ -14,6 +14,8 @@ fullnameOverride: "" commonLabels: {} ## @param commonAnnotations Annotations to add to all deployed objects commonAnnotations: {} +## @param podLabels Additional labels to add to pods (e.g. for Istio sidecar injection) +podLabels: {} ## @section Nginx image parameters image: @@ -22,7 +24,7 @@ image: ## @param image.repository Nginx image repository repository: nginx ## @param image.tag Nginx image tag - tag: "1.29.2-alpine@sha256:7c1b9a91514d1eb5288d7cd6e91d9f451707911bfaea9307a3acbc811d4aa82e" + tag: "1.29.3-alpine@sha256:b3c656d55d7ad751196f21b7fd2e8d4da9cb430e32f646adcf92441b72f82b14" ## @param image.pullPolicy Nginx image pull policy pullPolicy: Always @@ -63,6 +65,8 @@ service: targetPort: http protocol: TCP name: http + ## @param service.annotations Additional annotations to add to the service + annotations: {} ## @section Ingress parameters ingress: @@ -142,6 +146,13 @@ cloneStaticSiteFromGit: ## @param cloneStaticSiteFromGit.extraEnvVars Additional environment variables for Git containers extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param cloneStaticSiteFromGit.extraEnvVarsSecret Secret with extra environment variables extraEnvVarsSecret: "" @@ -165,6 +176,9 @@ resources: ## @param nodeSelector Node selector for pod assignment nodeSelector: {} +## @param priorityClassName for pod eviction +priorityClassName: "" + ## @param tolerations Tolerations for pod assignment tolerations: [] @@ -220,10 +234,15 @@ readinessProbe: ## @param readinessProbe.successThreshold Number of successes to mark probe as successful successThreshold: 1 -## @param extraEnv Additional environment variables to set -extraEnv: [] -# - name: EXTRA_VAR -# value: "extra_value" +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraVolumes Additional volumes to add to the pod extraVolumes: [] @@ -359,3 +378,6 @@ streamServerConfig: "" ## @param existingStreamServerConfigmap Name of an existing ConfigMap containing stream-server-config.conf existingStreamServerConfigConfigmap: "" + +## @param extraInitContainers Additional init containers to add to the pod +extraInitContainers: [] diff --git a/charts/postgres/CHANGELOG.md b/charts/postgres/CHANGELOG.md index 293dc579..c87909f9 100644 --- a/charts/postgres/CHANGELOG.md +++ b/charts/postgres/CHANGELOG.md @@ -1,5 +1,235 @@ # Changelog + +## 0.11.5 (2025-11-07) + +* Config for NodePort port (#561) ([bae2da0](https://github.com/CloudPirates-io/helm-charts/commit/bae2da0)) +* chore: update CHANGELOG.md for merged changes ([6e6ea47](https://github.com/CloudPirates-io/helm-charts/commit/6e6ea47)) +* chore: update CHANGELOG.md for merged changes ([63e0c74](https://github.com/CloudPirates-io/helm-charts/commit/63e0c74)) + +## 0.11.4 (2025-11-05) + +* chore: update CHANGELOG.md for merged changes ([b41d586](https://github.com/CloudPirates-io/helm-charts/commit/b41d586)) +* Fix logic in init-scripts ConfigMap (#551) ([90d61df](https://github.com/CloudPirates-io/helm-charts/commit/90d61df)) + +## 0.11.3 (2025-11-04) + +* chore: update CHANGELOG.md for merged changes ([8a36fa3](https://github.com/CloudPirates-io/helm-charts/commit/8a36fa3)) +* chore: update CHANGELOG.md for merged changes ([4b10ac6](https://github.com/CloudPirates-io/helm-charts/commit/4b10ac6)) +* Update charts/postgres/values.yaml postgres (#546) ([cd62d69](https://github.com/CloudPirates-io/helm-charts/commit/cd62d69)) + +## 0.11.2 (2025-11-04) + +* chore: update CHANGELOG.md for merged changes ([d18a69d](https://github.com/CloudPirates-io/helm-charts/commit/d18a69d)) +* chore: update CHANGELOG.md for merged changes ([19c8331](https://github.com/CloudPirates-io/helm-charts/commit/19c8331)) +* Update charts/postgres/values.yaml postgres (#541) ([a94dd22](https://github.com/CloudPirates-io/helm-charts/commit/a94dd22)) +* chore: update CHANGELOG.md for merged changes ([332f709](https://github.com/CloudPirates-io/helm-charts/commit/332f709)) +* chore: update CHANGELOG.md for merged changes ([e72bc46](https://github.com/CloudPirates-io/helm-charts/commit/e72bc46)) + +## 0.11.1 (2025-10-31) + +* [postgres]: fix nesting for auth.username & auth.secretKeys.passwordKey (#513) ([7692045](https://github.com/CloudPirates-io/helm-charts/commit/7692045)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.11.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([9be549e](https://github.com/CloudPirates-io/helm-charts/commit/9be549e)) +* chore: update CHANGELOG.md for merged changes ([2bd99d3](https://github.com/CloudPirates-io/helm-charts/commit/2bd99d3)) + +## 0.10.7 (2025-10-27) + +* add options to set service load balancer ip and external traffic policy (#475) ([a2db2ab](https://github.com/CloudPirates-io/helm-charts/commit/a2db2ab)) + +## 0.10.6 (2025-10-27) + +* chore: update CHANGELOG.md for merged changes ([099c280](https://github.com/CloudPirates-io/helm-charts/commit/099c280)) +* chore: update CHANGELOG.md for merged changes ([bcb63d1](https://github.com/CloudPirates-io/helm-charts/commit/bcb63d1)) +* Mount config map when existing configmap is provided (#472) ([f5d08a5](https://github.com/CloudPirates-io/helm-charts/commit/f5d08a5)) +* chore: update CHANGELOG.md for merged changes ([953c05c](https://github.com/CloudPirates-io/helm-charts/commit/953c05c)) +* chore: update CHANGELOG.md for merged changes ([9788604](https://github.com/CloudPirates-io/helm-charts/commit/9788604)) + +## 0.10.5 (2025-10-26) + +* Update charts/postgres/values.yaml postgres (#451) ([45d78b0](https://github.com/CloudPirates-io/helm-charts/commit/45d78b0)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.10.4 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([5ea39c2](https://github.com/CloudPirates-io/helm-charts/commit/5ea39c2)) +* chore: update CHANGELOG.md for merged changes ([1426e0a](https://github.com/CloudPirates-io/helm-charts/commit/1426e0a)) + +## 0.10.3 (2025-10-23) + +* Update charts/postgres/values.yaml postgres (#448) ([fdf19cf](https://github.com/CloudPirates-io/helm-charts/commit/fdf19cf)) +* chore: update CHANGELOG.md for merged changes ([06f9425](https://github.com/CloudPirates-io/helm-charts/commit/06f9425)) +* chore: update CHANGELOG.md for merged changes ([9d439f0](https://github.com/CloudPirates-io/helm-charts/commit/9d439f0)) + +## 0.10.2 (2025-10-22) + +* Update charts/postgres/values.yaml postgres (#426) ([ae72190](https://github.com/CloudPirates-io/helm-charts/commit/ae72190)) +* chore: update CHANGELOG.md for merged changes ([4587534](https://github.com/CloudPirates-io/helm-charts/commit/4587534)) +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.10.1 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([8aef3d0](https://github.com/CloudPirates-io/helm-charts/commit/8aef3d0)) +* chore: update CHANGELOG.md for merged changes ([a24446b](https://github.com/CloudPirates-io/helm-charts/commit/a24446b)) + +## 0.10.0 (2025-10-14) + +* Add support for `extraVolumes` and `extraVolumeMounts` (#387) ([ed17601](https://github.com/CloudPirates-io/helm-charts/commit/ed17601)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.9.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.8.3 (2025-10-13) + + +## 0.8.2 (2025-10-12) + +* fix: add connection details to secret (#350) ([066d248](https://github.com/CloudPirates-io/helm-charts/commit/066d248)) + +## 0.8.1 (2025-10-10) + +* merged initscript to avoid mount error, fixed quote from preloadlibrary and ajusted custom mount for init scripts (#297) ([e49d478](https://github.com/CloudPirates-io/helm-charts/commit/e49d478)) + +## 0.8.0 (2025-10-09) + +* feat: add metrics exporter (#285) ([b9ba642](https://github.com/CloudPirates-io/helm-charts/commit/b9ba642)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + ## 0.7.3 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* [postgres]: Init container implementation (#246) ([054112b](https://github.com/CloudPirates-io/helm-charts/commit/054112b)) +* [minio, mongodb, postgres, timescaledb] Update securityContext to containerSecurityContext in the values schema (#213) ([8a4003f](https://github.com/CloudPirates-io/helm-charts/commit/8a4003f)) + +## 0.7.2 (2025-10-02) + +* chore(deps): update docker.io/postgres:18.0 Docker digest to 073e7c8 (#172) ([f4b12f4](https://github.com/CloudPirates-io/helm-charts/commit/f4b12f4)) + +## 0.7.1 (2025-10-02) + +* implement support for existingClaim (#212) ([805d3f8](https://github.com/CloudPirates-io/helm-charts/commit/805d3f8)) + +## 0.7.0 (2025-09-30) + +* make postgres run on openshift (#184) ([0396895](https://github.com/CloudPirates-io/helm-charts/commit/0396895)) + +## 0.6.1 (2025-09-29) + +* update default postgres config files (#180) ([6385512](https://github.com/CloudPirates-io/helm-charts/commit/6385512)) +* [postgres]: Default config (#163) ([fc0da25](https://github.com/CloudPirates-io/helm-charts/commit/fc0da25)) + +## 0.6.0 (2025-09-26) + +* No changes recorded + +## 0.5.5 (2025-09-29) + +* [postgres]: Default config (#163) ([fc0da25](https://github.com/CloudPirates-io/helm-charts/commit/fc0da25)) +* [postgres]: Fix invalid data dir path on postgres 18 (#165) ([7592892](https://github.com/CloudPirates-io/helm-charts/commit/7592892)) + +## 0.5.4 (2025-09-26) + +* chore(deps): update docker.io/postgres:17.6 Docker digest to 0b6428e (#161) ([1946296](https://github.com/CloudPirates-io/helm-charts/commit/1946296)) + +## 0.5.3 (2025-09-25) + +* support custom pg_hba.conf (#157) ([9f3ceea](https://github.com/CloudPirates-io/helm-charts/commit/9f3ceea)) + +## 0.5.2 (2025-09-24) + +* Update CHANGELOG.md ([7749beb](https://github.com/CloudPirates-io/helm-charts/commit/7749beb)) +* bump chart version to 0.5.2 ([8c80572](https://github.com/CloudPirates-io/helm-charts/commit/8c80572)) +* bump chart version to 0.5.3 ([337480c](https://github.com/CloudPirates-io/helm-charts/commit/337480c)) +* Update CHANGELOG.md ([b1ce7c7](https://github.com/CloudPirates-io/helm-charts/commit/b1ce7c7)) +* Update CHANGELOG.md ([7df85ea](https://github.com/CloudPirates-io/helm-charts/commit/7df85ea)) +* fix: Change default name for CUSTOM_PASSWORD ([f7e74dd](https://github.com/CloudPirates-io/helm-charts/commit/f7e74dd)) + +## 0.5.1 (2025-09-24) + +* Update CHANGELOG.md ([3ac9592](https://github.com/CloudPirates-io/helm-charts/commit/3ac9592)) +* Update CHANGELOG.md ([574c9dc](https://github.com/CloudPirates-io/helm-charts/commit/574c9dc)) +* Bump chart version ([2907796](https://github.com/CloudPirates-io/helm-charts/commit/2907796)) +* chore(deps): update docker.io/postgres:17.6 Docker digest to 0f4f200 ([6f0746a](https://github.com/CloudPirates-io/helm-charts/commit/6f0746a)) +* Update CHANGELOG.md ([9c7f377](https://github.com/CloudPirates-io/helm-charts/commit/9c7f377)) + +## 0.5.0 (2025-09-18) + +* Update CHANGELOG.md ([ee72020](https://github.com/CloudPirates-io/helm-charts/commit/ee72020)) +* add support for custom user at initialisation with password and database ([62d9d0d](https://github.com/CloudPirates-io/helm-charts/commit/62d9d0d)) + +## 0.4.0 (2025-09-16) + +* add support for extra env vars from secret ([f6bb0dc](https://github.com/CloudPirates-io/helm-charts/commit/f6bb0dc)) + +## 0.3.0 (2025-09-16) + +* Update CHANGELOG.md ([8baa18d](https://github.com/CloudPirates-io/helm-charts/commit/8baa18d)) +* bump chartversion to 0.3.0 ([9e0454c](https://github.com/CloudPirates-io/helm-charts/commit/9e0454c)) +* update env-vars, initialisation values, remove unused auth values ([11a6947](https://github.com/CloudPirates-io/helm-charts/commit/11a6947)) +* Update CHANGELOG.md ([3e90557](https://github.com/CloudPirates-io/helm-charts/commit/3e90557)) +* fix admin postgres-password env-variable ([7b89fa4](https://github.com/CloudPirates-io/helm-charts/commit/7b89fa4)) + +## 0.2.8 (2025-09-15) + +* bump postgres ([4cc47f2](https://github.com/CloudPirates-io/helm-charts/commit/4cc47f2)) +* chore: add support for passing extra environment variables ([0951fdc](https://github.com/CloudPirates-io/helm-charts/commit/0951fdc)) + +## 0.2.7 (2025-09-15) + +* chore: add support for db initialization scripts ([96c8215](https://github.com/CloudPirates-io/helm-charts/commit/96c8215)) + +## 0.2.6 (2025-09-15) + +* chore: bump version ([33105e9](https://github.com/CloudPirates-io/helm-charts/commit/33105e9)) +* chore: add support for persistentVolumeClaimRetentionPolicy ([2f73cfb](https://github.com/CloudPirates-io/helm-charts/commit/2f73cfb)) + +## 0.2.5 (2025-09-10) + +* Update CHANGELOG.md ([65522d2](https://github.com/CloudPirates-io/helm-charts/commit/65522d2)) +* Bump chart version ([9bd67d6](https://github.com/CloudPirates-io/helm-charts/commit/9bd67d6)) +* chore(deps): update docker.io/postgres:17.6 Docker digest to feff5b2 ([8b89eda](https://github.com/CloudPirates-io/helm-charts/commit/8b89eda)) + +## 0.2.4 (2025-09-09) + +* Update CHANGELOG.md ([0a89918](https://github.com/CloudPirates-io/helm-charts/commit/0a89918)) +* bump chart version ([fc9c564](https://github.com/CloudPirates-io/helm-charts/commit/fc9c564)) +* chore(deps): update docker.io/postgres:17.6 Docker digest to 8a56bef ([3546801](https://github.com/CloudPirates-io/helm-charts/commit/3546801)) + +## 0.2.3 (2025-09-09) + +* Update CHANGELOG.md ([b82862d](https://github.com/CloudPirates-io/helm-charts/commit/b82862d)) +* Bump chart version ([492acc9](https://github.com/CloudPirates-io/helm-charts/commit/492acc9)) +* Update docker.io/postgres:17.6 Docker digest to 29574e2 ([1226760](https://github.com/CloudPirates-io/helm-charts/commit/1226760)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.2.2 (2025-08-27) + +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.2.1 (2025-08-26) + +* added support for service account configuration (#15) ([541a9df](https://github.com/CloudPirates-io/helm-charts/commit/541a9df)) + +## 0.2.0 (2025-08-26) + +* Initial tagged release diff --git a/charts/postgres/Chart.lock b/charts/postgres/Chart.lock index bf9ce6cd..aca78bdc 100644 --- a/charts/postgres/Chart.lock +++ b/charts/postgres/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-09-29T21:42:58.149716+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:49.235251+02:00" diff --git a/charts/postgres/Chart.yaml b/charts/postgres/Chart.yaml index dec518d6..0d5d7b75 100644 --- a/charts/postgres/Chart.yaml +++ b/charts/postgres/Chart.yaml @@ -2,22 +2,48 @@ apiVersion: v2 name: postgres description: The World's Most Advanced Open Source Relational Database type: application -version: 0.8.0 -appVersion: "18.0" +version: 0.11.5 +appVersion: "18.0.0" keywords: - postgres - postgresql - database - sql - relational -home: https://www.cloudpirates.io +home: https://www.postgresql.org sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/postgres + - https://github.com/postgres/postgres maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/95e7f13e62/postgres-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: PostgreSQL + url: https://www.postgresql.org + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/postgres + - name: Application + url: https://github.com/postgres/postgres + - name: Docker Image + url: https://hub.docker.com/_/postgres + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Config for NodePort port (#561)" + links: + - name: "Commit bae2da0" + url: "https://github.com/CloudPirates-io/helm-charts/commit/bae2da0" diff --git a/charts/postgres/LICENSE b/charts/postgres/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/charts/postgres/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/postgres/README.md b/charts/postgres/README.md index e2be8f60..6839fbfe 100644 --- a/charts/postgres/README.md +++ b/charts/postgres/README.md @@ -155,12 +155,15 @@ The following table lists the configurable parameters of the PostgreSQL chart an ### Service configuration -| Parameter | Description | Default | -| --------------------- | ------------------------- | ----------- | -| `service.type` | PostgreSQL service type | `ClusterIP` | -| `service.port` | PostgreSQL service port | `5432` | -| `service.targetPort` | PostgreSQL container port | `5432` | -| `service.annotations` | Service annotations | `{}` | +| Parameter | Description | Default | +|---------------------------------|-----------------------------------------------------------------------------------|-------------| +| `service.type` | PostgreSQL service type | `ClusterIP` | +| `service.port` | PostgreSQL service port | `5432` | +| `service.targetPort` | PostgreSQL container port | `5432` | +| `service.nodePort` | PostgreSQL NodePort port | `30432` | +| `service.annotations` | Service annotations | `{}` | +| `service.loadBalancerIP` | Load balancer IP (applies if service type is `LoadBalancer`) | `""` | +| `service.externalTrafficPolicy` | External traffic policy (applies if service type is `LoadBalancer` or `NodePort`) | `Cluster` | ### Ingress configuration @@ -239,16 +242,13 @@ The following table lists the configurable parameters of the PostgreSQL chart an | `serviceAccount.name` | The name of the service account to use. If not set and create is true, a name is generated using the `fullname` template. | `""` | | `serviceAccount.automountServiceAccountToken` | Whether to automount the SA token inside the pod | `false` | -### Extra Environment - -| Parameter | Description | Default | -| ---------- | ----------------------------------------------------- | ------- | -| `extraEnv` | Additional environment variables from key-value pairs | `{}` | - ### Extra Configuration Parameters | Parameter | Description | Default | | -------------------- | ---------------------------------------------------------------------- | ------- | +| `extraEnvVars` | Additional environment variables to set | `[]` | +| `extraVolumes` | Additional volumes to add to the pod | `[]` | +| `extraVolumeMounts` | Additional volume mounts to add to the MongoDB container | `[]` | | `extraObjects` | Array of extra objects to deploy with the release | `[]` | | `extraEnvVarsSecret` | Name of an existing Secret containing additional environment variables | `` | diff --git a/charts/postgres/templates/_helpers.tpl b/charts/postgres/templates/_helpers.tpl index 6a78d6b5..3f9955df 100644 --- a/charts/postgres/templates/_helpers.tpl +++ b/charts/postgres/templates/_helpers.tpl @@ -2,7 +2,7 @@ Expand the name of the chart. */}} {{- define "postgres.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* @@ -11,21 +11,21 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "postgres.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "postgres.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "postgres.labels" -}} -{{- include "common.labels" . -}} +{{- include "cloudpirates.labels" . -}} {{- end }} {{/* @@ -41,14 +41,14 @@ Common annotations Selector labels */}} {{- define "postgres.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Return the proper PostgreSQL image name */}} {{- define "postgres.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* @@ -56,7 +56,7 @@ Return PostgreSQL credentials secret name */}} {{- define "postgres.secretName" -}} {{- if .Values.auth.existingSecret -}} - {{- .Values.auth.existingSecret -}} + {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) -}} {{- else -}} {{- include "postgres.fullname" . -}} {{- end -}} @@ -137,7 +137,7 @@ Get PostgreSQL username */}} {{- define "postgres.username" -}} {{- if .Values.auth.username -}} -{{- .Values.auth.username -}} +{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.username "context" .) -}} {{- else -}} postgres {{- end -}} @@ -147,7 +147,7 @@ postgres Return the proper Docker Image Registry Secret Names */}} {{- define "postgres.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* diff --git a/charts/postgres/templates/configmap.yaml b/charts/postgres/templates/configmap.yaml index 9dc963c4..32a085c5 100644 --- a/charts/postgres/templates/configmap.yaml +++ b/charts/postgres/templates/configmap.yaml @@ -97,7 +97,7 @@ data: log_min_error_statement = error {{- if .Values.config.postgresqlLogStatement }} - log_statement = {{ .Values.config.postgresqlLogStatement | quote }} + log_statement = {{ .Values.config.postgresqlLogStatement | squote }} {{- else }} log_statement = 'none' {{- end }} @@ -110,7 +110,7 @@ data: # Shared Libraries {{- if .Values.config.postgresqlSharedPreloadLibraries }} - shared_preload_libraries = {{ .Values.config.postgresqlSharedPreloadLibraries | quote }} + shared_preload_libraries = {{ .Values.config.postgresqlSharedPreloadLibraries | squote }} {{- end }} # Locale and Formatting diff --git a/charts/postgres/templates/extraobjects.yaml b/charts/postgres/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/postgres/templates/extraobjects.yaml +++ b/charts/postgres/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/postgres/templates/init-custom-user-configmap.yaml b/charts/postgres/templates/init-custom-user-configmap.yaml deleted file mode 100644 index 997fde0b..00000000 --- a/charts/postgres/templates/init-custom-user-configmap.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- if and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-init-custom-user" (include "postgres.fullname" .) }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "postgres.labels" . | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: - {{- include "postgres.annotations" . | nindent 4 }} - {{- end }} -data: - init-custom-user.sh: | - #!/bin/sh - - if [ -z "$CUSTOM_DB" ] && [ -z "$CUSTOM_USER" ] && [ -z "$CUSTOM_PASSWORD" ]; then - exit 1 - fi - - set -e - - psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -v DATABASENAME="$CUSTOM_DB" -v USERNAME="$CUSTOM_USER" -v PASSWORD="'$CUSTOM_PASSWORD'" <<-EOSQL - CREATE USER :USERNAME WITH PASSWORD :PASSWORD; - CREATE DATABASE :DATABASENAME; - GRANT ALL PRIVILEGES ON DATABASE :DATABASENAME TO :USERNAME; - ALTER DATABASE :DATABASENAME OWNER TO :USERNAME; - EOSQL -{{- end }} diff --git a/charts/postgres/templates/initialization-configmap.yaml b/charts/postgres/templates/initialization-configmap.yaml index e4681a80..5ca626b2 100644 --- a/charts/postgres/templates/initialization-configmap.yaml +++ b/charts/postgres/templates/initialization-configmap.yaml @@ -1,4 +1,6 @@ -{{- if and .Values.initdb.scripts (not .Values.initdb.scriptsConfigMap) }} +{{- $createCustomUser := and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret) }} +{{- $appendInitdbScripts := and .Values.initdb.scripts (not .Values.initdb.scriptsConfigMap) }} +{{- if or $createCustomUser $appendInitdbScripts }} apiVersion: v1 kind: ConfigMap metadata: @@ -10,5 +12,29 @@ metadata: annotations: {{- include "postgres.annotations" . | nindent 4 }} {{- end }} -data: {{- include "common.tplvalues.render" (dict "value" .Values.initdb.scripts "context" .) | nindent 2 }} -{{- end }} +data: + {{- if $createCustomUser }} + 00-init-custom-user.sh: | + #!/bin/sh + + if [ -z "$CUSTOM_DB" ] && [ -z "$CUSTOM_USER" ] && [ -z "$CUSTOM_PASSWORD" ]; then + echo "No custom user configuration found, skipping..." + exit 0 + fi + + set -e + echo "Creating custom user: $CUSTOM_USER and database: $CUSTOM_DB" + + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -v DATABASENAME="$CUSTOM_DB" -v USERNAME="$CUSTOM_USER" -v PASSWORD="'$CUSTOM_PASSWORD'" <<-EOSQL + CREATE USER :USERNAME WITH PASSWORD :PASSWORD; + CREATE DATABASE :DATABASENAME; + GRANT ALL PRIVILEGES ON DATABASE :DATABASENAME TO :USERNAME; + ALTER DATABASE :DATABASENAME OWNER TO :USERNAME; + EOSQL + + echo "โœ… Custom user and database created successfully!" + {{- end }} + {{- if $appendInitdbScripts }} + {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.initdb.scripts "context" .) | nindent 2 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/postgres/templates/secret.yaml b/charts/postgres/templates/secret.yaml index 50b3b201..4cbbef3d 100644 --- a/charts/postgres/templates/secret.yaml +++ b/charts/postgres/templates/secret.yaml @@ -17,5 +17,15 @@ data: {{- if and $existingSecret $existingSecret.data }} {{- $existingPostgresPassword = index $existingSecret.data "postgres-password" }} {{- end }} - postgres-password: {{ $existingPostgresPassword | default (.Values.auth.password | default (randAlphaNum 32) | b64enc) | quote }} -{{- end }} \ No newline at end of file + {{- $postgresPassword := $existingPostgresPassword | default (.Values.auth.password | default (randAlphaNum 32) | b64enc) }} + {{- $host := printf "%s.%s.svc" (include "postgres.fullname" .) .Release.Namespace }} + {{- $port := .Values.service.port | toString }} + {{- $username := include "postgres.username" . }} + {{- $database := include "postgres.database" . }} + postgres-password: {{ $postgresPassword | quote }} + host: {{ $host | b64enc | quote }} + port: {{ $port | b64enc | quote }} + username: {{ $username | b64enc | quote }} + database: {{ $database | b64enc | quote }} + uri: {{ printf "postgresql://%s:%s@%s:%s/%s" $username ($postgresPassword | b64dec) $host $port $database | b64enc | quote }} +{{- end }} diff --git a/charts/postgres/templates/service-metrics.yaml b/charts/postgres/templates/service-metrics.yaml index 94c4d68e..af5e461b 100644 --- a/charts/postgres/templates/service-metrics.yaml +++ b/charts/postgres/templates/service-metrics.yaml @@ -10,7 +10,8 @@ metadata: {{- with .Values.metrics.service.labels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.metrics.service.annotations }} + {{- $annotations := merge .Values.metrics.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/postgres/templates/service.yaml b/charts/postgres/templates/service.yaml index 562bc7b7..ad340039 100644 --- a/charts/postgres/templates/service.yaml +++ b/charts/postgres/templates/service.yaml @@ -12,9 +12,18 @@ metadata: {{- end }} spec: type: {{ .Values.service.type }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if and (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")) (not (empty .Values.service.externalTrafficPolicy)) }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} + {{- end }} ports: - port: {{ .Values.service.port }} targetPort: {{ .Values.service.targetPort }} + {{- if and ( or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") ) (.Values.service.nodePort) }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} protocol: TCP name: postgresql selector: @@ -41,4 +50,4 @@ spec: protocol: TCP name: postgresql selector: - {{- include "postgres.selectorLabels" . | nindent 4 }} \ No newline at end of file + {{- include "postgres.selectorLabels" . | nindent 4 }} diff --git a/charts/postgres/templates/serviceaccount.yaml b/charts/postgres/templates/serviceaccount.yaml index 47b2013e..0467784f 100644 --- a/charts/postgres/templates/serviceaccount.yaml +++ b/charts/postgres/templates/serviceaccount.yaml @@ -6,7 +6,8 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "postgres.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} + {{- $annotations := merge .Values.serviceAccount.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/postgres/templates/servicemonitor.yaml b/charts/postgres/templates/servicemonitor.yaml index daa3e237..0ab7f4b9 100644 --- a/charts/postgres/templates/servicemonitor.yaml +++ b/charts/postgres/templates/servicemonitor.yaml @@ -14,7 +14,8 @@ metadata: {{- with .Values.metrics.serviceMonitor.selector }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.metrics.serviceMonitor.annotations }} + {{- $annotations := merge .Values.metrics.serviceMonitor.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/postgres/templates/statefulset.yaml b/charts/postgres/templates/statefulset.yaml index 422e14a0..5ea54be3 100644 --- a/charts/postgres/templates/statefulset.yaml +++ b/charts/postgres/templates/statefulset.yaml @@ -32,16 +32,16 @@ spec: serviceAccountName: {{ include "postgres.serviceAccountName" . }} automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} {{- with (include "postgres.imagePullSecrets" .) }} -{{ . | nindent 6 }} +{{- . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} {{- if .Values.initContainers }} initContainers: {{- toYaml .Values.initContainers | nindent 8 }} {{- end }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "postgres.image" . }} imagePullPolicy: {{ .Values.image.imagePullPolicy }} args: @@ -56,7 +56,7 @@ spec: {{- end }} {{- if .Values.auth.username }} - name: POSTGRES_USER - value: {{ .Values.auth.username | quote }} + value: {{ include "postgres.username" .}} {{- end }} {{- if .Values.auth.database }} - name: POSTGRES_DB @@ -66,7 +66,7 @@ spec: valueFrom: secretKeyRef: name: {{ include "postgres.secretName" . }} - key: {{ .Values.auth.secretKeys.passwordKey }} + key: "{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.secretKeys.passwordKey "context" .) -}}" {{- if .Values.config.postgresqlMaxConnections }} - name: POSTGRES_MAX_CONNECTIONS value: {{ .Values.config.postgresqlMaxConnections | quote }} @@ -79,16 +79,15 @@ spec: - name: POSTGRES_EFFECTIVE_CACHE_SIZE value: {{ .Values.config.postgresqlEffectiveCacheSize | quote }} {{- end }} - {{- range $key, $value := .Values.extraEnv }} - - name: {{ $key }} - value: {{ $value | quote }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} {{- end }} {{- if and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret) }} - name: CUSTOM_DB valueFrom: secretKeyRef: {{- if .Values.customUser.existingSecret }} - name: {{ .Values.customUser.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.customUser.existingSecret "context" $) }} {{- else }} name: {{ include "postgres.custom-user-configname" . }} {{- end }} @@ -101,7 +100,7 @@ spec: valueFrom: secretKeyRef: {{- if .Values.customUser.existingSecret }} - name: {{ .Values.customUser.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.customUser.existingSecret "context" $) }} {{- else }} name: {{ include "postgres.custom-user-configname" . }} {{- end }} @@ -114,7 +113,7 @@ spec: valueFrom: secretKeyRef: {{- if .Values.customUser.existingSecret }} - name: {{ .Values.customUser.existingSecret }} + name: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.customUser.existingSecret "context" $) }} {{- else }} name: {{ include "postgres.custom-user-configname" . }} {{- end }} @@ -180,22 +179,18 @@ spec: volumeMounts: - name: data mountPath: {{ include "postgres.dataDir" . }} - {{- if not .Values.config.existingConfigmap }} - name: config mountPath: {{ include "postgres.configDir" . }} - {{- end }} - name: run mountPath: {{ include "postgres.runDir" . }} - name: tmp mountPath: /tmp - {{- if or .Values.initdb.scriptsConfigMap .Values.initdb.scripts }} + {{- if or .Values.initdb.scriptsConfigMap .Values.initdb.scripts (and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret)) }} - name: custom-init-scripts - mountPath: /docker-entrypoint-initdb.d/ + mountPath: {{ .Values.initdb.directory }} {{- end }} - {{- if and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret) }} - - name: init-custom-user - mountPath: /docker-entrypoint-initdb.d/init-custom-user.sh - subPath: init-custom-user.sh + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} {{- if .Values.metrics.enabled }} - name: metrics @@ -218,7 +213,7 @@ spec: valueFrom: secretKeyRef: name: {{ include "postgres.secretName" . }} - key: {{ .Values.auth.secretKeys.passwordKey }} + key: "{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.secretKeys.passwordKey "context" .) -}}" ports: - name: metrics containerPort: 9187 @@ -250,28 +245,22 @@ spec: persistentVolumeClaim: claimName: {{ .Values.persistence.existingClaim }} {{- end }} - {{- if not .Values.config.existingConfigmap }} - name: config configMap: name: {{ include "postgres.configmapName" . }} optional: true - {{- end }} - name: run emptyDir: {} - name: tmp emptyDir: {} - {{- if or .Values.initdb.scriptsConfigMap .Values.initdb.scripts }} + {{- if or .Values.initdb.scriptsConfigMap .Values.initdb.scripts (and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret)) }} - name: custom-init-scripts configMap: name: {{ include "postgres.initdb.scriptsCM" . }} + defaultMode: 0755 {{- end }} - {{- if and .Values.customUser (or .Values.customUser.name .Values.customUser.existingSecret) }} - - name: init-custom-user - configMap: - name: {{ printf "%s-init-custom-user" (include "postgres.fullname" .) }} - items: - - key: init-custom-user.sh - path: init-custom-user.sh + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} {{- end }} {{- with .Values.nodeSelector }} nodeSelector: diff --git a/charts/postgres/values.schema.json b/charts/postgres/values.schema.json index 09391a67..0d251e29 100644 --- a/charts/postgres/values.schema.json +++ b/charts/postgres/values.schema.json @@ -1,757 +1,481 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "PostgreSQL Helm Chart Values Schema", - "description": "Schema for PostgreSQL Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global Parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker Image registry" - }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "image": { - "type": "object", - "title": "PostgreSQL Image Configuration", - "description": "PostgreSQL container image configuration", - "properties": { - "registry": { - "type": "string", - "title": "PostgreSQL Image Registry", - "description": "PostgreSQL image registry" - }, - "repository": { - "type": "string", - "title": "PostgreSQL Image Repository", - "description": "PostgreSQL image repository" - }, - "tag": { - "type": "string", - "title": "PostgreSQL Image Tag", - "description": "PostgreSQL image tag with digest" - }, - "imagePullPolicy": { - "type": "string", - "title": "PostgreSQL Image Pull Policy", - "description": "PostgreSQL image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] - } - } - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of PostgreSQL replicas to deploy (Note: PostgreSQL doesn't support multi-master replication by default)", - "minimum": 1 - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override postgres.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override postgres.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "podAnnotations": { - "type": "object", - "title": "Pod Annotations", - "description": "Map of annotations to add to the pods", - "additionalProperties": { - "type": "string" - } - }, - "podLabels": { - "type": "object", - "title": "Pod Labels", - "description": "Map of labels to add to the pods", - "additionalProperties": { - "type": "string" - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "Security Context configuration", - "properties": { - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Group ID for the volumes of the pod", - "minimum": 0 - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "Security Context", - "description": "Container security context", - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Enable container privilege escalation" - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Configure the container to run as a non-root user" - }, - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID for the PostgreSQL container", - "minimum": 0 - }, - "runAsGroup": { - "type": "integer", - "title": "Run As Group", - "description": "Group ID for the PostgreSQL container", - "minimum": 0 - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "title": "Read-Only Root Filesystem", - "description": "Mount container root filesystem as read-only" - }, - "capabilities": { - "type": "object", - "title": "Capabilities", - "description": "Linux capabilities configuration", - "properties": { - "drop": { - "type": "array", - "title": "Drop Capabilities", - "description": "Linux capabilities to be dropped", - "items": { - "type": "string" - } + "database": { + "type": "string" + }, + "existingSecret": { + "type": "string" + }, + "password": { + "type": "string" + }, + "secretKeys": { + "type": "object", + "properties": { + "passwordKey": { + "type": "string" + } + } + }, + "username": { + "type": "string" + } } - } - } - } - }, - "auth": { - "type": "object", - "title": "PostgreSQL Authentication", - "description": "PostgreSQL Authentication configuration", - "properties": { - "username": { - "type": "string", - "title": "Custom Username", - "description": "Name for a custom user to create" - }, - "password": { - "type": "string", - "title": "Custom Password", - "description": "Password for the custom user to create" - }, - "database": { - "type": "string", - "title": "Custom Database", - "description": "Name for a custom database to create" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret to use for PostgreSQL credentials" - }, - "secretKeys": { - "type": "object", - "title": "Secret Keys", - "description": "Keys in existing secret", - "properties": { - "passwordKey": { - "type": "string", - "title": "Postgres Password Key", - "description": "Name of key in existing secret to use for PostgreSQL credentials" + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { + "type": "object", + "properties": { + "existingConfigmap": { + "type": "string" + }, + "extraConfig": { + "type": "array" + }, + "pgHbaConfig": { + "type": "string" + }, + "postgresqlCheckpointCompletionTarget": { + "type": "string" + }, + "postgresqlEffectiveCacheSize": { + "type": "string" + }, + "postgresqlLogMinDurationStatement": { + "type": "string" + }, + "postgresqlLogStatement": { + "type": "string" + }, + "postgresqlMaintenanceWorkMem": { + "type": "string" + }, + "postgresqlMaxConnections": { + "type": "integer" + }, + "postgresqlRandomPageCost": { + "type": "string" + }, + "postgresqlSharedBuffers": { + "type": "string" + }, + "postgresqlSharedPreloadLibraries": { + "type": "string" + }, + "postgresqlWalBuffers": { + "type": "string" + }, + "postgresqlWorkMem": { + "type": "string" + } } - } - } - } - }, - "config": { - "type": "object", - "title": "PostgreSQL Configuration", - "description": "PostgreSQL Configuration parameters", - "properties": { - "postgresqlSharedPreloadLibraries": { - "type": "string", - "title": "Shared Preload Libraries", - "description": "Shared preload libraries (comma-separated list)" - }, - "postgresqlMaxConnections": { - "type": "integer", - "title": "Max Connections", - "description": "Maximum number of connections", - "minimum": 1 - }, - "postgresqlSharedBuffers": { - "type": "string", - "title": "Shared Buffers", - "description": "Amount of memory the database server uses for shared memory buffers" - }, - "postgresqlEffectiveCacheSize": { - "type": "string", - "title": "Effective Cache Size", - "description": "Effective cache size" - }, - "postgresqlWorkMem": { - "type": "string", - "title": "Work Memory", - "description": "Amount of memory to be used by internal sort operations and hash tables" - }, - "postgresqlMaintenanceWorkMem": { - "type": "string", - "title": "Maintenance Work Memory", - "description": "Maximum amount of memory to be used by maintenance operations" - }, - "postgresqlWalBuffers": { - "type": "string", - "title": "WAL Buffers", - "description": "Amount of memory used in shared memory for WAL data" - }, - "postgresqlCheckpointCompletionTarget": { - "type": "string", - "title": "Checkpoint Completion Target", - "description": "Time spent flushing dirty buffers during checkpoint, as fraction of checkpoint interval" - }, - "postgresqlRandomPageCost": { - "type": "string", - "title": "Random Page Cost", - "description": "Sets the planner's estimate of the cost of a non-sequentially-fetched disk page" - }, - "postgresqlLogStatement": { - "type": "string", - "title": "Log Statement", - "description": "Sets the type of statements logged" - }, - "postgresqlLogMinDurationStatement": { - "type": "string", - "title": "Log Min Duration Statement", - "description": "Sets the minimum execution time above which statements will be logged" - }, - "extraConfig": { - "type": "array", - "title": "Extra Configuration", - "description": "Additional PostgreSQL configuration parameters", - "items": { - "type": "string" - } }, - "existingConfigmap": { - "type": "string", - "title": "Existing ConfigMap", - "description": "Name of existing ConfigMap with PostgreSQL configuration" - } - } - }, - "initdb": { - "type": "object", - "title": "PostgreSQL Initdb Configuration", - "description": "PostgreSQL Initdb Configuration parameters", - "properties": { - "args": { - "type": "string", - "title": "Initdb Arguments", - "description": "Send arguments to postgres initdb. This is a space separated string of arguments" - }, - "scripts": { - "type": "object", - "title": "Initdb Scripts", - "description": "Dictionary of scripts to be run at first boot", - "additionalProperties": { - "type": "string" - } + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } + } }, - "scriptsConfigMap": { - "type": "string", - "title": "Initdb Scripts ConfigMap", - "description": "ConfigMap with scripts to be run at first boot" - } - } - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "Service configuration parameters", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "PostgreSQL service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "PostgreSQL service port", - "minimum": 1, - "maximum": 65535 - }, - "targetPort": { - "type": "integer", - "title": "Target Port", - "description": "PostgreSQL container port", - "minimum": 1, - "maximum": 65535 - }, - "annotations": { - "type": "object", - "title": "Service Annotations", - "description": "Service annotations", - "additionalProperties": { + "customUser": { + "type": "object" + }, + "extraEnvVars": { + "type": "array" + }, + "extraEnvVarsSecret": { "type": "string" - } - } - } - }, - "ingress": { - "type": "object", - "title": "Ingress Configuration", - "description": "Ingress configuration parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Ingress", - "description": "Enable ingress record generation for PostgreSQL" - }, - "className": { - "type": "string", - "title": "Ingress Class Name", - "description": "IngressClass that will be used to implement the Ingress" - }, - "annotations": { - "type": "object", - "title": "Ingress Annotations", - "description": "Additional annotations for the Ingress resource", - "additionalProperties": { + }, + "extraObjects": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "fullnameOverride": { "type": "string" - } }, - "hosts": { - "type": "array", - "title": "Ingress Hosts", - "description": "Ingress hosts configuration", - "items": { + "global": { "type": "object", "properties": { - "host": { - "type": "string", - "title": "Host", - "description": "Hostname for PostgreSQL ingress" - }, - "paths": { - "type": "array", - "title": "Paths", - "description": "Paths configuration for the host", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "title": "Path", - "description": "Path for PostgreSQL ingress" - }, - "pathType": { - "type": "string", - "title": "Path Type", - "description": "Path type for PostgreSQL ingress", - "enum": ["Exact", "Prefix", "ImplementationSpecific"] + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } } - } + }, + "tls": { + "type": "array" } - } } - } }, - "tls": { - "type": "array", - "title": "TLS Configuration", - "description": "TLS configuration for PostgreSQL ingress", - "items": { + "initContainers": { + "type": "array" + }, + "initdb": { "type": "object", "properties": { - "secretName": { - "type": "string", - "title": "Secret Name", - "description": "Name of the secret containing TLS certificates" - }, - "hosts": { - "type": "array", - "title": "TLS Hosts", - "description": "List of hosts covered by the TLS certificate", - "items": { - "type": "string" + "args": { + "type": "string" + }, + "directory": { + "type": "string" + }, + "scripts": { + "type": "object" + }, + "scriptsConfigMap": { + "type": "string" } - } } - } - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource configuration parameters", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "port": { + "type": "integer" + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "metricRelabelings": { + "type": "array" + }, + "namespace": { + "type": "string" + }, + "namespaceSelector": { + "type": "object" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + }, + "selector": { + "type": "object" + } + } + } } - } - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "Persistence configuration parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable persistence using Persistent Volume Claims" - }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "Persistent Volume storage class" - }, - "annotations": { - "type": "object", - "title": "PVC Annotations", - "description": "Persistent Volume Claim annotations", - "additionalProperties": { - "type": "string" - } - }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "Persistent Volume size", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" - }, - "accessModes": { - "type": "array", - "title": "Access Modes", - "description": "Persistent Volume access modes", - "items": { - "type": "string", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] - } - }, - "existingClaim": { - "type": "string", - "title": "Existing Claim", - "description": "The name of an existing PVC to use for persistence" - } - } - }, - "persistentVolumeClaimRetentionPolicy": { - "type": "object", - "title": "Persistent Volume Claim Retention Policy Configuration", - "description": "Persistent Volume Claim Retention Policy configuration parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistent volume retention policy", - "description": "Enable Persistent volume retention policy for the Statefulset" - }, - "whenDeleted": { - "type": "string", - "title": "whenDeleted Volume retention behavior", - "description": "Volume retention behavior that applies when the StatefulSet is deleted", - "enum": ["Delete", "Retain"] - }, - "whenScaled": { - "type": "string", - "title": "whenScaled Volume retention behavior", - "description": "Volume retention behavior when the replica count of the StatefulSet is reduced", - "enum": ["Delete", "Retain"] - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "Liveness and readiness probes configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable livenessProbe on PostgreSQL containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for livenessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for livenessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for livenessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for livenessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for livenessProbe", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "Readiness probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readinessProbe on PostgreSQL containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for readinessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for readinessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for readinessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for readinessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for readinessProbe", - "minimum": 1 - } - } - }, - "startupProbe": { - "type": "object", - "title": "Startup Probe Configuration", - "description": "Startup probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Startup Probe", - "description": "Enable startupProbe on PostgreSQL containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for startupProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for startupProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for startupProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for startupProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for startupProbe", - "minimum": 1 - } - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node labels for pod assignment", - "additionalProperties": { - "type": "string" - } - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Toleration labels for pod assignment", - "items": { - "type": "object" - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity settings for pod assignment" - }, - "serviceAccount": { - "type": "object", - "title": "Service Account Configuration", - "description": "Service account configuration", - "properties": { - "create": { - "type": "boolean", - "title": "Create Service Account", - "description": "Specifies whether a service account should be created" - }, - "annotations": { - "type": "object", - "title": "Service Account Annotations", - "description": "Annotations to add to the service account", - "additionalProperties": { + }, + "nameOverride": { "type": "string" - } }, - "name": { - "type": "string", - "title": "Service Account Name", - "description": "The name of the service account to use. If not set and create is true, a name is generated using the `fullname` template." + "nodeSelector": { + "type": "object" + }, + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "persistentVolumeClaimRetentionPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "whenDeleted": { + "type": "string" + }, + "whenScaled": { + "type": "string" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "nodePort": { + "type": "integer" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "automountServiceAccountToken": { - "type": "boolean", - "title": "Automount Service Account Token", - "description": "Whether to automount the service account token inside the pod" + "tolerations": { + "type": "array" } - } - }, - "extraEnv": { - "type": "object", - "title": "Extra Environment", - "description": "Additional environment variables from key-value pairs", - "additionalProperties": { - "type": "string" - } - }, - "extraEnvVarsSecret": { - "type": "string", - "title": "Extra Environment Secret", - "description": "Name of an existing Secret containing additional environment variables" - }, - "initContainers": { - "type": "array", - "title": "Init Containers", - "description": "Init containers to add to the PostgreSQL pods. Useful for tasks like pgautoupgrade for major version upgrades", - "items": { - "type": "object", - "description": "A Kubernetes init container specification. All fields are allowed." - } - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } } diff --git a/charts/postgres/values.yaml b/charts/postgres/values.yaml index ff72266c..3c88106b 100644 --- a/charts/postgres/values.yaml +++ b/charts/postgres/values.yaml @@ -22,7 +22,7 @@ image: ## @param image.repository PostgreSQL image repository repository: postgres ## @param image.tag PostgreSQL image tag (immutable tags are recommended) - tag: "18.0@sha256:073e7c8b84e2197f94c8083634640ab37105effe1bc853ca4d5fbece3219b0e8" + tag: "18.0@sha256:6f3e42ad37decc037c508dd405f5941c6dfa7d21f21a7237a43bde9def1e295e" ## @param image.imagePullPolicy PostgreSQL image pull policy imagePullPolicy: Always @@ -126,6 +126,8 @@ initdb: scripts: {} ## @param initdb.scriptsConfigMap ConfigMap with scripts to be run at first boot scriptsConfigMap: "" + ## @param initdb.directory Directory where to load initScripts + directory: "/docker-entrypoint-initdb.d/" ## @section Service configuration service: @@ -135,6 +137,8 @@ service: port: 5432 ## @param service.targetPort PostgreSQL container port targetPort: 5432 + ## @param service.nodePort PostgreSQL NodePort port + nodePort: 30432 ## @param service.annotations Service annotations annotations: {} @@ -266,14 +270,25 @@ serviceAccount: ## @param serviceAccount.automountServiceAccountToken whether to automount the SA token inside the pod automountServiceAccountToken: false -## @param extraEnv Additional environment variables from key-value pairs -extraEnv: {} -# VARNAME1: value1 -# VARNAME2: value2 +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraEnvVarsSecret Name of a secret containing additional environment variables extraEnvVarsSecret: "" +## @param extraVolumes Additional volumes to add to the pod +extraVolumes: [] + +## @param extraVolumeMounts Additional volume mounts to add to the MongoDB container +extraVolumeMounts: [] + ## @param initContainers Init containers to add to the PostgreSQL pods. Useful for tasks like pgautoupgrade for major version upgrades initContainers: [] # Example with pgautoupgrade for major version upgrades: diff --git a/charts/rabbitmq/CHANGELOG.md b/charts/rabbitmq/CHANGELOG.md index 3727b45d..06165a4c 100644 --- a/charts/rabbitmq/CHANGELOG.md +++ b/charts/rabbitmq/CHANGELOG.md @@ -1,118 +1,293 @@ # Changelog + +## 0.7.6 (2025-11-01) + +* Update charts/rabbitmq/values.yaml rabbitmq (#523) ([a23a731](https://github.com/CloudPirates-io/helm-charts/commit/a23a731)) +* chore: update CHANGELOG.md for merged changes ([b03d341](https://github.com/CloudPirates-io/helm-charts/commit/b03d341)) +* chore: update CHANGELOG.md for merged changes ([c4dd853](https://github.com/CloudPirates-io/helm-charts/commit/c4dd853)) + +## 0.7.5 (2025-10-30) + +* Update charts/rabbitmq/values.yaml rabbitmq (#509) ([532e1f5](https://github.com/CloudPirates-io/helm-charts/commit/532e1f5)) +* chore: update CHANGELOG.md for merged changes ([a914ea9](https://github.com/CloudPirates-io/helm-charts/commit/a914ea9)) +* chore: update CHANGELOG.md for merged changes ([4cac53b](https://github.com/CloudPirates-io/helm-charts/commit/4cac53b)) + +## 0.7.4 (2025-10-30) + +* chore: update CHANGELOG.md for merged changes ([1c809bd](https://github.com/CloudPirates-io/helm-charts/commit/1c809bd)) +* chore: update CHANGELOG.md for merged changes ([9640776](https://github.com/CloudPirates-io/helm-charts/commit/9640776)) + +## 0.7.3 (2025-10-29) + +* Update charts/rabbitmq/values.yaml rabbitmq to v4.2.0 (minor) (#480) ([dcef8f3](https://github.com/CloudPirates-io/helm-charts/commit/dcef8f3)) +* chore: update CHANGELOG.md for merged changes ([ca11524](https://github.com/CloudPirates-io/helm-charts/commit/ca11524)) +* chore: update CHANGELOG.md for merged changes ([33ed0c0](https://github.com/CloudPirates-io/helm-charts/commit/33ed0c0)) + +## 0.7.2 (2025-10-29) + +* chore: update CHANGELOG.md for merged changes ([0e3dfef](https://github.com/CloudPirates-io/helm-charts/commit/0e3dfef)) +* chore: update CHANGELOG.md for merged changes ([a3e93a0](https://github.com/CloudPirates-io/helm-charts/commit/a3e93a0)) +* Update charts/rabbitmq/values.yaml rabbitmq to v4.1.5 (patch) (#479) ([090a6b0](https://github.com/CloudPirates-io/helm-charts/commit/090a6b0)) +* chore: update CHANGELOG.md for merged changes ([0ef2300](https://github.com/CloudPirates-io/helm-charts/commit/0ef2300)) +* chore: update CHANGELOG.md for merged changes ([170dd6a](https://github.com/CloudPirates-io/helm-charts/commit/170dd6a)) +* chore: update CHANGELOG.md for merged changes ([9227d83](https://github.com/CloudPirates-io/helm-charts/commit/9227d83)) + +## 0.7.1 (2025-10-28) + +* [etcd, rabbitmq, redis, zookeeper] add signature verification documentation to readme (#476) ([91c7310](https://github.com/CloudPirates-io/helm-charts/commit/91c7310)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.7.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([cb10f6b](https://github.com/CloudPirates-io/helm-charts/commit/cb10f6b)) +* chore: update CHANGELOG.md for merged changes ([ea886c4](https://github.com/CloudPirates-io/helm-charts/commit/ea886c4)) +* chore: auto-generate values.schema.json (#466) ([650333f](https://github.com/CloudPirates-io/helm-charts/commit/650333f)) + +## 0.6.1 (2025-10-26) + +* Redis / Rabbitmq: add lifecyle hooks ([b253776](https://github.com/CloudPirates-io/helm-charts/commit/b253776)) +* chore: update CHANGELOG.md for merged changes ([5eca51e](https://github.com/CloudPirates-io/helm-charts/commit/5eca51e)) +* chore: update CHANGELOG.md for merged changes ([f0b5033](https://github.com/CloudPirates-io/helm-charts/commit/f0b5033)) +* chore: auto-generate values.schema.json (#465) ([217c03d](https://github.com/CloudPirates-io/helm-charts/commit/217c03d)) + +## 0.6.0 (2025-10-26) + +* Adding existing claim as a feature with PVC ([336c4fb](https://github.com/CloudPirates-io/helm-charts/commit/336c4fb)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.5.5 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([4587534](https://github.com/CloudPirates-io/helm-charts/commit/4587534)) +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.5.4 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([07213f3](https://github.com/CloudPirates-io/helm-charts/commit/07213f3)) +* chore: update CHANGELOG.md for merged changes ([7b68267](https://github.com/CloudPirates-io/helm-charts/commit/7b68267)) +* chore: update CHANGELOG.md for merged changes ([f7bbe99](https://github.com/CloudPirates-io/helm-charts/commit/f7bbe99)) + +## 0.5.3 (2025-10-17) + +* Update charts/rabbitmq/values.yaml rabbitmq (#401) ([d364501](https://github.com/CloudPirates-io/helm-charts/commit/d364501)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([02747d9](https://github.com/CloudPirates-io/helm-charts/commit/02747d9)) +* chore: update CHANGELOG.md for merged changes ([7730143](https://github.com/CloudPirates-io/helm-charts/commit/7730143)) + +## 0.5.2 (2025-10-15) + +* chore: update CHANGELOG.md for merged changes ([aa0d9fd](https://github.com/CloudPirates-io/helm-charts/commit/aa0d9fd)) +* chore: update CHANGELOG.md for merged changes ([cb41af3](https://github.com/CloudPirates-io/helm-charts/commit/cb41af3)) + +## 0.5.1 (2025-10-15) + +* rabbitmq - Add labeling to persistent volume claim template (#389) ([6ca30c9](https://github.com/CloudPirates-io/helm-charts/commit/6ca30c9)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.5.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.4.1 (2025-10-13) + + +## 0.4.0 (2025-10-13) + +* [rabbitmq]: Rabbitmq Loging + levels (#355) ([9c661bf](https://github.com/CloudPirates-io/helm-charts/commit/9c661bf)) + +## 0.3.7 (2025-10-13) + +* use the same default readiness probes as bitnami chart (#356) ([5eac28e](https://github.com/CloudPirates-io/helm-charts/commit/5eac28e)) + +## 0.3.6 (2025-10-10) + +* Update charts/rabbitmq/values.yaml rabbitmq (#339) ([1c06f2e](https://github.com/CloudPirates-io/helm-charts/commit/1c06f2e)) +* add traffic distribution and option to source definitions from existingSecret (#334) ([af00fe0](https://github.com/CloudPirates-io/helm-charts/commit/af00fe0)) + +## 0.3.5 (2025-10-10) + +* Update charts/rabbitmq/values.yaml rabbitmq (#321) ([986eff5](https://github.com/CloudPirates-io/helm-charts/commit/986eff5)) + ## 0.3.4 (2025-10-09) -* [redis , rabbitmq]: Add podAnnotations ([#294](https://github.com/CloudPirates-io/helm-charts/pull/294)) +* [redis , rabbitmq]: Add podAnnotations (#294) ([6d78869](https://github.com/CloudPirates-io/helm-charts/commit/6d78869)) -## 0.3.3 (2025-10-09) +## 0.3.3 (2025-10-09) -* [all] add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)), closes [#226](https://github.com/CloudPirates-io/helm-charts/issues/226) -* [mongodb] feat: add metrics exporter (#243) ([c931978](https://github.com/CloudPirates-io/helm-charts/commit/c931978)), closes [#243](https://github.com/CloudPirates-io/helm-charts/issues/243) -* [rabbitmq]: add option to handle definitions via chart (#286) ([5425131](https://github.com/CloudPirates-io/helm-charts/commit/5425131)), closes [#286](https://github.com/CloudPirates-io/helm-charts/issues/286) -* [rabbitmq]: Fix auth disable erlang cookie (#248) ([9abf547](https://github.com/CloudPirates-io/helm-charts/commit/9abf547)), closes [#248](https://github.com/CloudPirates-io/helm-charts/issues/248) +* [rabbitmq]: add option to handle definitions via chart (#286) ([5425131](https://github.com/CloudPirates-io/helm-charts/commit/5425131)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) +* [rabbitmq]: Fix auth disable erlang cookie (#248) ([9abf547](https://github.com/CloudPirates-io/helm-charts/commit/9abf547)) -## 0.3.2 (2025-10-09) +## 0.3.2 (2025-10-09) -* Feature/renovate fix (#256) ([0d364d0](https://github.com/CloudPirates-io/helm-charts/commit/0d364d0)), closes [#256](https://github.com/CloudPirates-io/helm-charts/issues/256) +* Feature/renovate fix (#256) ([0d364d0](https://github.com/CloudPirates-io/helm-charts/commit/0d364d0)) -## 0.3.1 (2025-10-06) +## 0.3.1 (2025-10-06) -* [mariadb] use tpl to return existingConfigMap (#217) ([c7c2f4c](https://github.com/CloudPirates-io/helm-charts/commit/c7c2f4c)), closes [#217](https://github.com/CloudPirates-io/helm-charts/issues/217) -* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 8c31e22 (#204) ([dd82ffe](https://github.com/CloudPirates-io/helm-charts/commit/dd82ffe)), closes [#204](https://github.com/CloudPirates-io/helm-charts/issues/204) +* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 8c31e22 (#204) ([dd82ffe](https://github.com/CloudPirates-io/helm-charts/commit/dd82ffe)) ## 0.3.0 (2025-10-06) -* make rabbitmq run on openshift (#201) ([df4deeb](https://github.com/CloudPirates-io/helm-charts/commit/df4deeb)), closes [#201](https://github.com/CloudPirates-io/helm-charts/issues/201) +* make rabbitmq run on openshift (#201) ([df4deeb](https://github.com/CloudPirates-io/helm-charts/commit/df4deeb)) -## 0.2.13 (2025-10-02) +## 0.2.13 (2025-10-02) -* [busybox] chore(deps): update docker.io/busybox:1.37.0 Docker digest to d82f458 ([a6990a6](https://github.com/CloudPirates-io/helm-charts/commit/a6990a6)) -* Add automatically generated fields to volumeClaimTemplates (#210) ([2c31a43](https://github.com/CloudPirates-io/helm-charts/commit/2c31a43)), closes [#210](https://github.com/CloudPirates-io/helm-charts/issues/210) -* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 0f83c90 ([554ccc0](https://github.com/CloudPirates-io/helm-charts/commit/554ccc0)) -* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 2d92ad8 ([2afff89](https://github.com/CloudPirates-io/helm-charts/commit/2afff89)) -* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 4788f7d ([1bdfe1c](https://github.com/CloudPirates-io/helm-charts/commit/1bdfe1c)) -* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 85cb76f ([9d6e3c5](https://github.com/CloudPirates-io/helm-charts/commit/9d6e3c5)) -* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to ba622d4 ([daeed6a](https://github.com/CloudPirates-io/helm-charts/commit/daeed6a)) -* Update appVersion ([b7d28b0](https://github.com/CloudPirates-io/helm-charts/commit/b7d28b0)) -* Update version ([bb928b4](https://github.com/CloudPirates-io/helm-charts/commit/bb928b4)) -* Bump chart version ([d26f247](https://github.com/CloudPirates-io/helm-charts/commit/d26f247)) -* Bump chart version ([e697ed5](https://github.com/CloudPirates-io/helm-charts/commit/e697ed5)) -* Bump chart version ([9f722c5](https://github.com/CloudPirates-io/helm-charts/commit/9f722c5)) -* Bump chart version ([81827c8](https://github.com/CloudPirates-io/helm-charts/commit/81827c8)) -* Bump chart version ([8e9f211](https://github.com/CloudPirates-io/helm-charts/commit/8e9f211)) -* Bump chart version ([8637a3e](https://github.com/CloudPirates-io/helm-charts/commit/8637a3e)) -* Bump chart version ([2cae2fb](https://github.com/CloudPirates-io/helm-charts/commit/2cae2fb)) -* Bump Chart Version ([2be6653](https://github.com/CloudPirates-io/helm-charts/commit/2be6653)) -* Bump RabbitMQ to latests stable ([14d0222](https://github.com/CloudPirates-io/helm-charts/commit/14d0222)) -* Bump version ([9427e8d](https://github.com/CloudPirates-io/helm-charts/commit/9427e8d)) -* Bump version and sha ([0bf0925](https://github.com/CloudPirates-io/helm-charts/commit/0bf0925)) -* Fix copy rabbitmq plugins ([9d1b0ed](https://github.com/CloudPirates-io/helm-charts/commit/9d1b0ed)) -* Fix erlang cookie copy / access rights ([54c8ab8](https://github.com/CloudPirates-io/helm-charts/commit/54c8ab8)) -* fix unit test ([80eba48](https://github.com/CloudPirates-io/helm-charts/commit/80eba48)) -* Fix YAML syntax in statefulset.yaml ([ee88104](https://github.com/CloudPirates-io/helm-charts/commit/ee88104)) -* Implement fix ([33fecf8](https://github.com/CloudPirates-io/helm-charts/commit/33fecf8)) -* Lintin works? ([0938b7c](https://github.com/CloudPirates-io/helm-charts/commit/0938b7c)) -* Reimplement chown ([d68af5e](https://github.com/CloudPirates-io/helm-charts/commit/d68af5e)) -* Remove incorrectly pushed file ([b03c230](https://github.com/CloudPirates-io/helm-charts/commit/b03c230)) -* Remove ownership change for .erlang.cookie ([723a45c](https://github.com/CloudPirates-io/helm-charts/commit/723a45c)) -* Resolve merge conflicts ([6921f33](https://github.com/CloudPirates-io/helm-charts/commit/6921f33)) +* Add automatically generated fields to volumeClaimTemplates (#210) ([2c31a43](https://github.com/CloudPirates-io/helm-charts/commit/2c31a43)) + +## 0.2.12 (2025-09-24) + +* docs(rabbitmq): update readme ([3006a9e](https://github.com/CloudPirates-io/helm-charts/commit/3006a9e)) +* feat(rabbitmq): fix podLabels ([e5af639](https://github.com/CloudPirates-io/helm-charts/commit/e5af639)) +* feat(rabbitmq): fix podLabels duplication ([ad3a30b](https://github.com/CloudPirates-io/helm-charts/commit/ad3a30b)) +* feat(rabbit): add podLabels ([0bbb86c](https://github.com/CloudPirates-io/helm-charts/commit/0bbb86c)) * Update CHANGELOG.md ([b2893ca](https://github.com/CloudPirates-io/helm-charts/commit/b2893ca)) +* chore: remove commonAnnotation ([2a9c666](https://github.com/CloudPirates-io/helm-charts/commit/2a9c666)) +* chore: fix no new line character at the end of file ([0c4d018](https://github.com/CloudPirates-io/helm-charts/commit/0c4d018)) * Update CHANGELOG.md ([6f9ff21](https://github.com/CloudPirates-io/helm-charts/commit/6f9ff21)) +* chore: fix no new line character at the end of file ([917d39a](https://github.com/CloudPirates-io/helm-charts/commit/917d39a)) +* chore: fix spaces ([a0a3394](https://github.com/CloudPirates-io/helm-charts/commit/a0a3394)) +* feat(rabbitmq): add new values for PDB, RBAC, ServiceAccount and STS ([b1506ca](https://github.com/CloudPirates-io/helm-charts/commit/b1506ca)) +* feat(rabbitmq): add sts podManagementPolicy in value ([4ec745d](https://github.com/CloudPirates-io/helm-charts/commit/4ec745d)) + +## 0.2.11 (2025-09-18) + * Update CHANGELOG.md ([9be9185](https://github.com/CloudPirates-io/helm-charts/commit/9be9185)) +* Bump chart version ([d26f247](https://github.com/CloudPirates-io/helm-charts/commit/d26f247)) * Update CHANGELOG.md ([61e7883](https://github.com/CloudPirates-io/helm-charts/commit/61e7883)) +* Resolve merge conflicts ([6921f33](https://github.com/CloudPirates-io/helm-charts/commit/6921f33)) +* Remove incorrectly pushed file ([b03c230](https://github.com/CloudPirates-io/helm-charts/commit/b03c230)) +* Fix copy rabbitmq plugins ([9d1b0ed](https://github.com/CloudPirates-io/helm-charts/commit/9d1b0ed)) + +## 0.2.10 (2025-09-18) + * Update CHANGELOG.md ([cf7c15e](https://github.com/CloudPirates-io/helm-charts/commit/cf7c15e)) +* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([0545898](https://github.com/CloudPirates-io/helm-charts/commit/0545898)) * Update CHANGELOG.md ([88006d0](https://github.com/CloudPirates-io/helm-charts/commit/88006d0)) * Update CHANGELOG.md ([1b168e6](https://github.com/CloudPirates-io/helm-charts/commit/1b168e6)) +* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([94ff4bd](https://github.com/CloudPirates-io/helm-charts/commit/94ff4bd)) +* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([bfbc729](https://github.com/CloudPirates-io/helm-charts/commit/bfbc729)) +* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([ed381e0](https://github.com/CloudPirates-io/helm-charts/commit/ed381e0)) + +## 0.2.9 (2025-09-18) + * Update CHANGELOG.md ([5df0a6f](https://github.com/CloudPirates-io/helm-charts/commit/5df0a6f)) +* Bump chart version ([e697ed5](https://github.com/CloudPirates-io/helm-charts/commit/e697ed5)) +* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 85cb76f ([9d6e3c5](https://github.com/CloudPirates-io/helm-charts/commit/9d6e3c5)) + +## 0.2.8 (2025-09-17) + * Update CHANGELOG.md ([9354db5](https://github.com/CloudPirates-io/helm-charts/commit/9354db5)) +* working ([0c29e1e](https://github.com/CloudPirates-io/helm-charts/commit/0c29e1e)) + +## 0.2.7 (2025-09-16) + * Update CHANGELOG.md ([cd341c8](https://github.com/CloudPirates-io/helm-charts/commit/cd341c8)) +* Bump chart version ([9f722c5](https://github.com/CloudPirates-io/helm-charts/commit/9f722c5)) + +## 0.2.6 (2025-09-16) + * Update CHANGELOG.md ([6021756](https://github.com/CloudPirates-io/helm-charts/commit/6021756)) +* Bump chart version ([81827c8](https://github.com/CloudPirates-io/helm-charts/commit/81827c8)) +* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 2d92ad8 ([2afff89](https://github.com/CloudPirates-io/helm-charts/commit/2afff89)) + +## 0.2.5 (2025-09-15) + * Update CHANGELOG.md ([622f5c5](https://github.com/CloudPirates-io/helm-charts/commit/622f5c5)) +* Bump Chart Version ([2be6653](https://github.com/CloudPirates-io/helm-charts/commit/2be6653)) +* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 0f83c90 ([554ccc0](https://github.com/CloudPirates-io/helm-charts/commit/554ccc0)) + +## 0.2.4 (2025-09-11) + * Update CHANGELOG.md ([7c4f20f](https://github.com/CloudPirates-io/helm-charts/commit/7c4f20f)) +* Bump chart version ([8e9f211](https://github.com/CloudPirates-io/helm-charts/commit/8e9f211)) +* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to ba622d4 ([daeed6a](https://github.com/CloudPirates-io/helm-charts/commit/daeed6a)) + +## 0.2.3 (2025-09-11) + * Update CHANGELOG.md ([b579d1b](https://github.com/CloudPirates-io/helm-charts/commit/b579d1b)) +* Bump chart version ([8637a3e](https://github.com/CloudPirates-io/helm-charts/commit/8637a3e)) +* chore(deps): update docker.io/rabbitmq:4.1.4-management Docker digest to 4788f7d ([1bdfe1c](https://github.com/CloudPirates-io/helm-charts/commit/1bdfe1c)) + +## 0.2.0 (2025-09-10) + * Update CHANGELOG.md ([7e42a1e](https://github.com/CloudPirates-io/helm-charts/commit/7e42a1e)) +* feat: add support to automatically download and enable 3rd party plugins ([c677de3](https://github.com/CloudPirates-io/helm-charts/commit/c677de3)) + +## 0.1.7 (2025-09-10) + * Update CHANGELOG.md ([0d009c0](https://github.com/CloudPirates-io/helm-charts/commit/0d009c0)) +* fix: add missing @ for sha image reference ([7abe06a](https://github.com/CloudPirates-io/helm-charts/commit/7abe06a)) + +## 0.1.6 (2025-09-10) + * Update CHANGELOG.md ([ab4655e](https://github.com/CloudPirates-io/helm-charts/commit/ab4655e)) +* feat: add securityContext spec for the initContainer ([3c6ca13](https://github.com/CloudPirates-io/helm-charts/commit/3c6ca13)) + +## 0.1.5 (2025-09-10) + * Update CHANGELOG.md ([be6bf34](https://github.com/CloudPirates-io/helm-charts/commit/be6bf34)) +* Bump version and sha ([0bf0925](https://github.com/CloudPirates-io/helm-charts/commit/0bf0925)) * Update CHANGELOG.md ([9112d4b](https://github.com/CloudPirates-io/helm-charts/commit/9112d4b)) +* Bump chart version ([2cae2fb](https://github.com/CloudPirates-io/helm-charts/commit/2cae2fb)) +* Implement fix ([33fecf8](https://github.com/CloudPirates-io/helm-charts/commit/33fecf8)) + +## 0.1.4 (2025-09-09) + * Update CHANGELOG.md ([ac217ce](https://github.com/CloudPirates-io/helm-charts/commit/ac217ce)) +* fix: allow setting a clusterdomain different than the default ([963a8c5](https://github.com/CloudPirates-io/helm-charts/commit/963a8c5)) + +## 0.1.3 (2025-09-09) + +* Reimplement chown ([d68af5e](https://github.com/CloudPirates-io/helm-charts/commit/d68af5e)) +* Remove ownership change for .erlang.cookie ([723a45c](https://github.com/CloudPirates-io/helm-charts/commit/723a45c)) +* Fix YAML syntax in statefulset.yaml ([ee88104](https://github.com/CloudPirates-io/helm-charts/commit/ee88104)) * Update CHANGELOG.md ([5794798](https://github.com/CloudPirates-io/helm-charts/commit/5794798)) +* fix unit test ([80eba48](https://github.com/CloudPirates-io/helm-charts/commit/80eba48)) +* Lintin works? ([0938b7c](https://github.com/CloudPirates-io/helm-charts/commit/0938b7c)) +* Bump version ([9427e8d](https://github.com/CloudPirates-io/helm-charts/commit/9427e8d)) +* Fix erlang cookie copy / access rights ([54c8ab8](https://github.com/CloudPirates-io/helm-charts/commit/54c8ab8)) + +## 0.1.2 (2025-09-08) + * Update CHANGELOG.md ([bcde9db](https://github.com/CloudPirates-io/helm-charts/commit/bcde9db)) * Update CHANGELOG.md ([a0217a1](https://github.com/CloudPirates-io/helm-charts/commit/a0217a1)) +* Update version ([bb928b4](https://github.com/CloudPirates-io/helm-charts/commit/bb928b4)) +* Update appVersion ([b7d28b0](https://github.com/CloudPirates-io/helm-charts/commit/b7d28b0)) * Update CHANGELOG.md ([59ea4e5](https://github.com/CloudPirates-io/helm-charts/commit/59ea4e5)) -* working ([0c29e1e](https://github.com/CloudPirates-io/helm-charts/commit/0c29e1e)) -* docs(rabbitmq): update readme ([3006a9e](https://github.com/CloudPirates-io/helm-charts/commit/3006a9e)) -* feat: add securityContext spec for the initContainer ([3c6ca13](https://github.com/CloudPirates-io/helm-charts/commit/3c6ca13)) -* feat: add support to automatically download and enable 3rd party plugins ([c677de3](https://github.com/CloudPirates-io/helm-charts/commit/c677de3)) -* feat(rabbit): add podLabels ([0bbb86c](https://github.com/CloudPirates-io/helm-charts/commit/0bbb86c)) -* feat(rabbitmq): add new values for PDB, RBAC, ServiceAccount and STS ([b1506ca](https://github.com/CloudPirates-io/helm-charts/commit/b1506ca)) -* feat(rabbitmq): add sts podManagementPolicy in value ([4ec745d](https://github.com/CloudPirates-io/helm-charts/commit/4ec745d)) -* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([0545898](https://github.com/CloudPirates-io/helm-charts/commit/0545898)) -* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([94ff4bd](https://github.com/CloudPirates-io/helm-charts/commit/94ff4bd)) -* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([bfbc729](https://github.com/CloudPirates-io/helm-charts/commit/bfbc729)) -* feat(rabbitmq): add support for extraPorts in Service and StatefulSet ([ed381e0](https://github.com/CloudPirates-io/helm-charts/commit/ed381e0)) -* feat(rabbitmq): fix podLabels ([e5af639](https://github.com/CloudPirates-io/helm-charts/commit/e5af639)) -* feat(rabbitmq): fix podLabels duplication ([ad3a30b](https://github.com/CloudPirates-io/helm-charts/commit/ad3a30b)) -* chore: fix no new line character at the end of file ([0c4d018](https://github.com/CloudPirates-io/helm-charts/commit/0c4d018)) -* chore: fix no new line character at the end of file ([917d39a](https://github.com/CloudPirates-io/helm-charts/commit/917d39a)) -* chore: fix spaces ([a0a3394](https://github.com/CloudPirates-io/helm-charts/commit/a0a3394)) -* chore: remove commonAnnotation ([2a9c666](https://github.com/CloudPirates-io/helm-charts/commit/2a9c666)) -* fix: add missing @ for sha image reference ([7abe06a](https://github.com/CloudPirates-io/helm-charts/commit/7abe06a)) -* fix: allow setting a clusterdomain different than the default ([963a8c5](https://github.com/CloudPirates-io/helm-charts/commit/963a8c5)) +* Bump RabbitMQ to latests stable ([14d0222](https://github.com/CloudPirates-io/helm-charts/commit/14d0222)) -## 0.1.1 (2025-09-08) +## 0.1.1 (2025-09-08) -* Fix erlang.cookie creation ([640e725](https://github.com/CloudPirates-io/helm-charts/commit/640e725)) * Update CHANGELOG.md ([63b1299](https://github.com/CloudPirates-io/helm-charts/commit/63b1299)) +* Fix erlang.cookie creation ([640e725](https://github.com/CloudPirates-io/helm-charts/commit/640e725)) ## 0.1.0 (2025-09-02) -* Fix clustering and metrics configurations ([f571ab3](https://github.com/CloudPirates-io/helm-charts/commit/f571ab3)) -* Fix ingress port and added test ([67ae961](https://github.com/CloudPirates-io/helm-charts/commit/67ae961)) -* Release 0.0.2 ([3f33f07](https://github.com/CloudPirates-io/helm-charts/commit/3f33f07)) -* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) -* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) * bump all chart versions for new extraObjects feature ([aaa57f9](https://github.com/CloudPirates-io/helm-charts/commit/aaa57f9)) -* Fix missing t in tag ([3ba5c21](https://github.com/CloudPirates-io/helm-charts/commit/3ba5c21)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.0.3 (2025-08-27) + * Fix values.yaml / Chart.yaml linting issues ([043c7e0](https://github.com/CloudPirates-io/helm-charts/commit/043c7e0)) -* initial implementation ([549034c](https://github.com/CloudPirates-io/helm-charts/commit/549034c)) +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.0.2 (2025-08-26) + +* Initial tagged release diff --git a/charts/rabbitmq/Chart.lock b/charts/rabbitmq/Chart.lock index 557ca2ec..76807f03 100644 --- a/charts/rabbitmq/Chart.lock +++ b/charts/rabbitmq/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-10-01T21:19:36.926334+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:14:55.100361+02:00" diff --git a/charts/rabbitmq/Chart.yaml b/charts/rabbitmq/Chart.yaml index 59f0c8b8..acc57dcf 100644 --- a/charts/rabbitmq/Chart.yaml +++ b/charts/rabbitmq/Chart.yaml @@ -2,25 +2,46 @@ apiVersion: v2 name: rabbitmq description: A messaging broker that implements the Advanced Message Queuing Protocol (AMQP) type: application -version: 0.3.4 -appVersion: "4.1.4" +version: 0.7.7 +appVersion: "4.2.0" keywords: - rabbitmq - message broker - amqp - messaging - queue -home: https://www.cloudpirates.io +home: https://www.rabbitmq.com sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/rabbitmq -annotations: - category: Message Broker - license: Apache-2.0 + - https://github.com/rabbitmq/rabbitmq-server maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/aa1bd68288/rabbitmq-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: streaming-messaging + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: RabbitMQ + url: https://www.rabbitmq.com + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/rabbitmq + - name: Application + url: https://github.com/rabbitmq/rabbitmq-server + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Update charts/rabbitmq/values.yaml rabbitmq (#523)" + links: + - name: "Commit a23a731" + url: "https://github.com/CloudPirates-io/helm-charts/commit/a23a731" diff --git a/charts/rabbitmq/README.md b/charts/rabbitmq/README.md index cac7c126..523f7be0 100644 --- a/charts/rabbitmq/README.md +++ b/charts/rabbitmq/README.md @@ -12,6 +12,25 @@ A Helm chart for RabbitMQ - A messaging broker that implements the Advanced Mess - Helm 3.2.0+ - PV provisioner support in the underlying infrastructure (if persistence is enabled) +## Security & Signature Verification + +This Helm chart is cryptographically signed with Cosign to ensure authenticity and prevent tampering. + +**Public Key:** + +``` +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7BgqFgKdPtHdXz6OfYBklYwJgGWQ +mZzYz8qJ9r6QhF3NxK8rD2oG7Bk6nHJz7qWXhQoU2JvJdI3Zx9HGpLfKvw== +-----END PUBLIC KEY----- +``` + +To verify the helm chart before installation, copy the public key to the file `cosign.pub` and run cosign: + +```bash +cosign verify --key cosign.pub registry-1.docker.io/cloudpirates/rabbitmq: +``` + ## Installing the Chart To install the chart with the release name `my-rabbitmq`: @@ -38,6 +57,27 @@ $ helm uninstall my-rabbitmq The command removes all the Kubernetes components associated with the chart and deletes the release. +> **Important:** By default, PersistentVolumeClaims (PVCs) are **NOT** deleted when you uninstall the chart. This is intentional to prevent accidental data loss. If you reinstall the chart with different passwords or Erlang cookies, you may encounter authentication issues because the old data persists. + +### Cleaning up PersistentVolumeClaims + +To manually delete the PVCs after uninstalling: + +```bash +$ kubectl delete pvc -l app.kubernetes.io/instance=my-rabbitmq +``` + +Alternatively, you can enable automatic PVC deletion by configuring the `persistentVolumeClaimRetentionPolicy` before installation: + +```yaml +persistentVolumeClaimRetentionPolicy: + enabled: true + whenDeleted: Delete # Automatically delete PVCs when StatefulSet is deleted + whenScaled: Delete # Automatically delete PVCs when scaling down +``` + +See the [Persistent Volume Claim Retention Policy](#persistent-volume-claim-retention-policy) section for more details. + ## Security & Signature Verification This Helm chart is cryptographically signed with Cosign to ensure authenticity and prevent tampering. @@ -103,11 +143,15 @@ The following table lists the configurable parameters of the RabbitMQ chart and | `podAnnotations` | Annotations to attach to pods | `{}` | | `statefulsetAnnotations` | Annotations for StatefulSet | `{}` | +### RabbitMQ Definitions + | Parameter | Description | Default | | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | `definitions.enabled` | Enable loading of RabbitMQ definitions on startup. When `true`, definitions will be loaded at container boot. | `false` | | `definitions.existingConfigMap` | Name of an existing ConfigMap containing RabbitMQ definitions (e.g., created via `kubectl create configmap rmq-defs --from-file=defs.json`). | `""` | | `definitions.existingConfigMapKey` | Key in the existing ConfigMap containing the RabbitMQ definitions JSON file. | `defs.json` | +| `defintions.existingSecret` | Name of an existing Secret containing RabbitMQ definitions. | `""` | +| `definitions.existingSecretKey` | Key in the existing Secret containing the RabbitMQ definitions JSON file. | `defs.json` | | `definitions.users` | Array of RabbitMQ users to create. | `[]` | | `definitions.vhosts` | Array of RabbitMQ virtual hosts to create. | `[]` | | `definitions.permissions` | Array of RabbitMQ permissions to set per vhost. | `[]` | @@ -121,15 +165,16 @@ The following table lists the configurable parameters of the RabbitMQ chart and ### Service configuration -| Parameter | Description | Default | -| ----------------------------- | -------------------------------------- | ----------- | -| `service.type` | Kubernetes service type | `ClusterIP` | -| `service.amqpPort` | RabbitMQ AMQP service port | `5672` | -| `service.managementPort` | RabbitMQ management UI port | `15672` | -| `service.epmdPort` | RabbitMQ EPMD port | `4369` | -| `service.distPort` | RabbitMQ distribution port | `25672` | -| `service.annotations` | Kubernetes service annotations | `{}` | -| `service.annotationsHeadless` | Kubernetes service annotationsHeadless | `25672` | +| Parameter | Description | Default | +| ----------------------------- | ------------------------------------------- | ----------- | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.amqpPort` | RabbitMQ AMQP service port | `5672` | +| `service.managementPort` | RabbitMQ management UI port | `15672` | +| `service.epmdPort` | RabbitMQ EPMD port | `4369` | +| `service.distPort` | RabbitMQ distribution port | `25672` | +| `service.annotations` | Kubernetes service annotations | `{}` | +| `service.annotationsHeadless` | Kubernetes service annotationsHeadless | `25672` | +| `service.trafficDistribution` | Traffic distribution policy for the service | `""` | ### RabbitMQ Authentication @@ -145,13 +190,13 @@ The following table lists the configurable parameters of the RabbitMQ chart and ### RabbitMQ configuration -| Parameter | Description | Default | -| ------------------------------------ | ----------------------------------------------------------- | ------------ | -| `config.memoryHighWatermark.enabled` | Enable configuring Memory high watermark on RabbitMQ | `false` | -| `config.memoryHighWatermark.type` | Memory high watermark type. Either `absolute` or `relative` | `"relative"` | -| `config.memoryHighWatermark.value` | Memory high watermark value | `0.4` | -| `config.extraConfiguration` | Additional RabbitMQ configuration | `""` | -| `config.advancedConfiguration` | Advanced RabbitMQ configuration | `""` | +| Parameter | Description | Default | +| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | +| `config.memoryHighWatermark.enabled` | Enable configuring Memory high watermark on RabbitMQ | `false` | +| `config.memoryHighWatermark.type` | Memory high watermark type. Either `absolute` or `relative` | `"relative"` | +| `config.memoryHighWatermark.value` | Memory high watermark value. For relative: use number (e.g., `0.4` for 40%). For absolute: use string to avoid scientific notation (e.g., `"8GB"`, `"8590000000"`) | `0.4` | +| `config.extraConfiguration` | Additional RabbitMQ configuration | `""` | +| `config.advancedConfiguration` | Advanced RabbitMQ configuration | `""` | ### PeerDiscoveryK8sPlugin configuration @@ -189,13 +234,15 @@ The following table lists the configurable parameters of the RabbitMQ chart and ### Persistence -| Parameter | Description | Default | -| -------------------------- | ------------------------------------------ | ------------------- | -| `persistence.enabled` | Enable persistent storage | `true` | -| `persistence.storageClass` | Storage class to use for persistent volume | `""` | -| `persistence.accessModes` | Persistent Volume access modes | `["ReadWriteOnce"]` | -| `persistence.size` | Size of persistent volume | `8Gi` | -| `persistence.annotations` | Annotations for persistent volume claims | `{}` | +| Parameter | Description | Default | +| --------------------------- | ------------------------------------------------------------------------------- | ------------------- | +| `persistence.enabled` | Enable persistent storage | `true` | +| `persistence.existingClaim` | Name of existing PVC to use (if empty, a new PVC will be created automatically) | `""` | +| `persistence.storageClass` | Storage class to use for persistent volume | `""` | +| `persistence.accessModes` | Persistent Volume access modes | `["ReadWriteOnce"]` | +| `persistence.size` | Size of persistent volume | `8Gi` | +| `persistence.labels` | Labels for persistent volume claims | `{}` | +| `persistence.annotations` | Annotations for persistent volume claims | `{}` | ### Ingress configuration @@ -245,17 +292,17 @@ The following table lists the configurable parameters of the RabbitMQ chart and | `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | | `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | | `readinessProbe.enabled` | Enable readinessProbe on RabbitMQ containers | `true` | -| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | -| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | -| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | -| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `1` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `10` | +| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `30` | +| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `20` | +| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | | `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | ### Additional Configuration | Parameter | Description | Default | | --------------------- | ----------------------------------------------------------------------- | -------------- | -| `extraEnv` | Additional environment variables to set | `[]` | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraVolumes` | Additional volumes to add to the pod | `[]` | | `extraVolumeMounts` | Additional volume mounts to add to the RabbitMQ container | `[]` | | `extraObjects` | A list of additional Kubernetes objects to deploy alongside the release | `[]` | diff --git a/charts/rabbitmq/templates/_helpers.tpl b/charts/rabbitmq/templates/_helpers.tpl index b8c9ecf0..9fdd077e 100644 --- a/charts/rabbitmq/templates/_helpers.tpl +++ b/charts/rabbitmq/templates/_helpers.tpl @@ -2,42 +2,42 @@ Expand the name of the chart. */}} {{- define "rabbitmq.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "rabbitmq.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "rabbitmq.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "rabbitmq.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Selector labels */}} {{- define "rabbitmq.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Common annotations */}} {{- define "rabbitmq.annotations" -}} -{{- include "common.annotations" . -}} +{{- include "cloudpirates.annotations" . -}} {{- end }} {{/* @@ -45,7 +45,7 @@ Get the secret name for RabbitMQ credentials */}} {{- define "rabbitmq.secretName" -}} {{- if .Values.auth.existingSecret }} -{{- .Values.auth.existingSecret }} +{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) }} {{- else }} {{- include "rabbitmq.fullname" . }} {{- end }} @@ -75,14 +75,14 @@ Get the secret key for Erlang cookie Return the proper RabbitMQ image name */}} {{- define "rabbitmq.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "rabbitmq.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{- define "rabbitmq.serviceAccountName" -}} diff --git a/charts/rabbitmq/templates/configmap.yaml b/charts/rabbitmq/templates/configmap.yaml index 4d886609..2ecab001 100644 --- a/charts/rabbitmq/templates/configmap.yaml +++ b/charts/rabbitmq/templates/configmap.yaml @@ -51,6 +51,8 @@ data: {{- if .Values.config.memoryHighWatermark.enabled }} # Memory configuration + # Note: Large absolute values should be specified as strings (e.g., "8GB" or "8590000000") + # to avoid scientific notation conversion by YAML (e.g., 8e+9) vm_memory_high_watermark.{{ .Values.config.memoryHighWatermark.type }} = {{ .Values.config.memoryHighWatermark.value }} {{- end }} @@ -63,6 +65,18 @@ data: management.load_definitions = /etc/rabbitmq-definitions/defs.json {{- end }} + # Logging configuration + log.console = {{ .Values.config.logging.console.enabled }} + {{- if .Values.config.logging.console.enabled }} + log.console.level = {{ .Values.config.logging.level }} + {{- end }} + {{- if .Values.config.logging.file.enabled }} + log.file = true + log.file.level = {{ .Values.config.logging.level }} + {{- else }} + log.file = false + {{- end }} + {{- if and .Values.config.extraConfiguration (ne .Values.config.extraConfiguration "") }} # Extra configuration {{ .Values.config.extraConfiguration | indent 4 }} diff --git a/charts/rabbitmq/templates/definitions-configmap.yaml b/charts/rabbitmq/templates/definitions-configmap.yaml index 6b5ba931..10b17a5e 100644 --- a/charts/rabbitmq/templates/definitions-configmap.yaml +++ b/charts/rabbitmq/templates/definitions-configmap.yaml @@ -2,7 +2,7 @@ This file is rendered only if definitions are enabled AND an existing ConfigMap is NOT specified. It constructs a dictionary from the values and then converts it to a valid JSON object. */}} -{{- if and .Values.definitions.enabled (not .Values.definitions.existingConfigMap) }} +{{- if and .Values.definitions.enabled (not .Values.definitions.existingConfigMap) (not .Values.definitions.existingSecret) }} {{- $def := dict }} {{- if .Values.definitions.users -}}{{- $_ := set $def "users" .Values.definitions.users }}{{- end }} {{- if .Values.definitions.vhosts -}}{{- $_ := set $def "vhosts" .Values.definitions.vhosts }}{{- end }} @@ -22,6 +22,10 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "rabbitmq.labels" . | nindent 4 }} + {{- with (include "rabbitmq.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} data: defs.json: |- {{- $def | toPrettyJson | nindent 4 }} diff --git a/charts/rabbitmq/templates/extraobjects.yaml b/charts/rabbitmq/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/rabbitmq/templates/extraobjects.yaml +++ b/charts/rabbitmq/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/rabbitmq/templates/rolebinding.yaml b/charts/rabbitmq/templates/rolebinding.yaml index 7748c5ef..cd73a8f2 100644 --- a/charts/rabbitmq/templates/rolebinding.yaml +++ b/charts/rabbitmq/templates/rolebinding.yaml @@ -5,6 +5,10 @@ metadata: name: {{ template "rabbitmq.fullname" . }}-peer-discovery namespace: {{ .Release.Namespace }} labels: {{- include "rabbitmq.labels" . | nindent 4 }} + {{- with (include "rabbitmq.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} subjects: - kind: ServiceAccount namespace: {{ .Release.Namespace }} diff --git a/charts/rabbitmq/templates/service.yaml b/charts/rabbitmq/templates/service.yaml index e1076a13..79f5828c 100644 --- a/charts/rabbitmq/templates/service.yaml +++ b/charts/rabbitmq/templates/service.yaml @@ -11,6 +11,7 @@ metadata: {{- end }} spec: type: {{ .Values.service.type }} + trafficDistribution: {{ .Values.service.trafficDistribution }} ports: - port: {{ .Values.service.amqpPort }} targetPort: amqp @@ -31,4 +32,4 @@ spec: name: {{ .name }} {{- end }} selector: - {{- include "rabbitmq.selectorLabels" . | nindent 4 }} \ No newline at end of file + {{- include "rabbitmq.selectorLabels" . | nindent 4 }} diff --git a/charts/rabbitmq/templates/servicemonitor.yaml b/charts/rabbitmq/templates/servicemonitor.yaml index 11805892..3632b128 100644 --- a/charts/rabbitmq/templates/servicemonitor.yaml +++ b/charts/rabbitmq/templates/servicemonitor.yaml @@ -9,7 +9,8 @@ metadata: {{- with .Values.metrics.serviceMonitor.labels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.metrics.serviceMonitor.annotations }} + {{- $annotations := merge .Values.metrics.serviceMonitor.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/rabbitmq/templates/statefulset.yaml b/charts/rabbitmq/templates/statefulset.yaml index 25e993e9..6fbe0547 100644 --- a/charts/rabbitmq/templates/statefulset.yaml +++ b/charts/rabbitmq/templates/statefulset.yaml @@ -32,12 +32,12 @@ spec: {{ . | nindent 6 }} {{- end }} serviceAccountName: {{ include "rabbitmq.serviceAccountName" . }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} initContainers: - name: init-erlang-cookie image: "{{ .Values.initContainer.image.registry | default .Values.global.imageRegistry }}/{{ .Values.initContainer.image.repository }}:{{ .Values.initContainer.image.tag }}" imagePullPolicy: "{{ .Values.initContainer.image.pullPolicy }}" - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} command: - sh - -c @@ -65,7 +65,7 @@ spec: - name: download-plugins image: "{{ .Values.initContainer.image.registry | default .Values.global.imageRegistry }}/{{ .Values.initContainer.image.repository }}:{{ .Values.initContainer.image.tag }}" imagePullPolicy: "{{ .Values.initContainer.image.pullPolicy }}" - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} command: - sh - -c @@ -89,8 +89,8 @@ spec: mountPath: /tmp/plugins - name: copy-plugins image: {{ include "rabbitmq.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} command: - sh - -c @@ -107,15 +107,23 @@ spec: {{- end }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "rabbitmq.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} - {{- if .Values.customScripts.postStart.enabled }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} + {{- if or .Values.customScripts.postStart.enabled .Values.customScripts.preStop.enabled }} lifecycle: + {{- if .Values.customScripts.postStart.enabled }} postStart: exec: command: {{- toYaml .Values.customScripts.postStart.command | nindent 18 }} + {{- end }} + {{- if .Values.customScripts.preStop.enabled }} + preStop: + exec: + command: + {{- toYaml .Values.customScripts.preStop.command | nindent 18 }} + {{- end }} {{- end }} ports: - name: amqp @@ -162,9 +170,8 @@ spec: - name: RABBITMQ_NODENAME value: rabbit@$(NODE_NAME) {{- end }} - {{- range .Values.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: @@ -210,7 +217,13 @@ spec: {{- if .Values.definitions.enabled }} - name: definitions mountPath: "/etc/rabbitmq-definitions/defs.json" - subPath: {{ .Values.definitions.existingConfigMapKey | default "defs.json" }} + subPath: {{- if .Values.definitions.existingConfigMap }} + {{ .Values.definitions.existingConfigMapKey | default "defs.json" }} + {{- else if .Values.definitions.existingSecret }} + {{ .Values.definitions.existingSecretKey | default "defs.json" }} + {{- else }} + defs.json + {{- end }} {{- end }} {{- if .Values.extraVolumeMounts }} {{- toYaml .Values.extraVolumeMounts | nindent 12 }} @@ -221,6 +234,10 @@ spec: {{- if not .Values.persistence.enabled }} - name: data emptyDir: {} + {{- else if .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | quote }} {{- end }} {{- if .Values.installPlugins }} - name: plugins @@ -231,8 +248,16 @@ spec: name: {{ include "rabbitmq.fullname" . }}-config {{- if .Values.definitions.enabled }} - name: definitions + {{- if .Values.definitions.existingConfigMap }} + configMap: + name: {{ .Values.definitions.existingConfigMap }} + {{- else if .Values.definitions.existingSecret }} + secret: + secretName: {{ include "cloudpirates.tplvalues.render" (dict "value" .Values.definitions.existingSecret "context" $) }} + {{- else }} configMap: - name: {{ .Values.definitions.existingConfigMap | default (printf "%s-definitions" (include "rabbitmq.fullname" .)) }} + name: {{ printf "%s-definitions" (include "rabbitmq.fullname" .) }} + {{- end }} {{- end }} {{- if .Values.extraVolumes }} {{- toYaml .Values.extraVolumes | nindent 8 }} @@ -253,12 +278,16 @@ spec: topologySpreadConstraints: {{- toYaml . | nindent 8 }} {{- end }} - {{- if .Values.persistence.enabled }} + {{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} volumeClaimTemplates: - apiVersion: v1 kind: PersistentVolumeClaim metadata: name: data + {{- with .Values.persistence.labels }} + labels: + {{- toYaml . | nindent 10 }} + {{- end }} {{- with .Values.persistence.annotations }} annotations: {{- toYaml . | nindent 10 }} diff --git a/charts/rabbitmq/tests/rabbitmq-functionality_test.yaml b/charts/rabbitmq/tests/rabbitmq-functionality_test.yaml index a634804a..6803e53a 100644 --- a/charts/rabbitmq/tests/rabbitmq-functionality_test.yaml +++ b/charts/rabbitmq/tests/rabbitmq-functionality_test.yaml @@ -73,6 +73,32 @@ tests: path: data["rabbitmq.conf"] pattern: "vm_memory_high_watermark.relative = 0.6" + - it: should configure memory watermark with absolute string value (human-readable) + set: + config: + memoryHighWatermark: + enabled: true + type: absolute + value: "8GB" + template: templates/configmap.yaml + asserts: + - matchRegex: + path: data["rabbitmq.conf"] + pattern: "vm_memory_high_watermark.absolute = 8GB" + + - it: should configure memory watermark with absolute string value (large number) + set: + config: + memoryHighWatermark: + enabled: true + type: absolute + value: "8590000000" + template: templates/configmap.yaml + asserts: + - matchRegex: + path: data["rabbitmq.conf"] + pattern: "vm_memory_high_watermark.absolute = 8590000000" + - it: should enable clustering when configured set: replicaCount: 3 diff --git a/charts/rabbitmq/values.schema.json b/charts/rabbitmq/values.schema.json index 019dd16d..5ad313ad 100644 --- a/charts/rabbitmq/values.schema.json +++ b/charts/rabbitmq/values.schema.json @@ -1,1017 +1,577 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "RabbitMQ Helm Chart Values Schema", - "description": "Schema for RabbitMQ Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker image registry" - }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "additionalPlugins": { + "type": "array" + }, + "affinity": { + "type": "object" + }, + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override rabbitmq.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override rabbitmq.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "image": { - "type": "object", - "title": "RabbitMQ Image Configuration", - "description": "RabbitMQ container image configuration", - "properties": { - "registry": { - "type": "string", - "title": "RabbitMQ Image Registry", - "description": "RabbitMQ image registry" - }, - "repository": { - "type": "string", - "title": "RabbitMQ Image Repository", - "description": "RabbitMQ image repository" - }, - "tag": { - "type": "string", - "title": "RabbitMQ Image Tag", - "description": "RabbitMQ image tag with digest" - }, - "imagePullPolicy": { - "type": "string", - "title": "RabbitMQ Image Pull Policy", - "description": "RabbitMQ image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] - } - } - }, - "clusterDomain": { - "type": "string", - "title": "Cluster Domain", - "description": "Kubernetes cluster domain" - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of RabbitMQ replicas to deploy (clustering needs to be enabled to set more than 1 replicas)", - "minimum": 1 - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "Kubernetes service configuration", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "Kubernetes service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "amqpPort": { - "type": "integer", - "title": "AMQP Port", - "description": "RabbitMQ AMQP service port", - "minimum": 1, - "maximum": 65535 - }, - "managementPort": { - "type": "integer", - "title": "Management Port", - "description": "RabbitMQ management UI port", - "minimum": 1, - "maximum": 65535 - }, - "epmdPort": { - "type": "integer", - "title": "EPMD Port", - "description": "RabbitMQ EPMD port", - "minimum": 1, - "maximum": 65535 - }, - "distPort": { - "type": "integer", - "title": "Distribution Port", - "description": "RabbitMQ distribution port", - "minimum": 1, - "maximum": 65535 - } - } - }, - "auth": { - "type": "object", - "title": "RabbitMQ Authentication", - "description": "RabbitMQ Authentication configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Authentication", - "description": "Enable RabbitMQ authentication" - }, - "username": { - "type": "string", - "title": "RabbitMQ Username", - "description": "RabbitMQ default username" - }, - "password": { - "type": "string", - "title": "RabbitMQ Password", - "description": "RabbitMQ password (if empty, random password will be generated)" - }, - "erlangCookie": { - "type": "string", - "title": "Erlang Cookie", - "description": "Erlang cookie for clustering (if empty, random cookie will be generated)" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret containing RabbitMQ credentials" - }, - "existingPasswordKey": { - "type": "string", - "title": "Existing Password Key", - "description": "Key in existing secret containing RabbitMQ password" - }, - "existingErlangCookieKey": { - "type": "string", - "title": "Existing Erlang Cookie Key", - "description": "Key in existing secret containing Erlang cookie" - } - } - }, - "config": { - "type": "object", - "title": "RabbitMQ Configuration", - "description": "RabbitMQ configuration parameters", - "properties": { - "memoryHighWatermark": { - "type": "object", - "title": "Memory High Watermark Configuration", - "description": "Memory high watermark configuration for RabbitMQ", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Memory High Watermark", - "description": "Enable configuring Memory high watermark on RabbitMQ" - }, - "type": { - "type": "string", - "title": "Memory High Watermark Type", - "description": "Memory high watermark type. Either `absolute` or `relative`", - "enum": ["absolute", "relative"] - }, - "value": { - "oneOf": [{ "type": "string" }, { "type": "number" }], - "title": "Memory High Watermark Value", - "description": "Memory high watermark value" + "enabled": { + "type": "boolean" + }, + "erlangCookie": { + "type": "string" + }, + "existingErlangCookieKey": { + "type": "string" + }, + "existingPasswordKey": { + "type": "string" + }, + "existingSecret": { + "type": "string" + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + } } - } }, - "extraConfiguration": { - "type": "string", - "title": "Extra Configuration", - "description": "Additional RabbitMQ configuration" + "clusterDomain": { + "type": "string" }, - "advancedConfiguration": { - "type": "string", - "title": "Advanced Configuration", - "description": "Advanced RabbitMQ configuration" - } - } - }, - "peerDiscoveryK8sPlugin": { - "type": "object", - "title": "Peer Discovery K8s Plugin Configuration", - "description": "Kubernetes peer discovery plugin configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Peer Discovery", - "description": "Enable K8s peer discovery plugin for a RabbitMQ HA-cluster" - }, - "useLongname": { - "type": "boolean", - "title": "Use Long Name", - "description": "Uses the FQDN as connection string (RABBITMQ_USE_LONGNAME)" - }, - "addressType": { - "type": "string", - "title": "Address Type", - "description": "Peer discovery plugin address type", - "enum": ["hostname", "ip"] - } - } - }, - "managementPlugin": { - "type": "object", - "title": "Management Plugin Configuration", - "description": "RabbitMQ management plugin configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Management Plugin", - "description": "Enable RabbitMQ management plugin" - } - } - }, - "metrics": { - "type": "object", - "title": "Metrics Configuration", - "description": "RabbitMQ metrics and monitoring configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Metrics", - "description": "Enable RabbitMQ metrics (via prometheus plugin)" - }, - "port": { - "type": "integer", - "title": "Metrics Port", - "description": "RabbitMQ metrics port", - "minimum": 1, - "maximum": 65535 - }, - "serviceMonitor": { - "type": "object", - "title": "Service Monitor Configuration", - "description": "Prometheus ServiceMonitor configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable ServiceMonitor", - "description": "Create ServiceMonitor for Prometheus monitoring" - }, - "namespace": { - "type": "string", - "title": "ServiceMonitor Namespace", - "description": "Namespace for ServiceMonitor" - }, - "labels": { - "type": "object", - "title": "ServiceMonitor Labels", - "description": "Labels for ServiceMonitor", - "additionalProperties": { - "type": "string" - } - }, - "annotations": { - "type": "object", - "title": "ServiceMonitor Annotations", - "description": "Annotations for ServiceMonitor", - "additionalProperties": { - "type": "string" - } - }, - "interval": { - "type": "string", - "title": "Scrape Interval", - "description": "Scrape interval" - }, - "scrapeTimeout": { - "type": "string", - "title": "Scrape Timeout", - "description": "Scrape timeout" + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { + "type": "object", + "properties": { + "advancedConfiguration": { + "type": "string" + }, + "extraConfiguration": { + "type": "string" + }, + "logging": { + "type": "object", + "properties": { + "console": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "file": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "level": { + "type": "string" + } + } + }, + "memoryHighWatermark": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "value": { + "oneOf": [ + {"type": "number"}, + {"type": "string"} + ] + } + } + } } - } - } - } - }, - "additionalPlugins": { - "type": "array", - "title": "Additional Plugins", - "description": "Additional RabbitMQ plugins to enable (Prometheus Metrics, PeerDiscoveryK8s and Management plugins are automatically added)", - "items": { - "type": "string" - } - }, - "installPlugins": { - "type": "array", - "title": "Install Plugins", - "description": "Additional 3rd party RabbitMQ plugins to download and enable", - "items": { - "type": "string" - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "Persistence configuration using Persistent Volume Claims", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable persistent storage" - }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "Storage class to use for persistent volume" - }, - "accessModes": { - "type": "array", - "title": "Access Modes", - "description": "Persistent Volume access modes", - "items": { - "type": "string", - "enum": [ - "ReadWriteOnce", - "ReadOnlyMany", - "ReadWriteMany", - "ReadWriteOncePod" - ] - } - }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "Size of persistent volume", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" - }, - "annotations": { - "type": "object", - "title": "PVC Annotations", - "description": "Annotations for persistent volume claims", - "additionalProperties": { - "type": "string" - } - } - } - }, - "ingress": { - "type": "object", - "title": "Ingress Configuration", - "description": "Ingress configuration for RabbitMQ management UI", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Ingress", - "description": "Enable ingress for RabbitMQ management" - }, - "className": { - "type": "string", - "title": "Ingress Class Name", - "description": "Ingress class name" - }, - "annotations": { - "type": "object", - "title": "Ingress Annotations", - "description": "Ingress annotations", - "additionalProperties": { - "type": "string" - } }, - "hosts": { - "type": "array", - "title": "Ingress Hosts", - "description": "Ingress hosts configuration", - "items": { + "containerSecurityContext": { "type": "object", "properties": { - "host": { - "type": "string", - "title": "Host", - "description": "Hostname for RabbitMQ ingress" - }, - "paths": { - "type": "array", - "title": "Paths", - "description": "Paths configuration for the host", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "title": "Path", - "description": "Path for RabbitMQ ingress" - }, - "pathType": { - "type": "string", - "title": "Path Type", - "description": "Path type for RabbitMQ ingress", - "enum": ["Exact", "Prefix", "ImplementationSpecific"] + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } } - } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" } - } } - } }, - "tls": { - "type": "array", - "title": "TLS Configuration", - "description": "Ingress TLS configuration", - "items": { - "type": "object" - } - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource limits and requests for RabbitMQ pods", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [{ "type": "string" }, { "type": "number" }], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + "customScripts": { + "type": "object", + "properties": { + "initContainers": { + "type": "array" + }, + "postStart": { + "type": "object", + "properties": { + "command": { + "type": "array" + }, + "enabled": { + "type": "boolean" + } + } + }, + "preStop": { + "type": "object", + "properties": { + "command": { + "type": "array" + }, + "enabled": { + "type": "boolean" + } + } + } } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [{ "type": "string" }, { "type": "number" }], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + }, + "definitions": { + "type": "object", + "properties": { + "bindings": { + "type": "array" + }, + "enabled": { + "type": "boolean" + }, + "exchanges": { + "type": "array" + }, + "existingConfigMap": { + "type": "string" + }, + "existingConfigMapKey": { + "type": "string" + }, + "existingSecret": { + "type": "string" + }, + "existingSecretKey": { + "type": "string" + }, + "global_parameters": { + "type": "array" + }, + "parameters": { + "type": "array" + }, + "permissions": { + "type": "array" + }, + "policies": { + "type": "array" + }, + "queues": { + "type": "array" + }, + "topic_permissions": { + "type": "array" + }, + "users": { + "type": "array" + }, + "vhosts": { + "type": "array" + } } - } - } - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node labels for pod assignment", - "additionalProperties": { - "type": "string" - } - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Toleration labels for pod assignment", - "items": { - "type": "object", - "properties": { - "key": { + }, + "extraEnvVars": { + "type": "array" + }, + "extraObjects": { + "type": "array" + }, + "extraPorts": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "fullnameOverride": { "type": "string" - }, - "operator": { - "type": "string", - "enum": ["Equal", "Exists"] - }, - "value": { + }, + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } + } + }, + "initContainer": { + "type": "object", + "properties": { + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + } + } + }, + "installPlugins": { + "type": "array" + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "managementPlugin": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + }, + "serviceMonitor": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "labels": { + "type": "object" + }, + "namespace": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + } + } + } + } + }, + "nameOverride": { "type": "string" - }, - "effect": { - "type": "string", - "enum": ["NoSchedule", "PreferNoSchedule", "NoExecute"] - }, - "tolerationSeconds": { - "type": "integer", - "minimum": 0 - } - } - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity settings for pod assignment", - "properties": { - "nodeAffinity": { - "type": "object", - "title": "Node Affinity", - "description": "Node affinity configuration" - }, - "podAffinity": { - "type": "object", - "title": "Pod Affinity", - "description": "Pod affinity configuration" - }, - "podAntiAffinity": { - "type": "object", - "title": "Pod Anti-Affinity", - "description": "Pod anti-affinity configuration" - } - } - }, - "topologySpreadConstraints": { - "type": "array", - "title": "Topology Spread Constraints", - "description": "Topology spread constraints for pod assignment", - "items": { - "type": "object" - } - }, - "securityContext": { - "type": "object", - "title": "Container Security Context", - "description": "Security context for the RabbitMQ container", - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Enable container privilege escalation" - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Configure the container to run as a non-root user" - }, - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID for the RabbitMQ container", - "minimum": 0 - }, - "runAsGroup": { - "type": "integer", - "title": "Run As Group", - "description": "Group ID for the RabbitMQ container", - "minimum": 0 - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "title": "Read-Only Root Filesystem", - "description": "Mount container root filesystem as read-only" - }, - "capabilities": { - "type": "object", - "title": "Capabilities", - "description": "Linux capabilities configuration", - "properties": { - "drop": { - "type": "array", - "title": "Drop Capabilities", - "description": "Linux capabilities to be dropped", - "items": { - "type": "string" - } + }, + "nodeSelector": { + "type": "object" + }, + "pdb": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "maxUnavailable": { + "type": "string" + }, + "minAvailable": { + "type": "string" + } } - } - } - } - }, - "initContainer.securityContext": { - "type": "object", - "title": "Init Container Security Context", - "description": "Security context for the init container", - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Enable container privilege escalation" - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Configure the container to run as a non-root user" - }, - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID for the RabbitMQ container", - "minimum": 0 - }, - "runAsGroup": { - "type": "integer", - "title": "Run As Group", - "description": "Group ID for the RabbitMQ container", - "minimum": 0 - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "title": "Read-Only Root Filesystem", - "description": "Mount container root filesystem as read-only" - }, - "capabilities": { - "type": "object", - "title": "Capabilities", - "description": "Linux capabilities configuration", - "properties": { - "drop": { - "type": "array", - "title": "Drop Capabilities", - "description": "Linux capabilities to be dropped", - "items": { - "type": "string" - } + }, + "peerDiscoveryK8sPlugin": { + "type": "object", + "properties": { + "addressType": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "useLongname": { + "type": "boolean" + } } - } - } - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "Security context for the pod", - "properties": { - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Group ID for the volumes of the pod", - "minimum": 0 - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "Liveness probe configuration for RabbitMQ container", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable livenessProbe on RabbitMQ containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for livenessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for livenessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for livenessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for livenessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for livenessProbe", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "Readiness probe configuration for RabbitMQ container", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readinessProbe on RabbitMQ containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for readinessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for readinessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for readinessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for readinessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for readinessProbe", - "minimum": 1 - } - } - }, - "extraEnv": { - "type": "array", - "title": "Extra Environment Variables", - "description": "Additional environment variables to set", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Variable Name", - "description": "Environment variable name" - }, - "value": { - "type": "string", - "title": "Variable Value", - "description": "Environment variable value" - } - }, - "required": ["name"] - } - }, - "extraVolumes": { - "type": "array", - "title": "Extra Volumes", - "description": "Additional volumes to add to the pod", - "items": { - "type": "object" - } - }, - "extraVolumeMounts": { - "type": "array", - "title": "Extra Volume Mounts", - "description": "Additional volume mounts to add to the RabbitMQ container", - "items": { - "type": "object" - } - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } - }, - "podLabels": { - "type": "object", - "title": "Pod Labels", - "description": "Labels to attach to pods", - "additionalProperties": { - "type": "string" - } - }, - "podAnnotations": { - "type": "object", - "title": "Pod Annotations", - "description": "Annotations to attach to pods", - "additionalProperties": { - "type": "string" - } - }, - "statefulsetLabels": { - "type": "object", - "title": "StatefulSet Labels", - "description": "Labels to attach to StatefulSet", - "additionalProperties": { - "type": "string" - } - }, - "statefulsetAnnotations": { - "type": "object", - "title": "StatefulSet Annotations", - "description": "Annotations for StatefulSet", - "additionalProperties": { - "type": "string" - } - }, - "podManagementPolicy": { - "type": "string", - "title": "Pod Management Policy", - "description": "StatefulSet pod management policy", - "enum": ["OrderedReady", "Parallel"] - }, - "persistentVolumeClaimRetentionPolicy": { - "type": "object", - "title": "PVC Retention Policy", - "description": "Persistent Volume Claim retention policy for StatefulSet", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Retention Policy", - "description": "Enable Persistent volume retention policy" - }, - "whenDeleted": { - "type": "string", - "title": "When Deleted", - "description": "Volume retention behavior when replica is deleted", - "enum": ["Retain", "Delete"] - }, - "whenScaled": { - "type": "string", - "title": "When Scaled", - "description": "Volume retention behavior when replica count is reduced", - "enum": ["Retain", "Delete"] - } - } - }, - "serviceAccount": { - "type": "object", - "title": "Service Account", - "description": "Service account configuration", - "properties": { - "create": { - "type": "boolean", - "title": "Create Service Account", - "description": "Enable creation of ServiceAccount" - }, - "name": { - "type": "string", - "title": "Service Account Name", - "description": "Name of serviceAccount" - }, - "annotations": { - "type": "object", - "title": "Service Account Annotations", - "description": "Annotations for service account", - "additionalProperties": { + }, + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "labels": { + "type": "object" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "persistentVolumeClaimRetentionPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "whenDeleted": { + "type": "string" + }, + "whenScaled": { + "type": "string" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podManagementPolicy": { "type": "string" - } - } - } - }, - "rbac": { - "type": "object", - "title": "RBAC Configuration", - "description": "RBAC parameters", - "properties": { - "create": { - "type": "boolean", - "title": "Create RBAC", - "description": "Whether RBAC rules should be created" - }, - "rules": { - "type": "array", - "title": "Custom RBAC Rules", - "description": "Custom RBAC rules", - "items": { + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "rules": { + "type": "array" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { "type": "object" - } - } - } - }, - "pdb": { - "type": "object", - "title": "Pod Disruption Budget", - "description": "Pod Disruption Budget configuration", - "properties": { - "create": { - "type": "boolean", - "title": "Create PDB", - "description": "Enable/disable a Pod Disruption Budget creation" - }, - "minAvailable": { - "oneOf": [ - {"type": "string"}, - {"type": "integer"} - ], - "title": "Min Available", - "description": "Minimum number/percentage of pods that should remain scheduled" - }, - "maxUnavailable": { - "oneOf": [ - {"type": "string"}, - {"type": "integer"} - ], - "title": "Max Unavailable", - "description": "Maximum number/percentage of pods that may be made unavailable" - } - } - }, - "definitions": { - "type": "object", - "title": "RabbitMQ Definitions", - "description": "RabbitMQ definitions loaded on startup (https://www.rabbitmq.com/docs/definitions)", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Definitions", - "description": "Enable loading of RabbitMQ definitions on startup" - }, - "existingConfigMap": { - "type": "string", - "title": "Existing ConfigMap", - "description": "Name of existing ConfigMap containing RabbitMQ definitions" - }, - "existingConfigMapKey": { - "type": "string", - "title": "Existing ConfigMap Key", - "description": "Key in existing ConfigMap containing RabbitMQ definitions", - "default": "defs.json" - }, - "bindings": { - "type": "array", - "title": "Bindings", - "description": "Array of RabbitMQ bindings to create", - "items": { "type": "object" } - }, - "global_parameters": { - "type": "array", - "title": "Global Parameters", - "description": "Array of RabbitMQ global parameters to create", - "items": { "type": "object" } - }, - "parameters": { - "type": "array", - "title": "Parameters", - "description": "Array of RabbitMQ parameters to create", - "items": { "type": "object" } - }, - "policies": { - "type": "array", - "title": "Policies", - "description": "Array of RabbitMQ policies to create", - "items": { "type": "object" } - }, - "queues": { - "type": "array", - "title": "Queues", - "description": "Array of RabbitMQ queues to create", - "items": { "type": "object" } - }, - "exchanges": { - "type": "array", - "title": "Exchanges", - "description": "Array of RabbitMQ exchanges to create", - "items": { "type": "object" } - }, - "topic_permissions": { - "type": "array", - "title": "Topic Permissions", - "description": "Array of RabbitMQ topic permissions to create", - "items": { "type": "object" } - }, - "users": { - "type": "array", - "title": "Users", - "description": "Array of RabbitMQ users to create", - "items": { "type": "object" } - }, - "vhosts": { - "type": "array", - "title": "Virtual Hosts", - "description": "Array of RabbitMQ vhosts to create", - "items": { "type": "object" } - }, - "permissions": { - "type": "array", - "title": "Permissions", - "description": "Array of RabbitMQ permissions to set", - "items": { "type": "object" } + }, + "service": { + "type": "object", + "properties": { + "amqpPort": { + "type": "integer" + }, + "annotations": { + "type": "object" + }, + "annotationsHeadless": { + "type": "object" + }, + "distPort": { + "type": "integer" + }, + "epmdPort": { + "type": "integer" + }, + "managementPort": { + "type": "integer" + }, + "trafficDistribution": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "statefulsetAnnotations": { + "type": "object" + }, + "statefulsetLabels": { + "type": "object" + }, + "tolerations": { + "type": "array" + }, + "topologySpreadConstraints": { + "type": "array" } - } } - } } diff --git a/charts/rabbitmq/values.yaml b/charts/rabbitmq/values.yaml index ca9bff9b..f0697d52 100644 --- a/charts/rabbitmq/values.yaml +++ b/charts/rabbitmq/values.yaml @@ -23,7 +23,7 @@ image: ## @param image.repository RabbitMQ image repository repository: rabbitmq ## @param image.tag RabbitMQ image tag - tag: "4.1.4-management@sha256:8c31e22adfd876e183d81281b82fa489cd8032e6f9ef886e52261a1182a60951" + tag: "4.2.0-management@sha256:23676732c0b7bb978c0837c150492222d5b23ff079fc2025b537f4ce5c013d98" ## @param image.imagePullPolicy RabbitMQ image pull policy imagePullPolicy: Always @@ -38,6 +38,8 @@ replicaCount: 1 service: ## @param service.type Kubernetes service type type: ClusterIP + ## @param service.trafficDistribution Traffic distribution policy for the service + trafficDistribution: "" ## @param service.amqpPort RabbitMQ AMQP service port amqpPort: 5672 ## @param service.managementPort RabbitMQ management UI port @@ -85,9 +87,28 @@ config: ## @param memoryHighWatermark.value Memory high watermark value ## The default value of 0.4 stands for 40% of available RAM ## Note: the memory relative limit is applied to the resourcesPreset memory limit or the resource.limits.memory to calculate the memory threshold - ## You can also use an absolute value, e.g.: 256Mi + ## For absolute values, you can use: + ## - Human-readable units as strings: "8GB", "256MiB", "1024MB" (recommended) + ## - Large numbers as strings: "8590000000" (to avoid YAML scientific notation like 8e+9) + ## - Small numbers as integers: 256000000 (only if < 1 million to avoid scientific notation) + ## Examples: + ## value: 0.4 # relative: 40% of available RAM + ## value: "8GB" # absolute: 8 gigabytes + ## value: "8590000000" # absolute: 8590000000 bytes (use string for large numbers) ## value: 0.4 + ## Logging configuration + ## ref: https://www.rabbitmq.com/docs/logging + ## + logging: + ## @param config.logging.console.enabled Enable console logging (outputs to stdout/stderr instead of files) + console: + enabled: true + ## @param config.logging.file.enabled Enable file logging (outputs to /var/log/rabbitmq/) + file: + enabled: false + ## @param config.logging.level Log level for RabbitMQ (debug, info, warning, error, critical, none) + level: "info" ## @param config.extraConfiguration Additional RabbitMQ configuration extraConfiguration: "" ## @param config.advancedConfiguration Advanced RabbitMQ configuration @@ -115,7 +136,7 @@ initContainer: ## @param initContainer.image.registry Init container image repository repository: busybox ## @param initContainer.image.tag Init container image tag - tag: "1.37.0@sha256:d82f458899c9696cb26a7c02d5568f81c8c8223f8661bb2a7988b269c8b9051e" + tag: "1.37.0@sha256:e3652a00a2fabd16ce889f0aa32c38eec347b997e73bd09e69c962ec7f8732ee" ## @param initContainer.image.pullPolicy Init container image pull policy pullPolicy: IfNotPresent @@ -149,6 +170,8 @@ installPlugins: [] persistence: ## @param persistence.enabled Enable persistent storage enabled: true + ## @param persistence.existingClaim Name of existing PVC to use (if empty, a new PVC will be created automatically) + existingClaim: "" ## @param persistence.storageClass Storage class to use for persistent volume storageClass: "" ## @param persistence.accessModes Persistent Volume access modes @@ -156,6 +179,8 @@ persistence: - ReadWriteOnce ## @param persistence.size Size of persistent volume size: 8Gi + ## @param persistence.labels Labels for persistent volume claims + labels: {} ## @param persistence.annotations Annotations for persistent volume claims annotations: {} @@ -246,20 +271,25 @@ readinessProbe: ## @param readinessProbe.enabled Enable readinessProbe on RabbitMQ containers enabled: true ## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - initialDelaySeconds: 0 + initialDelaySeconds: 10 ## @param readinessProbe.periodSeconds Period seconds for readinessProbe - periodSeconds: 10 + periodSeconds: 30 ## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - timeoutSeconds: 5 + timeoutSeconds: 20 ## @param readinessProbe.failureThreshold Failure threshold for readinessProbe - failureThreshold: 1 + failureThreshold: 3 ## @param readinessProbe.successThreshold Success threshold for readinessProbe successThreshold: 1 -## @param extraEnv Additional environment variables to set -extraEnv: [] -# - name: EXTRA_VAR -# value: "extra_value" +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraVolumes Additional volumes to add to the pod extraVolumes: [] @@ -296,6 +326,18 @@ customScripts: # - | # sleep 10 # rabbitmq-queues rebalance all + ## @param customScripts.preStop PreStop lifecycle hook configuration + preStop: + ## @param customScripts.preStop.enabled Enable preStop lifecycle hook + enabled: false + ## @param customScripts.preStop.command Command to execute in preStop hook + command: [] + # Example: + # - /bin/bash + # - -c + # - | + # sleep 10 + # rabbitmqctl stop_app ## @param customScripts.initContainers Custom init containers to run before RabbitMQ starts initContainers: [] # Example: @@ -374,6 +416,10 @@ definitions: existingConfigMap: "" ## @param definitions.existingConfigMapKey Key in existing ConfigMap containing RabbitMQ definitions existingConfigMapKey: defs.json + ## @param definitions.existingSecret Name of existing Secret containing RabbitMQ definitions + existingSecret: "" + ## @param definitions.existingSecretKey Key in existing Secret containing RabbitMQ definitions + existingSecretKey: defs.json ## @param definitions.bindings Array of RabbitMQ bindings to create bindings: [] ## @param definitions.global_parameters Array of RabbitMQ global parameters to create diff --git a/charts/redis/CHANGELOG.md b/charts/redis/CHANGELOG.md index a8792409..7b40090f 100644 --- a/charts/redis/CHANGELOG.md +++ b/charts/redis/CHANGELOG.md @@ -1,137 +1,357 @@ # Changelog + +## 0.14.0 (2025-11-07) + +* [redis]: Headless Service annotations ([10daf47](https://github.com/CloudPirates-io/helm-charts/commit/10daf47)) +* chore: update CHANGELOG.md for merged changes ([78cf9bf](https://github.com/CloudPirates-io/helm-charts/commit/78cf9bf)) +* chore: update CHANGELOG.md for merged changes ([099f401](https://github.com/CloudPirates-io/helm-charts/commit/099f401)) + +## 0.13.4 (2025-11-04) + +* Update charts/redis/values.yaml redis (#547) ([f0ba3c6](https://github.com/CloudPirates-io/helm-charts/commit/f0ba3c6)) + +## 0.13.3 (2025-11-04) + +* [redis]: fix sidecar auth args ([967558f](https://github.com/CloudPirates-io/helm-charts/commit/967558f)) +* chore: update CHANGELOG.md for merged changes ([a4d1e7f](https://github.com/CloudPirates-io/helm-charts/commit/a4d1e7f)) +* chore: update CHANGELOG.md for merged changes ([2c4ecc0](https://github.com/CloudPirates-io/helm-charts/commit/2c4ecc0)) + +## 0.13.2 (2025-11-04) + +* Update charts/redis/values.yaml redis to v8.2.3 (patch) (#536) ([2410eff](https://github.com/CloudPirates-io/helm-charts/commit/2410eff)) +* chore: update CHANGELOG.md for merged changes ([3d3b17a](https://github.com/CloudPirates-io/helm-charts/commit/3d3b17a)) +* chore: update CHANGELOG.md for merged changes ([ff8e82c](https://github.com/CloudPirates-io/helm-charts/commit/ff8e82c)) + +## 0.13.1 (2025-11-03) + +* [oliver006/redis_exporter] Update image to v1.80.0 (#532) ([f357771](https://github.com/CloudPirates-io/helm-charts/commit/f357771)) +* chore: update CHANGELOG.md for merged changes ([c86f513](https://github.com/CloudPirates-io/helm-charts/commit/c86f513)) +* chore: update CHANGELOG.md for merged changes ([b74d280](https://github.com/CloudPirates-io/helm-charts/commit/b74d280)) +* chore: auto-generate values.schema.json (#521) ([fe2d15b](https://github.com/CloudPirates-io/helm-charts/commit/fe2d15b)) + +## 0.13.0 (2025-10-31) + +* Implement startup probe ([579459a](https://github.com/CloudPirates-io/helm-charts/commit/579459a)) +* chore: update CHANGELOG.md for merged changes ([0acfe5d](https://github.com/CloudPirates-io/helm-charts/commit/0acfe5d)) +* chore: update CHANGELOG.md for merged changes ([91ce68f](https://github.com/CloudPirates-io/helm-charts/commit/91ce68f)) + +## 0.12.1 (2025-10-31) + +* Fix probes commands (#511) ([0ac529f](https://github.com/CloudPirates-io/helm-charts/commit/0ac529f)) +* chore: update CHANGELOG.md for merged changes ([3c4c441](https://github.com/CloudPirates-io/helm-charts/commit/3c4c441)) +* chore: update CHANGELOG.md for merged changes ([fb351f7](https://github.com/CloudPirates-io/helm-charts/commit/fb351f7)) + +## 0.12.0 (2025-10-30) + +* Add support for Redis Cluster (#507) ([c1e9fa8](https://github.com/CloudPirates-io/helm-charts/commit/c1e9fa8)) +* chore: update CHANGELOG.md for merged changes ([640b0f6](https://github.com/CloudPirates-io/helm-charts/commit/640b0f6)) +* chore: update CHANGELOG.md for merged changes ([bae5763](https://github.com/CloudPirates-io/helm-charts/commit/bae5763)) + +## 0.11.2 (2025-10-30) + +* fix: extraEnvVars parameter in statefulset template (#503) ([b681b99](https://github.com/CloudPirates-io/helm-charts/commit/b681b99)) +* chore: update CHANGELOG.md for merged changes ([434f326](https://github.com/CloudPirates-io/helm-charts/commit/434f326)) +* chore: update CHANGELOG.md for merged changes ([d3545cc](https://github.com/CloudPirates-io/helm-charts/commit/d3545cc)) + +## 0.11.1 (2025-10-29) + +* fix: metrics sidecar variable expansion (#499) ([af02f4a](https://github.com/CloudPirates-io/helm-charts/commit/af02f4a)) +* chore: update CHANGELOG.md for merged changes ([aec72a0](https://github.com/CloudPirates-io/helm-charts/commit/aec72a0)) +* chore: update CHANGELOG.md for merged changes ([5a8f954](https://github.com/CloudPirates-io/helm-charts/commit/5a8f954)) + +## 0.11.0 (2025-10-29) + +* Add master service for non-sentinel replication mode (#492) ([cafeccd](https://github.com/CloudPirates-io/helm-charts/commit/cafeccd)) +* chore: update CHANGELOG.md for merged changes ([8b84f2b](https://github.com/CloudPirates-io/helm-charts/commit/8b84f2b)) +* chore: update CHANGELOG.md for merged changes ([7bc4166](https://github.com/CloudPirates-io/helm-charts/commit/7bc4166)) +* chore: auto-generate values.schema.json (#487) ([fffe3af](https://github.com/CloudPirates-io/helm-charts/commit/fffe3af)) +* chore: update CHANGELOG.md for merged changes ([c7fa503](https://github.com/CloudPirates-io/helm-charts/commit/c7fa503)) +* chore: update CHANGELOG.md for merged changes ([ad9695d](https://github.com/CloudPirates-io/helm-charts/commit/ad9695d)) + +## 0.10.2 (2025-10-28) + +* Add support for extraPorts in Services and StatefulSet (#485) ([1805522](https://github.com/CloudPirates-io/helm-charts/commit/1805522)) +* chore: update CHANGELOG.md for merged changes ([170dd6a](https://github.com/CloudPirates-io/helm-charts/commit/170dd6a)) +* chore: update CHANGELOG.md for merged changes ([9227d83](https://github.com/CloudPirates-io/helm-charts/commit/9227d83)) +* [etcd, rabbitmq, redis, zookeeper] add signature verification documentation to readme (#476) ([91c7310](https://github.com/CloudPirates-io/helm-charts/commit/91c7310)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.10.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([05fdd01](https://github.com/CloudPirates-io/helm-charts/commit/05fdd01)) +* chore: update CHANGELOG.md for merged changes ([807dd92](https://github.com/CloudPirates-io/helm-charts/commit/807dd92)) + +## 0.9.8 (2025-10-27) + +* fix service annotations (#470) ([74d2a99](https://github.com/CloudPirates-io/helm-charts/commit/74d2a99)) +* chore: update CHANGELOG.md for merged changes ([cb10f6b](https://github.com/CloudPirates-io/helm-charts/commit/cb10f6b)) +* chore: update CHANGELOG.md for merged changes ([ea886c4](https://github.com/CloudPirates-io/helm-charts/commit/ea886c4)) +* chore: auto-generate values.schema.json (#466) ([650333f](https://github.com/CloudPirates-io/helm-charts/commit/650333f)) + +## 0.9.7 (2025-10-26) + +* Redis / Rabbitmq: add lifecyle hooks ([b253776](https://github.com/CloudPirates-io/helm-charts/commit/b253776)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.9.6 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([d014098](https://github.com/CloudPirates-io/helm-charts/commit/d014098)) +* chore: update CHANGELOG.md for merged changes ([a839665](https://github.com/CloudPirates-io/helm-charts/commit/a839665)) + +## 0.9.5 (2025-10-22) + +* add service support annotations (#446) ([72e7eb7](https://github.com/CloudPirates-io/helm-charts/commit/72e7eb7)) +* chore: update CHANGELOG.md for merged changes ([baf1dea](https://github.com/CloudPirates-io/helm-charts/commit/baf1dea)) +* chore: update CHANGELOG.md for merged changes ([42db63e](https://github.com/CloudPirates-io/helm-charts/commit/42db63e)) + +## 0.9.4 (2025-10-22) + +* Update charts/redis/values.yaml redis (#434) ([b833a77](https://github.com/CloudPirates-io/helm-charts/commit/b833a77)) +* chore: update CHANGELOG.md for merged changes ([4587534](https://github.com/CloudPirates-io/helm-charts/commit/4587534)) +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.9.3 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([71d5536](https://github.com/CloudPirates-io/helm-charts/commit/71d5536)) +* chore: update CHANGELOG.md for merged changes ([74b289b](https://github.com/CloudPirates-io/helm-charts/commit/74b289b)) + +## 0.9.2 (2025-10-21) + +* Modifiable cluster domain (#427) ([88652de](https://github.com/CloudPirates-io/helm-charts/commit/88652de)) +* chore: update CHANGELOG.md for merged changes ([c086532](https://github.com/CloudPirates-io/helm-charts/commit/c086532)) +* chore: update CHANGELOG.md for merged changes ([1742285](https://github.com/CloudPirates-io/helm-charts/commit/1742285)) +* chore: update CHANGELOG.md for merged changes ([48cf77d](https://github.com/CloudPirates-io/helm-charts/commit/48cf77d)) +* chore: update CHANGELOG.md for merged changes ([cd0be3e](https://github.com/CloudPirates-io/helm-charts/commit/cd0be3e)) + +## 0.9.1 (2025-10-21) + +* add support for replication mode without sentinel (#428) ([8cbfff2](https://github.com/CloudPirates-io/helm-charts/commit/8cbfff2)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([ef1ad8c](https://github.com/CloudPirates-io/helm-charts/commit/ef1ad8c)) +* chore: update CHANGELOG.md for merged changes ([aa678df](https://github.com/CloudPirates-io/helm-charts/commit/aa678df)) +* chore: update CHANGELOG.md for merged changes ([2998496](https://github.com/CloudPirates-io/helm-charts/commit/2998496)) + +## 0.9.0 (2025-10-17) + +* Network policies (#412) ([43c7285](https://github.com/CloudPirates-io/helm-charts/commit/43c7285)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([96dc658](https://github.com/CloudPirates-io/helm-charts/commit/96dc658)) +* chore: update CHANGELOG.md for merged changes ([80f5de8](https://github.com/CloudPirates-io/helm-charts/commit/80f5de8)) + +## 0.8.5 (2025-10-17) + +* [oliver006/redis_exporter] Update image to v1.79.0 (#408) ([11c625a](https://github.com/CloudPirates-io/helm-charts/commit/11c625a)) +* chore: update CHANGELOG.md for merged changes ([3442284](https://github.com/CloudPirates-io/helm-charts/commit/3442284)) +* chore: update CHANGELOG.md for merged changes ([0295d80](https://github.com/CloudPirates-io/helm-charts/commit/0295d80)) + +## 0.8.4 (2025-10-17) + +* Allow Sentinel authentication to be configured independently from Redis authentication (#403) ([ac12616](https://github.com/CloudPirates-io/helm-charts/commit/ac12616)) +* chore: update CHANGELOG.md for merged changes ([6ebfa2b](https://github.com/CloudPirates-io/helm-charts/commit/6ebfa2b)) +* chore: update CHANGELOG.md for merged changes ([a207257](https://github.com/CloudPirates-io/helm-charts/commit/a207257)) + +## 0.8.3 (2025-10-15) + +* Add initContainer securityContext and improve security defaults (#397) ([2b5c4bd](https://github.com/CloudPirates-io/helm-charts/commit/2b5c4bd)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([7b3173b](https://github.com/CloudPirates-io/helm-charts/commit/7b3173b)) +* chore: update CHANGELOG.md for merged changes ([ea7518b](https://github.com/CloudPirates-io/helm-charts/commit/ea7518b)) + +## 0.8.2 (2025-10-14) + +* Add additional args (#384) ([6dc59eb](https://github.com/CloudPirates-io/helm-charts/commit/6dc59eb)) +* chore: update CHANGELOG.md for merged changes ([d81bc22](https://github.com/CloudPirates-io/helm-charts/commit/d81bc22)) +* chore: update CHANGELOG.md for merged changes ([514e3a7](https://github.com/CloudPirates-io/helm-charts/commit/514e3a7)) + +## 0.8.1 (2025-10-14) + +* Fix namespace key prefix on redis pdb (#385) ([6451b4c](https://github.com/CloudPirates-io/helm-charts/commit/6451b4c)) +* chore: update CHANGELOG.md for merged changes ([420f342](https://github.com/CloudPirates-io/helm-charts/commit/420f342)) +* chore: update CHANGELOG.md for merged changes ([f594b6b](https://github.com/CloudPirates-io/helm-charts/commit/f594b6b)) + +## 0.8.0 (2025-10-14) + +* Add pdb and rootOnlyFilesystem options (#383) ([86b889f](https://github.com/CloudPirates-io/helm-charts/commit/86b889f)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.7.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.6.4 (2025-10-13) + + +## 0.6.3 (2025-10-10) + +* feat: use "common.namespace" (#332) ([6dd8563](https://github.com/CloudPirates-io/helm-charts/commit/6dd8563)) + +## 0.6.2 (2025-10-09) + +* fix: better IPv6 compatibility (#296) ([1d3543c](https://github.com/CloudPirates-io/helm-charts/commit/1d3543c)) + ## 0.6.1 (2025-10-09) -* [redis , rabbitmq]: Add podAnnotations ([#294](https://github.com/CloudPirates-io/helm-charts/pull/294)) +* [redis , rabbitmq]: Add podAnnotations (#294) ([6d78869](https://github.com/CloudPirates-io/helm-charts/commit/6d78869)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) ## 0.6.0 (2025-10-09) -* Include podLabels in redis statefulset (#274) ([024da55](https://github.com/CloudPirates-io/helm-charts/commit/024da55)), closes [#274](https://github.com/CloudPirates-io/helm-charts/issues/274) +* Include podLabels in redis statefulset (#274) ([024da55](https://github.com/CloudPirates-io/helm-charts/commit/024da55)) -## 0.5.7 (2025-10-09) +## 0.5.7 (2025-10-09) -* Update charts/redis/values.yaml redis to v8.2.2 (patch) (#264) ([f699d00](https://github.com/CloudPirates-io/helm-charts/commit/f699d00)), closes [#264](https://github.com/CloudPirates-io/helm-charts/issues/264) +* Update charts/redis/values.yaml redis to v8.2.2 (patch) (#264) ([f699d00](https://github.com/CloudPirates-io/helm-charts/commit/f699d00)) -## 0.5.6 (2025-10-08) +## 0.5.6 (2025-10-08) -* [oliver006/redis_exporter] Update oliver006/redis_exporter to v1.78.0 (#235) ([508fd61](https://github.com/CloudPirates-io/helm-charts/commit/508fd61)), closes [#235](https://github.com/CloudPirates-io/helm-charts/issues/235) +* [oliver006/redis_exporter] Update oliver006/redis_exporter to v1.78.0 (#235) ([508fd61](https://github.com/CloudPirates-io/helm-charts/commit/508fd61)) -## 0.5.5 (2025-10-08) +## 0.5.5 (2025-10-08) -* Update redis to v8.2.2 (#233) ([363468b](https://github.com/CloudPirates-io/helm-charts/commit/363468b)), closes [#233](https://github.com/CloudPirates-io/helm-charts/issues/233) +* Update redis to v8.2.2 (#233) ([363468b](https://github.com/CloudPirates-io/helm-charts/commit/363468b)) -## 0.5.4 (2025-10-08) +## 0.5.4 (2025-10-08) -* [redis]: fix dual stack networking issues (#227) ([381bd76](https://github.com/CloudPirates-io/helm-charts/commit/381bd76)), closes [#227](https://github.com/CloudPirates-io/helm-charts/issues/227) +* [redis]: fix dual stack networking issues (#227) ([381bd76](https://github.com/CloudPirates-io/helm-charts/commit/381bd76)) -## 0.5.3 (2025-10-06) +## 0.5.3 (2025-10-06) -* Add automatically generated fields to volumeClaimTemplates (#218) ([5f4142b](https://github.com/CloudPirates-io/helm-charts/commit/5f4142b)), closes [#218](https://github.com/CloudPirates-io/helm-charts/issues/218) +* Add automatically generated fields to volumeClaimTemplates (#218) ([5f4142b](https://github.com/CloudPirates-io/helm-charts/commit/5f4142b)) -## 0.5.2 (2025-10-06) +## 0.5.2 (2025-10-06) -* chore(deps): update redis:8.2.1 Docker digest to 5fa2edb (#188) ([6a72e00](https://github.com/CloudPirates-io/helm-charts/commit/6a72e00)), closes [#188](https://github.com/CloudPirates-io/helm-charts/issues/188) +* chore(deps): update redis:8.2.1 Docker digest to 5fa2edb (#188) ([6a72e00](https://github.com/CloudPirates-io/helm-charts/commit/6a72e00)) -## 0.5.1 (2025-10-06) +## 0.5.1 (2025-10-06) -* chore(deps): update docker.io/redis:8.2.1 Docker digest to 5fa2edb (#187) ([fe21dc2](https://github.com/CloudPirates-io/helm-charts/commit/fe21dc2)), closes [#187](https://github.com/CloudPirates-io/helm-charts/issues/187) +* chore(deps): update docker.io/redis:8.2.1 Docker digest to 5fa2edb (#187) ([fe21dc2](https://github.com/CloudPirates-io/helm-charts/commit/fe21dc2)) ## 0.5.0 (2025-10-01) -* make redis run on openshift (#193) ([cc4d3c3](https://github.com/CloudPirates-io/helm-charts/commit/cc4d3c3)), closes [#193](https://github.com/CloudPirates-io/helm-charts/issues/193) +* make redis run on openshift (#193) ([cc4d3c3](https://github.com/CloudPirates-io/helm-charts/commit/cc4d3c3)) -## 0.4.6 (2025-09-25) +## 0.4.6 (2025-09-25) + +* return fqdn for sentinel master lookup (#156) ([00b9882](https://github.com/CloudPirates-io/helm-charts/commit/00b9882)) + +## 0.4.5 (2025-09-24) -* Add metrics section to the README ([14a37bc](https://github.com/CloudPirates-io/helm-charts/commit/14a37bc)) -* Add topologySpreadConstraints option to the chart ([9c9eeeb](https://github.com/CloudPirates-io/helm-charts/commit/9c9eeeb)) -* add volumeMounts option for sentinel container ([8499307](https://github.com/CloudPirates-io/helm-charts/commit/8499307)) -* bump up chart patch version ([c436c6d](https://github.com/CloudPirates-io/helm-charts/commit/c436c6d)) -* bump up chart patch version ([a5c9dfb](https://github.com/CloudPirates-io/helm-charts/commit/a5c9dfb)) -* fix sentinel conditions. set default to standalone ([bf935fa](https://github.com/CloudPirates-io/helm-charts/commit/bf935fa)) -* Implement redis service monitoring ([3aec93d](https://github.com/CloudPirates-io/helm-charts/commit/3aec93d)) -* requirepass for sentinel cli operations when password is set ([60d1b5c](https://github.com/CloudPirates-io/helm-charts/commit/60d1b5c)) -* return fqdn for sentinel master lookup (#156) ([00b9882](https://github.com/CloudPirates-io/helm-charts/commit/00b9882)), closes [#156](https://github.com/CloudPirates-io/helm-charts/issues/156) -* [redis]: Persistent volume claim retentionpolicy ([1f708a5](https://github.com/CloudPirates-io/helm-charts/commit/1f708a5)) -* Bitnami style fail over script ([9b9a395](https://github.com/CloudPirates-io/helm-charts/commit/9b9a395)) -* Bump chart version ([a892492](https://github.com/CloudPirates-io/helm-charts/commit/a892492)) -* Bump chart version ([a6ac908](https://github.com/CloudPirates-io/helm-charts/commit/a6ac908)) -* Bump version ([43dceb2](https://github.com/CloudPirates-io/helm-charts/commit/43dceb2)) -* Configurable recheck values ([cf31961](https://github.com/CloudPirates-io/helm-charts/commit/cf31961)) -* Decrease defaults ([572cba9](https://github.com/CloudPirates-io/helm-charts/commit/572cba9)) -* Fix invalid master detection ([f1545d9](https://github.com/CloudPirates-io/helm-charts/commit/f1545d9)) -* fix lint ([c9a0e4f](https://github.com/CloudPirates-io/helm-charts/commit/c9a0e4f)) -* Fix lint ([9943a66](https://github.com/CloudPirates-io/helm-charts/commit/9943a66)) -* Fix pod not restarting after configmap change ([8181649](https://github.com/CloudPirates-io/helm-charts/commit/8181649)) -* Fix reviews ([87c780c](https://github.com/CloudPirates-io/helm-charts/commit/87c780c)) -* Fix roles ([9f6cd01](https://github.com/CloudPirates-io/helm-charts/commit/9f6cd01)) -* Full rework ([a8f4e56](https://github.com/CloudPirates-io/helm-charts/commit/a8f4e56)) -* Implement redis sentinal functionality ([70d64d5](https://github.com/CloudPirates-io/helm-charts/commit/70d64d5)) -* Implement suggested improvements ([aeac191](https://github.com/CloudPirates-io/helm-charts/commit/aeac191)) -* Improve defaults ([b964825](https://github.com/CloudPirates-io/helm-charts/commit/b964825)) -* Minor improvements ([016dee2](https://github.com/CloudPirates-io/helm-charts/commit/016dee2)) -* Sync on restart if sentinel available ([628128e](https://github.com/CloudPirates-io/helm-charts/commit/628128e)) -* Unhardcode ips ([b6e0a4e](https://github.com/CloudPirates-io/helm-charts/commit/b6e0a4e)) * Update CHANGELOG.md ([7691aa0](https://github.com/CloudPirates-io/helm-charts/commit/7691aa0)) +* requirepass for sentinel cli operations when password is set ([60d1b5c](https://github.com/CloudPirates-io/helm-charts/commit/60d1b5c)) * Update CHANGELOG.md ([fcf698f](https://github.com/CloudPirates-io/helm-charts/commit/fcf698f)) * Update CHANGELOG.md ([1afe498](https://github.com/CloudPirates-io/helm-charts/commit/1afe498)) * Update CHANGELOG.md ([0da41aa](https://github.com/CloudPirates-io/helm-charts/commit/0da41aa)) * Update CHANGELOG.md ([8425f12](https://github.com/CloudPirates-io/helm-charts/commit/8425f12)) * Update CHANGELOG.md ([2753a1e](https://github.com/CloudPirates-io/helm-charts/commit/2753a1e)) + +## 0.4.4 (2025-09-23) + * Update CHANGELOG.md ([f6ea97b](https://github.com/CloudPirates-io/helm-charts/commit/f6ea97b)) * Update CHANGELOG.md ([9bd42ad](https://github.com/CloudPirates-io/helm-charts/commit/9bd42ad)) +* [redis]: Persistent volume claim retentionpolicy ([1f708a5](https://github.com/CloudPirates-io/helm-charts/commit/1f708a5)) + +## 0.4.3 (2025-09-23) + * Update CHANGELOG.md ([497514f](https://github.com/CloudPirates-io/helm-charts/commit/497514f)) +* add volumeMounts option for sentinel container ([8499307](https://github.com/CloudPirates-io/helm-charts/commit/8499307)) + +## 0.4.2 (2025-09-23) + * Update CHANGELOG.md ([18008d2](https://github.com/CloudPirates-io/helm-charts/commit/18008d2)) +* bump up chart patch version ([c436c6d](https://github.com/CloudPirates-io/helm-charts/commit/c436c6d)) +* Add topologySpreadConstraints option to the chart ([9c9eeeb](https://github.com/CloudPirates-io/helm-charts/commit/9c9eeeb)) + +## 0.4.1 (2025-09-23) + +* bump up chart patch version ([a5c9dfb](https://github.com/CloudPirates-io/helm-charts/commit/a5c9dfb)) +* Add metrics section to the README ([14a37bc](https://github.com/CloudPirates-io/helm-charts/commit/14a37bc)) + +## 0.4.0 (2025-09-22) + +* Fix reviews ([87c780c](https://github.com/CloudPirates-io/helm-charts/commit/87c780c)) * Update CHANGELOG.md ([dfaff03](https://github.com/CloudPirates-io/helm-charts/commit/dfaff03)) +* Implement redis service monitoring ([3aec93d](https://github.com/CloudPirates-io/helm-charts/commit/3aec93d)) + +## 0.3.3 (2025-09-18) + * Update CHANGELOG.md ([e60664c](https://github.com/CloudPirates-io/helm-charts/commit/e60664c)) +* chore: bump chart version ([b8bec46](https://github.com/CloudPirates-io/helm-charts/commit/b8bec46)) +* feat: bind resource to init-container resources from values ([014db83](https://github.com/CloudPirates-io/helm-charts/commit/014db83)) +* feat: add init container resources configurable values ([852ac34](https://github.com/CloudPirates-io/helm-charts/commit/852ac34)) + +## 0.3.2 (2025-09-18) + * Update CHANGELOG.md ([025e4b2](https://github.com/CloudPirates-io/helm-charts/commit/025e4b2)) +* Fix lint ([9943a66](https://github.com/CloudPirates-io/helm-charts/commit/9943a66)) +* Bump chart version ([a892492](https://github.com/CloudPirates-io/helm-charts/commit/a892492)) +* Fix pod not restarting after configmap change ([8181649](https://github.com/CloudPirates-io/helm-charts/commit/8181649)) + +## 0.3.1 (2025-09-17) + * Update CHANGELOG.md ([a4c0fd0](https://github.com/CloudPirates-io/helm-charts/commit/a4c0fd0)) +* fix sentinel conditions. set default to standalone ([bf935fa](https://github.com/CloudPirates-io/helm-charts/commit/bf935fa)) + +## 0.3.0 (2025-09-15) + +* Decrease defaults ([572cba9](https://github.com/CloudPirates-io/helm-charts/commit/572cba9)) +* Bitnami style fail over script ([9b9a395](https://github.com/CloudPirates-io/helm-charts/commit/9b9a395)) +* Unhardcode ips ([b6e0a4e](https://github.com/CloudPirates-io/helm-charts/commit/b6e0a4e)) +* Implement suggested improvements ([aeac191](https://github.com/CloudPirates-io/helm-charts/commit/aeac191)) +* Improve defaults ([b964825](https://github.com/CloudPirates-io/helm-charts/commit/b964825)) +* Configurable recheck values ([cf31961](https://github.com/CloudPirates-io/helm-charts/commit/cf31961)) +* Full rework ([a8f4e56](https://github.com/CloudPirates-io/helm-charts/commit/a8f4e56)) * Update CHANGELOG.md ([103dbd5](https://github.com/CloudPirates-io/helm-charts/commit/103dbd5)) +* Sync on restart if sentinel available ([628128e](https://github.com/CloudPirates-io/helm-charts/commit/628128e)) +* Minor improvements ([016dee2](https://github.com/CloudPirates-io/helm-charts/commit/016dee2)) * Update CHANGELOG.md ([4657370](https://github.com/CloudPirates-io/helm-charts/commit/4657370)) +* Fix invalid master detection ([f1545d9](https://github.com/CloudPirates-io/helm-charts/commit/f1545d9)) +* Fix roles ([9f6cd01](https://github.com/CloudPirates-io/helm-charts/commit/9f6cd01)) * Update CHANGELOG.md ([e572ff3](https://github.com/CloudPirates-io/helm-charts/commit/e572ff3)) +* fix lint ([c9a0e4f](https://github.com/CloudPirates-io/helm-charts/commit/c9a0e4f)) +* Bump chart version ([a6ac908](https://github.com/CloudPirates-io/helm-charts/commit/a6ac908)) +* Implement redis sentinal functionality ([70d64d5](https://github.com/CloudPirates-io/helm-charts/commit/70d64d5)) + +## 0.2.1 (2025-09-09) + * Update CHANGELOG.md ([507c187](https://github.com/CloudPirates-io/helm-charts/commit/507c187)) +* Bump version ([43dceb2](https://github.com/CloudPirates-io/helm-charts/commit/43dceb2)) * Update docker.io/redis:8.2.1 Docker digest to acb90ce ([eb469b0](https://github.com/CloudPirates-io/helm-charts/commit/eb469b0)) -* chore: bump chart version ([b8bec46](https://github.com/CloudPirates-io/helm-charts/commit/b8bec46)) -* feat: add init container resources configurable values ([852ac34](https://github.com/CloudPirates-io/helm-charts/commit/852ac34)) -* feat: bind resource to init-container resources from values ([014db83](https://github.com/CloudPirates-io/helm-charts/commit/014db83)) ## 0.2.0 (2025-09-02) -* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) * bump all chart versions for new extraObjects feature ([aaa57f9](https://github.com/CloudPirates-io/helm-charts/commit/aaa57f9)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) -## 0.1.8 (2025-08-31) +## 0.1.8 (2025-08-31) -* Add support for statefulset priorityclassname ([b5847dd](https://github.com/CloudPirates-io/helm-charts/commit/b5847dd)) * Update CHANGELOG.md ([d1c5ba2](https://github.com/CloudPirates-io/helm-charts/commit/d1c5ba2)) +* Add support for statefulset priorityclassname ([b5847dd](https://github.com/CloudPirates-io/helm-charts/commit/b5847dd)) -## 0.1.7 (2025-08-28) +## 0.1.7 (2025-08-28) -* add readme and values.schema.json ([873286c](https://github.com/CloudPirates-io/helm-charts/commit/873286c)) -* Fix typo in readme ([cce0ea8](https://github.com/CloudPirates-io/helm-charts/commit/cce0ea8)) -* fix version ([2701959](https://github.com/CloudPirates-io/helm-charts/commit/2701959)) -* Refactor chart ([33323aa](https://github.com/CloudPirates-io/helm-charts/commit/33323aa)) -* Update chart to 0.1.1 ([5fa15b9](https://github.com/CloudPirates-io/helm-charts/commit/5fa15b9)) -* Update version to 8.2.1 / Fix readme ([5266eaf](https://github.com/CloudPirates-io/helm-charts/commit/5266eaf)) -* Add ArtifactHub Badges to all Charts ([08b855b](https://github.com/CloudPirates-io/helm-charts/commit/08b855b)) -* Add ArtifactHub repo config ([15180a8](https://github.com/CloudPirates-io/helm-charts/commit/15180a8)) -* Add cosign signature READMEs ([5f82e7f](https://github.com/CloudPirates-io/helm-charts/commit/5f82e7f)) -* Add extensive chart testing ([a46efac](https://github.com/CloudPirates-io/helm-charts/commit/a46efac)) -* Add generated values.schema.json files from values.yaml ([aa79ac3](https://github.com/CloudPirates-io/helm-charts/commit/aa79ac3)) -* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) -* Add LICENSE ([fdbf1ab](https://github.com/CloudPirates-io/helm-charts/commit/fdbf1ab)) -* add logos to helm-charts ([fc70cdc](https://github.com/CloudPirates-io/helm-charts/commit/fc70cdc)) +* Update CHANGELOG.md ([26bf940](https://github.com/CloudPirates-io/helm-charts/commit/26bf940)) * Bump chart version ([395c7d5](https://github.com/CloudPirates-io/helm-charts/commit/395c7d5)) -* Fix image tag/digest handling ([a5c982b](https://github.com/CloudPirates-io/helm-charts/commit/a5c982b)) -* Fix imagePullSecrets format and pull always ([ce0d301](https://github.com/CloudPirates-io/helm-charts/commit/ce0d301)) -* fix readme.md install text, update chart.yaml home-website ([3511582](https://github.com/CloudPirates-io/helm-charts/commit/3511582)) +* Fix typo in readme ([cce0ea8](https://github.com/CloudPirates-io/helm-charts/commit/cce0ea8)) + +## 0.1.6 (2025-08-27) + * Fix values.yaml / Chart.yaml linting issues ([043c7e0](https://github.com/CloudPirates-io/helm-charts/commit/043c7e0)) -* Format README files ([04aacab](https://github.com/CloudPirates-io/helm-charts/commit/04aacab)) -* init, add mariadb, mongodb and redis chart ([8e44c83](https://github.com/CloudPirates-io/helm-charts/commit/8e44c83)) -* Release new chart versions / update sources ([dbb0e45](https://github.com/CloudPirates-io/helm-charts/commit/dbb0e45)) -* Remove leading $ from code blocks ([836b2e3](https://github.com/CloudPirates-io/helm-charts/commit/836b2e3)) -* remove serviceaccounts from all charts ([be8f43a](https://github.com/CloudPirates-io/helm-charts/commit/be8f43a)) -* Update CHANGELOG.md ([26bf940](https://github.com/CloudPirates-io/helm-charts/commit/26bf940)) -* Update docker.io/redis Docker tag to v8.2.1 ([53db488](https://github.com/CloudPirates-io/helm-charts/commit/53db488)) -* update readme, chart.yaml texts and descriptions ([0179046](https://github.com/CloudPirates-io/helm-charts/commit/0179046)) -* Use lookup function for password where applicable ([dfb9a0e](https://github.com/CloudPirates-io/helm-charts/commit/dfb9a0e)) -* fix: chart icon urls ([cc38c0d](https://github.com/CloudPirates-io/helm-charts/commit/cc38c0d)) +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.1.5 (2025-08-26) + +* Initial tagged release diff --git a/charts/redis/Chart.lock b/charts/redis/Chart.lock index a52dadf2..5e3540df 100644 --- a/charts/redis/Chart.lock +++ b/charts/redis/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-09-30T20:54:19.733262+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:15:01.11841+02:00" diff --git a/charts/redis/Chart.yaml b/charts/redis/Chart.yaml index 5be29e05..22a09c3a 100644 --- a/charts/redis/Chart.yaml +++ b/charts/redis/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: redis description: An open source, in-memory data structure store used as a database, cache, and message broker. type: application -version: 0.6.1 -appVersion: "8.2.1" +version: 0.14.0 +appVersion: "8.2.3" keywords: - redis - database @@ -11,17 +11,38 @@ keywords: - in-memory - key-value - nosql -home: https://www.cloudpirates.io +home: https://www.redis.io sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/redis -annotations: - category: Database - license: Apache-2.0 + - https://github.com/redis/redis maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/32c74816d1/redis-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: Redis + url: https://redis.io + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/redis + - name: Application + url: https://github.com/redis/redis + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "[redis]: Headless Service annotations" + links: + - name: "Commit 10daf47" + url: "https://github.com/CloudPirates-io/helm-charts/commit/10daf47" diff --git a/charts/redis/README.md b/charts/redis/README.md index 87e91e67..a7d33f32 100644 --- a/charts/redis/README.md +++ b/charts/redis/README.md @@ -54,6 +54,26 @@ kubectl run redis-client --rm --tty -i --restart='Never' \ redis-cli -h my-redis -a $REDIS_PASSWORD ``` +## Security & Signature Verification + +This Helm chart is cryptographically signed with Cosign to ensure authenticity and prevent tampering. + +**Public Key:** + +``` +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7BgqFgKdPtHdXz6OfYBklYwJgGWQ +mZzYz8qJ9r6QhF3NxK8rD2oG7Bk6nHJz7qWXhQoU2JvJdI3Zx9HGpLfKvw== +-----END PUBLIC KEY----- +``` + +To verify the helm chart before installation, copy the public key to the file `cosign.pub` and run cosign: + +```bash +cosign verify --key cosign.pub registry-1.docker.io/cloudpirates/redis: +``` + + ## Configuration ### Image Configuration @@ -69,14 +89,17 @@ redis-cli -h my-redis -a $REDIS_PASSWORD ### Common Parameters -| Parameter | Description | Default | -|---------------------| ----------------------------------------------------------------------- | ------------ | -| `nameOverride` | String to partially override redis.fullname | `""` | -| `fullnameOverride` | String to fully override redis.fullname | `""` | -| `commonLabels` | Labels to add to all deployed objects | `{}` | -| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | -| `architecture` | Redis architecture. Allowed values: `standalone` or `replication` | `standalone` | -| `replicaCount` | Number of Redis replicas to deploy (only when architecture=replication) | `2` | +| Parameter | Description | Default | +| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | +| `nameOverride` | String to partially override redis.fullname | `""` | +| `fullnameOverride` | String to fully override redis.fullname | `""` | +| `namespaceOverride` | String to override the namespace for all resources | `""` | +| `clusterDomain` | Kubernetes cluster domain | `cluster.local` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `architecture` | Redis architecture. `standalone`: Single instance, `cluster`: Multi-master cluster, `replication`: Master-replica (use `sentinel.enabled` to control automatic failover) | `standalone` | +| `replicaCount` | Number of Redis instances (when `architecture=replication\|cluster`). As cluster or replication with Sentinel: total instances. Replication without Sentinel: 1 master + (n-1) replicas | `3` | +| `clusterReplicaCount` | Number of replicas to be created for each master when `architecture=cluster`. | `0` | ### Pod labels and annotations @@ -88,16 +111,19 @@ redis-cli -h my-redis -a $REDIS_PASSWORD ### Service Configuration -| Parameter | Description | Default | -| -------------- | ----------------------- | ----------- | -| `service.type` | Kubernetes service type | `ClusterIP` | -| `service.port` | Redis service port | `6379` | +| Parameter | Description | Default | +| --------------------- | ------------------------------ | ----------- | +| `service.annotations` | Kubernetes service annotations | `{}` | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.port` | Redis service port | `6379` | +| `service.clusterPort` | Redis cluster service port | `16379` | ### Authentication | Parameter | Description | Default | | -------------------------------- | ------------------------------------------------------------ | ------- | | `auth.enabled` | Enable Redis authentication | `true` | +| `auth.sentinel` | Enable authentication for Redis sentinels | `true` | | `auth.password` | Redis password (if empty, random password will be generated) | `""` | | `auth.existingSecret` | Name of existing secret containing Redis password | `""` | | `auth.existingSecretPasswordKey` | Key in existing secret containing Redis password | `""` | @@ -143,6 +169,14 @@ redis-cli -h my-redis -a $REDIS_PASSWORD | `metrics.serviceMonitor.annotations` | Additional custom annotations for the ServiceMonitor | `{}` | | `metrics.serviceMonitor.namespaceSelector` | Namespace selector for ServiceMonitor | `{}` | +### Pod Disruption Budget + +| Parameter | Description | Default | +| -------------------- | -------------------------------------------------------------- | ------- | +| `pdb.enabled` | Enable Pod Disruption Budget | `false` | +| `pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `1` | +| `pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable | `""` | + ### Persistence | Parameter | Description | Default | @@ -156,11 +190,11 @@ redis-cli -h my-redis -a $REDIS_PASSWORD ### Persistent Volume Claim Retention Policy -| Parameter | Description | Default | -| ---------------------------------------------------- | ------------------------------------------------------------------------------- | ----------- | -| `persistentVolumeClaimRetentionPolicy.enabled` | Enable Persistent volume retention policy for the Statefulset | `false` | -| `persistentVolumeClaimRetentionPolicy.whenDeleted` | Volume retention behavior that applies when the StatefulSet is deleted | `"Retain"` | -| `persistentVolumeClaimRetentionPolicy.whenScaled` | Volume retention behavior when the replica count of the StatefulSet is reduced | `"Retain"` | +| Parameter | Description | Default | +| -------------------------------------------------- | ------------------------------------------------------------------------------ | ---------- | +| `persistentVolumeClaimRetentionPolicy.enabled` | Enable Persistent volume retention policy for the StatefulSet | `false` | +| `persistentVolumeClaimRetentionPolicy.whenDeleted` | Volume retention behavior that applies when the StatefulSet is deleted | `"Retain"` | +| `persistentVolumeClaimRetentionPolicy.whenScaled` | Volume retention behavior when the replica count of the StatefulSet is reduced | `"Retain"` | ### Resource Management @@ -182,12 +216,17 @@ redis-cli -h my-redis -a $REDIS_PASSWORD ### Security Context -| Parameter | Description | Default | -| --------------------------------------------------- | ------------------------------ | ------- | -| `containerSecurityContext.runAsUser` | User ID to run the container | `999` | -| `containerSecurityContext.runAsNonRoot` | Run as non-root user | `true` | -| `containerSecurityContext.allowPrivilegeEscalation` | Allow privilege escalation | `false` | -| `podSecurityContext.fsGroup` | Pod's Security Context fsGroup | `999` | +| Parameter | Description | Default | +| --------------------------------------------------- | --------------------------------- | ---------------- | +| `containerSecurityContext.runAsUser` | User ID to run the container | `999` | +| `containerSecurityContext.runAsGroup` | Group ID to run the container | `999` | +| `containerSecurityContext.runAsNonRoot` | Run as non-root user | `true` | +| `containerSecurityContext.privileged` | Set container's privileged mode | `false` | +| `containerSecurityContext.allowPrivilegeEscalation` | Allow privilege escalation | `false` | +| `containerSecurityContext.readOnlyRootFilesystem` | Read-only root filesystem | `true` | +| `containerSecurityContext.capabilities.drop` | Linux capabilities to be dropped | `["ALL"]` | +| `containerSecurityContext.seccompProfile.type` | Seccomp profile for the container | `RuntimeDefault` | +| `podSecurityContext.fsGroup` | Pod's Security Context fsGroup | `999` | ### Health Checks @@ -215,35 +254,36 @@ redis-cli -h my-redis -a $REDIS_PASSWORD ### Redis Sentinel Configuration (High Availability) -Redis Sentinel provides high availability for Redis through automatic failover. When enabled in `replication` mode, Sentinel monitors the master and replicas, and promotes a replica to master if the current master becomes unavailable. - -| Parameter | Description | Default | -| ------------------------------------ | ----------------------------------------------------- | ------------------ | -| `sentinel.enabled` | Enable Redis Sentinel for high availability | `false` | -| `sentinel.image.repository` | Redis Sentinel image repository | `redis` | -| `sentinel.image.tag` | Redis Sentinel image tag | `8.2.1@sha256:...` | -| `sentinel.image.pullPolicy` | Sentinel image pull policy | `Always` | -| `sentinel.masterName` | Name of the master server | `mymaster` | -| `sentinel.quorum` | Number of Sentinels needed to agree on master failure | `2` | -| `sentinel.downAfterMilliseconds` | Time in ms after master is declared down | `30000` | -| `sentinel.failoverTimeout` | Timeout for failover in ms | `180000` | -| `sentinel.parallelSyncs` | Number of replicas to reconfigure during failover | `1` | -| `sentinel.port` | Sentinel port | `26379` | -| `sentinel.service.type` | Kubernetes service type for Sentinel | `ClusterIP` | -| `sentinel.service.port` | Sentinel service port | `26379` | -| `sentinel.resources.limits.memory` | Memory limit for Sentinel pods | `128Mi` | -| `sentinel.resources.requests.cpu` | CPU request for Sentinel pods | `25m` | -| `sentinel.resources.requests.memory` | Memory request for Sentinel pods | `64Mi` | -| `sentinel.extraVolumeMounts` | Additional volume mounts for Sentinel container | `[]` | +Redis Sentinel provides high availability for Redis through automatic failover. When enabled in `replication` mode, Sentinel monitors the master and replicas, and promotes a replica to master if the current master becomes unavailable. When disabled with `replication` mode, pod-0 is always the master. + +| Parameter | Description | Default | +| ------------------------------------ | --------------------------------------------------------------------------------------------- | ------------------ | +| `sentinel.enabled` | Enable Redis Sentinel for high availability. When disabled, pod-0 is master (manual failover) | `false` | +| `sentinel.image.repository` | Redis Sentinel image repository | `redis` | +| `sentinel.image.tag` | Redis Sentinel image tag | `8.2.1@sha256:...` | +| `sentinel.image.pullPolicy` | Sentinel image pull policy | `Always` | +| `sentinel.masterName` | Name of the master server | `mymaster` | +| `sentinel.quorum` | Number of Sentinels needed to agree on master failure | `2` | +| `sentinel.downAfterMilliseconds` | Time in ms after master is declared down | `30000` | +| `sentinel.failoverTimeout` | Timeout for failover in ms | `180000` | +| `sentinel.parallelSyncs` | Number of replicas to reconfigure during failover | `1` | +| `sentinel.port` | Sentinel port | `26379` | +| `sentinel.service.type` | Kubernetes service type for Sentinel | `ClusterIP` | +| `sentinel.service.port` | Sentinel service port | `26379` | +| `sentinel.resources.limits.memory` | Memory limit for Sentinel pods | `128Mi` | +| `sentinel.resources.requests.cpu` | CPU request for Sentinel pods | `25m` | +| `sentinel.resources.requests.memory` | Memory request for Sentinel pods | `64Mi` | +| `sentinel.extraVolumeMounts` | Additional volume mounts for Sentinel container | `[]` | ### Additional Configuration | Parameter | Description | Default | | ------------------- | ----------------------------------------------------------------------- | ------- | -| `extraEnv` | Additional environment variables | `[]` | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraVolumes` | Additional volumes to add to the pod | `[]` | | `extraVolumeMounts` | Additional volume mounts for Redis container | `[]` | | `extraObjects` | A list of additional Kubernetes objects to deploy alongside the release | `[]` | +| `extraPorts` | Additional ports to be exposed by Services and StatefulSet | `[]` | #### Extra Objects @@ -347,16 +387,53 @@ redis-cli -h -p 6379 -a $REDIS_PASSWORD ### Master-Replica without Sentinel -If you want replication without Sentinel (manual failover): +Deploy Redis with replication but without Sentinel for scenarios where automatic failover is not needed: ```yaml -# values-replication.yaml architecture: replication -replicaCount: 2 +replicaCount: 3 # 1 master + 2 replicas sentinel: enabled: false + +auth: + enabled: true ``` +After deployment, you'll have: + +- 1 Redis master instance (pod-0, always the master) +- 2 Redis replica instances (pod-1, pod-2) +- No automatic failover (manual intervention required if master fails) + +**Key differences from Sentinel mode:** + +- Pod-0 is always the master, other pods are always replicas +- No automatic failover - if the master fails, manual intervention is required +- Simpler setup with fewer components +- Lower resource usage (no Sentinel containers) + + +### Cluster mode + +Deploy Redis Cluster with 6 nodes - 3 master and 3 replicas for automated failover: + +```yaml +# values-cluster.yaml +architecture: cluster +replicaCount: 6 +clusterReplicaCount: 1 +``` + +```bash +helm install my-redis ./charts/redis -f values-cluster.yaml +``` + +**Key differences with replication** + +- Redis Cluster supports single database only +- Data is automatically divided across multiple nodes for improved performance +- With cluster-aware client, user can connect to any node (directly or via service) and requests will be automatically redirected, based on MOVED response + ## Upgrading To upgrade your Redis installation: diff --git a/charts/redis/templates/_helpers.tpl b/charts/redis/templates/_helpers.tpl index c7f98abc..ce7441de 100644 --- a/charts/redis/templates/_helpers.tpl +++ b/charts/redis/templates/_helpers.tpl @@ -2,42 +2,42 @@ Expand the name of the chart. */}} {{- define "redis.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "redis.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "redis.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "redis.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Selector labels */}} {{- define "redis.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Common annotations */}} {{- define "redis.annotations" -}} -{{- include "common.annotations" . -}} +{{- include "cloudpirates.annotations" . -}} {{- end }} {{/* @@ -45,7 +45,7 @@ Get the secret name for Redis password */}} {{- define "redis.secretName" -}} {{- if .Values.auth.existingSecret }} -{{- .Values.auth.existingSecret }} +{{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) }} {{- else }} {{- include "redis.fullname" . }} {{- end }} @@ -65,14 +65,14 @@ Get the secret key for Redis password Return the proper Redis image name */}} {{- define "redis.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "redis.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{- define "redis.configFullName" -}} @@ -87,14 +87,14 @@ Return the proper Docker Image Registry Secret Names Return the proper Redis Sentinel image name */}} {{- define "redis.sentinel.image" -}} -{{- include "common.image" (dict "image" .Values.sentinel.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.sentinel.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Redis metrics image name */}} {{- define "redis.metrics.image" -}} -{{- include "common.image" (dict "image" .Values.metrics.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.metrics.image "global" .Values.global) -}} {{- end }} {{/* @@ -106,18 +106,22 @@ app.kubernetes.io/component: sentinel {{- end }} {{/* -Generate Redis CLI command with auth +Generate Redis CLI command with automated auth */}} {{- define "redis.cli" -}} -{{- if .auth -}} -redis-cli -a "${REDIS_PASSWORD}" -{{- else -}} redis-cli {{- end -}} + +{{/* +Generate Redis CLI ping command with automated auth +*/}} +{{- define "redis.ping" -}} +{{ include "redis.cli" . }} ping {{- end -}} + {{/* -Generate Sentinel CLI command with auth and connection info +Generate Sentinel CLI command with automated auth and connection info */}} {{- define "redis.sentinelCli" -}} {{- if .auth -}} diff --git a/charts/redis/templates/configmap.yaml b/charts/redis/templates/configmap.yaml index 41ac77ff..df9f44bb 100644 --- a/charts/redis/templates/configmap.yaml +++ b/charts/redis/templates/configmap.yaml @@ -3,9 +3,13 @@ apiVersion: v1 kind: ConfigMap metadata: name: {{ include "redis.fullname" . }}-config - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} + {{- with (include "redis.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} data: redis.conf: | {{- .Values.config.content | nindent 4 }} diff --git a/charts/redis/templates/extraobjects.yaml b/charts/redis/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/redis/templates/extraobjects.yaml +++ b/charts/redis/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/redis/templates/headless-service.yaml b/charts/redis/templates/headless-service.yaml index 6e500f2c..a0cdcd98 100644 --- a/charts/redis/templates/headless-service.yaml +++ b/charts/redis/templates/headless-service.yaml @@ -2,9 +2,18 @@ apiVersion: v1 kind: Service metadata: name: {{ include "redis.fullname" . }}-headless - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} + {{- if or (include "redis.annotations" .) .Values.service.headless.annotations }} + annotations: + {{- with (include "redis.annotations" .) }} + {{- . | nindent 4 }} + {{- end }} + {{- with .Values.service.headless.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} spec: type: ClusterIP clusterIP: None @@ -13,11 +22,22 @@ spec: targetPort: redis protocol: TCP name: redis + {{- range .Values.extraPorts }} + - port: {{ .port }} + targetPort: {{ .targetPort | default .name }} + name: {{ .name }} + {{- end }} {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} - port: {{ .Values.sentinel.port }} targetPort: sentinel protocol: TCP name: sentinel {{- end }} + {{- if eq .Values.architecture "cluster" }} + - port: {{ .Values.service.clusterPort }} + targetPort: cluster + protocol: TCP + name: cluster + {{- end }} selector: {{- include "redis.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/redis/templates/job.yaml b/charts/redis/templates/job.yaml new file mode 100644 index 00000000..0666741e --- /dev/null +++ b/charts/redis/templates/job.yaml @@ -0,0 +1,71 @@ +{{- if eq .Values.architecture "cluster" }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "redis.fullname" . }}-init-cluster + namespace: {{ include "cloudpirates.namespace" . }} + labels: + {{- include "redis.labels" . | nindent 4 }} + annotations: + {{- include "redis.annotations" . | nindent 4 }} + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + template: + spec: +{{- with (include "redis.imagePullSecrets" .) }} +{{ . | nindent 6 }} +{{- end }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} + restartPolicy: OnFailure + containers: + - name: redis-cluster-init + image: {{ include "redis.image" . | quote }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} + env: + {{- if .Values.auth.enabled }} + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "redis.secretName" . }} + key: {{ include "redis.secretPasswordKey" . }} + - name: REDISCLI_AUTH + valueFrom: + secretKeyRef: + name: {{ include "redis.secretName" . }} + key: {{ include "redis.secretPasswordKey" . }} + {{- end }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} + {{- end }} + command: + - /bin/sh + - -c + - | + set -e + echo "Building list of Redis nodes..." + NODES="" + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do + NODES="$NODES {{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless:{{ .Values.service.port }}" + done + + echo "Waiting for all Redis pods to be reachable..." + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do + until redis-cli -h {{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless -p {{ .Values.service.port }} ping 2>/dev/null ; do + echo "Waiting for pod {{ include "redis.fullname" . }}-${i}..." + sleep 3 + done + done + + echo "Creating Redis cluster with nodes: $NODES" + redis-cli \ + -h {{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless \ + -p {{ .Values.service.port }} \ + --cluster create \ + $NODES \ + {{- if ne (int .Values.clusterReplicaCount) 0 }} + --cluster-replicas {{ .Values.clusterReplicaCount }} \ + {{- end }} + --cluster-yes +{{- end }} \ No newline at end of file diff --git a/charts/redis/templates/master-service.yaml b/charts/redis/templates/master-service.yaml new file mode 100644 index 00000000..d859f40a --- /dev/null +++ b/charts/redis/templates/master-service.yaml @@ -0,0 +1,29 @@ +{{- if and (eq .Values.architecture "replication") (not .Values.sentinel.enabled) }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "redis.fullname" . }}-master + namespace: {{ include "cloudpirates.namespace" . }} + labels: + {{- include "redis.labels" . | nindent 4 }} + app.kubernetes.io/component: master + {{- with (include "redis.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: redis + protocol: TCP + name: redis + {{- range .Values.extraPorts }} + - port: {{ .port }} + targetPort: {{ .targetPort | default .name }} + name: {{ .name }} + {{- end }} + selector: + {{- include "redis.selectorLabels" . | nindent 4 }} + statefulset.kubernetes.io/pod-name: {{ include "redis.fullname" . }}-0 +{{- end }} diff --git a/charts/redis/templates/metrics-service.yaml b/charts/redis/templates/metrics-service.yaml index 600445dd..f1e1ffdf 100644 --- a/charts/redis/templates/metrics-service.yaml +++ b/charts/redis/templates/metrics-service.yaml @@ -3,11 +3,12 @@ apiVersion: v1 kind: Service metadata: name: {{ include "redis.fullname" . }}-metrics - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} app.kubernetes.io/component: metrics - {{- with .Values.metrics.service.annotations }} + {{- $annotations := merge .Values.metrics.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/redis/templates/networkpolicy.yaml b/charts/redis/templates/networkpolicy.yaml new file mode 100644 index 00000000..af2b54ed --- /dev/null +++ b/charts/redis/templates/networkpolicy.yaml @@ -0,0 +1,151 @@ +{{- if .Values.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "redis.fullname" . }} + namespace: {{ include "cloudpirates.namespace" . }} + labels: + {{- include "redis.labels" . | nindent 4 }} + {{- with (include "redis.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "redis.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + # Allow Redis client connections + - ports: + - port: {{ .Values.service.port }} + protocol: TCP + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: {} + {{- end }} + {{- if and (eq .Values.architecture "replication") (not .Values.sentinel.enabled) }} + # Allow Redis replica-to-master communication + - ports: + - port: {{ .Values.service.port }} + protocol: TCP + from: + - podSelector: + matchLabels: + {{- include "redis.selectorLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.sentinel.enabled }} + # Allow Sentinel connections + - ports: + - port: {{ .Values.sentinel.port }} + protocol: TCP + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: {} + {{- end }} + # Allow Sentinel-to-Redis communication + - ports: + - port: {{ .Values.service.port }} + protocol: TCP + from: + - podSelector: + matchLabels: + {{- include "redis.sentinel.selectorLabels" . | nindent 14 }} + # Allow Sentinel peer communication + - ports: + - port: {{ .Values.sentinel.port }} + protocol: TCP + from: + - podSelector: + matchLabels: + {{- include "redis.sentinel.selectorLabels" . | nindent 14 }} + {{- end }} + {{- if eq .Values.architecture "cluster" -}} + - ports: + - port: {{ .Values.service.port }} + protocol: TCP + - port: {{ .Values.service.clusterPort }} + protocol: TCP + from: + - podSelector: + matchLabels: + {{- include "redis.selectorLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.metrics.enabled }} + # Allow metrics scraping + - ports: + - port: {{ .Values.metrics.service.port }} + protocol: TCP + {{- if not .Values.networkPolicy.allowExternal }} + from: + - namespaceSelector: {} + podSelector: + matchLabels: + app.kubernetes.io/name: prometheus + {{- end }} + {{- end }} + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + # Allow DNS resolution + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + {{- if and (eq .Values.architecture "replication") (not .Values.sentinel.enabled) }} + # Allow Redis replica-to-master communication + - ports: + - port: {{ .Values.service.port }} + protocol: TCP + to: + - podSelector: + matchLabels: + {{- include "redis.selectorLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.sentinel.enabled }} + # Allow Redis-to-Sentinel communication + - ports: + - port: {{ .Values.sentinel.port }} + protocol: TCP + to: + - podSelector: + matchLabels: + {{- include "redis.sentinel.selectorLabels" . | nindent 14 }} + # Allow Sentinel-to-Redis communication + - ports: + - port: {{ .Values.service.port }} + protocol: TCP + to: + - podSelector: + matchLabels: + {{- include "redis.selectorLabels" . | nindent 14 }} + # Allow Sentinel peer communication + - ports: + - port: {{ .Values.sentinel.port }} + protocol: TCP + to: + - podSelector: + matchLabels: + {{- include "redis.sentinel.selectorLabels" . | nindent 14 }} + {{- end }} + {{- if eq .Values.architecture "cluster" -}} + - ports: + - port: {{ .Values.service.port }} + protocol: TCP + - port: {{ .Values.service.clusterPort }} + protocol: TCP + to: + - podSelector: + matchLabels: + {{- include "redis.selectorLabels" . | nindent 14 }} + {{- end }} + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/redis/templates/pdb.yaml b/charts/redis/templates/pdb.yaml new file mode 100644 index 00000000..2809cdd1 --- /dev/null +++ b/charts/redis/templates/pdb.yaml @@ -0,0 +1,23 @@ +{{- if .Values.pdb.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "redis.fullname" . }} + namespace: {{ include "cloudpirates.namespace" . }} + labels: + {{- include "redis.labels" . | nindent 4 }} + {{- with (include "redis.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.pdb.minAvailable }} + minAvailable: {{ .Values.pdb.minAvailable }} + {{- end }} + {{- if .Values.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- include "redis.selectorLabels" . | nindent 6 }} +{{- end }} \ No newline at end of file diff --git a/charts/redis/templates/prestop-configmap.yaml b/charts/redis/templates/prestop-configmap.yaml index b4e5b48f..1f673553 100644 --- a/charts/redis/templates/prestop-configmap.yaml +++ b/charts/redis/templates/prestop-configmap.yaml @@ -3,9 +3,13 @@ apiVersion: v1 kind: ConfigMap metadata: name: {{ include "redis.fullname" . }}-prestop-script - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} + {{- with (include "redis.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} data: prestop.sh: | #!/bin/bash @@ -19,17 +23,24 @@ data: REDIS_PORT="{{ .Values.service.port }}" SENTINEL_PORT="{{ .Values.sentinel.port }}" MASTER_NAME="{{ .Values.sentinel.masterName }}" - HEADLESS_SERVICE="{{ include "redis.fullname" . }}-headless.{{ .Release.Namespace }}.svc.cluster.local" - REDIS_SERVICE="{{ include "redis.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + HEADLESS_SERVICE="{{ include "redis.fullname" . }}-headless.{{ include "cloudpirates.namespace" . }}.svc.{{ .Values.clusterDomain }}" + REDIS_SERVICE="{{ include "redis.fullname" . }}.{{ include "cloudpirates.namespace" . }}.svc.{{ .Values.clusterDomain }}" # Set authentication if enabled {{- if .Values.auth.enabled }} export REDISCLI_AUTH="${REDIS_PASSWORD}" {{- end }} + # Set loopback address based on ipFamily configuration + {{- if eq .Values.ipFamily "ipv6" }} + REDIS_LOOPBACK="::1" + {{- else }} + REDIS_LOOPBACK="127.0.0.1" + {{- end }} + # Function to run Redis commands run_redis_command() { - local args=("-h" "127.0.0.1" "-p" "$REDIS_PORT") + local args=("-h" "$REDIS_LOOPBACK" "-p" "$REDIS_PORT") redis-cli "${args[@]}" "$@" } @@ -48,7 +59,7 @@ data: # Function to run Sentinel commands run_sentinel_command() { - redis-cli -h "$REDIS_SERVICE" -p "$SENTINEL_PORT" {{- if .Values.auth.enabled }} -a "${REDIS_PASSWORD}"{{- end }} sentinel "$@" + redis-cli -h "$REDIS_SERVICE" -p "$SENTINEL_PORT" {{- if .Values.auth.sentinel }} -a "${REDIS_PASSWORD}"{{- end }} sentinel "$@" } # Function to check if sentinel failover has finished diff --git a/charts/redis/templates/secret.yaml b/charts/redis/templates/secret.yaml index b0e3cb9d..04d64fdc 100644 --- a/charts/redis/templates/secret.yaml +++ b/charts/redis/templates/secret.yaml @@ -3,12 +3,16 @@ apiVersion: v1 kind: Secret metadata: name: {{ include "redis.fullname" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} + {{- with (include "redis.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} type: Opaque data: - {{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace (include "redis.fullname" .)) }} + {{- $existingSecret := (lookup "v1" "Secret" (include "cloudpirates.namespace" .) (include "redis.fullname" .)) }} {{- $existingPassword := "" }} {{- if and $existingSecret $existingSecret.data }} {{- $existingPassword = index $existingSecret.data "redis-password" }} diff --git a/charts/redis/templates/sentinel-service.yaml b/charts/redis/templates/sentinel-service.yaml index a5cab230..a225b9a2 100644 --- a/charts/redis/templates/sentinel-service.yaml +++ b/charts/redis/templates/sentinel-service.yaml @@ -3,10 +3,14 @@ apiVersion: v1 kind: Service metadata: name: {{ include "redis.fullname" . }}-sentinel - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} app.kubernetes.io/component: sentinel + {{- with (include "redis.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} spec: type: {{ .Values.sentinel.service.type }} ports: diff --git a/charts/redis/templates/service.yaml b/charts/redis/templates/service.yaml index 55d4f050..1cc97d37 100644 --- a/charts/redis/templates/service.yaml +++ b/charts/redis/templates/service.yaml @@ -2,14 +2,21 @@ apiVersion: v1 kind: Service metadata: name: {{ include "redis.fullname" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} - {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- if or $annotations (and .Values.sentinel.enabled (eq .Values.architecture "replication")) }} annotations: + {{- if $annotations }} +{{- toYaml $annotations | nindent 4 }} + {{- end }} + {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} # This service points to all Redis instances for Sentinel-based discovery # Applications should use Sentinel clients to discover the current master service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" + {{- else }} + {{- end }} {{- end }} spec: type: {{ .Values.service.type }} @@ -18,6 +25,11 @@ spec: targetPort: redis protocol: TCP name: redis + {{- range .Values.extraPorts }} + - port: {{ .port }} + targetPort: {{ .targetPort | default .name }} + name: {{ .name }} + {{- end }} selector: {{- include "redis.selectorLabels" . | nindent 4 }} {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} diff --git a/charts/redis/templates/servicemonitor.yaml b/charts/redis/templates/servicemonitor.yaml index 53965ba3..97fdc102 100644 --- a/charts/redis/templates/servicemonitor.yaml +++ b/charts/redis/templates/servicemonitor.yaml @@ -3,7 +3,7 @@ apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: {{ include "redis.fullname" . }}-metrics - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} app.kubernetes.io/component: metrics diff --git a/charts/redis/templates/statefulset.yaml b/charts/redis/templates/statefulset.yaml index d29987a0..5d804afa 100644 --- a/charts/redis/templates/statefulset.yaml +++ b/charts/redis/templates/statefulset.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: StatefulSet metadata: name: {{ include "redis.fullname" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudpirates.namespace" . }} labels: {{- include "redis.labels" . | nindent 4 }} {{- with (include "redis.annotations" .) }} @@ -23,10 +23,10 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} annotations: - {{- if and .Values.config.content (not .Values.config.existingConfigmap) }} - checksum/config: {{ .Values.config.content | sha256sum }} - {{- else if .Values.config.existingConfigmap }} + {{- if .Values.config.existingConfigmap }} checksum/config: {{ .Values.config.existingConfigmap | sha256sum }} + {{- else if .Values.config.content }} + checksum/config: {{ .Values.config.content | sha256sum }} {{- end }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} @@ -35,16 +35,17 @@ spec: {{- with (include "redis.imagePullSecrets" .) }} {{ . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} {{- with .Values.topologySpreadConstraints }} topologySpreadConstraints: {{- toYaml . | nindent 8 }} {{- end }} - {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + {{- if (list "replication" "cluster" | has .Values.architecture) }} initContainers: - name: redis-init image: {{ include "redis.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} command: - /bin/sh - -c @@ -54,33 +55,26 @@ spec: POD_ORDINAL=$(hostname | sed 's/.*-//') MY_HOSTNAME=$(hostname) - # Copy base config - if [ -f "{{ include "redis.configFullName" . }}" ]; then - cp {{ include "redis.configFullName" . }} /tmp/redis.conf - else - # Create minimal config if no config exists - cat > /tmp/redis.conf << EOF - bind 0.0.0.0 - port 6379 - EOF - fi + touch /tmp/redis.conf + + echo "Pod ordinal: $POD_ORDINAL, hostname: $MY_HOSTNAME" + {{- if eq .Values.architecture "replication" }} + {{- if .Values.sentinel.enabled }} # Add Redis configurations for better Sentinel failover tolerance echo "" >> /tmp/redis.conf echo "# Configurations for Kubernetes force deletion tolerance" >> /tmp/redis.conf echo "min-slaves-to-write 0" >> /tmp/redis.conf echo "min-slaves-max-lag 0" >> /tmp/redis.conf - echo "Pod ordinal: $POD_ORDINAL, hostname: $MY_HOSTNAME" - # Try to determine current master from Sentinel (if any sentinel is available) CURRENT_MASTER="" SENTINEL_FOUND=false # Check if any sentinel is already running and knows the master - for i in $(seq 0 $(({{ if eq .Values.architecture "standalone" }}1{{ else }}{{ .Values.replicaCount }}{{ end }} - 1))); do + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do SENTINEL_HOST="{{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless" - MASTER_INFO=$(redis-cli -h "${SENTINEL_HOST}" -p {{ .Values.sentinel.port }} {{- if .Values.auth.enabled }} -a "${REDIS_PASSWORD}"{{- end }} sentinel get-master-addr-by-name {{ .Values.sentinel.masterName }} 2>/dev/null | head -1 || echo "") + MASTER_INFO=$(redis-cli -h "${SENTINEL_HOST}" -p {{ .Values.sentinel.port }} {{- if .Values.auth.sentinel }} -a "${REDIS_PASSWORD}"{{- end }} sentinel get-master-addr-by-name {{ .Values.sentinel.masterName }} 2>/dev/null | head -1 || echo "") if [ -n "$MASTER_INFO" ] && [ "$MASTER_INFO" != "Could not connect" ]; then CURRENT_MASTER="$MASTER_INFO" SENTINEL_FOUND=true @@ -149,6 +143,50 @@ spec: # Make slaves more eligible for promotion during force deletions echo "slave-priority 100" >> /tmp/redis.conf echo "replica-read-only yes" >> /tmp/redis.conf + {{- else }} + # Replication without Sentinel: pod-0 is always master, others are replicas + if [ "$POD_ORDINAL" != "0" ]; then + echo "Configuring as replica of pod-0 (master)" + MASTER_HOSTNAME="{{ include "redis.fullname" . }}-0.{{ include "redis.fullname" . }}-headless" + echo "replicaof $MASTER_HOSTNAME {{ .Values.service.port }}" >> /tmp/redis.conf + {{- if .Values.auth.enabled }} + echo "masterauth ${REDIS_PASSWORD}" >> /tmp/redis.conf + {{- end }} + echo "replica-read-only yes" >> /tmp/redis.conf + else + echo "Pod-0: Configuring as master" + fi + {{- end }} + {{- else if eq .Values.architecture "cluster" }} + echo "" >> /tmp/redis.conf + echo "# Default cluster settings" >> /tmp/redis.conf + echo "cluster-enabled yes" >> /tmp/redis.conf + echo "cluster-config-file nodes.conf" >> /tmp/redis.conf + echo "cluster-node-timeout 5000" >> /tmp/redis.conf + echo "cluster-port {{ .Values.service.clusterPort }}" >> /tmp/redis.conf + echo "databases 1" >> /tmp/redis.conf + {{- if .Values.auth.enabled }} + echo "masterauth ${REDIS_PASSWORD}" >> /tmp/redis.conf + {{- end }} + echo "" >> /tmp/redis.conf + echo "# Increased durability" >> /tmp/redis.conf + echo "appendonly yes" >> /tmp/redis.conf + {{- end }} + + # Add user provided settings at the end of file to ensure their precedence + echo "" >> /tmp/redis.conf + # If there is existing config map or .Values.config value provided - use it + if [ -f "{{ include "redis.configFullName" . }}" ]; then + echo "# Content from provided config" >> /tmp/redis.conf + cat {{ include "redis.configFullName" . }} >> /tmp/redis.conf + else + # Create minimal config if no config exists + echo "# Default minimal config" >> /tmp/redis.conf + cat >> /tmp/redis.conf << EOF + bind * -::* + port {{ .Values.service.port }} + EOF + fi {{- if .Values.auth.enabled }} env: - name: REDIS_PASSWORD @@ -163,32 +201,37 @@ spec: mountPath: {{ .Values.config.mountPath }} - name: redis-config mountPath: /tmp - {{- end }} + {{- end }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "redis.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.image) }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.image) }} command: - /bin/sh - -c - | - {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + {{- if (list "replication" "cluster" | has .Values.architecture) }} CONFIG_FILE="/tmp/redis.conf" {{- else }} CONFIG_FILE="{{ include "redis.configFullName" . }}" {{- end }} - {{- if .Values.auth.enabled }} - redis-server "$CONFIG_FILE" --requirepass "${REDIS_PASSWORD}" - {{- else }} - redis-server "$CONFIG_FILE" - {{- end }} + redis-server "$CONFIG_FILE" {{- if .Values.auth.enabled }} --requirepass "${REDIS_PASSWORD}" {{- end }} {{- range .Values.extraFlags }} {{ . }}{{- end }} ports: - name: redis containerPort: 6379 protocol: TCP - {{- if or .Values.auth.enabled .Values.extraEnv }} + {{- if eq .Values.architecture "cluster" }} + - name: cluster + containerPort: {{ .Values.service.clusterPort }} + protocol: TCP + {{- end }} + {{- range .Values.extraPorts }} + - containerPort: {{ .containerPort }} + name: {{ .name }} + {{- end }} + {{- if or .Values.auth.enabled .Values.extraEnvVars }} env: {{- if .Values.auth.enabled }} - name: REDIS_PASSWORD @@ -196,10 +239,14 @@ spec: secretKeyRef: name: {{ include "redis.secretName" . }} key: {{ include "redis.secretPasswordKey" . }} + - name: REDISCLI_AUTH + valueFrom: + secretKeyRef: + name: {{ include "redis.secretName" . }} + key: {{ include "redis.secretPasswordKey" . }} {{- end }} - {{- range .Values.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} {{- end }} {{- end }} {{- if .Values.livenessProbe.enabled }} @@ -208,11 +255,7 @@ spec: command: - /bin/sh - -c - {{- if .Values.auth.enabled }} - - redis-cli -a ${REDIS_PASSWORD} ping - {{- else }} - - redis-cli ping - {{- end }} + - redis-cli -h {{ if eq .Values.ipFamily "ipv6" }}"::1"{{ else }}"127.0.0.1"{{ end }} ping initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} @@ -225,45 +268,60 @@ spec: command: - /bin/sh - -c - - | - {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} - {{- if .Values.auth.enabled }} - redis-cli -a ${REDIS_PASSWORD} ping | grep -q PONG - {{- else }} - redis-cli ping | grep -q PONG - {{- end }} - {{- else }} - {{- if .Values.auth.enabled }} - redis-cli -a ${REDIS_PASSWORD} ping - {{- else }} - redis-cli ping - {{- end }} - {{- end }} + - redis-cli -h {{ if eq .Values.ipFamily "ipv6" }}"::1"{{ else }}"127.0.0.1"{{ end }} ping {{ if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} | grep -q PONG{{ end }} initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} failureThreshold: {{ .Values.readinessProbe.failureThreshold }} successThreshold: {{ .Values.readinessProbe.successThreshold }} {{- end }} - {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + {{- if .Values.startupProbe.enabled }} + startupProbe: + exec: + command: + - /bin/sh + - -c + - redis-cli -h {{ if eq .Values.ipFamily "ipv6" }}"::1"{{ else }}"127.0.0.1"{{ end }} ping + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + successThreshold: {{ .Values.startupProbe.successThreshold }} + {{- end }} + {{- if or (and .Values.sentinel.enabled (eq .Values.architecture "replication")) .Values.customScripts.postStart.enabled .Values.customScripts.preStop.enabled }} lifecycle: + {{- if .Values.customScripts.postStart.enabled }} + postStart: + exec: + command: + {{- toYaml .Values.customScripts.postStart.command | nindent 18 }} + {{- end }} + {{- if .Values.customScripts.preStop.enabled }} + preStop: + exec: + command: + {{- toYaml .Values.customScripts.preStop.command | nindent 18 }} + {{- else if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} preStop: exec: command: - /bin/bash - /scripts/prestop.sh + {{- end }} {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: - name: data mountPath: {{ .Values.persistence.mountPath }} - {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + {{- if (list "replication" "cluster" | has .Values.architecture) }} - name: redis-config mountPath: /tmp + {{- if .Values.sentinel.enabled }} - name: prestop-script mountPath: /scripts readOnly: true {{- end }} + {{- end }} {{- if or .Values.config.content .Values.config.existingConfigmap }} - name: config mountPath: {{ .Values.config.mountPath }} @@ -273,11 +331,13 @@ spec: {{- end }} {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} - name: sentinel - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "redis.sentinel.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.sentinel.image) }} - {{- if .Values.sentinel.extraVolumeMounts }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.sentinel.image) }} volumeMounts: + - name: sentinel-config + mountPath: /tmp + {{- if .Values.sentinel.extraVolumeMounts }} {{- toYaml .Values.sentinel.extraVolumeMounts | nindent 12 }} {{- end }} command: @@ -288,7 +348,12 @@ spec: # Wait for Redis to be ready echo "Waiting for Redis to start..." - while ! redis-cli {{- if .Values.auth.enabled }} -a "${REDIS_PASSWORD}"{{- end }} -h 127.0.0.1 -p {{ .Values.service.port }} ping >/dev/null 2>&1; do + {{- if eq .Values.ipFamily "ipv6" }} + REDIS_HOST="::1" + {{- else }} + REDIS_HOST="127.0.0.1" + {{- end }} + while ! redis-cli {{- if .Values.auth.enabled }} -a "${REDIS_PASSWORD}"{{- end }} -h "${REDIS_HOST}" -p {{ .Values.service.port }} ping >/dev/null 2>&1; do sleep 1 done echo "Redis is ready" @@ -300,10 +365,10 @@ spec: # First priority: Try to query other sentinels to find the current master echo "Checking existing Sentinels for current master..." - for i in $(seq 0 $(({{ if eq .Values.architecture "standalone" }}1{{ else }}{{ .Values.replicaCount }}{{ end }} - 1))); do + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do if [ "$i" != "$POD_ORDINAL" ]; then SENTINEL_HOST="{{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless" - EXISTING_MASTER=$(redis-cli -h "${SENTINEL_HOST}" -p {{ .Values.sentinel.port }} {{- if .Values.auth.enabled }} -a "${REDIS_PASSWORD}"{{- end }} sentinel get-master-addr-by-name {{ .Values.sentinel.masterName }} 2>/dev/null | head -1 || echo "") + EXISTING_MASTER=$(redis-cli -h "${SENTINEL_HOST}" -p {{ .Values.sentinel.port }} {{- if .Values.auth.sentinel }} -a "${REDIS_PASSWORD}"{{- end }} sentinel get-master-addr-by-name {{ .Values.sentinel.masterName }} 2>/dev/null | head -1 || echo "") if [ -n "$EXISTING_MASTER" ] && [ "$EXISTING_MASTER" != "Could not connect" ]; then MASTER_HOST="$EXISTING_MASTER" SENTINEL_FOUND_MASTER=true @@ -316,8 +381,8 @@ spec: # Second priority: If no Sentinels found master, check if any Redis instance claims to be master if [ "$SENTINEL_FOUND_MASTER" = false ]; then echo "No Sentinels available, checking Redis instances directly..." - for i in $(seq 0 $(({{ if eq .Values.architecture "standalone" }}1{{ else }}{{ .Values.replicaCount }}{{ end }} - 1))); do - REDIS_HOST="{{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless.{{ .Release.Namespace }}.svc.cluster.local" + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do + REDIS_HOST="{{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless.{{ include "cloudpirates.namespace" . }}.svc.{{ .Values.clusterDomain }}" ROLE_INFO=$(redis-cli -h "${REDIS_HOST}" -p {{ .Values.service.port }} {{- if .Values.auth.enabled }} -a "${REDIS_PASSWORD}"{{- end }} info replication 2>/dev/null | grep "role:master" || echo "") if [ -n "$ROLE_INFO" ]; then MASTER_HOST="$REDIS_HOST" @@ -329,7 +394,7 @@ spec: # Final fallback: Use pod-0 hostname for initial bootstrap only if [ -z "$MASTER_HOST" ]; then - MASTER_HOST="{{ include "redis.fullname" . }}-0.{{ include "redis.fullname" . }}-headless.{{ .Release.Namespace }}.svc.cluster.local" + MASTER_HOST="{{ include "redis.fullname" . }}-0.{{ include "redis.fullname" . }}-headless.{{ include "cloudpirates.namespace" . }}.svc.{{ .Values.clusterDomain }}" echo "No existing master found, using pod-0 for initial bootstrap: $MASTER_HOST" fi @@ -355,7 +420,7 @@ spec: # Create Sentinel config cat > /tmp/sentinel.conf << EOF port {{ .Values.sentinel.port }} - bind 0.0.0.0 + bind * -::* # Enable hostname resolution for Redis Sentinel sentinel resolve-hostnames yes sentinel announce-hostnames yes @@ -365,6 +430,8 @@ spec: sentinel parallel-syncs {{ .Values.sentinel.masterName }} {{ .Values.sentinel.parallelSyncs }} {{- if .Values.auth.enabled }} sentinel auth-pass {{ .Values.sentinel.masterName }} "${REDIS_PASSWORD}" + {{- end }} + {{- if .Values.auth.sentinel }} requirepass "${REDIS_PASSWORD}" {{- end }} # Make automatic failover more aggressive for Kubernetes force deletions @@ -381,7 +448,7 @@ spec: EOF # Add known sentinels to help with discovery (using hostnames for resilience) - for i in $(seq 0 $(({{ if eq .Values.architecture "standalone" }}1{{ else }}{{ .Values.replicaCount }}{{ end }} - 1))); do + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do if [ "$i" != "$POD_ORDINAL" ]; then SENTINEL_HOST="{{ include "redis.fullname" . }}-${i}.{{ include "redis.fullname" . }}-headless" # Test if the host is resolvable before adding @@ -407,15 +474,17 @@ spec: command: - /bin/sh - -c - - | - # Check if sentinel is responding - redis-cli -h 127.0.0.1 -p {{ .Values.sentinel.port }} {{- if .Values.auth.enabled }} -a "${REDIS_PASSWORD}"{{- end }} ping | grep -q PONG + {{- if eq .Values.ipFamily "ipv6" }} + - redis-cli -h "::1" -p {{ .Values.sentinel.port }} {{- if .Values.auth.sentinel }} -a "${REDIS_PASSWORD}"{{- end }} ping | grep -q PONG + {{- else }} + - redis-cli -h "127.0.0.1" -p {{ .Values.sentinel.port }} {{- if .Values.auth.sentinel }} -a "${REDIS_PASSWORD}"{{- end }} ping | grep -q PONG + {{- end }} initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 successThreshold: 1 - {{- if .Values.auth.enabled }} + {{- if or .Values.auth.enabled .Values.auth.sentinel }} env: - name: REDIS_PASSWORD valueFrom: @@ -427,9 +496,9 @@ spec: {{- end }} {{- if .Values.metrics.enabled }} - name: metrics - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "redis.metrics.image" . | quote }} - imagePullPolicy: {{ include "common.imagePullPolicy" (dict "image" .Values.metrics.image) }} + imagePullPolicy: {{ include "cloudpirates.imagePullPolicy" (dict "image" .Values.metrics.image) }} {{- if .Values.auth.enabled }} env: - name: REDIS_PASSWORD @@ -438,22 +507,17 @@ spec: name: {{ include "redis.secretName" . }} key: {{ include "redis.secretPasswordKey" . }} {{- end }} + {{- if .Values.metrics.extraArgs }} command: - /redis_exporter - {{- range .Values.metrics.extraArgs }} - - {{ . }} - {{- end }} args: - {{- if .Values.auth.enabled }} - - --redis.password=$(REDIS_PASSWORD) - {{- end }} - {{- if .Values.metrics.extraArgs }} {{- range .Values.metrics.extraArgs }} - {{- if not (hasPrefix "--" .) }} - {{ . }} {{- end }} - {{- end }} - {{- end }} + {{- else }} + command: + - /redis_exporter + {{- end }} ports: - name: metrics containerPort: 9121 @@ -483,14 +547,18 @@ spec: - name: data emptyDir: {} {{- end }} - {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + {{- if (list "replication" "cluster" | has .Values.architecture) }} - name: redis-config emptyDir: {} + {{- if .Values.sentinel.enabled }} + - name: sentinel-config + emptyDir: {} - name: prestop-script configMap: name: {{ include "redis.fullname" . }}-prestop-script defaultMode: 0755 {{- end }} + {{- end }} {{- if or .Values.config.content .Values.config.existingConfigmap }} - name: config configMap: diff --git a/charts/redis/test-production-values.yaml b/charts/redis/test-production-values.yaml index 13af75ad..4f895734 100644 --- a/charts/redis/test-production-values.yaml +++ b/charts/redis/test-production-values.yaml @@ -97,7 +97,7 @@ readinessProbe: config: content: | # Redis production configuration - bind 0.0.0.0 + bind * -::* port 6379 # Memory management diff --git a/charts/redis/tests/common-parameters_test.yaml b/charts/redis/tests/common-parameters_test.yaml index 58450b9d..bd7eccca 100644 --- a/charts/redis/tests/common-parameters_test.yaml +++ b/charts/redis/tests/common-parameters_test.yaml @@ -7,7 +7,7 @@ set: config: content: | # Redis configuration - bind 0.0.0.0 + bind * -::* port 6379 tests: - it: should use default values when nothing is overridden diff --git a/charts/redis/values.schema.json b/charts/redis/values.schema.json index 4b8ccc3e..0f03d0ec 100644 --- a/charts/redis/values.schema.json +++ b/charts/redis/values.schema.json @@ -1,972 +1,626 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "Redis Helm Chart Values Schema", - "description": "Schema for Redis Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker image registry" - }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "architecture": { + "type": "string" + }, + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override redis.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override redis.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "image": { - "type": "object", - "title": "Redis Image Configuration", - "description": "Configuration for Redis container image", - "properties": { - "registry": { - "type": "string", - "title": "Redis Image Registry", - "description": "Redis image registry" - }, - "repository": { - "type": "string", - "title": "Redis Image Repository", - "description": "Redis image repository" - }, - "tag": { - "type": "string", - "title": "Redis Image Tag", - "description": "Redis image tag with digest" - }, - "pullPolicy": { - "type": "string", - "title": "Redis Image Pull Policy", - "description": "Redis image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] - } - } - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of Redis replicas to deploy", - "minimum": 1 - }, - "ipFamily": { - "type": "string", - "title": "IP Family", - "description": "IP family to use for replica and sentinel announce IPs. 'auto' uses the first IP from hostname -i, 'ipv4' forces IPv4, 'ipv6' forces IPv6. Falls back to available IP family with warning if requested family is not available.", - "enum": ["auto", "ipv4", "ipv6"], - "default": "auto" - }, - "architecture": { - "type": "string", - "title": "Redis Architecture", - "description": "Redis architecture. Allowed values: standalone or replication", - "enum": ["standalone", "replication"], - "default": "standalone" - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "Kubernetes service configuration", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "Kubernetes service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "Redis service port", - "minimum": 1, - "maximum": 65535 - } - } - }, - "auth": { - "type": "object", - "title": "Redis Authentication", - "description": "Authentication configuration for Redis", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Authentication", - "description": "Enable Redis authentication" - }, - "password": { - "type": "string", - "title": "Redis Password", - "description": "Redis password (if empty, random password will be generated)" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret containing Redis password" - }, - "existingSecretPasswordKey": { - "type": "string", - "title": "Existing Secret Password Key", - "description": "Key in existing secret containing Redis password" - } - } - }, - "config": { - "type": "object", - "title": "Redis Configuration", - "description": "Redis configuration options", - "properties": { - "mountPath": { - "type": "string", - "title": "Config Mount Path", - "description": "Redis configuration mount path" - }, - "content": { - "type": "string", - "title": "Config Content", - "description": "Include your custom Redis configurations here as string" - }, - "existingConfigmap": { - "type": "string", - "title": "Existing ConfigMap", - "description": "Name of an existing Configmap to use instead of creating one" - }, - "existingConfigmapKey": { - "type": "string", - "title": "Existing ConfigMap Key", - "description": "Name of the key in the Configmap that should be used" - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "Persistence configuration using Persistent Volume Claims", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable persistent storage" - }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "Storage class to use for persistent volume" - }, - "accessMode": { - "type": "string", - "title": "Access Mode", - "description": "Access mode for persistent volume", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] - }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "Size of persistent volume", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" - }, - "mountPath": { - "type": "string", - "title": "Mount Path", - "description": "Mount path for Redis data" - }, - "annotations": { - "type": "object", - "title": "PVC Annotations", - "description": "Annotations for persistent volume claims", - "additionalProperties": { + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "existingSecretPasswordKey": { + "type": "string" + }, + "password": { + "type": "string" + }, + "sentinel": { + "type": "boolean" + } + } + }, + "clusterDomain": { "type": "string" - } - } - } - }, - "persistentVolumeClaimRetentionPolicy": { - "type": "object", - "title": "PVC Retention Policy", - "description": "Persistent Volume Claim retention policy for StatefulSet", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Retention Policy", - "description": "Enable Persistent volume retention policy for the StatefulSet" - }, - "whenScaled": { - "type": "string", - "title": "When Scaled", - "description": "Volume retention behavior when the replica count of the StatefulSet is reduced", - "enum": ["Retain", "Delete"], - "default": "Retain" - }, - "whenDeleted": { - "type": "string", - "title": "When Deleted", - "description": "Volume retention behavior that applies when the StatefulSet is deleted", - "enum": ["Retain", "Delete"], - "default": "Retain" - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource limits and requests for Redis pod", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + }, + "clusterReplicaCount": { + "type": "integer" + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "existingConfigmap": { + "type": "string" + }, + "existingConfigmapKey": { + "type": "string" + }, + "mountPath": { + "type": "string" + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "privileged": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + } } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + }, + "customScripts": { + "type": "object", + "properties": { + "postStart": { + "type": "object", + "properties": { + "command": { + "type": "array" + }, + "enabled": { + "type": "boolean" + } + } + }, + "preStop": { + "type": "object", + "properties": { + "command": { + "type": "array" + }, + "enabled": { + "type": "boolean" + } + } + } } - } - } - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node selector for pod assignment", - "additionalProperties": { - "type": "string" - } - }, - "priorityClassName": { - "type": "string", - "title": "Priority Class Name", - "description": "Name of the priority class" - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Tolerations for pod assignment", - "items": { - "type": "object", - "properties": { - "key": { + }, + "extraEnvVars": { + "type": "array" + }, + "extraFlags": { + "type": "array" + }, + "extraObjects": { + "type": "array" + }, + "extraPorts": { + "type": "array" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "fullnameOverride": { "type": "string" - }, - "operator": { - "type": "string", - "enum": ["Equal", "Exists"] - }, - "value": { + }, + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "initContainer": { + "type": "object", + "properties": { + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + } + } + }, + "ipFamily": { "type": "string" - }, - "effect": { - "type": "string", - "enum": ["NoSchedule", "PreferNoSchedule", "NoExecute"] - }, - "tolerationSeconds": { - "type": "integer", - "minimum": 0 - } - } - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity rules for pod assignment", - "properties": { - "nodeAffinity": { - "type": "object", - "title": "Node Affinity", - "description": "Node affinity configuration" - }, - "podAffinity": { - "type": "object", - "title": "Pod Affinity", - "description": "Pod affinity configuration" - }, - "podAntiAffinity": { - "type": "object", - "title": "Pod Anti-Affinity", - "description": "Pod anti-affinity configuration" - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "Container Security Context", - "description": "Security context for the Redis container", - "properties": { - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID to run the container", - "minimum": 0 - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Run as non-root user" - }, - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Set Redis container's privilege escalation" - } - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "Security context for the pod", - "properties": { - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Set Redis pod's Security Context fsGroup", - "minimum": 0 - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "Liveness probe configuration for Redis container", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable liveness probe" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay before starting probes", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "How often to perform the probe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout for each probe attempt", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Number of failures before pod is restarted", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Number of successes to mark probe as successful", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "Readiness probe configuration for Redis container", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readiness probe" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay before starting probes", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "How often to perform the probe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout for each probe attempt", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Number of failures before pod is marked unready", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Number of successes to mark probe as successful", - "minimum": 1 - } - } - }, - "extraEnv": { - "type": "array", - "title": "Extra Environment Variables", - "description": "Additional environment variables to set", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Variable Name", - "description": "Environment variable name" - }, - "value": { - "type": "string", - "title": "Variable Value", - "description": "Environment variable value" - } - }, - "required": ["name"] - } - }, - "extraVolumes": { - "type": "array", - "title": "Extra Volumes", - "description": "Additional volumes to add to the pod", - "items": { - "type": "object" - } - }, - "extraVolumeMounts": { - "type": "array", - "title": "Extra Volume Mounts", - "description": "Additional volume mounts to add to the Redis container", - "items": { - "type": "object" - } - }, - "topologySpreadConstraints": { - "type": "array", - "title": "Topology Spread Constraints", - "description": "Topology Spread Constraints for pod assignment", - "items": { - "type": "object" - } - }, - "podLabels": { - "type": "object", - "title": "Pod Labels", - "description": "Map of labels to add to the pods", - "additionalProperties": { - "type": "string" - } - }, - "podAnnotations": { - "type": "object", - "title": "Pod Annotations", - "description": "Map of annotations to add to the pods", - "additionalProperties": { - "type": "string" - } - }, - "initContainer": { - "type": "object", - "title": "Init Container Configuration", - "description": "Resource configuration for Redis init container pod", - "properties": { - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource limits and requests for init container", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the init container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the init container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "extraArgs": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "clusterIP": { + "type": "string" + }, + "loadBalancerIP": { + "type": "string" + }, + "loadBalancerSourceRanges": { + "type": "array" + }, + "nodePort": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "metricRelabelings": { + "type": "array" + }, + "namespace": { + "type": "string" + }, + "namespaceSelector": { + "type": "object" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + }, + "selector": { + "type": "object" + } + } } - } } - } - } - } - }, - "sentinel": { - "type": "object", - "title": "Redis Sentinel Configuration", - "description": "Configuration for Redis Sentinel high availability in replication mode", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Sentinel", - "description": "Enable Redis Sentinel for high availability" }, - "image": { - "type": "object", - "title": "Sentinel Image Configuration", - "description": "Configuration for Sentinel container image", - "properties": { - "repository": { - "type": "string", - "title": "Sentinel Image Repository", - "description": "Redis Sentinel image repository" - }, - "tag": { - "type": "string", - "title": "Sentinel Image Tag", - "description": "Redis Sentinel image tag with digest" - }, - "pullPolicy": { - "type": "string", - "title": "Sentinel Image Pull Policy", - "description": "Redis Sentinel image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] + "nameOverride": { + "type": "string" + }, + "namespaceOverride": { + "type": "string" + }, + "networkPolicy": { + "type": "object", + "properties": { + "allowExternal": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "extraEgress": { + "type": "array" + }, + "extraIngress": { + "type": "array" + } } - } - }, - "masterName": { - "type": "string", - "title": "Master Name", - "description": "Name of the master server", - "default": "mymaster" - }, - "quorum": { - "type": "integer", - "title": "Quorum", - "description": "Number of Sentinels that need to agree about the fact the master is not reachable", - "minimum": 1 - }, - "downAfterMilliseconds": { - "type": "integer", - "title": "Down After Milliseconds", - "description": "Time in milliseconds after the master is declared down", - "minimum": 1 - }, - "failoverTimeout": { - "type": "integer", - "title": "Failover Timeout", - "description": "Timeout for failover in milliseconds", - "minimum": 1 - }, - "parallelSyncs": { - "type": "integer", - "title": "Parallel Syncs", - "description": "Number of replicas that can be reconfigured to use the new master during a failover", - "minimum": 1 - }, - "port": { - "type": "integer", - "title": "Sentinel Port", - "description": "Sentinel port", - "minimum": 1, - "maximum": 65535 }, - "extraVolumeMounts": { - "type": "array", - "title": "Extra Volume Mounts", - "description": "Additional volume mounts to add to the Sentinel container", - "items": { + "nodeSelector": { "type": "object" - } }, - "service": { - "type": "object", - "title": "Sentinel Service Configuration", - "description": "Kubernetes service configuration for Sentinel", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "Kubernetes service type for Sentinel", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "Sentinel service port", - "minimum": 1, - "maximum": 65535 + "pdb": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxUnavailable": { + "type": "string" + }, + "minAvailable": { + "type": "integer" + } } - } }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource limits and requests for Sentinel pod", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the Sentinel container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + "persistence": { + "type": "object", + "properties": { + "accessMode": { + "type": "string" + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the Sentinel container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + } + }, + "persistentVolumeClaimRetentionPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "whenDeleted": { + "type": "string" + }, + "whenScaled": { + "type": "string" } - } } - } - } - } - }, - "metrics": { - "type": "object", - "title": "Metrics Configuration", - "description": "Prometheus metrics configuration for Redis", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Metrics", - "description": "Start a sidecar prometheus exporter to expose Redis metrics" }, - "image": { - "type": "object", - "title": "Metrics Image Configuration", - "description": "Configuration for metrics exporter container image", - "properties": { - "registry": { - "type": "string", - "title": "Metrics Image Registry", - "description": "Redis exporter image registry" - }, - "repository": { - "type": "string", - "title": "Metrics Image Repository", - "description": "Redis exporter image repository" - }, - "tag": { - "type": "string", - "title": "Metrics Image Tag", - "description": "Redis exporter image tag with digest" - }, - "pullPolicy": { - "type": "string", - "title": "Metrics Image Pull Policy", - "description": "Redis exporter image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } } - } }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource limits and requests for metrics container", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the metrics container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + "priorityClassName": { + "type": "string" + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the metrics container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } } - } } - } }, - "extraArgs": { - "type": "array", - "title": "Extra Arguments", - "description": "Extra arguments for redis exporter", - "items": { - "type": "string" - } + "sentinel": { + "type": "object", + "properties": { + "downAfterMilliseconds": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "extraVolumeMounts": { + "type": "array" + }, + "failoverTimeout": { + "type": "integer" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "masterName": { + "type": "string" + }, + "parallelSyncs": { + "type": "integer" + }, + "port": { + "type": "integer" + }, + "quorum": { + "type": "integer" + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "service": { + "type": "object", + "properties": { + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + } + } }, "service": { - "type": "object", - "title": "Metrics Service Configuration", - "description": "Kubernetes service configuration for metrics", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "Metrics service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "Metrics service port", - "minimum": 1, - "maximum": 65535 - }, - "annotations": { - "type": "object", - "title": "Service Annotations", - "description": "Additional custom annotations for Metrics service", - "additionalProperties": { - "type": "string" - } - }, - "loadBalancerIP": { - "type": "string", - "title": "Load Balancer IP", - "description": "Load balancer IP if metrics service type is LoadBalancer" - }, - "loadBalancerSourceRanges": { - "type": "array", - "title": "Load Balancer Source Ranges", - "description": "Addresses that are allowed when metrics service is LoadBalancer", - "items": { - "type": "string" - } - }, - "clusterIP": { - "type": "string", - "title": "Cluster IP", - "description": "Static clusterIP or None for headless services when metrics service type is ClusterIP" - }, - "nodePort": { - "oneOf": [ - {"type": "string"}, - {"type": "integer"} - ], - "title": "Node Port", - "description": "Specify the nodePort value for the LoadBalancer and NodePort service types" + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "clusterPort": { + "type": "integer" + }, + "headless": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + } + } + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } } - } - }, - "serviceMonitor": { - "type": "object", - "title": "Service Monitor Configuration", - "description": "Prometheus ServiceMonitor configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Service Monitor", - "description": "Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator" - }, - "namespace": { - "type": "string", - "title": "Namespace", - "description": "Namespace in which to create ServiceMonitor resource(s)" - }, - "interval": { - "type": "string", - "title": "Interval", - "description": "Interval at which metrics should be scraped" - }, - "scrapeTimeout": { - "type": "string", - "title": "Scrape Timeout", - "description": "Timeout after which the scrape is ended" - }, - "relabelings": { - "type": "array", - "title": "Relabelings", - "description": "Specify additional relabeling of metrics", - "items": { - "type": "object" - } - }, - "metricRelabelings": { - "type": "array", - "title": "Metric Relabelings", - "description": "Specify additional metric relabeling of metrics", - "items": { - "type": "object" - } - }, - "honorLabels": { - "type": "boolean", - "title": "Honor Labels", - "description": "Honor metrics labels" - }, - "selector": { - "type": "object", - "title": "Selector", - "description": "Prometheus instance selector labels", - "additionalProperties": { - "type": "string" - } - }, - "annotations": { - "type": "object", - "title": "Annotations", - "description": "Additional custom annotations for the ServiceMonitor", - "additionalProperties": { - "type": "string" - } - }, - "namespaceSelector": { - "type": "object", - "title": "Namespace Selector", - "description": "Namespace selector for ServiceMonitor", - "additionalProperties": true + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } } - } + }, + "tolerations": { + "type": "array" + }, + "topologySpreadConstraints": { + "type": "array" } - } - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } } diff --git a/charts/redis/values.yaml b/charts/redis/values.yaml index de0dd37e..51103bb2 100644 --- a/charts/redis/values.yaml +++ b/charts/redis/values.yaml @@ -10,6 +10,10 @@ global: nameOverride: "" ## @param fullnameOverride String to fully override redis.fullname fullnameOverride: "" +## @param namespaceOverride String to override the namespace for all resources +namespaceOverride: "" +## @param clusterDomain Kubernetes cluster domain +clusterDomain: cluster.local ## @param commonLabels Labels to add to all deployed objects commonLabels: {} ## @param commonAnnotations Annotations to add to all deployed objects @@ -22,19 +26,31 @@ image: ## @param image.repository Redis image repository repository: redis ## @param image.tag Redis image tag - tag: "8.2.2@sha256:f0957bcaa75fd58a9a1847c1f07caf370579196259d69ac07f2e27b5b389b021" + tag: "8.2.3@sha256:d318520052025d3cc5850ba3de966810916c7a7b327b412322399f38be39a39c" ## @param image.pullPolicy Redis image pull policy pullPolicy: Always ## @section Redis Architecture -## @param architecture Redis architecture. Allowed values: standalone or replication +## @param architecture Redis architecture. Allowed values: standalone, replication +## - standalone: Single Redis instance +## - replication: Master-replica setup (use sentinel.enabled to enable/disable Sentinel) +## - cluster: Multi-master setup with optional replicas architecture: standalone -## @param replicaCount Number of Redis instances to deploy (only when architecture=replication) -## When using Sentinel, this is the total number of Redis instances (including the initial master) -## For example: replicaCount: 3 creates 3 Redis instances where Sentinel manages master/replica roles +## @param replicaCount Number of Redis instances to deploy (only when architecture=(replication|cluster)) +## When using architecture=replication: +## with Sentinel, this is the total number of Redis instances (including the initial master) +## without Sentinel, pod-0 is always the master and other pods are replicas +## For example: replicaCount: 3 creates 1 master + 2 replicas +## When using architecture=cluster: +## this is total number of nodes, including replicas +## Value should be a multiple of (clusterReplicaCount + 1) and not less than 3 replicaCount: 3 +## @param clusterReplicaCount Number of replicas for each master node when architecture=cluster. +## For example: replicaCount: 6 and clusterReplicaCount: 1 creates 3 masters + 3 replicas (1 per master) +clusterReplicaCount: 0 + ## @section Pod labels and annotations ## @param podLabels Map of labels to add to the pods podLabels: {} @@ -48,14 +64,23 @@ podAnnotations: {} ipFamily: auto service: + ## @param service.annotations Additional custom annotations for Redis service + annotations: {} ## @param service.type Kubernetes service type type: ClusterIP ## @param service.port Redis service port port: 6379 + ## @param service.clusterPort Redis cluster port. Applicable only if architecture=cluster + clusterPort: 16379 + headless: + ## @param service.headless.annotations Additional custom annotations for Redis headless service + annotations: {} auth: ## @param auth.enabled Enable Redis authentication enabled: true + ## @param auth.enabled Enable Sentinel authentication + sentinel: true ## @param auth.password Redis password (if empty, random password will be generated) password: "" ## @param auth.existingSecret Name of existing secret containing Redis password @@ -68,15 +93,25 @@ config: ## @param config.mountPath Redis configuration options mountPath: /usr/local/etc/redis ## @param config.content Include your custom Redis configurations here as string + ## If no config is provided, minimal config will be created on the fly content: | # Redis configuration - bind 0.0.0.0 + bind * -::* port 6379 ## param config.existingConfigmap Name of an existing Configmap to use instead of creating one existingConfigmap: "" ## param config.existingConfigmapKey Name of the key in the Configmap that should be used existingConfigmapKey: "" +## @Section Pod Disruption Budget +pdb: + ## @param pdb.enabled Enable Pod Disruption Budget + enabled: false + ## @param pdb.minAvailable Minimum number/percentage of pods that should remain scheduled + minAvailable: 1 + ## @param pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable + maxUnavailable: "" + persistence: ## @param persistence.enabled Enable persistent storage enabled: true @@ -124,12 +159,25 @@ affinity: {} topologySpreadConstraints: [] containerSecurityContext: - ## @param securityContext.runAsUser User ID to run the container + ## @param containerSecurityContext.runAsUser User ID to run the container runAsUser: 999 - ## @param securityContext.runAsNonRoot Run as non-root user + ## @param containerSecurityContext.runAsGroup Group ID to run the container + runAsGroup: 999 + ## @param containerSecurityContext.runAsNonRoot Run as non-root user runAsNonRoot: true + ## @param containerSecurityContext.privileged Set container's privileged mode + privileged: false ## @param containerSecurityContext.allowPrivilegeEscalation Set Redis container's privilege escalation allowPrivilegeEscalation: false + ## @param containerSecurityContext.readOnlyRootFilesystem Read-only root filesystem + readOnlyRootFilesystem: true + ## @param containerSecurityContext.capabilities Linux capabilities to be dropped + capabilities: + drop: + - ALL + ## @param containerSecurityContext.seccompProfile Seccomp profile for the container + seccompProfile: + type: RuntimeDefault ## @param podSecurityContext Security context for the pod podSecurityContext: @@ -164,10 +212,45 @@ readinessProbe: ## @param readinessProbe.successThreshold Number of successes to mark probe as successful successThreshold: 1 -## @param extraEnv Additional environment variables to set -extraEnv: [] -# - name: EXTRA_VAR -# value: "extra_value" +startupProbe: + ## @param startupProbe.enabled Enable startup probe + enabled: false + ## @param startupProbe.initialDelaySeconds Initial delay before starting probes + initialDelaySeconds: 10 + ## @param startupProbe.periodSeconds How often to perform the probe + periodSeconds: 10 + ## @param startupProbe.timeoutSeconds Timeout for each probe attempt + timeoutSeconds: 5 + ## @param startupProbe.failureThreshold Number of failures before pod is restarted (30 * 10s = 5 minutes) + failureThreshold: 30 + ## @param startupProbe.successThreshold Number of successes to mark probe as successful + successThreshold: 1 + +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key + +## @param extraFlags Additional command-line flags to pass to redis-server +## Example: +## extraFlags: +## - --maxmemory 230mb +## - --maxmemory-policy volatile-lru +extraFlags: [] + +## @param extraPorts Additional ports to add to the pod and service +## Example: +## extraPorts: +## - name: redis-cluster +## port: 16379 +## targetPort: redis-cluster +## containerPort: 16379 +extraPorts: [] ## @param extraVolumes Additional volumes to add to the pod extraVolumes: [] @@ -178,14 +261,16 @@ extraVolumeMounts: [] ## @section Redis Sentinel configuration ## This section configures Redis Sentinel for high availability in replication mode ## When enabled, Redis instances use dynamic master/replica role assignment managed by Sentinel +## When disabled with replication architecture, pod-0 is always the master and other pods are replicas sentinel: ## @param sentinel.enabled Enable Redis Sentinel for high availability ## IMPORTANT: When enabled, applications should use Sentinel-aware clients to discover the current master + ## When disabled, pod-0 is the master and can be accessed via the -master service enabled: false ## @param sentinel.image.repository Redis Sentinel image repository image: repository: redis - tag: "8.2.2@sha256:f0957bcaa75fd58a9a1847c1f07caf370579196259d69ac07f2e27b5b389b021" + tag: "8.2.3@sha256:d318520052025d3cc5850ba3de966810916c7a7b327b412322399f38be39a39c" pullPolicy: Always ## @param sentinel.masterName Name of the master server (default: mymaster) masterName: mymaster @@ -236,7 +321,7 @@ metrics: image: registry: docker.io repository: oliver006/redis_exporter - tag: "v1.78.0@sha256:043d380adf3b23c9f73a986d820e79491975c104fe0ce6ecb8639a19914654fd" + tag: "v1.80.0@sha256:cd5fad1591e585db5b58beec7fca427027c61a4349f50109af67cf2f07964d02" pullPolicy: Always ## @param metrics.resources Resource limits and requests for metrics container resources: @@ -289,12 +374,51 @@ metrics: ## @param metrics.serviceMonitor.namespaceSelector Namespace selector for ServiceMonitor namespaceSelector: {} +## @section Network Policy +networkPolicy: + ## @param networkPolicy.enabled Enable NetworkPolicy + enabled: false + ## @param networkPolicy.allowExternal Allow external traffic + allowExternal: true + ## @param networkPolicy.extraIngress Additional ingress rules + extraIngress: [] + ## @param networkPolicy.extraEgress Additional egress rules + extraEgress: [] + ## @param extraObjects Array of extra objects to deploy with the release extraObjects: [] # - apiVersion: v1 # kind: ConfigMap # metadata: # name: extra-config -# namespace: "{{ .Release.Namespace }}" +# namespace: "{{ include "common.namespace" . }}" # data: # key: value + +## @section Custom Scripts and Hooks +customScripts: + ## @param customScripts.postStart PostStart lifecycle hook configuration + postStart: + ## @param customScripts.postStart.enabled Enable postStart lifecycle hook + enabled: false + ## @param customScripts.postStart.command Command to execute in postStart hook + command: [] + # Example: + # - /bin/bash + # - -c + # - | + # sleep 5 + # echo "Redis started" + ## @param customScripts.preStop PreStop lifecycle hook configuration + preStop: + ## @param customScripts.preStop.enabled Enable preStop lifecycle hook + ## NOTE: When enabled, this overrides the default preStop hook used by Sentinel + enabled: false + ## @param customScripts.preStop.command Command to execute in preStop hook + command: [] + # Example: + # - /bin/bash + # - -c + # - | + # sleep 10 + # redis-cli shutdown diff --git a/charts/rustfs/CHANGELOG.md b/charts/rustfs/CHANGELOG.md new file mode 100644 index 00000000..b0595ac2 --- /dev/null +++ b/charts/rustfs/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + + +## 0.1.0 (2025-10-29) + +* Initial tagged release diff --git a/charts/rustfs/Chart.lock b/charts/rustfs/Chart.lock new file mode 100644 index 00000000..cdaf9a9d --- /dev/null +++ b/charts/rustfs/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: oci://registry-1.docker.io/cloudpirates + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-21T22:06:19.969966+02:00" diff --git a/charts/rustfs/Chart.yaml b/charts/rustfs/Chart.yaml new file mode 100644 index 00000000..3efed8f8 --- /dev/null +++ b/charts/rustfs/Chart.yaml @@ -0,0 +1,49 @@ +apiVersion: v2 +name: rustfs +description: (ALPHA) High-performance distributed object storage with S3-compatible API +type: application +version: 0.1.0 +appVersion: "1.0.0" +keywords: + - rustfs + - file-system + - s3 + - storage + - cloud-native + - rust +home: https://github.com/rustfs/rustfs +sources: + - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/rustfs + - https://github.com/rustfs/rustfs +maintainers: + - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io + url: https://www.cloudpirates.io + - name: Gianni Carafa + email: gianni.carafa@srf.ch + url: https://www.srf.ch +dependencies: + - name: common + version: "2.x.x" + repository: oci://registry-1.docker.io/cloudpirates +icon: https://a.storyblok.com/f/143071/513x513/246ebb8da4/rustfs-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: storage + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: RustFS + url: https://github.com/rustfs/rustfs + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/rustfs + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "add RustFS chart (MinIO alternative) (#443)" + links: + - name: "Commit 3c2f886" + url: "https://github.com/CloudPirates-io/helm-charts/commit/3c2f886" diff --git a/charts/rustfs/LICENSE b/charts/rustfs/LICENSE new file mode 100644 index 00000000..f49a4e16 --- /dev/null +++ b/charts/rustfs/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/charts/rustfs/README.md b/charts/rustfs/README.md new file mode 100644 index 00000000..419df8c7 --- /dev/null +++ b/charts/rustfs/README.md @@ -0,0 +1,414 @@ +# RustFS + +A Helm chart for RustFS - High-performance distributed file system written in Rust with S3-compatible API. RustFS is a modern, efficient file system that provides S3-compatible APIs for cloud-native applications. + +> [!WARNING] +> RustFS is currently in ALPHA stage. It is not recommended for production use by the publisher. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.2.0+ +- PV provisioner support in the underlying infrastructure (if persistence is enabled) + + +## Modes +RustFS can be deployed in two modes: + +1. **Deployment Mode**: In this mode, RustFS is deployed as a standard Kubernetes Deployment. This mode is suitable for high load scenarios where stateless operation is acceptable. This deployment mode requires mounting persistent volumes in read-write-many (RWX) mode to ensure data persistence across pod restarts. + +

Deployment Diagram

+ +2. **StatefulSet Mode**: In this mode, RustFS is deployed as a StatefulSet. This mode is ideal for scenarios where data consistency and persistence are critical. Each pod in the StatefulSet has a unique identity and stable storage, making it suitable for stateful applications. + +

StatefulSet Diagram

+ + +## Installing the Chart + +To install the chart with the release name `my-rustfs`: + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs +``` + +To install with custom values: + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs -f my-values.yaml +``` + +Or install directly from the local chart: + +```bash +helm install my-rustfs ./charts/rustfs +``` + +The command deploys RustFS on the Kubernetes cluster in the default configuration. The [Configuration](#configuration) section lists the parameters that can be configured during installation. + +## Uninstalling the Chart + +To uninstall/delete the `my-rustfs` deployment: + +```bash +helm uninstall my-rustfs +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Security & Signature Verification + +This Helm chart is cryptographically signed with Cosign to ensure authenticity and prevent tampering. + +**Public Key:** + +``` +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7BgqFgKdPtHdXz6OfYBklYwJgGWQ +mZzYz8qJ9r6QhF3NxK8rD2oG7Bk6nHJz7qWXhQoU2JvJdI3Zx9HGpLfKvw== +-----END PUBLIC KEY----- +``` + +To verify the helm chart before installation, copy the public key to the file `cosign.pub` and run cosign: + +```bash +cosign verify --key cosign.pub registry-1.docker.io/cloudpirates/rustfs: +``` + +## Configuration + +The following table lists the configurable parameters of the RustFS chart and their default values. + +### Global parameters + +| Parameter | Description | Default | +| ------------------------- | ----------------------------------------------- | ------- | +| `global.imageRegistry` | Global Docker image registry | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | + +### Common parameters + +| Parameter | Description | Default | +| -------------------- | --------------------------------------- | ------- | +| `nameOverride` | String to partially override rustfs.fullname | `""` | +| `fullnameOverride` | String to fully override rustfs.fullname | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | + +### RustFS image configuration + +| Parameter | Description | Default | +| ----------------------- | --------------------------------------------- | ----------------- | +| `image.registry` | RustFS image registry | `docker.io` | +| `image.repository` | RustFS image repository | `rustfs/rustfs` | +| `image.tag` | RustFS image tag (immutable tags are recommended) | `"latest"` | +| `image.imagePullPolicy` | RustFS image pull policy | `Always` | + +### RustFS Authentication + +| Parameter | Description | Default | +| ---------------------------------- | ------------------------------------------------------------------ | ----------------- | +| `auth.accessKey` | RustFS access key | `"rustfsadmin"` | +| `auth.secretKey` | RustFS secret key. If not set, a random password will be generated | `""` | +| `auth.existingSecret` | Name of existing secret containing RustFS credentials | `""` | +| `auth.existingSecretAccessKeyKey` | Key in existing secret containing access key | `"access-key"` | +| `auth.existingSecretSecretKeyKey` | Key in existing secret containing secret key | `"secret-key"` | + +### RustFS configuration + +| Parameter | Description | Default | +| --------------------------------- | ------------------------------------- | ---------------------- | +| `config.volumes` | RustFS storage volumes configuration | `"/data/rustfs{0..3}"` | +| `config.address` | RustFS server address | `"0.0.0.0:9000"` | +| `config.consoleAddress` | RustFS console address | `"0.0.0.0:9001"` | +| `config.consoleEnabled` | Enable RustFS console | `true` | +| `config.externalAddress` | RustFS external address | `":9000"` | +| `config.corsAllowedOrigins` | CORS allowed origins for API | `"*"` | +| `config.consoleCorsAllowedOrigins` | CORS allowed origins for console | `"*"` | +| `config.logLevel` | RustFS log level (trace, debug, info, warn, error) | `"info"` | +| `config.tlsPath` | Path to TLS certificates | `"/opt/tls"` | +| `config.extraEnvVars` | Extra environment variables | `[]` | + +### Deployment configuration + +| Parameter | Description | Default | +| -------------- | --------------------- | ------- | +| `replicaCount` | Number of replicas | `4` | + +### Deployment type configuration + +| Parameter | Description | Default | +| ----------------------------------- | ------------------------------------------------ | ---------------- | +| `deploymentType` | Type of deployment (deployment or statefulset) | `"deployment"` | +| `updateStrategy.type` | Update strategy for StatefulSet | `RollingUpdate` | +| `updateStrategy.rollingUpdate.partition` | Partition for RollingUpdate (StatefulSet only) | `0` | +| `podManagementPolicy` | Pod management policy for StatefulSet (Parallel or OrderedReady) | `"Parallel"` | + +### Pod annotations and labels + +| Parameter | Description | Default | +| ---------------- | ---------------------- | ------- | +| `podAnnotations` | Pod annotations | `{}` | +| `podLabels` | Pod labels | `{}` | + +### Security Context + +| Parameter | Description | Default | +| -------------------------------------------- | ------------------------------------------------ | ------- | +| `podSecurityContext.fsGroup` | Group ID for the volumes of the pod | `1001` | +| `containerSecurityContext.allowPrivilegeEscalation` | Enable container privilege escalation | `false` | +| `containerSecurityContext.runAsNonRoot` | Configure the container to run as a non-root user | `true` | +| `containerSecurityContext.runAsUser` | User ID for the RustFS container | `1001` | +| `containerSecurityContext.runAsGroup` | Group ID for the RustFS container | `1001` | +| `containerSecurityContext.readOnlyRootFilesystem` | Mount container root filesystem as read-only | `false` | +| `containerSecurityContext.capabilities.drop` | Linux capabilities to be dropped | `["ALL"]` | + +### Service configuration + +| Parameter | Description | Default | +| ---------------------- | ---------------------------- | ----------- | +| `service.type` | RustFS service type | `ClusterIP` | +| `service.port` | RustFS API service port | `9000` | +| `service.consolePort` | RustFS console service port | `9001` | +| `service.annotations` | Service annotations | `{}` | + +### Console Service configuration (for StatefulSet only) + +| Parameter | Description | Default | +| ----------------------------------- | ------------------------------------------------ | ----------- | +| `consoleService.enabled` | Enable Console service that routes to the first pod only | `true` | +| `consoleService.type` | Console service type | `ClusterIP` | +| `consoleService.port` | Console service API port | `9000` | +| `consoleService.consolePort` | Console service console port | `9001` | +| `consoleService.sessionAffinityTimeout` | Session affinity timeout in seconds | `10800` | +| `consoleService.annotations` | Console service annotations | `{}` | + +### Ingress configuration + +| Parameter | Description | Default | +| ------------------------------ | --------------------------------------------- | ----------------- | +| `ingress.enabled` | Enable ingress record generation for RustFS API | `false` | +| `ingress.className` | IngressClass that will be used to implement the Ingress | `""` | +| `ingress.annotations` | Additional annotations for the Ingress resource | `{}` | +| `ingress.hosts[0].host` | Hostname for RustFS API ingress | `rustfs.local` | +| `ingress.hosts[0].paths[0].path` | Path for RustFS API ingress | `/` | +| `ingress.hosts[0].paths[0].pathType` | Path type for RustFS API ingress | `Prefix` | +| `ingress.tls` | TLS configuration for RustFS API ingress | `[]` | + +### Console Ingress configuration (for StatefulSet only) + +| Parameter | Description | Default | +| ----------------------------------- | --------------------------------------------------------------- | -------------------------- | +| `consoleIngress.enabled` | Enable Console ingress record generation for RustFS API (routes to first pod only) | `true` | +| `consoleIngress.className` | IngressClass that will be used to implement the Console Ingress | `""` | +| `consoleIngress.annotations` | Additional annotations for the Console Ingress resource | `{}` | +| `consoleIngress.hosts[0].host` | Hostname for Console RustFS API ingress | `rustfs-console.localhost` | +| `consoleIngress.hosts[0].paths[0].path` | Path for Console RustFS API ingress | `/` | +| `consoleIngress.hosts[0].paths[0].pathType` | Path type for Console RustFS API ingress | `Prefix` | +| `consoleIngress.tls` | TLS configuration for Console RustFS API ingress | `[]` | + +### Resources + +| Parameter | Description | Default | +| ----------- | ---------------------------------- | ------- | +| `resources` | Resource limits and requests | `{}` | + +### Data Persistence + +| Parameter | Description | Default | +| ---------------------------------- | ------------------------------------------------- | ------------ | +| `dataPersistence.enabled` | Enable data persistence using Persistent Volume Claims | `true` | +| `dataPersistence.storageClass` | Persistent Volume storage class for data | `""` | +| `dataPersistence.annotations` | Persistent Volume Claim annotations for data | `{}` | +| `dataPersistence.size` | Persistent Volume size for data | `10Gi` | +| `dataPersistence.accessModes` | Persistent Volume access modes for data | `["ReadWriteOnce"]` | +| `dataPersistence.existingClaim` | The name of an existing PVC to use for data persistence | `""` | +| `dataPersistence.mountPath` | The path where to mount the data volume | `/data` | + +### Logs Persistence + +| Parameter | Description | Default | +| ---------------------------------- | ------------------------------------------------- | ------------ | +| `logsPersistence.enabled` | Enable logs persistence using Persistent Volume Claims | `true` | +| `logsPersistence.storageClass` | Persistent Volume storage class for logs | `""` | +| `logsPersistence.annotations` | Persistent Volume Claim annotations for logs | `{}` | +| `logsPersistence.size` | Persistent Volume size for logs | `1Gi` | +| `logsPersistence.accessModes` | Persistent Volume access modes for logs | `["ReadWriteOnce"]` | +| `logsPersistence.existingClaim` | The name of an existing PVC to use for logs persistence | `""` | +| `logsPersistence.mountPath` | The path where to mount the logs volume | `/app/logs` | + +### TLS Persistence + +| Parameter | Description | Default | +| ---------------------------------- | ------------------------------------------------- | ------------ | +| `tlsPersistence.enabled` | Enable TLS persistence using Persistent Volume Claims | `false` | +| `tlsPersistence.storageClass` | Persistent Volume storage class for TLS | `""` | +| `tlsPersistence.annotations` | Persistent Volume Claim annotations for TLS | `{}` | +| `tlsPersistence.size` | Persistent Volume size for TLS | `100Mi` | +| `tlsPersistence.accessModes` | Persistent Volume access modes for TLS | `["ReadWriteOnce"]` | +| `tlsPersistence.existingClaim` | The name of an existing PVC to use for TLS persistence | `""` | +| `tlsPersistence.mountPath` | The path where to mount the TLS volume | `/opt/tls` | + +### Service Account + +| Parameter | Description | Default | +| ------------------------------------------ | ------------------------------------------------ | ------- | +| `serviceAccount.create` | Enable the creation of a ServiceAccount for RustFS | `true` | +| `serviceAccount.name` | Name of the created ServiceAccount | `""` | +| `serviceAccount.automountServiceAccountToken` | Enable/disable auto mounting of the service account token | `false` | +| `serviceAccount.annotations` | Custom annotations for RustFS serviceAccount | `{}` | + +### Liveness and readiness probes + +| Parameter | Description | Default | +| ------------------------------------ | ------------------------------------ | ------- | +| `livenessProbe.enabled` | Enable livenessProbe on RustFS containers | `true` | +| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `40` | +| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `30` | +| `livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `10` | +| `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | +| `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `readinessProbe.enabled` | Enable readinessProbe on RustFS containers | `true` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | +| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | +| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `startupProbe.enabled` | Enable startupProbe on RustFS containers | `true` | +| `startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `40` | +| `startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `10` | +| `startupProbe.failureThreshold` | Failure threshold for startupProbe | `3` | +| `startupProbe.successThreshold` | Success threshold for startupProbe | `1` | + +### Node Selection + +| Parameter | Description | Default | +| ------------- | ----------------- | ------- | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `affinity` | Affinity for pod assignment | `{}` | + +### Extra Objects + +| Parameter | Description | Default | +| -------------- | ------------------------------------------ | ------- | +| `extraObjects` | Array of extra objects to deploy with the release | `[]` | + +## Examples + +### Basic installation with default values + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs +``` + +### Installation with custom credentials + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs \ + --set auth.accessKey=myaccesskey \ + --set auth.secretKey=mysecretkey +``` + +### Installation with ingress enabled + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs \ + --set ingress.enabled=true \ + --set ingress.hosts[0].host=rustfs.example.com \ + --set consoleIngress.enabled=true \ + --set consoleIngress.hosts[0].host=rustfs-console.example.com +``` + +### Installation with console service enabled + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs \ + --set deploymentType=statefulset \ + --set consoleService.enabled=true \ + --set consoleIngress.enabled=true \ + --set consoleIngress.hosts[0].host=rustfs-console.example.com +``` + +### Installation with custom storage + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs \ + --set dataPersistence.size=100Gi \ + --set logsPersistence.size=5Gi \ + --set dataPersistence.storageClass=fast-ssd +``` + +### Installation as StatefulSet + +```bash +helm install my-rustfs oci://registry-1.docker.io/cloudpirates/rustfs \ + --set deploymentType=statefulset \ + --set replicaCount=3 \ + --set podManagementPolicy=OrderedReady +``` + + +## Accessing RustFS + +After installation, you can access RustFS: + +### Via port-forward + +```bash +# Access the API +kubectl port-forward service/my-rustfs 9000:9000 + +# Access the console +kubectl port-forward service/my-rustfs 9001:9001 + +# Access via console service (if enabled and using StatefulSet) +kubectl port-forward service/my-rustfs-console 9001:9001 +``` + +### Via ingress (if enabled) + +- API: `http://rustfs.local` (or your configured hostname) +- Console: `http://rustfs-console.local` (or your configured hostname via consoleIngress) + +## Health Checks + +RustFS provides health check endpoints: + +- API Health: `http://localhost:9000/health` +- Console Health: `http://localhost:9001/health` + +## Troubleshooting + +### Check pod status + +```bash +kubectl get pods -l app.kubernetes.io/name=rustfs +``` + +### Check pod logs + +```bash +kubectl logs -l app.kubernetes.io/name=rustfs +``` + +### Check persistent volumes + +```bash +kubectl get pvc -l app.kubernetes.io/name=rustfs +``` + +### Check service + +```bash +kubectl get svc -l app.kubernetes.io/name=rustfs +``` + +## Contributing + +This chart is maintained by CloudPirates. For issues, feature requests, or contributions, please visit our [GitHub repository](https://github.com/CloudPirates-io/helm-charts). + +## License + +This Helm chart is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/charts/rustfs/artifacthub-repo.yml b/charts/rustfs/artifacthub-repo.yml new file mode 100644 index 00000000..8b29ef71 --- /dev/null +++ b/charts/rustfs/artifacthub-repo.yml @@ -0,0 +1 @@ +repositoryID: 007589d8-64db-4e54-9f91-7b02c62b69da \ No newline at end of file diff --git a/charts/rustfs/ci/test-values.yaml b/charts/rustfs/ci/test-values.yaml new file mode 100644 index 00000000..1d87d46d --- /dev/null +++ b/charts/rustfs/ci/test-values.yaml @@ -0,0 +1,65 @@ +# CI test values for rustfs chart +# Optimized for faster testing in kind clusters and GitHub Actions + +image: + # Use IfNotPresent to avoid repeated pulls in CI + imagePullPolicy: IfNotPresent + # Keep latest tag for testing + tag: "latest" + +# Disable ingress for CI tests +ingress: + enabled: false + +consoleIngress: + enabled: false + +# Lenient probes for slow CI environments +readinessProbe: + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 30 + +livenessProbe: + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 10 + +startupProbe: + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + failureThreshold: 30 + +# Minimal resources for kind cluster +resources: + limits: + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + +# Use smaller persistent volumes for CI +dataPersistence: + enabled: true + size: 1Gi + +logsPersistence: + enabled: true + size: 500Mi + +# Disable TLS persistence for CI +tlsPersistence: + enabled: false + +# Test authentication with simple values +auth: + accessKey: "testkey" + secretKey: "testsecret" + +# Simple configuration for testing +config: + logLevel: "debug" + consoleEnabled: true diff --git a/charts/rustfs/docs/deployment.svg b/charts/rustfs/docs/deployment.svg new file mode 100644 index 00000000..e1d5831b --- /dev/null +++ b/charts/rustfs/docs/deployment.svg @@ -0,0 +1,4 @@ + + +dsingpvsvcpod-Xpod-Zpod-Fpod-A \ No newline at end of file diff --git a/charts/rustfs/docs/statefulset.svg b/charts/rustfs/docs/statefulset.svg new file mode 100644 index 00000000..f3a11c51 --- /dev/null +++ b/charts/rustfs/docs/statefulset.svg @@ -0,0 +1,4 @@ + + +ingpvpvpvpvstssvcpod-0pod-1pod-2pod-3 \ No newline at end of file diff --git a/charts/rustfs/templates/NOTES.txt b/charts/rustfs/templates/NOTES.txt new file mode 100644 index 00000000..759b1d33 --- /dev/null +++ b/charts/rustfs/templates/NOTES.txt @@ -0,0 +1,6 @@ +{{- if .Values.ingress.enabled -}} +URL: http://{{ (index .Values.ingress.hosts 0).host }} +{{- end }} +{{ if and .Values.config.consoleEnabled .Values.consoleIngress.enabled .Values.consoleIngress.hosts -}} +CONSOLE URL: http://{{ (index .Values.consoleIngress.hosts 0).host }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/_helpers.tpl b/charts/rustfs/templates/_helpers.tpl new file mode 100644 index 00000000..42d12bde --- /dev/null +++ b/charts/rustfs/templates/_helpers.tpl @@ -0,0 +1,174 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "rustfs.name" -}} +{{- include "cloudpirates.name" . -}} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "rustfs.fullname" -}} +{{- include "cloudpirates.fullname" . -}} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "rustfs.chart" -}} +{{- include "cloudpirates.chart" . -}} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "rustfs.labels" -}} +{{- include "cloudpirates.labels" . -}} +{{- end }} + +{{/* +Common annotations +*/}} +{{- define "rustfs.annotations" -}} +{{- with .Values.commonAnnotations }} +{{- toYaml . }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "rustfs.selectorLabels" -}} +{{- include "cloudpirates.selectorLabels" . -}} +{{- end }} + +{{/* +Return the proper RustFS image name +*/}} +{{- define "rustfs.image" -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- end }} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "rustfs.imagePullSecrets" -}} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{- end -}} + +{{/* +Return RustFS credentials secret name +*/}} +{{- define "rustfs.secretName" -}} +{{- if .Values.auth.existingSecret -}} + {{- .Values.auth.existingSecret -}} +{{- else -}} + {{- include "rustfs.fullname" . -}} +{{- end -}} +{{- end }} + +{{/* +Return RustFS access key +*/}} +{{- define "rustfs.accessKeyKey" -}} +{{- if .Values.auth.existingSecret -}} + {{- printf "%s" .Values.auth.existingSecretAccessKeyKey -}} +{{- else -}} +access-key +{{- end -}} +{{- end }} + +{{/* +Return RustFS secret key +*/}} +{{- define "rustfs.secretKeyKey" -}} +{{- if .Values.auth.existingSecret -}} + {{- printf "%s" .Values.auth.existingSecretSecretKeyKey -}} +{{- else -}} +secret-key +{{- end -}} +{{- end }} + +{{/* +Returns RustFS serviceAccount name +*/}} +{{- define "rustfs.serviceAccountName" -}} + {{- if .Values.serviceAccount.create -}} + {{ default (include "rustfs.fullname" .) .Values.serviceAccount.name }} + {{- else -}} + {{ default "default" .Values.serviceAccount.name }} + {{- end -}} +{{- end -}} + +{{/* +Return RustFS data PVC name +*/}} +{{- define "rustfs.dataPvcName" -}} +{{- if .Values.dataPersistence.existingClaim -}} + {{- .Values.dataPersistence.existingClaim -}} +{{- else -}} + {{- printf "%s-data" (include "rustfs.fullname" .) -}} +{{- end -}} +{{- end }} + +{{/* +Return RustFS logs PVC name +*/}} +{{- define "rustfs.logsPvcName" -}} +{{- if .Values.logsPersistence.existingClaim -}} + {{- .Values.logsPersistence.existingClaim -}} +{{- else -}} + {{- printf "%s-logs" (include "rustfs.fullname" .) -}} +{{- end -}} +{{- end }} + +{{/* +Return RustFS TLS PVC name +*/}} +{{- define "rustfs.tlsPvcName" -}} +{{- if .Values.tlsPersistence.existingClaim -}} + {{- .Values.tlsPersistence.existingClaim -}} +{{- else -}} + {{- printf "%s-tls" (include "rustfs.fullname" .) -}} +{{- end -}} +{{- end }} + +{{/* +Return minimal Replicas in statefulset mode +*/}} +{{- define "rustfs.replicaCount" -}} +{{- if eq .Values.deploymentType "statefulset" }} +{{- if lt (.Values.replicaCount | int) 4 -}} +4 +{{- else -}} +{{- .Values.replicaCount -}} +{{- end -}} +{{- else -}} +{{- .Values.replicaCount -}} +{{- end }} +{{- end }} + +{{/* +Return RustFS Stateful Nodes +Example: http://rfs-rustfs-{0...1}.rfs-rustfs-headless.rustfs.svc.cluster.local + http://[NODE].[HEADLESS-SERVICE].[NAMESPACE].svc.cluster.local +*/}} +{{- define "rustfs.statefulNodes" -}} +{{- $namespace := .Release.Namespace }} +{{- $name := include "rustfs.fullname" . -}} +{{- $maxNode := sub (include "rustfs.replicaCount" . | int) 1 }} +{{- printf "http://%s-{0...%d}.%s-headless.%s.svc.cluster.local" $name $maxNode $name $namespace -}} +{{- end }} + +{{/* +Return RustFS volumes +*/}} +{{- define "rustfs.volumes" -}} +{{- if eq .Values.deploymentType "statefulset" }} + {{ include "rustfs.statefulNodes" . }}:9000{{ .Values.config.volumes }} +{{- else -}} + {{- .Values.config.volumes -}} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/configmap.yaml b/charts/rustfs/templates/configmap.yaml new file mode 100644 index 00000000..a1bc0d17 --- /dev/null +++ b/charts/rustfs/templates/configmap.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "rustfs.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: + {{- include "rustfs.annotations" . | nindent 4 }} + {{- end }} +data: + RUSTFS_VOLUMES: {{ include "rustfs.volumes" . }} + RUSTFS_ADDRESS: {{ .Values.config.address | quote }} + RUSTFS_CONSOLE_ADDRESS: {{ .Values.config.consoleAddress | quote }} + RUSTFS_CONSOLE_ENABLE: {{ .Values.config.consoleEnabled | quote }} + RUSTFS_EXTERNAL_ADDRESS: {{ .Values.config.externalAddress | quote }} + RUSTFS_CORS_ALLOWED_ORIGINS: {{ .Values.config.corsAllowedOrigins | quote }} + RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS: {{ .Values.config.consoleCorsAllowedOrigins | quote }} + RUSTFS_LOG_LEVEL: {{ .Values.config.logLevel | quote }} + RUSTFS_TLS_PATH: {{ .Values.config.tlsPath | quote }} + {{- range $key, $value := .Values.config.extraEnvVars }} + {{ $key }}: {{ $value | quote }} + {{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/deployment.yaml b/charts/rustfs/templates/deployment.yaml new file mode 100644 index 00000000..75010201 --- /dev/null +++ b/charts/rustfs/templates/deployment.yaml @@ -0,0 +1,158 @@ +{{- if eq .Values.deploymentType "deployment" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "rustfs.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: + {{- include "rustfs.annotations" . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount | default 1 }} + strategy: + type: Recreate + selector: + matchLabels: + {{- include "rustfs.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- $annotations := merge .Values.podAnnotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "rustfs.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: +{{- with (include "rustfs.imagePullSecrets" .) }} +{{ . | nindent 6 }} +{{- end }} + serviceAccountName: {{ template "rustfs.serviceAccountName" . }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + image: {{ include "rustfs.image" . }} + imagePullPolicy: {{ .Values.image.imagePullPolicy }} + envFrom: + - configMapRef: + name: {{ include "rustfs.fullname" . }} + env: + - name: RUSTFS_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ include "rustfs.secretName" . }} + key: {{ include "rustfs.accessKeyKey" . }} + - name: RUSTFS_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ include "rustfs.secretName" . }} + key: {{ include "rustfs.secretKeyKey" . }} + - name: RUSTFS_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: RUSTFS_ADDRESS_POD_IP + value: "$(RUSTFS_POD_IP):9000" + {{- with .Values.config.extraEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - name: api + containerPort: {{ .Values.service.port }} + protocol: TCP + - name: console + containerPort: {{ .Values.service.consolePort }} + protocol: TCP + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /health + port: {{ .Values.service.port }} + scheme: HTTP + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /health + port: {{ .Values.service.port }} + scheme: HTTP + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + {{- if .Values.startupProbe.enabled }} + startupProbe: + httpGet: + path: /health + port: {{ .Values.service.port }} + scheme: HTTP + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} + successThreshold: {{ .Values.startupProbe.successThreshold }} + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + {{- end }} + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ .Values.dataPersistence.mountPath }} + - name: logs + mountPath: {{ .Values.logsPersistence.mountPath }} + {{- if .Values.tlsPersistence.enabled }} + - name: tls + mountPath: {{ .Values.tlsPersistence.mountPath }} + {{- end }} + - name: tmp + mountPath: /tmp + volumes: + - name: data + {{- if .Values.dataPersistence.enabled }} + persistentVolumeClaim: + claimName: {{ include "rustfs.dataPvcName" . }} + {{- else }} + emptyDir: {} + {{- end }} + - name: logs + {{- if .Values.logsPersistence.enabled }} + persistentVolumeClaim: + claimName: {{ include "rustfs.logsPvcName" . }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.tlsPersistence.enabled }} + - name: tls + persistentVolumeClaim: + claimName: {{ include "rustfs.tlsPvcName" . }} + {{- end }} + - name: tmp + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/ingress.yaml b/charts/rustfs/templates/ingress.yaml new file mode 100644 index 00000000..8efc567b --- /dev/null +++ b/charts/rustfs/templates/ingress.yaml @@ -0,0 +1,123 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "rustfs.fullname" . -}} +{{- $deploymentType := .Values.deploymentType -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- $annotations := merge .Values.ingress.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if .pathType }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ $fullName }} + port: + name: api + {{- end }} + - host: "*.{{ .host }}" + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if .pathType }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ $fullName }} + port: + name: api + {{- end }} + {{- end }} +{{- end }} + +{{- if and .Values.config.consoleEnabled .Values.consoleIngress.enabled (eq .Values.deploymentType "statefulset") }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "rustfs.fullname" . }}-console + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + app.kubernetes.io/component: console + {{- $consoleAnnotations := merge .Values.consoleIngress.annotations .Values.commonAnnotations }} + {{- with $consoleAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.consoleIngress.className }} + ingressClassName: {{ .Values.consoleIngress.className }} + {{- end }} + {{- if .Values.consoleIngress.tls }} + tls: + {{- range .Values.consoleIngress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.consoleIngress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if .pathType }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ include "rustfs.fullname" $ }}-pod0 + port: + name: api + {{- end }} + - host: "*.{{ .host }}" + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if .pathType }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ include "rustfs.fullname" $ }}-pod0 + port: + name: api + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/pvc.yaml b/charts/rustfs/templates/pvc.yaml new file mode 100644 index 00000000..9d306421 --- /dev/null +++ b/charts/rustfs/templates/pvc.yaml @@ -0,0 +1,92 @@ +{{- if and (eq .Values.deploymentType "deployment") .Values.dataPersistence.enabled (not .Values.dataPersistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "rustfs.dataPvcName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + app.kubernetes.io/component: data + {{- $annotations := merge .Values.dataPersistence.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.dataPersistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.dataPersistence.size | quote }} + {{- if .Values.dataPersistence.storageClass }} + {{- if (eq "-" .Values.dataPersistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.dataPersistence.storageClass }}" + {{- end }} + {{- end }} +--- +{{- end }} +{{- if and (eq .Values.deploymentType "deployment") .Values.logsPersistence.enabled (not .Values.logsPersistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "rustfs.logsPvcName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + app.kubernetes.io/component: logs + {{- $annotations := merge .Values.logsPersistence.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.logsPersistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.logsPersistence.size | quote }} + {{- if .Values.logsPersistence.storageClass }} + {{- if (eq "-" .Values.logsPersistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.logsPersistence.storageClass }}" + {{- end }} + {{- end }} +--- +{{- end }} +{{- if and (eq .Values.deploymentType "deployment") .Values.tlsPersistence.enabled (not .Values.tlsPersistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "rustfs.tlsPvcName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + app.kubernetes.io/component: tls + {{- $annotations := merge .Values.tlsPersistence.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.tlsPersistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.tlsPersistence.size | quote }} + {{- if .Values.tlsPersistence.storageClass }} + {{- if (eq "-" .Values.tlsPersistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.tlsPersistence.storageClass }}" + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/secret.yaml b/charts/rustfs/templates/secret.yaml new file mode 100644 index 00000000..986fcc67 --- /dev/null +++ b/charts/rustfs/templates/secret.yaml @@ -0,0 +1,22 @@ +{{- if not .Values.auth.existingSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "rustfs.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: + {{- include "rustfs.annotations" . | nindent 4 }} + {{- end }} +type: Opaque +data: + {{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace (include "rustfs.fullname" .)) }} + {{- $existingSecretKey := "" }} + {{- if and $existingSecret $existingSecret.data }} + {{- $existingSecretKey = index $existingSecret.data "secret-key" }} + {{- end }} + access-key: {{ .Values.auth.accessKey | b64enc | quote }} + secret-key: {{ $existingSecretKey | default (.Values.auth.secretKey | default (randAlphaNum 32) | b64enc) | quote }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/service.yaml b/charts/rustfs/templates/service.yaml new file mode 100644 index 00000000..16ea2fca --- /dev/null +++ b/charts/rustfs/templates/service.yaml @@ -0,0 +1,76 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "rustfs.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + protocol: TCP + name: api + targetPort: api + selector: + {{- include "rustfs.selectorLabels" . | nindent 4 }} +{{- if eq .Values.deploymentType "statefulset" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "rustfs.fullname" . }}-headless + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + - port: {{ .Values.service.port }} + protocol: TCP + name: api + targetPort: api + selector: + {{- include "rustfs.selectorLabels" . | nindent 4 }} +--- +{{- if and .Values.config.consoleEnabled .Values.consoleIngress.enabled (eq .Values.deploymentType "statefulset") }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "rustfs.fullname" . }}-pod0 + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + app.kubernetes.io/component: console + {{- $consoleAnnotations := merge .Values.consoleService.annotations .Values.commonAnnotations }} + {{- with $consoleAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.consoleService.type }} + sessionAffinity: ClientIP + sessionAffinityConfig: + clientIP: + timeoutSeconds: {{ .Values.consoleService.sessionAffinityTimeout }} + ports: + - port: {{ .Values.consoleService.port }} + protocol: TCP + name: api + targetPort: api + selector: + {{- include "rustfs.selectorLabels" . | nindent 4 }} + statefulset.kubernetes.io/pod-name: {{ include "rustfs.fullname" . }}-0 +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/serviceaccount.yaml b/charts/rustfs/templates/serviceaccount.yaml new file mode 100644 index 00000000..120f5800 --- /dev/null +++ b/charts/rustfs/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "rustfs.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- $annotations := merge .Values.serviceAccount.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +secrets: + - name: {{ include "rustfs.fullname" . }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/templates/statefulset.yaml b/charts/rustfs/templates/statefulset.yaml new file mode 100644 index 00000000..6c9cc0f9 --- /dev/null +++ b/charts/rustfs/templates/statefulset.yaml @@ -0,0 +1,237 @@ +{{- if eq .Values.deploymentType "statefulset" }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "rustfs.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "rustfs.labels" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: + {{- include "rustfs.annotations" . | nindent 4 }} + {{- end }} +spec: + replicas: {{ include "rustfs.replicaCount" . }} + serviceName: {{ include "rustfs.fullname" . }}-headless + podManagementPolicy: {{ .Values.podManagementPolicy }} + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if eq .Values.updateStrategy.type "RollingUpdate" }} + rollingUpdate: + partition: {{ .Values.updateStrategy.rollingUpdate.partition }} + {{- end }} + selector: + matchLabels: + {{- include "rustfs.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- $annotations := merge .Values.podAnnotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "rustfs.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: +{{- with (include "rustfs.imagePullSecrets" .) }} +{{ . | nindent 6 }} +{{- end }} + serviceAccountName: {{ template "rustfs.serviceAccountName" . }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} + initContainers: + - name: wait-for-pods + image: busybox:1.35 + command: ['sh', '-c'] + args: + - | + echo "Waiting 5 seconds to ensure all pod domains are resolvable ..." + sleep 5 + echo "Init container completed, starting main container" + securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1001 + runAsGroup: 1001 + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + containers: + - name: {{ .Chart.Name }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + image: {{ include "rustfs.image" . }} + imagePullPolicy: {{ .Values.image.imagePullPolicy }} + envFrom: + - configMapRef: + name: {{ include "rustfs.fullname" . }} + env: + - name: RUSTFS_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ include "rustfs.secretName" . }} + key: {{ include "rustfs.accessKeyKey" . }} + - name: RUSTFS_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ include "rustfs.secretName" . }} + key: {{ include "rustfs.secretKeyKey" . }} + - name: RUSTFS_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: RUSTFS_ADDRESS_POD_IP + value: "$(RUSTFS_POD_IP):9000" + - name: RUSTFS_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + {{- with .Values.config.extraEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - name: api + containerPort: {{ .Values.service.port }} + protocol: TCP + - name: console + containerPort: {{ .Values.service.consolePort }} + protocol: TCP + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /health + port: {{ .Values.service.port }} + scheme: HTTP + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /health + port: {{ .Values.service.port }} + scheme: HTTP + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + {{- if .Values.startupProbe.enabled }} + startupProbe: + httpGet: + path: /health + port: {{ .Values.service.port }} + scheme: HTTP + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} + successThreshold: {{ .Values.startupProbe.successThreshold }} + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + {{- end }} + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ .Values.dataPersistence.mountPath }} + - name: logs + mountPath: {{ .Values.logsPersistence.mountPath }} + {{- if .Values.tlsPersistence.enabled }} + - name: tls + mountPath: {{ .Values.tlsPersistence.mountPath }} + {{- end }} + - name: tmp + mountPath: /tmp + volumes: + {{- if not .Values.dataPersistence.enabled }} + - name: data + emptyDir: {} + {{- end }} + {{- if not .Values.logsPersistence.enabled }} + - name: logs + emptyDir: {} + {{- end }} + {{- if .Values.tlsPersistence.enabled }} + - name: tls + persistentVolumeClaim: + claimName: {{ include "rustfs.tlsPvcName" . }} + {{- end }} + - name: tmp + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.dataPersistence.enabled .Values.logsPersistence.enabled }} + volumeClaimTemplates: + {{- if .Values.dataPersistence.enabled }} + - metadata: + name: data + labels: + {{- include "rustfs.labels" . | nindent 10 }} + app.kubernetes.io/component: data + {{- $annotations := merge .Values.dataPersistence.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.dataPersistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.dataPersistence.size | quote }} + {{- if .Values.dataPersistence.storageClass }} + {{- if (eq "-" .Values.dataPersistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.dataPersistence.storageClass }}" + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.logsPersistence.enabled }} + - metadata: + name: logs + labels: + {{- include "rustfs.labels" . | nindent 10 }} + app.kubernetes.io/component: logs + {{- $annotations := merge .Values.logsPersistence.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.logsPersistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.logsPersistence.size | quote }} + {{- if .Values.logsPersistence.storageClass }} + {{- if (eq "-" .Values.logsPersistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.logsPersistence.storageClass }}" + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rustfs/tests/common-parameters_test.yaml b/charts/rustfs/tests/common-parameters_test.yaml new file mode 100644 index 00000000..7dbcd3b7 --- /dev/null +++ b/charts/rustfs/tests/common-parameters_test.yaml @@ -0,0 +1,207 @@ +suite: test rustfs common parameters +templates: + - deployment.yaml + - statefulset.yaml +set: + deploymentType: statefulset + image: + tag: latest +tests: + - it: should use default values when nothing is overridden + template: statefulset.yaml + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-rustfs + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: rustfs + - equal: + path: metadata.labels["app.kubernetes.io/instance"] + value: RELEASE-NAME + - equal: + path: spec.template.spec.containers[0].image + value: docker.io/rustfs/rustfs:latest + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + + - it: should respect global.imageRegistry override + template: statefulset.yaml + set: + global: + imageRegistry: "my-registry.com" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: my-registry.com/rustfs/rustfs:latest + + - it: should respect nameOverride + template: statefulset.yaml + set: + nameOverride: "custom-rustfs" + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-custom-rustfs + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: custom-rustfs + + - it: should respect fullnameOverride + template: statefulset.yaml + set: + fullnameOverride: "completely-custom-rustfs" + asserts: + - equal: + path: metadata.name + value: completely-custom-rustfs + + - it: should add commonLabels to all resources + template: statefulset.yaml + set: + commonLabels: + environment: "test" + team: "platform" + asserts: + - equal: + path: metadata.labels.environment + value: test + - equal: + path: metadata.labels.team + value: platform + + - it: should respect image configuration overrides + template: statefulset.yaml + set: + image: + registry: "custom-registry.io" + repository: "custom/rustfs" + tag: "v1.0.0" + imagePullPolicy: "IfNotPresent" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: custom-registry.io/custom/rustfs:v1.0.0 + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + + - it: should configure environment variables correctly + template: statefulset.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].envFrom[0].configMapRef.name + value: RELEASE-NAME-rustfs + - equal: + path: spec.template.spec.containers[0].env[0].name + value: RUSTFS_ACCESS_KEY + - equal: + path: spec.template.spec.containers[0].env[1].name + value: RUSTFS_SECRET_KEY + + - it: should configure ports correctly + template: statefulset.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].ports[0].name + value: api + - equal: + path: spec.template.spec.containers[0].ports[0].containerPort + value: 9000 + - equal: + path: spec.template.spec.containers[0].ports[1].name + value: console + - equal: + path: spec.template.spec.containers[0].ports[1].containerPort + value: 9001 + + - it: should configure volume mounts correctly + template: statefulset.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].volumeMounts[0].name + value: data + - equal: + path: spec.template.spec.containers[0].volumeMounts[0].mountPath + value: /data + - equal: + path: spec.template.spec.containers[0].volumeMounts[1].name + value: logs + - equal: + path: spec.template.spec.containers[0].volumeMounts[1].mountPath + value: /app/logs + + - it: should deploy as StatefulSet when deploymentType is statefulset + set: + deploymentType: statefulset + template: statefulset.yaml + asserts: + - equal: + path: kind + value: StatefulSet + - equal: + path: metadata.name + value: RELEASE-NAME-rustfs + - equal: + path: spec.serviceName + value: RELEASE-NAME-rustfs-headless + - equal: + path: spec.podManagementPolicy + value: Parallel + + - it: should configure StatefulSet update strategy correctly + set: + deploymentType: statefulset + updateStrategy: + type: RollingUpdate + rollingUpdate: + partition: 2 + template: statefulset.yaml + asserts: + - equal: + path: spec.updateStrategy.type + value: RollingUpdate + - equal: + path: spec.updateStrategy.rollingUpdate.partition + value: 2 + + - it: should create volumeClaimTemplates for StatefulSet + set: + deploymentType: statefulset + dataPersistence: + enabled: true + size: 20Gi + logsPersistence: + enabled: true + size: 2Gi + template: statefulset.yaml + asserts: + - equal: + path: spec.volumeClaimTemplates[0].metadata.name + value: data + - equal: + path: spec.volumeClaimTemplates[0].spec.resources.requests.storage + value: 20Gi + - equal: + path: spec.volumeClaimTemplates[1].metadata.name + value: logs + - equal: + path: spec.volumeClaimTemplates[1].spec.resources.requests.storage + value: 2Gi + + - it: should not deploy Deployment when deploymentType is statefulset + set: + deploymentType: statefulset + template: deployment.yaml + asserts: + - hasDocuments: + count: 0 + + - it: should not deploy StatefulSet when deploymentType is deployment + set: + deploymentType: deployment + template: statefulset.yaml + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/charts/rustfs/values.schema.json b/charts/rustfs/values.schema.json new file mode 100644 index 00000000..28b92d8c --- /dev/null +++ b/charts/rustfs/values.schema.json @@ -0,0 +1,483 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "auth": { + "type": "object", + "properties": { + "accessKey": { + "type": "string" + }, + "existingSecret": { + "type": "string" + }, + "existingSecretAccessKeyKey": { + "type": "string" + }, + "existingSecretSecretKeyKey": { + "type": "string" + }, + "secretKey": { + "type": "string" + } + } + }, + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "consoleAddress": { + "type": "string" + }, + "consoleCorsAllowedOrigins": { + "type": "string" + }, + "consoleEnabled": { + "type": "boolean" + }, + "corsAllowedOrigins": { + "type": "string" + }, + "externalAddress": { + "type": "string" + }, + "extraEnvVars": { + "type": "array" + }, + "logLevel": { + "type": "string" + }, + "tlsPath": { + "type": "string" + }, + "volumes": { + "type": "string" + } + } + }, + "consoleIngress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } + } + }, + "consoleService": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "consolePort": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + }, + "sessionAffinityTimeout": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } + } + }, + "dataPersistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "deploymentType": { + "type": "string" + }, + "extraObjects": { + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } + } + }, + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "logsPersistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "nameOverride": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podManagementPolicy": { + "type": "string" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "consolePort": { + "type": "integer" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "tlsPersistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "tolerations": { + "type": "array" + }, + "updateStrategy": { + "type": "object", + "properties": { + "rollingUpdate": { + "type": "object", + "properties": { + "partition": { + "type": "integer" + } + } + }, + "type": { + "type": "string" + } + } + } + } +} diff --git a/charts/rustfs/values.yaml b/charts/rustfs/values.yaml new file mode 100644 index 00000000..bc57fb90 --- /dev/null +++ b/charts/rustfs/values.yaml @@ -0,0 +1,318 @@ +## @section Global parameters +global: + ## @param global.imageRegistry Global Docker Image registry + imageRegistry: "" + ## @param global.imagePullSecrets Global Docker registry secret names as an array + imagePullSecrets: [] + +## @section Common parameters +## @param nameOverride String to partially override rustfs.fullname +nameOverride: "" +## @param fullnameOverride String to fully override rustfs.fullname +fullnameOverride: "" +## @param commonLabels Labels to add to all deployed objects +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +commonAnnotations: {} + +## @section RustFS image configuration +image: + ## @param image.registry RustFS image registry + registry: docker.io + ## @param image.repository RustFS image repository + repository: rustfs/rustfs + ## @param image.tag RustFS image tag (immutable tags are recommended) + tag: "1.0.0-alpha.64@sha256:11ba8ff3870e8ee88494ad5b34e6942d1d91321483895c05aa264643f6d99a94" + ## @param image.imagePullPolicy RustFS image pull policy + imagePullPolicy: Always + +## @section RustFS Authentication +auth: + ## @param auth.accessKey RustFS access key + accessKey: "rustfsadmin" + ## @param auth.secretKey RustFS secret key. If not set, a random password will be generated + secretKey: "" + ## @param auth.existingSecret Name of existing secret containing RustFS credentials + existingSecret: "" + ## @param auth.existingSecretAccessKeyKey Key in existing secret containing access key + existingSecretAccessKeyKey: "access-key" + ## @param auth.existingSecretSecretKeyKey Key in existing secret containing secret key + existingSecretSecretKeyKey: "secret-key" + +## @section RustFS configuration +config: + ## @param config.volumes RustFS storage volumes configuration TODO (Not implemented yet in this chart) + # volumes: "/data/rustfs{0...3}" + volumes: "/data" + ## @param config.address RustFS server address + address: "0.0.0.0:9000" + ## @param config.consoleAddress RustFS console address + consoleAddress: "0.0.0.0:9001" + ## @param config.consoleEnabled Enable RustFS console + consoleEnabled: true + ## @param config.externalAddress RustFS external address (port your cluster ingress is listening to) + externalAddress: ":80" + ## @param config.corsAllowedOrigins CORS allowed origins for API + corsAllowedOrigins: "*" + ## @param config.consoleCorsAllowedOrigins CORS allowed origins for console + consoleCorsAllowedOrigins: "*" + ## @param config.logLevel RustFS log level (trace, debug, info, warn, error) + logLevel: "debug" + ## @param config.tlsPath Path to TLS certificates + tlsPath: "/opt/tls" + + ## @param config.extraEnvVars Extra environment variables to be set on RustFS containers + extraEnvVars: [] + +## @section Deployment configuration +replicaCount: 1 +## @section Deployment type configuration +## @param deploymentType Type of deployment (deployment or statefulset). StatefulSet needs a replicacount of 4. +deploymentType: "deployment" + +## @param updateStrategy Update strategy for StatefulSet (only applies when deploymentType is statefulset) +updateStrategy: + type: RollingUpdate + ## @param updateStrategy.rollingUpdate.partition Partition for RollingUpdate (only for StatefulSet) + rollingUpdate: + partition: 0 + +## @param podManagementPolicy Pod management policy for StatefulSet (Parallel or OrderedReady) +podManagementPolicy: "Parallel" + +## @section Pod annotations and labels +podAnnotations: {} +podLabels: {} + +## @section Security Context +podSecurityContext: + ## @param podSecurityContext.fsGroup Group ID for the volumes of the pod + fsGroup: 1001 + +containerSecurityContext: + ## @param containerSecurityContext.allowPrivilegeEscalation Enable container privilege escalation + allowPrivilegeEscalation: false + ## @param containerSecurityContext.runAsNonRoot Configure the container to run as a non-root user + runAsNonRoot: true + ## @param containerSecurityContext.runAsUser User ID for the RustFS container + runAsUser: 1001 + ## @param containerSecurityContext.runAsGroup Group ID for the RustFS container + runAsGroup: 1001 + ## @param containerSecurityContext.readOnlyRootFilesystem Mount container root filesystem as read-only + readOnlyRootFilesystem: false + ## @param containerSecurityContext.capabilities.drop Linux capabilities to be dropped + capabilities: + drop: + - ALL + +## @section Service configuration +service: + ## @param service.type RustFS service type + type: ClusterIP + ## @param service.port RustFS API service port + port: 9000 + ## @param service.consolePort RustFS console service port + consolePort: 9001 + ## @param service.annotations Service annotations + annotations: {} + +## @section Console Service configuration (for StatefulSet only) +consoleService: + ## @param consoleService.enabled Enable Console service that routes to the first pod only + enabled: true + ## @param consoleService.type Console service type + type: ClusterIP + ## @param consoleService.port Console service API port + port: 9000 + ## @param consoleService.consolePort Console service console port + consolePort: 9001 + ## @param consoleService.sessionAffinityTimeout Session affinity timeout in seconds + sessionAffinityTimeout: 10800 + ## @param consoleService.annotations Console service annotations + annotations: {} + +## @section Ingress configuration +ingress: + ## @param ingress.enabled Enable ingress record generation for RustFS API + enabled: true + ## @param ingress.className IngressClass that will be used to implement the Ingress + className: "" + ## @param ingress.annotations Additional annotations for the Ingress resource + annotations: + {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + ## @param ingress.hosts[0].host Hostname for RustFS API ingress + ## @param ingress.hosts[0].paths[0].path Path for RustFS API ingress + ## @param ingress.hosts[0].paths[0].pathType Path type for RustFS API ingress + hosts: + - host: rustfs.localhost + paths: + - path: / + pathType: Prefix + ## @param ingress.tls TLS configuration for RustFS API ingress + tls: [] + # - secretName: rustfs-tls + # hosts: + # - rustfs.local + +## @section Console Ingress configuration (for StatefulSet only) +consoleIngress: + ## @param consoleIngress.enabled Enable Console ingress record generation for RustFS API (routes to first pod only) + enabled: true + ## @param consoleIngress.className IngressClass that will be used to implement the Console Ingress + className: "" + ## @param consoleIngress.annotations Additional annotations for the Console Ingress resource + annotations: + {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/affinity: "cookie" + # nginx.ingress.kubernetes.io/affinity-mode: "persistent" + # nginx.ingress.kubernetes.io/session-cookie-name: "rustfs-console" + # nginx.ingress.kubernetes.io/session-cookie-max-age: "86400" + ## @param consoleIngress.hosts[0].host Hostname for Console RustFS API ingress + ## @param consoleIngress.hosts[0].paths[0].path Path for Console RustFS API ingress + ## @param consoleIngress.hosts[0].paths[0].pathType Path type for Console RustFS API ingress + hosts: + - host: rustfs-console.localhost + paths: + - path: / + pathType: Prefix + ## @param consoleIngress.tls TLS configuration for Console RustFS API ingress + tls: [] + # - secretName: rustfs-console-tls + # hosts: + # - rustfs-console.local + +## @section Resources +resources: + {} + ## We usually recommend not to specify default resources and to leave this as a conscious + ## choice for the user. This also increases chances charts run on environments with little + ## resources, such as Minikube. If you do want to specify resources, uncomment the following + ## lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +## @section Data Persistence +dataPersistence: + ## @param dataPersistence.enabled Enable data persistence using Persistent Volume Claims + enabled: true + ## @param dataPersistence.storageClass Persistent Volume storage class for data + storageClass: "" + ## @param dataPersistence.annotations Persistent Volume Claim annotations for data + annotations: {} + ## @param dataPersistence.size Persistent Volume size for data + size: 10Gi + ## @param dataPersistence.accessModes Persistent Volume access modes for data + accessModes: + - ReadWriteOnce + ## @param dataPersistence.existingClaim The name of an existing PVC to use for data persistence + existingClaim: "" + ## @param dataPersistence.mountPath The path where to mount the data volume + mountPath: /data + +## @section Logs Persistence +logsPersistence: + ## @param logsPersistence.enabled Enable logs persistence using Persistent Volume Claims + enabled: true + ## @param logsPersistence.storageClass Persistent Volume storage class for logs + storageClass: "" + ## @param logsPersistence.annotations Persistent Volume Claim annotations for logs + annotations: {} + ## @param logsPersistence.size Persistent Volume size for logs + size: 1Gi + ## @param logsPersistence.accessModes Persistent Volume access modes for logs + accessModes: + - ReadWriteOnce + ## @param logsPersistence.existingClaim The name of an existing PVC to use for logs persistence + existingClaim: "" + ## @param logsPersistence.mountPath The path where to mount the logs volume + mountPath: /app/logs + +## @section TLS Persistence +tlsPersistence: + ## @param tlsPersistence.enabled Enable TLS persistence using Persistent Volume Claims + enabled: false + ## @param tlsPersistence.storageClass Persistent Volume storage class for TLS + storageClass: "" + ## @param tlsPersistence.annotations Persistent Volume Claim annotations for TLS + annotations: {} + ## @param tlsPersistence.size Persistent Volume size for TLS + size: 100Mi + ## @param tlsPersistence.accessModes Persistent Volume access modes for TLS + accessModes: + - ReadWriteOnce + ## @param tlsPersistence.existingClaim The name of an existing PVC to use for TLS persistence + existingClaim: "" + ## @param tlsPersistence.mountPath The path where to mount the TLS volume + mountPath: /opt/tls + +serviceAccount: + ## @param serviceAccount.create Enable the creation of a ServiceAccount for RustFS + create: true + ## @param serviceAccount.name Name of the created ServiceAccount + ## If not set and create is true, a name is generated using the common.names.fullname template + name: "" + ## @param serviceAccount.automountServiceAccountToken Enable/disable auto mounting of the service account token + automountServiceAccountToken: false + ## @param serviceAccount.annotations Custom annotations for RustFS serviceAccount + annotations: {} + +## @section Liveness and readiness probes +livenessProbe: + ## @param livenessProbe.enabled Enable livenessProbe on RustFS containers + enabled: true + ## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + initialDelaySeconds: 15 + ## @param livenessProbe.periodSeconds Period seconds for livenessProbe + periodSeconds: 30 + ## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + timeoutSeconds: 10 + ## @param livenessProbe.failureThreshold Failure threshold for livenessProbe + failureThreshold: 3 + ## @param livenessProbe.successThreshold Success threshold for livenessProbe + successThreshold: 1 + +readinessProbe: + ## @param readinessProbe.enabled Enable readinessProbe on RustFS containers + enabled: true + ## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + initialDelaySeconds: 5 + ## @param readinessProbe.periodSeconds Period seconds for readinessProbe + periodSeconds: 10 + ## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + timeoutSeconds: 5 + ## @param readinessProbe.failureThreshold Failure threshold for readinessProbe + failureThreshold: 3 + ## @param readinessProbe.successThreshold Success threshold for readinessProbe + successThreshold: 1 + +startupProbe: + ## @param startupProbe.enabled Enable startupProbe on RustFS containers + enabled: true + ## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + initialDelaySeconds: 5 + ## @param startupProbe.periodSeconds Period seconds for startupProbe + periodSeconds: 10 + ## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe + timeoutSeconds: 10 + ## @param startupProbe.failureThreshold Failure threshold for startupProbe + failureThreshold: 3 + ## @param startupProbe.successThreshold Success threshold for startupProbe + successThreshold: 1 + +## @section Node Selection +nodeSelector: {} + +tolerations: [] + +affinity: {} + +## @param extraObjects Array of extra objects to deploy with the release +extraObjects: [] diff --git a/charts/timescaledb/CHANGELOG.md b/charts/timescaledb/CHANGELOG.md index c0e88257..1e384110 100644 --- a/charts/timescaledb/CHANGELOG.md +++ b/charts/timescaledb/CHANGELOG.md @@ -1,5 +1,86 @@ # Changelog + +## 0.5.1 (2025-10-30) + +* [timescale/timescaledb] Update charts/timescaledb/values.yaml timescale/timescaledb to v2.23.0 (minor) (#498) ([af305d0](https://github.com/CloudPirates-io/helm-charts/commit/af305d0)) +* chore: update CHANGELOG.md for merged changes ([6fd22a6](https://github.com/CloudPirates-io/helm-charts/commit/6fd22a6)) +* chore: update CHANGELOG.md for merged changes ([3eb08ee](https://github.com/CloudPirates-io/helm-charts/commit/3eb08ee)) +* chore: auto-generate values.schema.json (#481) ([d37c7ed](https://github.com/CloudPirates-io/helm-charts/commit/d37c7ed)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.5.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.4.2 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([4587534](https://github.com/CloudPirates-io/helm-charts/commit/4587534)) +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.4.1 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([c80ea42](https://github.com/CloudPirates-io/helm-charts/commit/c80ea42)) +* chore: update CHANGELOG.md for merged changes ([8ccb4bb](https://github.com/CloudPirates-io/helm-charts/commit/8ccb4bb)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.4.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.3.2 (2025-10-13) + +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + ## 0.3.1 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* [timescale/timescaledb] Update charts/timescaledb/values.yaml timescale/timescaledb to v2.22.1 (patch) (#265) ([df11e54](https://github.com/CloudPirates-io/helm-charts/commit/df11e54)) +* [minio, mongodb, postgres, timescaledb] Update securityContext to containerSecurityContext in the values schema (#213) ([8a4003f](https://github.com/CloudPirates-io/helm-charts/commit/8a4003f)) + +## 0.3.0 (2025-10-02) + +* make timescaledb run on openshift (#205) ([250b562](https://github.com/CloudPirates-io/helm-charts/commit/250b562)) + +## 0.2.2 (2025-09-26) + +* [timescale/timescaledb] chore(deps): update docker.io/timescale/timescaledb:2.22.0-pg17 Docker digest to bd55a8c (#167) ([b8ca89e](https://github.com/CloudPirates-io/helm-charts/commit/b8ca89e)) + +## 0.2.1 (2025-09-08) + +* Update CHANGELOG.md ([147c2f6](https://github.com/CloudPirates-io/helm-charts/commit/147c2f6)) +* Update CHANGELOG.md ([de23d89](https://github.com/CloudPirates-io/helm-charts/commit/de23d89)) +* Update appVersion ([377966d](https://github.com/CloudPirates-io/helm-charts/commit/377966d)) +* Update CHANGELOG.md ([4d63d23](https://github.com/CloudPirates-io/helm-charts/commit/4d63d23)) +* Bump Timescaledb to latests stable ([d096653](https://github.com/CloudPirates-io/helm-charts/commit/d096653)) + +## 0.2.0 (2025-09-02) + +* bump all chart versions for new extraObjects feature ([aaa57f9](https://github.com/CloudPirates-io/helm-charts/commit/aaa57f9)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.1.1 (2025-08-27) + +* Fix values.yaml / Chart.yaml linting issues ([043c7e0](https://github.com/CloudPirates-io/helm-charts/commit/043c7e0)) +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.1.0 (2025-08-26) + +* Initial tagged release diff --git a/charts/timescaledb/Chart.lock b/charts/timescaledb/Chart.lock index fe245150..574dc295 100644 --- a/charts/timescaledb/Chart.lock +++ b/charts/timescaledb/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-10-01T22:19:25.458376+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:15:07.881936+02:00" diff --git a/charts/timescaledb/Chart.yaml b/charts/timescaledb/Chart.yaml index eeccf581..64a90809 100644 --- a/charts/timescaledb/Chart.yaml +++ b/charts/timescaledb/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: timescaledb description: TimescaleDB - The Open Source Time-Series Database for PostgreSQL type: application -version: 0.3.1 -appVersion: "2.22.0-pg17" +version: 0.5.1 +appVersion: "2.23.0" keywords: - timescaledb - timeseries @@ -11,14 +11,38 @@ keywords: - database - sql - analytics -home: https://www.cloudpirates.io +home: https://www.timescale.com sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/timescaledb + - https://github.com/timescale/timescaledb maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/b2e01452ce/timescaledb-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: TimescaleDB + url: https://www.timescale.com + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/timescaledb + - name: Application + url: https://github.com/timescale/timescaledb + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "[timescale/timescaledb] Update charts/timescaledb/values.yaml timescale/timescaledb to v2.23.0 (minor) (#498)" + links: + - name: "Commit af305d0" + url: "https://github.com/CloudPirates-io/helm-charts/commit/af305d0" diff --git a/charts/timescaledb/README.md b/charts/timescaledb/README.md index d10aeff6..ae950f29 100644 --- a/charts/timescaledb/README.md +++ b/charts/timescaledb/README.md @@ -200,6 +200,7 @@ The following table lists the configurable parameters of the TimescaleDB chart a | Parameter | Description | Default | | ------------------- | ----------------------------------------------------------------------- | ------- | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraObjects` | A list of additional Kubernetes objects to deploy alongside the release | `[]` | #### Extra Objects diff --git a/charts/timescaledb/templates/_helpers.tpl b/charts/timescaledb/templates/_helpers.tpl index 098b08c9..9a722f9b 100644 --- a/charts/timescaledb/templates/_helpers.tpl +++ b/charts/timescaledb/templates/_helpers.tpl @@ -2,7 +2,7 @@ Expand the name of the chart. */}} {{- define "timescaledb.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* @@ -11,21 +11,21 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "timescaledb.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "timescaledb.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "timescaledb.labels" -}} -{{- include "common.labels" . -}} +{{- include "cloudpirates.labels" . -}} {{- end }} {{/* @@ -41,14 +41,14 @@ Common annotations Selector labels */}} {{- define "timescaledb.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Return the proper TimescaleDB image name */}} {{- define "timescaledb.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* @@ -56,7 +56,7 @@ Return TimescaleDB credentials secret name */}} {{- define "timescaledb.secretName" -}} {{- if .Values.auth.existingSecret -}} - {{- .Values.auth.existingSecret -}} + {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) -}} {{- else -}} {{- include "timescaledb.fullname" . -}} {{- end -}} @@ -109,5 +109,5 @@ Return TimescaleDB run directory Return the proper Docker Image Registry Secret Names */}} {{- define "timescaledb.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} \ No newline at end of file diff --git a/charts/timescaledb/templates/extraobjects.yaml b/charts/timescaledb/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/timescaledb/templates/extraobjects.yaml +++ b/charts/timescaledb/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/timescaledb/templates/statefulset.yaml b/charts/timescaledb/templates/statefulset.yaml index c3c82cd5..0929eba6 100644 --- a/charts/timescaledb/templates/statefulset.yaml +++ b/charts/timescaledb/templates/statefulset.yaml @@ -29,10 +29,10 @@ spec: {{- with (include "timescaledb.imagePullSecrets" .) }} {{ . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "timescaledb.image" . }} imagePullPolicy: {{ .Values.image.imagePullPolicy }} env: @@ -57,6 +57,9 @@ spec: - name: POSTGRES_EFFECTIVE_CACHE_SIZE value: {{ .Values.config.postgresqlEffectiveCacheSize | quote }} {{- end }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} + {{- end }} ports: - name: postgresql containerPort: {{ .Values.service.targetPort }} diff --git a/charts/timescaledb/values.schema.json b/charts/timescaledb/values.schema.json index 5966784d..b2a9e613 100644 --- a/charts/timescaledb/values.schema.json +++ b/charts/timescaledb/values.schema.json @@ -1,558 +1,287 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "TimescaleDB Helm Chart Values Schema", - "description": "Schema for TimescaleDB Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global Parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker Image registry" + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "image": { - "type": "object", - "title": "TimescaleDB Image Configuration", - "description": "TimescaleDB container image configuration", - "properties": { - "registry": { - "type": "string", - "title": "TimescaleDB Image Registry", - "description": "TimescaleDB image registry" - }, - "repository": { - "type": "string", - "title": "TimescaleDB Image Repository", - "description": "TimescaleDB image repository" - }, - "tag": { - "type": "string", - "title": "TimescaleDB Image Tag", - "description": "TimescaleDB image tag with digest" - }, - "imagePullPolicy": { - "type": "string", - "title": "TimescaleDB Image Pull Policy", - "description": "TimescaleDB image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] - } - } - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of TimescaleDB replicas to deploy (Note: TimescaleDB doesn't support multi-master replication by default)", - "minimum": 1 - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override timescaledb.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override timescaledb.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "Security Context configuration", - "properties": { - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Group ID for the volumes of the pod", - "minimum": 0 - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "Security Context", - "description": "Container security context", - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Enable container privilege escalation" - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Configure the container to run as a non-root user" - }, - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID for the TimescaleDB container", - "minimum": 0 + "existingSecret": { + "type": "string" + }, + "postgresPassword": { + "type": "string" + }, + "secretKeys": { + "type": "object", + "properties": { + "adminPasswordKey": { + "type": "string" + } + } + } + } }, - "runAsGroup": { - "type": "integer", - "title": "Run As Group", - "description": "Group ID for the TimescaleDB container", - "minimum": 0 + "commonAnnotations": { + "type": "object" }, - "readOnlyRootFilesystem": { - "type": "boolean", - "title": "Read-Only Root Filesystem", - "description": "Mount container root filesystem as read-only" + "commonLabels": { + "type": "object" }, - "capabilities": { - "type": "object", - "title": "Capabilities", - "description": "Linux capabilities configuration", - "properties": { - "drop": { - "type": "array", - "title": "Drop Capabilities", - "description": "Linux capabilities to be dropped", - "items": { - "type": "string" - } + "config": { + "type": "object", + "properties": { + "existingConfigmap": { + "type": "string" + }, + "extraConfig": { + "type": "array" + }, + "postgresqlCheckpointCompletionTarget": { + "type": "string" + }, + "postgresqlEffectiveCacheSize": { + "type": "string" + }, + "postgresqlLogMinDurationStatement": { + "type": "string" + }, + "postgresqlLogStatement": { + "type": "string" + }, + "postgresqlMaintenanceWorkMem": { + "type": "string" + }, + "postgresqlMaxConnections": { + "type": "integer" + }, + "postgresqlRandomPageCost": { + "type": "string" + }, + "postgresqlSharedBuffers": { + "type": "string" + }, + "postgresqlSharedPreloadLibraries": { + "type": "string" + }, + "postgresqlWalBuffers": { + "type": "string" + }, + "postgresqlWorkMem": { + "type": "string" + }, + "timescaledbMaxBackgroundWorkers": { + "type": "integer" + }, + "timescaledbTelemetry": { + "type": "string" + } } - } - } - } - }, - "auth": { - "type": "object", - "title": "TimescaleDB Authentication", - "description": "TimescaleDB Authentication configuration", - "properties": { - "postgresPassword": { - "type": "string", - "title": "Postgres Password", - "description": "Password for the postgres admin user. If not set, a random password will be generated" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "Name of existing secret to use for TimescaleDB credentials" }, - "secretKeys": { - "type": "object", - "title": "Secret Keys", - "description": "Keys in existing secret", - "properties": { - "adminPasswordKey": { - "type": "string", - "title": "Admin Password Key", - "description": "Name of key in existing secret to use for TimescaleDB credentials" + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + } } - } - } - } - }, - "config": { - "type": "object", - "title": "TimescaleDB Configuration", - "description": "TimescaleDB Configuration parameters", - "properties": { - "postgresqlSharedPreloadLibraries": { - "type": "string", - "title": "Shared Preload Libraries", - "description": "Shared preload libraries (comma-separated list)" - }, - "postgresqlMaxConnections": { - "type": "integer", - "title": "Max Connections", - "description": "Maximum number of connections", - "minimum": 1 }, - "postgresqlSharedBuffers": { - "type": "string", - "title": "Shared Buffers", - "description": "Amount of memory the database server uses for shared memory buffers" + "extraEnvVars": { + "type": "array" }, - "postgresqlEffectiveCacheSize": { - "type": "string", - "title": "Effective Cache Size", - "description": "Effective cache size" + "extraObjects": { + "type": "array" }, - "postgresqlWorkMem": { - "type": "string", - "title": "Work Memory", - "description": "Amount of memory to be used by internal sort operations and hash tables" - }, - "postgresqlMaintenanceWorkMem": { - "type": "string", - "title": "Maintenance Work Memory", - "description": "Maximum amount of memory to be used by maintenance operations" - }, - "postgresqlWalBuffers": { - "type": "string", - "title": "WAL Buffers", - "description": "Amount of memory used in shared memory for WAL data" - }, - "postgresqlCheckpointCompletionTarget": { - "type": "string", - "title": "Checkpoint Completion Target", - "description": "Time spent flushing dirty buffers during checkpoint, as fraction of checkpoint interval" - }, - "postgresqlRandomPageCost": { - "type": "string", - "title": "Random Page Cost", - "description": "Sets the planner's estimate of the cost of a non-sequentially-fetched disk page" - }, - "postgresqlLogStatement": { - "type": "string", - "title": "Log Statement", - "description": "Sets the type of statements logged" - }, - "postgresqlLogMinDurationStatement": { - "type": "string", - "title": "Log Min Duration Statement", - "description": "Sets the minimum execution time above which statements will be logged" - }, - "extraConfig": { - "type": "array", - "title": "Extra Configuration", - "description": "Additional PostgreSQL configuration parameters", - "items": { + "fullnameOverride": { "type": "string" - } - }, - "timescaledbTelemetry": { - "type": "string", - "title": "TimescaleDB Telemetry", - "description": "Enable/disable TimescaleDB telemetry", - "enum": ["on", "off"] - }, - "timescaledbMaxBackgroundWorkers": { - "type": "integer", - "title": "TimescaleDB Max Background Workers", - "description": "Maximum number of TimescaleDB background workers", - "minimum": 1 }, - "existingConfigmap": { - "type": "string", - "title": "Existing ConfigMap", - "description": "Name of existing ConfigMap with TimescaleDB configuration" - } - } - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "Service configuration parameters", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "TimescaleDB service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "TimescaleDB service port", - "minimum": 1, - "maximum": 65535 - }, - "targetPort": { - "type": "integer", - "title": "Target Port", - "description": "TimescaleDB container port", - "minimum": 1, - "maximum": 65535 - }, - "annotations": { - "type": "object", - "title": "Service Annotations", - "description": "Service annotations", - "additionalProperties": { - "type": "string" - } - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "Resource configuration parameters", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } } - } }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } } - } - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "Persistence configuration parameters", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable persistence using Persistent Volume Claims" }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "Persistent Volume storage class" + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "annotations": { - "type": "object", - "title": "PVC Annotations", - "description": "Persistent Volume Claim annotations", - "additionalProperties": { + "nameOverride": { "type": "string" - } - }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "Persistent Volume size", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" - }, - "accessModes": { - "type": "array", - "title": "Access Modes", - "description": "Persistent Volume access modes", - "items": { - "type": "string", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] - } - }, - "existingClaim": { - "type": "string", - "title": "Existing Claim", - "description": "The name of an existing PVC to use for persistence" - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "Liveness and readiness probes configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable livenessProbe on TimescaleDB containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for livenessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for livenessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for livenessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for livenessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for livenessProbe", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "Readiness probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readinessProbe on TimescaleDB containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for readinessProbe", - "minimum": 0 }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for readinessProbe", - "minimum": 1 + "nodeSelector": { + "type": "object" }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for readinessProbe", - "minimum": 1 + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for readinessProbe", - "minimum": 1 + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for readinessProbe", - "minimum": 1 - } - } - }, - "startupProbe": { - "type": "object", - "title": "Startup Probe Configuration", - "description": "Startup probe configuration", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Startup Probe", - "description": "Enable startupProbe on TimescaleDB containers" + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for startupProbe", - "minimum": 0 + "replicaCount": { + "type": "integer" }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for startupProbe", - "minimum": 1 + "resources": { + "type": "object" }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for startupProbe", - "minimum": 1 + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "type": "integer" + }, + "type": { + "type": "string" + } + } }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for startupProbe", - "minimum": 1 + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for startupProbe", - "minimum": 1 + "tolerations": { + "type": "array" } - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node labels for pod assignment", - "additionalProperties": { - "type": "string" - } - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Toleration labels for pod assignment", - "items": { - "type": "object" - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity settings for pod assignment" - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } -} \ No newline at end of file +} diff --git a/charts/timescaledb/values.yaml b/charts/timescaledb/values.yaml index 30511a8d..f36bf14d 100644 --- a/charts/timescaledb/values.yaml +++ b/charts/timescaledb/values.yaml @@ -22,7 +22,7 @@ image: ## @param image.repository TimescaleDB image repository repository: timescale/timescaledb ## @param image.tag TimescaleDB image tag (immutable tags are recommended) - tag: "2.22.1-pg17@sha256:fba60021a224479e174ae1ec577c1a0576d5185b09fe9e622f1d19e4bf5bab0d" + tag: "2.23.0-pg17@sha256:92fcd95150342632b8bcd12c2248599ba58441bc6dd3b80576445027b06cd1eb" ## @param image.imagePullPolicy TimescaleDB image pull policy imagePullPolicy: Always @@ -197,3 +197,13 @@ extraObjects: [] # namespace: "{{ .Release.Namespace }}" # data: # key: value + +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key diff --git a/charts/valkey/CHANGELOG.md b/charts/valkey/CHANGELOG.md index 93649a44..bf30208e 100644 --- a/charts/valkey/CHANGELOG.md +++ b/charts/valkey/CHANGELOG.md @@ -1,5 +1,121 @@ # Changelog + +## 0.10.0 (2025-11-07) + +* [valkey]: Support TLS ([3b0b609](https://github.com/CloudPirates-io/helm-charts/commit/3b0b609)) + +## 0.9.2 (2025-11-03) + +* [valkey]: fix broken statement ([49a9fe9](https://github.com/CloudPirates-io/helm-charts/commit/49a9fe9)) +* chore: update CHANGELOG.md for merged changes ([7af5c40](https://github.com/CloudPirates-io/helm-charts/commit/7af5c40)) +* chore: update CHANGELOG.md for merged changes ([e086407](https://github.com/CloudPirates-io/helm-charts/commit/e086407)) + +## 0.9.1 (2025-11-03) + +* [oliver006/redis_exporter] Update charts/valkey/values.yaml oliver006/redis_exporter to v1.80.0 (minor) (#531) ([57d1caf](https://github.com/CloudPirates-io/helm-charts/commit/57d1caf)) +* chore: update CHANGELOG.md for merged changes ([5e662d8](https://github.com/CloudPirates-io/helm-charts/commit/5e662d8)) +* chore: update CHANGELOG.md for merged changes ([bb1523e](https://github.com/CloudPirates-io/helm-charts/commit/bb1523e)) + +## 0.9.0 (2025-10-31) + +* [valkey]: Valkey HA (#518) ([d8b1bbe](https://github.com/CloudPirates-io/helm-charts/commit/d8b1bbe)) +* chore: update CHANGELOG.md for merged changes ([6fd22a6](https://github.com/CloudPirates-io/helm-charts/commit/6fd22a6)) +* chore: update CHANGELOG.md for merged changes ([3eb08ee](https://github.com/CloudPirates-io/helm-charts/commit/3eb08ee)) +* chore: auto-generate values.schema.json (#481) ([d37c7ed](https://github.com/CloudPirates-io/helm-charts/commit/d37c7ed)) +* chore: update CHANGELOG.md for merged changes ([8260788](https://github.com/CloudPirates-io/helm-charts/commit/8260788)) +* chore: update CHANGELOG.md for merged changes ([402f7bd](https://github.com/CloudPirates-io/helm-charts/commit/402f7bd)) + +## 0.8.0 (2025-10-28) + +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.7.1 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([bfb9443](https://github.com/CloudPirates-io/helm-charts/commit/bfb9443)) +* chore: update CHANGELOG.md for merged changes ([80edeb0](https://github.com/CloudPirates-io/helm-charts/commit/80edeb0)) +* chore: update CHANGELOG.md for merged changes ([cbb73ba](https://github.com/CloudPirates-io/helm-charts/commit/cbb73ba)) + +## 0.7.0 (2025-10-22) + +* [valkey/valkey] Update charts/valkey/values.yaml valkey/valkey to v9 (major) (#442) ([75276a8](https://github.com/CloudPirates-io/helm-charts/commit/75276a8)) +* chore: update CHANGELOG.md for merged changes ([4587534](https://github.com/CloudPirates-io/helm-charts/commit/4587534)) +* chore: update CHANGELOG.md for merged changes ([051ad83](https://github.com/CloudPirates-io/helm-charts/commit/051ad83)) +* chore: update CHANGELOG.md for merged changes ([1a50307](https://github.com/CloudPirates-io/helm-charts/commit/1a50307)) + +## 0.6.2 (2025-10-22) + +* chore: update CHANGELOG.md for merged changes ([c80ea42](https://github.com/CloudPirates-io/helm-charts/commit/c80ea42)) +* chore: update CHANGELOG.md for merged changes ([8ccb4bb](https://github.com/CloudPirates-io/helm-charts/commit/8ccb4bb)) +* chore: update CHANGELOG.md for merged changes ([5d1f01a](https://github.com/CloudPirates-io/helm-charts/commit/5d1f01a)) +* chore: update CHANGELOG.md for merged changes ([fc47c5d](https://github.com/CloudPirates-io/helm-charts/commit/fc47c5d)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([838e5c5](https://github.com/CloudPirates-io/helm-charts/commit/838e5c5)) +* chore: update CHANGELOG.md for merged changes ([e2a1daa](https://github.com/CloudPirates-io/helm-charts/commit/e2a1daa)) + +## 0.6.1 (2025-10-17) + +* [oliver006/redis_exporter] Update charts/valkey/values.yaml oliver006/redis_exporter to v1.79.0 (minor) (#407) ([7c0e2b3](https://github.com/CloudPirates-io/helm-charts/commit/7c0e2b3)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.6.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([63b7bfa](https://github.com/CloudPirates-io/helm-charts/commit/63b7bfa)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.5.1 (2025-10-13) + + +## 0.5.0 (2025-10-10) + +* feat: add metrics exporter (#342) ([e6b474b](https://github.com/CloudPirates-io/helm-charts/commit/e6b474b)) +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + ## 0.4.1 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* [valkey/valkey] Update charts/valkey/values.yaml valkey/valkey to v8.1.4 (patch) (#266) ([b52fedf](https://github.com/CloudPirates-io/helm-charts/commit/b52fedf)) + +## 0.4.0 (2025-10-06) + +* make valkey run on openshift (#206) ([b1f530c](https://github.com/CloudPirates-io/helm-charts/commit/b1f530c)) + +## 0.3.2 (2025-09-16) + +* Update CHANGELOG.md ([3005f2f](https://github.com/CloudPirates-io/helm-charts/commit/3005f2f)) +* Oops, wrong bump ([1d2fefa](https://github.com/CloudPirates-io/helm-charts/commit/1d2fefa)) +* Fix scheduling directives with disabled persistance ([7485b37](https://github.com/CloudPirates-io/helm-charts/commit/7485b37)) + +## 0.3.1 (2025-09-12) + +* Update CHANGELOG.md ([36da816](https://github.com/CloudPirates-io/helm-charts/commit/36da816)) +* fix templating of `affinity`, `nodeSelector` and `tolerations` values ([e98c8ea](https://github.com/CloudPirates-io/helm-charts/commit/e98c8ea)) + +## 0.3.0 (2025-09-02) + +* bump all chart versions for new extraObjects feature ([aaa57f9](https://github.com/CloudPirates-io/helm-charts/commit/aaa57f9)) +* add extraObject array to all charts ([34772b7](https://github.com/CloudPirates-io/helm-charts/commit/34772b7)) + +## 0.2.0 (2025-09-02) + +* Update serviceaccount config to disable automatic creation, add missing ns ([77281c6](https://github.com/CloudPirates-io/helm-charts/commit/77281c6)) +* Add support for serviceAccount ([16ac6b3](https://github.com/CloudPirates-io/helm-charts/commit/16ac6b3)) + +## 0.1.7 (2025-08-27) + +* Add initial Changelogs to all Charts ([68f10ca](https://github.com/CloudPirates-io/helm-charts/commit/68f10ca)) + +## 0.1.6 (2025-08-26) + +* Initial tagged release diff --git a/charts/valkey/Chart.lock b/charts/valkey/Chart.lock index 972854e4..1a7d1799 100644 --- a/charts/valkey/Chart.lock +++ b/charts/valkey/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-10-01T22:44:24.995595+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:15:13.740266+02:00" diff --git a/charts/valkey/Chart.yaml b/charts/valkey/Chart.yaml index 1bf364eb..a23bdd78 100644 --- a/charts/valkey/Chart.yaml +++ b/charts/valkey/Chart.yaml @@ -2,11 +2,12 @@ apiVersion: v2 name: valkey description: High performance in-memory data structure store, fork of Redis. Valkey is an open-source, high-performance key/value datastore that supports a variety of workloads such as caching, message queues, and can act as a primary database. type: application -version: 0.4.1 -appVersion: "8.1.3" -home: https://www.cloudpirates.io +version: 0.10.0 +appVersion: "9.0.0" +home: https://www.valkey.io sources: - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/valkey + - https://github.com/valkey-io/valkey keywords: - valkey - redis @@ -15,14 +16,34 @@ keywords: - key-value - in-memory - nosql -annotations: - category: Database - license: Apache-2.0 maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/5242c0e31a/valkey-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: Valkey + url: https://valkey.io + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/valkey + - name: Application + url: https://github.com/valkey-io/valkey + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "[valkey]: Support TLS" + links: + - name: "Commit 3b0b609" + url: "https://github.com/CloudPirates-io/helm-charts/commit/3b0b609" diff --git a/charts/valkey/README.md b/charts/valkey/README.md index f9f8668c..864c49fd 100644 --- a/charts/valkey/README.md +++ b/charts/valkey/README.md @@ -86,13 +86,16 @@ The following table lists the configurable parameters of the Valkey chart and th ### Deployment configuration -| Parameter | Description | Default | -| ------------------- | -------------------------------------------- | ------- | -| `replicaCount` | Number of Valkey replicas to deploy | `1` | -| `nameOverride` | String to partially override valkey.fullname | `""` | -| `fullnameOverride` | String to fully override valkey.fullname | `""` | -| `commonLabels` | Labels to add to all deployed objects | `{}` | -| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| Parameter | Description | Default | +| ------------------- | ---------------------------------------------------------------------------------------------- | -------------- | +| `architecture` | Valkey architecture. Allowed values: `standalone`, `replication` | `standalone` | +| `replicaCount` | Number of Valkey replicas to deploy (only when architecture=replication) | `3` | +| `ipFamily` | IP family to use for replica and sentinel announce IPs. Allowed values: `auto`, `ipv4`, `ipv6` | `auto` | +| `clusterDomain` | Kubernetes cluster domain | `cluster.local`| +| `nameOverride` | String to partially override valkey.fullname | `""` | +| `fullnameOverride` | String to fully override valkey.fullname | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | ### Pod annotations and labels @@ -210,10 +213,68 @@ The following table lists the configurable parameters of the Valkey chart and th | `tolerations` | Toleration labels for pod assignment | `[]` | | `affinity` | Affinity settings for pod assignment | `{}` | +### Metrics configuration + +| Parameter | Description | Default | +| ------------------------------------------ | ------------------------------------------------------------------------------- | -------------------------- | +| `metrics.enabled` | Start a sidecar prometheus exporter to expose Valkey metrics | `false` | +| `metrics.image.registry` | Valkey exporter image registry | `docker.io` | +| `metrics.image.repository` | Valkey exporter image repository | `oliver006/redis_exporter` | +| `metrics.image.tag` | Valkey exporter image tag | `v1.78.0-alpine` | +| `metrics.image.pullPolicy` | Valkey exporter image pull policy | `Always` | +| `metrics.resources` | Resource limits and requests for metrics container | `{}` | +| `metrics.service.annotations` | Additional custom annotations for Metrics service | `{}` | +| `metrics.service.labels` | Additional custom labels for Metrics service | `{}` | +| `metrics.service.port` | Metrics service port | `9121` | +| `metrics.serviceMonitor.enabled` | Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator | `false` | +| `metrics.serviceMonitor.namespace` | The namespace in which the ServiceMonitor will be created | `""` | +| `metrics.serviceMonitor.interval` | The interval at which metrics should be scraped | `30s` | +| `metrics.serviceMonitor.scrapeTimeout` | The timeout after which the scrape is ended | `10s` | +| `metrics.serviceMonitor.selector` | Additional labels for ServiceMonitor resource | `{}` | +| `metrics.serviceMonitor.annotations` | ServiceMonitor annotations | `{}` | +| `metrics.serviceMonitor.honorLabels` | honorLabels chooses the metric's labels on collisions with target labels | `false` | +| `metrics.serviceMonitor.relabelings` | ServiceMonitor relabel configs to apply to samples before scraping | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | ServiceMonitor metricRelabelings configs to apply to samples before ingestion | `[]` | +| `metrics.serviceMonitor.namespaceSelector` | ServiceMonitor namespace selector | `{}` | + +### Valkey Sentinel Configuration + +Sentinel provides high availability for Valkey replication. When enabled, Sentinel monitors the master and automatically promotes a replica to master if the master fails. + +| Parameter | Description | Default | +| ----------------------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| `sentinel.enabled` | Enable Valkey Sentinel for high availability | `false` | +| `sentinel.image.repository` | Valkey Sentinel image repository | `valkey/valkey` | +| `sentinel.image.tag` | Valkey Sentinel image tag | `"9.0.0-alpine3.22@sha256:b4ee67d73e00393e712accc72cfd7003b87d0fcd63f0eba798b23251bfc9c394"` | +| `sentinel.image.pullPolicy` | Valkey Sentinel image pull policy | `Always` | +| `sentinel.masterName` | Name of the master server | `mymaster` | +| `sentinel.quorum` | Number of Sentinels that need to agree about the fact the master is not reachable | `2` | +| `sentinel.downAfterMilliseconds` | Time in milliseconds after the master is declared down | `1500` | +| `sentinel.failoverTimeout` | Timeout for failover in milliseconds | `15000` | +| `sentinel.parallelSyncs` | Number of replicas that can be reconfigured to use the new master during a failover | `1` | +| `sentinel.port` | Sentinel port | `26379` | +| `sentinel.extraVolumeMounts` | Additional volume mounts to add to the Sentinel container | `[]` | +| `sentinel.service.type` | Kubernetes service type for Sentinel | `ClusterIP` | +| `sentinel.service.port` | Sentinel service port | `26379` | +| `sentinel.resources.limits.memory` | Memory limit for Sentinel container | `128Mi` | +| `sentinel.resources.limits.cpu` | CPU limit for Sentinel container | Not set | +| `sentinel.resources.requests.cpu` | CPU request for Sentinel container | `25m` | +| `sentinel.resources.requests.memory`| Memory request for Sentinel container | `64Mi` | + +### Init Container Configuration + +| Parameter | Description | Default | +| ------------------------------------- | ------------------------------------------- | -------- | +| `initContainer.resources.limits.cpu` | CPU limit for init container | `50m` | +| `initContainer.resources.limits.memory` | Memory limit for init container | `128Mi` | +| `initContainer.resources.requests.cpu` | CPU request for init container | `25m` | +| `initContainer.resources.requests.memory`| Memory request for init container | `64Mi` | + ### Additional Configuration | Parameter | Description | Default | | -------------- | ----------------------------------------------------------------------- | ------- | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraObjects` | A list of additional Kubernetes objects to deploy alongside the release | `[]` | #### Extra Objects @@ -309,10 +370,105 @@ Deploy with production values: helm install my-valkey ./charts/valkey -f values-production.yaml ``` -### High Availability Configuration +### High Availability Configuration with Sentinel + +Deploy Valkey with Sentinel for automatic failover: + +```yaml +# values-ha-sentinel.yaml +# Enable replication architecture +architecture: replication + +# Deploy 3 Valkey instances (1 master + 2 replicas) +replicaCount: 3 + +# Enable Sentinel for automatic failover +sentinel: + enabled: true + masterName: mymaster + quorum: 2 + downAfterMilliseconds: 1500 + failoverTimeout: 15000 + parallelSyncs: 1 + resources: + limits: + memory: 128Mi + requests: + cpu: 25m + memory: 64Mi + +# Enable authentication +auth: + enabled: true + password: "your-secure-password" + +# Configure persistence +persistence: + enabled: true + size: 10Gi + storageClass: "fast-ssd" + +# Resource allocation for Valkey +resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + +# Init container resources +initContainer: + resources: + limits: + cpu: 50m + memory: 128Mi + requests: + cpu: 25m + memory: 64Mi + +# Spread pods across nodes for better availability +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - valkey + topologyKey: kubernetes.io/hostname +``` + +Deploy with Sentinel HA: + +```bash +helm install my-valkey ./charts/valkey -f values-ha-sentinel.yaml +``` + +**Connecting to Sentinel-enabled Valkey:** + +When Sentinel is enabled, your application should use a Sentinel-aware client to automatically discover the current master. The Sentinel service provides endpoints for querying the master: + +```bash +# Get the current master from Sentinel +kubectl run -it --rm valkey-client --image=valkey/valkey:9.0.0-alpine3.22 --restart=Never -- sh +valkey-cli -h my-valkey-sentinel -p 26379 SENTINEL get-master-addr-by-name mymaster +``` + +Connection URLs for Sentinel-aware clients: +- Sentinel endpoints: `my-valkey-sentinel:26379` +- Master name: `mymaster` (or your configured `sentinel.masterName`) + +### High Availability Configuration without Sentinel + +Deploy multiple replicas without Sentinel (pod-0 is always master): ```yaml -# values-ha.yaml +# values-ha-replication.yaml +architecture: replication replicaCount: 3 affinity: @@ -368,15 +524,42 @@ config: - "databases 16" ``` +### Monitoring with Prometheus + +Enable metrics collection with Prometheus: + +```yaml +# values-monitoring.yaml +metrics: + enabled: true + serviceMonitor: + enabled: true +``` + +Deploy with monitoring enabled: + +```bash +helm install my-valkey ./charts/valkey -f values-monitoring.yaml +``` + +You can access metrics directly via port-forward: + +```bash +kubectl port-forward service/my-valkey-metrics 9121:9121 +curl http://localhost:9121/metrics +``` + ## Access Valkey -### Via kubectl port-forward +### Standalone or Replication (without Sentinel) + +#### Via kubectl port-forward ```bash kubectl port-forward service/my-valkey 6379:6379 ``` -### Connect using valkey-cli +#### Connect using valkey-cli ```bash # Without authentication @@ -386,6 +569,37 @@ valkey-cli -h localhost -p 6379 valkey-cli -h localhost -p 6379 -a your-password ``` +### With Sentinel Enabled + +When Sentinel is enabled, three services are created: + +1. **my-valkey-sentinel** (port 26379): Sentinel service for querying master/replica information +2. **my-valkey-master** (port 6379): Points to the current master (headless service) +3. **my-valkey** (port 6379): Headless service for all Valkey instances + +#### Connect to Sentinel + +```bash +# Port-forward to Sentinel +kubectl port-forward service/my-valkey-sentinel 26379:26379 + +# Query master information +valkey-cli -h localhost -p 26379 SENTINEL get-master-addr-by-name mymaster + +# List all replicas +valkey-cli -h localhost -p 26379 SENTINEL replicas mymaster +``` + +#### Connect to current master + +```bash +# Port-forward to master service +kubectl port-forward service/my-valkey-master 6379:6379 + +# Connect with valkey-cli +valkey-cli -h localhost -p 6379 -a your-password +``` + ### Default Credentials - **Password**: Auto-generated (check secret) or configured value @@ -422,6 +636,13 @@ kubectl get secret my-valkey -o jsonpath="{.data.password}" | base64 --decode - Monitor memory usage with `valkey-cli info memory` - Adjust memory eviction policy if needed +5. **Sentinel failover issues** + - Ensure `sentinel.quorum` is properly configured (typically `floor(replicas/2) + 1`) + - Check Sentinel logs: `kubectl logs -c sentinel` + - Verify all Sentinels can communicate with each other + - Check if Sentinel can reach all Valkey instances + - Review Sentinel configuration: `valkey-cli -h -p 26379 SENTINEL master mymaster` + ### Getting Support For issues related to this Helm chart, please check: diff --git a/charts/valkey/templates/_helpers.tpl b/charts/valkey/templates/_helpers.tpl index 35c6c1cc..bd2ae844 100644 --- a/charts/valkey/templates/_helpers.tpl +++ b/charts/valkey/templates/_helpers.tpl @@ -2,7 +2,7 @@ Expand the name of the chart. */}} {{- define "valkey.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* @@ -11,21 +11,21 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "valkey.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "valkey.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "valkey.labels" -}} -{{- include "common.labels" . -}} +{{- include "cloudpirates.labels" . -}} {{- end }} {{/* @@ -41,14 +41,14 @@ Common annotations Selector labels */}} {{- define "valkey.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Return the proper Valkey image name */}} {{- define "valkey.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* @@ -56,7 +56,7 @@ Return Valkey credentials secret name */}} {{- define "valkey.secretName" -}} {{- if .Values.auth.existingSecret -}} - {{- .Values.auth.existingSecret -}} + {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) -}} {{- else -}} {{- include "valkey.fullname" . -}} {{- end -}} @@ -113,5 +113,19 @@ Return Valkey config directory Return the proper Docker Image Registry Secret Names */}} {{- define "valkey.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} + +{{/* +Return the proper Valkey Sentinel image name +*/}} +{{- define "valkey.sentinel.image" -}} +{{- include "cloudpirates.image" (dict "image" .Values.sentinel.image "global" .Values.global) -}} +{{- end }} + +{{/* +Return Valkey config full path name +*/}} +{{- define "valkey.configFullName" -}} +{{- printf "%s/valkey.conf" (include "valkey.configDir" .) -}} +{{- end }} diff --git a/charts/valkey/templates/configmap.yaml b/charts/valkey/templates/configmap.yaml index 587e4161..29a3fd23 100644 --- a/charts/valkey/templates/configmap.yaml +++ b/charts/valkey/templates/configmap.yaml @@ -16,7 +16,21 @@ data: # Network bind 0.0.0.0 + {{- if .Values.tls.enabled }} + port 0 + tls-port {{ .Values.tls.port }} + tls-cert-file /etc/valkey/tls/{{ .Values.tls.certFilename }} + tls-key-file /etc/valkey/tls/{{ .Values.tls.certKeyFilename }} + tls-ca-cert-file /etc/valkey/tls/{{ .Values.tls.certCAFilename }} + {{- if .Values.tls.authClients }} + tls-auth-clients yes + {{- else }} + tls-auth-clients no + {{- end }} + tls-replication yes + {{- else }} port {{ .Values.service.targetPort }} + {{- end }} # General daemonize no diff --git a/charts/valkey/templates/extraobjects.yaml b/charts/valkey/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/valkey/templates/extraobjects.yaml +++ b/charts/valkey/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/valkey/templates/master-service.yaml b/charts/valkey/templates/master-service.yaml new file mode 100644 index 00000000..0e775874 --- /dev/null +++ b/charts/valkey/templates/master-service.yaml @@ -0,0 +1,25 @@ +{{- if and (eq .Values.architecture "replication") (not .Values.sentinel.enabled) }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "valkey.fullname" . }}-master + namespace: {{ .Release.Namespace }} + labels: + {{- include "valkey.labels" . | nindent 4 }} + app.kubernetes.io/component: master + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: valkey + protocol: TCP + name: valkey + selector: + {{- include "valkey.selectorLabels" . | nindent 4 }} + statefulset.kubernetes.io/pod-name: {{ include "valkey.fullname" . }}-0 +{{- end }} diff --git a/charts/valkey/templates/prestop-configmap.yaml b/charts/valkey/templates/prestop-configmap.yaml new file mode 100644 index 00000000..47fe259a --- /dev/null +++ b/charts/valkey/templates/prestop-configmap.yaml @@ -0,0 +1,134 @@ +{{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "valkey.fullname" . }}-prestop-script + namespace: {{ .Release.Namespace }} + labels: + {{- include "valkey.labels" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: + {{- include "valkey.annotations" . | nindent 4 }} + {{- end }} +data: + prestop.sh: | + #!/bin/bash + + # Valkey master failover script for graceful shutdown + # Based on Redis/Bitnami charts failover handling + + set -e + + # Configuration + VALKEY_PORT="{{ .Values.service.port }}" + SENTINEL_PORT="{{ .Values.sentinel.port }}" + MASTER_NAME="{{ .Values.sentinel.masterName }}" + HEADLESS_SERVICE="{{ include "valkey.fullname" . }}-headless.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}" + VALKEY_SERVICE="{{ include "valkey.fullname" . }}.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}" + + # Set authentication if enabled + {{- if .Values.auth.enabled }} + export REDISCLI_AUTH="${VALKEY_PASSWORD}" + {{- end }} + + # Set loopback address based on ipFamily configuration + {{- if eq .Values.ipFamily "ipv6" }} + VALKEY_LOOPBACK="::1" + {{- else }} + VALKEY_LOOPBACK="127.0.0.1" + {{- end }} + + # Function to run Valkey commands + run_valkey_command() { + local args=("-h" "$VALKEY_LOOPBACK" "-p" "$VALKEY_PORT") + valkey-cli "${args[@]}" "$@" + } + + # Function to check if current instance is master + is_master() { + VALKEY_ROLE=$(run_valkey_command role | head -1) + [[ "$VALKEY_ROLE" == "master" ]] + } + + # Function to get full hostname for a pod + get_full_hostname() { + hostname="$1" + full_hostname="${hostname}.${HEADLESS_SERVICE}" + echo "${full_hostname}" + } + + # Function to run Sentinel commands + run_sentinel_command() { + valkey-cli -h "$VALKEY_SERVICE" -p "$SENTINEL_PORT" {{- if .Values.auth.enabled }} -a "${VALKEY_PASSWORD}"{{- end }} sentinel "$@" + } + + # Function to check if sentinel failover has finished + sentinel_failover_finished() { + VALKEY_SENTINEL_INFO=($(run_sentinel_command get-master-addr-by-name "$MASTER_NAME" 2>/dev/null || echo "")) + if [ ${#VALKEY_SENTINEL_INFO[@]} -ge 1 ]; then + VALKEY_MASTER_HOST="${VALKEY_SENTINEL_INFO[0]}" + [[ "$VALKEY_MASTER_HOST" != "$(get_full_hostname $HOSTNAME)" ]] + else + # If we can't get master info, assume failover is complete + return 0 + fi + } + + # Function to wait with retries + retry_while() { + local condition="$1" + local max_attempts="$2" + local sleep_time="$3" + local attempt=0 + + while [ $attempt -lt $max_attempts ]; do + if $condition; then + return 0 + fi + sleep "$sleep_time" + ((attempt++)) + done + return 1 + } + + echo "Valkey preStop hook starting for pod: $HOSTNAME" + + # Only proceed with failover if this instance is the master + if is_master; then + echo "I am the master pod and I'm being stopped. Initiating graceful failover." + + # Pause client write connections to prevent data loss during failover + echo "Pausing client write connections for 22 seconds to prevent data loss..." + if run_valkey_command CLIENT PAUSE "22000" WRITE; then + echo "Client write connections paused successfully" + else + echo "Warning: Failed to pause client connections, continuing anyway" + fi + + # Issue failover command to Sentinel + echo "Issuing failover command to Sentinel..." + if run_sentinel_command failover "$MASTER_NAME"; then + echo "Failover command sent successfully" + else + echo "Warning: Failed to send failover command, Sentinel may handle this automatically" + fi + + # Wait for Sentinel to complete the failover + echo "Waiting for Sentinel to complete failover (up to 20 seconds)..." + if retry_while "sentinel_failover_finished" "20" "1"; then + echo "Sentinel failover completed successfully" + else + echo "Warning: Failover may still be in progress or Sentinel unavailable" + fi + + # Additional delay to ensure new master is fully established + echo "Allowing additional time for new master to stabilize..." + sleep 3 + + else + echo "I am not the master, no failover needed" + fi + + echo "Valkey preStop hook completed" + exit 0 +{{- end }} diff --git a/charts/valkey/templates/sentinel-service.yaml b/charts/valkey/templates/sentinel-service.yaml new file mode 100644 index 00000000..d34af85a --- /dev/null +++ b/charts/valkey/templates/sentinel-service.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "valkey.fullname" . }}-sentinel + namespace: {{ .Release.Namespace }} + labels: + {{- include "valkey.labels" . | nindent 4 }} + app.kubernetes.io/component: sentinel + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.sentinel.service.type }} + ports: + - port: {{ .Values.sentinel.service.port }} + targetPort: sentinel + protocol: TCP + name: sentinel + selector: + {{- include "valkey.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/valkey/templates/service-metrics.yaml b/charts/valkey/templates/service-metrics.yaml new file mode 100644 index 00000000..0ef85989 --- /dev/null +++ b/charts/valkey/templates/service-metrics.yaml @@ -0,0 +1,27 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "valkey.fullname" . }}-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- include "valkey.labels" . | nindent 4 }} + app.kubernetes.io/component: metrics + {{- with .Values.metrics.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- $annotations := merge .Values.metrics.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: ClusterIP + ports: + - name: metrics + port: {{ .Values.metrics.service.port }} + protocol: TCP + targetPort: metrics + selector: + {{- include "valkey.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/valkey/templates/service.yaml b/charts/valkey/templates/service.yaml index 7d9c7639..ed3437dc 100644 --- a/charts/valkey/templates/service.yaml +++ b/charts/valkey/templates/service.yaml @@ -13,8 +13,8 @@ metadata: spec: type: {{ .Values.service.type }} ports: - - port: {{ .Values.service.port }} - targetPort: {{ .Values.service.targetPort }} + - port: {{ if .Values.tls.enabled }}{{ .Values.tls.port }}{{ else }}{{ .Values.service.port }}{{ end }} + targetPort: {{ if .Values.tls.enabled }}{{ .Values.tls.port }}{{ else }}{{ .Values.service.targetPort }}{{ end }} protocol: TCP name: valkey selector: @@ -36,9 +36,15 @@ spec: type: ClusterIP clusterIP: None ports: - - port: {{ .Values.service.port }} - targetPort: {{ .Values.service.targetPort }} + - port: {{ if .Values.tls.enabled }}{{ .Values.tls.port }}{{ else }}{{ .Values.service.port }}{{ end }} + targetPort: {{ if .Values.tls.enabled }}{{ .Values.tls.port }}{{ else }}{{ .Values.service.targetPort }}{{ end }} protocol: TCP name: valkey + {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + - port: {{ .Values.sentinel.port }} + targetPort: sentinel + protocol: TCP + name: sentinel + {{- end }} selector: {{- include "valkey.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/valkey/templates/servicemonitor.yaml b/charts/valkey/templates/servicemonitor.yaml new file mode 100644 index 00000000..98fe4f8c --- /dev/null +++ b/charts/valkey/templates/servicemonitor.yaml @@ -0,0 +1,52 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "valkey.fullname" . }}-metrics + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} + labels: + {{- include "valkey.labels" . | nindent 4 }} + app.kubernetes.io/component: metrics + {{- with .Values.metrics.serviceMonitor.selector }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- $annotations := merge .Values.metrics.serviceMonitor.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ include "valkey.fullname" . }} + selector: + matchLabels: + {{- include "valkey.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics + {{- with .Values.metrics.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + path: /metrics + {{- with .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ . }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.namespaceSelector }} + namespaceSelector: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/valkey/templates/statefulset.yaml b/charts/valkey/templates/statefulset.yaml index 34e49498..d6f6c08e 100644 --- a/charts/valkey/templates/statefulset.yaml +++ b/charts/valkey/templates/statefulset.yaml @@ -10,123 +10,525 @@ metadata: {{- include "valkey.annotations" . | nindent 4 }} {{- end }} spec: - replicas: {{ .Values.replicaCount }} + replicas: {{ if eq .Values.architecture "standalone" }}1{{ else }}{{ .Values.replicaCount }}{{ end }} serviceName: {{ include "valkey.fullname" . }}-headless selector: matchLabels: {{- include "valkey.selectorLabels" . | nindent 6 }} template: metadata: + labels: + {{- include "valkey.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or (include "valkey.annotations" .) .Values.podAnnotations }} annotations: {{- include "valkey.annotations" . | nindent 8 }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} - labels: - {{- include "valkey.labels" . | nindent 8 }} - {{- with .Values.podLabels }} - {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} spec: {{- with (include "valkey.imagePullSecrets" .) }} {{ . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} serviceAccountName: {{ include "valkey.serviceAccountName" . }} - containers: - - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + {{- if eq .Values.architecture "replication" }} + initContainers: + - name: valkey-init image: {{ include "valkey.image" . }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} imagePullPolicy: {{ .Values.image.imagePullPolicy }} command: - /bin/sh - -c - - valkey-server /etc/valkey/valkey.conf --requirepass "${VALKEY_PASSWORD}" + - | + set -e + # Get pod ordinal from hostname + POD_ORDINAL=$(hostname | sed 's/.*-//') + MY_HOSTNAME=$(hostname) + + # Create config file + touch /tmp/valkey/valkey.conf + + echo "Pod ordinal: $POD_ORDINAL, hostname: $MY_HOSTNAME" + + {{- if .Values.sentinel.enabled }} + # Add Valkey configurations for better Sentinel failover tolerance + echo "" >> /tmp/valkey/valkey.conf + echo "# Configurations for Kubernetes force deletion tolerance" >> /tmp/valkey/valkey.conf + echo "min-slaves-to-write 0" >> /tmp/valkey/valkey.conf + echo "min-slaves-max-lag 0" >> /tmp/valkey/valkey.conf + + # Try to determine current master from Sentinel (if any sentinel is available) + CURRENT_MASTER="" + SENTINEL_FOUND=false + + # Check if any sentinel is already running and knows the master + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do + SENTINEL_HOST="{{ include "valkey.fullname" . }}-${i}.{{ include "valkey.fullname" . }}-headless" + MASTER_INFO=$(valkey-cli -h "${SENTINEL_HOST}" -p {{ .Values.sentinel.port }} {{- if .Values.auth.enabled }} -a "${VALKEY_PASSWORD}"{{- end }} sentinel get-master-addr-by-name {{ .Values.sentinel.masterName }} 2>/dev/null | head -1 || echo "") + if [ -n "$MASTER_INFO" ] && [ "$MASTER_INFO" != "Could not connect" ]; then + CURRENT_MASTER="$MASTER_INFO" + SENTINEL_FOUND=true + echo "Found current master from sentinel: $CURRENT_MASTER" + break + fi + done + + # Configuration logic + if [ "$SENTINEL_FOUND" = true ] && [ -n "$CURRENT_MASTER" ]; then + # Sentinel knows the master - configure accordingly + MY_HOSTNAME=$(hostname) + MY_HOSTNAME_FQDN="${MY_HOSTNAME}.{{ include "valkey.fullname" . }}-headless" + MY_IP=$(hostname -i) + + # Check if I am the master by hostname or IP + if [ "$MY_IP" = "$CURRENT_MASTER" ] || [ "$MY_HOSTNAME_FQDN" = "$CURRENT_MASTER" ] || [ "$MY_HOSTNAME" = "$CURRENT_MASTER" ]; then + echo "I am the current master according to Sentinel" + else + echo "Configuring as replica of current master: $CURRENT_MASTER" + echo "replicaof $CURRENT_MASTER {{ .Values.service.port }}" >> /tmp/valkey/valkey.conf + {{- if .Values.auth.enabled }} + echo "masterauth ${VALKEY_PASSWORD}" >> /tmp/valkey/valkey.conf + {{- end }} + fi + else + # No sentinel available - use bootstrap logic + if [ "$POD_ORDINAL" != "0" ]; then + echo "Bootstrap mode: configuring as replica of pod-0" + # Use hostname-based replication for better resilience + MASTER_HOSTNAME="{{ include "valkey.fullname" . }}-0.{{ include "valkey.fullname" . }}-headless" + echo "replicaof $MASTER_HOSTNAME {{ .Values.service.port }}" >> /tmp/valkey/valkey.conf + echo "Bootstrap replica using pod-0 hostname: $MASTER_HOSTNAME" + {{- if .Values.auth.enabled }} + echo "masterauth ${VALKEY_PASSWORD}" >> /tmp/valkey/valkey.conf + {{- end }} + else + echo "Bootstrap mode: pod-0 starting as initial master" + fi + fi + + # Configure for Sentinel discovery and force deletion tolerance + # Get IP address based on ipFamily setting + {{- if eq .Values.ipFamily "ipv4" }} + MY_IP=$(hostname -i | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) + if [ -z "$MY_IP" ]; then + echo "Warning: No IPv4 address found, falling back to first available IP" + MY_IP=$(hostname -i | awk '{print $1}') + fi + {{- else if eq .Values.ipFamily "ipv6" }} + MY_IP=$(hostname -i | grep -oE '([0-9a-f:]+:+)+[0-9a-f]+' | head -1) + if [ -z "$MY_IP" ]; then + echo "Warning: No IPv6 address found, falling back to first available IP" + MY_IP=$(hostname -i | awk '{print $1}') + fi + {{- else }} + # auto: Use the first IP address for dual-stack compatibility + MY_IP=$(hostname -i | awk '{print $1}') + {{- end }} + echo "Using IP address: ${MY_IP}" + echo "replica-announce-ip ${MY_IP}" >> /tmp/valkey/valkey.conf + echo "replica-announce-port {{ .Values.service.port }}" >> /tmp/valkey/valkey.conf + echo "slave-announce-ip ${MY_IP}" >> /tmp/valkey/valkey.conf + echo "slave-announce-port {{ .Values.service.port }}" >> /tmp/valkey/valkey.conf + + # Make slaves more eligible for promotion during force deletions + echo "slave-priority 100" >> /tmp/valkey/valkey.conf + echo "replica-read-only yes" >> /tmp/valkey/valkey.conf + {{- else }} + # Replication without Sentinel: pod-0 is always master, others are replicas + if [ "$POD_ORDINAL" != "0" ]; then + echo "Configuring as replica of pod-0 (master)" + MASTER_HOSTNAME="{{ include "valkey.fullname" . }}-0.{{ include "valkey.fullname" . }}-headless" + echo "replicaof $MASTER_HOSTNAME {{ .Values.service.port }}" >> /tmp/valkey/valkey.conf + {{- if .Values.auth.enabled }} + echo "masterauth ${VALKEY_PASSWORD}" >> /tmp/valkey/valkey.conf + {{- end }} + echo "replica-read-only yes" >> /tmp/valkey/valkey.conf + else + echo "Pod-0: Configuring as master" + fi + {{- end }} + + # Add user provided settings at the end of file to ensure their precedence + echo "" >> /tmp/valkey/valkey.conf + # If there is existing config map or .Values.config value provided - use it + if [ -f "{{ include "valkey.configFullName" . }}" ]; then + echo "# Content from provided config" >> /tmp/valkey/valkey.conf + cat {{ include "valkey.configFullName" . }} >> /tmp/valkey/valkey.conf + else + # Create minimal config if no config exists + echo "# Default minimal config" >> /tmp/valkey/valkey.conf + cat >> /tmp/valkey/valkey.conf << EOF + bind 0.0.0.0 + port {{ .Values.service.port }} + EOF + fi + {{- if .Values.auth.enabled }} env: - {{- if .Values.auth.enabled }} - name: VALKEY_PASSWORD valueFrom: secretKeyRef: name: {{ include "valkey.secretName" . }} key: {{ include "valkey.passwordKey" . }} + {{- end }} + resources: {{- toYaml .Values.initContainer.resources | nindent 12 }} + volumeMounts: + {{- if or .Values.config.content .Values.config.existingConfigmap }} + - name: config + mountPath: {{ .Values.config.mountPath }} {{- end }} + - name: valkey-config + mountPath: /tmp/valkey + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + image: {{ include "valkey.image" . }} + imagePullPolicy: {{ .Values.image.imagePullPolicy }} + command: + - /bin/sh + - -c + - | + {{- if eq .Values.architecture "replication" }} + CONFIG_FILE="/tmp/valkey/valkey.conf" + {{- else }} + CONFIG_FILE="{{ include "valkey.configFullName" . }}" + {{- end }} + + valkey-server "$CONFIG_FILE" {{- if .Values.auth.enabled }} --requirepass "${VALKEY_PASSWORD}" {{- end }} ports: - name: valkey - containerPort: {{ .Values.service.targetPort }} + containerPort: {{ if .Values.tls.enabled }}{{ .Values.tls.port }}{{ else }}{{ .Values.service.targetPort }}{{ end }} protocol: TCP + env: + {{- if .Values.auth.enabled }} + - name: VALKEY_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "valkey.secretName" . }} + key: {{ include "valkey.passwordKey" . }} + - name: REDISCLI_AUTH + valueFrom: + secretKeyRef: + name: {{ include "valkey.secretName" . }} + key: {{ include "valkey.passwordKey" . }} + {{- end }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} + {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: exec: command: - - sh + - /bin/sh - -c - - | - {{- if .Values.auth.enabled }} - valkey-cli -a "${VALKEY_PASSWORD}" ping - {{- else }} - valkey-cli ping - {{- end }} + - valkey-cli -h {{ if eq .Values.ipFamily "ipv6" }}"::1"{{ else }}"127.0.0.1"{{ end }}{{- if .Values.tls.enabled }} -p {{ .Values.tls.port }} --tls --cert /etc/valkey/tls/{{ .Values.tls.certFilename }} --key /etc/valkey/tls/{{ .Values.tls.certKeyFilename }} --cacert /etc/valkey/tls/{{ .Values.tls.certCAFilename }}{{- end }} ping initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} {{- end }} {{- if .Values.readinessProbe.enabled }} readinessProbe: exec: command: - - sh + - /bin/sh - -c - - | - {{- if .Values.auth.enabled }} - valkey-cli -a "${VALKEY_PASSWORD}" ping - {{- else }} - valkey-cli ping - {{- end }} + - valkey-cli -h {{ if eq .Values.ipFamily "ipv6" }}"::1"{{ else }}"127.0.0.1"{{ end }}{{- if .Values.tls.enabled }} -p {{ .Values.tls.port }} --tls --cert /etc/valkey/tls/{{ .Values.tls.certFilename }} --key /etc/valkey/tls/{{ .Values.tls.certKeyFilename }} --cacert /etc/valkey/tls/{{ .Values.tls.certCAFilename }}{{- end }} ping {{ if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} | grep -q PONG{{ end }} initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} {{- end }} {{- if .Values.startupProbe.enabled }} startupProbe: exec: command: - - sh + - /bin/sh - -c - - | - {{- if .Values.auth.enabled }} - valkey-cli -a "${VALKEY_PASSWORD}" ping - {{- else }} - valkey-cli ping - {{- end }} + - valkey-cli -h {{ if eq .Values.ipFamily "ipv6" }}"::1"{{ else }}"127.0.0.1"{{ end }}{{- if .Values.tls.enabled }} -p {{ .Values.tls.port }} --tls --cert /etc/valkey/tls/{{ .Values.tls.certFilename }} --key /etc/valkey/tls/{{ .Values.tls.certKeyFilename }} --cacert /etc/valkey/tls/{{ .Values.tls.certCAFilename }}{{- end }} ping initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} periodSeconds: {{ .Values.startupProbe.periodSeconds }} timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} - successThreshold: {{ .Values.startupProbe.successThreshold }} failureThreshold: {{ .Values.startupProbe.failureThreshold }} + successThreshold: {{ .Values.startupProbe.successThreshold }} + {{- end }} + {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + lifecycle: + preStop: + exec: + command: + - /bin/bash + - /scripts/prestop.sh {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: - name: data mountPath: {{ include "valkey.dataDir" . }} + {{- if eq .Values.architecture "replication" }} + - name: valkey-config + mountPath: /tmp/valkey + {{- if .Values.sentinel.enabled }} + - name: prestop-script + mountPath: /scripts + readOnly: true + {{- end }} + {{- else }} - name: config mountPath: {{ include "valkey.configDir" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: tls-certs + mountPath: /etc/valkey/tls + readOnly: true + {{- end }} - name: tmp mountPath: /tmp + {{- if and .Values.sentinel.enabled (eq .Values.architecture "replication") }} + - name: sentinel + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} + image: {{ include "valkey.sentinel.image" . }} + imagePullPolicy: {{ .Values.sentinel.image.pullPolicy }} + volumeMounts: + - name: sentinel-config + mountPath: /tmp + {{- if .Values.sentinel.extraVolumeMounts }} + {{- toYaml .Values.sentinel.extraVolumeMounts | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -c + - | + set -e + + # Wait for Valkey to be ready + echo "Waiting for Valkey to start..." + {{- if eq .Values.ipFamily "ipv6" }} + VALKEY_HOST="::1" + {{- else }} + VALKEY_HOST="127.0.0.1" + {{- end }} + while ! valkey-cli {{- if .Values.auth.enabled }} -a "${VALKEY_PASSWORD}"{{- end }} -h "${VALKEY_HOST}" -p {{ .Values.service.port }} ping >/dev/null 2>&1; do + sleep 1 + done + echo "Valkey is ready" + + # Determine initial master: query existing Sentinels first, fallback to pod-0 only for bootstrap + POD_ORDINAL=$(hostname | sed 's/.*-//') + MASTER_HOST="" + SENTINEL_FOUND_MASTER=false + + # First priority: Try to query other sentinels to find the current master + echo "Checking existing Sentinels for current master..." + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do + if [ "$i" != "$POD_ORDINAL" ]; then + SENTINEL_HOST="{{ include "valkey.fullname" . }}-${i}.{{ include "valkey.fullname" . }}-headless" + EXISTING_MASTER=$(valkey-cli -h "${SENTINEL_HOST}" -p {{ .Values.sentinel.port }} {{- if .Values.auth.enabled }} -a "${VALKEY_PASSWORD}"{{- end }} sentinel get-master-addr-by-name {{ .Values.sentinel.masterName }} 2>/dev/null | head -1 || echo "") + if [ -n "$EXISTING_MASTER" ] && [ "$EXISTING_MASTER" != "Could not connect" ]; then + MASTER_HOST="$EXISTING_MASTER" + SENTINEL_FOUND_MASTER=true + echo "Found current master via sentinel: $MASTER_HOST" + break + fi + fi + done + + # Second priority: If no Sentinels found master, check if any Valkey instance claims to be master + if [ "$SENTINEL_FOUND_MASTER" = false ]; then + echo "No Sentinels available, checking Valkey instances directly..." + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do + VALKEY_HOST="{{ include "valkey.fullname" . }}-${i}.{{ include "valkey.fullname" . }}-headless.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}" + ROLE_INFO=$(valkey-cli -h "${VALKEY_HOST}" -p {{ .Values.service.port }} {{- if .Values.auth.enabled }} -a "${VALKEY_PASSWORD}"{{- end }} info replication 2>/dev/null | grep "role:master" || echo "") + if [ -n "$ROLE_INFO" ]; then + MASTER_HOST="$VALKEY_HOST" + echo "Found current master by role check: $MASTER_HOST" + break + fi + done + fi + + # Final fallback: Use pod-0 hostname for initial bootstrap only + if [ -z "$MASTER_HOST" ]; then + MASTER_HOST="{{ include "valkey.fullname" . }}-0.{{ include "valkey.fullname" . }}-headless.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}" + echo "No existing master found, using pod-0 for initial bootstrap: $MASTER_HOST" + fi + + # Get IP address based on ipFamily setting + {{- if eq .Values.ipFamily "ipv4" }} + SENTINEL_IP=$(hostname -i | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) + if [ -z "$SENTINEL_IP" ]; then + echo "Warning: No IPv4 address found, falling back to first available IP" + SENTINEL_IP=$(hostname -i | awk '{print $1}') + fi + {{- else if eq .Values.ipFamily "ipv6" }} + SENTINEL_IP=$(hostname -i | grep -oE '([0-9a-f:]+:+)+[0-9a-f]+' | head -1) + if [ -z "$SENTINEL_IP" ]; then + echo "Warning: No IPv6 address found, falling back to first available IP" + SENTINEL_IP=$(hostname -i | awk '{print $1}') + fi + {{- else }} + # auto: Use the first IP address for dual-stack compatibility + SENTINEL_IP=$(hostname -i | awk '{print $1}') + {{- end }} + echo "Sentinel using IP address: ${SENTINEL_IP}" + + # Create Sentinel config + cat > /tmp/sentinel.conf << EOF + port {{ .Values.sentinel.port }} + bind * -::* + # Enable hostname resolution for Valkey Sentinel + sentinel resolve-hostnames yes + sentinel announce-hostnames yes + sentinel monitor {{ .Values.sentinel.masterName }} ${MASTER_HOST} {{ .Values.service.port }} {{ .Values.sentinel.quorum }} + sentinel down-after-milliseconds {{ .Values.sentinel.masterName }} {{ .Values.sentinel.downAfterMilliseconds }} + sentinel failover-timeout {{ .Values.sentinel.masterName }} {{ .Values.sentinel.failoverTimeout }} + sentinel parallel-syncs {{ .Values.sentinel.masterName }} {{ .Values.sentinel.parallelSyncs }} + {{- if .Values.auth.enabled }} + sentinel auth-pass {{ .Values.sentinel.masterName }} "${VALKEY_PASSWORD}" + requirepass "${VALKEY_PASSWORD}" + {{- end }} + # Make automatic failover more aggressive for Kubernetes force deletions + sentinel deny-scripts-reconfig yes + # Fix leader election issues during force deletions + protected-mode no + # Allow sentinels to discover each other + sentinel announce-ip ${SENTINEL_IP} + sentinel announce-port {{ .Values.sentinel.port }} + logfile "" + loglevel notice + EOF + + # Add known sentinels to help with discovery (using hostnames for resilience) + for i in $(seq 0 {{ sub .Values.replicaCount 1 }}); do + if [ "$i" != "$POD_ORDINAL" ]; then + SENTINEL_HOST="{{ include "valkey.fullname" . }}-${i}.{{ include "valkey.fullname" . }}-headless" + # Test if the host is resolvable before adding + if getent hosts "$SENTINEL_HOST" >/dev/null 2>&1; then + SENTINEL_IP=$(getent hosts "$SENTINEL_HOST" | awk '{print $1}' | head -1) + if [ -n "$SENTINEL_IP" ]; then + echo "sentinel known-sentinel {{ .Values.sentinel.masterName }} ${SENTINEL_IP} {{ .Values.sentinel.port }}" >> /tmp/sentinel.conf + fi + fi + fi + done + + echo "Starting Sentinel with config:" + cat /tmp/sentinel.conf + + valkey-sentinel /tmp/sentinel.conf + ports: + - name: sentinel + containerPort: {{ .Values.sentinel.port }} + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + {{- if eq .Values.ipFamily "ipv6" }} + - valkey-cli -h "::1" -p {{ .Values.sentinel.port }} {{- if .Values.auth.enabled }} -a "${VALKEY_PASSWORD}"{{- end }} ping | grep -q PONG + {{- else }} + - valkey-cli -h "127.0.0.1" -p {{ .Values.sentinel.port }} {{- if .Values.auth.enabled }} -a "${VALKEY_PASSWORD}"{{- end }} ping | grep -q PONG + {{- end }} + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + successThreshold: 1 + {{- if .Values.auth.enabled }} + env: + - name: VALKEY_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "valkey.secretName" . }} + key: {{ include "valkey.passwordKey" . }} + {{- end }} + resources: {{- toYaml .Values.sentinel.resources | nindent 12 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: "{{ .Values.metrics.image.registry }}/{{ .Values.metrics.image.repository }}:{{ .Values.metrics.image.tag }}" + imagePullPolicy: {{ .Values.metrics.image.pullPolicy }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 65534 + runAsGroup: 65534 + env: + {{- if .Values.auth.enabled }} + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "valkey.secretName" . }} + key: {{ include "valkey.passwordKey" . }} + {{- end }} + ports: + - name: metrics + containerPort: 9121 + protocol: TCP + startupProbe: + httpGet: + path: / + port: metrics + readinessProbe: + httpGet: + path: / + port: metrics + livenessProbe: + httpGet: + path: / + port: metrics + {{- with .Values.metrics.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} volumes: + {{- if not .Values.persistence.enabled }} + - name: data + emptyDir: {} + {{- end }} + {{- if eq .Values.architecture "replication" }} + - name: valkey-config + emptyDir: {} + {{- if .Values.sentinel.enabled }} + - name: sentinel-config + emptyDir: {} + - name: prestop-script + configMap: + name: {{ include "valkey.fullname" . }}-prestop-script + defaultMode: 0755 + {{- end }} + {{- end }} - name: config configMap: name: {{ include "valkey.configmapName" . }} + {{- if .Values.tls.enabled }} + - name: tls-certs + secret: + secretName: {{ required "TLS secret name is required when TLS is enabled" .Values.tls.existingSecret }} + items: + - key: {{ .Values.tls.certFilename }} + path: {{ .Values.tls.certFilename }} + - key: {{ .Values.tls.certKeyFilename }} + path: {{ .Values.tls.certKeyFilename }} + - key: {{ .Values.tls.certCAFilename }} + path: {{ .Values.tls.certCAFilename }} + {{- end }} - name: tmp emptyDir: {} - {{- if not .Values.persistence.enabled }} - - name: data - emptyDir: {} - {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/valkey/values.schema.json b/charts/valkey/values.schema.json index 1cdf6033..bdd9a341 100644 --- a/charts/valkey/values.schema.json +++ b/charts/valkey/values.schema.json @@ -1,692 +1,560 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "Valkey Helm Chart Values Schema", - "description": "Schema for Valkey Helm chart values", - "properties": { - "global": { - "type": "object", - "title": "Global parameters", - "description": "Global Docker image parameters", - "properties": { - "imageRegistry": { - "type": "string", - "title": "Global Docker Image Registry", - "description": "Global Docker image registry" - }, - "imagePullSecrets": { - "type": "array", - "title": "Global Image Pull Secrets", - "description": "Global Docker registry secret names as an array of objects", - "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "architecture": { + "type": "string" + }, + "auth": { "type": "object", "properties": { - "name": { - "type": "string", - "title": "Secret Name", - "description": "Name of the image pull secret" - } - }, - "required": ["name"] - } - } - } - }, - "image": { - "type": "object", - "title": "Valkey image configuration", - "description": "Configuration for Valkey container image", - "properties": { - "registry": { - "type": "string", - "title": "Valkey Image Registry", - "description": "Valkey image registry" - }, - "repository": { - "type": "string", - "title": "Valkey Image Repository", - "description": "Valkey image repository" - }, - "tag": { - "type": "string", - "title": "Valkey Image Tag", - "description": "Valkey image tag with digest" - }, - "imagePullPolicy": { - "type": "string", - "title": "Valkey Image Pull Policy", - "description": "Valkey image pull policy", - "enum": ["Always", "Never", "IfNotPresent"] - } - } - }, - "replicaCount": { - "type": "integer", - "title": "Replica Count", - "description": "Number of Valkey replicas to deploy", - "minimum": 1 - }, - "nameOverride": { - "type": "string", - "title": "Name Override", - "description": "String to partially override valkey.fullname" - }, - "fullnameOverride": { - "type": "string", - "title": "Full Name Override", - "description": "String to fully override valkey.fullname" - }, - "commonLabels": { - "type": "object", - "title": "Common Labels", - "description": "Labels to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "commonAnnotations": { - "type": "object", - "title": "Common Annotations", - "description": "Annotations to add to all deployed objects", - "additionalProperties": { - "type": "string" - } - }, - "podAnnotations": { - "type": "object", - "title": "Pod Annotations", - "description": "Map of annotations to add to the pods", - "additionalProperties": { - "type": "string" - } - }, - "podLabels": { - "type": "object", - "title": "Pod Labels", - "description": "Map of labels to add to the pods", - "additionalProperties": { - "type": "string" - } - }, - "podSecurityContext": { - "type": "object", - "title": "Pod Security Context", - "description": "Security context for the pod", - "properties": { - "fsGroup": { - "type": "integer", - "title": "FS Group", - "description": "Group ID for the volumes of the pod", - "minimum": 0 - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "Security Context", - "description": "Security context for the container", - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean", - "title": "Allow Privilege Escalation", - "description": "Enable container privilege escalation" - }, - "runAsNonRoot": { - "type": "boolean", - "title": "Run As Non-Root", - "description": "Configure the container to run as a non-root user" - }, - "runAsUser": { - "type": "integer", - "title": "Run As User", - "description": "User ID for the Valkey container", - "minimum": 0 - }, - "runAsGroup": { - "type": "integer", - "title": "Run As Group", - "description": "Group ID for the Valkey container", - "minimum": 0 - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "title": "Read-Only Root Filesystem", - "description": "Mount container root filesystem as read-only" - }, - "capabilities": { - "type": "object", - "title": "Capabilities", - "description": "Linux capabilities configuration", - "properties": { - "drop": { - "type": "array", - "title": "Drop Capabilities", - "description": "Linux capabilities to be dropped", - "items": { - "type": "string" - } - }, - "add": { - "type": "array", - "title": "Add Capabilities", - "description": "Linux capabilities to be added", - "items": { - "type": "string" - } + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "existingSecretPasswordKey": { + "type": "string" + }, + "password": { + "type": "string" + } } - } - } - } - }, - "auth": { - "type": "object", - "title": "Valkey Authentication", - "description": "Authentication configuration for Valkey", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Authentication", - "description": "Enable password authentication" - }, - "password": { - "type": "string", - "title": "Valkey Password", - "description": "Valkey password" - }, - "existingSecret": { - "type": "string", - "title": "Existing Secret", - "description": "The name of an existing secret with Valkey credentials" - }, - "existingSecretPasswordKey": { - "type": "string", - "title": "Existing Secret Password Key", - "description": "Password key to be retrieved from existing secret" - } - } - }, - "config": { - "type": "object", - "title": "Valkey Configuration", - "description": "Configuration parameters for Valkey", - "properties": { - "maxMemory": { - "type": "string", - "title": "Max Memory", - "description": "Maximum memory usage for Valkey (e.g., 256mb, 1gb)", - "pattern": "^$|^(\\d+)(b|kb|mb|gb|tb)?$" - }, - "maxMemoryPolicy": { - "type": "string", - "title": "Max Memory Policy", - "description": "Memory eviction policy when maxmemory is reached", - "enum": [ - "noeviction", - "allkeys-lru", - "volatile-lru", - "allkeys-random", - "volatile-random", - "volatile-ttl", - "volatile-lfu", - "allkeys-lfu" - ] - }, - "save": { - "type": "string", - "title": "Save Configuration", - "description": "Valkey save configuration (e.g., \"900 1 300 10 60 10000\")" - }, - "extraConfig": { - "type": "array", - "title": "Extra Configuration", - "description": "Additional Valkey configuration parameters", - "items": { - "type": "string" - } }, - "existingConfigmap": { - "type": "string", - "title": "Existing ConfigMap", - "description": "Name of existing ConfigMap with Valkey configuration" - } - } - }, - "service": { - "type": "object", - "title": "Service Configuration", - "description": "Kubernetes service configuration", - "properties": { - "type": { - "type": "string", - "title": "Service Type", - "description": "Valkey service type", - "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] - }, - "port": { - "type": "integer", - "title": "Service Port", - "description": "Valkey service port", - "minimum": 1, - "maximum": 65535 - }, - "targetPort": { - "oneOf": [ - {"type": "integer", "minimum": 1, "maximum": 65535}, - {"type": "string"} - ], - "title": "Target Port", - "description": "Valkey container port" - }, - "annotations": { - "type": "object", - "title": "Service Annotations", - "description": "Service annotations", - "additionalProperties": { - "type": "string" - } - } - } - }, - "ingress": { - "type": "object", - "title": "Ingress Configuration", - "description": "Ingress configuration for Valkey", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Ingress", - "description": "Enable ingress record generation for Valkey" - }, - "className": { - "type": "string", - "title": "Ingress Class Name", - "description": "IngressClass that will be used to implement the Ingress" - }, - "annotations": { - "type": "object", - "title": "Ingress Annotations", - "description": "Additional annotations for the Ingress resource", - "additionalProperties": { + "clusterDomain": { "type": "string" - } }, - "hosts": { - "type": "array", - "title": "Ingress Hosts", - "description": "Ingress hosts configuration", - "items": { + "commonAnnotations": { + "type": "object" + }, + "commonLabels": { + "type": "object" + }, + "config": { "type": "object", "properties": { - "host": { - "type": "string", - "title": "Host", - "description": "Hostname for Valkey ingress" - }, - "paths": { - "type": "array", - "title": "Paths", - "description": "Paths configuration for the host", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "title": "Path", - "description": "Path for Valkey ingress" - }, - "pathType": { - "type": "string", - "title": "Path Type", - "description": "Path type for Valkey ingress", - "enum": ["Exact", "Prefix", "ImplementationSpecific"] + "existingConfigmap": { + "type": "string" + }, + "extraConfig": { + "type": "array" + }, + "maxMemory": { + "type": "string" + }, + "maxMemoryPolicy": { + "type": "string" + }, + "save": { + "type": "string" + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } } - }, - "required": ["path", "pathType"] + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" } - } - }, - "required": ["host", "paths"] - } + } }, - "tls": { - "type": "array", - "title": "TLS Configuration", - "description": "TLS configuration for Valkey ingress", - "items": { + "extraEnvVars": { + "type": "array" + }, + "extraObjects": { + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "global": { "type": "object", "properties": { - "secretName": { - "type": "string", - "title": "Secret Name", - "description": "Name of the TLS secret" - }, - "hosts": { - "type": "array", - "title": "TLS Hosts", - "description": "Hosts covered by the TLS certificate", - "items": { - "type": "string" + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" } - } } - } - } - } - }, - "resources": { - "type": "object", - "title": "Resource Configuration", - "description": "The resources to allocate for the container", - "properties": { - "limits": { - "type": "object", - "title": "Resource Limits", - "description": "Resource limits for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Limit", - "description": "CPU resource limit" - }, - "memory": { - "type": "string", - "title": "Memory Limit", - "description": "Memory resource limit" + }, + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } } - } - }, - "requests": { - "type": "object", - "title": "Resource Requests", - "description": "Resource requests for the container", - "properties": { - "cpu": { - "oneOf": [ - {"type": "string"}, - {"type": "number"} - ], - "title": "CPU Request", - "description": "CPU resource request" - }, - "memory": { - "type": "string", - "title": "Memory Request", - "description": "Memory resource request" + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } } - } - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence Configuration", - "description": "Persistence configuration using Persistent Volume Claims", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Persistence", - "description": "Enable persistence using Persistent Volume Claims" - }, - "storageClass": { - "type": "string", - "title": "Storage Class", - "description": "Persistent Volume storage class" - }, - "annotations": { - "type": "object", - "title": "PVC Annotations", - "description": "Persistent Volume Claim annotations", - "additionalProperties": { - "type": "string" - } - }, - "size": { - "type": "string", - "title": "Storage Size", - "description": "Persistent Volume size", - "pattern": "^\\d+(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|K)?$" - }, - "accessModes": { - "type": "array", - "title": "Access Modes", - "description": "Persistent Volume access modes", - "items": { - "type": "string", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] - } - }, - "existingClaim": { - "type": "string", - "title": "Existing Claim", - "description": "The name of an existing PVC to use for persistence" - } - } - }, - "livenessProbe": { - "type": "object", - "title": "Liveness Probe Configuration", - "description": "Liveness probe configuration for Valkey container", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Liveness Probe", - "description": "Enable livenessProbe on Valkey containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for livenessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for livenessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for livenessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for livenessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for livenessProbe", - "minimum": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "title": "Readiness Probe Configuration", - "description": "Readiness probe configuration for Valkey container", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Readiness Probe", - "description": "Enable readinessProbe on Valkey containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for readinessProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for readinessProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for readinessProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for readinessProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for readinessProbe", - "minimum": 1 - } - } - }, - "startupProbe": { - "type": "object", - "title": "Startup Probe Configuration", - "description": "Startup probe configuration for Valkey container (for slow-starting applications)", - "properties": { - "enabled": { - "type": "boolean", - "title": "Enable Startup Probe", - "description": "Enable startupProbe on Valkey containers" - }, - "initialDelaySeconds": { - "type": "integer", - "title": "Initial Delay Seconds", - "description": "Initial delay seconds for startupProbe", - "minimum": 0 - }, - "periodSeconds": { - "type": "integer", - "title": "Period Seconds", - "description": "Period seconds for startupProbe", - "minimum": 1 - }, - "timeoutSeconds": { - "type": "integer", - "title": "Timeout Seconds", - "description": "Timeout seconds for startupProbe", - "minimum": 1 - }, - "failureThreshold": { - "type": "integer", - "title": "Failure Threshold", - "description": "Failure threshold for startupProbe", - "minimum": 1 - }, - "successThreshold": { - "type": "integer", - "title": "Success Threshold", - "description": "Success threshold for startupProbe", - "minimum": 1 - } - } - }, - "nodeSelector": { - "type": "object", - "title": "Node Selector", - "description": "Node labels for pod assignment", - "additionalProperties": { - "type": "string" - } - }, - "tolerations": { - "type": "array", - "title": "Tolerations", - "description": "Toleration labels for pod assignment", - "items": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "operator": { - "type": "string", - "enum": ["Equal", "Exists"] - }, - "value": { + }, + "initContainer": { + "type": "object", + "properties": { + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + } + } + }, + "ipFamily": { "type": "string" - }, - "effect": { - "type": "string", - "enum": ["NoSchedule", "PreferNoSchedule", "NoExecute"] - }, - "tolerationSeconds": { - "type": "integer", - "minimum": 0 - } - } - } - }, - "serviceAccount": { - "type": "object", - "title": "Service Account Configuration", - "description": "ServiceAccount configuration for Valkey", - "properties": { - "create": { - "type": "boolean", - "title": "Create ServiceAccount", - "description": "Enable creation of a Service Account" - }, - "name": { - "type": "string", - "title": "ServiceAccount Name", - "description": "Name of the Service Account" - }, - "annotations": { - "type": "object", - "title": "ServiceAccount Annotations", - "description": "Annotations to add to the Service Account", - "additionalProperties": { + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "port": { + "type": "integer" + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "honorLabels": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "metricRelabelings": { + "type": "array" + }, + "namespace": { + "type": "string" + }, + "namespaceSelector": { + "type": "object" + }, + "relabelings": { + "type": "array" + }, + "scrapeTimeout": { + "type": "string" + }, + "selector": { + "type": "object" + } + } + } + } + }, + "nameOverride": { "type": "string" - } }, - "automountToken": { - "type": "boolean", - "title": "Automount ServiceAccount Token", - "description": "Enable automounting of the Service Account token" - } - } - }, - "affinity": { - "type": "object", - "title": "Affinity Configuration", - "description": "Affinity settings for pod assignment", - "properties": { - "nodeAffinity": { - "type": "object", - "title": "Node Affinity", - "description": "Node affinity configuration" - }, - "podAffinity": { - "type": "object", - "title": "Pod Affinity", - "description": "Pod affinity configuration" - }, - "podAntiAffinity": { - "type": "object", - "title": "Pod Anti-Affinity", - "description": "Pod anti-affinity configuration" + "nodeSelector": { + "type": "object" + }, + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "sentinel": { + "type": "object", + "properties": { + "downAfterMilliseconds": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "extraVolumeMounts": { + "type": "array" + }, + "failoverTimeout": { + "type": "integer" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "masterName": { + "type": "string" + }, + "parallelSyncs": { + "type": "integer" + }, + "port": { + "type": "integer" + }, + "quorum": { + "type": "integer" + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "service": { + "type": "object", + "properties": { + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + } + } + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountToken": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "tls": { + "type": "object", + "properties": { + "authClients": { + "type": "boolean" + }, + "certCAFilename": { + "type": "string" + }, + "certFilename": { + "type": "string" + }, + "certKeyFilename": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "port": { + "type": "integer" + } + } + }, + "tolerations": { + "type": "array" } - } - }, - "extraObjects": { - "type": "array", - "title": "Extra Objects", - "description": "A list of additional Kubernetes objects to deploy alongside the release. Helm templating is supported in any field, but all template expressions must be quoted. Each item should be a valid Kubernetes manifest object.", - "items": { - "type": "object", - "description": "A Kubernetes manifest object. All fields are allowed." - } } - } -} \ No newline at end of file +} diff --git a/charts/valkey/values.yaml b/charts/valkey/values.yaml index c766ccdd..f739a1cc 100644 --- a/charts/valkey/values.yaml +++ b/charts/valkey/values.yaml @@ -5,6 +5,9 @@ global: ## @param global.imagePullSecrets Global Docker registry secret names as an array imagePullSecrets: [] +## @param clusterDomain Kubernetes cluster domain +clusterDomain: cluster.local + ## @section Common parameters ## @param nameOverride String to partially override valkey.fullname nameOverride: "" @@ -22,13 +25,28 @@ image: ## @param image.repository Valkey image repository repository: valkey/valkey ## @param image.tag Valkey image tag (immutable tags are recommended) - tag: "8.1.4-alpine3.22@sha256:e706d1213aaba6896c162bb6a3a9e1894e1a435f28f8f856d14fab2e10aa098b" + tag: "9.0.0-alpine3.22@sha256:b4ee67d73e00393e712accc72cfd7003b87d0fcd63f0eba798b23251bfc9c394" ## @param image.imagePullPolicy Valkey image pull policy imagePullPolicy: Always -## @section StatefulSet configuration -## @param replicaCount Number of Valkey replicas to deploy -replicaCount: 1 +## @section Valkey Architecture +## @param architecture Valkey architecture. Allowed values: standalone, replication +## - standalone: Single Valkey instance +## - replication: Master-replica setup (use sentinel.enabled to enable/disable Sentinel) +architecture: standalone + +## @param replicaCount Number of Valkey instances to deploy (only when architecture=replication) +## When using architecture=replication: +## with Sentinel, this is the total number of Valkey instances (including the initial master) +## without Sentinel, pod-0 is always the master and other pods are replicas +## For example: replicaCount: 3 creates 1 master + 2 replicas +replicaCount: 3 + +## @param ipFamily IP family to use for replica and sentinel announce IPs. Allowed values: auto, ipv4, ipv6 +## auto: Uses the first IP returned by hostname -i (default) +## ipv4: Forces IPv4 address selection +## ipv6: Forces IPv6 address selection +ipFamily: auto ## @section Pod annotations and labels ## @param podAnnotations Map of annotations to add to the pods @@ -68,6 +86,24 @@ auth: ## @param auth.existingSecretPasswordKey Password key to be retrieved from existing secret existingSecretPasswordKey: "password" +## @section TLS/SSL configuration +tls: + ## @param tls.enabled Enable TLS/SSL for Valkey connections + enabled: false + ## @param tls.existingSecret Name of an existing secret containing TLS certificates + ## Expected keys in the secret: tls.crt, tls.key, ca.crt + existingSecret: "" + ## @param tls.certFilename Certificate filename in the secret + certFilename: "tls.crt" + ## @param tls.certKeyFilename Certificate key filename in the secret + certKeyFilename: "tls.key" + ## @param tls.certCAFilename CA certificate filename in the secret + certCAFilename: "ca.crt" + ## @param tls.port TLS port for Valkey (default: 6380) + port: 6380 + ## @param tls.authClients Require clients to authenticate with a valid client certificate + authClients: true + ## @section Valkey Configuration config: ## @param config.maxMemory Maximum memory usage for Valkey (e.g., 256mb, 1gb) @@ -203,6 +239,16 @@ tolerations: [] ## @param affinity Affinity settings for pod assignment affinity: {} +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key + ## @param extraObjects Array of extra objects to deploy with the release extraObjects: [] # - apiVersion: v1 @@ -212,3 +258,102 @@ extraObjects: [] # namespace: "{{ .Release.Namespace }}" # data: # key: value + +## @section Metrics configuration +metrics: + ## @param metrics.enabled Start a sidecar prometheus exporter to expose Valkey metrics + enabled: false + image: + ## @param metrics.image.registry Valkey exporter image registry + registry: docker.io + ## @param metrics.image.repository Valkey exporter image repository + repository: oliver006/redis_exporter + ## @param metrics.image.tag Valkey exporter image tag + tag: "v1.80.0-alpine@sha256:1484ab443e344ac4fd23bb2df8edd297b704abb9e0a354ab5103017764b4a311" + ## @param metrics.image.pullPolicy Valkey exporter image pull policy + pullPolicy: Always + ## @param metrics.resources Resource limits and requests for metrics container + resources: {} + ## Metrics service configuration + service: + ## @param metrics.service.annotations Additional custom annotations for Metrics service + annotations: {} + ## @param metrics.service.labels Additional custom labels for Metrics service + labels: {} + ## @param metrics.service.port Metrics service port + port: 9121 + ## Prometheus Operator ServiceMonitor configuration + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator + enabled: false + ## @param metrics.serviceMonitor.namespace The namespace in which the ServiceMonitor will be created + namespace: "" + ## @param metrics.serviceMonitor.interval The interval at which metrics should be scraped + interval: 30s + ## @param metrics.serviceMonitor.scrapeTimeout The timeout after which the scrape is ended + scrapeTimeout: 10s + ## @param metrics.serviceMonitor.selector Additional labels for ServiceMonitor resource + selector: {} + ## @param metrics.serviceMonitor.annotations ServiceMonitor annotations + annotations: {} + ## @param metrics.serviceMonitor.honorLabels honorLabels chooses the metric's labels on collisions with target labels + honorLabels: false + ## @param metrics.serviceMonitor.relabelings ServiceMonitor relabel configs to apply to samples before scraping + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings ServiceMonitor metricRelabelings configs to apply to samples before ingestion + metricRelabelings: [] + ## @param metrics.serviceMonitor.namespaceSelector ServiceMonitor namespace selector + namespaceSelector: {} + +## @section Valkey Sentinel configuration +## This section configures Valkey Sentinel for high availability in replication mode +## When enabled, Valkey instances use dynamic master/replica role assignment managed by Sentinel +## When disabled with replication architecture, pod-0 is always the master and other pods are replicas +sentinel: + ## @param sentinel.enabled Enable Valkey Sentinel for high availability + ## IMPORTANT: When enabled, applications should use Sentinel-aware clients to discover the current master + ## When disabled, pod-0 is the master and can be accessed via the -master service + enabled: false + image: + ## @param sentinel.image.repository Valkey Sentinel image repository + repository: valkey/valkey + ## @param sentinel.image.tag Valkey Sentinel image tag + tag: "9.0.0-alpine3.22@sha256:b4ee67d73e00393e712accc72cfd7003b87d0fcd63f0eba798b23251bfc9c394" + ## @param sentinel.image.pullPolicy Valkey Sentinel image pull policy + pullPolicy: Always + ## @param sentinel.masterName Name of the master server (default: mymaster) + masterName: mymaster + ## @param sentinel.quorum Number of Sentinels that need to agree about the fact the master is not reachable + quorum: 2 + ## @param sentinel.downAfterMilliseconds Time in milliseconds after the master is declared down + downAfterMilliseconds: 1500 + ## @param sentinel.failoverTimeout Timeout for failover in milliseconds + failoverTimeout: 15000 + ## @param sentinel.parallelSyncs Number of replicas that can be reconfigured to use the new master during a failover + parallelSyncs: 1 + ## @param sentinel.port Sentinel port + port: 26379 + ## @param sentinel.extraVolumeMounts Additional volume mounts to add to the Sentinel container + extraVolumeMounts: [] + service: + ## @param sentinel.service.type Kubernetes service type for Sentinel + type: ClusterIP + ## @param sentinel.service.port Sentinel service port + port: 26379 + ## @param sentinel.resources Resource limits and requests for Sentinel pods + resources: + limits: + memory: 128Mi + requests: + cpu: 25m + memory: 64Mi + +## @param resources Resource limits and requests for Valkey init container pod +initContainer: + resources: + limits: + cpu: 50m + memory: 128Mi + requests: + cpu: 25m + memory: 64Mi diff --git a/charts/zookeeper/CHANGELOG.md b/charts/zookeeper/CHANGELOG.md index 2db31a16..c8d0a7e7 100644 --- a/charts/zookeeper/CHANGELOG.md +++ b/charts/zookeeper/CHANGELOG.md @@ -1,5 +1,62 @@ # Changelog + +## 0.3.0 (2025-10-28) + +* chore: auto-generate values.schema.json for updated charts (#455) ([aec6840](https://github.com/CloudPirates-io/helm-charts/commit/aec6840)) +* chore: update CHANGELOG.md for merged changes ([f9c3ff0](https://github.com/CloudPirates-io/helm-charts/commit/f9c3ff0)) +* chore: update CHANGELOG.md for merged changes ([db2d800](https://github.com/CloudPirates-io/helm-charts/commit/db2d800)) + +## 0.2.1 (2025-10-23) + +* chore: update CHANGELOG.md for merged changes ([c80ea42](https://github.com/CloudPirates-io/helm-charts/commit/c80ea42)) +* chore: update CHANGELOG.md for merged changes ([8ccb4bb](https://github.com/CloudPirates-io/helm-charts/commit/8ccb4bb)) +* chore: update CHANGELOG.md for merged changes ([1a4f87b](https://github.com/CloudPirates-io/helm-charts/commit/1a4f87b)) +* chore: update CHANGELOG.md for merged changes ([da866ca](https://github.com/CloudPirates-io/helm-charts/commit/da866ca)) +* chore: update CHANGELOG.md for merged changes ([b54c4f1](https://github.com/CloudPirates-io/helm-charts/commit/b54c4f1)) +* chore: update CHANGELOG.md for merged changes ([5a2ed20](https://github.com/CloudPirates-io/helm-charts/commit/5a2ed20)) +* chore: update CHANGELOG.md for merged changes ([3361964](https://github.com/CloudPirates-io/helm-charts/commit/3361964)) +* chore: update CHANGELOG.md for merged changes ([7f61172](https://github.com/CloudPirates-io/helm-charts/commit/7f61172)) +* chore: update CHANGELOG.md for merged changes ([1ec9aab](https://github.com/CloudPirates-io/helm-charts/commit/1ec9aab)) +* chore: update CHANGELOG.md for merged changes ([c9ff4ec](https://github.com/CloudPirates-io/helm-charts/commit/c9ff4ec)) +* chore: update CHANGELOG.md for merged changes ([86f1d25](https://github.com/CloudPirates-io/helm-charts/commit/86f1d25)) + +## 0.2.0 (2025-10-14) + +* Update chart.yaml dependencies for indepentent charts (#382) ([87acfb1](https://github.com/CloudPirates-io/helm-charts/commit/87acfb1)) +* chore: update CHANGELOG.md for merged changes ([84cf67b](https://github.com/CloudPirates-io/helm-charts/commit/84cf67b)) +* chore: update CHANGELOG.md for all charts via manual trigger ([6974964](https://github.com/CloudPirates-io/helm-charts/commit/6974964)) +* chore: update CHANGELOG.md for merged changes ([da69e0e](https://github.com/CloudPirates-io/helm-charts/commit/da69e0e)) +* chore: update CHANGELOG.md for merged changes ([5da1b15](https://github.com/CloudPirates-io/helm-charts/commit/5da1b15)) + +## 0.1.7 (2025-10-13) + +* add tests for openshift (#226) ([c80c98a](https://github.com/CloudPirates-io/helm-charts/commit/c80c98a)) + ## 0.1.6 (2025-10-09) -* [mongodb] feat: add metrics exporter ([#243](https://github.com/CloudPirates-io/helm-charts/pull/243)) +* Update charts/zookeeper/values.yaml zookeeper to v3.9.4 (patch) (#267) ([df3b9e3](https://github.com/CloudPirates-io/helm-charts/commit/df3b9e3)) + +## 0.1.5 (2025-10-01) + +* Fix/allow zookeeper to scale to 0 replicas (#196) ([7403e9d](https://github.com/CloudPirates-io/helm-charts/commit/7403e9d)) +* trigger pipeline without version-upgrade (#191) ([819492c](https://github.com/CloudPirates-io/helm-charts/commit/819492c)) + +## 0.1.4 (2025-09-30) + +* [Nginx] Change nginx and zookeeper security-context to use helper-function (#169) ([b581bc7](https://github.com/CloudPirates-io/helm-charts/commit/b581bc7)) + +## 0.1.3 (2025-09-26) + +* #170 fix for command whitelist (#171) ([ebd91d8](https://github.com/CloudPirates-io/helm-charts/commit/ebd91d8)) + +## 0.1.2 (2025-09-26) + + +## 0.1.1 (2025-09-25) + +* add networkpolicy and poddisruptionbudget (#2) (#155) ([2a84b43](https://github.com/CloudPirates-io/helm-charts/commit/2a84b43)) + +## 0.1.0 (2025-09-11) + +* Initial tagged release diff --git a/charts/zookeeper/Chart.lock b/charts/zookeeper/Chart.lock index 55f923b3..5e816749 100644 --- a/charts/zookeeper/Chart.lock +++ b/charts/zookeeper/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: oci://registry-1.docker.io/cloudpirates - version: 1.1.1 -digest: sha256:8da3c04e2c4a1ebfff4f21936399938e0f3fcf9fbd2f7135e7e907ce725b8f00 -generated: "2025-09-26T20:23:22.029394+02:00" + version: 2.0.0 +digest: sha256:ae9378e0dcfd09a35b7f994007db99c2d6fe02ef7634f424d5233237c209a1c7 +generated: "2025-10-14T11:15:19.971362+02:00" diff --git a/charts/zookeeper/Chart.yaml b/charts/zookeeper/Chart.yaml index b8da7288..6dd91631 100644 --- a/charts/zookeeper/Chart.yaml +++ b/charts/zookeeper/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: zookeeper description: Apache ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. type: application -version: 0.1.6 -appVersion: "3.9.3" +version: 0.3.1 +appVersion: "3.9.4" keywords: - zookeeper - distributed @@ -11,18 +11,36 @@ keywords: - apache home: https://zookeeper.apache.org/ sources: + - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/zookeeper - https://github.com/apache/zookeeper -annotations: - category: Database - license: Apache-2.0 maintainers: - name: CloudPirates GmbH & Co. KG + email: hello@cloudpirates.io url: https://www.cloudpirates.io - name: Gianni Carafa email: gianni.carafa@srf.ch url: https://www.srf.ch dependencies: - name: common - version: "1.x.x" + version: "2.x.x" repository: oci://registry-1.docker.io/cloudpirates icon: https://a.storyblok.com/f/143071/512x512/07b0f90b58/apache-zookeeper-logo.svg +annotations: + license: Apache-2.0 + artifacthub.io/category: streaming-messaging + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/signKey: | + fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a + url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub + artifacthub.io/links: | + - name: ZooKeeper + url: https://zookeeper.apache.org/ + - name: Helm Chart + url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/zookeeper + - name: Application + url: https://github.com/apache/zookeeper + - name: Maintainer CloudPirates + url: https://www.cloudpirates.io + artifacthub.io/changes: |2 + - kind: changed + description: "Chart updated" diff --git a/charts/zookeeper/README.md b/charts/zookeeper/README.md index 4ad16c3d..085c4270 100644 --- a/charts/zookeeper/README.md +++ b/charts/zookeeper/README.md @@ -23,6 +23,24 @@ To install with custom values: helm install my-zookeeper ./charts/zookeeper -f values.yaml ``` +## Security & Signature Verification + +This Helm chart is cryptographically signed with Cosign to ensure authenticity and prevent tampering. + +**Public Key:** + +``` +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7BgqFgKdPtHdXz6OfYBklYwJgGWQ +mZzYz8qJ9r6QhF3NxK8rD2oG7Bk6nHJz7qWXhQoU2JvJdI3Zx9HGpLfKvw== +-----END PUBLIC KEY----- +``` + +To verify the helm chart before installation, copy the public key to the file `cosign.pub` and run cosign: + +```bash +cosign verify --key cosign.pub registry-1.docker.io/cloudpirates/zookeeper: +``` ### Getting Started @@ -99,6 +117,7 @@ zkCli.sh -server my-zookeeper:2181 | `service.ports.quorum` | ZooKeeper quorum service port | `2888` | | `service.ports.leaderElection` | ZooKeeper leader election service port | `3888` | | `service.ports.admin` | ZooKeeper admin service port | `8080` | +| `service.annotations` | Additional annotations to add to the service | `{}` | ### Persistence @@ -182,7 +201,7 @@ zkCli.sh -server my-zookeeper:2181 | Parameter | Description | Default | |-----------|-------------|---------| -| `extraEnv` | Additional environment variables | `[]` | +| `extraEnvVars` | Additional environment variables to set | `[]` | | `extraVolumes` | Additional volumes to add to the pod | `[]` | | `extraVolumeMounts` | Additional volume mounts | `[]` | | `extraObjects` | Array of extra objects to deploy | `[]` | diff --git a/charts/zookeeper/templates/_helpers.tpl b/charts/zookeeper/templates/_helpers.tpl index 41fb7930..18ca0be6 100644 --- a/charts/zookeeper/templates/_helpers.tpl +++ b/charts/zookeeper/templates/_helpers.tpl @@ -2,56 +2,56 @@ Expand the name of the chart. */}} {{- define "zookeeper.name" -}} -{{- include "common.name" . -}} +{{- include "cloudpirates.name" . -}} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "zookeeper.fullname" -}} -{{- include "common.fullname" . -}} +{{- include "cloudpirates.fullname" . -}} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "zookeeper.chart" -}} -{{- include "common.chart" . -}} +{{- include "cloudpirates.chart" . -}} {{- end }} {{/* Common labels */}} {{- define "zookeeper.labels" -}} -{{- include "common.labels" . }} +{{- include "cloudpirates.labels" . }} {{- end }} {{/* Selector labels */}} {{- define "zookeeper.selectorLabels" -}} -{{- include "common.selectorLabels" . -}} +{{- include "cloudpirates.selectorLabels" . -}} {{- end }} {{/* Common annotations */}} {{- define "zookeeper.annotations" -}} -{{- include "common.annotations" . -}} +{{- include "cloudpirates.annotations" . -}} {{- end }} {{/* Return the proper ZooKeeper image name */}} {{- define "zookeeper.image" -}} -{{- include "common.image" (dict "image" .Values.image "global" .Values.global) -}} +{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}} {{- end }} {{/* Return the proper Docker Image Registry Secret Names */}} {{- define "zookeeper.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} +{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }} {{- end -}} {{/* diff --git a/charts/zookeeper/templates/configmap.yaml b/charts/zookeeper/templates/configmap.yaml index f2f4673d..ba602c2d 100644 --- a/charts/zookeeper/templates/configmap.yaml +++ b/charts/zookeeper/templates/configmap.yaml @@ -5,6 +5,10 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "zookeeper.labels" . | nindent 4 }} + {{- with (include "zookeeper.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} data: zoo.cfg: | tickTime={{ .Values.zookeeperConfig.tickTime | default 2000 }} diff --git a/charts/zookeeper/templates/extraobjects.yaml b/charts/zookeeper/templates/extraobjects.yaml index fd7643e4..7f5ede80 100644 --- a/charts/zookeeper/templates/extraobjects.yaml +++ b/charts/zookeeper/templates/extraobjects.yaml @@ -1,4 +1,4 @@ {{- range .Values.extraObjects }} --- -{{- include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }} {{- end }} \ No newline at end of file diff --git a/charts/zookeeper/templates/networkpolicy.yaml b/charts/zookeeper/templates/networkpolicy.yaml index f97a0a20..6200e047 100644 --- a/charts/zookeeper/templates/networkpolicy.yaml +++ b/charts/zookeeper/templates/networkpolicy.yaml @@ -6,6 +6,10 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "zookeeper.labels" . | nindent 4 }} + {{- with (include "zookeeper.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} spec: podSelector: matchLabels: diff --git a/charts/zookeeper/templates/poddisruptionbudget.yaml b/charts/zookeeper/templates/poddisruptionbudget.yaml index 113f83e9..dcad8572 100644 --- a/charts/zookeeper/templates/poddisruptionbudget.yaml +++ b/charts/zookeeper/templates/poddisruptionbudget.yaml @@ -6,6 +6,10 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "zookeeper.labels" . | nindent 4 }} + {{- with (include "zookeeper.annotations" .) }} + annotations: +{{- . | indent 4 }} + {{- end }} spec: maxUnavailable: 1 selector: diff --git a/charts/zookeeper/templates/service.yaml b/charts/zookeeper/templates/service.yaml index e07bcfb0..71d0e9b4 100644 --- a/charts/zookeeper/templates/service.yaml +++ b/charts/zookeeper/templates/service.yaml @@ -5,6 +5,11 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "zookeeper.labels" . | nindent 4 }} + {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }} + {{- with $annotations }} + annotations: +{{ toYaml . | indent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} ports: diff --git a/charts/zookeeper/templates/statefulset.yaml b/charts/zookeeper/templates/statefulset.yaml index 9f080f5a..a7a7fe1c 100644 --- a/charts/zookeeper/templates/statefulset.yaml +++ b/charts/zookeeper/templates/statefulset.yaml @@ -32,10 +32,10 @@ spec: {{- with (include "zookeeper.imagePullSecrets" .) }} {{ . | nindent 6 }} {{- end }} - securityContext: {{ include "common.renderPodSecurityContext" . | nindent 8 }} + securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }} containers: - name: {{ .Chart.Name }} - securityContext: {{ include "common.renderContainerSecurityContext" . | nindent 12 }} + securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }} image: {{ include "zookeeper.image" . | quote }} imagePullPolicy: {{ .Values.image.imagePullPolicy | default "Always" | quote }} ports: @@ -52,9 +52,8 @@ spec: containerPort: {{ .Values.service.ports.admin | default 8080 }} protocol: TCP env: - {{- range .Values.extraEnv }} - - name: {{ .name }} - value: {{ .value | quote }} + {{- with .Values.extraEnvVars }} +{{ toYaml . | indent 12 }} {{- end }} - name: ZOO_MY_ID valueFrom: diff --git a/charts/zookeeper/values.schema.json b/charts/zookeeper/values.schema.json index ca457ef3..3bf9568c 100644 --- a/charts/zookeeper/values.schema.json +++ b/charts/zookeeper/values.schema.json @@ -1,259 +1,353 @@ { - "$schema": "https://json-schema.org/draft-07/schema#", - "type": "object", - "title": "ZooKeeper Helm Chart Values Schema", - "description": "Schema for ZooKeeper Helm chart values", - "properties": { - "global": { - "type": "object", - "properties": { - "imageRegistry": { "type": "string" }, - "imagePullSecrets": { "type": "array", "items": { "type": "string" } } - } - }, - "nameOverride": { "type": "string" }, - "fullnameOverride": { "type": "string" }, - "commonLabels": { "type": "object", "additionalProperties": { "type": "string" } }, - "commonAnnotations": { "type": "object", "additionalProperties": { "type": "string" } }, - "zookeeperConfig": { - "type": "object", - "properties": { - "tickTime": { "type": "integer", "default": 2000 }, - "dataDir": { "type": "string" }, - "initLimit": { "type": "integer", "default": 10 }, - "syncLimit": { "type": "integer", "default": 5 } - } - }, - "image": { - "type": "object", - "properties": { - "registry": { "type": "string" }, - "repository": { "type": "string" }, - "tag": { "type": "string" }, - "pullPolicy": { "type": "string", "enum": ["Always", "Never", "IfNotPresent"] } - } - }, - "replicaCount": { "type": "integer", "minimum": 0 }, - "metrics": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "service": { - "type": "object", - "properties": { - "type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] }, - "port": { "type": "integer", "minimum": 1, "maximum": 65535 } - } - } - } - }, - "containerSecurityContext": { - "type": "object", - "description": "Container-level security context settings", - "properties": { - "runAsUser": { - "type": "integer", - "description": "User ID to run the container process" + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "commonAnnotations": { + "type": "object" }, - "runAsGroup": { - "type": "integer", - "description": "Group ID to run the container process" + "commonLabels": { + "type": "object" + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "privileged": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + }, + "seLinuxOptions": { + "type": "object" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + } + } }, - "seLinuxOptions": { - "type": "object", - "description": "Set container's Security Context seLinuxOptions" + "extraEnvVars": { + "type": "array" }, - "runAsNonRoot": { - "type": "boolean", - "description": "Require the container to run as a non-root user" + "extraObjects": { + "type": "array" }, - "allowPrivilegeEscalation": { - "type": "boolean", - "description": "Whether to allow privilege escalation for the container" + "extraVolumeMounts": { + "type": "array" }, - "privileged": { - "type": "boolean", - "description": "Set container's privileged mode" + "extraVolumes": { + "type": "array" }, - "readOnlyRootFilesystem": { - "type": "boolean", - "description": "Mount container root filesystem as read-only" + "fullnameOverride": { + "type": "string" }, - "capabilities": { - "type": "object", - "description": "Linux capabilities to drop or add for the container", - "properties": { - "drop": { - "type": "array", - "items": { "type": "string" }, - "description": "List of Linux capabilities to drop (e.g., ALL)" - }, - "add": { - "type": "array", - "items": { "type": "string" }, - "description": "List of Linux capabilities to add" + "global": { + "type": "object", + "properties": { + "imagePullSecrets": { + "type": "array" + }, + "imageRegistry": { + "type": "string" + } } - } }, - "seccompProfile": { - "type": "object", - "description": "Seccomp profile configuration for the container", - "properties": { - "type": { - "type": "string", - "description": "Type of seccomp profile to use (e.g., RuntimeDefault, Localhost)" - }, - "localhostProfile": { - "type": "string", - "description": "Path to a localhost seccomp profile (if type is Localhost)" + "image": { + "type": "object", + "properties": { + "imagePullPolicy": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } } - } - } - } - }, - "podSecurityContext": { - "type": "object", - "description": "Pod-level security context settings", - "properties": { - "fsGroup": { - "type": "integer", - "description": "Group ID for the volumes of the pod" - } - } - }, - "service": { - "type": "object", - "properties": { - "type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] }, - "ports": { - "type": "object", - "properties": { - "client": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "quorum": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "leaderElection": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "admin": { "type": "integer", "minimum": 1, "maximum": 65535 } - } - } - } - }, - "resources": { - "type": "object", - "properties": { - "limits": { - "type": "object", - "properties": { - "cpu": { "oneOf": [ {"type": "string"}, {"type": "number"} ] }, - "memory": { "type": "string" } - } }, - "requests": { - "type": "object", - "properties": { - "cpu": { "oneOf": [ {"type": "string"}, {"type": "number"} ] }, - "memory": { "type": "string" } - } - } - } - }, - "nodeSelector": { "type": "object", "additionalProperties": { "type": "string" } }, - "priorityClassName": { "type": "string" }, - "targetPlatform": { - "type": "string", - "description": "Target platform for deployment (e.g., openshift, default)" - }, - "tolerations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "key": { "type": "string" }, - "operator": { "type": "string", "enum": ["Equal", "Exists"] }, - "value": { "type": "string" }, - "effect": { "type": "string", "enum": ["NoSchedule", "PreferNoSchedule", "NoExecute"] }, - "tolerationSeconds": { "type": "integer", "minimum": 0 } - } - } - }, - "affinity": { "type": "object" }, - "persistence": { - "type": "object", - "description": "Persistence configuration", - "properties": { - "enabled": { "type": "boolean", "description": "Enable persistence using Persistent Volume Claims" }, - "storageClass": { "type": "string", "description": "Persistent Volume storage class" }, - "annotations": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Persistent Volume Claim annotations" }, - "size": { "type": "string", "description": "Persistent Volume size" }, - "accessModes": { "type": "array", "items": { "type": "string" }, "description": "Persistent Volume access modes" }, - "existingClaim": { "type": "string", "description": "The name of an existing PVC to use for persistence" }, - "mountPath": { "type": "string", "description": "The path where to mount the data volume" } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "initialDelaySeconds": { "type": "integer", "minimum": 0 }, - "periodSeconds": { "type": "integer", "minimum": 1 }, - "timeoutSeconds": { "type": "integer", "minimum": 1 }, - "failureThreshold": { "type": "integer", "minimum": 1 }, - "successThreshold": { "type": "integer", "minimum": 1 } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "initialDelaySeconds": { "type": "integer", "minimum": 0 }, - "periodSeconds": { "type": "integer", "minimum": 1 }, - "timeoutSeconds": { "type": "integer", "minimum": 1 }, - "failureThreshold": { "type": "integer", "minimum": 1 }, - "successThreshold": { "type": "integer", "minimum": 1 } - } - }, - "startupProbe": { - "type": "object", - "properties": { - "enabled": { "type": "boolean" }, - "initialDelaySeconds": { "type": "integer", "minimum": 0 }, - "periodSeconds": { "type": "integer", "minimum": 1 }, - "timeoutSeconds": { "type": "integer", "minimum": 1 }, - "failureThreshold": { "type": "integer", "minimum": 1 }, - "successThreshold": { "type": "integer", "minimum": 1 } - } - }, - "extraEnv": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "value": { "type": "string" } + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } }, - "required": ["name"] - } - }, - "extraVolumes": { "type": "array", "items": { "type": "object" } }, - "extraVolumeMounts": { "type": "array", "items": { "type": "object" } }, - "extraObjects": { "type": "array", "items": { "type": "object" } }, - "podDisruptionBudget": { - "type": "object", - "description": "Pod Disruption Budget configuration", - "properties": { - "enabled": { - "type": "boolean", - "description": "Create a Pod Disruption Budget to ensure high availability during voluntary disruptions" - } - } - }, - "networkPolicy": { - "type": "object", - "description": "Network Policy configuration", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable network policies" + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "service": { + "type": "object", + "properties": { + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + } + } + }, + "nameOverride": { + "type": "string" + }, + "networkPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "nodeSelector": { + "type": "object" + }, + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "podDisruptionBudget": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "podSecurityContext": { + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + } + } + }, + "priorityClassName": { + "type": "string" + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "revisionHistoryLimit": { + "type": "integer" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "ports": { + "type": "object", + "properties": { + "admin": { + "type": "integer" + }, + "client": { + "type": "integer" + }, + "leaderElection": { + "type": "integer" + }, + "quorum": { + "type": "integer" + } + } + }, + "type": { + "type": "string" + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "tolerations": { + "type": "array" + }, + "zookeeperConfig": { + "type": "object", + "properties": { + "admin": { + "type": "object", + "properties": { + "commandUrl": { + "type": "string" + }, + "enableServer": { + "type": "string" + }, + "idleTimeout": { + "type": "integer" + }, + "serverAddress": { + "type": "string" + }, + "serverPort": { + "type": "integer" + } + } + }, + "adminServerEnabled": { + "type": "string" + }, + "autopurge": { + "type": "object", + "properties": { + "purgeInterval": { + "type": "integer" + }, + "snapRetainCount": { + "type": "integer" + } + } + }, + "commandsWhitelist": { + "type": "string" + }, + "electionPortBindRetry": { + "type": "integer" + }, + "initLimit": { + "type": "integer" + }, + "maxClientCnxns": { + "type": "integer" + }, + "standaloneEnabled": { + "type": "string" + }, + "syncLimit": { + "type": "integer" + }, + "tickTime": { + "type": "integer" + } + } } - } } - } } diff --git a/charts/zookeeper/values.yaml b/charts/zookeeper/values.yaml index fbbaff23..a01a307b 100644 --- a/charts/zookeeper/values.yaml +++ b/charts/zookeeper/values.yaml @@ -133,6 +133,8 @@ service: leaderElection: 3888 ## @param service.ports.admin Zookeeper admin service port admin: 8080 + ## @param service.annotations Additional annotations to add to the service + annotations: {} ## @section Resources resources: @@ -222,10 +224,15 @@ startupProbe: successThreshold: 1 -## @param extraEnv Additional environment variables to set -extraEnv: [] -# - name: EXTRA_VAR -# value: "extra_value" +## @param extraEnvVars Additional environment variables to set +extraEnvVars: [] + # - name: CUSTOM_VAR + # value: "custom-value" + # - name: SECRET_VAR + # valueFrom: + # secretKeyRef: + # name: my-secret + # key: secret-key ## @param extraVolumes Additional volumes to add to the pod extraVolumes: [] diff --git a/create-changelogs.sh b/create-changelogs.sh deleted file mode 100755 index 2b61db20..00000000 --- a/create-changelogs.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# Helper script to create CHANGELOGS for all charts bases on the commit messages and existing tags -# @see https://github.com/conventional-changelog/conventional-changelog - -set -euo pipefail - -CHARTS=($(find ./charts -mindepth 1 -maxdepth 1 -type d ! -name 'charts' ! -name 'common' -exec basename {} \;)) -if [ ${#CHARTS[@]} -gt 0 ]; then - for CHART in "${CHARTS[@]}"; do - echo "Generating changelog for $CHART..." - # Generate full changelog with conventional-changelog - conventional-changelog -i "charts/${CHART}/CHANGELOG.md" -s -t "${CHART}-" -r 0 --commit-path "charts/${CHART}" - - # Get chart version and current date - CHART_VERSION=$(yq eval '.version' "charts/${CHART}/Chart.yaml") - UPPER_CHART=$(echo "$CHART" | tr '[:lower:]' '[:upper:]') - - # Remove chart tags - sed -i -E "s/\* \[(${CHART}|${UPPER_CHART})\] /\* /g" "charts/${CHART}/CHANGELOG.md" - - # Update latest version header - sed -i -E "s/##\s+(\([0-9-]+\))/## $CHART_VERSION \1<\/small>/" "charts/${CHART}/CHANGELOG.md" - - # Add "Changelog" header - if ! grep -q "^# Changelog" "charts/${CHART}/CHANGELOG.md"; then - sed -i '1i# Changelog\n' "charts/${CHART}/CHANGELOG.md" - fi - - # Remove trailing newlines - sed -i -E ':a;/^[[:space:]]*$/{$d;N;ba}' "charts/${CHART}/CHANGELOG.md" - done -else - echo -e "Failed to find charts" - exit 1 -fi diff --git a/generate-changelog.sh b/generate-changelog.sh new file mode 100755 index 00000000..9dac2ae6 --- /dev/null +++ b/generate-changelog.sh @@ -0,0 +1,438 @@ +#!/bin/bash + +# Changelog generation script for Helm charts +# This script generates changelogs based on git history and PR information +# It works for both PRs from forks and branches within the main repository + +set -eo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored messages +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" || echo "[INFO] $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check required tools +check_dependencies() { + local missing_deps=() + + if ! command -v yq &> /dev/null; then + missing_deps+=("yq") + fi + + if ! command -v git &> /dev/null; then + missing_deps+=("git") + fi + + if [ ${#missing_deps[@]} -gt 0 ]; then + log_error "Missing required dependencies: ${missing_deps[*]}" + exit 1 + fi +} + +# Function to format changes for artifacthub.io/changes annotation +format_changes_for_chart_yaml() { + local chart_name="$1" + local pr_title="${2:-}" + local pr_number="${3:-}" + local pr_url="${4:-}" + local chart_dir="charts/${chart_name}" + local commit_limit=8 + + # Create changes array - only include recent changes (latest version) + local changes_yaml="" + + # Add new PR if provided + if [ -n "$pr_title" ] && [ -n "$pr_number" ] && [ -n "$pr_url" ]; then + changes_yaml=" - kind: added\n description: \"${pr_title}\"\n links:\n - name: \"PR #${pr_number}\"\n url: \"${pr_url}\"" + else + # Get the latest tag for this chart + local latest_tag + latest_tag=$(git tag -l "${chart_name}-*" 2>/dev/null | sort -V -r | head -n 1 || true) + + if [ -n "$latest_tag" ]; then + # Get the second latest tag to determine the range + local prev_tag + prev_tag=$(git tag -l "${chart_name}-*" 2>/dev/null | sort -V -r | sed -n '2p' || true) + + local commit_range + if [ -n "$prev_tag" ]; then + commit_range="${prev_tag}..${latest_tag}" + else + # If no previous tag, just get commits for the latest tag + commit_range=$(git log --format=%H "$latest_tag" | tail -1)..${latest_tag} + fi + + # Get recent commits for this chart + local changes_found=false + while IFS= read -r commit_line; do + [ -z "$commit_line" ] && continue + + local commit_hash + commit_hash=$(echo "$commit_line" | cut -d' ' -f1) + local commit_msg + commit_msg=$(echo "$commit_line" | cut -d' ' -f2-) + + # Skip commits that are clearly for other charts + if echo "$commit_msg" | grep -qE '^\[[a-z]+\]'; then + if ! echo "$commit_msg" | grep -qiE '^\[('"${chart_name}"'|all)\]'; then + continue + fi + fi + + # Skip commits that contain "chore", "docs", "typo", "bump" (case insensitive) + if echo "$commit_msg" | grep -qiE '(chore|docs|typo|bump)'; then + continue + fi + + # Clean up commit message + commit_msg=$(echo "$commit_msg" | sed -E "s/^\[${chart_name}\] //i") + commit_msg=$(echo "$commit_msg" | sed -E "s/^\[$(echo "${chart_name}" | tr '[:lower:]' '[:upper:]')\] //") + commit_msg=$(echo "$commit_msg" | sed -E "s/^\[all\] //i") + + # Escape quotes in commit message for YAML + commit_msg=$(echo "$commit_msg" | sed 's/"/\\"/g') + + # Add to changes (limit to first few) + if [ "$changes_found" = false ]; then + changes_yaml=" - kind: changed\n description: \"${commit_msg}\"\n links:\n - name: \"Commit ${commit_hash:0:8}\"\n url: \"${GITHUB_REPOSITORY_URL:-https://github.com/${GITHUB_REPOSITORY:-CloudPirates-io/helm-charts}}/commit/${commit_hash}\"" + changes_found=true + else + changes_yaml="${changes_yaml}\n - kind: changed\n description: \"${commit_msg}\"\n links:\n - name: \"Commit ${commit_hash:0:8}\"\n url: \"${GITHUB_REPOSITORY_URL:-https://github.com/${GITHUB_REPOSITORY:-CloudPirates-io/helm-charts}}/commit/${commit_hash}\"" + fi + + # Limit to 3 most recent changes to keep annotation reasonable + local change_count + change_count=$(echo -e "$changes_yaml" | grep -c "kind:" || echo "0") + if [ "$change_count" -ge "$commit_limit" ]; then + break + fi + done < <(git log "$commit_range" --oneline --no-merges -- "$chart_dir" 2>/dev/null | head -3 || true) + + if [ "$changes_found" = false ]; then + changes_yaml=" - kind: changed\n description: \"Chart updated\"" + fi + else + # No tags found, create a basic entry + changes_yaml=" - kind: added\n description: \"Initial chart release\"" + fi + fi + + echo -e "$changes_yaml" +} + +# Function to update Chart.yaml with artifacthub.io/changes annotation +update_chart_yaml_changes() { + local chart_yaml="$1" + local changes_content="$2" + + # Create a temporary file for the updated Chart.yaml + local temp_chart_yaml + temp_chart_yaml=$(mktemp) + + # Check if the file already has artifacthub.io/changes annotation + if grep -q "artifacthub.io/changes:" "$chart_yaml"; then + # Remove existing artifacthub.io/changes annotation and its content + # This is complex because the annotation is multi-line YAML + yq eval 'del(.annotations."artifacthub.io/changes")' "$chart_yaml" > "$temp_chart_yaml" + else + cp "$chart_yaml" "$temp_chart_yaml" + fi + + # Add the new artifacthub.io/changes annotation + # Create a temporary file with the changes content + local temp_changes + temp_changes=$(mktemp) + echo -e "$changes_content" > "$temp_changes" + + # Use yq to add the changes annotation + yq eval '.annotations."artifacthub.io/changes" = load_str("'"$temp_changes"'")' "$temp_chart_yaml" > "${temp_chart_yaml}.new" + mv "${temp_chart_yaml}.new" "$temp_chart_yaml" + + # Replace the original file + mv "$temp_chart_yaml" "$chart_yaml" + + # Clean up temporary files + rm -f "$temp_changes" + + log_info "Updated artifacthub.io/changes annotation in Chart.yaml" +} + +# Function to generate changelog for a single chart +generate_chart_changelog() { + local chart_name="$1" + local pr_title="${2:-}" + local pr_number="${3:-}" + local pr_url="${4:-}" + + log_info "Generating changelog for chart: $chart_name" + + local chart_dir="charts/${chart_name}" + local chart_yaml="${chart_dir}/Chart.yaml" + local changelog_file="${chart_dir}/CHANGELOG.md" + + # Validate chart directory exists + if [ ! -d "$chart_dir" ]; then + log_error "Chart directory not found: $chart_dir" + return 1 + fi + + # Validate Chart.yaml exists + if [ ! -f "$chart_yaml" ]; then + log_error "Chart.yaml not found: $chart_yaml" + return 1 + fi + + # Extract version from Chart.yaml + local chart_version + chart_version=$(yq eval '.version' "$chart_yaml") + + if [ -z "$chart_version" ]; then + log_error "Could not extract version from $chart_yaml" + return 1 + fi + + log_info "Chart version: $chart_version" + + # Create temporary file for new changelog + local temp_changelog + temp_changelog=$(mktemp) + + # Start with header + echo "# Changelog" > "$temp_changelog" + echo "" >> "$temp_changelog" + + # Add new version entry if PR info is provided + if [ -n "$pr_title" ] && [ -n "$pr_number" ] && [ -n "$pr_url" ]; then + local current_date + current_date=$(date +'%Y-%m-%d') + + echo "## $chart_version ($current_date)" >> "$temp_changelog" + echo "" >> "$temp_changelog" + echo "* ${pr_title} ([#${pr_number}](${pr_url}))" >> "$temp_changelog" + + log_info "Added new version entry: $chart_version ($current_date)" + fi + + # Get all tags for this chart, sorted by version (newest first) + local chart_tags + chart_tags=$(git tag -l "${chart_name}-*" 2>/dev/null | sort -V -r || true) + + if [ -z "$chart_tags" ]; then + log_warn "No tags found for chart: $chart_name" + else + log_info "Found tags for $chart_name" + + # Convert tags to array for easier processing + local tags_array=() + while IFS= read -r tag; do + [ -n "$tag" ] && tags_array+=("$tag") + done <<< "$chart_tags" + + # Process each tag to generate historical entries + for i in "${!tags_array[@]}"; do + local tag="${tags_array[$i]}" + local prev_older_tag="" + + # Get the previous (older) tag - one position back in the array + if [ $i -lt $((${#tags_array[@]} - 1)) ]; then + prev_older_tag="${tags_array[$((i+1))]}" + fi + + # Get the tag version (strip chart name prefix) + local tag_version="${tag#${chart_name}-}" + + # Get tag date + local tag_date + tag_date=$(git log -1 --format=%ai "$tag" 2>/dev/null | cut -d' ' -f1 || echo "unknown") + + echo "" >> "$temp_changelog" + echo "## $tag_version ($tag_date)" >> "$temp_changelog" + echo "" >> "$temp_changelog" + + # Determine commit range + # Get commits between the previous older tag and this tag + local commit_range + if [ -z "$prev_older_tag" ]; then + # This is the oldest tag - don't show full history, just note it + echo "* Initial tagged release" >> "$temp_changelog" + continue + else + # Get commits between the previous older tag and this tag + commit_range="${prev_older_tag}..${tag}" + fi + + # Get commits that touched this chart's directory + local commits_found=false + while IFS= read -r commit_line; do + [ -z "$commit_line" ] && continue + commits_found=true + + local commit_hash + commit_hash=$(echo "$commit_line" | cut -d' ' -f1) + + local commit_msg + commit_msg=$(echo "$commit_line" | cut -d' ' -f2-) + + # Skip commits that are clearly for other charts (have [other-chart] prefix) + # But allow commits with [chart-name] prefix, [all] prefix, or no prefix + if echo "$commit_msg" | grep -qE '^\[[a-z]+\]'; then + # Has a chart prefix - check if it's for this chart or [all] + if ! echo "$commit_msg" | grep -qiE '^\[('"${chart_name}"'|all)\]'; then + # Skip this commit - it's for a different chart + continue + fi + fi + + # Remove chart name prefix from commit message (case insensitive) + commit_msg=$(echo "$commit_msg" | sed -E "s/^\[${chart_name}\] //i") + commit_msg=$(echo "$commit_msg" | sed -E "s/^\[$(echo "${chart_name}" | tr '[:lower:]' '[:upper:]')\] //") + commit_msg=$(echo "$commit_msg" | sed -E "s/^\[all\] //i") + + # Add commit to changelog with link + local repo_url="${GITHUB_REPOSITORY_URL:-https://github.com/${GITHUB_REPOSITORY:-CloudPirates-io/helm-charts}}" + echo "* ${commit_msg} ([${commit_hash}](${repo_url}/commit/${commit_hash}))" >> "$temp_changelog" + done < <(git log "$commit_range" --oneline --no-merges -- "$chart_dir" 2>/dev/null || true) + + if [ "$commits_found" = false ]; then + # No commits found for this tag, add a placeholder + echo "* No changes recorded" >> "$temp_changelog" + fi + done + fi + + # Replace old changelog with new one + mv "$temp_changelog" "$changelog_file" + + log_info "Changelog updated: $changelog_file" + + # Update Chart.yaml with artifacthub.io/changes annotation + local changes_for_chart_yaml + changes_for_chart_yaml=$(format_changes_for_chart_yaml "$chart_name" "$pr_title" "$pr_number" "$pr_url") + + if [ -n "$changes_for_chart_yaml" ]; then + update_chart_yaml_changes "$chart_yaml" "$changes_for_chart_yaml" + log_info "Chart.yaml updated with artifacthub.io/changes annotation" + fi + + return 0 +} + +# Main script logic +main() { + log_info "Starting changelog generation" + + # Check dependencies + check_dependencies + + # Parse command line arguments + local chart_names=() + local pr_title="" + local pr_number="" + local pr_url="" + local generate_all=false + + while [[ $# -gt 0 ]]; do + case $1 in + --chart) + chart_names+=("$2") + shift 2 + ;; + --pr-title) + pr_title="$2" + shift 2 + ;; + --pr-number) + pr_number="$2" + shift 2 + ;; + --pr-url) + pr_url="$2" + shift 2 + ;; + --all) + generate_all=true + shift + ;; + --help|-h) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --chart CHART_NAME Generate changelog for specific chart (can be specified multiple times)" + echo " --pr-title TITLE PR title to add to changelog" + echo " --pr-number NUMBER PR number for reference" + echo " --pr-url URL PR URL for linking" + echo " --all Generate changelogs for all charts" + echo " --help, -h Show this help message" + echo "" + echo "Examples:" + echo " $0 --chart nginx --chart redis" + echo " $0 --chart nginx --pr-title 'Fix nginx config' --pr-number 123 --pr-url 'https://github.com/org/repo/pull/123'" + echo " $0 --all" + exit 0 + ;; + *) + log_error "Unknown option: $1" + echo "Use --help for usage information" + exit 1 + ;; + esac + done + + # If --all flag is set, find all charts + if [ "$generate_all" = true ]; then + log_info "Discovering all charts..." + while IFS= read -r chart_dir; do + local chart_name + chart_name=$(basename "$chart_dir") + # Skip 'common' chart + if [ "$chart_name" != "common" ]; then + chart_names+=("$chart_name") + fi + done < <(find ./charts -mindepth 1 -maxdepth 1 -type d ! -name 'common') + fi + + # Validate we have charts to process + if [ ${#chart_names[@]} -eq 0 ]; then + log_error "No charts specified. Use --chart, --all, or --help" + exit 1 + fi + + log_info "Processing ${#chart_names[@]} chart(s): ${chart_names[*]}" + + # Generate changelogs + local success_count=0 + local fail_count=0 + + for chart_name in "${chart_names[@]}"; do + if generate_chart_changelog "$chart_name" "$pr_title" "$pr_number" "$pr_url"; then + success_count=$((success_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + done + + # Summary + log_info "Changelog generation complete" + log_info "Success: $success_count, Failed: $fail_count" + + if [ $fail_count -gt 0 ]; then + exit 1 + fi +} + +# Run main function +main "$@" diff --git a/renovate.json b/renovate.json index 4ca5aeb8..c4e76e79 100644 --- a/renovate.json +++ b/renovate.json @@ -10,10 +10,11 @@ ], "separateMinorPatch": true, "prConcurrentLimit": 5, - "recreateWhen": "always", + "recreateWhen": "never", "customManagers": [ { "customType": "regex", + "description": "Match Docker images in all charts", "managerFilePatterns": [ "/(^|/)charts/.+/values\\.ya?ml$/" ], @@ -23,9 +24,33 @@ ], "datasourceTemplate": "docker", "versioningTemplate": "docker" + }, + { + "customType": "regex", + "description": "Match etcd image and use GitHub releases", + "managerFilePatterns": [ + "/^charts/etcd/values\\.ya?ml$/" + ], + "matchStrings": [ + "(?image):\\s*\\n(?:[^\\n]*\\n){0,5}?\\s*repository:\\s*coreos/etcd\\s*\\n(?:[^\\n]*\\n){0,3}?\\s*tag:\\s*['\"]?(?[^@'\"\\s]+)(?:@(?sha256:[a-f0-9]{64}))?['\"]?" + ], + "datasourceTemplate": "github-releases", + "packageNameTemplate": "etcd-io/etcd", + "extractVersionTemplate": "^v(?.+)$" } ], "packageRules": [ + { + "description": "Disable Docker datasource for etcd packages (use GitHub releases instead)", + "matchDatasources": [ + "docker" + ], + "matchPackageNames": [ + "coreos/etcd", + "quay.io/coreos/etcd" + ], + "enabled": false + }, { "matchManagers": [ "custom.regex" @@ -62,7 +87,8 @@ "koperator-internal/services/clusterpirate" ], "enabled": false, - "pinDigests": false + "pinDigests": false, + "recreateWhen": "never" }, { "matchDatasources": [ @@ -72,7 +98,25 @@ "cloudpirates/common", "cloudpirates/valkey" ], - "enabled": false + "enabled": false, + "recreateWhen": "never" + }, + { + "description": "Configure etcd updates from GitHub releases", + "matchDatasources": [ + "github-releases" + ], + "matchPackageNames": [ + "etcd-io/etcd" + ], + "pinDigests": false, + "labels": [ + "dependencies", + "renovate" + ], + "commitMessagePrefix": "[etcd]", + "automerge": false, + "separateMinorPatch": true } ] } diff --git a/test-all-charts.sh b/test-all-charts.sh deleted file mode 100755 index 72763cf9..00000000 --- a/test-all-charts.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash - -# Test runner script for all helm charts -# This script runs helm unittest for all charts to validate common parameters - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CHARTS_DIR="${SCRIPT_DIR}/charts" - -# Colors for output -RED='\033[1;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[3;36m' -NC='\033[0m' # No Color - -echo "๐Ÿงช Running Helm unit tests for all charts" -echo "==========================================" - -# Ensure that helm-unittest plugin is installed -if ! helm plugin list | grep -q unittest; then - echo -e "${YELLOW}โš ๏ธ helm-unittest plugin not found. Installing...${NC}" - helm plugin install https://github.com/helm-unittest/helm-unittest -fi - -# Collect charts to test -CHARTS=($(find ./charts -maxdepth 1 -type d ! -name '.' ! -name 'charts' ! -name 'common' -exec basename {} \;)) -if [ ${#CHARTS[@]} -gt 0 ]; then - echo -e "\n${GREEN}๐Ÿ‘€ Found ${#CHARTS[@]} charts:${NC}" - for CHART in "${CHARTS[@]}"; do - echo -e " ${GREEN}โ€ข${NC} $CHART" - done -else - echo -e "${RED}โŒ Failed to find charts" - exit 1 -fi - -# Track results -PASSED_CHARTS=() -FAILED_CHARTS=() - -for CHART in "${CHARTS[@]}"; do - echo -e "\n${BLUE}๐Ÿ” Testing ${CHART} chart...${NC}" - - CHART_PATH="${CHARTS_DIR}/${CHART}" - - if [ ! -d "$CHART_PATH" ]; then - echo -e "${RED}โŒ Chart directory not found: $CHART_PATH${NC}" - FAILED_CHARTS+=("$CHART") - continue - fi - - if [ ! -d "$CHART_PATH/tests" ]; then - echo -e "${YELLOW}โš ๏ธ No tests directory found for $CHART${NC}" - FAILED_CHARTS+=("$CHART") - continue - fi - - # Update dependencies first - echo "๐Ÿ“ฆ Updating dependencies for $CHART..." - if ! helm dependency update "$CHART_PATH" >/dev/null 2> >(grep -vE '^(Pulled:|Digest:)' >&2); then - echo -e "${RED}โŒ Failed to update dependencies for $CHART${NC}" - FAILED_CHARTS+=("$CHART") - continue - fi - - # Run tests - if helm unittest "$CHART_PATH"; then - echo -e "${GREEN}โœ… $CHART tests passed${NC}" - PASSED_CHARTS+=("$CHART") - else - echo -e "${RED}โŒ $CHART tests failed${NC}" - FAILED_CHARTS+=("$CHART") - fi -done - -# Summary -echo -e "\n๐Ÿ“Š Test Summary" -echo "===============" -if [ ${#PASSED_CHARTS[@]} -gt 0 ]; then - echo -e "${GREEN}โœ… Passed: ${#PASSED_CHARTS[@]}${NC}" - for CHART in "${PASSED_CHARTS[@]}"; do - echo -e " ${GREEN}โ€ข${NC} $CHART" - done -fi - -if [ ${#FAILED_CHARTS[@]} -gt 0 ]; then - echo -e "${RED}โŒ Failed: ${#FAILED_CHARTS[@]}${NC}" - for CHART in "${FAILED_CHARTS[@]}"; do - echo -e " ${RED}โ€ข${NC} $CHART" - done -fi - -if [ ${#FAILED_CHARTS[@]} -eq 0 ]; then - echo -e "\n${GREEN}๐ŸŽ‰ All tests passed!${NC}" - exit 0 -else - echo -e "\n${RED}๐Ÿ’ฅ Some tests failed. Check the output above for details.${NC}" - exit 1 -fi \ No newline at end of file diff --git a/test-charts.sh b/test-charts.sh index c8e42156..4f63de50 100755 --- a/test-charts.sh +++ b/test-charts.sh @@ -161,7 +161,17 @@ test_chart() { # Test template rendering echo "๐Ÿ“ Testing template rendering..." - if ! helm template test-release . --debug > /tmp/rendered-$chart.yaml; then + + # Check for CI values files + CI_VALUES_ARGS="" + if [ -d "ci" ] && [ "$(ls -A ci/*.yaml 2>/dev/null)" ]; then + echo "๐Ÿ“‹ Found CI values files, using them for testing" + for values_file in ci/*.yaml; do + CI_VALUES_ARGS="$CI_VALUES_ARGS -f $values_file" + done + fi + + if ! helm template test-release . $CI_VALUES_ARGS --debug > /tmp/rendered-$chart.yaml; then echo -e "${RED}โŒ Template rendering failed for $chart${NC}" return 1 fi @@ -172,8 +182,10 @@ test_chart() { return 1 fi - # Helm unittest (if tests exist) - if [ -d "tests" ] && [ "$(ls -A tests 2>/dev/null)" ]; then + # Helm unittest (if tests exist and not disabled) + if [ -f ".disable-unittest" ]; then + echo -e "${YELLOW}โ„น๏ธ Unittest disabled for $chart (.disable-unittest found)${NC}" + elif [ -d "tests" ] && [ "$(ls -A tests 2>/dev/null)" ]; then echo "๐Ÿงช Running Helm unittest..." if ! helm unittest .; then echo -e "${RED}โŒ Helm unittest failed for $chart${NC}" @@ -193,14 +205,29 @@ test_chart() { # Install chart local namespace="test-$chart" local release_name="test-$chart" - + echo "๐Ÿš€ Installing chart..." + echo " Release: $release_name" + echo " Namespace: $namespace" + echo " Timeout: 600s" + if [ -n "$CI_VALUES_ARGS" ]; then + echo " Values files: $CI_VALUES_ARGS" + fi + echo "" + if ! helm install "$release_name" . \ + $CI_VALUES_ARGS \ --create-namespace \ --namespace "$namespace" \ --wait \ - --timeout=600s; then + --timeout=600s \ + --debug; then echo -e "${RED}โŒ Chart installation failed for $chart${NC}" + echo -e "\n${YELLOW}๐Ÿ“‹ Checking resources in namespace...${NC}" + kubectl get all -n "$namespace" || true + kubectl describe pods -n "$namespace" || true + echo -e "\n${YELLOW}๐Ÿ“‹ Recent events:${NC}" + kubectl get events -n "$namespace" --sort-by='.lastTimestamp' || true return 1 fi @@ -208,10 +235,38 @@ test_chart() { echo "๐Ÿ” Verifying installation..." helm list -n "$namespace" kubectl get all -n "$namespace" - + # Wait for pods to be ready (with timeout) echo "โณ Waiting for pods to be ready..." - kubectl wait --for=condition=Ready pods --all -n "$namespace" --timeout=300s || true + + # Show pod status while waiting + local max_wait=300 + local elapsed=0 + local interval=10 + + while [ $elapsed -lt $max_wait ]; do + echo " [$elapsed/${max_wait}s] Checking pod status..." + kubectl get pods -n "$namespace" -o wide + + # Check if all pods are ready + if kubectl wait --for=condition=Ready pods --all -n "$namespace" --timeout=1s 2>/dev/null; then + echo -e "${GREEN}โœ… All pods are ready${NC}" + break + fi + + # Show recent events for debugging + echo " Recent events:" + kubectl get events -n "$namespace" --sort-by='.lastTimestamp' | tail -5 + + sleep $interval + elapsed=$((elapsed + interval)) + done + + if [ $elapsed -ge $max_wait ]; then + echo -e "${YELLOW}โš ๏ธ Timeout waiting for pods. Current status:${NC}" + kubectl get pods -n "$namespace" -o wide + kubectl describe pods -n "$namespace" + fi # Run tests if they exist if [ -d "tests" ] && [ "$(ls -A tests 2>/dev/null)" ]; then @@ -225,7 +280,7 @@ test_chart() { # Test upgrade echo "๐Ÿ”„ Testing chart upgrade..." - if ! helm upgrade "$release_name" . -n "$namespace" --wait --timeout=300s; then + if ! helm upgrade "$release_name" . $CI_VALUES_ARGS -n "$namespace" --wait --timeout=300s; then echo -e "${YELLOW}โš ๏ธ Chart upgrade failed for $chart${NC}" fi diff --git a/update-appversion.sh b/update-appversion.sh new file mode 100755 index 00000000..83cecd6e --- /dev/null +++ b/update-appversion.sh @@ -0,0 +1,360 @@ +#!/bin/bash + +# Update AppVersion script for Helm charts +# This script updates the appVersion in Chart.yaml with the image.tag from values.yaml +# It's designed to be triggered after generate-changelog.sh + +set -eo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored messages +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" || echo "[INFO] $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check required tools +check_dependencies() { + local missing_deps=() + + if ! command -v yq &> /dev/null; then + missing_deps+=("yq") + fi + + if [ ${#missing_deps[@]} -gt 0 ]; then + log_error "Missing required dependencies: ${missing_deps[*]}" + log_error "Please install yq: https://github.com/mikefarah/yq" + exit 1 + fi +} + +# Function to extract version from image tag +# This function handles various tag formats and ensures only semantic versions are returned: +# - "1.2.3" -> "1.2.3" +# - "1.2.3@sha256:..." -> "1.2.3" +# - "v1.2.3" -> "1.2.3" +# - "v1.2.3@sha256:..." -> "1.2.3" +# - "1.2.3-alpine" -> "1.2.3" (removes non-semver suffixes) +# - "1.2.3-alpha.1" -> "1.2.3-alpha.1" (keeps semver pre-release) +# - "RELEASE.2025-09-07T16-13-09Z" -> null (not semver) +# - "464e93ac" -> null (not semver) +extract_version_from_tag() { + local tag="$1" + + # Remove quotes if present + tag=$(echo "$tag" | sed 's/^"//;s/"$//') + + # Split by @ to remove digest if present + tag=$(echo "$tag" | cut -d'@' -f1) + + # Remove 'v' prefix if present (but keep it for versions that start with v followed by number) + if [[ "$tag" =~ ^v[0-9] ]]; then + tag=$(echo "$tag" | sed 's/^v//') + fi + + # Extract semantic version - prioritize core version (MAJOR.MINOR.PATCH) + # Only keep pre-release if it follows strict semver rules + + # First, try to extract the core version (MAJOR.MINOR.PATCH or MAJOR.MINOR) + local core_version + core_version=$(echo "$tag" | grep -oE '^[0-9]+\.[0-9]+(\.[0-9]+)?' || echo "") + + if [ -z "$core_version" ]; then + # No valid core version found + echo "" + return + fi + + # If we only have MAJOR.MINOR, convert to MAJOR.MINOR.0 for strict semver compliance + if [[ "$core_version" =~ ^[0-9]+\.[0-9]+$ ]]; then + core_version="${core_version}.0" + fi + + # Check if there's anything after the core version + local remaining_part + remaining_part=$(echo "$tag" | sed "s/^$(echo "$core_version" | sed 's/\.0$//')//") + + if [ -z "$remaining_part" ]; then + # Just the core version, perfect + echo "$core_version" + return + fi + + # Check if the remaining part is a valid semver pre-release/build + # Valid pre-release: -alpha, -alpha.1, -rc.1, -beta.2 (alphanumeric + hyphen, no leading zeros in numeric parts) + if [[ "$remaining_part" =~ ^-([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*)(\+[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*)?$ ]]; then + local prerelease_part="${BASH_REMATCH[1]}" + + # Validate each identifier in pre-release (no leading zeros in numeric identifiers) + local valid_prerelease=true + IFS='.' read -ra IDENTIFIERS <<< "$prerelease_part" + for identifier in "${IDENTIFIERS[@]}"; do + # Check if it's a numeric identifier with leading zero (invalid) + if [[ "$identifier" =~ ^0[0-9]+$ ]]; then + valid_prerelease=false + break + fi + # Check for mixed patterns like "alpine3", "management", "pg17" which are not valid semver + if [[ "$identifier" =~ [a-zA-Z][0-9] ]] || [[ "$identifier" =~ [0-9][a-zA-Z] ]]; then + valid_prerelease=false + break + fi + # Check for words like "management", "alpine" (common non-semver suffixes) + if [[ "$identifier" =~ ^(alpine|management|ubuntu|debian|slim|fat)$ ]]; then + valid_prerelease=false + break + fi + done + + if [ "$valid_prerelease" = true ]; then + # Valid semver pre-release, keep the full version + echo "${core_version}${remaining_part}" + else + # Invalid pre-release, return just core version + echo "$core_version" + fi + else + # Not a valid semver pre-release format, return just core version + echo "$core_version" + fi +} + +# Function to update appVersion in Chart.yaml +update_chart_appversion() { + local chart_name="$1" + local chart_dir="charts/${chart_name}" + local chart_yaml="${chart_dir}/Chart.yaml" + local values_yaml="${chart_dir}/values.yaml" + + log_info "Processing chart: $chart_name" + + # Validate chart directory exists + if [ ! -d "$chart_dir" ]; then + log_error "Chart directory not found: $chart_dir" + return 1 + fi + + # Validate Chart.yaml exists + if [ ! -f "$chart_yaml" ]; then + log_error "Chart.yaml not found: $chart_yaml" + return 1 + fi + + # Validate values.yaml exists + if [ ! -f "$values_yaml" ]; then + log_error "values.yaml not found: $values_yaml" + return 1 + fi + + # Extract current appVersion from Chart.yaml + local current_app_version + current_app_version=$(yq eval '.appVersion' "$chart_yaml" 2>/dev/null || echo "null") + + if [ "$current_app_version" = "null" ]; then + log_warn "No appVersion found in $chart_yaml" + current_app_version="(not set)" + fi + + # Extract image tag from values.yaml + # Try different possible paths for the image tag + local image_tag="" + + # Try image.tag first (most common) + image_tag=$(yq eval '.image.tag' "$values_yaml" 2>/dev/null || echo "null") + + # If not found, try other common patterns + if [ "$image_tag" = "null" ]; then + # Try under different sections that might contain image configurations + for path in \ + '.*.image.tag' \ + '.images.*.tag' \ + '.global.image.tag' \ + '.*.*.image.tag'; do + + local temp_tag + temp_tag=$(yq eval "$path" "$values_yaml" 2>/dev/null | head -1 || echo "null") + if [ "$temp_tag" != "null" ] && [ -n "$temp_tag" ]; then + image_tag="$temp_tag" + log_info "Found image tag at path: $path" + break + fi + done + fi + + if [ "$image_tag" = "null" ] || [ -z "$image_tag" ]; then + log_warn "No image tag found in $values_yaml for chart $chart_name" + log_warn "Skipping appVersion update" + return 0 + fi + + log_info "Found image tag: $image_tag" + + # Extract version from the image tag + local new_app_version + new_app_version=$(extract_version_from_tag "$image_tag") + + if [ -z "$new_app_version" ]; then + log_warn "Could not extract valid semantic version from image tag: $image_tag" + log_warn "Skipping appVersion update for chart $chart_name" + return 0 + fi + + log_info "Extracted semantic version: $new_app_version" + + # Check if appVersion needs to be updated + if [ "$current_app_version" = "\"$new_app_version\"" ] || [ "$current_app_version" = "$new_app_version" ]; then + log_info "appVersion is already up to date ($new_app_version)" + return 0 + fi + + # Update appVersion in Chart.yaml + log_info "Updating appVersion from $current_app_version to $new_app_version" + + # Use yq to update the appVersion + yq eval ".appVersion = \"$new_app_version\"" -i "$chart_yaml" + + if [ $? -eq 0 ]; then + log_info "Successfully updated appVersion in $chart_yaml" + else + log_error "Failed to update appVersion in $chart_yaml" + return 1 + fi + + return 0 +} + +# Function to process all charts or specific charts +process_charts() { + local chart_names=("$@") + local success_count=0 + local fail_count=0 + local skip_count=0 + + for chart_name in "${chart_names[@]}"; do + # Skip the 'common' chart as it typically doesn't have an image + if [ "$chart_name" = "common" ]; then + log_info "Skipping 'common' chart (no image expected)" + skip_count=$((skip_count + 1)) + continue + fi + + if update_chart_appversion "$chart_name"; then + success_count=$((success_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + done + + # Summary + log_info "AppVersion update complete" + log_info "Success: $success_count, Failed: $fail_count, Skipped: $skip_count" + + if [ $fail_count -gt 0 ]; then + return 1 + fi + + return 0 +} + +# Main script logic +main() { + log_info "Starting appVersion update" + + # Check dependencies + check_dependencies + + # Parse command line arguments + local chart_names=() + local update_all=false + + while [[ $# -gt 0 ]]; do + case $1 in + --chart) + chart_names+=("$2") + shift 2 + ;; + --all) + update_all=true + shift + ;; + --help|-h) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Description:" + echo " Updates the appVersion in Chart.yaml with the version extracted from image.tag in values.yaml" + echo " Designed to be run after generate-changelog.sh to keep appVersion in sync with image versions" + echo "" + echo "Options:" + echo " --chart CHART_NAME Update appVersion for specific chart (can be specified multiple times)" + echo " --all Update appVersion for all charts" + echo " --help, -h Show this help message" + echo "" + echo "Examples:" + echo " $0 --chart nginx --chart redis" + echo " $0 --all" + echo "" + echo "Version Extraction Logic:" + echo " - Removes SHA256 digest: '1.2.3@sha256:...' -> '1.2.3'" + echo " - Removes 'v' prefix: 'v1.2.3' -> '1.2.3'" + echo " - Extracts semantic version only: '1.2.3-alpine' -> '1.2.3'" + echo " - Preserves semver pre-release: '1.2.3-alpha.1' -> '1.2.3-alpha.1'" + echo " - Skips non-semver tags: 'RELEASE.2025-09-07' -> (skipped)" + echo " - Skips git hashes: '464e93ac' -> (skipped)" + echo "" + echo "Supported tag paths in values.yaml:" + echo " - image.tag (most common)" + echo " - *.image.tag" + echo " - images.*.tag" + echo " - global.image.tag" + exit 0 + ;; + *) + log_error "Unknown option: $1" + echo "Use --help for usage information" + exit 1 + ;; + esac + done + + # If --all flag is set, find all charts + if [ "$update_all" = true ]; then + log_info "Discovering all charts..." + while IFS= read -r chart_dir; do + local chart_name + chart_name=$(basename "$chart_dir") + chart_names+=("$chart_name") + done < <(find ./charts -mindepth 1 -maxdepth 1 -type d) + fi + + # Validate we have charts to process + if [ ${#chart_names[@]} -eq 0 ]; then + log_error "No charts specified. Use --chart, --all, or --help" + exit 1 + fi + + log_info "Processing ${#chart_names[@]} chart(s): ${chart_names[*]}" + + # Process charts + if process_charts "${chart_names[@]}"; then + log_info "All updates completed successfully" + exit 0 + else + log_error "Some updates failed" + exit 1 + fi +} + +# Run main function +main "$@" \ No newline at end of file