Compare commits
53 Commits
codex/veri
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1819905253 | ||
|
|
54edf1d219 | ||
|
|
eb7f01e0ac | ||
|
|
f14bcd8c4d | ||
|
|
60d95acfd9 | ||
|
|
fd4069e5cd | ||
|
|
8de8726693 | ||
|
|
094593efb9 | ||
|
|
61c5ba3146 | ||
|
|
7e4b1061d9 | ||
|
|
6cbca2e23b | ||
|
|
c3eb670c3c | ||
|
|
7765759e3b | ||
|
|
45f2945dde | ||
|
|
17186b6222 | ||
|
|
446dd16c03 | ||
|
|
2183d475a6 | ||
|
|
a7b97d3130 | ||
|
|
befefc83f0 | ||
|
|
fd31184f53 | ||
|
|
8f8f83da6d | ||
|
|
6bce9d16a1 | ||
|
|
1655304e70 | ||
|
|
19bbff1052 | ||
|
|
fb1744cba0 | ||
|
|
65cdef366a | ||
|
|
9178f9a2c8 | ||
|
|
a151cb8496 | ||
|
|
4c44439825 | ||
|
|
248219298f | ||
|
|
3da8cf8a29 | ||
|
|
e2ed57e974 | ||
|
|
14748088a1 | ||
|
|
03b7ba02fc | ||
|
|
6d4de96a7d | ||
|
|
f7fba192b1 | ||
|
|
86e8fadf75 | ||
|
|
3b1b4c234b | ||
|
|
5fbad3f82d | ||
|
|
36fbbc9aaf | ||
|
|
68967496c6 | ||
|
|
6b48d60354 | ||
|
|
4b27cded56 | ||
|
|
909ec6b79b | ||
|
|
8b500b8c9b | ||
|
|
a85263830b | ||
|
|
07727ed086 | ||
|
|
95b2ea8362 | ||
|
|
6153128c5c | ||
|
|
8c17aeed82 | ||
|
|
167404f709 | ||
|
|
e2c50547b2 | ||
|
|
702087349c |
36
.github/workflows/build-chart-multi-model-LLM.yaml
vendored
Normal file
36
.github/workflows/build-chart-multi-model-LLM.yaml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
name: build chart multi-model llm
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'oci/multi-model-LLM/**'
|
||||||
|
- '.github/workflows/build-chart-multi-model-LLM.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
CHART_DIR: oci/multi-model-LLM/charts/model-serving
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-and-package:
|
||||||
|
name: Lint and package Helm chart
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up Helm
|
||||||
|
uses: azure/setup-helm@v4
|
||||||
|
with:
|
||||||
|
version: v3.14.4
|
||||||
|
- name: Helm lint
|
||||||
|
run: helm lint $CHART_DIR
|
||||||
|
- name: Helm package
|
||||||
|
run: helm package $CHART_DIR --version 0.1.0 --app-version 0.1.0 -d oci/multi-model-LLM/charts
|
||||||
|
- name: Upload chart artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: model-serving-chart
|
||||||
|
path: oci/multi-model-LLM/charts/model-serving-0.1.0.tgz
|
||||||
29
.github/workflows/build-ci-image-Ollama.yaml
vendored
Normal file
29
.github/workflows/build-ci-image-Ollama.yaml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: build image ollama
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'oci/base/cuda/Ollama/Dockerfile'
|
||||||
|
- '.github/workflows/build-ci-image-Ollama.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_REPO: "artifact.svc.plus"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-ollama:
|
||||||
|
name: Build Ollama image
|
||||||
|
uses: svc-design/actions/.github/workflows/build-images.yaml@main
|
||||||
|
with:
|
||||||
|
method: 'docker'
|
||||||
|
registry_addr: "harbor.onwalk.net"
|
||||||
|
dockerfile_path: 'oci/base/cuda/Ollama'
|
||||||
|
image_name: 'public/base/cuda/ollama'
|
||||||
|
image_tag: 'latest'
|
||||||
|
secrets:
|
||||||
|
artifactory_sa: ${{ secrets.REPO_USER }}
|
||||||
|
artifactory_pw: ${{ secrets.HELM_REPO_PASSWORD }}
|
||||||
29
.github/workflows/build-ci-image-SGLang.yaml
vendored
Normal file
29
.github/workflows/build-ci-image-SGLang.yaml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: build image cuda sglang
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'oci/base/cuda/SGLang/Dockerfile'
|
||||||
|
- '.github/workflows/build-ci-image-SGLang.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_REPO: "artifact.svc.plus"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-sglang:
|
||||||
|
name: Build CUDA SGLang image
|
||||||
|
uses: svc-design/actions/.github/workflows/build-images.yaml@main
|
||||||
|
with:
|
||||||
|
method: 'docker'
|
||||||
|
registry_addr: "harbor.onwalk.net"
|
||||||
|
dockerfile_path: 'oci/base/cuda/SGLang'
|
||||||
|
image_name: 'public/base/cuda/sglang'
|
||||||
|
image_tag: 'cuda12'
|
||||||
|
secrets:
|
||||||
|
artifactory_sa: ${{ secrets.REPO_USER }}
|
||||||
|
artifactory_pw: ${{ secrets.HELM_REPO_PASSWORD }}
|
||||||
29
.github/workflows/build-ci-image-vLLM.yaml
vendored
Normal file
29
.github/workflows/build-ci-image-vLLM.yaml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: build image cuda vllm
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'oci/base/cuda/vLLM/Dockerfile'
|
||||||
|
- '.github/workflows/build-ci-image-vLLM.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_REPO: "artifact.svc.plus"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-vllm:
|
||||||
|
name: Build CUDA vLLM image
|
||||||
|
uses: svc-design/actions/.github/workflows/build-images.yaml@main
|
||||||
|
with:
|
||||||
|
method: 'docker'
|
||||||
|
registry_addr: "harbor.onwalk.net"
|
||||||
|
dockerfile_path: 'oci/base/cuda/vLLM'
|
||||||
|
image_name: 'public/base/cuda/vllm'
|
||||||
|
image_tag: 'cuda12'
|
||||||
|
secrets:
|
||||||
|
artifactory_sa: ${{ secrets.REPO_USER }}
|
||||||
|
artifactory_pw: ${{ secrets.HELM_REPO_PASSWORD }}
|
||||||
216
.github/workflows/cloud-neutra-golden-image.yaml
vendored
Normal file
216
.github/workflows/cloud-neutra-golden-image.yaml
vendored
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
name: Cloud-Neutra Golden Image Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
edition:
|
||||||
|
description: "Golden Image Edition"
|
||||||
|
type: choice
|
||||||
|
options: ["base", "container", "k3s", "sealos", "sealos-gpu"]
|
||||||
|
default: "container"
|
||||||
|
ubuntu_version:
|
||||||
|
description: "Ubuntu LTS version"
|
||||||
|
type: choice
|
||||||
|
options: ["2204", "2404"]
|
||||||
|
default: "2404"
|
||||||
|
cpu_arch:
|
||||||
|
description: "CPU Architecture"
|
||||||
|
type: choice
|
||||||
|
options: ["amd64", "arm64"]
|
||||||
|
default: "amd64"
|
||||||
|
|
||||||
|
schedule:
|
||||||
|
- cron: "0 18 1 * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
BASE_REGION: ap-northeast-1
|
||||||
|
TARGET_REGIONS: "ap-northeast-1 ap-east-1 us-west-1"
|
||||||
|
PROJECT_TAG: Cloud-Neutra
|
||||||
|
PACKER_TEMPLATE_ROOT: packer/Cloud-Neutra-VMs/templates
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
##########################################################################
|
||||||
|
# Stage 1 — Lint / Validate / Security
|
||||||
|
##########################################################################
|
||||||
|
lint:
|
||||||
|
name: Lint & Validate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: actionlint
|
||||||
|
uses: raven-actions/actionlint@v2
|
||||||
|
with:
|
||||||
|
files: ".github/workflows/cloud-neutra-golden-image.yaml"
|
||||||
|
matcher: false
|
||||||
|
cache: false
|
||||||
|
fail-on-error: true
|
||||||
|
flags: "-ignore SC2086"
|
||||||
|
|
||||||
|
- name: Install tools
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y shellcheck jq
|
||||||
|
|
||||||
|
- name: Packer FMT
|
||||||
|
run: packer fmt -recursive .
|
||||||
|
|
||||||
|
- name: Packer Validate
|
||||||
|
run: packer validate "${PACKER_TEMPLATE_ROOT}"
|
||||||
|
|
||||||
|
- name: gitleaks Scan
|
||||||
|
uses: gitleaks/gitleaks-action@v2
|
||||||
|
with:
|
||||||
|
args: detect --no-git -v
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Stage 2 — Build Golden Image
|
||||||
|
##########################################################################
|
||||||
|
build:
|
||||||
|
name: Build Golden AMI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: lint
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
ami_id: ${{ steps.packer_build.outputs.ami_id }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- edition: base
|
||||||
|
ubuntu_version: "2204"
|
||||||
|
cpu_arch: amd64
|
||||||
|
- edition: base
|
||||||
|
ubuntu_version: "2204"
|
||||||
|
cpu_arch: arm64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# must be step-level to allow matrix.*
|
||||||
|
- name: Skip matrix items not requested
|
||||||
|
if: >
|
||||||
|
github.event_name == 'schedule' ||
|
||||||
|
(
|
||||||
|
github.event_name == 'workflow_dispatch' &&
|
||||||
|
github.event.inputs.edition == matrix.edition &&
|
||||||
|
github.event.inputs.ubuntu_version == matrix.ubuntu_version &&
|
||||||
|
github.event.inputs.cpu_arch == matrix.cpu_arch
|
||||||
|
)
|
||||||
|
run: echo "Matrix item selected."
|
||||||
|
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v4
|
||||||
|
with:
|
||||||
|
aws-region: ${{ env.BASE_REGION }}
|
||||||
|
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ROOT_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_ROOT_SECRET_ACCESS_KEY }}
|
||||||
|
mask-aws-account-id: true
|
||||||
|
|
||||||
|
- name: Setup Packer
|
||||||
|
uses: hashicorp/setup-packer@v3
|
||||||
|
|
||||||
|
- name: Build AMI
|
||||||
|
id: packer_build
|
||||||
|
env:
|
||||||
|
EDITION: ${{ matrix.edition }}
|
||||||
|
UBUNTU_VERSION: ${{ matrix.ubuntu_version }}
|
||||||
|
CPU_ARCH: ${{ matrix.cpu_arch }}
|
||||||
|
run: |
|
||||||
|
TEMPLATE="${PACKER_TEMPLATE_ROOT}/${EDITION}/ubuntu-${UBUNTU_VERSION}-${EDITION}.pkr.hcl"
|
||||||
|
echo "Using template: ${TEMPLATE}"
|
||||||
|
|
||||||
|
packer build \
|
||||||
|
-color=false \
|
||||||
|
-var "cpu_arch=${CPU_ARCH}" \
|
||||||
|
-var "edition=${EDITION}" \
|
||||||
|
-var "ubuntu_version=${UBUNTU_VERSION}" \
|
||||||
|
"${TEMPLATE}" | tee packer.log
|
||||||
|
|
||||||
|
AMI_ID=$(grep 'AMI:' packer.log | awk '{print $2}' | tail -n1 || true)
|
||||||
|
|
||||||
|
if [ -z "${AMI_ID}" ]; then
|
||||||
|
echo "ERROR: Cannot parse AMI ID"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ami_id=${AMI_ID}" >> "${GITHUB_OUTPUT}"
|
||||||
|
|
||||||
|
- name: Upload Logs
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: packer-build-log
|
||||||
|
path: packer.log
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Stage 3 — QA Test
|
||||||
|
##########################################################################
|
||||||
|
test:
|
||||||
|
name: Test Built AMI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
|
||||||
|
# must re-expose build's output for downstream needs.*
|
||||||
|
outputs:
|
||||||
|
ami_id: ${{ needs.build.outputs.ami_id }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Placeholder test
|
||||||
|
run: |
|
||||||
|
echo "TODO: Future QA test"
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Stage 4 — AMI Replication + Retention
|
||||||
|
##########################################################################
|
||||||
|
distribute:
|
||||||
|
name: Replicate & Retain AMI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: test
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- edition: base
|
||||||
|
ubuntu_version: "2204"
|
||||||
|
cpu_arch: amd64
|
||||||
|
- edition: base
|
||||||
|
ubuntu_version: "2204"
|
||||||
|
cpu_arch: arm64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v4
|
||||||
|
with:
|
||||||
|
aws-region: ${{ env.BASE_REGION }}
|
||||||
|
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ROOT_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_ROOT_SECRET_ACCESS_KEY }}
|
||||||
|
|
||||||
|
- name: Distribute AMI
|
||||||
|
env:
|
||||||
|
BASE_REGION: ${{ env.BASE_REGION }}
|
||||||
|
TARGET_REGIONS: ${{ env.TARGET_REGIONS }}
|
||||||
|
PROJECT_TAG: ${{ env.PROJECT_TAG }}
|
||||||
|
EDITION: ${{ matrix.edition }}
|
||||||
|
UBUNTU_VERSION: ${{ matrix.ubuntu_version }}
|
||||||
|
CPU_ARCH: ${{ matrix.cpu_arch }}
|
||||||
|
AMI_ID: ${{ needs.test.outputs.ami_id }}
|
||||||
|
run: |
|
||||||
|
bash packer/scripts/common/ami-replicate.sh \
|
||||||
|
"${AMI_ID}" "${EDITION}" "${UBUNTU_VERSION}" "${CPU_ARCH}" \
|
||||||
|
"${BASE_REGION}" "${TARGET_REGIONS}" "${PROJECT_TAG}"
|
||||||
|
|
||||||
|
- name: Retention
|
||||||
|
env:
|
||||||
|
TARGET_REGIONS: ${{ env.TARGET_REGIONS }}
|
||||||
|
PROJECT_TAG: ${{ env.PROJECT_TAG }}
|
||||||
|
EDITION: ${{ matrix.edition }}
|
||||||
|
UBUNTU_VERSION: ${{ matrix.ubuntu_version }}
|
||||||
|
CPU_ARCH: ${{ matrix.cpu_arch }}
|
||||||
|
run: |
|
||||||
|
bash packer/scripts/common/ami-retention.sh \
|
||||||
|
"${EDITION}" "${UBUNTU_VERSION}" "${CPU_ARCH}" "${PROJECT_TAG}" "${TARGET_REGIONS}"
|
||||||
@ -53,14 +53,7 @@ jobs:
|
|||||||
id: resolve
|
id: resolve
|
||||||
env:
|
env:
|
||||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||||
run: |
|
run: bash scripts/offline-argocd/resolve_chart_version.sh
|
||||||
set -euo pipefail
|
|
||||||
if [ -n "${OVERRIDE_CHART_VERSION}" ]; then
|
|
||||||
CHART_VERSION="${OVERRIDE_CHART_VERSION}"
|
|
||||||
else
|
|
||||||
CHART_VERSION=$(helm search repo argo/argo-cd --versions | awk 'NR==2{print $2}')
|
|
||||||
fi
|
|
||||||
echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Prepare directories
|
- name: Prepare directories
|
||||||
run: |
|
run: |
|
||||||
@ -71,45 +64,7 @@ jobs:
|
|||||||
- name: Stage installer script
|
- name: Stage installer script
|
||||||
env:
|
env:
|
||||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||||
run: |
|
run: bash scripts/offline-argocd/stage_installer.sh
|
||||||
set -euo pipefail
|
|
||||||
cat <<'SCRIPT' > argocd-offline-package/scripts/install-argocd.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
||||||
CHART_DIR="${ROOT_DIR}/charts/argo-cd"
|
|
||||||
IMAGES_DIR="${ROOT_DIR}/images"
|
|
||||||
RELEASE_NAME="${RELEASE_NAME:-argo-cd}"
|
|
||||||
NAMESPACE="${NAMESPACE:-argocd}"
|
|
||||||
|
|
||||||
if command -v nerdctl >/dev/null 2>&1; then
|
|
||||||
LOADER="nerdctl"
|
|
||||||
elif command -v docker >/dev/null 2>&1; then
|
|
||||||
LOADER="docker"
|
|
||||||
else
|
|
||||||
echo "Either docker or nerdctl is required to load images." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
for tar in "${IMAGES_DIR}"/*.tar; do
|
|
||||||
[ -f "$tar" ] || continue
|
|
||||||
echo "Loading image: $tar"
|
|
||||||
"$LOADER" load -i "$tar"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Installing/Upgrading Argo CD release ${RELEASE_NAME} in namespace ${NAMESPACE}"
|
|
||||||
helm upgrade --install "${RELEASE_NAME}" "${CHART_DIR}" \
|
|
||||||
--namespace "${NAMESPACE}" \
|
|
||||||
--create-namespace \
|
|
||||||
"$@"
|
|
||||||
SCRIPT
|
|
||||||
chmod +x argocd-offline-package/scripts/install-argocd.sh
|
|
||||||
cat <<EOFMETA > argocd-offline-package/metadata/INFO
|
|
||||||
chart: argo/argo-cd
|
|
||||||
chart_version: ${CHART_VERSION}
|
|
||||||
created_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
EOFMETA
|
|
||||||
|
|
||||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||||
run: |
|
run: |
|
||||||
@ -120,25 +75,8 @@ EOFMETA
|
|||||||
- name: Pull & export required images
|
- name: Pull & export required images
|
||||||
env:
|
env:
|
||||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||||
run: |
|
MATRIX_ARCH: ${{ matrix.arch }}
|
||||||
set -euo pipefail
|
run: bash scripts/offline-argocd/pull_and_export_images.sh
|
||||||
PLATFORM="linux/${{ matrix.arch }}"
|
|
||||||
helm template argo argo/argo-cd --version "${CHART_VERSION}" > manifest.yaml
|
|
||||||
mapfile -t images < <(grep -oP 'image:\s*"?\K([^"\s]+)' manifest.yaml | sort -u || true)
|
|
||||||
rm -f manifest.yaml
|
|
||||||
for img in "${images[@]}"; do
|
|
||||||
[ -n "$img" ] || continue
|
|
||||||
if [[ "$img" == *"{{"* ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
echo "Pulling $img for ${PLATFORM}"
|
|
||||||
if ! docker pull --platform "${PLATFORM}" "$img"; then
|
|
||||||
echo "::warning::Failed to pull $img for ${PLATFORM}, skipping" >&2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
safe=$(echo "$img" | tr '/:' '-_')
|
|
||||||
docker save "$img" -o "argocd-offline-package/images/${safe}.tar"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Download Helm chart
|
- name: Download Helm chart
|
||||||
env:
|
env:
|
||||||
@ -186,7 +124,7 @@ EOFMETA
|
|||||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||||
REMOTE_ROOT: /data/update-server/argocd
|
REMOTE_ROOT: /data/update-server/offline-package/argocd/
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
@ -238,15 +176,7 @@ EOFMETA
|
|||||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Rsync release assets to remote
|
- name: Rsync release assets to remote
|
||||||
run: |
|
run: bash scripts/offline-argocd/rsync_release_assets.sh
|
||||||
set -euo pipefail
|
|
||||||
REMOTE_DIR="${REMOTE_ROOT}/${TAG_NAME}"
|
|
||||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "mkdir -p '${REMOTE_DIR}'"
|
|
||||||
echo "Rsync -> ${VPS_HOST}:${REMOTE_DIR}/"
|
|
||||||
rsync -av -e "ssh -i ~/.ssh/id_rsa" \
|
|
||||||
release-artifacts/amd64/offline-package-argocd-amd64.tar.gz \
|
|
||||||
release-artifacts/arm64/offline-package-argocd-arm64.tar.gz \
|
|
||||||
"${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
|
||||||
|
|
||||||
retention:
|
retention:
|
||||||
name: Remote retention (keep latest 3)
|
name: Remote retention (keep latest 3)
|
||||||
@ -267,20 +197,4 @@ EOFMETA
|
|||||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Prune old versions on remote (keep 3)
|
- name: Prune old versions on remote (keep 3)
|
||||||
run: |
|
run: bash scripts/offline-argocd/prune_remote_versions.sh
|
||||||
set -euo pipefail
|
|
||||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" bash -lc '
|
|
||||||
set -euo pipefail
|
|
||||||
cd "'"${REMOTE_ROOT}"'" || exit 0
|
|
||||||
keep=3
|
|
||||||
mapfile -t all < <(ls -1 | grep -E "^(offline-argocd-|v[0-9]+\.)" | sort -V -r || true)
|
|
||||||
if [ "${#all[@]}" -le "$keep" ]; then
|
|
||||||
echo "Nothing to prune. Count=${#all[@]}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
to_delete=("${all[@]:keep}")
|
|
||||||
echo "Pruning old versions: ${to_delete[*]}"
|
|
||||||
for d in "${to_delete[@]}"; do
|
|
||||||
rm -rf -- "$d"
|
|
||||||
done
|
|
||||||
'
|
|
||||||
|
|||||||
159
.github/workflows/offline-package-autogen-studio.yaml
vendored
Normal file
159
.github/workflows/offline-package-autogen-studio.yaml
vendored
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
name: Build Offline AutoGen Studio Installer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'gitops/scripts/autogen-studio/**'
|
||||||
|
- '.github/workflows/offline-package-autogen-studio.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-autogen-studio-<run_number>"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
autogen_tag:
|
||||||
|
description: "AutoGen Studio container tag (default: latest)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-offline-autogen-studio
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-offline-installer:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64, arm64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
autogen_tag: ${{ steps.resolve.outputs.autogen_tag }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Resolve image tag
|
||||||
|
id: resolve
|
||||||
|
env:
|
||||||
|
INPUT_AUTOGEN_TAG: ${{ github.event.inputs.autogen_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
AUTOGEN_TAG=${INPUT_AUTOGEN_TAG:-latest}
|
||||||
|
echo "autogen_tag=${AUTOGEN_TAG}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Prepare directories
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
rm -rf offline-installer
|
||||||
|
mkdir -p offline-installer/{images,scripts}
|
||||||
|
|
||||||
|
- name: Stage compose file and scripts
|
||||||
|
env:
|
||||||
|
AUTOGEN_TAG: ${{ steps.resolve.outputs.autogen_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cp gitops/scripts/autogen-studio/docker-compose.yaml offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__AUTOGEN_TAG__/${AUTOGEN_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
cp gitops/scripts/autogen-studio/deploy-autogen-studio.sh offline-installer/scripts/
|
||||||
|
chmod +x offline-installer/scripts/deploy-autogen-studio.sh
|
||||||
|
cat <<'README' > offline-installer/README.md
|
||||||
|
# Offline AutoGen Studio Installer
|
||||||
|
|
||||||
|
This archive contains container images and helper assets for deploying AutoGen Studio with Docker Compose.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images.
|
||||||
|
- `images/`: Pre-pulled container images saved as tar archives.
|
||||||
|
- `scripts/deploy-autogen-studio.sh`: Helper script to load the images and manage the compose stack.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
1. Extract the archive on a host with Docker/nerdctl available.
|
||||||
|
2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-autogen-studio.sh load-images` to import the images with nerdctl.
|
||||||
|
3. Start the stack: `./scripts/deploy-autogen-studio.sh up`.
|
||||||
|
4. Access AutoGen Studio at http://localhost:9090.
|
||||||
|
|
||||||
|
Adjust the compose file as needed before running the helper script.
|
||||||
|
README
|
||||||
|
|
||||||
|
- name: Pull & export container images
|
||||||
|
env:
|
||||||
|
AUTOGEN_TAG: ${{ steps.resolve.outputs.autogen_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
image="autogenstudio/autogen-studio:${AUTOGEN_TAG}"
|
||||||
|
docker pull "$image"
|
||||||
|
safe=$(echo "$image" | tr '/:' '-_')
|
||||||
|
docker save "$image" -o "offline-installer/images/${safe}.tar"
|
||||||
|
|
||||||
|
- name: Package offline installer
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
tar -czf offline-package-autogen-studio-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-autogen-studio-${{ matrix.arch }}
|
||||||
|
path: offline-package-autogen-studio-${{ matrix.arch }}.tar.gz
|
||||||
|
|
||||||
|
test-offline-installer:
|
||||||
|
needs: build-offline-installer
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-autogen-studio-${{ matrix.arch }}
|
||||||
|
path: offline-test
|
||||||
|
|
||||||
|
- name: Verify archive integrity
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cd offline-test
|
||||||
|
tar -tzf offline-package-autogen-studio-${{ matrix.arch }}.tar.gz > /dev/null
|
||||||
|
|
||||||
|
publish-release:
|
||||||
|
needs: test-offline-installer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-autogen-studio-{0}', github.run_number) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
release_name: Build ${{ env.TAG_NAME }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Download amd64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-autogen-studio-amd64
|
||||||
|
path: release-artifacts/amd64
|
||||||
|
|
||||||
|
- name: Download arm64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-autogen-studio-arm64
|
||||||
|
path: release-artifacts/arm64
|
||||||
|
|
||||||
|
- name: Upload offline installers to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
release-artifacts/amd64/offline-package-autogen-studio-amd64.tar.gz
|
||||||
|
release-artifacts/arm64/offline-package-autogen-studio-arm64.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
192
.github/workflows/offline-package-dify.yaml
vendored
Normal file
192
.github/workflows/offline-package-dify.yaml
vendored
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
name: Build Offline Dify Installer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'gitops/scripts/dify/**'
|
||||||
|
- '.github/workflows/offline-package-dify.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-dify-<run_number>"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
dify_tag:
|
||||||
|
description: "Dify container tag (default: latest)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
postgres_tag:
|
||||||
|
description: "Postgres image tag (default: 15-alpine)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
redis_tag:
|
||||||
|
description: "Redis image tag (default: 7-alpine)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-offline-dify
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-offline-installer:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64, arm64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
dify_tag: ${{ steps.resolve.outputs.dify_tag }}
|
||||||
|
postgres_tag: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
redis_tag: ${{ steps.resolve.outputs.redis_tag }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Resolve image tags
|
||||||
|
id: resolve
|
||||||
|
env:
|
||||||
|
INPUT_DIFY_TAG: ${{ github.event.inputs.dify_tag }}
|
||||||
|
INPUT_POSTGRES_TAG: ${{ github.event.inputs.postgres_tag }}
|
||||||
|
INPUT_REDIS_TAG: ${{ github.event.inputs.redis_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
DIFY_TAG=${INPUT_DIFY_TAG:-latest}
|
||||||
|
POSTGRES_TAG=${INPUT_POSTGRES_TAG:-15-alpine}
|
||||||
|
REDIS_TAG=${INPUT_REDIS_TAG:-7-alpine}
|
||||||
|
{
|
||||||
|
echo "dify_tag=${DIFY_TAG}"
|
||||||
|
echo "postgres_tag=${POSTGRES_TAG}"
|
||||||
|
echo "redis_tag=${REDIS_TAG}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Prepare directories
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
rm -rf offline-installer
|
||||||
|
mkdir -p offline-installer/{images,scripts}
|
||||||
|
|
||||||
|
- name: Stage compose file and scripts
|
||||||
|
env:
|
||||||
|
DIFY_TAG: ${{ steps.resolve.outputs.dify_tag }}
|
||||||
|
POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cp gitops/scripts/dify/docker-compose.yaml offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__DIFY_TAG__/${DIFY_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__POSTGRES_TAG__/${POSTGRES_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__REDIS_TAG__/${REDIS_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
cp gitops/scripts/dify/deploy-dify.sh offline-installer/scripts/
|
||||||
|
chmod +x offline-installer/scripts/deploy-dify.sh
|
||||||
|
cat <<'README' > offline-installer/README.md
|
||||||
|
# Offline Dify Installer
|
||||||
|
|
||||||
|
This archive contains container images and helper assets for deploying Dify with Docker Compose.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images.
|
||||||
|
- `images/`: Pre-pulled container images saved as tar archives.
|
||||||
|
- `scripts/deploy-dify.sh`: Helper script to load the images and manage the compose stack.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
1. Extract the archive on a host with Docker/nerdctl available.
|
||||||
|
2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-dify.sh load-images` to import the images with nerdctl.
|
||||||
|
3. Start the stack: `./scripts/deploy-dify.sh up`.
|
||||||
|
4. Access the Dify web UI at http://localhost:8080.
|
||||||
|
|
||||||
|
Adjust the compose file as needed before running the helper script.
|
||||||
|
README
|
||||||
|
|
||||||
|
- name: Pull & export container images
|
||||||
|
env:
|
||||||
|
DIFY_TAG: ${{ steps.resolve.outputs.dify_tag }}
|
||||||
|
POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
images=(
|
||||||
|
"langgenius/dify-api:${DIFY_TAG}"
|
||||||
|
"langgenius/dify-worker:${DIFY_TAG}"
|
||||||
|
"langgenius/dify-web:${DIFY_TAG}"
|
||||||
|
"langgenius/dify-nginx:${DIFY_TAG}"
|
||||||
|
"postgres:${POSTGRES_TAG}"
|
||||||
|
"redis:${REDIS_TAG}"
|
||||||
|
)
|
||||||
|
for image in "${images[@]}"; do
|
||||||
|
docker pull "$image"
|
||||||
|
safe=$(echo "$image" | tr '/:' '-_')
|
||||||
|
docker save "$image" -o "offline-installer/images/${safe}.tar"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Package offline installer
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
tar -czf offline-package-dify-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-dify-${{ matrix.arch }}
|
||||||
|
path: offline-package-dify-${{ matrix.arch }}.tar.gz
|
||||||
|
|
||||||
|
test-offline-installer:
|
||||||
|
needs: build-offline-installer
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-dify-${{ matrix.arch }}
|
||||||
|
path: offline-test
|
||||||
|
|
||||||
|
- name: Verify archive integrity
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cd offline-test
|
||||||
|
tar -tzf offline-package-dify-${{ matrix.arch }}.tar.gz > /dev/null
|
||||||
|
|
||||||
|
publish-release:
|
||||||
|
needs: test-offline-installer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-dify-{0}', github.run_number) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
release_name: Build ${{ env.TAG_NAME }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Download amd64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-dify-amd64
|
||||||
|
path: release-artifacts/amd64
|
||||||
|
|
||||||
|
- name: Download arm64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-dify-arm64
|
||||||
|
path: release-artifacts/arm64
|
||||||
|
|
||||||
|
- name: Upload offline installers to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
release-artifacts/amd64/offline-package-dify-amd64.tar.gz
|
||||||
|
release-artifacts/arm64/offline-package-dify-arm64.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
159
.github/workflows/offline-package-flowise.yaml
vendored
Normal file
159
.github/workflows/offline-package-flowise.yaml
vendored
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
name: Build Offline Flowise Installer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'gitops/scripts/flowise/**'
|
||||||
|
- '.github/workflows/offline-package-flowise.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-flowise-<run_number>"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
flowise_tag:
|
||||||
|
description: "Flowise container tag (default: latest)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-offline-flowise
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-offline-installer:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64, arm64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
flowise_tag: ${{ steps.resolve.outputs.flowise_tag }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Resolve image tag
|
||||||
|
id: resolve
|
||||||
|
env:
|
||||||
|
INPUT_FLOWISE_TAG: ${{ github.event.inputs.flowise_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
FLOWISE_TAG=${INPUT_FLOWISE_TAG:-latest}
|
||||||
|
echo "flowise_tag=${FLOWISE_TAG}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Prepare directories
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
rm -rf offline-installer
|
||||||
|
mkdir -p offline-installer/{images,scripts}
|
||||||
|
|
||||||
|
- name: Stage compose file and scripts
|
||||||
|
env:
|
||||||
|
FLOWISE_TAG: ${{ steps.resolve.outputs.flowise_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cp gitops/scripts/flowise/docker-compose.yaml offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__FLOWISE_TAG__/${FLOWISE_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
cp gitops/scripts/flowise/deploy-flowise.sh offline-installer/scripts/
|
||||||
|
chmod +x offline-installer/scripts/deploy-flowise.sh
|
||||||
|
cat <<'README' > offline-installer/README.md
|
||||||
|
# Offline Flowise Installer
|
||||||
|
|
||||||
|
This archive contains container images and helper assets for deploying Flowise with Docker Compose.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images.
|
||||||
|
- `images/`: Pre-pulled container images saved as tar archives.
|
||||||
|
- `scripts/deploy-flowise.sh`: Helper script to load the images and manage the compose stack.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
1. Extract the archive on a host with Docker/nerdctl available.
|
||||||
|
2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-flowise.sh load-images` to import the images with nerdctl.
|
||||||
|
3. Start the stack: `./scripts/deploy-flowise.sh up`.
|
||||||
|
4. Access the Flowise UI at http://localhost:3000.
|
||||||
|
|
||||||
|
Adjust the compose file as needed before running the helper script.
|
||||||
|
README
|
||||||
|
|
||||||
|
- name: Pull & export container images
|
||||||
|
env:
|
||||||
|
FLOWISE_TAG: ${{ steps.resolve.outputs.flowise_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
image="flowiseai/flowise:${FLOWISE_TAG}"
|
||||||
|
docker pull "$image"
|
||||||
|
safe=$(echo "$image" | tr '/:' '-_')
|
||||||
|
docker save "$image" -o "offline-installer/images/${safe}.tar"
|
||||||
|
|
||||||
|
- name: Package offline installer
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
tar -czf offline-package-flowise-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-flowise-${{ matrix.arch }}
|
||||||
|
path: offline-package-flowise-${{ matrix.arch }}.tar.gz
|
||||||
|
|
||||||
|
test-offline-installer:
|
||||||
|
needs: build-offline-installer
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-flowise-${{ matrix.arch }}
|
||||||
|
path: offline-test
|
||||||
|
|
||||||
|
- name: Verify archive integrity
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cd offline-test
|
||||||
|
tar -tzf offline-package-flowise-${{ matrix.arch }}.tar.gz > /dev/null
|
||||||
|
|
||||||
|
publish-release:
|
||||||
|
needs: test-offline-installer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-flowise-{0}', github.run_number) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
release_name: Build ${{ env.TAG_NAME }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Download amd64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-flowise-amd64
|
||||||
|
path: release-artifacts/amd64
|
||||||
|
|
||||||
|
- name: Download arm64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-flowise-arm64
|
||||||
|
path: release-artifacts/arm64
|
||||||
|
|
||||||
|
- name: Upload offline installers to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
release-artifacts/amd64/offline-package-flowise-amd64.tar.gz
|
||||||
|
release-artifacts/arm64/offline-package-flowise-arm64.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@ -53,14 +53,7 @@ jobs:
|
|||||||
id: resolve
|
id: resolve
|
||||||
env:
|
env:
|
||||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||||
run: |
|
run: script/offline-fluxcd/resolve-chart-version.sh
|
||||||
set -euo pipefail
|
|
||||||
if [ -n "${OVERRIDE_CHART_VERSION}" ]; then
|
|
||||||
CHART_VERSION="${OVERRIDE_CHART_VERSION}"
|
|
||||||
else
|
|
||||||
CHART_VERSION=$(helm search repo fluxcd-community/flux2 --versions | awk 'NR==2{print $2}')
|
|
||||||
fi
|
|
||||||
echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Prepare directories
|
- name: Prepare directories
|
||||||
run: |
|
run: |
|
||||||
@ -71,45 +64,7 @@ jobs:
|
|||||||
- name: Stage installer script
|
- name: Stage installer script
|
||||||
env:
|
env:
|
||||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||||
run: |
|
run: script/offline-fluxcd/stage-installer.sh
|
||||||
set -euo pipefail
|
|
||||||
cat <<'SCRIPT' > offline-installer/scripts/install-fluxcd.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
||||||
CHART_DIR="${ROOT_DIR}/charts/flux2"
|
|
||||||
IMAGES_DIR="${ROOT_DIR}/images"
|
|
||||||
RELEASE_NAME="${RELEASE_NAME:-flux-system}"
|
|
||||||
NAMESPACE="${NAMESPACE:-flux-system}"
|
|
||||||
|
|
||||||
if command -v nerdctl >/dev/null 2>&1; then
|
|
||||||
LOADER="nerdctl"
|
|
||||||
elif command -v docker >/dev/null 2>&1; then
|
|
||||||
LOADER="docker"
|
|
||||||
else
|
|
||||||
echo "Either docker or nerdctl is required to load images." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
for tar in "${IMAGES_DIR}"/*.tar; do
|
|
||||||
[ -f "$tar" ] || continue
|
|
||||||
echo "Loading image: $tar"
|
|
||||||
"$LOADER" load -i "$tar"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Installing/Upgrading FluxCD release ${RELEASE_NAME} in namespace ${NAMESPACE}"
|
|
||||||
helm upgrade --install "${RELEASE_NAME}" "${CHART_DIR}" \
|
|
||||||
--namespace "${NAMESPACE}" \
|
|
||||||
--create-namespace \
|
|
||||||
"$@"
|
|
||||||
SCRIPT
|
|
||||||
chmod +x offline-installer/scripts/install-fluxcd.sh
|
|
||||||
cat <<EOFMETA > offline-installer/metadata/INFO
|
|
||||||
chart: fluxcd-community/flux2
|
|
||||||
chart_version: ${CHART_VERSION}
|
|
||||||
created_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
EOFMETA
|
|
||||||
|
|
||||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||||
run: |
|
run: |
|
||||||
@ -120,25 +75,8 @@ EOFMETA
|
|||||||
- name: Pull & export required images
|
- name: Pull & export required images
|
||||||
env:
|
env:
|
||||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||||
run: |
|
MATRIX_ARCH: ${{ matrix.arch }}
|
||||||
set -euo pipefail
|
run: script/offline-fluxcd/pull-and-export-images.sh
|
||||||
PLATFORM="linux/${{ matrix.arch }}"
|
|
||||||
helm template flux fluxcd-community/flux2 --version "${CHART_VERSION}" > manifest.yaml
|
|
||||||
mapfile -t images < <(grep -oP 'image:\s*"?\K([^"\s]+)' manifest.yaml | sort -u || true)
|
|
||||||
rm -f manifest.yaml
|
|
||||||
for img in "${images[@]}"; do
|
|
||||||
[ -n "$img" ] || continue
|
|
||||||
if [[ "$img" == *"{{"* ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
echo "Pulling $img for ${PLATFORM}"
|
|
||||||
if ! docker pull --platform "${PLATFORM}" "$img"; then
|
|
||||||
echo "::warning::Failed to pull $img for ${PLATFORM}, skipping" >&2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
safe=$(echo "$img" | tr '/:' '-_')
|
|
||||||
docker save "$img" -o "offline-installer/images/${safe}.tar"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Download Helm chart
|
- name: Download Helm chart
|
||||||
env:
|
env:
|
||||||
|
|||||||
@ -36,12 +36,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install deps (curl, jq, helm)
|
- name: Install deps (curl, jq, helm)
|
||||||
run: |
|
run: script/install-offline-gitlab-deps.sh
|
||||||
set -euo pipefail
|
|
||||||
sudo apt-get update -y
|
|
||||||
sudo apt-get install -y curl jq
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
|
||||||
helm version
|
|
||||||
|
|
||||||
- name: Add helm repo
|
- name: Add helm repo
|
||||||
run: |
|
run: |
|
||||||
@ -53,14 +48,7 @@ jobs:
|
|||||||
id: resolve
|
id: resolve
|
||||||
env:
|
env:
|
||||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||||
run: |
|
run: script/resolve-gitlab-chart-version.sh
|
||||||
set -euo pipefail
|
|
||||||
if [ -n "${OVERRIDE_CHART_VERSION}" ]; then
|
|
||||||
CHART_VERSION="${OVERRIDE_CHART_VERSION}"
|
|
||||||
else
|
|
||||||
CHART_VERSION=$(helm search repo gitlab/gitlab --versions | awk 'NR==2{print $2}')
|
|
||||||
fi
|
|
||||||
echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Prepare directories
|
- name: Prepare directories
|
||||||
run: |
|
run: |
|
||||||
@ -71,45 +59,7 @@ jobs:
|
|||||||
- name: Stage installer script
|
- name: Stage installer script
|
||||||
env:
|
env:
|
||||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||||
run: |
|
run: script/stage-gitlab-offline-installer.sh
|
||||||
set -euo pipefail
|
|
||||||
cat <<'SCRIPT' > offline-installer/scripts/install-gitlab.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
||||||
CHART_DIR="${ROOT_DIR}/charts/gitlab"
|
|
||||||
IMAGES_DIR="${ROOT_DIR}/images"
|
|
||||||
RELEASE_NAME="${RELEASE_NAME:-gitlab}"
|
|
||||||
NAMESPACE="${NAMESPACE:-gitlab}"
|
|
||||||
|
|
||||||
if command -v nerdctl >/dev/null 2>&1; then
|
|
||||||
LOADER="nerdctl"
|
|
||||||
elif command -v docker >/dev/null 2>&1; then
|
|
||||||
LOADER="docker"
|
|
||||||
else
|
|
||||||
echo "Either docker or nerdctl is required to load images." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
for tar in "${IMAGES_DIR}"/*.tar; do
|
|
||||||
[ -f "$tar" ] || continue
|
|
||||||
echo "Loading image: $tar"
|
|
||||||
"$LOADER" load -i "$tar"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Installing/Upgrading GitLab release ${RELEASE_NAME} in namespace ${NAMESPACE}"
|
|
||||||
helm upgrade --install "${RELEASE_NAME}" "${CHART_DIR}" \
|
|
||||||
--namespace "${NAMESPACE}" \
|
|
||||||
--create-namespace \
|
|
||||||
"$@"
|
|
||||||
SCRIPT
|
|
||||||
chmod +x offline-installer/scripts/install-gitlab.sh
|
|
||||||
cat <<EOFMETA > offline-installer/metadata/INFO
|
|
||||||
chart: gitlab/gitlab
|
|
||||||
chart_version: ${CHART_VERSION}
|
|
||||||
created_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
EOFMETA
|
|
||||||
|
|
||||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||||
run: |
|
run: |
|
||||||
@ -120,25 +70,8 @@ EOFMETA
|
|||||||
- name: Pull & export required images
|
- name: Pull & export required images
|
||||||
env:
|
env:
|
||||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||||
run: |
|
ARCH: ${{ matrix.arch }}
|
||||||
set -euo pipefail
|
run: script/pull-and-export-gitlab-images.sh
|
||||||
PLATFORM="linux/${{ matrix.arch }}"
|
|
||||||
helm template gitlab gitlab/gitlab --version "${CHART_VERSION}" > manifest.yaml
|
|
||||||
mapfile -t images < <(grep -oP 'image:\s*"?\K([^"\s]+)' manifest.yaml | sort -u || true)
|
|
||||||
rm -f manifest.yaml
|
|
||||||
for img in "${images[@]}"; do
|
|
||||||
[ -n "$img" ] || continue
|
|
||||||
if [[ "$img" == *"{{"* ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
echo "Pulling $img for ${PLATFORM}"
|
|
||||||
if ! docker pull --platform "${PLATFORM}" "$img"; then
|
|
||||||
echo "::warning::Failed to pull $img for ${PLATFORM}, skipping" >&2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
safe=$(echo "$img" | tr '/:' '-_')
|
|
||||||
docker save "$img" -o "offline-installer/images/${safe}.tar"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Download Helm chart
|
- name: Download Helm chart
|
||||||
env:
|
env:
|
||||||
|
|||||||
177
.github/workflows/offline-package-n8n.yaml
vendored
Normal file
177
.github/workflows/offline-package-n8n.yaml
vendored
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
name: Build Offline n8n Installer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'gitops/scripts/n8n/**'
|
||||||
|
- '.github/workflows/offline-package-n8n.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-n8n-<run_number>"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
n8n_tag:
|
||||||
|
description: "n8n container tag (default: latest)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
postgres_tag:
|
||||||
|
description: "Postgres image tag (default: 15-alpine)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-offline-n8n
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-offline-installer:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64, arm64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
n8n_tag: ${{ steps.resolve.outputs.n8n_tag }}
|
||||||
|
postgres_tag: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Resolve image tags
|
||||||
|
id: resolve
|
||||||
|
env:
|
||||||
|
INPUT_N8N_TAG: ${{ github.event.inputs.n8n_tag }}
|
||||||
|
INPUT_POSTGRES_TAG: ${{ github.event.inputs.postgres_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
N8N_TAG=${INPUT_N8N_TAG:-latest}
|
||||||
|
POSTGRES_TAG=${INPUT_POSTGRES_TAG:-15-alpine}
|
||||||
|
{
|
||||||
|
echo "n8n_tag=${N8N_TAG}"
|
||||||
|
echo "postgres_tag=${POSTGRES_TAG}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Prepare directories
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
rm -rf offline-installer
|
||||||
|
mkdir -p offline-installer/{images,scripts}
|
||||||
|
|
||||||
|
- name: Stage compose file and scripts
|
||||||
|
env:
|
||||||
|
N8N_TAG: ${{ steps.resolve.outputs.n8n_tag }}
|
||||||
|
POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cp gitops/scripts/n8n/docker-compose.yaml offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__N8N_TAG__/${N8N_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__POSTGRES_TAG__/${POSTGRES_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
cp gitops/scripts/n8n/deploy-n8n.sh offline-installer/scripts/
|
||||||
|
chmod +x offline-installer/scripts/deploy-n8n.sh
|
||||||
|
cat <<'README' > offline-installer/README.md
|
||||||
|
# Offline n8n Installer
|
||||||
|
|
||||||
|
This archive contains container images and helper assets for deploying n8n with Docker Compose.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images.
|
||||||
|
- `images/`: Pre-pulled container images saved as tar archives.
|
||||||
|
- `scripts/deploy-n8n.sh`: Helper script to load the images and manage the compose stack.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
1. Extract the archive on a host with Docker/nerdctl available.
|
||||||
|
2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-n8n.sh load-images` to import the images with nerdctl.
|
||||||
|
3. Start the stack: `./scripts/deploy-n8n.sh up`.
|
||||||
|
4. Access the n8n UI at http://localhost:5678.
|
||||||
|
|
||||||
|
Adjust the compose file as needed before running the helper script.
|
||||||
|
README
|
||||||
|
|
||||||
|
- name: Pull & export container images
|
||||||
|
env:
|
||||||
|
N8N_TAG: ${{ steps.resolve.outputs.n8n_tag }}
|
||||||
|
POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
images=(
|
||||||
|
"n8nio/n8n:${N8N_TAG}"
|
||||||
|
"postgres:${POSTGRES_TAG}"
|
||||||
|
)
|
||||||
|
for image in "${images[@]}"; do
|
||||||
|
docker pull "$image"
|
||||||
|
safe=$(echo "$image" | tr '/:' '-_')
|
||||||
|
docker save "$image" -o "offline-installer/images/${safe}.tar"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Package offline installer
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
tar -czf offline-package-n8n-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-n8n-${{ matrix.arch }}
|
||||||
|
path: offline-package-n8n-${{ matrix.arch }}.tar.gz
|
||||||
|
|
||||||
|
test-offline-installer:
|
||||||
|
needs: build-offline-installer
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-n8n-${{ matrix.arch }}
|
||||||
|
path: offline-test
|
||||||
|
|
||||||
|
- name: Verify archive integrity
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cd offline-test
|
||||||
|
tar -tzf offline-package-n8n-${{ matrix.arch }}.tar.gz > /dev/null
|
||||||
|
|
||||||
|
publish-release:
|
||||||
|
needs: test-offline-installer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-n8n-{0}', github.run_number) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
release_name: Build ${{ env.TAG_NAME }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Download amd64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-n8n-amd64
|
||||||
|
path: release-artifacts/amd64
|
||||||
|
|
||||||
|
- name: Download arm64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-n8n-arm64
|
||||||
|
path: release-artifacts/arm64
|
||||||
|
|
||||||
|
- name: Upload offline installers to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
release-artifacts/amd64/offline-package-n8n-amd64.tar.gz
|
||||||
|
release-artifacts/arm64/offline-package-n8n-arm64.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@ -43,73 +43,15 @@ jobs:
|
|||||||
id: resolve
|
id: resolve
|
||||||
env:
|
env:
|
||||||
OVERRIDE_VERSION: ${{ github.event.inputs.pulumi_version }}
|
OVERRIDE_VERSION: ${{ github.event.inputs.pulumi_version }}
|
||||||
run: |
|
run: script/resolve-pulumi-version.sh
|
||||||
set -euo pipefail
|
|
||||||
if [ -n "${OVERRIDE_VERSION}" ]; then
|
|
||||||
VERSION="${OVERRIDE_VERSION}"
|
|
||||||
else
|
|
||||||
VERSION=$(curl -fsSL https://api.github.com/repos/pulumi/pulumi/releases?per_page=100 \
|
|
||||||
| jq -r '.[].tag_name' \
|
|
||||||
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
|
|
||||||
| sed 's/^v//' \
|
|
||||||
| sort -V \
|
|
||||||
| tail -n 1)
|
|
||||||
fi
|
|
||||||
if [ -z "${VERSION}" ]; then
|
|
||||||
echo "Failed to resolve Pulumi version" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Resolved Pulumi version: ${VERSION}"
|
|
||||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Build offline Pulumi package
|
- name: Build offline Pulumi package
|
||||||
env:
|
env:
|
||||||
|
ARCH: ${{ matrix.arch }}
|
||||||
PULUMI_VERSION: ${{ steps.resolve.outputs.version }}
|
PULUMI_VERSION: ${{ steps.resolve.outputs.version }}
|
||||||
run: |
|
MATRIX_ARCH: ${{ matrix.arch }}
|
||||||
set -euo pipefail
|
|
||||||
ARCH="${{ matrix.arch }}"
|
|
||||||
case "$ARCH" in
|
|
||||||
amd64) ASSET_ARCH="x64" ;;
|
|
||||||
arm64) ASSET_ARCH="arm64" ;;
|
|
||||||
*) echo "Unsupported arch: $ARCH" >&2; exit 1 ;;
|
|
||||||
esac
|
|
||||||
WORKDIR="pulumi-offline-package"
|
|
||||||
rm -rf "${WORKDIR}"
|
|
||||||
mkdir -p "${WORKDIR}" "${WORKDIR}/scripts"
|
|
||||||
|
|
||||||
ARCHIVE="pulumi-v${PULUMI_VERSION}-linux-${ASSET_ARCH}.tar.gz"
|
run: script/build-offline-pulumi-package.sh
|
||||||
URL="https://get.pulumi.com/releases/sdk/${ARCHIVE}"
|
|
||||||
echo "Downloading ${URL}"
|
|
||||||
curl -fSL "${URL}" -o "${ARCHIVE}"
|
|
||||||
|
|
||||||
tar -xzvf "${ARCHIVE}" -C "${WORKDIR}" --strip-components=1
|
|
||||||
rm -f "${ARCHIVE}"
|
|
||||||
|
|
||||||
echo "${PULUMI_VERSION}" > "${WORKDIR}/VERSION"
|
|
||||||
|
|
||||||
cat <<'SCRIPT' > "${WORKDIR}/scripts/install-pulumi.sh"
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
||||||
BIN_DIR="${ROOT_DIR}/bin"
|
|
||||||
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
|
|
||||||
|
|
||||||
if [[ "${1:-}" == "--install" ]]; then
|
|
||||||
sudo install -m 0755 "${BIN_DIR}"/* "${INSTALL_DIR}/"
|
|
||||||
echo "Pulumi binaries installed to ${INSTALL_DIR}"
|
|
||||||
else
|
|
||||||
cat <<USAGE
|
|
||||||
Usage: $(basename "$0") --install
|
|
||||||
--install Copy Pulumi CLI binaries into ${INSTALL_DIR}
|
|
||||||
USAGE
|
|
||||||
fi
|
|
||||||
SCRIPT
|
|
||||||
chmod +x "${WORKDIR}/scripts/install-pulumi.sh"
|
|
||||||
|
|
||||||
OUTPUT_ARCHIVE="offline-package-pulumi-${ARCH}.tar.gz"
|
|
||||||
tar -czf "${OUTPUT_ARCHIVE}" "${WORKDIR}"
|
|
||||||
ls -lh "${OUTPUT_ARCHIVE}"
|
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@ -125,6 +67,8 @@ SCRIPT
|
|||||||
arch: [amd64, arm64]
|
arch: [amd64, arm64]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
@ -139,17 +83,11 @@ SCRIPT
|
|||||||
|
|
||||||
- name: Verify Pulumi bundle
|
- name: Verify Pulumi bundle
|
||||||
env:
|
env:
|
||||||
|
ARCH: ${{ matrix.arch }}
|
||||||
PULUMI_VERSION: ${{ needs.build-offline-installer.outputs.version }}
|
PULUMI_VERSION: ${{ needs.build-offline-installer.outputs.version }}
|
||||||
run: |
|
MATRIX_ARCH: ${{ matrix.arch }}
|
||||||
set -euo pipefail
|
|
||||||
cd test-dir/pulumi-offline-package
|
run: script/verify-pulumi-bundle.sh
|
||||||
test -f VERSION
|
|
||||||
if [ "${{ matrix.arch }}" = "amd64" ]; then
|
|
||||||
./bin/pulumi version
|
|
||||||
./bin/pulumi version | grep "v${PULUMI_VERSION}"
|
|
||||||
else
|
|
||||||
file ./bin/pulumi | grep -E "ARM|aarch64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
publish-release:
|
publish-release:
|
||||||
needs: test-offline-installer
|
needs: test-offline-installer
|
||||||
@ -211,15 +149,7 @@ SCRIPT
|
|||||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Rsync release assets to remote
|
- name: Rsync release assets to remote
|
||||||
run: |
|
run: script/rsync-release-assets.sh
|
||||||
set -euo pipefail
|
|
||||||
REMOTE_DIR="${REMOTE_ROOT}/${TAG_NAME}"
|
|
||||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "mkdir -p '${REMOTE_DIR}'"
|
|
||||||
echo "Rsync -> ${VPS_HOST}:${REMOTE_DIR}/"
|
|
||||||
rsync -av -e "ssh -i ~/.ssh/id_rsa" \
|
|
||||||
release-artifacts/amd64/offline-package-pulumi-amd64.tar.gz \
|
|
||||||
release-artifacts/arm64/offline-package-pulumi-arm64.tar.gz \
|
|
||||||
"${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
|
||||||
|
|
||||||
retention:
|
retention:
|
||||||
name: Remote retention (keep latest 3)
|
name: Remote retention (keep latest 3)
|
||||||
@ -231,6 +161,8 @@ SCRIPT
|
|||||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||||
REMOTE_ROOT: /data/update-server/pulumi
|
REMOTE_ROOT: /data/update-server/pulumi
|
||||||
steps:
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Init SSH
|
- name: Init SSH
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@ -240,20 +172,4 @@ SCRIPT
|
|||||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Prune old versions on remote (keep 3)
|
- name: Prune old versions on remote (keep 3)
|
||||||
run: |
|
run: script/prune-remote-versions.sh
|
||||||
set -euo pipefail
|
|
||||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" bash -lc '
|
|
||||||
set -euo pipefail
|
|
||||||
cd "'"${REMOTE_ROOT}"'" || exit 0
|
|
||||||
keep=3
|
|
||||||
mapfile -t all < <(ls -1 | grep -E "^(offline-pulumi-|v[0-9]+\.)" | sort -V -r || true)
|
|
||||||
if [ "${#all[@]}" -le "$keep" ]; then
|
|
||||||
echo "Nothing to prune. Count=${#all[@]}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
to_delete=("${all[@]:keep}")
|
|
||||||
echo "Pruning old versions: ${to_delete[*]}"
|
|
||||||
for d in "${to_delete[@]}"; do
|
|
||||||
rm -rf -- "$d"
|
|
||||||
done
|
|
||||||
'
|
|
||||||
|
|||||||
189
.github/workflows/offline-package-ragflow.yaml
vendored
Normal file
189
.github/workflows/offline-package-ragflow.yaml
vendored
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
name: Build Offline RAGFlow Installer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'gitops/scripts/ragflow/**'
|
||||||
|
- '.github/workflows/offline-package-ragflow.yaml'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-ragflow-<run_number>"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
ragflow_tag:
|
||||||
|
description: "RAGFlow container tag (default: latest)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
postgres_tag:
|
||||||
|
description: "Postgres image tag (default: 15-alpine)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
redis_tag:
|
||||||
|
description: "Redis image tag (default: 7-alpine)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-offline-ragflow
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-offline-installer:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64, arm64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
ragflow_tag: ${{ steps.resolve.outputs.ragflow_tag }}
|
||||||
|
postgres_tag: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
redis_tag: ${{ steps.resolve.outputs.redis_tag }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Resolve image tags
|
||||||
|
id: resolve
|
||||||
|
env:
|
||||||
|
INPUT_RAGFLOW_TAG: ${{ github.event.inputs.ragflow_tag }}
|
||||||
|
INPUT_POSTGRES_TAG: ${{ github.event.inputs.postgres_tag }}
|
||||||
|
INPUT_REDIS_TAG: ${{ github.event.inputs.redis_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
RAGFLOW_TAG=${INPUT_RAGFLOW_TAG:-latest}
|
||||||
|
POSTGRES_TAG=${INPUT_POSTGRES_TAG:-15-alpine}
|
||||||
|
REDIS_TAG=${INPUT_REDIS_TAG:-7-alpine}
|
||||||
|
{
|
||||||
|
echo "ragflow_tag=${RAGFLOW_TAG}"
|
||||||
|
echo "postgres_tag=${POSTGRES_TAG}"
|
||||||
|
echo "redis_tag=${REDIS_TAG}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Prepare directories
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
rm -rf offline-installer
|
||||||
|
mkdir -p offline-installer/{images,scripts}
|
||||||
|
|
||||||
|
- name: Stage compose file and scripts
|
||||||
|
env:
|
||||||
|
RAGFLOW_TAG: ${{ steps.resolve.outputs.ragflow_tag }}
|
||||||
|
POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cp gitops/scripts/ragflow/docker-compose.yaml offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__RAGFLOW_TAG__/${RAGFLOW_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__POSTGRES_TAG__/${POSTGRES_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
sed -i "s/__REDIS_TAG__/${REDIS_TAG}/g" offline-installer/docker-compose.yaml
|
||||||
|
cp gitops/scripts/ragflow/deploy-ragflow.sh offline-installer/scripts/
|
||||||
|
chmod +x offline-installer/scripts/deploy-ragflow.sh
|
||||||
|
cat <<'README' > offline-installer/README.md
|
||||||
|
# Offline RAGFlow Installer
|
||||||
|
|
||||||
|
This archive contains container images and helper assets for deploying RAGFlow with Docker Compose.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
- `docker-compose.yaml`: Reference deployment manifest configured for the packaged images.
|
||||||
|
- `images/`: Pre-pulled container images saved as tar archives.
|
||||||
|
- `scripts/deploy-ragflow.sh`: Helper script to load the images and manage the compose stack.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
1. Extract the archive on a host with Docker/nerdctl available.
|
||||||
|
2. (Optional) Run `IMAGE_LOAD_TOOL=nerdctl ./scripts/deploy-ragflow.sh load-images` to import the images with nerdctl.
|
||||||
|
3. Start the stack: `./scripts/deploy-ragflow.sh up`.
|
||||||
|
4. Access the RAGFlow UI at http://localhost:3001.
|
||||||
|
|
||||||
|
Adjust the compose file as needed before running the helper script. Configure external vector stores or storage services as required by your deployment.
|
||||||
|
README
|
||||||
|
|
||||||
|
- name: Pull & export container images
|
||||||
|
env:
|
||||||
|
RAGFLOW_TAG: ${{ steps.resolve.outputs.ragflow_tag }}
|
||||||
|
POSTGRES_TAG: ${{ steps.resolve.outputs.postgres_tag }}
|
||||||
|
REDIS_TAG: ${{ steps.resolve.outputs.redis_tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
images=(
|
||||||
|
"ragflow/ragflow:${RAGFLOW_TAG}"
|
||||||
|
"postgres:${POSTGRES_TAG}"
|
||||||
|
"redis:${REDIS_TAG}"
|
||||||
|
)
|
||||||
|
for image in "${images[@]}"; do
|
||||||
|
docker pull "$image"
|
||||||
|
safe=$(echo "$image" | tr '/:' '-_')
|
||||||
|
docker save "$image" -o "offline-installer/images/${safe}.tar"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Package offline installer
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
tar -czf offline-package-ragflow-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-ragflow-${{ matrix.arch }}
|
||||||
|
path: offline-package-ragflow-${{ matrix.arch }}.tar.gz
|
||||||
|
|
||||||
|
test-offline-installer:
|
||||||
|
needs: build-offline-installer
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-ragflow-${{ matrix.arch }}
|
||||||
|
path: offline-test
|
||||||
|
|
||||||
|
- name: Verify archive integrity
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cd offline-test
|
||||||
|
tar -tzf offline-package-ragflow-${{ matrix.arch }}.tar.gz > /dev/null
|
||||||
|
|
||||||
|
publish-release:
|
||||||
|
needs: test-offline-installer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-ragflow-{0}', github.run_number) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
release_name: Build ${{ env.TAG_NAME }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Download amd64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-ragflow-amd64
|
||||||
|
path: release-artifacts/amd64
|
||||||
|
|
||||||
|
- name: Download arm64 artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: offline-package-ragflow-arm64
|
||||||
|
path: release-artifacts/arm64
|
||||||
|
|
||||||
|
- name: Upload offline installers to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
release-artifacts/amd64/offline-package-ragflow-amd64.tar.gz
|
||||||
|
release-artifacts/arm64/offline-package-ragflow-arm64.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@ -43,62 +43,13 @@ jobs:
|
|||||||
id: resolve
|
id: resolve
|
||||||
env:
|
env:
|
||||||
OVERRIDE_VERSION: ${{ github.event.inputs.terraform_version }}
|
OVERRIDE_VERSION: ${{ github.event.inputs.terraform_version }}
|
||||||
run: |
|
run: script/resolve-terraform-version.sh
|
||||||
set -euo pipefail
|
|
||||||
if [ -n "${OVERRIDE_VERSION}" ]; then
|
|
||||||
VERSION="${OVERRIDE_VERSION}"
|
|
||||||
else
|
|
||||||
VERSION=$(curl -fsSL https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r '.current_version')
|
|
||||||
fi
|
|
||||||
echo "Resolved Terraform version: ${VERSION}"
|
|
||||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Build offline Terraform package
|
- name: Build offline Terraform package
|
||||||
env:
|
env:
|
||||||
TERRAFORM_VERSION: ${{ steps.resolve.outputs.version }}
|
TERRAFORM_VERSION: ${{ steps.resolve.outputs.version }}
|
||||||
run: |
|
ARCH: ${{ matrix.arch }}
|
||||||
set -euo pipefail
|
run: script/build-offline-terraform-package.sh
|
||||||
ARCH="${{ matrix.arch }}"
|
|
||||||
WORKDIR="terraform-offline-package"
|
|
||||||
rm -rf "${WORKDIR}"
|
|
||||||
mkdir -p "${WORKDIR}/"{bin,scripts,docs}
|
|
||||||
|
|
||||||
BASE_URL="https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}"
|
|
||||||
ARCHIVE="terraform_${TERRAFORM_VERSION}_linux_${ARCH}.zip"
|
|
||||||
echo "Downloading ${BASE_URL}/${ARCHIVE}"
|
|
||||||
curl -fSL "${BASE_URL}/${ARCHIVE}" -o "${ARCHIVE}"
|
|
||||||
|
|
||||||
unzip -d "${WORKDIR}/bin" "${ARCHIVE}"
|
|
||||||
rm -f "${ARCHIVE}"
|
|
||||||
|
|
||||||
echo "${TERRAFORM_VERSION}" > "${WORKDIR}/VERSION"
|
|
||||||
|
|
||||||
cat <<'SCRIPT' > "${WORKDIR}/scripts/install-terraform.sh"
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
||||||
BIN="${ROOT_DIR}/bin/terraform"
|
|
||||||
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<USAGE
|
|
||||||
Usage: $(basename "$0") [--install]
|
|
||||||
--install Copy terraform binary into ${INSTALL_DIR}
|
|
||||||
USAGE
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "${1:-}" == "--install" ]]; then
|
|
||||||
sudo install -m 0755 "$BIN" "${INSTALL_DIR}/terraform"
|
|
||||||
echo "Terraform installed to ${INSTALL_DIR}/terraform"
|
|
||||||
else
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
SCRIPT
|
|
||||||
chmod +x "${WORKDIR}/scripts/install-terraform.sh"
|
|
||||||
|
|
||||||
tar -czf "terraform-offline-package-${ARCH}.tar.gz" "${WORKDIR}"
|
|
||||||
ls -lh "terraform-offline-package-${ARCH}.tar.gz"
|
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@ -129,16 +80,8 @@ SCRIPT
|
|||||||
- name: Verify Terraform bundle
|
- name: Verify Terraform bundle
|
||||||
env:
|
env:
|
||||||
TERRAFORM_VERSION: ${{ needs.build-offline-installer.outputs.version }}
|
TERRAFORM_VERSION: ${{ needs.build-offline-installer.outputs.version }}
|
||||||
run: |
|
ARCH: ${{ matrix.arch }}
|
||||||
set -euo pipefail
|
run: script/verify-terraform-bundle.sh
|
||||||
cd test-dir/terraform-offline-package
|
|
||||||
test -f VERSION
|
|
||||||
if [ "${{ matrix.arch }}" = "amd64" ]; then
|
|
||||||
./bin/terraform version
|
|
||||||
./bin/terraform version | grep "Terraform v${TERRAFORM_VERSION}"
|
|
||||||
else
|
|
||||||
file ./bin/terraform | grep -E "ARM|aarch64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
publish-release:
|
publish-release:
|
||||||
needs: test-offline-installer
|
needs: test-offline-installer
|
||||||
@ -200,15 +143,7 @@ SCRIPT
|
|||||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Rsync release assets to remote
|
- name: Rsync release assets to remote
|
||||||
run: |
|
run: script/rsync-release-assets.sh
|
||||||
set -euo pipefail
|
|
||||||
REMOTE_DIR="${REMOTE_ROOT}/${TAG_NAME}"
|
|
||||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "mkdir -p '${REMOTE_DIR}'"
|
|
||||||
echo "Rsync -> ${VPS_HOST}:${REMOTE_DIR}/"
|
|
||||||
rsync -av -e "ssh -i ~/.ssh/id_rsa" \
|
|
||||||
release-artifacts/amd64/terraform-offline-package-amd64.tar.gz \
|
|
||||||
release-artifacts/arm64/terraform-offline-package-arm64.tar.gz \
|
|
||||||
"${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
|
||||||
|
|
||||||
retention:
|
retention:
|
||||||
name: Remote retention (keep latest 3)
|
name: Remote retention (keep latest 3)
|
||||||
@ -229,20 +164,4 @@ SCRIPT
|
|||||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Prune old versions on remote (keep 3)
|
- name: Prune old versions on remote (keep 3)
|
||||||
run: |
|
run: script/prune-remote-versions.sh
|
||||||
set -euo pipefail
|
|
||||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" bash -lc '
|
|
||||||
set -euo pipefail
|
|
||||||
cd "'"${REMOTE_ROOT}"'" || exit 0
|
|
||||||
keep=3
|
|
||||||
mapfile -t all < <(ls -1 | grep -E "^(offline-terraform-|v[0-9]+\.)" | sort -V -r || true)
|
|
||||||
if [ "${#all[@]}" -le "$keep" ]; then
|
|
||||||
echo "Nothing to prune. Count=${#all[@]}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
to_delete=("${all[@]:keep}")
|
|
||||||
echo "Pruning old versions: ${to_delete[*]}"
|
|
||||||
for d in "${to_delete[@]}"; do
|
|
||||||
rm -rf -- "$d"
|
|
||||||
done
|
|
||||||
'
|
|
||||||
|
|||||||
67
.github/workflows/release-oci-charts.yml
vendored
Normal file
67
.github/workflows/release-oci-charts.yml
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
name: release-oci-charts
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "oci/charts/apps/app-service/**"
|
||||||
|
- "oci/charts/postgresql/**"
|
||||||
|
- "oci/charts/observability/**"
|
||||||
|
- ".github/workflows/release-oci-charts.yml"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
||||||
|
|
||||||
|
- name: Setup Helm
|
||||||
|
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
|
||||||
|
with:
|
||||||
|
version: v3.15.4
|
||||||
|
|
||||||
|
- name: Log In To GHCR
|
||||||
|
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Lint charts
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
charts=(
|
||||||
|
"oci/charts/apps/app-service"
|
||||||
|
"oci/charts/postgresql"
|
||||||
|
"oci/charts/observability"
|
||||||
|
)
|
||||||
|
for chart in "${charts[@]}"; do
|
||||||
|
helm lint "./${chart}"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Package charts
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
mkdir -p dist
|
||||||
|
charts=(
|
||||||
|
"oci/charts/apps/app-service"
|
||||||
|
"oci/charts/postgresql"
|
||||||
|
"oci/charts/observability"
|
||||||
|
)
|
||||||
|
for chart in "${charts[@]}"; do
|
||||||
|
helm package "./${chart}" --destination dist
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Push charts to GHCR
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
for pkg in dist/*.tgz; do
|
||||||
|
helm push "${pkg}" oci://ghcr.io/x-evor
|
||||||
|
done
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,3 +22,6 @@
|
|||||||
.build-harness
|
.build-harness
|
||||||
build-harness
|
build-harness
|
||||||
dist/bin/*
|
dist/bin/*
|
||||||
|
|
||||||
|
# Packaged Helm charts generated in-place during release work
|
||||||
|
oci/charts/apps/*/charts/*.tgz
|
||||||
|
|||||||
86
gitops/scripts/autogen-studio/deploy-autogen-studio.sh
Executable file
86
gitops/scripts/autogen-studio/deploy-autogen-studio.sh
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_NAME="AutoGen Studio"
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd)
|
||||||
|
COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml"
|
||||||
|
IMAGES_DIR="${OFFLINE_ROOT}/images"
|
||||||
|
IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}"
|
||||||
|
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
load_images() {
|
||||||
|
if ! command_exists "${IMAGE_LOAD_TOOL}"; then
|
||||||
|
echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "${IMAGES_DIR}" ]; then
|
||||||
|
echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
local tarball
|
||||||
|
for tarball in "${IMAGES_DIR}"/*.tar; do
|
||||||
|
echo "Loading container images from ${tarball}"
|
||||||
|
"${IMAGE_LOAD_TOOL}" load -i "${tarball}"
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
}
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
if command_exists docker && docker compose version >/dev/null 2>&1; then
|
||||||
|
docker compose "$@"
|
||||||
|
elif command_exists docker-compose; then
|
||||||
|
docker-compose "$@"
|
||||||
|
else
|
||||||
|
echo "Error: docker compose plugin or docker-compose binary is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: $(basename "$0") [command]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
up Load images (if available) and start ${APP_NAME}
|
||||||
|
down Stop ${APP_NAME}
|
||||||
|
load-images Only load container images from the images/ directory
|
||||||
|
status Show status of the compose application
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
IMAGE_LOAD_TOOL Override the container image loader (default: docker)
|
||||||
|
COMPOSE_FILE Override docker compose file path (default: ${COMPOSE_FILE})
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd=${1:-up}
|
||||||
|
case "${cmd}" in
|
||||||
|
up)
|
||||||
|
load_images
|
||||||
|
compose -f "${COMPOSE_FILE}" up -d
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
compose -f "${COMPOSE_FILE}" down
|
||||||
|
;;
|
||||||
|
load-images)
|
||||||
|
load_images
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
compose -f "${COMPOSE_FILE}" ps
|
||||||
|
;;
|
||||||
|
-h|--help|help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: ${cmd}" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
18
gitops/scripts/autogen-studio/docker-compose.yaml
Normal file
18
gitops/scripts/autogen-studio/docker-compose.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
autogen-studio:
|
||||||
|
image: autogenstudio/autogen-studio:__AUTOGEN_TAG__
|
||||||
|
container_name: autogen-studio
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "9090:9090"
|
||||||
|
environment:
|
||||||
|
AUTOGEN_STUDIO_HOST: 0.0.0.0
|
||||||
|
AUTOGEN_STUDIO_PORT: 9090
|
||||||
|
AUTOGEN_STUDIO_LOG_LEVEL: info
|
||||||
|
volumes:
|
||||||
|
- autogen-data:/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
autogen-data:
|
||||||
86
gitops/scripts/dify/deploy-dify.sh
Executable file
86
gitops/scripts/dify/deploy-dify.sh
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_NAME="Dify"
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd)
|
||||||
|
COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml"
|
||||||
|
IMAGES_DIR="${OFFLINE_ROOT}/images"
|
||||||
|
IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}"
|
||||||
|
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
load_images() {
|
||||||
|
if ! command_exists "${IMAGE_LOAD_TOOL}"; then
|
||||||
|
echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "${IMAGES_DIR}" ]; then
|
||||||
|
echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
local tarball
|
||||||
|
for tarball in "${IMAGES_DIR}"/*.tar; do
|
||||||
|
echo "Loading container images from ${tarball}"
|
||||||
|
"${IMAGE_LOAD_TOOL}" load -i "${tarball}"
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
}
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
if command_exists docker && docker compose version >/dev/null 2>&1; then
|
||||||
|
docker compose "$@"
|
||||||
|
elif command_exists docker-compose; then
|
||||||
|
docker-compose "$@"
|
||||||
|
else
|
||||||
|
echo "Error: docker compose plugin or docker-compose binary is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: $(basename "$0") [command]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
up Load images (if available) and start ${APP_NAME}
|
||||||
|
down Stop ${APP_NAME}
|
||||||
|
load-images Only load container images from the images/ directory
|
||||||
|
status Show status of the compose application
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
IMAGE_LOAD_TOOL Override the container image loader (default: docker)
|
||||||
|
COMPOSE_FILE Override docker compose file path (default: ${COMPOSE_FILE})
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd=${1:-up}
|
||||||
|
case "${cmd}" in
|
||||||
|
up)
|
||||||
|
load_images
|
||||||
|
compose -f "${COMPOSE_FILE}" up -d
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
compose -f "${COMPOSE_FILE}" down
|
||||||
|
;;
|
||||||
|
load-images)
|
||||||
|
load_images
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
compose -f "${COMPOSE_FILE}" ps
|
||||||
|
;;
|
||||||
|
-h|--help|help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: ${cmd}" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
72
gitops/scripts/dify/docker-compose.yaml
Normal file
72
gitops/scripts/dify/docker-compose.yaml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:__POSTGRES_TAG__
|
||||||
|
container_name: dify-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: dify
|
||||||
|
POSTGRES_USER: dify
|
||||||
|
POSTGRES_PASSWORD: dify
|
||||||
|
volumes:
|
||||||
|
- dify-postgres:/var/lib/postgresql/data
|
||||||
|
redis:
|
||||||
|
image: redis:__REDIS_TAG__
|
||||||
|
container_name: dify-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
command: ["redis-server", "--appendonly", "yes"]
|
||||||
|
volumes:
|
||||||
|
- dify-redis:/data
|
||||||
|
dify-api:
|
||||||
|
image: langgenius/dify-api:__DIFY_TAG__
|
||||||
|
container_name: dify-api
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql+psycopg://dify:dify@postgres:5432/dify
|
||||||
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
WEB_URL: http://localhost:8080
|
||||||
|
WORKER_QUEUE_BROKER_URL: redis://redis:6379/1
|
||||||
|
WORKER_QUEUE_BACKEND_URL: redis://redis:6379/2
|
||||||
|
volumes:
|
||||||
|
- dify-storage:/app/storage
|
||||||
|
dify-worker:
|
||||||
|
image: langgenius/dify-worker:__DIFY_TAG__
|
||||||
|
container_name: dify-worker
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- dify-api
|
||||||
|
environment:
|
||||||
|
REDIS_URL: redis://redis:6379/1
|
||||||
|
WORKER_QUEUE_BACKEND_URL: redis://redis:6379/2
|
||||||
|
API_URL: http://dify-api:5001
|
||||||
|
dify-web:
|
||||||
|
image: langgenius/dify-web:__DIFY_TAG__
|
||||||
|
container_name: dify-web
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- dify-api
|
||||||
|
environment:
|
||||||
|
VITE_API_URL: http://dify-nginx
|
||||||
|
VITE_APP_ENV: production
|
||||||
|
dify-nginx:
|
||||||
|
image: langgenius/dify-nginx:__DIFY_TAG__
|
||||||
|
container_name: dify-nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
depends_on:
|
||||||
|
- dify-api
|
||||||
|
- dify-web
|
||||||
|
environment:
|
||||||
|
API_HOST: dify-api:5001
|
||||||
|
WEB_HOST: dify-web:3000
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dify-postgres:
|
||||||
|
dify-redis:
|
||||||
|
dify-storage:
|
||||||
86
gitops/scripts/flowise/deploy-flowise.sh
Executable file
86
gitops/scripts/flowise/deploy-flowise.sh
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_NAME="Flowise"
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd)
|
||||||
|
COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml"
|
||||||
|
IMAGES_DIR="${OFFLINE_ROOT}/images"
|
||||||
|
IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}"
|
||||||
|
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
load_images() {
|
||||||
|
if ! command_exists "${IMAGE_LOAD_TOOL}"; then
|
||||||
|
echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "${IMAGES_DIR}" ]; then
|
||||||
|
echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
local tarball
|
||||||
|
for tarball in "${IMAGES_DIR}"/*.tar; do
|
||||||
|
echo "Loading container images from ${tarball}"
|
||||||
|
"${IMAGE_LOAD_TOOL}" load -i "${tarball}"
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
}
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
if command_exists docker && docker compose version >/dev/null 2>&1; then
|
||||||
|
docker compose "$@"
|
||||||
|
elif command_exists docker-compose; then
|
||||||
|
docker-compose "$@"
|
||||||
|
else
|
||||||
|
echo "Error: docker compose plugin or docker-compose binary is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: $(basename "$0") [command]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
up Load images (if available) and start ${APP_NAME}
|
||||||
|
down Stop ${APP_NAME}
|
||||||
|
load-images Only load container images from the images/ directory
|
||||||
|
status Show status of the compose application
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
IMAGE_LOAD_TOOL Override the container image loader (default: docker)
|
||||||
|
COMPOSE_FILE Override docker compose file path (default: ${COMPOSE_FILE})
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd=${1:-up}
|
||||||
|
case "${cmd}" in
|
||||||
|
up)
|
||||||
|
load_images
|
||||||
|
compose -f "${COMPOSE_FILE}" up -d
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
compose -f "${COMPOSE_FILE}" down
|
||||||
|
;;
|
||||||
|
load-images)
|
||||||
|
load_images
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
compose -f "${COMPOSE_FILE}" ps
|
||||||
|
;;
|
||||||
|
-h|--help|help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: ${cmd}" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
19
gitops/scripts/flowise/docker-compose.yaml
Normal file
19
gitops/scripts/flowise/docker-compose.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
flowise:
|
||||||
|
image: flowiseai/flowise:__FLOWISE_TAG__
|
||||||
|
container_name: flowise-app
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
PORT: 3000
|
||||||
|
FLOWISE_USERNAME: admin
|
||||||
|
FLOWISE_PASSWORD: changeme
|
||||||
|
DATABASE_PATH: /data/flowise.sqlite
|
||||||
|
volumes:
|
||||||
|
- flowise-data:/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
flowise-data:
|
||||||
86
gitops/scripts/n8n/deploy-n8n.sh
Executable file
86
gitops/scripts/n8n/deploy-n8n.sh
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_NAME="n8n"
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd)
|
||||||
|
COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml"
|
||||||
|
IMAGES_DIR="${OFFLINE_ROOT}/images"
|
||||||
|
IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}"
|
||||||
|
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
load_images() {
|
||||||
|
if ! command_exists "${IMAGE_LOAD_TOOL}"; then
|
||||||
|
echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "${IMAGES_DIR}" ]; then
|
||||||
|
echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
local tarball
|
||||||
|
for tarball in "${IMAGES_DIR}"/*.tar; do
|
||||||
|
echo "Loading container images from ${tarball}"
|
||||||
|
"${IMAGE_LOAD_TOOL}" load -i "${tarball}"
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
}
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
if command_exists docker && docker compose version >/dev/null 2>&1; then
|
||||||
|
docker compose "$@"
|
||||||
|
elif command_exists docker-compose; then
|
||||||
|
docker-compose "$@"
|
||||||
|
else
|
||||||
|
echo "Error: docker compose plugin or docker-compose binary is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: $(basename "$0") [command]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
up Load images (if available) and start ${APP_NAME}
|
||||||
|
down Stop ${APP_NAME}
|
||||||
|
load-images Only load container images from the images/ directory
|
||||||
|
status Show status of the compose application
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
IMAGE_LOAD_TOOL Override the container image loader (default: docker)
|
||||||
|
COMPOSE_FILE Override docker compose file path (default: ${COMPOSE_FILE})
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd=${1:-up}
|
||||||
|
case "${cmd}" in
|
||||||
|
up)
|
||||||
|
load_images
|
||||||
|
compose -f "${COMPOSE_FILE}" up -d
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
compose -f "${COMPOSE_FILE}" down
|
||||||
|
;;
|
||||||
|
load-images)
|
||||||
|
load_images
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
compose -f "${COMPOSE_FILE}" ps
|
||||||
|
;;
|
||||||
|
-h|--help|help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: ${cmd}" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
37
gitops/scripts/n8n/docker-compose.yaml
Normal file
37
gitops/scripts/n8n/docker-compose.yaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:__POSTGRES_TAG__
|
||||||
|
container_name: n8n-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: n8n
|
||||||
|
POSTGRES_USER: n8n
|
||||||
|
POSTGRES_PASSWORD: n8n
|
||||||
|
volumes:
|
||||||
|
- n8n-postgres:/var/lib/postgresql/data
|
||||||
|
n8n:
|
||||||
|
image: n8nio/n8n:__N8N_TAG__
|
||||||
|
container_name: n8n-app
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
ports:
|
||||||
|
- "5678:5678"
|
||||||
|
environment:
|
||||||
|
DB_TYPE: postgresdb
|
||||||
|
DB_POSTGRESDB_HOST: postgres
|
||||||
|
DB_POSTGRESDB_PORT: 5432
|
||||||
|
DB_POSTGRESDB_DATABASE: n8n
|
||||||
|
DB_POSTGRESDB_USER: n8n
|
||||||
|
DB_POSTGRESDB_PASSWORD: n8n
|
||||||
|
N8N_BASIC_AUTH_ACTIVE: "true"
|
||||||
|
N8N_BASIC_AUTH_USER: admin
|
||||||
|
N8N_BASIC_AUTH_PASSWORD: changeme
|
||||||
|
volumes:
|
||||||
|
- n8n-data:/home/node/.n8n
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
n8n-postgres:
|
||||||
|
n8n-data:
|
||||||
86
gitops/scripts/ragflow/deploy-ragflow.sh
Executable file
86
gitops/scripts/ragflow/deploy-ragflow.sh
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_NAME="RAGFlow"
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
OFFLINE_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd)
|
||||||
|
COMPOSE_FILE="${OFFLINE_ROOT}/docker-compose.yaml"
|
||||||
|
IMAGES_DIR="${OFFLINE_ROOT}/images"
|
||||||
|
IMAGE_LOAD_TOOL="${IMAGE_LOAD_TOOL:-docker}"
|
||||||
|
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
load_images() {
|
||||||
|
if ! command_exists "${IMAGE_LOAD_TOOL}"; then
|
||||||
|
echo "Error: image loader '${IMAGE_LOAD_TOOL}' not found in PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "${IMAGES_DIR}" ]; then
|
||||||
|
echo "No images directory found at ${IMAGES_DIR}. Skipping image load." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
local tarball
|
||||||
|
for tarball in "${IMAGES_DIR}"/*.tar; do
|
||||||
|
echo "Loading container images from ${tarball}"
|
||||||
|
"${IMAGE_LOAD_TOOL}" load -i "${tarball}"
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
}
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
if command_exists docker && docker compose version >/dev/null 2>&1; then
|
||||||
|
docker compose "$@"
|
||||||
|
elif command_exists docker-compose; then
|
||||||
|
docker-compose "$@"
|
||||||
|
else
|
||||||
|
echo "Error: docker compose plugin or docker-compose binary is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: $(basename "$0") [command]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
up Load images (if available) and start ${APP_NAME}
|
||||||
|
down Stop ${APP_NAME}
|
||||||
|
load-images Only load container images from the images/ directory
|
||||||
|
status Show status of the compose application
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
IMAGE_LOAD_TOOL Override the container image loader (default: docker)
|
||||||
|
COMPOSE_FILE Override docker compose file path (default: ${COMPOSE_FILE})
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd=${1:-up}
|
||||||
|
case "${cmd}" in
|
||||||
|
up)
|
||||||
|
load_images
|
||||||
|
compose -f "${COMPOSE_FILE}" up -d
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
compose -f "${COMPOSE_FILE}" down
|
||||||
|
;;
|
||||||
|
load-images)
|
||||||
|
load_images
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
compose -f "${COMPOSE_FILE}" ps
|
||||||
|
;;
|
||||||
|
-h|--help|help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: ${cmd}" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
37
gitops/scripts/ragflow/docker-compose.yaml
Normal file
37
gitops/scripts/ragflow/docker-compose.yaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:__POSTGRES_TAG__
|
||||||
|
container_name: ragflow-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ragflow
|
||||||
|
POSTGRES_USER: ragflow
|
||||||
|
POSTGRES_PASSWORD: ragflow
|
||||||
|
volumes:
|
||||||
|
- ragflow-postgres:/var/lib/postgresql/data
|
||||||
|
redis:
|
||||||
|
image: redis:__REDIS_TAG__
|
||||||
|
container_name: ragflow-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
command: ["redis-server", "--appendonly", "yes"]
|
||||||
|
volumes:
|
||||||
|
- ragflow-redis:/data
|
||||||
|
ragflow:
|
||||||
|
image: ragflow/ragflow:__RAGFLOW_TAG__
|
||||||
|
container_name: ragflow-app
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- redis
|
||||||
|
ports:
|
||||||
|
- "3001:3000"
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://ragflow:ragflow@postgres:5432/ragflow
|
||||||
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
SECRET_KEY: changeme
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
ragflow-postgres:
|
||||||
|
ragflow-redis:
|
||||||
29
oci/base/cuda/Makefile
Normal file
29
oci/base/cuda/Makefile
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
ORG ?= your-org
|
||||||
|
REGISTRY ?= ghcr.io/$(ORG)/model-serving
|
||||||
|
VLLM_TAG ?= cuda12
|
||||||
|
SGLANG_TAG ?= cuda12
|
||||||
|
OLLAMA_TAG ?= latest
|
||||||
|
|
||||||
|
.PHONY: docker-build docker-push docker-build-vllm docker-build-sglang docker-build-ollama docker-push-vllm docker-push-sglang docker-push-ollama
|
||||||
|
|
||||||
|
docker-build: docker-build-vllm docker-build-sglang docker-build-ollama
|
||||||
|
|
||||||
|
docker-push: docker-push-vllm docker-push-sglang docker-push-ollama
|
||||||
|
|
||||||
|
docker-build-vllm:
|
||||||
|
docker build -t $(REGISTRY)/vllm:$(VLLM_TAG) vLLM
|
||||||
|
|
||||||
|
docker-build-sglang:
|
||||||
|
docker build -t $(REGISTRY)/sglang:$(SGLANG_TAG) SGLang
|
||||||
|
|
||||||
|
docker-build-ollama:
|
||||||
|
docker build -t $(REGISTRY)/ollama:$(OLLAMA_TAG) Ollama
|
||||||
|
|
||||||
|
docker-push-vllm:
|
||||||
|
docker push $(REGISTRY)/vllm:$(VLLM_TAG)
|
||||||
|
|
||||||
|
docker-push-sglang:
|
||||||
|
docker push $(REGISTRY)/sglang:$(SGLANG_TAG)
|
||||||
|
|
||||||
|
docker-push-ollama:
|
||||||
|
docker push $(REGISTRY)/ollama:$(OLLAMA_TAG)
|
||||||
28
oci/base/cuda/Ollama/Dockerfile
Normal file
28
oci/base/cuda/Ollama/Dockerfile
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Ollama runtime image that leans on host NVIDIA drivers via container toolkit
|
||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
curl ca-certificates unzip gnupg \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN curl -fsSL https://ollama.com/download/ollama-linux-amd64.tgz | tar -xz -C /usr/local/bin \
|
||||||
|
&& chmod +x /usr/local/bin/ollama
|
||||||
|
|
||||||
|
RUN useradd -m -u 10001 app && mkdir -p /home/app/.ollama && chown -R app:app /home/app
|
||||||
|
USER app
|
||||||
|
|
||||||
|
ENV OLLAMA_HOST=0.0.0.0:11434 \
|
||||||
|
OLLAMA_MODELS=/home/app/.ollama/models \
|
||||||
|
OLLAMA_MODEL="phi3:latest"
|
||||||
|
|
||||||
|
EXPOSE 11434
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s CMD curl -fsS http://127.0.0.1:11434/api/tags || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT ["bash","-lc","set -euo pipefail; \
|
||||||
|
ollama serve & \
|
||||||
|
for i in $(seq 1 30); do sleep 1; curl -fsS http://127.0.0.1:11434/api/tags && break || true; done; \
|
||||||
|
ollama pull \"$OLLAMA_MODEL\" || true; \
|
||||||
|
wait -n"]
|
||||||
30
oci/base/cuda/SGLang/Dockerfile
Normal file
30
oci/base/cuda/SGLang/Dockerfile
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# CUDA 12.1 runtime base for SGLang
|
||||||
|
FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
python3 python3-venv python3-pip git curl ca-certificates build-essential \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
ENV PIP_NO_CACHE_DIR=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
RUN pip3 install --upgrade pip \
|
||||||
|
&& pip3 install --extra-index-url https://download.pytorch.org/whl/cu121 \
|
||||||
|
torch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 \
|
||||||
|
&& pip3 install sglang==0.2.3 uvicorn fastapi
|
||||||
|
|
||||||
|
EXPOSE 30000
|
||||||
|
|
||||||
|
ENV SGLANG_MODEL="Qwen/Qwen2-7B-Instruct" \
|
||||||
|
SGLANG_PORT=30000 \
|
||||||
|
SGLANG_ARGS="--tp 1 --context-length 8192"
|
||||||
|
|
||||||
|
RUN useradd -m -u 10001 app && mkdir -p /models && chown -R app:app /models
|
||||||
|
USER app
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s CMD curl -fsS http://127.0.0.1:${SGLANG_PORT}/v1/models || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT ["bash","-lc","python3 -m sglang.launch_server --model \"$SGLANG_MODEL\" --port $SGLANG_PORT --trust-remote-code --enable-openai-compatible-api $SGLANG_ARGS"]
|
||||||
33
oci/base/cuda/vLLM/Dockerfile
Normal file
33
oci/base/cuda/vLLM/Dockerfile
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# CUDA 12.1 + cuDNN8 runtime base — tested with recent PyTorch wheels
|
||||||
|
FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# System deps + Python
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
python3 python3-venv python3-pip git curl ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
ENV PIP_NO_CACHE_DIR=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# Install CUDA-enabled PyTorch + vLLM
|
||||||
|
RUN pip3 install --upgrade pip \
|
||||||
|
&& pip3 install --extra-index-url https://download.pytorch.org/whl/cu121 \
|
||||||
|
torch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 \
|
||||||
|
&& pip3 install vllm==0.5.2 uvicorn fastapi
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
ENV MODEL_PATH="meta-llama/Meta-Llama-3-8B-Instruct" \
|
||||||
|
VLLM_ARGS="--max-model-len 8192 --gpu-memory-utilization 0.9" \
|
||||||
|
HF_HOME=/models/.cache \
|
||||||
|
VLLM_WORKER_USE_GRAPH_EXECUTOR=1
|
||||||
|
|
||||||
|
RUN useradd -m -u 10001 app && mkdir -p /models && chown -R app:app /models
|
||||||
|
USER app
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s CMD curl -fsS http://127.0.0.1:8000/v1/models || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT ["bash","-lc","vllm serve \"$MODEL_PATH\" --port 8000 --api-key dummy $VLLM_ARGS"]
|
||||||
15
oci/charts/README.md
Normal file
15
oci/charts/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# OCI Charts
|
||||||
|
|
||||||
|
This repository stores reusable Helm charts published to `ghcr.io/x-evor`.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
- `apps/app-service`: reusable runtime chart for application services
|
||||||
|
- `postgresql`: PostgreSQL service chart with optional `stunnel` server/client
|
||||||
|
- `observability`: observability composition chart for server and agent components
|
||||||
|
|
||||||
|
## Release Model
|
||||||
|
|
||||||
|
- Registry: `oci://ghcr.io/x-evor`
|
||||||
|
- Each chart is versioned independently
|
||||||
|
- Runtime image tags are managed by GitOps values rather than chart versions
|
||||||
6
oci/charts/apps/accounts/Chart.lock
Normal file
6
oci/charts/apps/accounts/Chart.lock
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
dependencies:
|
||||||
|
- name: app-service
|
||||||
|
repository: file://../app-service
|
||||||
|
version: 0.1.0
|
||||||
|
digest: sha256:29102607dbddc890cc60258ec869b75fd9e5f995fc8c5ee1f1a31b046b80e407
|
||||||
|
generated: "2026-04-02T17:55:26.238504+08:00"
|
||||||
11
oci/charts/apps/accounts/Chart.yaml
Normal file
11
oci/charts/apps/accounts/Chart.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: accounts-chart
|
||||||
|
description: Accounts service chart backed by the shared app-service subchart
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
dependencies:
|
||||||
|
- name: app-service
|
||||||
|
version: 0.1.0
|
||||||
|
repository: file://../app-service
|
||||||
|
alias: service
|
||||||
25
oci/charts/apps/accounts/values.yaml
Normal file
25
oci/charts/apps/accounts/values.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
service:
|
||||||
|
nameOverride: accounts
|
||||||
|
containerPort: 8080
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
global:
|
||||||
|
existingSecretName: accounts-env
|
||||||
|
repository: ghcr.io/x-evor/accounts
|
||||||
|
tag: latest
|
||||||
|
env:
|
||||||
|
PORT: "8080"
|
||||||
|
SERVICE_NAME: accounts
|
||||||
|
HEALTHCHECK_PATH: /healthz
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 20
|
||||||
6
oci/charts/apps/app-service/Chart.yaml
Normal file
6
oci/charts/apps/app-service/Chart.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: app-service
|
||||||
|
description: Reusable chart for core HTTP application services
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
26
oci/charts/apps/app-service/templates/_helpers.tpl
Normal file
26
oci/charts/apps/app-service/templates/_helpers.tpl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{{- define "app-service.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "app-service.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride -}}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- include "app-service.name" . -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "app-service.labels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "app-service.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "app-service.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
{{- default (include "app-service.fullname" .) .Values.serviceAccount.name -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- default "default" .Values.serviceAccount.name -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
128
oci/charts/apps/app-service/templates/deployment.yaml
Normal file
128
oci/charts/apps/app-service/templates/deployment.yaml
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
{{- $global := .Values.global | default dict -}}
|
||||||
|
{{- $globalRepository := $global.repository | default "" -}}
|
||||||
|
{{- $globalTag := $global.tag | default "" -}}
|
||||||
|
{{- $globalEnv := $global.env | default dict -}}
|
||||||
|
{{- $localEnv := .Values.env | default dict -}}
|
||||||
|
{{- $env := mergeOverwrite (deepCopy $globalEnv) $localEnv -}}
|
||||||
|
{{- $existingSecretName := .Values.existingSecretName | default ($global.existingSecretName | default "") -}}
|
||||||
|
{{- $imageRepository := default $globalRepository .Values.image.repository -}}
|
||||||
|
{{- $imageTag := default $globalTag .Values.image.tag -}}
|
||||||
|
{{- $globalEnvFromSecretRefs := $global.envFromSecretRefs | default list -}}
|
||||||
|
{{- $localEnvFromSecretRefs := .Values.envFromSecretRefs | default list -}}
|
||||||
|
{{- $envFromSecretRefs := concat $globalEnvFromSecretRefs $localEnvFromSecretRefs -}}
|
||||||
|
{{- $globalExternalServices := index $global "external-service" | default list -}}
|
||||||
|
{{- $localExternalServices := index .Values "external-service" | default list -}}
|
||||||
|
{{- $externalServices := concat $globalExternalServices $localExternalServices -}}
|
||||||
|
{{- if $externalServices -}}
|
||||||
|
{{- $_ := set $env "EXTERNAL_SERVICES" (join "," $externalServices) -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "app-service.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "app-service.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
revisionHistoryLimit: 3
|
||||||
|
strategy:
|
||||||
|
type: {{ .Values.strategy.type }}
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: {{ .Values.strategy.rollingUpdate.maxUnavailable }}
|
||||||
|
maxSurge: {{ .Values.strategy.rollingUpdate.maxSurge }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: {{ include "app-service.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "app-service.labels" . | nindent 8 }}
|
||||||
|
{{- with .Values.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
annotations:
|
||||||
|
{{- if and .Values.reloader.enabled $existingSecretName }}
|
||||||
|
secret.reloader.stakater.com/reload: {{ default $existingSecretName .Values.reloader.secretMatch | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ include "app-service.serviceAccountName" . }}
|
||||||
|
{{- with .Values.image.pullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- range . }}
|
||||||
|
- name: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.initContainers }}
|
||||||
|
initContainers:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: app
|
||||||
|
image: "{{ $imageRepository }}:{{ $imageTag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
{{- with .Values.command }}
|
||||||
|
command:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.args }}
|
||||||
|
args:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.workingDir }}
|
||||||
|
workingDir: {{ .Values.workingDir | quote }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.containerPort }}
|
||||||
|
{{- if $env }}
|
||||||
|
env:
|
||||||
|
{{- range $key := keys $env | sortAlpha }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ index $env $key | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if or $existingSecretName $envFromSecretRefs }}
|
||||||
|
envFrom:
|
||||||
|
{{- if $existingSecretName }}
|
||||||
|
- secretRef:
|
||||||
|
name: {{ $existingSecretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $envFromSecretRefs }}
|
||||||
|
- secretRef:
|
||||||
|
name: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.volumeMounts }}
|
||||||
|
volumeMounts:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
readinessProbe:
|
||||||
|
{{- toYaml .Values.readinessProbe | nindent 12 }}
|
||||||
|
livenessProbe:
|
||||||
|
{{- toYaml .Values.livenessProbe | nindent 12 }}
|
||||||
|
{{- with .Values.extraContainers }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.volumes }}
|
||||||
|
volumes:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
35
oci/charts/apps/app-service/templates/ingress.yaml
Normal file
35
oci/charts/apps/app-service/templates/ingress.yaml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "app-service.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "app-service.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ .host }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ default "Prefix" .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "app-service.fullname" $ }}
|
||||||
|
port:
|
||||||
|
number: {{ default $.Values.service.port .servicePort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
14
oci/charts/apps/app-service/templates/pdb.yaml
Normal file
14
oci/charts/apps/app-service/templates/pdb.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{{- if .Values.pdb.enabled }}
|
||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: {{ include "app-service.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "app-service.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
minAvailable: {{ .Values.pdb.minAvailable }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: {{ include "app-service.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
19
oci/charts/apps/app-service/templates/service.yaml
Normal file
19
oci/charts/apps/app-service/templates/service.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "app-service.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "app-service.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: {{ include "app-service.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ .Values.service.port }}
|
||||||
|
targetPort: http
|
||||||
12
oci/charts/apps/app-service/templates/serviceaccount.yaml
Normal file
12
oci/charts/apps/app-service/templates/serviceaccount.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "app-service.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "app-service.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
94
oci/charts/apps/app-service/values.yaml
Normal file
94
oci/charts/apps/app-service/values.yaml
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ""
|
||||||
|
tag: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
pullSecrets: []
|
||||||
|
|
||||||
|
command: []
|
||||||
|
args: []
|
||||||
|
workingDir: ""
|
||||||
|
|
||||||
|
containerPort: 8080
|
||||||
|
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
type: ClusterIP
|
||||||
|
annotations: {}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 0
|
||||||
|
maxSurge: 1
|
||||||
|
|
||||||
|
podLabels: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
create: false
|
||||||
|
name: ""
|
||||||
|
annotations: {}
|
||||||
|
|
||||||
|
global:
|
||||||
|
repository: ""
|
||||||
|
tag: ""
|
||||||
|
env: {}
|
||||||
|
existingSecretName: ""
|
||||||
|
external-service: []
|
||||||
|
envFromSecretRefs: []
|
||||||
|
|
||||||
|
# Local overrides remain available for backwards compatibility.
|
||||||
|
env: {}
|
||||||
|
existingSecretName: ""
|
||||||
|
external-service: []
|
||||||
|
envFromSecretRefs: []
|
||||||
|
initContainers: []
|
||||||
|
extraContainers: []
|
||||||
|
volumeMounts: []
|
||||||
|
volumes: []
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 20
|
||||||
|
|
||||||
|
pdb:
|
||||||
|
enabled: true
|
||||||
|
minAvailable: 1
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: ""
|
||||||
|
annotations: {}
|
||||||
|
tls: []
|
||||||
|
hosts: []
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
reloader:
|
||||||
|
enabled: true
|
||||||
|
secretMatch: ""
|
||||||
6
oci/charts/apps/console/Chart.lock
Normal file
6
oci/charts/apps/console/Chart.lock
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
dependencies:
|
||||||
|
- name: app-service
|
||||||
|
repository: file://../app-service
|
||||||
|
version: 0.1.0
|
||||||
|
digest: sha256:29102607dbddc890cc60258ec869b75fd9e5f995fc8c5ee1f1a31b046b80e407
|
||||||
|
generated: "2026-04-02T17:55:26.213216+08:00"
|
||||||
11
oci/charts/apps/console/Chart.yaml
Normal file
11
oci/charts/apps/console/Chart.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: console-chart
|
||||||
|
description: Console service chart backed by the shared app-service subchart
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
dependencies:
|
||||||
|
- name: app-service
|
||||||
|
version: 0.1.0
|
||||||
|
repository: file://../app-service
|
||||||
|
alias: service
|
||||||
31
oci/charts/apps/console/values.yaml
Normal file
31
oci/charts/apps/console/values.yaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
service:
|
||||||
|
nameOverride: console
|
||||||
|
containerPort: 3000
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
global:
|
||||||
|
existingSecretName: console-env
|
||||||
|
repository: ghcr.io/x-evor/console
|
||||||
|
tag: latest
|
||||||
|
env:
|
||||||
|
PORT: "3000"
|
||||||
|
SERVICE_NAME: console
|
||||||
|
HEALTHCHECK_PATH: /
|
||||||
|
DOCS_SERVICE_URL: https://docs.svc.plus
|
||||||
|
NEXT_PUBLIC_DOCS_BASE_URL: https://docs.svc.plus
|
||||||
|
external-service:
|
||||||
|
- docs.svc.plus
|
||||||
|
- xworkmate.svc.plus
|
||||||
|
- openclaw-gateway.svc.plus
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 20
|
||||||
6
oci/charts/apps/rag-server/Chart.lock
Normal file
6
oci/charts/apps/rag-server/Chart.lock
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
dependencies:
|
||||||
|
- name: app-service
|
||||||
|
repository: file://../app-service
|
||||||
|
version: 0.1.0
|
||||||
|
digest: sha256:29102607dbddc890cc60258ec869b75fd9e5f995fc8c5ee1f1a31b046b80e407
|
||||||
|
generated: "2026-04-02T17:55:26.26398+08:00"
|
||||||
11
oci/charts/apps/rag-server/Chart.yaml
Normal file
11
oci/charts/apps/rag-server/Chart.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: rag-server-chart
|
||||||
|
description: RAG server chart backed by the shared app-service subchart
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
dependencies:
|
||||||
|
- name: app-service
|
||||||
|
version: 0.1.0
|
||||||
|
repository: file://../app-service
|
||||||
|
alias: service
|
||||||
25
oci/charts/apps/rag-server/values.yaml
Normal file
25
oci/charts/apps/rag-server/values.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
service:
|
||||||
|
nameOverride: rag-server
|
||||||
|
containerPort: 8080
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
global:
|
||||||
|
existingSecretName: rag-server-env
|
||||||
|
repository: ghcr.io/x-evor/rag-server
|
||||||
|
tag: latest
|
||||||
|
env:
|
||||||
|
PORT: "8080"
|
||||||
|
SERVICE_NAME: rag-server
|
||||||
|
HEALTHCHECK_PATH: /healthz
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 20
|
||||||
18
oci/charts/observability/Chart.yaml
Normal file
18
oci/charts/observability/Chart.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: observability
|
||||||
|
description: Observability composition chart for server and agent components
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
keywords:
|
||||||
|
- observability
|
||||||
|
- prometheus
|
||||||
|
- victoria
|
||||||
|
- grafana
|
||||||
|
- otel
|
||||||
|
home: https://github.com/cloud-neutral-toolkit/observability.svc.plus
|
||||||
|
sources:
|
||||||
|
- https://github.com/cloud-neutral-toolkit/observability.svc.plus
|
||||||
|
maintainers:
|
||||||
|
- name: Cloud-Neutral Toolkit
|
||||||
|
email: admin@svc.plus
|
||||||
4
oci/charts/observability/templates/extra-objects.yaml
Normal file
4
oci/charts/observability/templates/extra-objects.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{{- range .Values.extraObjects }}
|
||||||
|
---
|
||||||
|
{{ toYaml . }}
|
||||||
|
{{- end }}
|
||||||
26
oci/charts/observability/templates/grafana-helmrelease.yaml
Normal file
26
oci/charts/observability/templates/grafana-helmrelease.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{{- if .Values.server.grafana.enabled }}
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.server.grafana.releaseName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
releaseName: {{ .Values.server.grafana.releaseName }}
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: {{ .Values.server.grafana.chart.name }}
|
||||||
|
version: {{ .Values.server.grafana.chart.version | quote }}
|
||||||
|
sourceRef:
|
||||||
|
kind: {{ .Values.server.grafana.sourceRef.kind }}
|
||||||
|
name: {{ .Values.server.grafana.sourceRef.name }}
|
||||||
|
namespace: {{ .Values.server.grafana.sourceRef.namespace }}
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
{{- toYaml .Values.server.grafana.values | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{{- if .Values.agent.nodeExporter.enabled }}
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.agent.nodeExporter.releaseName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
releaseName: {{ .Values.agent.nodeExporter.releaseName }}
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: {{ .Values.agent.nodeExporter.chart.name }}
|
||||||
|
version: {{ .Values.agent.nodeExporter.chart.version | quote }}
|
||||||
|
sourceRef:
|
||||||
|
kind: {{ .Values.agent.nodeExporter.sourceRef.kind }}
|
||||||
|
name: {{ .Values.agent.nodeExporter.sourceRef.name }}
|
||||||
|
namespace: {{ .Values.agent.nodeExporter.sourceRef.namespace }}
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
{{- toYaml .Values.agent.nodeExporter.values | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{{- if .Values.server.otelConnector.enabled }}
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.server.otelConnector.releaseName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
releaseName: {{ .Values.server.otelConnector.releaseName }}
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: {{ .Values.server.otelConnector.chart.name }}
|
||||||
|
version: {{ .Values.server.otelConnector.chart.version | quote }}
|
||||||
|
sourceRef:
|
||||||
|
kind: {{ .Values.server.otelConnector.sourceRef.kind }}
|
||||||
|
name: {{ .Values.server.otelConnector.sourceRef.name }}
|
||||||
|
namespace: {{ .Values.server.otelConnector.sourceRef.namespace }}
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
{{- toYaml .Values.server.otelConnector.values | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
65
oci/charts/observability/templates/process-exporter.yaml
Normal file
65
oci/charts/observability/templates/process-exporter.yaml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{{- if .Values.agent.processExporter.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.agent.processExporter.serviceAccountName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: process-exporter-config
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
data:
|
||||||
|
config.yaml: |
|
||||||
|
{{- .Values.agent.processExporter.config | nindent 4 }}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: process-exporter
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: process-exporter
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: process-exporter
|
||||||
|
annotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "{{ .Values.agent.processExporter.port }}"
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ .Values.agent.processExporter.serviceAccountName }}
|
||||||
|
hostPID: true
|
||||||
|
containers:
|
||||||
|
- name: process-exporter
|
||||||
|
image: "{{ .Values.agent.processExporter.image.repository }}:{{ .Values.agent.processExporter.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.agent.processExporter.image.pullPolicy }}
|
||||||
|
args:
|
||||||
|
- --procfs
|
||||||
|
- /host/proc
|
||||||
|
- --config.path
|
||||||
|
- /etc/process-exporter/config.yaml
|
||||||
|
- --web.listen-address=:{{ .Values.agent.processExporter.port }}
|
||||||
|
ports:
|
||||||
|
- name: metrics
|
||||||
|
containerPort: {{ .Values.agent.processExporter.port }}
|
||||||
|
protocol: TCP
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.agent.processExporter.resources | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/process-exporter
|
||||||
|
- name: proc
|
||||||
|
mountPath: /host/proc
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: process-exporter-config
|
||||||
|
- name: proc
|
||||||
|
hostPath:
|
||||||
|
path: /proc
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{{- if .Values.server.prometheus.enabled }}
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.server.prometheus.releaseName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
releaseName: {{ .Values.server.prometheus.releaseName }}
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: {{ .Values.server.prometheus.chart.name }}
|
||||||
|
version: {{ .Values.server.prometheus.chart.version | quote }}
|
||||||
|
sourceRef:
|
||||||
|
kind: {{ .Values.server.prometheus.sourceRef.kind }}
|
||||||
|
name: {{ .Values.server.prometheus.sourceRef.name }}
|
||||||
|
namespace: {{ .Values.server.prometheus.sourceRef.namespace }}
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
{{- toYaml .Values.server.prometheus.values | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
69
oci/charts/observability/templates/vector-agent.yaml
Normal file
69
oci/charts/observability/templates/vector-agent.yaml
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
{{- if .Values.agent.vector.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.agent.vector.serviceAccountName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: vector-agent-config
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
data:
|
||||||
|
vector.yaml: |
|
||||||
|
{{- .Values.agent.vector.config | nindent 4 }}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: vector-agent
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: vector-agent
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: vector-agent
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ .Values.agent.vector.serviceAccountName }}
|
||||||
|
containers:
|
||||||
|
- name: vector
|
||||||
|
image: "{{ .Values.agent.vector.image.repository }}:{{ .Values.agent.vector.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.agent.vector.image.pullPolicy }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.agent.vector.resources | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/vector
|
||||||
|
{{- if .Values.agent.vector.volume.enabled }}
|
||||||
|
- name: {{ .Values.agent.vector.volume.name }}
|
||||||
|
mountPath: {{ .Values.agent.vector.volume.mountPath }}
|
||||||
|
{{- end }}
|
||||||
|
- name: var-log
|
||||||
|
mountPath: /var/log
|
||||||
|
readOnly: true
|
||||||
|
- name: machine-id
|
||||||
|
mountPath: /etc/machine-id
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: vector-agent-config
|
||||||
|
{{- if .Values.agent.vector.volume.enabled }}
|
||||||
|
- name: {{ .Values.agent.vector.volume.name }}
|
||||||
|
emptyDir:
|
||||||
|
{{- if .Values.agent.vector.volume.sizeLimit }}
|
||||||
|
sizeLimit: {{ .Values.agent.vector.volume.sizeLimit }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
- name: var-log
|
||||||
|
hostPath:
|
||||||
|
path: /var/log
|
||||||
|
- name: machine-id
|
||||||
|
hostPath:
|
||||||
|
path: /etc/machine-id
|
||||||
|
type: File
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{{- if .Values.server.victoriaLogs.enabled }}
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.server.victoriaLogs.releaseName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
releaseName: {{ .Values.server.victoriaLogs.releaseName }}
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: {{ .Values.server.victoriaLogs.chart.name }}
|
||||||
|
version: {{ .Values.server.victoriaLogs.chart.version | quote }}
|
||||||
|
sourceRef:
|
||||||
|
kind: {{ .Values.server.victoriaLogs.sourceRef.kind }}
|
||||||
|
name: {{ .Values.server.victoriaLogs.sourceRef.name }}
|
||||||
|
namespace: {{ .Values.server.victoriaLogs.sourceRef.namespace }}
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
{{- toYaml .Values.server.victoriaLogs.values | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{{- if .Values.server.victoriaMetrics.enabled }}
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.server.victoriaMetrics.releaseName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
releaseName: {{ .Values.server.victoriaMetrics.releaseName }}
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: {{ .Values.server.victoriaMetrics.chart.name }}
|
||||||
|
version: {{ .Values.server.victoriaMetrics.chart.version | quote }}
|
||||||
|
sourceRef:
|
||||||
|
kind: {{ .Values.server.victoriaMetrics.sourceRef.kind }}
|
||||||
|
name: {{ .Values.server.victoriaMetrics.sourceRef.name }}
|
||||||
|
namespace: {{ .Values.server.victoriaMetrics.sourceRef.namespace }}
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
{{- toYaml .Values.server.victoriaMetrics.values | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{{- if .Values.server.victoriaTraces.enabled }}
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.server.victoriaTraces.releaseName }}
|
||||||
|
namespace: {{ .Values.namespaces.observability }}
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
releaseName: {{ .Values.server.victoriaTraces.releaseName }}
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: {{ .Values.server.victoriaTraces.chart.name }}
|
||||||
|
version: {{ .Values.server.victoriaTraces.chart.version | quote }}
|
||||||
|
sourceRef:
|
||||||
|
kind: {{ .Values.server.victoriaTraces.sourceRef.kind }}
|
||||||
|
name: {{ .Values.server.victoriaTraces.sourceRef.name }}
|
||||||
|
namespace: {{ .Values.server.victoriaTraces.sourceRef.namespace }}
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
{{- toYaml .Values.server.victoriaTraces.values | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
199
oci/charts/observability/values.yaml
Normal file
199
oci/charts/observability/values.yaml
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
namespaces:
|
||||||
|
observability: observability
|
||||||
|
|
||||||
|
server:
|
||||||
|
prometheus:
|
||||||
|
enabled: true
|
||||||
|
releaseName: prometheus
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: prometheus-community
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: prometheus
|
||||||
|
version: ">=25.0.0 <26.0.0"
|
||||||
|
values:
|
||||||
|
server:
|
||||||
|
persistentVolume:
|
||||||
|
enabled: true
|
||||||
|
size: 20Gi
|
||||||
|
prometheus-node-exporter:
|
||||||
|
enabled: false
|
||||||
|
victoriaMetrics:
|
||||||
|
enabled: true
|
||||||
|
releaseName: victoria-metrics
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: victoria-metrics
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: victoria-metrics-single
|
||||||
|
version: ">=0.13.0 <1.0.0"
|
||||||
|
values:
|
||||||
|
server:
|
||||||
|
persistentVolume:
|
||||||
|
enabled: true
|
||||||
|
size: 50Gi
|
||||||
|
victoriaLogs:
|
||||||
|
enabled: true
|
||||||
|
releaseName: victoria-logs
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: victoria-metrics
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: victoria-logs-single
|
||||||
|
version: ">=0.9.0 <1.0.0"
|
||||||
|
values:
|
||||||
|
server:
|
||||||
|
persistentVolume:
|
||||||
|
enabled: true
|
||||||
|
size: 50Gi
|
||||||
|
victoriaTraces:
|
||||||
|
enabled: true
|
||||||
|
releaseName: victoria-traces
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: victoria-metrics
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: victoria-traces-single
|
||||||
|
version: ">=0.0.1 <1.0.0"
|
||||||
|
values: {}
|
||||||
|
grafana:
|
||||||
|
enabled: false
|
||||||
|
releaseName: grafana
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: grafana
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: grafana
|
||||||
|
version: ">=8.0.0 <9.0.0"
|
||||||
|
values:
|
||||||
|
initChownData:
|
||||||
|
enabled: false
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 472
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 472
|
||||||
|
runAsGroup: 472
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 10Gi
|
||||||
|
otelConnector:
|
||||||
|
enabled: false
|
||||||
|
releaseName: otel-connector
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: open-telemetry
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: opentelemetry-collector
|
||||||
|
version: ">=0.104.0 <1.0.0"
|
||||||
|
values:
|
||||||
|
image:
|
||||||
|
repository: otel/opentelemetry-collector-contrib
|
||||||
|
mode: deployment
|
||||||
|
config:
|
||||||
|
receivers:
|
||||||
|
otlp:
|
||||||
|
protocols:
|
||||||
|
grpc: {}
|
||||||
|
http: {}
|
||||||
|
processors:
|
||||||
|
batch: {}
|
||||||
|
exporters:
|
||||||
|
debug: {}
|
||||||
|
service:
|
||||||
|
pipelines:
|
||||||
|
traces:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [debug]
|
||||||
|
metrics:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [debug]
|
||||||
|
logs:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [debug]
|
||||||
|
|
||||||
|
agent:
|
||||||
|
nodeExporter:
|
||||||
|
enabled: true
|
||||||
|
releaseName: node-exporter
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: prometheus-community
|
||||||
|
namespace: flux-system
|
||||||
|
chart:
|
||||||
|
name: prometheus-node-exporter
|
||||||
|
version: ">=4.30.0 <5.0.0"
|
||||||
|
values: {}
|
||||||
|
vector:
|
||||||
|
enabled: true
|
||||||
|
image:
|
||||||
|
repository: timberio/vector
|
||||||
|
tag: "0.36.0-distroless-libc"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
serviceAccountName: vector-agent
|
||||||
|
vlogsEndpoint: http://victoria-logs-victoria-logs-single-server.observability.svc.cluster.local:9428
|
||||||
|
config: |
|
||||||
|
data_dir: /vector-data-dir
|
||||||
|
|
||||||
|
sources:
|
||||||
|
journald:
|
||||||
|
type: journald
|
||||||
|
|
||||||
|
transforms:
|
||||||
|
normalize:
|
||||||
|
type: remap
|
||||||
|
inputs: ["journald"]
|
||||||
|
source: |
|
||||||
|
.cluster = "k3s"
|
||||||
|
.origin = "vector-agent"
|
||||||
|
|
||||||
|
sinks:
|
||||||
|
vlogs:
|
||||||
|
type: elasticsearch
|
||||||
|
inputs: ["normalize"]
|
||||||
|
endpoints:
|
||||||
|
- http://victoria-logs-victoria-logs-single-server.observability.svc.cluster.local:9428/insert/elasticsearch/
|
||||||
|
mode: bulk
|
||||||
|
compression: gzip
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 300m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
volume:
|
||||||
|
enabled: true
|
||||||
|
name: vector-data-dir
|
||||||
|
mountPath: /vector-data-dir
|
||||||
|
sizeLimit: 1Gi
|
||||||
|
processExporter:
|
||||||
|
enabled: true
|
||||||
|
image:
|
||||||
|
repository: ncabatoff/process-exporter
|
||||||
|
tag: v0.8.3
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
serviceAccountName: process-exporter
|
||||||
|
port: 9256
|
||||||
|
config: |
|
||||||
|
process_names:
|
||||||
|
- name: "{{.Comm}}"
|
||||||
|
cmdline:
|
||||||
|
- '.+'
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
extraObjects: []
|
||||||
19
oci/charts/postgresql/Chart.yaml
Normal file
19
oci/charts/postgresql/Chart.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: postgresql
|
||||||
|
description: PostgreSQL service chart with optional stunnel server and client for cloud-neutral deployments
|
||||||
|
type: application
|
||||||
|
version: 1.1.0
|
||||||
|
appVersion: "16.4"
|
||||||
|
keywords:
|
||||||
|
- postgresql
|
||||||
|
- database
|
||||||
|
- vector
|
||||||
|
- search
|
||||||
|
- queue
|
||||||
|
home: https://github.com/cloud-neutral-toolkit/postgresql.svc.plus
|
||||||
|
sources:
|
||||||
|
- https://github.com/cloud-neutral-toolkit/postgresql.svc.plus
|
||||||
|
maintainers:
|
||||||
|
- name: Cloud-Neutral Toolkit
|
||||||
|
email: admin@svc.plus
|
||||||
|
icon: https://www.postgresql.org/media/img/about/press/elephant.png
|
||||||
82
oci/charts/postgresql/templates/_helpers.tpl
Normal file
82
oci/charts/postgresql/templates/_helpers.tpl
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "postgresql.chart" . }}
|
||||||
|
{{ include "postgresql.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "postgresql.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "postgresql.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Get the password secret name
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.secretName" -}}
|
||||||
|
{{- if .Values.auth.existingSecret -}}
|
||||||
|
{{- .Values.auth.existingSecret -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- include "postgresql.fullname" . -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Get the password key
|
||||||
|
*/}}
|
||||||
|
{{- define "postgresql.secretKey" -}}
|
||||||
|
{{- if .Values.auth.existingSecret -}}
|
||||||
|
{{- .Values.auth.secretKey -}}
|
||||||
|
{{- else -}}
|
||||||
|
password
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
13
oci/charts/postgresql/templates/configmap-init-scripts.yaml
Normal file
13
oci/charts/postgresql/templates/configmap-init-scripts.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{{- if and .Values.server.enabled .Values.initScripts.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-init-scripts
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
{{- range $key, $value := .Values.initScripts.scripts }}
|
||||||
|
{{ $key }}: |
|
||||||
|
{{- $value | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
11
oci/charts/postgresql/templates/configmap-stunnel.yaml
Normal file
11
oci/charts/postgresql/templates/configmap-stunnel.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{{- if and .Values.server.enabled .Values.stunnel.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-stunnel-config
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
stunnel.conf: |
|
||||||
|
{{- .Values.stunnel.config | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
25
oci/charts/postgresql/templates/configmap.yaml
Normal file
25
oci/charts/postgresql/templates/configmap.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{{- if .Values.server.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-config
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
postgresql.conf: |
|
||||||
|
{{- .Values.postgresql.config | nindent 4 }}
|
||||||
|
|
||||||
|
{{- if .Values.postgresql.pgHba }}
|
||||||
|
pg_hba.conf: |
|
||||||
|
# TYPE DATABASE USER ADDRESS METHOD
|
||||||
|
# Default entries
|
||||||
|
local all all trust
|
||||||
|
host all all 127.0.0.1/32 trust
|
||||||
|
host all all ::1/128 trust
|
||||||
|
host all all 0.0.0.0/0 md5
|
||||||
|
host all all ::/0 md5
|
||||||
|
|
||||||
|
# Custom entries
|
||||||
|
{{- .Values.postgresql.pgHba | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
11
oci/charts/postgresql/templates/secret.yaml
Normal file
11
oci/charts/postgresql/templates/secret.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{{- if and .Values.server.enabled (not .Values.auth.existingSecret) }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
password: {{ .Values.auth.password | b64enc | quote }}
|
||||||
|
{{- end }}
|
||||||
21
oci/charts/postgresql/templates/service-metrics.yaml
Normal file
21
oci/charts/postgresql/templates/service-metrics.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{{- if and .Values.server.enabled .Values.metrics.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-metrics
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.metrics.service.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 "postgresql.selectorLabels" . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
27
oci/charts/postgresql/templates/service.yaml
Normal file
27
oci/charts/postgresql/templates/service.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{{- if .Values.server.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: postgres
|
||||||
|
protocol: TCP
|
||||||
|
name: postgres
|
||||||
|
{{- if .Values.stunnel.enabled }}
|
||||||
|
- port: {{ .Values.stunnel.port }}
|
||||||
|
targetPort: stunnel
|
||||||
|
protocol: TCP
|
||||||
|
name: stunnel
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
{{- include "postgresql.selectorLabels" . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
12
oci/charts/postgresql/templates/serviceaccount.yaml
Normal file
12
oci/charts/postgresql/templates/serviceaccount.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{{- if and .Values.server.enabled .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
203
oci/charts/postgresql/templates/statefulset.yaml
Normal file
203
oci/charts/postgresql/templates/statefulset.yaml
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
{{- if .Values.server.enabled }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
serviceName: {{ include "postgresql.fullname" . }}
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "postgresql.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
||||||
|
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "postgresql.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: postgresql
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
containerPort: 5432
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: {{ .Values.auth.username | quote }}
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "postgresql.secretName" . }}
|
||||||
|
key: {{ include "postgresql.secretKey" . }}
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: {{ .Values.auth.database | quote }}
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
{{- if .Values.livenessProbe.enabled }}
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- pg_isready -U {{ .Values.auth.username }}
|
||||||
|
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:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- pg_isready -U {{ .Values.auth.username }}
|
||||||
|
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: /var/lib/postgresql/data
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/postgresql
|
||||||
|
{{- if .Values.initScripts.enabled }}
|
||||||
|
- name: init-scripts
|
||||||
|
mountPath: /docker-entrypoint-initdb.d
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.tls.enabled }}
|
||||||
|
- name: tls-certs
|
||||||
|
mountPath: /etc/postgresql/certs
|
||||||
|
readOnly: true
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.stunnel.enabled }}
|
||||||
|
- name: stunnel
|
||||||
|
image: "{{ .Values.stunnel.image.repository }}:{{ .Values.stunnel.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.stunnel.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: stunnel
|
||||||
|
containerPort: {{ .Values.stunnel.port }}
|
||||||
|
protocol: TCP
|
||||||
|
volumeMounts:
|
||||||
|
- name: stunnel-config
|
||||||
|
mountPath: /etc/stunnel/stunnel.conf
|
||||||
|
subPath: stunnel.conf
|
||||||
|
{{- if .Values.stunnel.certificatesSecret }}
|
||||||
|
- name: stunnel-certs
|
||||||
|
mountPath: /etc/stunnel/certs
|
||||||
|
readOnly: true
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.metrics.enabled }}
|
||||||
|
- name: metrics
|
||||||
|
image: "{{ .Values.metrics.image.repository }}:{{ .Values.metrics.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.metrics.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: metrics
|
||||||
|
containerPort: 9187
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: DATA_SOURCE_NAME
|
||||||
|
value: "postgresql://{{ .Values.auth.username }}:$(POSTGRES_PASSWORD)@localhost:5432/{{ .Values.auth.database }}?sslmode=disable"
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "postgresql.secretName" . }}
|
||||||
|
key: {{ include "postgresql.secretKey" . }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.metrics.resources | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-config
|
||||||
|
{{- if .Values.initScripts.enabled }}
|
||||||
|
- name: init-scripts
|
||||||
|
configMap:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-init-scripts
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.tls.enabled }}
|
||||||
|
- name: tls-certs
|
||||||
|
secret:
|
||||||
|
secretName: {{ .Values.tls.certificatesSecret }}
|
||||||
|
defaultMode: 0600
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.stunnel.enabled }}
|
||||||
|
- name: stunnel-config
|
||||||
|
configMap:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-stunnel-config
|
||||||
|
{{- if .Values.stunnel.certificatesSecret }}
|
||||||
|
- name: stunnel-certs
|
||||||
|
secret:
|
||||||
|
secretName: {{ .Values.stunnel.certificatesSecret }}
|
||||||
|
defaultMode: 0600
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- 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 .Values.persistence.enabled }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
{{- with .Values.persistence.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 10 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
{{- range .Values.persistence.accessModes }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.persistence.storageClass | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.persistence.size | quote }}
|
||||||
|
{{- with .Values.persistence.selector }}
|
||||||
|
selector:
|
||||||
|
{{- toYaml . | nindent 10 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
- name: data
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{{- if .Values.stunnelClient.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-stunnel-client
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
stunnel.conf: |
|
||||||
|
{{- .Values.stunnelClient.config | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
{{- if .Values.stunnelClient.enabled }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-stunnel-client
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.stunnelClient.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: {{ include "postgresql.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/component: stunnel-client
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ include "postgresql.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/component: stunnel-client
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: stunnel-client
|
||||||
|
image: "{{ .Values.stunnelClient.image.repository }}:{{ .Values.stunnelClient.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.stunnelClient.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
containerPort: {{ .Values.stunnelClient.service.port }}
|
||||||
|
protocol: TCP
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.stunnelClient.resources | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/stunnel/stunnel.conf
|
||||||
|
subPath: stunnel.conf
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-stunnel-client
|
||||||
|
{{- end }}
|
||||||
23
oci/charts/postgresql/templates/stunnel-client-service.yaml
Normal file
23
oci/charts/postgresql/templates/stunnel-client-service.yaml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{{- if .Values.stunnelClient.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "postgresql.fullname" . }}-stunnel-client
|
||||||
|
labels:
|
||||||
|
{{- include "postgresql.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.stunnelClient.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.stunnelClient.service.type }}
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: {{ .Values.stunnelClient.service.port }}
|
||||||
|
targetPort: postgres
|
||||||
|
protocol: TCP
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: {{ include "postgresql.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/component: stunnel-client
|
||||||
|
{{- end }}
|
||||||
245
oci/charts/postgresql/values.yaml
Normal file
245
oci/charts/postgresql/values.yaml
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
# Default values for postgresql chart
|
||||||
|
|
||||||
|
server:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Image configuration
|
||||||
|
image:
|
||||||
|
repository: postgres-extensions
|
||||||
|
tag: "16"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Image pull secrets for private registries
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
# Override name
|
||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
# Service account
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
annotations: {}
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
# Pod annotations
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
# Pod security context
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 999
|
||||||
|
|
||||||
|
# Container security context
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 999
|
||||||
|
runAsNonRoot: true
|
||||||
|
# capabilities:
|
||||||
|
# drop:
|
||||||
|
# - ALL
|
||||||
|
# readOnlyRootFilesystem: true
|
||||||
|
|
||||||
|
# Service configuration
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 5432
|
||||||
|
annotations: {}
|
||||||
|
|
||||||
|
# Ingress (not typically used for PostgreSQL, but available)
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: ""
|
||||||
|
annotations: {}
|
||||||
|
hosts: []
|
||||||
|
tls: []
|
||||||
|
|
||||||
|
# PostgreSQL authentication
|
||||||
|
auth:
|
||||||
|
username: postgres
|
||||||
|
password: "" # Set this or use existingSecret
|
||||||
|
database: postgres
|
||||||
|
existingSecret: "" # Name of existing secret with password
|
||||||
|
secretKey: "password" # Key in the secret
|
||||||
|
|
||||||
|
# PostgreSQL configuration
|
||||||
|
postgresql:
|
||||||
|
# Custom postgresql.conf settings
|
||||||
|
config: |
|
||||||
|
shared_buffers = 256MB
|
||||||
|
effective_cache_size = 1GB
|
||||||
|
work_mem = 16MB
|
||||||
|
maintenance_work_mem = 64MB
|
||||||
|
max_connections = 100
|
||||||
|
wal_buffers = 16MB
|
||||||
|
checkpoint_completion_target = 0.9
|
||||||
|
random_page_cost = 1.1
|
||||||
|
effective_io_concurrency = 200
|
||||||
|
log_min_duration_statement = 1000
|
||||||
|
|
||||||
|
# Custom pg_hba.conf entries (appended to defaults)
|
||||||
|
pgHba: |
|
||||||
|
# Custom entries
|
||||||
|
# host all all 0.0.0.0/0 md5
|
||||||
|
|
||||||
|
# Initialization scripts
|
||||||
|
initScripts:
|
||||||
|
enabled: true
|
||||||
|
# Scripts will be created from the scripts below
|
||||||
|
scripts:
|
||||||
|
01-init-extensions.sql: |
|
||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pg_jieba;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgmq;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS hstore;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
# Persistence
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: "" # Use default storage class
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
size: 10Gi
|
||||||
|
annotations: {}
|
||||||
|
selector: {}
|
||||||
|
|
||||||
|
# Resource limits
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 2000m
|
||||||
|
memory: 2Gi
|
||||||
|
requests:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 1Gi
|
||||||
|
|
||||||
|
# Liveness probe
|
||||||
|
livenessProbe:
|
||||||
|
enabled: true
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
successThreshold: 1
|
||||||
|
|
||||||
|
# Readiness probe
|
||||||
|
readinessProbe:
|
||||||
|
enabled: true
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
successThreshold: 1
|
||||||
|
|
||||||
|
# Node selector
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
# Tolerations
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
# Affinity
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
# Metrics (for Prometheus)
|
||||||
|
metrics:
|
||||||
|
enabled: false
|
||||||
|
image:
|
||||||
|
repository: prometheuscommunity/postgres-exporter
|
||||||
|
tag: v0.15.0
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 9187
|
||||||
|
annotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "9187"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
# Backup configuration (optional)
|
||||||
|
backup:
|
||||||
|
enabled: false
|
||||||
|
schedule: "0 2 * * *" # Daily at 2 AM
|
||||||
|
retention: 7 # Keep 7 days of backups
|
||||||
|
storageClass: ""
|
||||||
|
size: 20Gi
|
||||||
|
|
||||||
|
# TLS/SSL configuration
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
certificatesSecret: "" # Name of secret containing tls.crt and tls.key
|
||||||
|
certFilename: "tls.crt"
|
||||||
|
certKeyFilename: "tls.key"
|
||||||
|
certCAFilename: "ca.crt"
|
||||||
|
|
||||||
|
# Stunnel sidecar for TLS over TCP
|
||||||
|
stunnel:
|
||||||
|
enabled: false
|
||||||
|
image:
|
||||||
|
repository: dweomer/stunnel
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
port: 5433
|
||||||
|
certificatesSecret: "" # Name of secret containing stunnel certificates
|
||||||
|
config: |
|
||||||
|
[postgres-tunnel]
|
||||||
|
client = no
|
||||||
|
accept = 0.0.0.0:5433
|
||||||
|
connect = 127.0.0.1:5432
|
||||||
|
cert = /etc/stunnel/certs/server-cert.pem
|
||||||
|
key = /etc/stunnel/certs/server-key.pem
|
||||||
|
sslVersion = TLSv1.2
|
||||||
|
options = NO_SSLv2
|
||||||
|
options = NO_SSLv3
|
||||||
|
ciphers = HIGH:!aNULL:!MD5
|
||||||
|
|
||||||
|
# NetworkPolicy
|
||||||
|
networkPolicy:
|
||||||
|
enabled: false
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector: {}
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 5432
|
||||||
|
|
||||||
|
# PodDisruptionBudget
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
minAvailable: 1
|
||||||
|
# maxUnavailable: 1
|
||||||
|
|
||||||
|
stunnelClient:
|
||||||
|
enabled: false
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: dweomer/stunnel
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 5432
|
||||||
|
annotations: {}
|
||||||
|
config: |
|
||||||
|
[postgres-client]
|
||||||
|
client = yes
|
||||||
|
accept = 0.0.0.0:5432
|
||||||
|
connect = postgresql.database.svc.cluster.local:5433
|
||||||
|
verifyChain = no
|
||||||
|
sslVersion = TLSv1.2
|
||||||
|
options = NO_SSLv2
|
||||||
|
options = NO_SSLv3
|
||||||
|
ciphers = HIGH:!aNULL:!MD5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 64Mi
|
||||||
35
oci/multi-model-LLM/Makefile
Normal file
35
oci/multi-model-LLM/Makefile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
ORG ?= your-org
|
||||||
|
IMAGE_REGISTRY ?= ghcr.io/$(ORG)/model-serving
|
||||||
|
CHART_NAME ?= model-serving
|
||||||
|
CHART_DIR := charts/$(CHART_NAME)
|
||||||
|
VERSION ?= 0.1.0
|
||||||
|
|
||||||
|
.PHONY: docker-build docker-push helm-lint helm-package helm-push install uninstall template
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
$(MAKE) -C ../base/cuda docker-build REGISTRY=$(IMAGE_REGISTRY)
|
||||||
|
|
||||||
|
docker-push:
|
||||||
|
$(MAKE) -C ../base/cuda docker-push REGISTRY=$(IMAGE_REGISTRY)
|
||||||
|
|
||||||
|
helm-lint:
|
||||||
|
helm lint $(CHART_DIR)
|
||||||
|
|
||||||
|
helm-package:
|
||||||
|
helm package $(CHART_DIR) --version $(VERSION) --app-version $(VERSION) -d charts/
|
||||||
|
|
||||||
|
helm-push: helm-package
|
||||||
|
helm push charts/$(CHART_NAME)-$(VERSION).tgz oci://ghcr.io/$(ORG)/helm
|
||||||
|
|
||||||
|
RELEASE ?= ms
|
||||||
|
NAMESPACE ?= llm
|
||||||
|
|
||||||
|
install:
|
||||||
|
kubectl create ns $(NAMESPACE) --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
helm upgrade --install $(RELEASE) $(CHART_DIR) -n $(NAMESPACE)
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
helm uninstall $(RELEASE) -n $(NAMESPACE) || true
|
||||||
|
|
||||||
|
template:
|
||||||
|
helm template $(RELEASE) $(CHART_DIR)
|
||||||
101
oci/multi-model-LLM/README.md
Normal file
101
oci/multi-model-LLM/README.md
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# CUDA LLM Serving — vLLM / SGLang / Ollama (Kubernetes)
|
||||||
|
|
||||||
|
This package bundles three CUDA-ready images plus a single Helm chart that can serve **multiple models** behind one host with **path-based routing** such as:
|
||||||
|
|
||||||
|
- `https://api.svc.plus/v1/llama3` → vLLM (OpenAI-compatible)
|
||||||
|
- `https://api.svc.plus/v1/qwen2` → SGLang (OpenAI-compatible)
|
||||||
|
- `https://api.svc.plus/v1/phi3` → Ollama `/api/*`
|
||||||
|
|
||||||
|
The Dockerfiles live under [`oci/base/cuda`](../base/cuda/), while the Helm chart is in [`charts/model-serving`](charts/model-serving/).
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes ≥ 1.25
|
||||||
|
- NVIDIA GPUs on worker nodes + NVIDIA Container Toolkit
|
||||||
|
- Ingress Controller (e.g. NGINX) and TLS secret if using HTTPS
|
||||||
|
- (Optional) GitHub Container Registry (GHCR) for distributing images and charts
|
||||||
|
|
||||||
|
## Build & Publish
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1) Build and push images to GHCR (adjust ORG)
|
||||||
|
make -C oci/base/cuda ORG=svc-design docker-build docker-push
|
||||||
|
|
||||||
|
# 2) Lint & package the chart
|
||||||
|
make -C oci/multi-model-LLM helm-lint helm-package VERSION=0.1.0
|
||||||
|
|
||||||
|
# 3) Push chart as OCI to GHCR
|
||||||
|
make -C oci/multi-model-LLM ORG=svc-design VERSION=0.1.0 helm-push
|
||||||
|
```
|
||||||
|
|
||||||
|
> Authenticate GHCR first:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> echo $GHCR_TOKEN | docker login ghcr.io -u <GITHUB_USER> --password-stdin
|
||||||
|
> helm registry login ghcr.io -u <GITHUB_USER> -p $GHCR_TOKEN
|
||||||
|
> ```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# install into namespace llm with release name ms
|
||||||
|
make -C oci/multi-model-LLM install RELEASE=ms NAMESPACE=llm
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configure Models
|
||||||
|
|
||||||
|
Edit [`charts/model-serving/values.yaml`](charts/model-serving/values.yaml) and extend the `models:` list. Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
models:
|
||||||
|
- name: llama3-8b-vllm
|
||||||
|
engine: vllm
|
||||||
|
image: "model-serving/vllm"
|
||||||
|
tag: "cuda12"
|
||||||
|
path: v1/llama3
|
||||||
|
env:
|
||||||
|
- name: MODEL_PATH
|
||||||
|
value: meta-llama/Meta-Llama-3-8B-Instruct
|
||||||
|
- name: VLLM_ARGS
|
||||||
|
value: --max-model-len 8192 --gpu-memory-utilization 0.9
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
nvidia.com/gpu: 1
|
||||||
|
|
||||||
|
- name: qwen2-7b-sglang
|
||||||
|
engine: sglang
|
||||||
|
image: "model-serving/sglang"
|
||||||
|
tag: "cuda12"
|
||||||
|
path: v1/qwen2
|
||||||
|
env:
|
||||||
|
- name: SGLANG_MODEL
|
||||||
|
value: Qwen/Qwen2-7B-Instruct
|
||||||
|
|
||||||
|
- name: phi3-ollama
|
||||||
|
engine: ollama
|
||||||
|
image: "model-serving/ollama"
|
||||||
|
tag: latest
|
||||||
|
path: v1/phi3
|
||||||
|
env:
|
||||||
|
- name: OLLAMA_MODEL
|
||||||
|
value: phi3:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Deployments and services are generated per model, and a single ingress exposes them under unique paths.
|
||||||
|
|
||||||
|
## Runtime Notes
|
||||||
|
|
||||||
|
* **GPU scheduling**: Templates set `runtimeClassName: nvidia` and default GPU limits. Ensure the cluster has the NVIDIA device plugin and RuntimeClass defined, or override `runtimeClassName` per model.
|
||||||
|
* **Storage**: vLLM/SGLang cache defaults to the container filesystem. Mount an external volume by extending the template if persistence is required.
|
||||||
|
* **Authentication**: vLLM launches with a dummy API key. Place an API gateway or ingress authentication in front for production.
|
||||||
|
* **Scaling**: Increase `replicas` per model and add engine-specific flags through environment variables for tensor parallelism or sharding.
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make -C oci/multi-model-LLM uninstall RELEASE=ms NAMESPACE=llm
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
6
oci/multi-model-LLM/charts/model-serving/.helmignore
Normal file
6
oci/multi-model-LLM/charts/model-serving/.helmignore
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
*.tgz
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.DS_Store
|
||||||
|
.git/
|
||||||
|
.github/
|
||||||
14
oci/multi-model-LLM/charts/model-serving/Chart.yaml
Normal file
14
oci/multi-model-LLM/charts/model-serving/Chart.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: model-serving
|
||||||
|
version: 0.1.0
|
||||||
|
kubeVersion: ">=1.25.0"
|
||||||
|
description: Multi-model LLM serving (vLLM / SGLang / Ollama) with one API host & path routing
|
||||||
|
home: https://github.com/svc-design/artifacts
|
||||||
|
keywords:
|
||||||
|
- llm
|
||||||
|
- vllm
|
||||||
|
- sglang
|
||||||
|
- ollama
|
||||||
|
- cuda
|
||||||
|
- gpu
|
||||||
|
type: application
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
{{- define "model-serving.fullname" -}}
|
||||||
|
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "model-serving.svcname" -}}
|
||||||
|
{{- printf "%s-svc" (include "model-serving.fullname" .) -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "model-serving.image" -}}
|
||||||
|
{{- $reg := .Values.global.imageRegistry -}}
|
||||||
|
{{- $img := .image -}}
|
||||||
|
{{- $tag := .tag | default "latest" -}}
|
||||||
|
{{- printf "%s/%s:%s" $reg $img $tag -}}
|
||||||
|
{{- end -}}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
{{- $root := . -}}
|
||||||
|
{{- range $m := .Values.models }}
|
||||||
|
{{- if eq $m.engine "ollama" }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "model-serving.fullname" $root }}-{{ $m.name }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
app.kubernetes.io/engine: ollama
|
||||||
|
spec:
|
||||||
|
replicas: {{ $m.replicas | default 1 }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
app.kubernetes.io/engine: ollama
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ $m.name }}
|
||||||
|
image: {{ include "model-serving.image" (dict "Values" $root.Values "image" $m.image "tag" $m.tag) }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
{{- if $m.env }}
|
||||||
|
env:
|
||||||
|
{{- range $m.env }}
|
||||||
|
- name: {{ .name }}
|
||||||
|
value: {{ .value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- containerPort: 11434
|
||||||
|
{{- if $m.resources }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml $m.resources | nindent 12 }}
|
||||||
|
{{- else }}
|
||||||
|
resources: {}
|
||||||
|
{{- end }}
|
||||||
|
runtimeClassName: {{ $m.runtimeClassName | default "nvidia" }}
|
||||||
|
{{- if $m.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml $m.nodeSelector | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $m.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml $m.tolerations | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $root.Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- range $root.Values.imagePullSecrets }}
|
||||||
|
- name: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
{{- $root := . -}}
|
||||||
|
{{- range $m := .Values.models }}
|
||||||
|
{{- if eq $m.engine "sglang" }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "model-serving.fullname" $root }}-{{ $m.name }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
app.kubernetes.io/engine: sglang
|
||||||
|
spec:
|
||||||
|
replicas: {{ $m.replicas | default 1 }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
app.kubernetes.io/engine: sglang
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ $m.name }}
|
||||||
|
image: {{ include "model-serving.image" (dict "Values" $root.Values "image" $m.image "tag" $m.tag) }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
{{- if $m.env }}
|
||||||
|
env:
|
||||||
|
{{- range $m.env }}
|
||||||
|
- name: {{ .name }}
|
||||||
|
value: {{ .value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- containerPort: 30000
|
||||||
|
{{- if $m.resources }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml $m.resources | nindent 12 }}
|
||||||
|
{{- else }}
|
||||||
|
resources: {}
|
||||||
|
{{- end }}
|
||||||
|
runtimeClassName: {{ $m.runtimeClassName | default "nvidia" }}
|
||||||
|
{{- if $m.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml $m.nodeSelector | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $m.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml $m.tolerations | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $root.Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- range $root.Values.imagePullSecrets }}
|
||||||
|
- name: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
{{- $root := . -}}
|
||||||
|
{{- range $m := .Values.models }}
|
||||||
|
{{- if eq $m.engine "vllm" }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "model-serving.fullname" $root }}-{{ $m.name }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
app.kubernetes.io/engine: vllm
|
||||||
|
spec:
|
||||||
|
replicas: {{ $m.replicas | default 1 }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
app.kubernetes.io/engine: vllm
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ $m.name }}
|
||||||
|
image: {{ include "model-serving.image" (dict "Values" $root.Values "image" $m.image "tag" $m.tag) }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
{{- if $m.env }}
|
||||||
|
env:
|
||||||
|
{{- range $m.env }}
|
||||||
|
- name: {{ .name }}
|
||||||
|
value: {{ .value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- containerPort: 8000
|
||||||
|
{{- if $m.resources }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml $m.resources | nindent 12 }}
|
||||||
|
{{- else }}
|
||||||
|
resources: {}
|
||||||
|
{{- end }}
|
||||||
|
runtimeClassName: {{ $m.runtimeClassName | default "nvidia" }}
|
||||||
|
{{- if $m.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml $m.nodeSelector | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $m.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml $m.tolerations | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $root.Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- range $root.Values.imagePullSecrets }}
|
||||||
|
- name: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
{{- if .Values.global.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "model-serving.fullname" . }}
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: {{ .Values.global.ingress.className | quote }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.global.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- {{ .Values.global.ingress.host | quote }}
|
||||||
|
secretName: {{ .Values.global.ingress.tlsSecretName | quote }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.global.ingress.host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .Values.models }}
|
||||||
|
- path: /{{ .path }}
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "model-serving.fullname" $ }}-{{ .name }}
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.service.port | default 80 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
{{- $root := . -}}
|
||||||
|
{{- range $m := .Values.models }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "model-serving.fullname" $root }}-{{ $m.name }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
spec:
|
||||||
|
type: {{ $root.Values.service.type | default "ClusterIP" }}
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: {{ $m.name }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ $root.Values.service.port | default 80 }}
|
||||||
|
targetPort: {{ if eq $m.engine "vllm" }}8000{{ else if eq $m.engine "sglang" }}30000{{ else }}11434{{ end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
61
oci/multi-model-LLM/charts/model-serving/values.yaml
Normal file
61
oci/multi-model-LLM/charts/model-serving/values.yaml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
global:
|
||||||
|
imageRegistry: ghcr.io/your-org
|
||||||
|
namespace: default
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
host: api.svc.plus
|
||||||
|
tls: true
|
||||||
|
tlsSecretName: model-serving-tls
|
||||||
|
|
||||||
|
models:
|
||||||
|
- name: llama3-8b-vllm
|
||||||
|
engine: vllm
|
||||||
|
image: "model-serving/vllm"
|
||||||
|
tag: "cuda12"
|
||||||
|
replicas: 1
|
||||||
|
path: v1/llama3
|
||||||
|
env:
|
||||||
|
- name: MODEL_PATH
|
||||||
|
value: "meta-llama/Meta-Llama-3-8B-Instruct"
|
||||||
|
- name: VLLM_ARGS
|
||||||
|
value: "--max-model-len 8192 --gpu-memory-utilization 0.9"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
nvidia.com/gpu: 1
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
- name: qwen2-7b-sglang
|
||||||
|
engine: sglang
|
||||||
|
image: "model-serving/sglang"
|
||||||
|
tag: "cuda12"
|
||||||
|
replicas: 1
|
||||||
|
path: v1/qwen2
|
||||||
|
env:
|
||||||
|
- name: SGLANG_MODEL
|
||||||
|
value: "Qwen/Qwen2-7B-Instruct"
|
||||||
|
- name: SGLANG_ARGS
|
||||||
|
value: "--tp 1 --context-length 8192"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
nvidia.com/gpu: 1
|
||||||
|
|
||||||
|
- name: phi3-ollama
|
||||||
|
engine: ollama
|
||||||
|
image: "model-serving/ollama"
|
||||||
|
tag: "latest"
|
||||||
|
replicas: 1
|
||||||
|
path: v1/phi3
|
||||||
|
env:
|
||||||
|
- name: OLLAMA_MODEL
|
||||||
|
value: "phi3:latest"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
nvidia.com/gpu: 1
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
imagePullSecrets: []
|
||||||
212
packer/Cloud-Neutra-VMs/README.md
Normal file
212
packer/Cloud-Neutra-VMs/README.md
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
# Cloud-Neutra Golden Image Pipeline
|
||||||
|
|
||||||
|
Cloud-Neutra Golden Image Pipeline 为多云环境构建一套统一、可靠、可自动化的 Ubuntu Golden Image 家族。
|
||||||
|
该体系覆盖 Ubuntu LTS 双版本(22.04 / 24.04)、双架构(amd64 / arm64) 以及多个容器/集群运行时的变种。
|
||||||
|
|
||||||
|
Pipeline 包含:
|
||||||
|
- Packer 自动构建 AMI
|
||||||
|
- GitHub Actions 全自动流水线(构建 → 多 Region 复制 → 过期清理)
|
||||||
|
- Terraform 模块自动引用最新 Golden Image
|
||||||
|
- 完全统一的脚本与硬化规范
|
||||||
|
|
||||||
|
## 0. Overall Goals
|
||||||
|
|
||||||
|
Ubuntu LTS Baseline
|
||||||
|
|
||||||
|
- Ubuntu 22.04 LTS
|
||||||
|
- Ubuntu 24.04 LTS
|
||||||
|
|
||||||
|
CPU Architectures
|
||||||
|
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
|
||||||
|
### Golden Image Editions
|
||||||
|
|
||||||
|
- Edition 内容说明
|
||||||
|
- base 干净操作系统 + 基础硬化(去 snap,去 MOTD,去不必要服务)
|
||||||
|
- container containerd + nerdctl,作为通用 Container VM
|
||||||
|
- k3s 预装 K3s,可在运行时决定 server/agent
|
||||||
|
- sealos 预装 sealos CLI + containerd
|
||||||
|
- sealos-gpu 适用于 GPU 节点:sealos + NVIDIA 驱动 + nvidia-container-toolkit
|
||||||
|
|
||||||
|
### Pipeline 统一要求
|
||||||
|
|
||||||
|
- 完整统一脚本结构(base → flavor)
|
||||||
|
- 去除 snap / MOTD / landscape / update-notifier 等非必要组件
|
||||||
|
- 无 amazon-import 误用(使用 amazon-ebs 构建 AMI)
|
||||||
|
|
||||||
|
GitHub Actions 统一构建 + 多 Region 复制
|
||||||
|
|
||||||
|
- 每 Edition / Version / Arch 每月仅保留 1 个 AMI
|
||||||
|
- Terraform 自动检索“最新且合法”的 Golden Image
|
||||||
|
|
||||||
|
## 1. Naming Conventions & Tagging
|
||||||
|
|
||||||
|
### AMI 命名规范
|
||||||
|
|
||||||
|
Cloud-Neutra-${edition}-VM-${ubuntu_version}-${arch}-${timestamp}
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
- Cloud-Neutra-base-VM-2204-amd64-20251121-120000
|
||||||
|
- Cloud-Neutra-container-VM-2404-arm64-20251121-123000
|
||||||
|
- Cloud-Neutra-k3s-VM-2404-amd64-20251121-130000
|
||||||
|
- Cloud-Neutra-sealos-gpu-VM-2404-amd64-20251121-133000
|
||||||
|
|
||||||
|
### 统一标签(Tags)
|
||||||
|
|
||||||
|
- Key Value
|
||||||
|
- Project Cloud-Neutra
|
||||||
|
- OS Ubuntu 22.04 / Ubuntu 24.04
|
||||||
|
- Edition base / container / k3s / sealos / sealos-gpu
|
||||||
|
- Architecture amd64 / arm64
|
||||||
|
- Role Golden-Image
|
||||||
|
|
||||||
|
这些标签用于:
|
||||||
|
|
||||||
|
GitHub Actions Retention 策略过滤
|
||||||
|
|
||||||
|
Terraform AMI 检索
|
||||||
|
多 Region 管理
|
||||||
|
生产审计与溯源
|
||||||
|
|
||||||
|
## 2 . Directory Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
packer/
|
||||||
|
templates/
|
||||||
|
base/
|
||||||
|
ubuntu-2204-base.pkr.hcl
|
||||||
|
ubuntu-2404-base.pkr.hcl
|
||||||
|
container/
|
||||||
|
ubuntu-2204-container.pkr.hcl
|
||||||
|
ubuntu-2404-container.pkr.hcl
|
||||||
|
k3s/
|
||||||
|
ubuntu-2204-k3s.pkr.hcl
|
||||||
|
ubuntu-2404-k3s.pkr.hcl
|
||||||
|
sealos/
|
||||||
|
ubuntu-2204-sealos.pkr.hcl
|
||||||
|
ubuntu-2404-sealos.pkr.hcl
|
||||||
|
sealos-gpu/
|
||||||
|
ubuntu-2204-sealos-gpu.pkr.hcl
|
||||||
|
ubuntu-2404-sealos-gpu.pkr.hcl
|
||||||
|
|
||||||
|
scripts/
|
||||||
|
base/
|
||||||
|
01_os_base.sh # 开源仓库、更新系统、移除 snap / motd 等
|
||||||
|
02_hardening.sh # 可选:sysctl / sshd / journald 硬化
|
||||||
|
flavors/
|
||||||
|
container.sh
|
||||||
|
k3s.sh
|
||||||
|
sealos.sh
|
||||||
|
sealos_gpu.sh
|
||||||
|
common/
|
||||||
|
cleanup.sh # apt autoremove + 清理临时文件
|
||||||
|
```
|
||||||
|
|
||||||
|
模板结构说明
|
||||||
|
|
||||||
|
- 每个 flavor 模板只负责:
|
||||||
|
- 指定 Ubuntu 版本与 CPU 架构
|
||||||
|
- 引用 base 脚本(01_os_base.sh / 02_hardening.sh)
|
||||||
|
- 引用 flavor 脚本(如 container.sh / k3s.sh)
|
||||||
|
- 最后引用 cleanup.sh
|
||||||
|
|
||||||
|
## 3. Script Architecture
|
||||||
|
|
||||||
|
Base Scripts (scripts/base/)
|
||||||
|
|
||||||
|
### 01_os_base.sh
|
||||||
|
|
||||||
|
启用 universe/multiverse
|
||||||
|
dist-upgrade(禁内核升级风险)
|
||||||
|
移除 snapd / resolvconf / landscape / MOTD-news
|
||||||
|
安装基础工具:curl、jq、lsb-release、net-tools、iptables
|
||||||
|
关闭 apt-daily 自动更新
|
||||||
|
|
||||||
|
### 02_hardening.sh
|
||||||
|
|
||||||
|
可选的系统硬化(sysctl、sshd、journald 持久化等)
|
||||||
|
Flavor Scripts (scripts/flavors/)
|
||||||
|
container.sh
|
||||||
|
containerd + nerdctl 安装
|
||||||
|
containerd config 自动生成
|
||||||
|
k3s.sh 安装 K3s(skip-start) 运行时可作为 server 或 agent
|
||||||
|
sealos.sh 安装 sealos CLI 依赖 containerd(可复用 container flavor)
|
||||||
|
sealos_gpu.sh 安装 NVIDIA 驱动(可扩展到不同云平台) 安装 nvidia-container-toolkit
|
||||||
|
|
||||||
|
安装 sealos
|
||||||
|
|
||||||
|
Common Scripts (scripts/common/)
|
||||||
|
cleanup.sh
|
||||||
|
apt autoremove
|
||||||
|
清理 apt lists
|
||||||
|
|
||||||
|
清理 tmp
|
||||||
|
|
||||||
|
packer build -var cpu_arch=amd64 packer/templates/container/ubuntu-2404-container.pkr.hcl
|
||||||
|
packer build -var cpu_arch=arm64 packer/templates/k3s/ubuntu-2404-k3s.pkr.hcl
|
||||||
|
|
||||||
|
|
||||||
|
4. GitHub Actions Pipeline
|
||||||
|
|
||||||
|
Pipeline 负责:
|
||||||
|
Packer 构建 AMI(按 edition + Ubuntu version + arch)
|
||||||
|
AMI 复制到多 Region(如 Tokyo/HK/US-West)
|
||||||
|
Tag AMI
|
||||||
|
按 edition/version/arch 筛选 → 每 Region 仅保留 1 个 AMI
|
||||||
|
输出 AMI Map JSON(供 Terraform & Dashboard 使用)
|
||||||
|
|
||||||
|
支持矩阵
|
||||||
|
edition: base / container / k3s / sealos / sealos-gpu
|
||||||
|
ubuntu_version: 2204 / 2404
|
||||||
|
cpu_arch: amd64 / arm64
|
||||||
|
|
||||||
|
|
||||||
|
GitHub Actions 会自动组合出所有 Golden Image 变种。
|
||||||
|
|
||||||
|
5. Terraform: Auto-Select Latest Golden Image
|
||||||
|
|
||||||
|
模块位置:
|
||||||
|
|
||||||
|
modules/cloud_neutra_ami/
|
||||||
|
main.tf
|
||||||
|
variables.tf
|
||||||
|
outputs.tf
|
||||||
|
|
||||||
|
|
||||||
|
使用方式:
|
||||||
|
|
||||||
|
module "cn_container_2404_amd64" {
|
||||||
|
source = "../../modules/cloud_neutra_ami"
|
||||||
|
ubuntu_version = "2404"
|
||||||
|
cpu_arch = "amd64"
|
||||||
|
edition = "container"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
输出:
|
||||||
|
|
||||||
|
module.cn_container_2404_amd64.id # 最新 AMI ID
|
||||||
|
module.cn_container_2404_amd64.name # AMI 名称
|
||||||
|
|
||||||
|
|
||||||
|
Terraform 会自动从目标 Region 检索最 新 Golden Image,即使你复制了多 Region。
|
||||||
|
|
||||||
|
6. Status
|
||||||
|
|
||||||
|
Cloud-Neutra Golden Image Pipeline 已具备:
|
||||||
|
完整家族命名体系(base / container / k3s / sealos / sealos-gpu)
|
||||||
|
双 LTS / 双架构覆盖
|
||||||
|
完整 Packer 模板体系
|
||||||
|
完整统一脚本(base + flavors)
|
||||||
|
GitHub Actions 自动构建、多 Region 复制、Retention
|
||||||
|
Terraform 自动引用最新 AMI 的可重用模块
|
||||||
|
整个体系作为 Cloud-Neutra IAC/GitOps 的底座,可直接扩展到:
|
||||||
|
EKS 节点(GPU/ARM)
|
||||||
|
K3s 边缘节点
|
||||||
|
Sealos 容器云节点
|
||||||
|
大模型推理 GPU 节点
|
||||||
|
通用 Container VM
|
||||||
|
DevOps 工具链
|
||||||
2
packer/Cloud-Neutra-VMs/docs/README.md
Normal file
2
packer/Cloud-Neutra-VMs/docs/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Cloud-Neutra VM Project
|
||||||
|
This directory contains documentation for building custom VM images using Packer.
|
||||||
2
packer/Cloud-Neutra-VMs/docs/environment-setup.md
Normal file
2
packer/Cloud-Neutra-VMs/docs/environment-setup.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Environment Setup
|
||||||
|
Instructions for setting up the environment for Packer builds.
|
||||||
2
packer/Cloud-Neutra-VMs/docs/packer-templates.md
Normal file
2
packer/Cloud-Neutra-VMs/docs/packer-templates.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Packer Templates
|
||||||
|
This document explains the Packer templates and their configuration.
|
||||||
110
packer/Cloud-Neutra-VMs/packer/scripts/common/ami-replicate.sh
Executable file
110
packer/Cloud-Neutra-VMs/packer/scripts/common/ami-replicate.sh
Executable file
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: $0 <AMI_ID> <EDITION> <UBUNTU_VERSION> <CPU_ARCH> <BASE_REGION> "<TARGET_REGIONS>" <PROJECT_TAG>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
$0 ami-1234567890 base 2204 amd64 ap-northeast-1 "ap-northeast-1 ap-east-1" Cloud-Neutra
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 7 ]; then
|
||||||
|
echo "[ami-replicate] ERROR: Invalid arguments" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
AMI_ID="$1"
|
||||||
|
EDITION="$2"
|
||||||
|
UBUNTU_VERSION="$3"
|
||||||
|
CPU_ARCH="$4"
|
||||||
|
BASE_REGION="$5"
|
||||||
|
TARGET_REGIONS_STR="$6"
|
||||||
|
PROJECT_TAG="$7"
|
||||||
|
|
||||||
|
if ! command -v aws >/dev/null 2>&1; then
|
||||||
|
echo "[ami-replicate] ERROR: aws CLI is required." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$TARGET_REGIONS_STR" ]; then
|
||||||
|
echo "[ami-replicate] ERROR: TARGET_REGIONS cannot be empty." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Normalize target regions into an array
|
||||||
|
IFS=' ' read -r -a TARGET_REGIONS <<< "$TARGET_REGIONS_STR"
|
||||||
|
|
||||||
|
if [ "${#TARGET_REGIONS[@]}" -eq 0 ]; then
|
||||||
|
echo "[ami-replicate] ERROR: No target regions provided." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fetch AMI metadata from base region
|
||||||
|
read -r IMAGE_NAME IMAGE_DESC <<< "$(aws ec2 describe-images \
|
||||||
|
--region "$BASE_REGION" \
|
||||||
|
--image-ids "$AMI_ID" \
|
||||||
|
--query 'Images[0].[Name,Description]' \
|
||||||
|
--output text)"
|
||||||
|
|
||||||
|
if [ -z "$IMAGE_NAME" ] || [ "$IMAGE_NAME" = "None" ]; then
|
||||||
|
echo "[ami-replicate] ERROR: Unable to resolve AMI name for $AMI_ID in $BASE_REGION" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$IMAGE_DESC" ] || [ "$IMAGE_DESC" = "None" ]; then
|
||||||
|
IMAGE_DESC="Cloud-Neutra ${EDITION} image Ubuntu ${UBUNTU_VERSION} ${CPU_ARCH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAG_SET=(
|
||||||
|
Key=Name,Value="$IMAGE_NAME"
|
||||||
|
Key=Project,Value="$PROJECT_TAG"
|
||||||
|
Key=Edition,Value="$EDITION"
|
||||||
|
Key=UbuntuVersion,Value="$UBUNTU_VERSION"
|
||||||
|
Key=Architecture,Value="$CPU_ARCH"
|
||||||
|
Key=Role,Value=Golden-Image
|
||||||
|
Key=SourceRegion,Value="$BASE_REGION"
|
||||||
|
)
|
||||||
|
|
||||||
|
for REGION in "${TARGET_REGIONS[@]}"; do
|
||||||
|
if [ "$REGION" = "$BASE_REGION" ]; then
|
||||||
|
echo "[ami-replicate] Skip base region $BASE_REGION"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[ami-replicate] Replicating $AMI_ID ($IMAGE_NAME) to $REGION ..."
|
||||||
|
|
||||||
|
NEW_AMI_ID=$(aws ec2 copy-image \
|
||||||
|
--region "$REGION" \
|
||||||
|
--source-region "$BASE_REGION" \
|
||||||
|
--source-image-id "$AMI_ID" \
|
||||||
|
--name "$IMAGE_NAME" \
|
||||||
|
--description "$IMAGE_DESC" \
|
||||||
|
--query 'ImageId' \
|
||||||
|
--output text)
|
||||||
|
|
||||||
|
echo "[ami-replicate] Waiting for AMI $NEW_AMI_ID in $REGION to become available ..."
|
||||||
|
aws ec2 wait image-available --region "$REGION" --image-ids "$NEW_AMI_ID"
|
||||||
|
|
||||||
|
echo "[ami-replicate] Tagging AMI $NEW_AMI_ID in $REGION"
|
||||||
|
aws ec2 create-tags --region "$REGION" --resources "$NEW_AMI_ID" --tags "${TAG_SET[@]}"
|
||||||
|
|
||||||
|
SNAPSHOT_IDS=$(aws ec2 describe-images \
|
||||||
|
--region "$REGION" \
|
||||||
|
--image-ids "$NEW_AMI_ID" \
|
||||||
|
--query 'Images[0].BlockDeviceMappings[].Ebs.SnapshotId' \
|
||||||
|
--output text)
|
||||||
|
|
||||||
|
if [ -n "$SNAPSHOT_IDS" ]; then
|
||||||
|
for SNAP_ID in $SNAPSHOT_IDS; do
|
||||||
|
echo "[ami-replicate] Tagging snapshot $SNAP_ID in $REGION"
|
||||||
|
aws ec2 create-tags --region "$REGION" --resources "$SNAP_ID" --tags "${TAG_SET[@]}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[ami-replicate] Completed replication to $REGION (AMI: $NEW_AMI_ID)"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[ami-replicate] Replication process finished."
|
||||||
60
packer/Cloud-Neutra-VMs/scripts/base/01_os_base.sh
Normal file
60
packer/Cloud-Neutra-VMs/scripts/base/01_os_base.sh
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# 强制非交互模式(解决 debconf / dpkg-preconfigure 报错)
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
export DEBCONF_NONINTERACTIVE_SEEN=true
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] OS Base Initialization"
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Enable standard repositories
|
||||||
|
##############################################
|
||||||
|
sudo add-apt-repository universe -y || true
|
||||||
|
sudo add-apt-repository multiverse -y || true
|
||||||
|
sudo add-apt-repository restricted -y || true
|
||||||
|
sudo sed -i 's/# deb/deb/g' /etc/apt/sources.list
|
||||||
|
|
||||||
|
sudo apt-get update -y
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Safe upgrade (no kernel updates)
|
||||||
|
##############################################
|
||||||
|
sudo apt-get dist-upgrade -y --no-install-recommends
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Remove snapd
|
||||||
|
##############################################
|
||||||
|
if command -v snap >/dev/null 2>&1; then
|
||||||
|
sudo systemctl stop snapd.service || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo apt-get remove --purge -y snapd || true
|
||||||
|
sudo rm -rf /var/cache/snapd/ ~/snap /snap || true
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Remove MOTD noise and useless packages
|
||||||
|
##############################################
|
||||||
|
sudo apt-get remove --purge -y \
|
||||||
|
landscape-common \
|
||||||
|
update-notifier-common \
|
||||||
|
motd-news-config \
|
||||||
|
apport \
|
||||||
|
whoopsie || true
|
||||||
|
|
||||||
|
sudo rm -rf /etc/update-motd.d/* || true
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Add minimal essential tools
|
||||||
|
##############################################
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
jq curl unzip gnupg lsb-release ca-certificates \
|
||||||
|
software-properties-common net-tools iproute2 iptables
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Disable auto-update timers
|
||||||
|
##############################################
|
||||||
|
sudo systemctl disable apt-daily.service apt-daily-upgrade.service || true
|
||||||
|
sudo systemctl disable apt-daily.timer apt-daily-upgrade.timer || true
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Base OS setup completed."
|
||||||
35
packer/Cloud-Neutra-VMs/scripts/base/02_hardening.sh
Normal file
35
packer/Cloud-Neutra-VMs/scripts/base/02_hardening.sh
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# 强制非交互模式(解决 debconf / dpkg-preconfigure 报错)
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
export DEBCONF_NONINTERACTIVE_SEEN=true
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] System Hardening"
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# SSH hardening
|
||||||
|
##############################################
|
||||||
|
sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||||
|
sudo sed -i 's/^#PermitRootLogin .*/PermitRootLogin no/' /etc/ssh/sshd_config
|
||||||
|
sudo sed -i 's/^X11Forwarding yes/X11Forwarding no/' /etc/ssh/sshd_config
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Sysctl tuning (safe defaults)
|
||||||
|
##############################################
|
||||||
|
cat <<EOF | sudo tee /etc/sysctl.d/99-cloud-neutra.conf
|
||||||
|
fs.inotify.max_user_watches=524288
|
||||||
|
vm.swappiness=10
|
||||||
|
net.ipv4.ip_forward=1
|
||||||
|
net.ipv4.conf.all.rp_filter=1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo sysctl --system || true
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Journald persistent logging
|
||||||
|
##############################################
|
||||||
|
sudo mkdir -p /var/log/journal
|
||||||
|
sudo systemd-tmpfiles --create --prefix /var/log/journal
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Hardening complete."
|
||||||
15
packer/Cloud-Neutra-VMs/scripts/common/cleanup.sh
Normal file
15
packer/Cloud-Neutra-VMs/scripts/common/cleanup.sh
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Cleanup phase"
|
||||||
|
|
||||||
|
sudo apt-get autoremove -y
|
||||||
|
sudo apt-get clean -y
|
||||||
|
sudo rm -rf /var/lib/apt/lists/*
|
||||||
|
sudo rm -rf /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
# Cloud images best practice
|
||||||
|
sudo truncate -s 0 /var/log/wtmp || true
|
||||||
|
sudo truncate -s 0 /var/log/lastlog || true
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Cleanup complete."
|
||||||
33
packer/Cloud-Neutra-VMs/scripts/flavors/container.sh
Normal file
33
packer/Cloud-Neutra-VMs/scripts/flavors/container.sh
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Installing containerd + nerdctl"
|
||||||
|
|
||||||
|
ARCH="$(uname -m)"
|
||||||
|
NERDCTL_VERSION="2.2.0"
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Install containerd
|
||||||
|
##############################################
|
||||||
|
sudo apt-get install -y containerd
|
||||||
|
|
||||||
|
sudo mkdir -p /etc/containerd
|
||||||
|
sudo containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
|
||||||
|
sudo systemctl enable containerd
|
||||||
|
sudo systemctl restart containerd
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Install nerdctl
|
||||||
|
##############################################
|
||||||
|
if [[ "$ARCH" == "x86_64" ]]; then
|
||||||
|
URL="https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz"
|
||||||
|
else
|
||||||
|
URL="https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-arm64.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -LO $URL
|
||||||
|
tar -xzf nerdctl-*.tar.gz
|
||||||
|
sudo mv nerdctl /usr/local/bin/nerdctl
|
||||||
|
rm -f nerdctl-*.tar.gz
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] container edition installed."
|
||||||
14
packer/Cloud-Neutra-VMs/scripts/flavors/k3s.sh
Normal file
14
packer/Cloud-Neutra-VMs/scripts/flavors/k3s.sh
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Installing K3s (skip start)"
|
||||||
|
|
||||||
|
curl -sfL https://get.k3s.io -o install_k3s.sh
|
||||||
|
chmod +x install_k3s.sh
|
||||||
|
|
||||||
|
# Skip start (important for AMI)
|
||||||
|
sudo INSTALL_K3S_SKIP_START=true ./install_k3s.sh
|
||||||
|
|
||||||
|
sudo systemctl disable k3s || true
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] K3s installed (not started)."
|
||||||
20
packer/Cloud-Neutra-VMs/scripts/flavors/sealos.sh
Normal file
20
packer/Cloud-Neutra-VMs/scripts/flavors/sealos.sh
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Installing Sealos"
|
||||||
|
|
||||||
|
ARCH="$(uname -m)"
|
||||||
|
VERSION="5.0.0-alpha1"
|
||||||
|
|
||||||
|
if [[ "$ARCH" == "x86_64" ]]; then
|
||||||
|
URL="https://github.com/labring/sealos/releases/download/v${VERSION}/sealos_${VERSION}_linux_amd64.tar.gz"
|
||||||
|
else
|
||||||
|
URL="https://github.com/labring/sealos/releases/download/v${VERSION}/sealos_${VERSION}_linux_arm64.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -LO $URL
|
||||||
|
tar -xzf sealos_*.tar.gz
|
||||||
|
sudo mv sealos /usr/local/bin/
|
||||||
|
rm -f sealos_*.tar.gz
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Sealos installed."
|
||||||
54
packer/Cloud-Neutra-VMs/scripts/flavors/sealos_gpu.sh
Normal file
54
packer/Cloud-Neutra-VMs/scripts/flavors/sealos_gpu.sh
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Installing Sealos GPU edition"
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Install NVIDIA drivers (AWS/AliCloud safe)
|
||||||
|
##############################################
|
||||||
|
if lspci | grep -i nvidia >/dev/null 2>&1; then
|
||||||
|
echo "[GPU] NVIDIA GPU detected"
|
||||||
|
sudo apt-get install -y nvidia-driver-535
|
||||||
|
else
|
||||||
|
echo "[GPU] No NVIDIA GPU detected, skip driver"
|
||||||
|
fi
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Install containerd (if not installed)
|
||||||
|
##############################################
|
||||||
|
sudo apt-get install -y containerd
|
||||||
|
sudo containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
|
||||||
|
sudo systemctl restart containerd
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Install NVIDIA container toolkit
|
||||||
|
##############################################
|
||||||
|
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
|
||||||
|
curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add -
|
||||||
|
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/libnvidia-container.list
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y nvidia-container-toolkit
|
||||||
|
|
||||||
|
sudo nvidia-ctk runtime configure --runtime=containerd
|
||||||
|
sudo systemctl restart containerd
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Install Sealos
|
||||||
|
##############################################
|
||||||
|
ARCH="$(uname -m)"
|
||||||
|
VERSION="5.0.0-alpha1"
|
||||||
|
|
||||||
|
if [[ "$ARCH" == "x86_64" ]]; then
|
||||||
|
URL="https://github.com/labring/sealos/releases/download/v${VERSION}/sealos_${VERSION}_linux_amd64.tar.gz"
|
||||||
|
else
|
||||||
|
URL="https://github.com/labring/sealos/releases/download/v${VERSION}/sealos_${VERSION}_linux_arm64.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -LO "$URL"
|
||||||
|
tar -xzf sealos_*.tar.gz
|
||||||
|
sudo mv sealos /usr/local/bin/
|
||||||
|
rm -f sealos_*.tar.gz
|
||||||
|
|
||||||
|
echo "[Cloud-Neutra] Sealos GPU edition installed."
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
###############################################################
|
||||||
|
# Cloud-Neutra AWS AMI Builder (Multi-Arch / Multi-LTS)
|
||||||
|
# This file is the COMMON builder template inherited by:
|
||||||
|
# base / container / k3s / sealos / sealos-gpu
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
packer {
|
||||||
|
required_plugins {
|
||||||
|
amazon = {
|
||||||
|
version = ">= 1.2.8"
|
||||||
|
source = "github.com/hashicorp/amazon"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# Input Variables
|
||||||
|
###############################################################
|
||||||
|
variable "cpu_arch" {
|
||||||
|
type = string
|
||||||
|
description = "CPU architecture (amd64 or arm64)"
|
||||||
|
default = "amd64"
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# Locals — override `edition` / `ubuntu_version` in edition-specific template
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
locals {
|
||||||
|
edition = lookup(var, "edition", "container")
|
||||||
|
ubuntu_version = lookup(var, "ubuntu_version", "2204")
|
||||||
|
|
||||||
|
arch_map = {
|
||||||
|
amd64 = "amd64"
|
||||||
|
arm64 = "arm64"
|
||||||
|
}
|
||||||
|
|
||||||
|
ubuntu_codename = lookup(
|
||||||
|
{
|
||||||
|
"2204" = "jammy"
|
||||||
|
"2404" = "noble"
|
||||||
|
},
|
||||||
|
local.ubuntu_version,
|
||||||
|
"unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
ubuntu_version_dot = lookup(
|
||||||
|
{
|
||||||
|
"2204" = "22.04"
|
||||||
|
"2404" = "24.04"
|
||||||
|
},
|
||||||
|
local.ubuntu_version,
|
||||||
|
"unknown"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# AMI Builder
|
||||||
|
###############################################################
|
||||||
|
source "amazon-ebs" "this" {
|
||||||
|
region = "ap-northeast-1"
|
||||||
|
|
||||||
|
# Arm = t4g, AMD64 = t3
|
||||||
|
instance_type = var.cpu_arch == "arm64" ? "t4g.micro" : "t3.micro"
|
||||||
|
|
||||||
|
ami_name = "Cloud-Neutra-${local.edition}-VM-${local.ubuntu_version}-${var.cpu_arch}-{{timestamp}}"
|
||||||
|
ami_description = "Cloud-Neutra ${local.edition} image Ubuntu ${local.ubuntu_version} ${var.cpu_arch}"
|
||||||
|
ssh_username = "ubuntu"
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# Official Ubuntu AMI Filter (AWS official image name pattern)
|
||||||
|
#
|
||||||
|
# Example name pattern:
|
||||||
|
# ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20240229
|
||||||
|
###############################################################
|
||||||
|
source_ami_filter {
|
||||||
|
filters = {
|
||||||
|
name = "ubuntu/images/*ubuntu-${local.ubuntu_codename}-${local.ubuntu_version_dot}-${local.arch_map[var.cpu_arch]}-server-*"
|
||||||
|
root-device-type = "ebs"
|
||||||
|
virtualization-type = "hvm"
|
||||||
|
}
|
||||||
|
most_recent = true
|
||||||
|
owners = ["099720109477"] # Canonical
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# Tags
|
||||||
|
###############################################################
|
||||||
|
tags = {
|
||||||
|
Project = "Cloud-Neutra"
|
||||||
|
OS = "Ubuntu ${local.ubuntu_version}"
|
||||||
|
Edition = local.edition
|
||||||
|
Architecture = var.cpu_arch
|
||||||
|
Role = "Golden-Image"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tags = {
|
||||||
|
Name = "CN-${local.edition}-${local.ubuntu_version}-${var.cpu_arch}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# Build Script Pipeline (Standardized)
|
||||||
|
###############################################################
|
||||||
|
build {
|
||||||
|
name = "Cloud-Neutra-${local.edition}-VM-${local.ubuntu_version}"
|
||||||
|
sources = ["source.amazon-ebs.this"]
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
script = "packer/scripts/base/01_os_base.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
script = "packer/scripts/base/02_hardening.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
script = "packer/scripts/flavors/${local.edition}.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
script = "packer/scripts/common/cleanup.sh"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
# # Packer Template for AWS - Cloud-Neutra Container VM (Ubuntu 22.04)
|
||||||
|
|
||||||
|
packer {
|
||||||
|
required_plugins {
|
||||||
|
amazon = {
|
||||||
|
version = ">= 1.2.8"
|
||||||
|
source = "github.com/hashicorp/amazon"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Define the builder to create an AWS AMI
|
||||||
|
source "amazon-ebs" "ami-ubuntu-2204" {
|
||||||
|
region = "ap-northeast-1" # AWS Region for the AMI
|
||||||
|
ami_name = "Cloud-Neutra-Container-VM-2204-{{timestamp}}"
|
||||||
|
instance_type = "t3a.micro" # Instance type for AMI creation
|
||||||
|
source_ami_filter {
|
||||||
|
filters = {
|
||||||
|
name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*"
|
||||||
|
root-device-type = "ebs"
|
||||||
|
virtualization-type = "hvm"
|
||||||
|
}
|
||||||
|
most_recent = true
|
||||||
|
owners = ["099720109477"] # Official Ubuntu AMI owner ID
|
||||||
|
}
|
||||||
|
ami_description = "Containerized Ubuntu 22.04 with nerdctl, containerd, and monitoring tools"
|
||||||
|
ssh_username = "ubuntu" # Default user for Ubuntu AMIs
|
||||||
|
#ssh_private_key_file = "~/.ssh/id_rsa" # SSH private key to connect (GitHub Secrets)
|
||||||
|
run_tags = { "Name" = "Container-VM-2204" }
|
||||||
|
|
||||||
|
tags = {
|
||||||
|
"Environment" = "Container"
|
||||||
|
"Project" = "Cloud-Neutra"
|
||||||
|
}
|
||||||
|
|
||||||
|
# AWS specific variables for network configuration
|
||||||
|
subnet_id = "subnet-0c98af564f030a473" # Specify subnet if needed
|
||||||
|
vpc_id = "vpc-05e6af5f2bc7eb41b" # Specify VPC ID if needed
|
||||||
|
associate_public_ip_address = true # Optional for public IP
|
||||||
|
}
|
||||||
|
|
||||||
|
# Define the build block with provisioners and post-processors
|
||||||
|
build {
|
||||||
|
name = "Cloud-Neutra-Container-VM-2204"
|
||||||
|
sources = [
|
||||||
|
"source.amazon-ebs.ami-ubuntu-2204"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Provisioners to install and configure the system
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = [
|
||||||
|
# Enable all standard repositories
|
||||||
|
"sudo add-apt-repository universe -y",
|
||||||
|
"sudo add-apt-repository multiverse -y",
|
||||||
|
"sudo add-apt-repository restricted -y",
|
||||||
|
"sudo sed -i 's/# deb/deb/g' /etc/apt/sources.list",
|
||||||
|
|
||||||
|
"sudo apt-get update",
|
||||||
|
|
||||||
|
# Safe upgrade without kernel/bootloader risks
|
||||||
|
"sudo apt-get dist-upgrade -y --no-install-recommends",
|
||||||
|
|
||||||
|
# Remove unwanted packages
|
||||||
|
"sudo apt-get remove --purge -y snapd resolvconf",
|
||||||
|
"sudo rm -rf /var/cache/snapd/",
|
||||||
|
"sudo rm -rf ~/snap",
|
||||||
|
|
||||||
|
# Remove MOTD spam / cloud-init noise
|
||||||
|
"sudo apt-get remove --purge -y landscape-common update-notifier-common motd-news-config",
|
||||||
|
"sudo rm -rf /etc/update-motd.d/*",
|
||||||
|
|
||||||
|
# Install required minimal tools
|
||||||
|
"sudo apt-get install -y --no-install-recommends jq curl unzip gnupg lsb-release software-properties-common",
|
||||||
|
|
||||||
|
# Install containerd
|
||||||
|
"sudo apt-get install -y containerd",
|
||||||
|
|
||||||
|
# Install nerdctl (for containerd orchestration)
|
||||||
|
"curl -LO https://github.com/containerd/nerdctl/releases/download/v2.2.0/nerdctl-2.2.0-linux-amd64.tar.gz",
|
||||||
|
"tar -xvzf nerdctl-2.2.0-linux-amd64.tar.gz",
|
||||||
|
"sudo mv nerdctl /usr/local/bin/nerdctl",
|
||||||
|
|
||||||
|
|
||||||
|
# Install monitoring tools
|
||||||
|
|
||||||
|
# Install node_exporter (Prometheus Node Exporter)
|
||||||
|
#"curl -s https://github.com/prometheus/node_exporter/releases/download/v1.10.2/node_exporter-1.10.2.linux-amd64.tar.gz | tar xz",
|
||||||
|
#"sudo mv node_exporter-1.10.2.linux-amd64/node_exporter /usr/local/bin/",
|
||||||
|
#"sudo systemctl enable node_exporter && sudo systemctl start node_exporter",
|
||||||
|
|
||||||
|
# Install process_exporter
|
||||||
|
#"curl -sL https://github.com/ncabatoff/process-exporter/releases/download/v0.8.7/process-exporter-0.8.7.linux-amd64.tar.gz | tar xz",
|
||||||
|
#"sudo mv process_exporter-0.8.7.linux-amd64/process_exporter /usr/local/bin/",
|
||||||
|
#"sudo systemctl enable process_exporter && sudo systemctl start process_exporter",
|
||||||
|
|
||||||
|
# Install Vector (log aggregation and processing)
|
||||||
|
#"curl -LO https://github.com/vectordotdev/vector/releases/download/v0.51.1/vector_0.51.1-1_amd64.deb",
|
||||||
|
#"sudo dpkg -i vector_0.51.1-1_amd64.deb",
|
||||||
|
#"sudo systemctl enable vector && sudo systemctl start vector"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user