Files
zeekay 3b9ae0d2ed feat: add Cloud CRD — manage bootnode multi-brand Web3 platform
8th CRD: Cloud (shortName: cloud) manages the bootnode platform:
- Multi-brand support (hanzo, lux, zoo, pars) with per-brand Ingress
- Shared API Deployment + per-brand Web Deployments
- HPA with aggressive scale-up, conservative scale-down
- KMS secret integration for database credentials
- Per-brand IAM config (hanzo.id, lux.id, zoo.id, pars.id)

Cloud controller creates:
- 1 API Deployment (shared, 3+ replicas, /health probes)
- N Web Deployments (per brand, NEXT_PUBLIC_BRAND env)
- 3N Ingresses (web3.{domain}, api.web3.{domain}, ws.web3.{domain})
- HPA for API + each web deployment
- PDB for API high availability

Network CRD updated to compose Cloud as child resource.

Total: 8 CRDs, 8 controllers, 3 protocol drivers, 7,417 lines Go
2026-03-03 07:03:45 -08:00

176 lines
5.3 KiB
Go

package main
import (
"crypto/tls"
"flag"
"os"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"
v1alpha1 "github.com/hanzoai/nchain/api/v1alpha1"
"github.com/hanzoai/nchain/internal/controller"
)
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(v1alpha1.AddToScheme(scheme))
}
func main() {
var metricsAddr string
var enableLeaderElection bool
var probeAddr string
var secureMetrics bool
var enableHTTP2 bool
var tlsOpts []func(*tls.Config)
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager.")
flag.BoolVar(&secureMetrics, "metrics-secure", true,
"If set, the metrics endpoint is served securely via HTTPS.")
flag.BoolVar(&enableHTTP2, "enable-http2", false,
"If set, HTTP/2 will be enabled for the metrics and webhook servers.")
opts := zap.Options{Development: true}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
if !enableHTTP2 {
tlsOpts = append(tlsOpts, func(c *tls.Config) {
setupLog.Info("Disabling HTTP/2")
c.NextProtos = []string{"http/1.1"}
})
}
webhookServer := webhook.NewServer(webhook.Options{TLSOpts: tlsOpts})
metricsServerOptions := metricsserver.Options{
BindAddress: metricsAddr,
SecureServing: secureMetrics,
TLSOpts: tlsOpts,
}
if secureMetrics {
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Metrics: metricsServerOptions,
WebhookServer: webhookServer,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "nchain.hanzo.ai",
})
if err != nil {
setupLog.Error(err, "Failed to start manager")
os.Exit(1)
}
// Register all controllers.
if err := (&controller.NodeClusterReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("NodeCluster"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "NodeCluster")
os.Exit(1)
}
if err := (&controller.ChainReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("Chain"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Chain")
os.Exit(1)
}
if err := (&controller.IndexerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("Indexer"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Indexer")
os.Exit(1)
}
if err := (&controller.ExplorerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("Explorer"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Explorer")
os.Exit(1)
}
if err := (&controller.BridgeReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("Bridge"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Bridge")
os.Exit(1)
}
if err := (&controller.GatewayReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("Gateway"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Gateway")
os.Exit(1)
}
if err := (&controller.NetworkReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("Network"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Network")
os.Exit(1)
}
if err := (&controller.CloudReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("Cloud"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Cloud")
os.Exit(1)
}
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "Failed to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
setupLog.Error(err, "Failed to set up ready check")
os.Exit(1)
}
setupLog.Info("Starting nchain operator")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "Failed to run manager")
os.Exit(1)
}
}