Compare commits
149 Commits
codex/fix-
...
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 | ||
|
|
5332ae70bc | ||
|
|
78edeaa474 | ||
|
|
ea29271b18 | ||
|
|
be28eba9e8 | ||
|
|
be07c921b8 | ||
|
|
96499a6325 | ||
|
|
f86f17eb4f | ||
|
|
356ebc392e | ||
|
|
6cc99943d8 | ||
|
|
b4f88166f9 | ||
|
|
916b480d3a | ||
|
|
8381076e1a | ||
|
|
8c833b8ba7 | ||
|
|
72b692e546 | ||
|
|
c9449f16eb | ||
|
|
2d0458ab6f | ||
|
|
890a93856a | ||
|
|
441e549678 | ||
|
|
b95025d2b5 | ||
|
|
f2dd39bcf2 | ||
|
|
fb36e17706 | ||
|
|
0f33753e69 | ||
|
|
451302ef2b | ||
|
|
eb7bcf0be0 | ||
|
|
1dc8dbd9b2 | ||
|
|
0602e036c1 | ||
|
|
50a463f3f3 | ||
|
|
d95b94e2cf | ||
|
|
50d9f1f1dd | ||
|
|
b4c13aca30 | ||
|
|
df31ec3aee | ||
|
|
79afce267f | ||
|
|
394696a76f | ||
|
|
0f996e0f01 | ||
|
|
ad2f702975 | ||
|
|
69d210c2a4 | ||
|
|
0d3e307926 | ||
|
|
fc1402dc7e | ||
|
|
ee8e92d878 | ||
|
|
484a486a5f | ||
|
|
8e91f28dbd | ||
|
|
ce0d0678e4 | ||
|
|
35b14f95a9 | ||
|
|
341332a58a | ||
|
|
0493c91057 | ||
|
|
50b6409579 | ||
|
|
a53106003c | ||
|
|
f481311a44 | ||
|
|
f3ac693487 | ||
|
|
14dc79496b | ||
|
|
8538ca6e0b | ||
|
|
56d4a001f0 | ||
|
|
3aab8cb28f | ||
|
|
16aa0226ba | ||
|
|
38d3ebcfed | ||
|
|
13dca8c138 | ||
|
|
36c3446c17 | ||
|
|
8cfcd543a8 | ||
|
|
6a92aeb9e2 | ||
|
|
326500ea45 | ||
|
|
18d0c1095d | ||
|
|
79c63515a3 | ||
|
|
21836c4d7c | ||
|
|
8dc9d76926 | ||
|
|
03ec279bf0 | ||
|
|
da62dfcb6f | ||
|
|
f8586778e2 | ||
|
|
c890f727cc | ||
|
|
1b956d7986 | ||
|
|
a1f747411c | ||
|
|
114c30a2a7 | ||
|
|
25f685d850 | ||
|
|
a2bfcc06d0 | ||
|
|
806cc8dac9 | ||
|
|
f9ce2042db | ||
|
|
0bdb537bfd | ||
|
|
e21f0ac494 | ||
|
|
384002a6d4 | ||
|
|
e7603bed4a | ||
|
|
93dab64dd8 | ||
|
|
d970ab7ed3 | ||
|
|
b600d23a59 | ||
|
|
e8f0d14f35 | ||
|
|
ad8afe4431 | ||
|
|
1c2f62f10c | ||
|
|
e39e3185b9 | ||
|
|
6c2a67875c | ||
|
|
7e2c8112c7 | ||
|
|
eef2d909ac | ||
|
|
c24a9223b9 | ||
|
|
6fd5df2b6d | ||
|
|
4a9cc6f265 | ||
|
|
9adb4d1a91 | ||
|
|
7bfd6f19e8 | ||
|
|
aad04fb7fc | ||
|
|
b86d196c3d |
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 }}
|
||||
131
.github/workflows/build-k3s-offline-installer.yml
vendored
131
.github/workflows/build-k3s-offline-installer.yml
vendored
@ -1,131 +0,0 @@
|
||||
name: Build Offline K3s Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/make_k3s_offline_package.sh'
|
||||
- '.github/workflows/build-k3s-offline-installer.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-k3s-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
export NERDCTL_VERSION=2.0.4
|
||||
sudo apt-get update && sudo apt-get install -y curl tar tree
|
||||
# 安装 K3s
|
||||
curl -sfL https://get.k3s.io | sh -
|
||||
# 设置 kubeconfig
|
||||
mkdir -p $HOME/.kube
|
||||
sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
|
||||
sudo chown $USER:$USER $HOME/.kube/config
|
||||
# 安装 nerdctl
|
||||
sudo curl -LO https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz
|
||||
sudo tar -C /usr/local/bin -xzf nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz
|
||||
sudo chmod +x /usr/local/bin/nerdctl
|
||||
|
||||
# k3s 测试
|
||||
kubectl get nodes
|
||||
kubectl get pods -A
|
||||
|
||||
# nerdctl 测试
|
||||
sudo nerdctl --version
|
||||
sudo nerdctl --namespace k8s.io --address /run/k3s/containerd/containerd.sock ps
|
||||
|
||||
- name: Run Offline Package Builder
|
||||
run: |
|
||||
chmod +x scripts/make_k3s_offline_package.sh
|
||||
ARCH=${{ matrix.arch }} ./scripts/make_k3s_offline_package.sh
|
||||
|
||||
- name: Compress Offline Installer
|
||||
run: |
|
||||
tar czvf k3s-offline-package-${{ matrix.arch }}.tar.gz k3s-offline-package
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: k3s-offline-package-${{ matrix.arch }}
|
||||
path: k3s-offline-package-${{ matrix.arch }}.tar.gz
|
||||
|
||||
test-k3s-installer:
|
||||
needs: build-k3s-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: k3s-offline-package-${{ matrix.arch }}
|
||||
path: ./test-dir
|
||||
|
||||
- name: Extract Package
|
||||
run: |
|
||||
cd test-dir
|
||||
tar -xzvf k3s-offline-package-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Setup K3s and Test
|
||||
run: |
|
||||
cd test-dir/k3s-offline-package
|
||||
bash install-server.sh
|
||||
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get nodes
|
||||
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get pods -A
|
||||
|
||||
publish-release:
|
||||
needs: test-k3s-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
tag_name: offline-k3s-${{ github.run_number }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create GitHub Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.tag_name }}
|
||||
release_name: Daily 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: k3s-offline-package-amd64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Download arm64 Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: k3s-offline-package-arm64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.tag_name }}
|
||||
files: |
|
||||
release-artifacts/k3s-offline-package-amd64.tar.gz
|
||||
release-artifacts/k3s-offline-package-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@ -1,212 +0,0 @@
|
||||
name: Build Offline NGINX Ingress Installer (OCI multi-arch)
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'gitops/scripts/ingress-installer.sh'
|
||||
- '.github/workflows/build-nginx-ingress-offline-installer.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
NERDCTL_VERSION: "2.0.4"
|
||||
NGINX_IC_IMAGE: "nginx/nginx-ingress:2.4.0"
|
||||
# 证书生成 Job 镜像(建议使用官方多架构镜像;如需换 tag 可在这里改)
|
||||
CERT_IMG: "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407"
|
||||
HELM_REPO_NAME: "nginx-stable"
|
||||
HELM_REPO_URL: "https://helm.nginx.com/stable"
|
||||
HELM_CHART_NAME: "nginx-ingress"
|
||||
|
||||
jobs:
|
||||
build-nginx-ingress-installer:
|
||||
name: build-nginx-ingress-installer (${{ matrix.arch }})
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 40
|
||||
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies (helm, skopeo, curl, tar, tree, jq)
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y skopeo curl tar tree jq
|
||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
helm version
|
||||
skopeo --version
|
||||
|
||||
- name: Prepare offline package layout
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
PKG=nginx-ingress-offline-installer
|
||||
rm -rf "${PKG}"
|
||||
mkdir -p "${PKG}/images" "${PKG}/charts"
|
||||
install -m 0755 gitops/scripts/ingress-installer.sh "${PKG}/ingress-installer.sh"
|
||||
cat > "${PKG}/VERSION.txt" <<EOF
|
||||
Build Time: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
Arch Package: ${{ matrix.arch }}
|
||||
NERDCTL_VERSION: ${NERDCTL_VERSION}
|
||||
Controller Image: ${NGINX_IC_IMAGE}
|
||||
CertGen Image: ${CERT_IMG}
|
||||
Helm Chart: ${HELM_REPO_NAME}/${HELM_CHART_NAME}
|
||||
EOF
|
||||
|
||||
- name: Build nerdctl.tar.gz (linux amd64/arm64 + darwin arm64 + wrapper)
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
PKG=nginx-ingress-offline-installer
|
||||
TMP=$(mktemp -d)
|
||||
curl -L -o "${TMP}/nerdctl-linux-amd64.tgz" "https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz"
|
||||
curl -L -o "${TMP}/nerdctl-linux-arm64.tgz" "https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-arm64.tar.gz"
|
||||
curl -L -o "${TMP}/nerdctl-darwin-arm64.tgz" "https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-darwin-arm64.tar.gz"
|
||||
mkdir -p "${TMP}/bundle"
|
||||
tar -xzf "${TMP}/nerdctl-linux-amd64.tgz" -C "${TMP}/bundle"
|
||||
install -m0755 "${TMP}/bundle/nerdctl" "${TMP}/bundle/nerdctl.linux.amd64"; rm -f "${TMP}/bundle/nerdctl"
|
||||
tar -xzf "${TMP}/nerdctl-linux-arm64.tgz" -C "${TMP}/bundle"
|
||||
install -m0755 "${TMP}/bundle/nerdctl" "${TMP}/bundle/nerdctl.linux.arm64"; rm -f "${TMP}/bundle/nerdctl"
|
||||
tar -xzf "${TMP}/nerdctl-darwin-arm64.tgz" -C "${TMP}/bundle"
|
||||
install -m0755 "${TMP}/bundle/nerdctl" "${TMP}/bundle/nerdctl.darwin.arm64"; rm -f "${TMP}/bundle/nerdctl"
|
||||
cat > "${TMP}/bundle/nerdctl" <<'SH'
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]'); ARCH=$(uname -m)
|
||||
case "$OS/$ARCH" in
|
||||
linux/x86_64) exec /usr/local/bin/nerdctl.linux.amd64 "$@" ;;
|
||||
linux/arm64|linux/aarch64) exec /usr/local/bin/nerdctl.linux.arm64 "$@" ;;
|
||||
darwin/arm64) exec /usr/local/bin/nerdctl.darwin.arm64 "$@" ;;
|
||||
*) echo "Unsupported platform: $OS/$ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
SH
|
||||
chmod +x "${TMP}/bundle/nerdctl"
|
||||
tar -C "${TMP}/bundle" -czf "${PKG}/nerdctl.tar.gz" nerdctl nerdctl.linux.amd64 nerdctl.linux.arm64 nerdctl.darwin.arm64
|
||||
ls -lh "${PKG}/nerdctl.tar.gz"
|
||||
|
||||
- name: Pull Helm chart to charts/nginx-ingress
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
PKG=nginx-ingress-offline-installer
|
||||
helm repo add "${HELM_REPO_NAME}" "${HELM_REPO_URL}"
|
||||
helm repo update
|
||||
helm pull "${HELM_REPO_NAME}/${HELM_CHART_NAME}" --untar --untardir "${PKG}/charts"
|
||||
test -d "${PKG}/charts/nginx-ingress"
|
||||
|
||||
- name: Build single OCI multi-arch archive with both images
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
PKG=nginx-ingress-offline-installer
|
||||
LAYOUT_DIR="${PKG}/images/oci-layout"
|
||||
mkdir -p "${LAYOUT_DIR}"
|
||||
# 将 controller 和 certgen 都写入同一个 OCI Layout 目录
|
||||
skopeo copy --all docker://${NGINX_IC_IMAGE} oci:${LAYOUT_DIR}:nginx-ingress-2.4.0
|
||||
skopeo copy --all docker://${CERT_IMG} oci:${LAYOUT_DIR}:kube-webhook-certgen
|
||||
# 打包成单个归档文件
|
||||
tar -C "${PKG}/images" -czf "${PKG}/images/oci-archive.tar" oci-layout
|
||||
rm -rf "${LAYOUT_DIR}"
|
||||
ls -lh "${PKG}/images/oci-archive.tar"
|
||||
|
||||
- name: Show package tree
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
tree -L 2 nginx-ingress-offline-installer
|
||||
|
||||
- name: Create tarball artifact
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
PKG=nginx-ingress-offline-installer
|
||||
tar -czf ${PKG}-${{ matrix.arch }}.tar.gz -C ${PKG} .
|
||||
ls -lh ${PKG}-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nginx-ingress-offline-installer-${{ matrix.arch }}
|
||||
path: nginx-ingress-offline-installer-${{ matrix.arch }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
test-nginx-ingress-installer:
|
||||
name: test-nginx-ingress-installer (amd64)
|
||||
needs: build-nginx-ingress-installer
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 35
|
||||
|
||||
steps:
|
||||
- name: Download amd64 Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nginx-ingress-offline-installer-amd64
|
||||
path: ./test-dir
|
||||
|
||||
- name: Extract Package
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
cd test-dir
|
||||
tar -xzvf nginx-ingress-offline-installer-amd64.tar.gz
|
||||
|
||||
- name: Install K3s and kubectl context
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
curl -sfL https://get.k3s.io | sh -
|
||||
mkdir -p $HOME/.kube
|
||||
sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
|
||||
sudo chown $USER:$USER $HOME/.kube/config
|
||||
kubectl get nodes
|
||||
|
||||
- name: Install helm
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
|
||||
- name: Run offline installer script (containerd path)
|
||||
working-directory: ./test-dir
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
export DOCKER_HOST=unix:///invalid # 强制走 containerd 分支
|
||||
sudo bash ./ingress-installer.sh
|
||||
|
||||
- name: Wait for rollout & show objects
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
for d in $(kubectl -n ingress get deploy -o name); do
|
||||
kubectl -n ingress rollout status "$d" --timeout=180s || true
|
||||
done
|
||||
kubectl -n ingress get all
|
||||
|
||||
publish-release:
|
||||
name: publish-release
|
||||
needs: test-nginx-ingress-installer
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
tag_name: offline-nginx-ingress-${{ github.run_number }}
|
||||
|
||||
steps:
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ env.tag_name }}
|
||||
name: Daily Build ${{ env.tag_name }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Download amd64 Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nginx-ingress-offline-installer-amd64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Download arm64 Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nginx-ingress-offline-installer-arm64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Upload Assets to Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ env.tag_name }}
|
||||
files: |
|
||||
release-artifacts/nginx-ingress-offline-installer-amd64.tar.gz
|
||||
release-artifacts/nginx-ingress-offline-installer-arm64.tar.gz
|
||||
152
.github/workflows/build-offline-package.yaml
vendored
152
.github/workflows/build-offline-package.yaml
vendored
@ -1,152 +0,0 @@
|
||||
name: Build Offline Nginx Ingress Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/ingress-installer.sh'
|
||||
- '.github/workflows/build-offline-package.yaml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
artifact-name: ${{ steps.upload-artifact.outputs.artifact-name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
mkdir -p offline-installer/{images,charts,scripts,bin}
|
||||
|
||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||
run: |
|
||||
wget https://github.com/containerd/nerdctl/releases/download/v2.0.3/nerdctl-2.0.3-linux-${{ matrix.arch }}.tar.gz \
|
||||
-O offline-installer/nerdctl.tar.gz
|
||||
|
||||
- name: Pull & export required images
|
||||
run: |
|
||||
docker pull nginx/nginx-ingress:2.4.0
|
||||
docker pull registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407
|
||||
|
||||
docker save nginx/nginx-ingress:2.4.0 \
|
||||
-o offline-installer/images/nginx-ingress.tar
|
||||
|
||||
docker save registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407 \
|
||||
-o offline-installer/images/kube-webhook-certgen.tar
|
||||
|
||||
- name: Download Helm Chart (nginx-stable/nginx-ingress v0.15.0)
|
||||
run: |
|
||||
helm repo add nginx-stable https://helm.nginx.com/stable
|
||||
helm repo update
|
||||
helm pull nginx-stable/nginx-ingress --version=0.15.0 --untar --untardir offline-installer/charts
|
||||
|
||||
- name: Copy installer script
|
||||
run: |
|
||||
cp scripts/ingress-installer.sh offline-installer/scripts/
|
||||
chmod +x offline-installer/scripts/ingress-installer.sh
|
||||
|
||||
- name: Package offline installer
|
||||
run: |
|
||||
cd offline-installer
|
||||
tar czvf ../offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz ./
|
||||
cd ..
|
||||
|
||||
- name: Upload artifact
|
||||
id: upload-artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-setup-nginx-ingress-${{ matrix.arch }}
|
||||
path: offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz
|
||||
|
||||
test-offline-installer:
|
||||
needs: build-offline-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download offline installer artifact for ${{ matrix.arch }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-nginx-ingress-${{ matrix.arch }}
|
||||
path: offline-test
|
||||
|
||||
- name: Setup K3s and KUBECONFIG for user
|
||||
run: |
|
||||
curl -sfL https://get.k3s.io | sudo sh -
|
||||
# 配置当前用户的 kubeconfig
|
||||
mkdir -p $HOME/.kube
|
||||
sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
|
||||
sudo chown $USER:$USER $HOME/.kube/config
|
||||
# 测试 kubectl 可用性(不需要 sudo)
|
||||
kubectl get nodes
|
||||
kubectl version
|
||||
|
||||
- name: Install Helm
|
||||
run: |
|
||||
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | sudo bash
|
||||
|
||||
- name: Load offline installer package
|
||||
run: |
|
||||
cd offline-test
|
||||
tar -xzvf offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz
|
||||
sudo tar xzvf nerdctl.tar.gz -C /usr/local/bin/
|
||||
docker load -i images/nginx-ingress.tar
|
||||
docker load -i images/kube-webhook-certgen.tar
|
||||
cd ..
|
||||
|
||||
- name: Run offline installer in K3S cluster
|
||||
run: |
|
||||
cd offline-test
|
||||
bash scripts/ingress-installer.sh # ❗不要用 sudo,除非你传入 KUBECONFIG
|
||||
sleep 10
|
||||
helm list -A
|
||||
kubectl -n ingress get pods
|
||||
|
||||
publish-release:
|
||||
needs: test-offline-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
tag_name: offline-nginx-ingress-${{ 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: Daily 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-setup-nginx-ingress-amd64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-nginx-ingress-arm64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Upload offline installers to GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.tag_name }}
|
||||
files: |
|
||||
release-artifacts/offline-setup-nginx-ingress-amd64.tar.gz
|
||||
release-artifacts/offline-setup-nginx-ingress-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
104
.github/workflows/build-sealos-offline-installer.yml
vendored
104
.github/workflows/build-sealos-offline-installer.yml
vendored
@ -1,104 +0,0 @@
|
||||
name: Build Sealos Offline Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/create-sealos-offline-package.sh'
|
||||
- 'scripts/sealos-install.sh'
|
||||
- 'scripts/cilium-values.yaml'
|
||||
- '.github/workflows/build-sealos-offline-installer.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-sealos-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Run Offline Package Builder
|
||||
run: |
|
||||
chmod +x scripts/create-sealos-offline-package.sh
|
||||
ARCH=${{ matrix.arch }} ./scripts/create-sealos-offline-package.sh
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sealos-offline-package-${{ matrix.arch }}
|
||||
path: sealos-offline-package-${{ matrix.arch }}.tar.gz
|
||||
|
||||
test-sealos-installer:
|
||||
needs: build-sealos-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sealos-offline-package-${{ matrix.arch }}
|
||||
path: ./test-dir
|
||||
|
||||
- name: Extract Package
|
||||
run: |
|
||||
cd test-dir
|
||||
tar -xzvf sealos-offline-package-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Verify Package Contents
|
||||
run: |
|
||||
test -f test-dir/sealos-offline-package/sealos-install.sh
|
||||
test -f test-dir/sealos-offline-package/cilium-values.yaml
|
||||
|
||||
publish-release:
|
||||
needs: test-sealos-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
tag_name: offline-sealos-${{ github.run_number }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create GitHub Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.tag_name }}
|
||||
release_name: Daily 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: sealos-offline-package-amd64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Download arm64 Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sealos-offline-package-arm64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.tag_name }}
|
||||
files: |
|
||||
release-artifacts/sealos-offline-package-amd64.tar.gz
|
||||
release-artifacts/sealos-offline-package-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
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}"
|
||||
151
.github/workflows/offline-package-apisix-gateway.yaml
vendored
Normal file
151
.github/workflows/offline-package-apisix-gateway.yaml
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
name: Build Offline APISIX Gateway Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'gitops/scripts/apisix-gateway/deploy-apisix-gateway.sh'
|
||||
- '.github/workflows/offline-package-apisix-gateway.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-apisix-gateway-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
chart_version:
|
||||
description: "Override helm chart version for apisix (e.g., 1.2.3). Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write # 需要创建/上传 Release 资产
|
||||
|
||||
concurrency:
|
||||
group: build-offline-apisix-gateway
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
chart_version: ${{ steps.resolve.outputs.chart_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, helm)
|
||||
run: |
|
||||
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
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm repo add apisix https://charts.apiseven.com
|
||||
helm repo update
|
||||
|
||||
- name: Resolve latest chart version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -n "${OVERRIDE_CHART_VERSION}" ]; then
|
||||
CHART_VERSION="${OVERRIDE_CHART_VERSION}"
|
||||
else
|
||||
CHART_VERSION=$(helm search repo apisix/apisix --versions | awk 'NR==2{print $2}')
|
||||
fi
|
||||
echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p offline-installer/{images,charts,scripts,manifests}
|
||||
|
||||
- name: Download Gateway API manifests
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml -o offline-installer/manifests/gateway-api-standard-install.yaml
|
||||
|
||||
- name: Pull & export images from chart
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm template apisix apisix/apisix --version "${CHART_VERSION}" > manifest.yaml
|
||||
images=$(grep -oP 'image:\s*\K[^\s]+' manifest.yaml | tr -d '"' | sort -u)
|
||||
for img in $images; do
|
||||
[ -z "$img" ] && continue
|
||||
docker pull "$img"
|
||||
safe=$(echo "$img" | tr '/:' '-_')
|
||||
docker save "$img" -o offline-installer/images/${safe}.tar
|
||||
done
|
||||
|
||||
- name: Download Helm chart (apisix/apisix ${{ steps.resolve.outputs.chart_version }})
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm pull apisix/apisix --version="${CHART_VERSION}" --untar --untardir offline-installer/charts
|
||||
|
||||
- name: Stage deployment script
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p offline-installer/scripts
|
||||
cp gitops/scripts/apisix-gateway/deploy-apisix-gateway.sh offline-installer/scripts/
|
||||
|
||||
- name: Pack offline installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tar -czvf offline-setup-apisix-gateway-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-setup-apisix-gateway-${{ matrix.arch }}
|
||||
path: offline-setup-apisix-gateway-${{ matrix.arch }}.tar.gz
|
||||
|
||||
publish-release:
|
||||
needs: build-offline-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-apisix-gateway-{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-setup-apisix-gateway-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-apisix-gateway-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-setup-apisix-gateway-amd64.tar.gz
|
||||
release-artifacts/arm64/offline-setup-apisix-gateway-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
200
.github/workflows/offline-package-argocd-installer.yaml
vendored
Normal file
200
.github/workflows/offline-package-argocd-installer.yaml
vendored
Normal file
@ -0,0 +1,200 @@
|
||||
name: Build Offline Argo CD Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/offline-package-argocd-installer.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v2.11.0). Leave empty to use offline-argocd-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
chart_version:
|
||||
description: "Override Helm chart version for argo/argo-cd. Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-argocd
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NERDCTL_VERSION: "2.0.3"
|
||||
outputs:
|
||||
chart_version: ${{ steps.resolve.outputs.chart_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, helm)
|
||||
run: |
|
||||
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
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm repo add argo https://argoproj.github.io/argo-helm --force-update
|
||||
helm repo update
|
||||
|
||||
- name: Resolve chart version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||
run: bash scripts/offline-argocd/resolve_chart_version.sh
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf argocd-offline-package
|
||||
mkdir -p argocd-offline-package/{images,charts,scripts,metadata}
|
||||
|
||||
- name: Stage installer script
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: bash scripts/offline-argocd/stage_installer.sh
|
||||
|
||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
wget https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-${{ matrix.arch }}.tar.gz \
|
||||
-O argocd-offline-package/nerdctl.tar.gz
|
||||
|
||||
- name: Pull & export required images
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
MATRIX_ARCH: ${{ matrix.arch }}
|
||||
run: bash scripts/offline-argocd/pull_and_export_images.sh
|
||||
|
||||
- name: Download Helm chart
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm pull argo/argo-cd --version "${CHART_VERSION}" --untar --untardir argocd-offline-package/charts
|
||||
|
||||
- name: Package offline installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tar -czf offline-package-argocd-${{ matrix.arch }}.tar.gz -C . argocd-offline-package
|
||||
ls -lh offline-package-argocd-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-package-argocd-${{ matrix.arch }}
|
||||
path: offline-package-argocd-${{ 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-argocd-${{ matrix.arch }}
|
||||
path: offline-test
|
||||
|
||||
- name: Verify offline package integrity
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-test
|
||||
tar -tzf offline-package-argocd-${{ 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-argocd-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/offline-package/argocd/
|
||||
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-argocd-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-package-argocd-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-argocd-amd64.tar.gz
|
||||
release-artifacts/arm64/offline-package-argocd-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Ensure deps (rsync, ssh)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y rsync openssh-client
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync release assets to remote
|
||||
run: bash scripts/offline-argocd/rsync_release_assets.sh
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 3)
|
||||
needs: publish-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/argocd
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 3)
|
||||
run: bash scripts/offline-argocd/prune_remote_versions.sh
|
||||
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 }}
|
||||
98
.github/workflows/offline-package-fluxcd-installer.yaml
vendored
Normal file
98
.github/workflows/offline-package-fluxcd-installer.yaml
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
name: Build Offline FluxCD Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/offline-package-fluxcd-installer.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v2.2.0). Leave empty to use offline-fluxcd-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
chart_version:
|
||||
description: "Override Helm chart version for fluxcd-community/flux2. Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-fluxcd
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NERDCTL_VERSION: "2.0.3"
|
||||
outputs:
|
||||
chart_version: ${{ steps.resolve.outputs.chart_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, helm)
|
||||
run: |
|
||||
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
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm repo add fluxcd-community https://fluxcd-community.github.io/helm-charts --force-update
|
||||
helm repo update
|
||||
|
||||
- name: Resolve chart version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||
run: script/offline-fluxcd/resolve-chart-version.sh
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf offline-installer
|
||||
mkdir -p offline-installer/{images,charts,scripts,metadata}
|
||||
|
||||
- name: Stage installer script
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: script/offline-fluxcd/stage-installer.sh
|
||||
|
||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
wget https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-${{ matrix.arch }}.tar.gz \
|
||||
-O offline-installer/nerdctl.tar.gz
|
||||
|
||||
- name: Pull & export required images
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
MATRIX_ARCH: ${{ matrix.arch }}
|
||||
run: script/offline-fluxcd/pull-and-export-images.sh
|
||||
|
||||
- name: Download Helm chart
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm pull fluxcd-community/flux2 --version "${CHART_VERSION}" --untar --untardir offline-installer/charts
|
||||
|
||||
- name: Package offline installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tar -czf offline-setup-fluxcd-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||
ls -lh offline-setup-fluxcd-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-setup-fluxcd-${{ matrix.arch }}
|
||||
path: offline-setup-fluxcd-${{ matrix.arch }}.tar.gz
|
||||
302
.github/workflows/offline-package-gitea-installer.yaml
vendored
Normal file
302
.github/workflows/offline-package-gitea-installer.yaml
vendored
Normal file
@ -0,0 +1,302 @@
|
||||
name: Build Offline Gitea Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/offline-package-gitea-installer.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v1.21.10). Leave empty to use offline-gitea-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
chart_version:
|
||||
description: "Override Helm chart version for gitea-charts/gitea. Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-gitea
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NERDCTL_VERSION: "2.0.3"
|
||||
OFFLINE_DIR: gitea-offline-package
|
||||
outputs:
|
||||
chart_version: ${{ steps.resolve.outputs.chart_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, helm)
|
||||
run: |
|
||||
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
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm repo add gitea-charts https://dl.gitea.io/charts/ --force-update
|
||||
helm repo update
|
||||
|
||||
- name: Resolve chart version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -n "${OVERRIDE_CHART_VERSION}" ]; then
|
||||
CHART_VERSION="${OVERRIDE_CHART_VERSION}"
|
||||
else
|
||||
CHART_VERSION=$(helm search repo gitea-charts/gitea --versions | awk 'NR==2{print $2}')
|
||||
fi
|
||||
echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf "${OFFLINE_DIR}"
|
||||
mkdir -p "${OFFLINE_DIR}"/{images,charts,metadata}
|
||||
|
||||
- name: Stage installer script
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cat <<'SCRIPT' > "${OFFLINE_DIR}/install-gitea.sh"
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CHART_DIR="${ROOT_DIR}/charts/gitea"
|
||||
IMAGES_DIR="${ROOT_DIR}/images"
|
||||
RELEASE_NAME="${RELEASE_NAME:-gitea}"
|
||||
NAMESPACE="${NAMESPACE:-gitea}"
|
||||
|
||||
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 Gitea release ${RELEASE_NAME} in namespace ${NAMESPACE}"
|
||||
helm upgrade --install "${RELEASE_NAME}" "${CHART_DIR}" \
|
||||
--namespace "${NAMESPACE}" \
|
||||
--create-namespace \
|
||||
"$@"
|
||||
SCRIPT
|
||||
chmod +x "${OFFLINE_DIR}/scripts/install-gitea.sh"
|
||||
cat <<'ROOTSCRIPT' > "${OFFLINE_DIR}/install-gitea.sh"
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
exec "${SCRIPT_DIR}/scripts/install-gitea.sh" "$@"
|
||||
ROOTSCRIPT
|
||||
chmod +x "${OFFLINE_DIR}/install-gitea.sh"
|
||||
cat <<EOFMETA > "${OFFLINE_DIR}/metadata/INFO"
|
||||
chart: gitea-charts/gitea
|
||||
chart_version: ${CHART_VERSION}
|
||||
created_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
EOFMETA
|
||||
|
||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
wget https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-${{ matrix.arch }}.tar.gz \
|
||||
-O "${OFFLINE_DIR}/nerdctl.tar.gz"
|
||||
|
||||
- name: Pull & export required images
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PLATFORM="linux/${{ matrix.arch }}"
|
||||
helm template gitea gitea-charts/gitea --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_DIR}/images/${safe}.tar"
|
||||
done
|
||||
|
||||
- name: Download Helm chart
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm pull gitea-charts/gitea --version "${CHART_VERSION}" --untar --untardir "${OFFLINE_DIR}/charts"
|
||||
|
||||
- name: Package offline installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tar -czf offline-package-gitea-${{ matrix.arch }}.tar.gz "${OFFLINE_DIR}"
|
||||
ls -lh offline-package-gitea-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-package-gitea-${{ matrix.arch }}
|
||||
path: offline-package-gitea-${{ 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-gitea-${{ matrix.arch }}
|
||||
path: offline-test
|
||||
|
||||
- name: Verify offline package integrity
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-test
|
||||
tar -tzf offline-package-gitea-${{ matrix.arch }}.tar.gz > /dev/null
|
||||
|
||||
- name: Verify install script layout
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-test
|
||||
tar -xvpf offline-package-gitea-${{ matrix.arch }}.tar.gz
|
||||
test -f gitea-offline-package/install-gitea.sh
|
||||
|
||||
publish-release:
|
||||
needs: test-offline-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-gitea-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/gitea
|
||||
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-gitea-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-package-gitea-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-gitea-amd64.tar.gz
|
||||
release-artifacts/arm64/offline-package-gitea-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Ensure deps (rsync, ssh)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y rsync openssh-client
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync release assets to remote
|
||||
run: |
|
||||
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-gitea-amd64.tar.gz \
|
||||
release-artifacts/arm64/offline-package-gitea-arm64.tar.gz \
|
||||
"${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 3)
|
||||
needs: publish-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/gitea
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 3)
|
||||
run: |
|
||||
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-gitea-|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
|
||||
'
|
||||
219
.github/workflows/offline-package-gitlab-installer.yaml
vendored
Normal file
219
.github/workflows/offline-package-gitlab-installer.yaml
vendored
Normal file
@ -0,0 +1,219 @@
|
||||
name: Build Offline GitLab Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/offline-package-gitlab-installer.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v16.11.0). Leave empty to use offline-gitlab-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
chart_version:
|
||||
description: "Override Helm chart version for gitlab/gitlab. Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-gitlab
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NERDCTL_VERSION: "2.0.3"
|
||||
outputs:
|
||||
chart_version: ${{ steps.resolve.outputs.chart_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, helm)
|
||||
run: script/install-offline-gitlab-deps.sh
|
||||
|
||||
- name: Add helm repo
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm repo add gitlab https://charts.gitlab.io --force-update
|
||||
helm repo update
|
||||
|
||||
- name: Resolve chart version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||
run: script/resolve-gitlab-chart-version.sh
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf offline-installer
|
||||
mkdir -p offline-installer/{images,charts,scripts,metadata}
|
||||
|
||||
- name: Stage installer script
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: script/stage-gitlab-offline-installer.sh
|
||||
|
||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
wget https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-${{ matrix.arch }}.tar.gz \
|
||||
-O offline-installer/nerdctl.tar.gz
|
||||
|
||||
- name: Pull & export required images
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: script/pull-and-export-gitlab-images.sh
|
||||
|
||||
- name: Download Helm chart
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm pull gitlab/gitlab --version "${CHART_VERSION}" --untar --untardir offline-installer/charts
|
||||
|
||||
- name: Package offline installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tar -czf offline-setup-gitlab-${{ matrix.arch }}.tar.gz -C offline-installer .
|
||||
ls -lh offline-setup-gitlab-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-setup-gitlab-${{ matrix.arch }}
|
||||
path: offline-setup-gitlab-${{ 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-setup-gitlab-${{ matrix.arch }}
|
||||
path: offline-test
|
||||
|
||||
- name: Verify offline package integrity
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-test
|
||||
tar -tzf offline-setup-gitlab-${{ 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-gitlab-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/gitlab
|
||||
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-setup-gitlab-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-gitlab-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-setup-gitlab-amd64.tar.gz
|
||||
release-artifacts/arm64/offline-setup-gitlab-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Ensure deps (rsync, ssh)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y rsync openssh-client
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync release assets to remote
|
||||
run: |
|
||||
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-setup-gitlab-amd64.tar.gz \
|
||||
release-artifacts/arm64/offline-setup-gitlab-arm64.tar.gz \
|
||||
"${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 3)
|
||||
needs: publish-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/gitlab
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 3)
|
||||
run: |
|
||||
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-gitlab-|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
|
||||
'
|
||||
207
.github/workflows/offline-package-k3s-installer.yaml
vendored
Normal file
207
.github/workflows/offline-package-k3s-installer.yaml
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
name: Build Offline K3s Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/resolve_k3s_versions.sh'
|
||||
- 'scripts/make_k3s_offline_package.sh'
|
||||
- '.github/workflows/offline-package-k3s-installer.yaml'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
NERDCTL_VERSION: "2.1.4"
|
||||
|
||||
jobs:
|
||||
build-k3s-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
k3s_version: ${{ steps.resolve.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare toolchain (curl/jq/tar/tree + nerdctl)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y curl jq tar tree
|
||||
|
||||
NURL="https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz"
|
||||
TGZ="/tmp/nerdctl-${NERDCTL_VERSION}.tgz"
|
||||
echo "Downloading: ${NURL}"
|
||||
curl -fSL --retry 3 --retry-connrefused --connect-timeout 15 "${NURL}" -o "${TGZ}"
|
||||
# 可选校验:如需严格校验,取消下面两行的注释
|
||||
# curl -fSL "${NURL}.sha256" -o "${TGZ}.sha256"
|
||||
# (cd /tmp && sha256sum -c "$(basename ${TGZ}).sha256") || { echo "SHA256 mismatch"; exit 1; }
|
||||
|
||||
sudo tar -C /usr/local/bin -xzf "${TGZ}"
|
||||
sudo chmod +x /usr/local/bin/nerdctl
|
||||
sudo nerdctl --version
|
||||
|
||||
- name: Resolve latest k3s version
|
||||
id: resolve
|
||||
run: |
|
||||
set -euo pipefail
|
||||
bash scripts/resolve_k3s_versions.sh
|
||||
|
||||
- name: Build offline package
|
||||
env:
|
||||
K3S_VERSION: ${{ steps.resolve.outputs.version }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
chmod +x scripts/make_k3s_offline_package.sh
|
||||
./scripts/make_k3s_offline_package.sh
|
||||
|
||||
- name: Validate airgap image tar
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TAR="k3s-offline-package/images/k3s-airgap-images-${{ matrix.arch }}.tar"
|
||||
tmp=$(mktemp -d)
|
||||
tar -xf "$TAR" -C "$tmp" manifest.json
|
||||
configs=$(jq -r '.[].Config' "$tmp/manifest.json")
|
||||
for cfg in $configs; do
|
||||
tar -xf "$TAR" -C "$tmp" "$cfg"
|
||||
arch=$(jq -r '.architecture' "$tmp/$cfg")
|
||||
if [ "$arch" != "${{ matrix.arch }}" ]; then
|
||||
echo "unexpected arch $arch in $cfg" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
rm -rf "$tmp"
|
||||
|
||||
- name: Pack final installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# 假设脚本产出目录为 k3s-offline-package
|
||||
test -d k3s-offline-package
|
||||
tar czf offline-package-k3s-installer-${{ matrix.arch }}.tar.gz k3s-offline-package
|
||||
ls -lh offline-package-k3s-installer-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-package-k3s-installer-${{ matrix.arch }}
|
||||
path: offline-package-k3s-installer-${{ matrix.arch }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
test-k3s-installer:
|
||||
needs: build-k3s-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-package-k3s-installer-${{ matrix.arch }}
|
||||
path: ./test-dir
|
||||
|
||||
- name: Extract Package
|
||||
run: |
|
||||
cd test-dir
|
||||
tar -xzvf offline-package-k3s-installer-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Install jq
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq
|
||||
|
||||
- name: Verify k3s binary arch
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BIN="test-dir/k3s-offline-package/bin/k3s-${{ matrix.arch }}"
|
||||
file "$BIN"
|
||||
if [ "${{ matrix.arch }}" = "amd64" ]; then
|
||||
file "$BIN" | grep -q 'x86-64'
|
||||
else
|
||||
file "$BIN" | grep -q 'aarch64'
|
||||
fi
|
||||
|
||||
- name: Verify image platforms
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TAR="test-dir/k3s-offline-package/images/k3s-airgap-images-${{ matrix.arch }}.tar"
|
||||
tmp=$(mktemp -d)
|
||||
tar -xf "$TAR" -C "$tmp" manifest.json
|
||||
configs=$(jq -r '.[].Config' "$tmp/manifest.json")
|
||||
for cfg in $configs; do
|
||||
tar -xf "$TAR" -C "$tmp" "$cfg"
|
||||
arch=$(jq -r '.architecture' "$tmp/$cfg")
|
||||
if [ "$arch" != "${{ matrix.arch }}" ]; then
|
||||
echo "unexpected arch $arch in $cfg" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Setup K3s and Test
|
||||
if: matrix.arch == 'amd64'
|
||||
run: |
|
||||
cd test-dir/k3s-offline-package
|
||||
bash install-server.sh
|
||||
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get nodes
|
||||
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get pods -A
|
||||
|
||||
publish-release:
|
||||
needs: test-k3s-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-k3s-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/nginx-ingress
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create GitHub Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
release_name: Daily 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-k3s-installer-amd64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Download arm64 Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-package-k3s-installer-arm64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
files: |
|
||||
release-artifacts/offline-package-k3s-installer-amd64.tar.gz
|
||||
release-artifacts/offline-package-k3s-installer-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Prune old releases (keep last 3)
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
releases=$(gh release list --limit 100 --json tagName,createdAt --jq 'sort_by(.createdAt) | reverse | .[3:] | .[].tagName')
|
||||
if [[ -n "$releases" ]]; then
|
||||
for tag in $releases; do
|
||||
gh release delete "$tag" -y
|
||||
done
|
||||
fi
|
||||
169
.github/workflows/offline-package-kong-gateway.yaml
vendored
Normal file
169
.github/workflows/offline-package-kong-gateway.yaml
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
name: Build Offline Kong Gateway Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'gitops/scripts/kong-gateway/deploy-kong-gateway.sh'
|
||||
- 'gitops/scripts/kong-gateway/configure-example-app.sh'
|
||||
- '.github/workflows/offline-package-kong-gateway.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v0.1.0). Leave empty to use offline-kong-gateway-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
gateway_tag:
|
||||
description: "Kong Gateway image tag. Default: 3.7"
|
||||
required: false
|
||||
type: string
|
||||
kic_tag:
|
||||
description: "Kubernetes Ingress Controller image tag. Default: 3.2"
|
||||
required: false
|
||||
type: string
|
||||
chart_version:
|
||||
description: "Override helm chart version for kong/ingress"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-kong-gateway
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GATEWAY_TAG: ${{ github.event.inputs.gateway_tag || '3.7' }}
|
||||
KIC_TAG: ${{ github.event.inputs.kic_tag || '3.2' }}
|
||||
CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, helm)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y curl
|
||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
helm version
|
||||
|
||||
- name: Add helm repo
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm repo add kong https://charts.konghq.com
|
||||
helm repo update
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p offline-installer/{images,charts,scripts,bin}
|
||||
|
||||
- name: Stage scripts
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cp gitops/scripts/kong-gateway/deploy-kong-gateway.sh offline-installer/scripts/
|
||||
cp gitops/scripts/kong-gateway/configure-example-app.sh offline-installer/scripts/
|
||||
chmod +x offline-installer/scripts/deploy-kong-gateway.sh offline-installer/scripts/configure-example-app.sh
|
||||
|
||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
wget https://github.com/containerd/nerdctl/releases/download/v2.0.3/nerdctl-2.0.3-linux-${{ matrix.arch }}.tar.gz -O offline-installer/nerdctl.tar.gz
|
||||
|
||||
- name: Pull & export required images
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker pull "kong/kong-gateway:${GATEWAY_TAG}"
|
||||
docker pull "kong/kubernetes-ingress-controller:${KIC_TAG}"
|
||||
|
||||
docker save "kong/kong-gateway:${GATEWAY_TAG}" -o offline-installer/images/kong-gateway.tar
|
||||
docker save "kong/kubernetes-ingress-controller:${KIC_TAG}" -o offline-installer/images/kic.tar
|
||||
|
||||
- name: Download Helm Chart (kong/ingress)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -n "${CHART_VERSION}" ]; then
|
||||
helm pull kong/ingress --version="${CHART_VERSION}" --untar --untardir offline-installer/charts
|
||||
else
|
||||
helm pull kong/ingress --untar --untardir offline-installer/charts
|
||||
fi
|
||||
|
||||
- name: Create offline package
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tar -C offline-installer -czf offline-setup-kong-gateway-${{ matrix.arch }}.tar.gz .
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-setup-kong-gateway-${{ matrix.arch }}
|
||||
path: offline-setup-kong-gateway-${{ matrix.arch }}.tar.gz
|
||||
|
||||
test-release:
|
||||
needs: build-offline-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download offline installer artifact for ${{ matrix.arch }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-kong-gateway-${{ matrix.arch }}
|
||||
path: offline-test
|
||||
|
||||
- name: Verify offline package
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-test
|
||||
tar -tzf offline-setup-kong-gateway-${{ matrix.arch }}.tar.gz > /dev/null
|
||||
cd ..
|
||||
|
||||
publish-release:
|
||||
needs: test-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-kong-gateway-{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-setup-kong-gateway-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-kong-gateway-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-setup-kong-gateway-amd64.tar.gz
|
||||
release-artifacts/arm64/offline-setup-kong-gateway-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
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 }}
|
||||
289
.github/workflows/offline-package-nginx-ingress.yaml
vendored
Normal file
289
.github/workflows/offline-package-nginx-ingress.yaml
vendored
Normal file
@ -0,0 +1,289 @@
|
||||
name: Build Offline Nginx Ingress Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/ingress-installer.sh'
|
||||
- 'scripts/resolve_nginx_ingress_versions.sh'
|
||||
- '.github/workflows/offline-package-nginx-ingress.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v0.133.0). Leave empty to use offline-nginx-ingress-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
image_tag:
|
||||
description: "Override image tag for nginx/nginx-ingress (e.g., 5.1.1). Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
chart_version:
|
||||
description: "Override helm chart version for nginx-stable/nginx-ingress (e.g., 1.2.3). Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
major_whitelist:
|
||||
description: "Allowed major versions for image tag (regex alternation). Default: 5 (i.e., ^5\\.)"
|
||||
required: false
|
||||
type: string
|
||||
default: "5"
|
||||
|
||||
permissions:
|
||||
contents: write # 需要创建/上传 Release 资产
|
||||
|
||||
concurrency:
|
||||
group: build-offline-nginx-ingress
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
image_tag: ${{ steps.resolve.outputs.image_tag }}
|
||||
chart_version: ${{ steps.resolve.outputs.chart_version }}
|
||||
artifact-name: ${{ steps.upload-artifact.outputs.artifact-name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, helm)
|
||||
run: |
|
||||
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
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm repo add nginx-stable https://helm.nginx.com/stable
|
||||
helm repo update
|
||||
|
||||
- name: Resolve latest versions
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_IMAGE_TAG: ${{ github.event.inputs.image_tag }}
|
||||
OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
|
||||
MAJOR_WHITELIST: ${{ github.event.inputs.major_whitelist }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
bash scripts/resolve_nginx_ingress_versions.sh
|
||||
|
||||
- name: Prepare directories
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p offline-installer/{images,charts,scripts,bin}
|
||||
|
||||
# 复制并“盖章”版本号到安装脚本
|
||||
- name: Stage installer script and stamp resolved image tag
|
||||
env:
|
||||
IMG_TAG: ${{ steps.resolve.outputs.image_tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cp scripts/ingress-installer.sh offline-installer/scripts/
|
||||
# 替换默认的 NGINX_IC_IMAGE 与 OCI_NGINX_REF 中的 2.4.0 为解析到的 ${IMG_TAG}
|
||||
sed -i -E "s|(NGINX_IC_IMAGE:=nginx/nginx-ingress:)[0-9]+\.[0-9]+\.[0-9]+|\1${IMG_TAG}|" offline-installer/scripts/ingress-installer.sh
|
||||
sed -i -E "s|(OCI_NGINX_REF:=nginx-ingress-)[0-9]+\.[0-9]+\.[0-9]+|\1${IMG_TAG}|" offline-installer/scripts/ingress-installer.sh
|
||||
chmod +x offline-installer/scripts/ingress-installer.sh
|
||||
|
||||
- name: Download nerdctl binary for ${{ matrix.arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
wget https://github.com/containerd/nerdctl/releases/download/v2.0.3/nerdctl-2.0.3-linux-${{ matrix.arch }}.tar.gz \
|
||||
-O offline-installer/nerdctl.tar.gz
|
||||
|
||||
- name: Pull & export required images (nginx/nginx-ingress:${{ steps.resolve.outputs.image_tag }})
|
||||
env:
|
||||
IMG_TAG: ${{ steps.resolve.outputs.image_tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker pull "nginx/nginx-ingress:${IMG_TAG}"
|
||||
docker pull "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407"
|
||||
|
||||
docker save "nginx/nginx-ingress:${IMG_TAG}" \
|
||||
-o offline-installer/images/nginx-ingress.tar
|
||||
|
||||
docker save "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407" \
|
||||
-o offline-installer/images/kube-webhook-certgen.tar
|
||||
|
||||
- name: Download Helm Chart (nginx-stable/nginx-ingress ${{ steps.resolve.outputs.chart_version }})
|
||||
env:
|
||||
CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm pull nginx-stable/nginx-ingress --version="${CHART_VERSION}" --untar --untardir offline-installer/charts
|
||||
|
||||
- name: Package offline installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-installer
|
||||
tar czvf ../offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz ./
|
||||
cd ..
|
||||
|
||||
- name: Upload artifact
|
||||
id: upload-artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: offline-setup-nginx-ingress-${{ matrix.arch }}
|
||||
path: offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz
|
||||
|
||||
test-offline-installer:
|
||||
needs: build-offline-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download offline installer artifact for ${{ matrix.arch }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-nginx-ingress-${{ matrix.arch }}
|
||||
path: offline-test
|
||||
|
||||
- name: Setup K3s and KUBECONFIG for user
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -sfL https://get.k3s.io | sudo sh -
|
||||
mkdir -p $HOME/.kube
|
||||
sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
|
||||
sudo chown $USER:$USER $HOME/.kube/config
|
||||
sudo mkdir -p /root/.kube
|
||||
sudo cp /etc/rancher/k3s/k3s.yaml /root/.kube/config
|
||||
kubectl get nodes
|
||||
kubectl version --client=true
|
||||
|
||||
- name: Install Helm
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
|
||||
- name: Load offline installer package
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-test
|
||||
tar -xzvf offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz
|
||||
sudo tar xzvf nerdctl.tar.gz -C /usr/local/bin/
|
||||
docker load -i images/nginx-ingress.tar
|
||||
docker load -i images/kube-webhook-certgen.tar
|
||||
cd ..
|
||||
|
||||
- name: Run offline installer in K3S cluster
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd offline-test
|
||||
sudo bash scripts/ingress-installer.sh
|
||||
sleep 10
|
||||
sudo helm list -A
|
||||
sudo kubectl -n ingress get pods
|
||||
|
||||
publish-release:
|
||||
needs: test-offline-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-nginx-ingress-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/nginx-ingress
|
||||
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-setup-nginx-ingress-amd64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: offline-setup-nginx-ingress-arm64
|
||||
path: release-artifacts
|
||||
|
||||
- name: Upload offline installers to GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
files: |
|
||||
release-artifacts/offline-setup-nginx-ingress-amd64.tar.gz
|
||||
release-artifacts/offline-setup-nginx-ingress-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# === Rsync 到远端 ===
|
||||
- name: Ensure deps (rsync, ssh)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y rsync openssh-client
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync release assets to remote
|
||||
run: |
|
||||
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/offline-setup-nginx-ingress-amd64.tar.gz \
|
||||
release-artifacts/offline-setup-nginx-ingress-arm64.tar.gz \
|
||||
"${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 3)
|
||||
needs: publish-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/nginx-ingress
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 3)
|
||||
run: |
|
||||
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
|
||||
# 同时兼容两类目录命名:offline-nginx-ingress-* 和 v<semver>
|
||||
mapfile -t all < <(ls -1 | grep -E "^(offline-nginx-ingress-|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
|
||||
'
|
||||
175
.github/workflows/offline-package-pulumi-installer.yaml
vendored
Normal file
175
.github/workflows/offline-package-pulumi-installer.yaml
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
name: Build Offline Pulumi Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/offline-package-pulumi-installer.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v3.127.0). Leave empty to use offline-pulumi-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
pulumi_version:
|
||||
description: "Override Pulumi version (e.g., 3.127.0). Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-pulumi
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.resolve.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, tar)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y curl jq tar
|
||||
|
||||
- name: Resolve Pulumi version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_VERSION: ${{ github.event.inputs.pulumi_version }}
|
||||
run: script/resolve-pulumi-version.sh
|
||||
|
||||
- name: Build offline Pulumi package
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
PULUMI_VERSION: ${{ steps.resolve.outputs.version }}
|
||||
MATRIX_ARCH: ${{ matrix.arch }}
|
||||
|
||||
run: script/build-offline-pulumi-package.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pulumi-offline-package-${{ matrix.arch }}
|
||||
path: offline-package-pulumi-${{ matrix.arch }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
test-offline-installer:
|
||||
needs: build-offline-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: pulumi-offline-package-${{ matrix.arch }}
|
||||
path: ./test-dir
|
||||
|
||||
- name: Extract package
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd test-dir
|
||||
tar -xzvf offline-package-pulumi-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Verify Pulumi bundle
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
PULUMI_VERSION: ${{ needs.build-offline-installer.outputs.version }}
|
||||
MATRIX_ARCH: ${{ matrix.arch }}
|
||||
|
||||
run: script/verify-pulumi-bundle.sh
|
||||
|
||||
publish-release:
|
||||
needs: test-offline-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-pulumi-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/pulumi
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create GitHub 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: pulumi-offline-package-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: pulumi-offline-package-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-pulumi-amd64.tar.gz
|
||||
release-artifacts/arm64/offline-package-pulumi-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Ensure deps (rsync, ssh)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y rsync openssh-client
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync release assets to remote
|
||||
run: script/rsync-release-assets.sh
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 3)
|
||||
needs: publish-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/pulumi
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 3)
|
||||
run: script/prune-remote-versions.sh
|
||||
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 }}
|
||||
201
.github/workflows/offline-package-sealos-installer.yaml
vendored
Normal file
201
.github/workflows/offline-package-sealos-installer.yaml
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
name: Build Offline Sealos Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/create-sealos-offline-package.sh'
|
||||
- 'scripts/sealos-install.sh'
|
||||
- 'scripts/cilium-values.yaml'
|
||||
- 'scripts/resolve_sealos_versions.sh'
|
||||
- '.github/workflows/offline-package-sealos-installer.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v5.0.3). Leave empty to use offline-sealos-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
sealos_version:
|
||||
description: "Override Sealos version (e.g., 5.0.3). Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-sealos
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
sealos_version: ${{ steps.resolve.outputs.sealos_version }}
|
||||
artifact-name: ${{ steps.upload-artifact.outputs.artifact-name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y curl jq
|
||||
|
||||
- name: Resolve latest Sealos version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_SEALOS_VERSION: ${{ github.event.inputs.sealos_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
bash scripts/resolve_sealos_versions.sh
|
||||
|
||||
- name: Run Offline Package Builder
|
||||
env:
|
||||
SEALOS_VERSION: ${{ steps.resolve.outputs.sealos_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
chmod +x scripts/create-sealos-offline-package.sh
|
||||
ARCH=${{ matrix.arch }} ./scripts/create-sealos-offline-package.sh
|
||||
|
||||
- name: Upload Artifact
|
||||
id: upload-artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sealos-offline-package-${{ matrix.arch }}
|
||||
path: sealos-offline-package-${{ matrix.arch }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
test-offline-installer:
|
||||
needs: build-offline-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sealos-offline-package-${{ matrix.arch }}
|
||||
path: ./test-dir
|
||||
|
||||
- name: Extract Package
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd test-dir
|
||||
tar -xzvf sealos-offline-package-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Verify Package Contents
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -f test-dir/sealos-offline-package/sealos-install.sh
|
||||
test -f test-dir/sealos-offline-package/cilium-values.yaml
|
||||
|
||||
publish-release:
|
||||
needs: test-offline-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-sealos-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/sealos
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create GitHub 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: sealos-offline-package-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sealos-offline-package-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/sealos-offline-package-amd64.tar.gz
|
||||
release-artifacts/arm64/sealos-offline-package-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Ensure deps (rsync, ssh)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y rsync openssh-client
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync release assets to remote
|
||||
run: |
|
||||
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/sealos-offline-package-amd64.tar.gz \
|
||||
release-artifacts/arm64/sealos-offline-package-arm64.tar.gz \
|
||||
"${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 3)
|
||||
needs: publish-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/sealos
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 3)
|
||||
run: |
|
||||
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-sealos-|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
|
||||
'
|
||||
167
.github/workflows/offline-package-terraform-installer.yaml
vendored
Normal file
167
.github/workflows/offline-package-terraform-installer.yaml
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
name: Build Offline Terraform Installer
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/offline-package-terraform-installer.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to use/sync (e.g., v1.8.5). Leave empty to use offline-terraform-<run_number>"
|
||||
required: false
|
||||
type: string
|
||||
terraform_version:
|
||||
description: "Override Terraform version (e.g., 1.8.5). Leave empty to auto-resolve"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: build-offline-terraform
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build-offline-installer:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.resolve.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps (curl, jq, unzip)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y curl jq unzip
|
||||
|
||||
- name: Resolve Terraform version
|
||||
id: resolve
|
||||
env:
|
||||
OVERRIDE_VERSION: ${{ github.event.inputs.terraform_version }}
|
||||
run: script/resolve-terraform-version.sh
|
||||
|
||||
- name: Build offline Terraform package
|
||||
env:
|
||||
TERRAFORM_VERSION: ${{ steps.resolve.outputs.version }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: script/build-offline-terraform-package.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: terraform-offline-package-${{ matrix.arch }}
|
||||
path: terraform-offline-package-${{ matrix.arch }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
test-offline-installer:
|
||||
needs: build-offline-installer
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: terraform-offline-package-${{ matrix.arch }}
|
||||
path: ./test-dir
|
||||
|
||||
- name: Extract package
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd test-dir
|
||||
tar -xzvf terraform-offline-package-${{ matrix.arch }}.tar.gz
|
||||
|
||||
- name: Verify Terraform bundle
|
||||
env:
|
||||
TERRAFORM_VERSION: ${{ needs.build-offline-installer.outputs.version }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: script/verify-terraform-bundle.sh
|
||||
|
||||
publish-release:
|
||||
needs: test-offline-installer
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-terraform-{0}', github.run_number) }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/terraform
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create GitHub 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: terraform-offline-package-amd64
|
||||
path: release-artifacts/amd64
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: terraform-offline-package-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/terraform-offline-package-amd64.tar.gz
|
||||
release-artifacts/arm64/terraform-offline-package-arm64.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Ensure deps (rsync, ssh)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y rsync openssh-client
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync release assets to remote
|
||||
run: script/rsync-release-assets.sh
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 3)
|
||||
needs: publish-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/terraform
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 3)
|
||||
run: script/prune-remote-versions.sh
|
||||
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
|
||||
201
.github/workflows/sync-blackbox-exporter.yml
vendored
Normal file
201
.github/workflows/sync-blackbox-exporter.yml
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
name: Sync blackbox_exporter latest v0.* (matrix)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 2 * * *" # <-- 这是 UTC 02:00。若需 JST 02:00,请改为 "0 17 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: sync-blackbox-exporter-v0
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
name: Resolve latest tag & remote check (${{ matrix.vps_host }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
GH_REPO: prometheus/blackbox_exporter
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/prometheus/blackbox_exporter
|
||||
outputs:
|
||||
tag: ${{ steps.latest.outputs.tag }}
|
||||
version: ${{ steps.latest.outputs.version }}
|
||||
exists: ${{ steps.remotecheck.outputs.exists }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Ensure GitHub CLI & deps
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y gh jq rsync
|
||||
gh --version
|
||||
jq --version
|
||||
rsync --version | head -n1
|
||||
|
||||
- name: Resolve latest tag (v0.*)
|
||||
id: latest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TAG=$(./scripts/resolve_github_repo_release.sh "${GH_REPO}" '^v0(\.|$)' 'v0.*')
|
||||
VERSION=${TAG#v}
|
||||
|
||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Latest tag: $TAG (version: $VERSION)"
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Check remote existing version dir
|
||||
id: remotecheck
|
||||
env:
|
||||
VERSION: ${{ steps.latest.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
REMOTE_DIR="${REMOTE_ROOT}/${VERSION}"
|
||||
if ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "test -d '${REMOTE_DIR}'"; then
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
echo "Remote already has ${REMOTE_DIR}, skip whole sync."
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Remote does not have ${REMOTE_DIR}, will sync."
|
||||
fi
|
||||
|
||||
sync-one:
|
||||
name: Sync ${{ matrix.asset_suffix }} for ${{ needs.prep.outputs.version }} (${{ matrix.vps_host }})
|
||||
needs: prep
|
||||
if: needs.prep.outputs.exists == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
asset_suffix:
|
||||
- "linux-amd64.tar.gz"
|
||||
- "linux-arm64.tar.gz"
|
||||
- "darwin-amd64.tar.gz"
|
||||
- "darwin-arm64.tar.gz"
|
||||
env:
|
||||
GH_REPO: prometheus/blackbox_exporter
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/prometheus/blackbox_exporter
|
||||
TAG: ${{ needs.prep.outputs.tag }}
|
||||
VERSION: ${{ needs.prep.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Ensure GitHub CLI & deps
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y gh jq rsync
|
||||
gh --version
|
||||
|
||||
- name: Check asset exists via GitHub CLI
|
||||
id: has_asset
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ASSET="blackbox_exporter-${VERSION}.${{ matrix.asset_suffix }}"
|
||||
echo "Checking asset $ASSET for tag ${TAG}"
|
||||
if gh release view "${TAG}" --repo "${GH_REPO}" --json assets \
|
||||
| jq -r '.assets[].name' | grep -Fxq "$ASSET"; then
|
||||
echo "asset=$ASSET" >> "$GITHUB_OUTPUT"
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Asset $ASSET not found for ${TAG}, will skip."
|
||||
fi
|
||||
|
||||
- name: Download asset
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "releases/${VERSION}"
|
||||
gh release download "${TAG}" \
|
||||
--repo "${GH_REPO}" \
|
||||
--pattern "${{ steps.has_asset.outputs.asset }}" \
|
||||
--dir "releases/${VERSION}"
|
||||
|
||||
- name: Init SSH
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync this asset to remote
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
REMOTE_DIR="${REMOTE_ROOT}/${VERSION}"
|
||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "mkdir -p '${REMOTE_DIR}'"
|
||||
echo "Rsync releases/${VERSION}/${{ steps.has_asset.outputs.asset }} -> ${VPS_HOST}:${REMOTE_DIR}/"
|
||||
rsync -av -e "ssh -i ~/.ssh/id_rsa" \
|
||||
"releases/${VERSION}/${{ steps.has_asset.outputs.asset }}" "${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 10 v0.*) (${{ matrix.vps_host }})
|
||||
needs: [prep, sync-one]
|
||||
if: needs.prep.outputs.exists == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/prometheus/blackbox_exporter
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 10)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" bash -lc '
|
||||
set -euo pipefail
|
||||
cd "'"${REMOTE_ROOT}"'" || exit 0
|
||||
keep=10
|
||||
mapfile -t all < <(ls -1 | grep -E "^[0-9]+\\.[0-9]+\\.[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
|
||||
'
|
||||
217
.github/workflows/sync-node-exporter.yml
vendored
Normal file
217
.github/workflows/sync-node-exporter.yml
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
name: Sync node_exporter 1.9.* / 1.8.* (matrix)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release version without 'v' (e.g., 1.9.1). Defaults to 1.9.1"
|
||||
required: false
|
||||
type: string
|
||||
schedule:
|
||||
- cron: "0 2 * * *" # <-- 这是 UTC 02:00。若需 JST 02:00,请改为 "0 17 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: sync-node-exporter-1x
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
name: Resolve version & remote check (${{ matrix.vps_host }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
GH_REPO: prometheus/node_exporter
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/otel/node_exporter/
|
||||
DEFAULT_TAG: 1.9.1 # <-- 无 v
|
||||
ALLOWED_SERIES: "^(1\\.9|1\\.8)\\.[0-9]+\\.[0-9]+$"
|
||||
outputs:
|
||||
tag: ${{ steps.resolve.outputs.tag }} # v1.9.1
|
||||
version: ${{ steps.resolve.outputs.version }} # 1.9.1
|
||||
exists: ${{ steps.remotecheck.outputs.exists }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Ensure GitHub CLI & deps
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y gh jq rsync
|
||||
gh --version
|
||||
jq --version
|
||||
rsync --version | head -n1
|
||||
|
||||
- name: Resolve version (use input or default) & validate (1.9.* / 1.8.*)
|
||||
id: resolve
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VERSION_INPUT='${{ github.event.inputs.tag }}'
|
||||
if [ -n "$VERSION_INPUT" ]; then
|
||||
VERSION="$VERSION_INPUT"
|
||||
else
|
||||
VERSION="$DEFAULT_TAG"
|
||||
fi
|
||||
|
||||
if ! echo "$VERSION" | grep -Eq '${{ env.ALLOWED_SERIES }}'; then
|
||||
echo "Invalid or disallowed version: $VERSION. Allowed: 1.9.* or 1.8.*" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REL_TAG="v${VERSION}" # GitHub release tag 有 v 前缀
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "tag=$REL_TAG" >> "$GITHUB_OUTPUT"
|
||||
echo "Use version: $VERSION (release tag: $REL_TAG)"
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Check remote existing version dir
|
||||
id: remotecheck
|
||||
env:
|
||||
VERSION: ${{ steps.resolve.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
REMOTE_DIR="${REMOTE_ROOT}/${VERSION}"
|
||||
if ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "test -d '${REMOTE_DIR}'"; then
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
echo "Remote already has ${REMOTE_DIR}, skip whole sync."
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Remote does not have ${REMOTE_DIR}, will sync."
|
||||
fi
|
||||
|
||||
sync-one:
|
||||
name: Sync ${{ matrix.asset_suffix }} for ${{ needs.prep.outputs.version }} (${{ matrix.vps_host }})
|
||||
needs: prep
|
||||
if: needs.prep.outputs.exists == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
asset_suffix:
|
||||
- "linux-amd64.tar.gz"
|
||||
- "linux-arm64.tar.gz"
|
||||
env:
|
||||
GH_REPO: prometheus/node_exporter
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/prometheus/node_exporter
|
||||
TAG: ${{ needs.prep.outputs.tag }} # v1.9.1
|
||||
VERSION: ${{ needs.prep.outputs.version }} # 1.9.1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Ensure GitHub CLI & deps
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y gh jq rsync
|
||||
gh --version
|
||||
|
||||
- name: Check asset exists via GitHub CLI
|
||||
id: has_asset
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# 文件名:node_exporter-${VERSION}.linux-amd64.tar.gz / linux-arm64.tar.gz
|
||||
ASSET="node_exporter-${VERSION}.${{ matrix.asset_suffix }}"
|
||||
echo "Checking asset $ASSET for tag ${TAG}"
|
||||
if gh release view "${TAG}" --repo "${GH_REPO}" --json assets \
|
||||
| jq -r '.assets[].name' | grep -Fxq "$ASSET"; then
|
||||
echo "asset=$ASSET" >> "$GITHUB_OUTPUT"
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Asset $ASSET not found for ${TAG}, will skip."
|
||||
fi
|
||||
|
||||
- name: Download asset
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "releases/${VERSION}"
|
||||
gh release download "${TAG}" \
|
||||
--repo "${GH_REPO}" \
|
||||
--pattern "${{ steps.has_asset.outputs.asset }}" \
|
||||
--dir "releases/${VERSION}"
|
||||
|
||||
- name: Init SSH
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync this asset to remote
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
REMOTE_DIR="${REMOTE_ROOT}/${VERSION}"
|
||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "mkdir -p '${REMOTE_DIR}'"
|
||||
echo "Rsync releases/${VERSION}/${{ steps.has_asset.outputs.asset }} -> ${VPS_HOST}:${REMOTE_DIR}/"
|
||||
rsync -av -e "ssh -i ~/.ssh/id_rsa" \
|
||||
"releases/${VERSION}/${{ steps.has_asset.outputs.asset }}" "${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 10) (${{ matrix.vps_host }})
|
||||
needs: [prep, sync-one]
|
||||
if: needs.prep.outputs.exists == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/prometheus/node_exporter/
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 10)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" bash -lc '
|
||||
set -euo pipefail
|
||||
cd "'"${REMOTE_ROOT}"'" || exit 0
|
||||
keep=10
|
||||
mapfile -t all < <(ls -1 | grep -E "^[0-9]+\.[0-9]+\.[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
|
||||
'
|
||||
77
.github/workflows/sync-otel-collector.yml
vendored
77
.github/workflows/sync-otel-collector.yml
vendored
@ -20,16 +20,20 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
name: Resolve tag & remote check
|
||||
name: Resolve tag & remote check (${{ matrix.vps_host }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
GH_REPO: open-telemetry/opentelemetry-collector-releases
|
||||
GH_TOKEN: ${{ github.token }} # 用内置 token,无需自建 PAT
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/otelcol-contrib
|
||||
DEFAULT_TAG: v0.133.0
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/otel/OpenTelemetry/
|
||||
outputs:
|
||||
tag: ${{ steps.resolve.outputs.tag }}
|
||||
version: ${{ steps.resolve.outputs.version }}
|
||||
@ -46,7 +50,7 @@ jobs:
|
||||
jq --version
|
||||
rsync --version | head -n1
|
||||
|
||||
- name: Resolve tag (use input or default)
|
||||
- name: Resolve tag (use input or latest v0.*)
|
||||
id: resolve
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@ -54,7 +58,7 @@ jobs:
|
||||
if [ -n "$TAG_INPUT" ]; then
|
||||
TAG="$TAG_INPUT"
|
||||
else
|
||||
TAG="$DEFAULT_TAG"
|
||||
TAG=$(./scripts/resolve_github_repo_release.sh "${GH_REPO}" '^v0\.[0-9]+\.[0-9]+$' 'v0.*')
|
||||
fi
|
||||
|
||||
# 基本校验:必须形如 v0.X.Y
|
||||
@ -92,25 +96,45 @@ jobs:
|
||||
fi
|
||||
|
||||
sync-one:
|
||||
name: Sync ${{ matrix.asset_suffix }} for ${{ needs.prep.outputs.tag }}
|
||||
name: Sync ${{ matrix.asset_prefix }}_${{ matrix.asset_suffix }} for ${{ needs.prep.outputs.tag }} (${{ matrix.vps_host }})
|
||||
needs: prep
|
||||
if: needs.prep.outputs.exists == 'false' # 远端已存在则整个矩阵跳过
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
asset_suffix:
|
||||
- "linux_amd64.tar.gz"
|
||||
- "linux_amd64.deb"
|
||||
- "linux_arm64.tar.gz"
|
||||
- "linux_arm64.deb"
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
asset:
|
||||
- otelcol-contrib_linux_amd64
|
||||
- otelcol-contrib_linux_arm64
|
||||
- opampsupervisor_linux_amd64
|
||||
- opampsupervisor_linux_arm64
|
||||
include:
|
||||
- asset: otelcol-contrib_linux_amd64
|
||||
asset_prefix: "otelcol-contrib"
|
||||
asset_suffix: "linux_amd64.tar.gz"
|
||||
release_tag_prefix: ""
|
||||
- asset: otelcol-contrib_linux_arm64
|
||||
asset_prefix: "otelcol-contrib"
|
||||
asset_suffix: "linux_arm64.tar.gz"
|
||||
release_tag_prefix: ""
|
||||
- asset: opampsupervisor_linux_amd64
|
||||
asset_prefix: "opampsupervisor"
|
||||
asset_suffix: "linux_amd64"
|
||||
release_tag_prefix: "cmd/opampsupervisor/"
|
||||
- asset: opampsupervisor_linux_arm64
|
||||
asset_prefix: "opampsupervisor"
|
||||
asset_suffix: "linux_arm64"
|
||||
release_tag_prefix: "cmd/opampsupervisor/"
|
||||
env:
|
||||
GH_REPO: open-telemetry/opentelemetry-collector-releases
|
||||
GH_TOKEN: ${{ github.token }} # 继续使用内置 token
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/otelcol-contrib
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/otel/OpenTelemetry
|
||||
TAG: ${{ needs.prep.outputs.tag }}
|
||||
VERSION: ${{ needs.prep.outputs.version }}
|
||||
steps:
|
||||
@ -127,15 +151,17 @@ jobs:
|
||||
id: has_asset
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ASSET="otelcol-contrib_${VERSION}_${{ matrix.asset_suffix }}"
|
||||
echo "Checking asset $ASSET for tag ${TAG}"
|
||||
if gh release view "${TAG}" --repo "${GH_REPO}" --json assets \
|
||||
| jq -r '.assets[].name' | grep -Fxq "$ASSET"; then
|
||||
ASSET="${{ matrix.asset_prefix }}_${VERSION}_${{ matrix.asset_suffix }}"
|
||||
RELEASE_TAG="${{ matrix.release_tag_prefix }}${TAG}"
|
||||
echo "Checking asset $ASSET for release tag ${RELEASE_TAG}"
|
||||
ASSET_LIST=$(gh release view "${RELEASE_TAG}" --repo "${GH_REPO}" --json assets | jq -r '.assets[].name')
|
||||
if echo "${ASSET_LIST}" | grep -Fxq "$ASSET"; then
|
||||
echo "asset=$ASSET" >> "$GITHUB_OUTPUT"
|
||||
echo "release_tag=${RELEASE_TAG}" >> "$GITHUB_OUTPUT"
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Asset $ASSET not found for ${TAG}, will skip."
|
||||
echo "Asset $ASSET not found for ${RELEASE_TAG}, will skip."
|
||||
fi
|
||||
|
||||
- name: Download asset
|
||||
@ -143,7 +169,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "releases/${TAG}"
|
||||
gh release download "${TAG}" \
|
||||
gh release download "${{ steps.has_asset.outputs.release_tag }}" \
|
||||
--repo "${GH_REPO}" \
|
||||
--pattern "${{ steps.has_asset.outputs.asset }}" \
|
||||
--dir "releases/${TAG}"
|
||||
@ -168,15 +194,20 @@ jobs:
|
||||
"releases/${TAG}/${{ steps.has_asset.outputs.asset }}" "${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 10 v0.*)
|
||||
name: Remote retention (keep latest 10 v0.*) (${{ matrix.vps_host }})
|
||||
needs: [prep, sync-one]
|
||||
if: needs.prep.outputs.exists == 'false' # 只有新增版本时才清理
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
REMOTE_ROOT: /data/update-server/otelcol-contrib
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/otel/OpenTelemetry/
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
|
||||
199
.github/workflows/sync-vultr-cli.yml
vendored
Normal file
199
.github/workflows/sync-vultr-cli.yml
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
name: Sync vultr-cli latest (matrix)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 2 * * *" # <-- 这是 UTC 02:00。若需 JST 02:00,请改为 "0 17 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: sync-vultr-cli-latest
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
name: Resolve latest tag & remote check (${{ matrix.vps_host }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
GH_REPO: vultr/vultr-cli
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/iac/vultr-cli/
|
||||
outputs:
|
||||
tag: ${{ steps.latest.outputs.tag }}
|
||||
version: ${{ steps.latest.outputs.version }}
|
||||
exists: ${{ steps.remotecheck.outputs.exists }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Ensure GitHub CLI & deps
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y gh jq rsync
|
||||
gh --version
|
||||
jq --version
|
||||
rsync --version | head -n1
|
||||
|
||||
- name: Resolve latest tag (semver)
|
||||
id: latest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TAG=$(./scripts/resolve_github_repo_release.sh "${GH_REPO}" '^v[0-9]+\.[0-9]+\.[0-9]+$' 'v*.*.*')
|
||||
VERSION=${TAG#v}
|
||||
|
||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Latest tag: $TAG (version: $VERSION)"
|
||||
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Check remote existing version dir
|
||||
id: remotecheck
|
||||
env:
|
||||
VERSION: ${{ steps.latest.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
REMOTE_DIR="${REMOTE_ROOT%/}/${VERSION}"
|
||||
if ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "test -d '${REMOTE_DIR}'"; then
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
echo "Remote already has ${REMOTE_DIR}, skip whole sync."
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Remote does not have ${REMOTE_DIR}, will sync."
|
||||
fi
|
||||
|
||||
sync-one:
|
||||
name: Sync ${{ matrix.asset_suffix }} for ${{ needs.prep.outputs.version }} (${{ matrix.vps_host }})
|
||||
needs: prep
|
||||
if: needs.prep.outputs.exists == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
asset_suffix:
|
||||
- "linux_amd64.tar.gz"
|
||||
- "macOS_arm64.tar.gz"
|
||||
env:
|
||||
GH_REPO: vultr/vultr-cli
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/iac/vultr-cli/
|
||||
TAG: ${{ needs.prep.outputs.tag }}
|
||||
VERSION: ${{ needs.prep.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Ensure GitHub CLI & deps
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y gh jq rsync
|
||||
gh --version
|
||||
|
||||
- name: Check asset exists via GitHub CLI
|
||||
id: has_asset
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ASSET="vultr_${TAG}_${{ matrix.asset_suffix }}"
|
||||
echo "Checking asset $ASSET for tag ${TAG}"
|
||||
if gh release view "${TAG}" --repo "${GH_REPO}" --json assets \
|
||||
| jq -r '.assets[].name' | grep -Fxq "$ASSET"; then
|
||||
echo "asset=$ASSET" >> "$GITHUB_OUTPUT"
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Asset $ASSET not found for ${TAG}, will skip."
|
||||
fi
|
||||
|
||||
- name: Download asset
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "releases/${VERSION}"
|
||||
gh release download "${TAG}" \
|
||||
--repo "${GH_REPO}" \
|
||||
--pattern "${{ steps.has_asset.outputs.asset }}" \
|
||||
--dir "releases/${VERSION}"
|
||||
|
||||
- name: Init SSH
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Rsync this asset to remote
|
||||
if: steps.has_asset.outputs.exists == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
REMOTE_DIR="${REMOTE_ROOT%/}/${VERSION}"
|
||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "mkdir -p '${REMOTE_DIR}'"
|
||||
echo "Rsync releases/${VERSION}/${{ steps.has_asset.outputs.asset }} -> ${VPS_HOST}:${REMOTE_DIR}/"
|
||||
rsync -av -e "ssh -i ~/.ssh/id_rsa" \
|
||||
"releases/${VERSION}/${{ steps.has_asset.outputs.asset }}" "${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 10) (${{ matrix.vps_host }})
|
||||
needs: [prep, sync-one]
|
||||
if: needs.prep.outputs.exists == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/iac/vultr-cli/
|
||||
steps:
|
||||
- name: Init SSH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Prune old versions on remote (keep 10)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" bash -lc '
|
||||
set -euo pipefail
|
||||
cd "'"${REMOTE_ROOT}"'" || exit 0
|
||||
keep=10
|
||||
mapfile -t all < <(ls -1 | grep -E "^[0-9]+\\.[0-9]+\\.[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
|
||||
'
|
||||
39
.github/workflows/sync-xray-core.yml
vendored
39
.github/workflows/sync-xray-core.yml
vendored
@ -15,14 +15,19 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
name: Resolve latest tag & remote check
|
||||
name: Resolve latest tag & remote check (${{ matrix.vps_host }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
GH_REPO: XTLS/Xray-core
|
||||
GH_TOKEN: ${{ github.token }} # 用内置 token,无需自建 PAT
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/xray-core
|
||||
outputs:
|
||||
tag: ${{ steps.latest.outputs.tag }}
|
||||
@ -43,19 +48,7 @@ jobs:
|
||||
id: latest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gh api -H "Accept: application/vnd.github+json" \
|
||||
"/repos/${GH_REPO}/releases?per_page=100" \
|
||||
| jq -r '.[].tag_name' \
|
||||
| grep -E '^v25(\.|$)' \
|
||||
| sort -V -r \
|
||||
| head -n 1 > /tmp/tag.txt
|
||||
|
||||
if [ ! -s /tmp/tag.txt ]; then
|
||||
echo "No v25.* tags found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG=$(cat /tmp/tag.txt)
|
||||
TAG=$(./scripts/resolve_github_repo_release.sh "${GH_REPO}" '^v25(\.|$)' 'v25.*')
|
||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||
echo "Latest tag: $TAG"
|
||||
|
||||
@ -82,20 +75,23 @@ jobs:
|
||||
fi
|
||||
|
||||
sync-one:
|
||||
name: Sync ${{ matrix.asset }} for ${{ needs.prep.outputs.tag }}
|
||||
name: Sync ${{ matrix.asset }} for ${{ needs.prep.outputs.tag }} (${{ matrix.vps_host }})
|
||||
needs: prep
|
||||
if: needs.prep.outputs.exists == 'false' # 远端已存在则整个矩阵跳过
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
asset: [ "Xray-linux-64.zip", "Xray-macos-64.zip", "Xray-windows-64.zip" ]
|
||||
env:
|
||||
GH_REPO: XTLS/Xray-core
|
||||
GH_TOKEN: ${{ github.token }} # 继续使用内置 token
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/xray-core
|
||||
TAG: ${{ needs.prep.outputs.tag }}
|
||||
steps:
|
||||
@ -152,14 +148,19 @@ jobs:
|
||||
"releases/${TAG}/${{ matrix.asset }}" "${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"
|
||||
|
||||
retention:
|
||||
name: Remote retention (keep latest 10 v25.*)
|
||||
name: Remote retention (keep latest 10 v25.*) (${{ matrix.vps_host }})
|
||||
needs: [prep, sync-one]
|
||||
if: needs.prep.outputs.exists == 'false' # 只有新增版本时才清理
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vps_host:
|
||||
- cn-homepage.svc.plus
|
||||
- global-homepage.svc.plus
|
||||
env:
|
||||
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
||||
RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
VPS_HOST: ${{ matrix.vps_host }}
|
||||
REMOTE_ROOT: /data/update-server/xray-core
|
||||
steps:
|
||||
- name: Init SSH
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,3 +22,6 @@
|
||||
.build-harness
|
||||
build-harness
|
||||
dist/bin/*
|
||||
|
||||
# Packaged Helm charts generated in-place during release work
|
||||
oci/charts/apps/*/charts/*.tgz
|
||||
|
||||
56
gitops/scripts/apisix-gateway/deploy-apisix-gateway.sh
Executable file
56
gitops/scripts/apisix-gateway/deploy-apisix-gateway.sh
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ingress_ip=$(hostname -I | awk '{print $1}')
|
||||
|
||||
cat > values.yaml <<EOF
|
||||
service:
|
||||
type: NodePort
|
||||
externalIPs:
|
||||
- ${ingress_ip}
|
||||
http:
|
||||
enabled: true
|
||||
servicePort: 80
|
||||
tls:
|
||||
servicePort: 443
|
||||
nodePort: 30443
|
||||
|
||||
# 仅部署网关数据面;不装 etcd、不装 ingress-controller
|
||||
etcd:
|
||||
enabled: false
|
||||
|
||||
ingress-controller:
|
||||
enabled: false
|
||||
|
||||
apisix:
|
||||
deployment:
|
||||
# standalone = 无 etcd,本地文件/ConfigMap 驱动;同时禁用 Admin API
|
||||
mode: standalone
|
||||
role: data_plane
|
||||
role_data_plane:
|
||||
# 需要时可用 yaml/json 作配置源;此处先保留 yaml
|
||||
config_provider: yaml
|
||||
|
||||
# 基本特性可按需开启
|
||||
ssl:
|
||||
enabled: true
|
||||
prometheus:
|
||||
enabled: true
|
||||
|
||||
# (可选加固)即便 Helm 仍创建了 Admin Service,standalone 下也不会有 Admin 监听;
|
||||
# 这里进一步把 Admin 访问白名单收紧,避免误触。
|
||||
admin:
|
||||
allow:
|
||||
ipList:
|
||||
- 127.0.0.1/32
|
||||
EOF
|
||||
|
||||
helm repo add apisix https://charts.apiseven.com || true
|
||||
helm repo update
|
||||
|
||||
kubectl get ns ingress >/dev/null 2>&1 || kubectl create ns ingress
|
||||
|
||||
# 只安装 APISIX 网关(无 etcd / 无 admin / 无 ingress-controller)
|
||||
helm upgrade --install apisix apisix/apisix \
|
||||
--namespace ingress \
|
||||
-f values.yaml
|
||||
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:
|
||||
@ -1,176 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# gitops/scripts/ingress-installer.sh
|
||||
set -euo pipefail
|
||||
|
||||
# ======================
|
||||
# Config & Defaults
|
||||
# ======================
|
||||
: "${NGINX_IC_IMAGE:=nginx/nginx-ingress:2.4.0}"
|
||||
: "${CERT_IMG:=registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407}"
|
||||
|
||||
# 这些是我们在构建离线 OCI 归档时写入的“内部引用名”(ref.name)
|
||||
# 若你的打包工作流改了它们,这里也要相应修改
|
||||
: "${OCI_NGINX_REF:=nginx-ingress-2.4.0}"
|
||||
: "${OCI_CERT_REF:=kube-webhook-certgen}"
|
||||
|
||||
: "${CHART_DIR:=./charts/nginx-ingress}"
|
||||
: "${NAMESPACE:=ingress}"
|
||||
: "${OCI_ARCHIVE:=images/oci-archive.tar}"
|
||||
: "${NERDCTL_TAR:=nerdctl.tar.gz}"
|
||||
|
||||
# 1st arg: Ingress 对外 IP(默认取本机第一个 IP)
|
||||
INGRESS_IP="${1:-$(hostname -I 2>/dev/null | awk '{print $1}')}"
|
||||
# 2nd arg: 节点标签(形如 "node-role=ingress")
|
||||
NODE_LABEL="${2:-}"
|
||||
|
||||
SUDO=""
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
SUDO="sudo"
|
||||
fi
|
||||
|
||||
log() { echo -e "$@"; }
|
||||
die() { echo "❌ $*" >&2; exit 1; }
|
||||
ok() { echo "✅ $*"; }
|
||||
warn() { echo "⚠️ $*"; }
|
||||
|
||||
have_cmd() { command -v "$1" &>/dev/null; }
|
||||
|
||||
# ======================
|
||||
# Nerdctl Install (wrapper+多平台)
|
||||
# ======================
|
||||
install_nerdctl() {
|
||||
if [ -f "${NERDCTL_TAR}" ]; then
|
||||
log "📦 安装 nerdctl(多平台 + wrapper)..."
|
||||
$SUDO tar xzf "${NERDCTL_TAR}" -C /usr/local/bin/
|
||||
$SUDO chmod +x /usr/local/bin/nerdctl || true
|
||||
else
|
||||
warn "未找到 ${NERDCTL_TAR},跳过解包(确保系统已有 nerdctl/ctr)。"
|
||||
fi
|
||||
}
|
||||
|
||||
# ======================
|
||||
# Import OCI images
|
||||
# ======================
|
||||
import_images_from_oci() {
|
||||
[ -f "${OCI_ARCHIVE}" ] || die "未找到 OCI 归档: ${OCI_ARCHIVE}"
|
||||
|
||||
log "📦 准备从 OCI 归档导入镜像: ${OCI_ARCHIVE}"
|
||||
|
||||
# 情况 A:Docker 环境
|
||||
if have_cmd docker && docker info &>/dev/null; then
|
||||
log "🔎 检测到 Docker 运行中。"
|
||||
if ! have_cmd skopeo; then
|
||||
die "检测到 Docker,但未安装 skopeo。Docker 无法直接导入 OCI Layout,请安装 skopeo 或在 containerd 环境执行。"
|
||||
fi
|
||||
log "🔁 使用 skopeo 将归档中的两个镜像导入 docker-daemon ..."
|
||||
# 必须显式指定 oci-archive 内部的 ref.name
|
||||
skopeo --insecure-policy copy --all "oci-archive:${OCI_ARCHIVE}:${OCI_NGINX_REF}" "docker-daemon:${NGINX_IC_IMAGE}"
|
||||
skopeo --insecure-policy copy --all "oci-archive:${OCI_ARCHIVE}:${OCI_CERT_REF}" "docker-daemon:${CERT_IMG}"
|
||||
ok "已导入到 Docker 本地镜像:${NGINX_IC_IMAGE}, ${CERT_IMG}"
|
||||
return
|
||||
fi
|
||||
|
||||
# 情况 B:K3s 的 containerd
|
||||
if [ -S /run/k3s/containerd/containerd.sock ]; then
|
||||
log "🔎 检测到 K3s containerd,使用 ctr 导入(含多架构)..."
|
||||
$SUDO ctr -n k8s.io images import --all-platforms "${OCI_ARCHIVE}"
|
||||
# retag 成 chart 会使用的镜像名
|
||||
$SUDO ctr -n k8s.io images tag "${OCI_NGINX_REF}" "${NGINX_IC_IMAGE}" || true
|
||||
$SUDO ctr -n k8s.io images tag "${OCI_CERT_REF}" "${CERT_IMG}" || true
|
||||
ok "已导入并完成 tag:${NGINX_IC_IMAGE}, ${CERT_IMG}"
|
||||
return
|
||||
fi
|
||||
|
||||
# 情况 C:通用 containerd
|
||||
if [ -S /run/containerd/containerd.sock ]; then
|
||||
log "🔎 检测到系统 containerd,使用 ctr 导入(含多架构)..."
|
||||
$SUDO ctr -n k8s.io images import --all-platforms "${OCI_ARCHIVE}"
|
||||
$SUDO ctr -n k8s.io images tag "${OCI_NGINX_REF}" "${NGINX_IC_IMAGE}" || true
|
||||
$SUDO ctr -n k8s.io images tag "${OCI_CERT_REF}" "${CERT_IMG}" || true
|
||||
ok "已导入并完成 tag:${NGINX_IC_IMAGE}, ${CERT_IMG}"
|
||||
return
|
||||
fi
|
||||
|
||||
die "未检测到可用的容器运行时(docker 或 containerd)。"
|
||||
}
|
||||
|
||||
# ======================
|
||||
# Kubernetes & Helm
|
||||
# ======================
|
||||
ensure_namespace() {
|
||||
log "📁 创建命名空间 ${NAMESPACE}(如已存在忽略)"
|
||||
kubectl create namespace "${NAMESPACE}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
generate_values() {
|
||||
log "🧾 生成 Helm values.yaml"
|
||||
cat > values.yaml <<EOF
|
||||
controller:
|
||||
ingressClass: nginx
|
||||
ingressClassResource:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
image:
|
||||
registry: docker.io
|
||||
image: nginx/nginx-ingress
|
||||
tag: "2.4.0"
|
||||
service:
|
||||
enabled: true
|
||||
type: NodePort
|
||||
externalIPs:
|
||||
- ${INGRESS_IP}
|
||||
nodePorts:
|
||||
http: 80
|
||||
https: 443
|
||||
EOF
|
||||
|
||||
if [[ -n "${NODE_LABEL}" ]]; then
|
||||
cat >> values.yaml <<EOF
|
||||
nodeSelector:
|
||||
${NODE_LABEL%%=*}: "${NODE_LABEL#*=}"
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
install_chart() {
|
||||
[ -d "${CHART_DIR}" ] || die "未找到 Chart 目录:${CHART_DIR}"
|
||||
log "🧭 使用本地 Chart 安装/升级 NGINX Ingress:${CHART_DIR}"
|
||||
helm upgrade --install nginx "${CHART_DIR}" \
|
||||
--namespace "${NAMESPACE}" -f values.yaml
|
||||
}
|
||||
|
||||
apply_configmap_tuning() {
|
||||
log "🛠️ 应用 ConfigMap 优化参数"
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: nginx-nginx-ingress
|
||||
namespace: ${NAMESPACE}
|
||||
data:
|
||||
proxy-connect-timeout: "10"
|
||||
proxy-read-timeout: "10"
|
||||
client-header-buffer-size: 64k
|
||||
client-body-buffer-size: 64k
|
||||
client-max-body-size: 1000m
|
||||
proxy-buffers: "8 32k"
|
||||
proxy-buffer-size: 32k
|
||||
EOF
|
||||
}
|
||||
|
||||
# ======================
|
||||
# Main
|
||||
# ======================
|
||||
log "🚀 Ingress 离线部署开始"
|
||||
log " Ingress IP: ${INGRESS_IP:-<auto>}"
|
||||
log " Namespace: ${NAMESPACE}"
|
||||
log " Chart Dir: ${CHART_DIR}"
|
||||
log " Images: ${NGINX_IC_IMAGE} , ${CERT_IMG}"
|
||||
|
||||
install_nerdctl
|
||||
import_images_from_oci
|
||||
ensure_namespace
|
||||
generate_values
|
||||
install_chart
|
||||
apply_configmap_tuning
|
||||
ok "离线安装完成,Ingress IP: ${INGRESS_IP}"
|
||||
98
gitops/scripts/kong-gateway/configure-example-app.sh
Executable file
98
gitops/scripts/kong-gateway/configure-example-app.sh
Executable file
@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
NODE_NAME=$(hostname)
|
||||
kubectl label nodes "${NODE_NAME}" ingress-node=true --overwrite
|
||||
|
||||
cat <<'YEOF' | kubectl apply -f -
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: GatewayClass
|
||||
metadata:
|
||||
name: kong
|
||||
annotations:
|
||||
konghq.com/gatewayclass-unmanaged: 'true'
|
||||
|
||||
spec:
|
||||
controllerName: konghq.com/kic-gateway-controller
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx-svc
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: demo-gateway
|
||||
namespace: default
|
||||
annotations:
|
||||
konghq.com/publish-service: kong/kong-gateway-proxy
|
||||
spec:
|
||||
gatewayClassName: kong
|
||||
listeners:
|
||||
- name: https
|
||||
port: 443
|
||||
protocol: HTTPS
|
||||
hostname: "example.com"
|
||||
tls:
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- name: example-tls
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: All
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: demo-route
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: demo-gateway
|
||||
namespace: default
|
||||
hostnames:
|
||||
- example.com
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: nginx-svc
|
||||
port: 80
|
||||
YEOF
|
||||
|
||||
EXTERNAL_IP=$(hostname -I | awk '{print $1}')
|
||||
curl -ksv https://example.com --resolve example.com:443:${EXTERNAL_IP}
|
||||
63
gitops/scripts/kong-gateway/deploy-kong-gateway.sh
Executable file
63
gitops/scripts/kong-gateway/deploy-kong-gateway.sh
Executable file
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Install Gateway API CRDs
|
||||
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml
|
||||
|
||||
# Setup Helm repository and values
|
||||
helm repo add kong https://charts.konghq.com
|
||||
helm repo update
|
||||
cat > kong-values.yaml <<'VEOF'
|
||||
kong:
|
||||
secretVolumes:
|
||||
- example-tls
|
||||
env:
|
||||
ssl_cert: /etc/secrets/example-tls/tls.crt
|
||||
ssl_cert_key: /etc/secrets/example-tls/tls.key
|
||||
VEOF
|
||||
|
||||
kubectl create ns kong || true
|
||||
|
||||
# Generate self-signed certificate for example.com
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-subj "/CN=example.com" \
|
||||
-keyout example.com.key \
|
||||
-out example.com.pem
|
||||
|
||||
kubectl create secret tls example-tls --cert=example.com.pem --key=example.com.key -n kong
|
||||
helm upgrade --install kong kong/ingress -n kong --create-namespace -f kong-values.yaml
|
||||
|
||||
# Expose Kong proxy via NodePort and external IP
|
||||
kubectl patch svc kong-gateway-proxy -n kong \
|
||||
--type='merge' \
|
||||
-p '{
|
||||
"spec": {
|
||||
"type": "NodePort",
|
||||
"ports": [
|
||||
{
|
||||
"port": 80,
|
||||
"targetPort": 8000,
|
||||
"protocol": "TCP",
|
||||
"name": "http",
|
||||
"nodePort": 30080
|
||||
},
|
||||
{
|
||||
"port": 443,
|
||||
"targetPort": 8443,
|
||||
"protocol": "TCP",
|
||||
"name": "https",
|
||||
"nodePort": 30443
|
||||
}
|
||||
]
|
||||
}
|
||||
}'
|
||||
|
||||
EXTERNAL_IP=$(hostname -I | awk '{print $1}')
|
||||
kubectl patch svc kong-gateway-proxy -n kong \
|
||||
--type='merge' \
|
||||
-p "{\"spec\": {\"externalIPs\": [\"${EXTERNAL_IP}\"]}}"
|
||||
|
||||
NODE_NAME=$(hostname)
|
||||
kubectl patch deployment kong-gateway -n kong \
|
||||
--type='merge' \
|
||||
-p "{\"spec\": {\"template\": {\"spec\": {\"nodeName\": \"${NODE_NAME}\"}}}}"
|
||||
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 }}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user