Compare commits

...

14 Commits

Author SHA1 Message Date
eball
751e69d20b cli: update ResolveOlaresName and CheckJWS to accept gateUrl parameter 2025-12-30 22:41:06 +08:00
berg
1a200ed17c system frontend: update market topic ids (#2351)
feat: update system frontend version
2025-12-30 21:17:53 +08:00
eball
48fdaa5481 daemon: enhance USB monitoring with serial filtering support (#2349)
* daemon: enhance USB monitoring with serial filtering support

* daemon: add check for USB devices with serial before mounting

* daemon: implement FilterBySerial function for USB device filtering
2025-12-30 21:17:15 +08:00
eball
570fe070c9 k3s: update eviction thresholds and image GC settings (#2348)
k3s: update eviction thresholds and image GC settings for improved resource management
2025-12-30 21:16:54 +08:00
lovehunter9
6b18bbd94d fix: files change usb watcher to retry and change sync reconnection to callback (#2342)
* fix: files change usb watcher to retry and change sync reconnection to callback

* fix: create folder and rsync chown to 1000
2025-12-30 21:15:34 +08:00
Yajing
c6836f9859 docs: update nav to reflect the latest changes (#2343) 2025-12-30 17:41:39 +08:00
yajing wang
288869d91d docs: update nav to reflect the latest changes 2025-12-29 20:55:06 +08:00
hysyeah
8ea8a0857e app-service: add helm upgrade timeout (#2339)
* fix: failed release upgrade

* fix: update appservice image tag to 0.4.71

* fix: helm upgrade do not use atomic param and allow upgrade failed release
2025-12-27 14:05:22 +08:00
eball
87674cc5d9 opa: update image validation to exclude alpine and mariadb images (#2337) 2025-12-27 14:04:31 +08:00
berg
11f556e9af system frontend, market backend: verify the update time when the app status is changed. (#2336)
feat: update system frontend version
2025-12-27 14:04:14 +08:00
simon
d2d3195fea download-server: modify ytdlp support domain (#2335)
download
2025-12-27 14:03:45 +08:00
hysyeah
ad3b138284 app-service: fix exposeport upgrade (#2334)
* fix: exposeport upgrade (#2333)

* update appservice tag to 0.4.70
2025-12-26 19:41:14 +08:00
eball
ff609db1aa tapr: change kvrocks to run as root by default (#2332)
* tapr: upgrade pod template and image for PGCluster reconciliation (#2213)

* tapr: upgrade pod template and image for PGCluster reconciliation

* fix(ci): specify working directory in github action for tapr (#2215)

---------

Co-authored-by: dkeven <82354774+dkeven@users.noreply.github.com>

* tapr: upgrade pod template and image for PGCluster reconciliation

* fix(kvrocks): update init container image and pull policy configuration (#2331)

* tapr: change kvrocks running as root by default

---------

Co-authored-by: dkeven <82354774+dkeven@users.noreply.github.com>
2025-12-26 19:40:48 +08:00
dkeven
43c6bff906 feat(cli): collect more logs for K8s resources (#2330) 2025-12-26 15:36:02 +08:00
31 changed files with 271 additions and 189 deletions

View File

@@ -317,7 +317,7 @@ spec:
chown -R 1000:1000 /uploadstemp && \
chown -R 1000:1000 /appdata
- name: olares-app-init
image: beclab/system-frontend:v1.6.32
image: beclab/system-frontend:v1.6.36
imagePullPolicy: IfNotPresent
command:
- /bin/sh

View File

@@ -5,17 +5,18 @@ import (
"compress/gzip"
"fmt"
"io"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"log"
"net"
"os"
"os/exec"
"path/filepath"
ctrl "sigs.k8s.io/controller-runtime"
"strings"
"time"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
ctrl "sigs.k8s.io/controller-runtime"
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/util"
"github.com/spf13/cobra"
@@ -242,7 +243,6 @@ func collectSystemdLogs(tw *tar.Writer, options *LogCollectOptions) error {
if err := cmd.Run(); err != nil {
logFile.Close()
return fmt.Errorf("failed to collect logs for %s: %v", service, err)
continue
}
logFile.Close()
@@ -375,43 +375,27 @@ func collectKubernetesLogs(tw *tar.Writer, options *LogCollectOptions) error {
}
}
cmd = exec.Command("kubectl", "describe", "pods", "--all-namespaces")
output, err = tryKubectlCommand(cmd, "describe pods", options)
if err != nil && !options.IgnoreKubeErrors {
return err
}
if err == nil {
header := &tar.Header{
Name: "pods-describe.txt",
Mode: 0644,
Size: int64(len(output)),
ModTime: time.Now(),
}
if err := tw.WriteHeader(header); err != nil {
return fmt.Errorf("failed to write pods description header: %v", err)
}
if _, err := tw.Write(output); err != nil {
return fmt.Errorf("failed to write pods description data: %v", err)
}
}
resourceTypes := []string{"node", "pod", "statefulset", "deployment", "replicaset", "service", "configmap"}
cmd = exec.Command("kubectl", "describe", "node")
output, err = tryKubectlCommand(cmd, "describe node", options)
if err != nil && !options.IgnoreKubeErrors {
return err
}
if err == nil {
header := &tar.Header{
Name: "node-describe.txt",
Mode: 0644,
Size: int64(len(output)),
ModTime: time.Now(),
for _, res := range resourceTypes {
cmd = exec.Command("kubectl", "describe", res, "--all-namespaces")
output, err = tryKubectlCommand(cmd, fmt.Sprintf("describe %s", res), options)
if err != nil && !options.IgnoreKubeErrors {
return err
}
if err := tw.WriteHeader(header); err != nil {
return fmt.Errorf("failed to write node description header: %v", err)
}
if _, err := tw.Write(output); err != nil {
return fmt.Errorf("failed to write node description data: %v", err)
if err == nil {
header := &tar.Header{
Name: fmt.Sprintf("%s-describe.txt", res),
Mode: 0644,
Size: int64(len(output)),
ModTime: time.Now(),
}
if err := tw.WriteHeader(header); err != nil {
return fmt.Errorf("failed to write %s description header: %v", res, err)
}
if _, err := tw.Write(output); err != nil {
return fmt.Errorf("failed to write %s description data: %v", res, err)
}
}
}

View File

@@ -195,13 +195,13 @@ func (g *GenerateK3sService) Execute(runtime connector.Runtime) error {
defaultKubeletArs := map[string]string{
"kube-reserved": "cpu=200m,memory=250Mi,ephemeral-storage=1Gi",
"system-reserved": "cpu=200m,memory=250Mi,ephemeral-storage=1Gi",
"eviction-hard": "memory.available<5%,nodefs.available<10%,imagefs.available<10%",
"eviction-hard": "memory.available<5%,nodefs.available<5%,imagefs.available<5%",
"config": "/etc/rancher/k3s/kubelet.config",
"containerd": container.DefaultContainerdCRISocket,
"cgroup-driver": "systemd",
"runtime-request-timeout": "5m",
"image-gc-high-threshold": "91",
"image-gc-low-threshold": "90",
"image-gc-high-threshold": "96",
"image-gc-low-threshold": "95",
"housekeeping_interval": "5s",
}
defaultKubeProxyArgs := map[string]string{

View File

@@ -296,8 +296,10 @@ func GetKubeletConfiguration(runtime connector.Runtime, kubeConf *common.KubeCon
"memory": "250Mi",
},
"evictionHard": map[string]string{
"memory.available": "5%",
"pid.available": "10%",
"memory.available": "5%",
"pid.available": "10%",
"nodefs.available": "5%",
"imagefs.available": "5%",
},
"evictionSoft": map[string]string{
"memory.available": "10%",
@@ -309,8 +311,8 @@ func GetKubeletConfiguration(runtime connector.Runtime, kubeConf *common.KubeCon
"evictionPressureTransitionPeriod": "30s",
"featureGates": FeatureGatesDefaultConfiguration,
"runtimeRequestTimeout": "5m",
"imageGCHighThresholdPercent": 91,
"imageGCLowThresholdPercent": 90,
"imageGCHighThresholdPercent": 96,
"imageGCLowThresholdPercent": 95,
}
if securityEnhancement {

View File

@@ -19,7 +19,6 @@ import (
)
var (
DIDGateURL = "https://did-gate-v3.bttcdn.com/1.0/name/"
DIDGateTimeout = 10 * time.Second
DIDCachePath = "/var/lib/olares"
)
@@ -90,7 +89,7 @@ type CheckJWSResult struct {
}
// resolveDID resolves a DID either from cache or from the DID gate
func ResolveOlaresName(olares_id string) (*didcore.ResolutionResult, error) {
func ResolveOlaresName(gateUrl, olares_id string) (*didcore.ResolutionResult, error) {
name := strings.Replace(olares_id, "@", ".", -1)
// Try to get from cache first
cached, err := getDB().Get([]byte(name), nil)
@@ -105,7 +104,7 @@ func ResolveOlaresName(olares_id string) (*didcore.ResolutionResult, error) {
client := &http.Client{
Timeout: DIDGateTimeout,
}
resp, err := client.Get(DIDGateURL + name)
resp, err := client.Get(gateUrl + name)
if err != nil {
return nil, fmt.Errorf("failed to fetch DID from gate: %w", err)
}
@@ -135,7 +134,7 @@ func ResolveOlaresName(olares_id string) (*didcore.ResolutionResult, error) {
}
// CheckJWS verifies a JWS and returns the terminus name, body and kid
func CheckJWS(jws string, duration int64) (*CheckJWSResult, error) {
func CheckJWS(gateUrl, jws string, duration int64) (*CheckJWSResult, error) {
var kid string
var name string
var timestamp int64
@@ -198,7 +197,7 @@ func CheckJWS(jws string, duration int64) (*CheckJWSResult, error) {
}
// Resolve DID
resolutionResult, err := ResolveOlaresName(name)
resolutionResult, err := ResolveOlaresName(gateUrl, name)
if err != nil {
return nil, fmt.Errorf("failed to resolve DID: %w", err)
}

View File

@@ -20,6 +20,12 @@ func NewUsbWatcher() *usbWatcher {
return w
}
var UsbSerialKey = struct{}{}
func WithSerial(ctx context.Context, serial string) context.Context {
return context.WithValue(ctx, UsbSerialKey, serial)
}
func (w *usbWatcher) Watch(ctx context.Context) {
retry := 1
devs, err := utils.DetectdUsbDevices(ctx)
@@ -55,6 +61,16 @@ func (w *usbWatcher) Watch(ctx context.Context) {
return
}
serial := ctx.Value(UsbSerialKey).(string)
if serial != "" {
klog.Info("mount usb device with serial, ", serial)
devs = utils.FilterArray(devs, utils.FilterBySerial(serial))
if len(devs) == 0 {
klog.Info("no usb device found with serial, ", serial)
return
}
}
mountedPath, err := utils.MountUsbDevice(ctx, commands.MOUNT_BASE_DIR, devs)
if err != nil {
klog.Error("mount usb error, ", err)
@@ -80,13 +96,13 @@ func (w *umountWatcher) Watch(ctx context.Context) {
}
func NewUsbMonitor(ctx context.Context) error {
return utils.MonitorUsbDevice(ctx, func(action string) error {
return utils.MonitorUsbDevice(ctx, func(action, serial string) error {
switch action {
case "add":
delay := time.NewTimer(2 * time.Second)
go func() {
<-delay.C
NewUsbWatcher().Watch(ctx)
NewUsbWatcher().Watch(WithSerial(ctx, serial))
}()
case "remove":
NewUmountWatcher().Watch(ctx)

View File

@@ -119,7 +119,7 @@ func DetectdHddDevices(ctx context.Context) (usbDevs []storageDevice, err error)
return detectdStorageDevices(ctx, "ata")
}
func MonitorUsbDevice(ctx context.Context, cb func(action string) error) error {
func MonitorUsbDevice(ctx context.Context, cb func(action, serial string) error) error {
filter := &usbmon.ActionFilter{Action: usbmon.ActionAll}
devs, err := usbmon.ListenFiltered(ctx, filter)
if err != nil {
@@ -137,8 +137,8 @@ func MonitorUsbDevice(ctx context.Context, cb func(action string) error) error {
fmt.Println("Path: " + dev.Path())
fmt.Println("Vendor: " + dev.Vendor())
if cb != nil {
err = cb(dev.Action())
if cb != nil && dev.Serial() != "" {
err = cb(dev.Action(), dev.Serial())
if err != nil {
klog.Error("usb action callback error, ", err, ", ", dev.Action())
}
@@ -197,6 +197,12 @@ func MountedHddPath(ctx context.Context) ([]string, error) {
return getMountedPath(hdds)
}
func FilterBySerial(serial string) func(dev storageDevice) bool {
return func(dev storageDevice) bool {
return dev.IDSerial == serial || dev.IDSerialShort == serial
}
}
func MountUsbDevice(ctx context.Context, mountBaseDir string, dev []storageDevice) (mountedPath []string, err error) {
mounter := mountutils.New("")
mountedList, err := mounter.List()

View File

@@ -19,7 +19,7 @@ func DetectdHddDevices(ctx context.Context) (usbDevs []storageDevice, err error)
return
}
func MonitorUsbDevice(ctx context.Context, cb func(action string) error) error {
func MonitorUsbDevice(ctx context.Context, cb func(action, id string) error) error {
klog.Warning("not implement")
return nil
}
@@ -72,3 +72,9 @@ func MountedPath(ctx context.Context) ([]mountedPath, error) {
klog.Warning("not implement")
return nil, nil
}
func FilterBySerial(serial string) func(dev storageDevice) bool {
return func(dev storageDevice) bool {
return dev.IDSerial == serial || dev.IDSerialShort == serial
}
}

11
daemon/pkg/utils/utils.go Normal file
View File

@@ -0,0 +1,11 @@
package utils
func FilterArray[T any](items []T, fn func(T) bool) []T {
var filtered []T
for _, item := range items {
if fn(item) {
filtered = append(filtered, item)
}
}
return filtered
}

View File

@@ -6,7 +6,7 @@ const side = {
text: "What is Olares",
link: "/manual/overview",
items: [
{ text: "Compare Olares and NAS", link: "/manual/olares-vs-nas" },
// { text: "Compare Olares and NAS", link: "/manual/olares-vs-nas" },
{ text: "Help and support", link: "/manual/help/request-technical-support"}
// collapsed: true,
// items: [
@@ -468,10 +468,10 @@ const side = {
text: "Steam",
link: "/use-cases/stream-game",
},
{
text: "Redroid",
link: "/use-cases/host-cloud-android",
},
// {
// text: "Redroid",
// link: "/use-cases/host-cloud-android",
// },
{
text: "Windows",
link: "/use-cases/windows",

View File

@@ -8,7 +8,7 @@ const side = {
items: [
// { text: "应用场景", link: "/zh/manual/why-olares" },
//{ text: "功能对比", link: "/zh/manual/feature-overview" },
{ text: "比较 Olares 和 NAS", link: "/zh/manual/olares-vs-nas" },
// { text: "比较 Olares 和 NAS", link: "/zh/manual/olares-vs-nas" },
{text: "帮助与支持", link: "/zh/manual/help/request-technical-support",}
// collapsed: true,
// items: [
@@ -425,7 +425,7 @@ const side = {
],
"/zh/use-cases/": [
{
text: "Tutorials & use cases",
text: "应用示例",
link: "/zh/use-cases/",
items: [
{
@@ -471,10 +471,10 @@ const side = {
text: "Steam",
link: "/zh/use-cases/stream-game",
},
{
text: "Redroid",
link: "/zh/use-cases/host-cloud-android",
},
// {
// text: "Redroid",
// link: "/zh/use-cases/host-cloud-android",
// },
],
},
],

View File

@@ -16,7 +16,6 @@ From running AI models to building seamless workflows across your self-hosted se
{ title: 'Ollama', link: './ollama.html', tags: ['AI']},
{ title: 'Jellyfin', link: './stream-media.html', tags: ['Entertainment']},
{ title: 'Steam', link: './stream-game.html', tags: ['Entertainment']},
{ title: 'Redroid', link: './host-cloud-android.html', tags: ['Virtual Machine']},
{ title: 'Windows', link: './windows.html', tags: ['Virtual Machine']},
{ title: 'DeerFlow', link: './host-cloud-android.html', tags: ['AI']},
{ title: 'ACE-Step', link: './ace-step.html', tags: ['AI']},

View File

@@ -2,9 +2,9 @@
description: 了解 Olares 在 AI 流程、创意工具和自托管应用中的实际用例,充分释放 Olares 的潜力。
---
# 使用场景与教程
# 应用示例
本节聚焦于**真实场景**,帮助你充分挖掘 Olares 的强大功能。 从运行 AI 模型到在自托管服务间构建无缝工作流,这些动手教程将指导你完成具体任务,并利用已安装的应用实现完整、实用的解决方案。
本节聚焦于真实场景,帮助你充分挖掘 Olares 的强大功能。 从运行 AI 模型到在自托管服务间构建无缝工作流,这些动手教程将指导你完成具体任务,并利用已安装的应用实现完整、实用的解决方案。
<FilterableList :items="[
{ title: 'Stable Diffusion', link: './stable-diffusion.html', tags: ['AI'] },
@@ -15,5 +15,4 @@ description: 了解 Olares 在 AI 流程、创意工具和自托管应用中的
{ title: 'Ollama', link: './ollama.html', tags: ['AI'] },
{ title: 'Jellyfin', link: './stream-media.html', tags: ['娱乐'] },
{ title: 'Steam', link: './stream-game.html', tags: ['娱乐'] },
{ title: 'Redroid', link: './host-cloud-android.html', tags: ['虚拟机'] },
]" />

View File

@@ -170,7 +170,7 @@ spec:
priorityClassName: "system-cluster-critical"
containers:
- name: app-service
image: beclab/app-service:0.4.69
image: beclab/app-service:0.4.72
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 0

View File

@@ -146,6 +146,16 @@ func (h *upgradeHandlerHelper) setAndEncodingAppCofnig(prevCfg *appcfg.Applicati
}
}
}
prevPortsMap := apputils.BuildPrevPortsMap(prevCfg)
// Set expose ports for upgrade, preserving existing ports with same name
err := apputils.SetExposePorts(context.TODO(), h.appConfig, prevPortsMap)
if err != nil {
klog.Errorf("set expose ports failed %v", err)
return "", err
}
encoding, err := json.Marshal(h.appConfig)
if err != nil {
klog.Errorf("Failed to marshal app config err=%v", err)

View File

@@ -2,7 +2,6 @@ package appinstaller
import (
"encoding/json"
"fmt"
"time"
appv1alpha1 "github.com/beclab/Olares/framework/app-service/api/app.bytetrade.io/v1alpha1"
@@ -12,7 +11,6 @@ import (
"github.com/beclab/Olares/framework/app-service/pkg/helm"
"github.com/beclab/Olares/framework/app-service/pkg/users/userspace"
apputils "github.com/beclab/Olares/framework/app-service/pkg/utils/app"
helmrelease "helm.sh/helm/v3/pkg/release"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -23,15 +21,7 @@ import (
// Upgrade do a upgrade operation for release.
func (h *HelmOps) Upgrade() error {
status, err := h.status()
if err != nil {
klog.Errorf("get release status failed %v", err)
return err
}
if status.Info.Status == helmrelease.StatusDeployed {
return h.upgrade()
}
return fmt.Errorf("cannot upgrade release %s/%s, current state is %s", h.app.Namespace, h.app.AppName, status.Info.Status)
return h.upgrade()
}
func (h *HelmOps) upgrade() error {

View File

@@ -13,6 +13,7 @@ import (
"github.com/beclab/Olares/framework/app-service/pkg/appinstaller/versioned"
"github.com/beclab/Olares/framework/app-service/pkg/constants"
"github.com/beclab/Olares/framework/app-service/pkg/errcode"
apputils "github.com/beclab/Olares/framework/app-service/pkg/utils/app"
"github.com/pkg/errors"
"k8s.io/klog/v2"
@@ -59,12 +60,25 @@ func (p *InstallingApp) Exec(ctx context.Context) (StatefulInProgressApp, error)
klog.Errorf("get kube config failed %v", err)
return nil, err
}
err = setExposePorts(ctx, appCfg)
err = apputils.SetExposePorts(ctx, appCfg, nil)
if err != nil {
klog.Errorf("set expose ports failed %v", err)
return nil, err
}
updatedConfig, err := json.Marshal(appCfg)
if err != nil {
klog.Errorf("marshal appConfig failed %v", err)
return nil, err
}
managerCopy := p.manager.DeepCopy()
managerCopy.Spec.Config = string(updatedConfig)
err = p.client.Patch(ctx, managerCopy, client.MergeFrom(p.manager))
if err != nil {
klog.Errorf("update ApplicationManager config failed %v", err)
return nil, err
}
opCtx, cancel := context.WithCancel(context.Background())
ops, err := versioned.NewHelmOps(opCtx, kubeConfig, appCfg, token,

View File

@@ -169,6 +169,14 @@ func (p *UpgradingApp) exec(ctx context.Context) error {
klog.Errorf("get app config failed %v", err)
return err
}
var cfg *appcfg.ApplicationConfig
err = json.Unmarshal([]byte(p.manager.Spec.Config), &cfg)
if err != nil {
klog.Errorf("unmarshal to appConfig failed %v", err)
return err
}
appConfig.Ports = cfg.Ports
} else {
_, err = apputils.GetIndexAndDownloadChart(ctx, &apputils.ConfigOptions{
App: p.manager.Spec.AppName,

View File

@@ -6,9 +6,6 @@ import (
appv1alpha1 "github.com/beclab/Olares/framework/app-service/api/app.bytetrade.io/v1alpha1"
"github.com/beclab/Olares/framework/app-service/pkg/apiserver/api"
"github.com/beclab/Olares/framework/app-service/pkg/appcfg"
"github.com/beclab/Olares/framework/app-service/pkg/utils"
"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
@@ -17,7 +14,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -25,96 +21,6 @@ import (
const suspendAnnotation = "bytetrade.io/suspend-by"
const suspendCauseAnnotation = "bytetrade.io/suspend-cause"
type portKey struct {
port int32
protocol string
}
func setExposePorts(ctx context.Context, appConfig *appcfg.ApplicationConfig) error {
existPorts := make(map[portKey]struct{})
client, err := utils.GetClient()
if err != nil {
return err
}
apps, err := client.AppV1alpha1().Applications().List(ctx, metav1.ListOptions{})
if err != nil {
return err
}
for _, app := range apps.Items {
for _, p := range app.Spec.Ports {
protos := []string{p.Protocol}
if p.Protocol == "" {
protos = []string{"tcp", "udp"}
}
for _, proto := range protos {
key := portKey{
port: p.ExposePort,
protocol: proto,
}
existPorts[key] = struct{}{}
}
}
}
klog.Infof("existPorts: %v", existPorts)
for i := range appConfig.Ports {
port := &appConfig.Ports[i]
if port.ExposePort == 0 {
var exposePort int32
protos := []string{port.Protocol}
if port.Protocol == "" {
protos = []string{"tcp", "udp"}
}
for i := 0; i < 5; i++ {
exposePort, err = genPort(protos)
if err != nil {
continue
}
for _, proto := range protos {
key := portKey{port: exposePort, protocol: proto}
if _, ok := existPorts[key]; !ok && err == nil {
break
}
}
}
for _, proto := range protos {
key := portKey{port: exposePort, protocol: proto}
if _, ok := existPorts[key]; ok || err != nil {
return fmt.Errorf("%d port is not available", key.port)
}
existPorts[key] = struct{}{}
port.ExposePort = exposePort
}
}
}
// add exposePort to tailscale acls
for i := range appConfig.Ports {
if appConfig.Ports[i].AddToTailscaleAcl {
appConfig.TailScale.ACLs = append(appConfig.TailScale.ACLs, appv1alpha1.ACL{
Action: "accept",
Src: []string{"*"},
Proto: appConfig.Ports[i].Protocol,
Dst: []string{fmt.Sprintf("*:%d", appConfig.Ports[i].ExposePort)},
})
}
}
klog.Infof("appConfig.TailScale: %v", appConfig.TailScale)
return nil
}
func genPort(protos []string) (int32, error) {
exposePort := int32(rand.IntnRange(46800, 50000))
for _, proto := range protos {
if !utils.IsPortAvailable(proto, int(exposePort)) {
return 0, fmt.Errorf("failed to allocate an available port after 5 attempts")
}
}
return exposePort, nil
}
func suspendOrResumeApp(ctx context.Context, cli client.Client, am *appv1alpha1.ApplicationManager, replicas int32) error {
suspend := func(list client.ObjectList) error {
namespace := am.Spec.AppNamespace

View File

@@ -87,7 +87,8 @@ func UpgradeCharts(ctx context.Context, actionConfig *action.Configuration, sett
client.Namespace = namespace
client.Timeout = 300 * time.Second
client.Recreate = false
client.Atomic = true
// Do not use Atomic, this could cause helm wait all resource ready.
//client.Atomic = true
if reuseValue {
client.ReuseValues = true
}

View File

@@ -35,6 +35,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/util/retry"
@@ -1094,3 +1095,118 @@ func GetRawAppName(AppName, rawAppName string) string {
return rawAppName
}
type portKey struct {
port int32
protocol string
}
func genPort(protos []string) (int32, error) {
exposePort := int32(rand.IntnRange(46800, 50000))
for _, proto := range protos {
if !utils.IsPortAvailable(proto, int(exposePort)) {
return 0, fmt.Errorf("failed to allocate an available port after 5 attempts")
}
}
return exposePort, nil
}
// SetExposePorts sets expose ports for app config.
func SetExposePorts(ctx context.Context, appConfig *appcfg.ApplicationConfig, prevPortsMap map[string]int32) error {
existPorts := make(map[portKey]struct{})
client, err := utils.GetClient()
if err != nil {
return err
}
apps, err := client.AppV1alpha1().Applications().List(ctx, metav1.ListOptions{})
if err != nil {
return err
}
for _, app := range apps.Items {
for _, p := range app.Spec.Ports {
protos := []string{p.Protocol}
if p.Protocol == "" {
protos = []string{"tcp", "udp"}
}
for _, proto := range protos {
key := portKey{
port: p.ExposePort,
protocol: proto,
}
existPorts[key] = struct{}{}
}
}
}
klog.Infof("existPorts: %v", existPorts)
for i := range appConfig.Ports {
port := &appConfig.Ports[i]
// For upgrade: if port with same name exists in prevPortsMap, preserve its ExposePort
if prevPortsMap != nil && port.Name != "" {
if prevExposePort, exists := prevPortsMap[port.Name]; exists && prevExposePort != 0 {
klog.Infof("preserving ExposePort %d for port %s from previous config", prevExposePort, port.Name)
port.ExposePort = prevExposePort
continue
}
}
if port.ExposePort == 0 {
var exposePort int32
protos := []string{port.Protocol}
if port.Protocol == "" {
protos = []string{"tcp", "udp"}
}
for i := 0; i < 5; i++ {
exposePort, err = genPort(protos)
if err != nil {
continue
}
for _, proto := range protos {
key := portKey{port: exposePort, protocol: proto}
if _, ok := existPorts[key]; !ok && err == nil {
break
}
}
}
for _, proto := range protos {
key := portKey{port: exposePort, protocol: proto}
if _, ok := existPorts[key]; ok || err != nil {
return fmt.Errorf("%d port is not available", key.port)
}
existPorts[key] = struct{}{}
port.ExposePort = exposePort
}
}
}
// add exposePort to tailscale acls
for i := range appConfig.Ports {
if appConfig.Ports[i].AddToTailscaleAcl {
appConfig.TailScale.ACLs = append(appConfig.TailScale.ACLs, v1alpha1.ACL{
Action: "accept",
Src: []string{"*"},
Proto: appConfig.Ports[i].Protocol,
Dst: []string{fmt.Sprintf("*:%d", appConfig.Ports[i].ExposePort)},
})
}
}
klog.Infof("appConfig.TailScale: %v", appConfig.TailScale)
return nil
}
// BuildPrevPortsMap builds a map of port name -> expose port from previous config.
func BuildPrevPortsMap(prevConfig *appcfg.ApplicationConfig) map[string]int32 {
if prevConfig == nil {
return nil
}
m := make(map[string]int32)
for _, p := range prevConfig.Ports {
if p.Name != "" && p.ExposePort != 0 {
m[p.Name] = p.ExposePort
}
}
return m
}

View File

@@ -180,7 +180,7 @@ spec:
memory: 300Mi
- name: download-server
image: "beclab/download-server:v0.1.16"
image: "beclab/download-server:v0.1.17"
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 0

View File

@@ -210,7 +210,7 @@ spec:
command:
- /samba_share
- name: files
image: beclab/files-server:v0.2.142
image: beclab/files-server:v0.2.144
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: true

View File

@@ -140,7 +140,7 @@ spec:
name: check-chart-repo
containers:
- name: appstore-backend
image: beclab/market-backend:v0.6.13
image: beclab/market-backend:v0.6.15
imagePullPolicy: IfNotPresent
ports:
- containerPort: 81

View File

@@ -248,7 +248,7 @@ spec:
containers:
- name: seafile-server
image: beclab/pg_seafile_server:v0.0.16
image: beclab/pg_seafile_server:v0.0.17
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8082

View File

@@ -251,6 +251,8 @@ data:
not startswith(image, "ghcr.io/coder/coder:v2.19.0")
not startswith(image, "apecloud/")
not startswith(image, "kldtks/")
not startswith(image, "alpine:")
not startswith(image, "mariadb:")
}
is_root_user(ctx) if {

View File

@@ -3,7 +3,7 @@ target: prebuilt
output:
containers:
-
name: beclab/kvrocks:0.1.1
name: beclab/kvrocks:0.1.2

View File

@@ -57,7 +57,7 @@ spec:
path: '{{ $dbbackup_rootpath }}/pg_backup'
containers:
- name: operator-api
image: beclab/middleware-operator:0.2.29
image: beclab/middleware-operator:0.2.30
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080

View File

@@ -64,7 +64,7 @@ spec:
kvrocks:
owner: system
backupStorage: '{{ $redix_backuppath }}/kvrocks_backup'
image: beclab/kvrocks:0.1.1
image: beclab/kvrocks:0.1.2
imagePullPolicy: IfNotPresent
password:
valueFrom:

View File

@@ -64,6 +64,19 @@ func GetKVRocksDefineByUser(ctx context.Context, client *kubernetes.Clientset,
sts.Namespace = namespace
sts.Name = kvrocksDef.Name
for i, c := range sts.Spec.Template.Spec.InitContainers {
if c.Name == "init-kvrocks-cfg" {
ptrC := &sts.Spec.Template.Spec.InitContainers[i]
if kvrocksDef.Spec.KVRocks.Image != "" {
ptrC.Image = kvrocksDef.Spec.KVRocks.Image
}
if kvrocksDef.Spec.KVRocks.ImagePullPolicy != "" {
ptrC.ImagePullPolicy = kvrocksDef.Spec.KVRocks.ImagePullPolicy
}
}
}
for i, c := range sts.Spec.Template.Spec.Containers {
if c.Name == "kvrocks" {
ptrC := &sts.Spec.Template.Spec.Containers[i]

View File

@@ -12,7 +12,7 @@ import (
const (
DefaultKVRocksName = "kvrocks"
DefaultKVRocksImage = "beclab/kvrocks:0.1.1"
DefaultKVRocksImage = "beclab/kvrocks:0.1.2"
KVRocksVolumeName = "kvrdata"
KVRocksBackupVolumeName = "kvrbackup"
KVRocksBackupDir = "/backup"