diff --git a/apps-gx10/fc-aistation/certificate-aistation-web-tls.json b/apps-gx10/fc-aistation/certificate-aistation-web-tls.json new file mode 100644 index 0000000..22eb47c --- /dev/null +++ b/apps-gx10/fc-aistation/certificate-aistation-web-tls.json @@ -0,0 +1,18 @@ +{ + "apiVersion": "cert-manager.io/v1", + "kind": "Certificate", + "metadata": { + "name": "aistation-web-tls", + "namespace": "fc-aistation" + }, + "spec": { + "dnsNames": [ + "aistation.iamworkin.lan" + ], + "issuerRef": { + "kind": "ClusterIssuer", + "name": "step-ca-acme" + }, + "secretName": "aistation-web-tls" + } +} diff --git a/apps-gx10/fc-aistation/configmap-aistation-web-config.json b/apps-gx10/fc-aistation/configmap-aistation-web-config.json new file mode 100644 index 0000000..2e09cd8 --- /dev/null +++ b/apps-gx10/fc-aistation/configmap-aistation-web-config.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:5000", + "AiStation__Appliance__FallbackEdition": "gx10", + "FLOWERCORE_AISTATION_EDITION": "gx10", + "FlowerCore__AgentZero__Enabled": "false", + "FlowerCore__DataDirectory": "/data", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/aistation.db", + "FlowerCore__Database__Provider": "Sqlite", + "FlowerCore__Editions__ProfileDirectory": "/app/editions", + "FlowerCore__Ollama__BaseUrl": "http://10.0.57.201:11434", + "FlowerCore__Operator__Enabled": "true", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.AiStation" + }, + "kind": "ConfigMap", + "metadata": { + "labels": { + "app.kubernetes.io/name": "aistation-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "aistation-web-config", + "namespace": "fc-aistation" + } +} diff --git a/apps-gx10/fc-aistation/deployment-aistation-web.json b/apps-gx10/fc-aistation/deployment-aistation-web.json new file mode 100644 index 0000000..ca43887 --- /dev/null +++ b/apps-gx10/fc-aistation/deployment-aistation-web.json @@ -0,0 +1,111 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "aistation-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "aistation-web", + "namespace": "fc-aistation" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "aistation-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-06-16T14:00:18-05:00", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "5000", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "aistation-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "aistation-web-config" + } + } + ], + "image": "localhost/fc-aistation-web:v20260616-ai6-gx10-websurface-a8a3e9d-2f9f89e", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "aistation-web", + "ports": [ + { + "containerPort": 5000, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "httpGet": { + "path": "/healthz", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "nodeSelector": { + "kubernetes.io/arch": "arm64" + }, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "aistation-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-aistation/ingressroute-aistation-web.json b/apps-gx10/fc-aistation/ingressroute-aistation-web.json new file mode 100644 index 0000000..d95cb6c --- /dev/null +++ b/apps-gx10/fc-aistation/ingressroute-aistation-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "aistation-web", + "namespace": "fc-aistation" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`aistation.iamworkin.lan`)", + "services": [ + { + "name": "aistation-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "aistation-web-tls" + } + } +} diff --git a/apps-gx10/fc-aistation/service-aistation-web.json b/apps-gx10/fc-aistation/service-aistation-web.json new file mode 100644 index 0000000..975c47f --- /dev/null +++ b/apps-gx10/fc-aistation/service-aistation-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "aistation-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "aistation-web", + "namespace": "fc-aistation" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 5000 + } + ], + "selector": { + "app.kubernetes.io/name": "aistation-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-chat/configmap-chat-web-config.json b/apps-gx10/fc-chat/configmap-chat-web-config.json new file mode 100644 index 0000000..47daac8 --- /dev/null +++ b/apps-gx10/fc-chat/configmap-chat-web-config.json @@ -0,0 +1,54 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:8080", + "ChatOptions__BehaviorRuleEngine__FallbackOllamaBaseUrl": "http://10.0.57.201:11434", + "ChatOptions__BehaviorRuleEngine__ModelName": "gemma3:4b", + "ChatOptions__BehaviorRuleEngine__OllamaBaseUrl": "http://10.0.57.201:11434", + "FlowerCore__AI__DefaultModelName": "gemma3:12b", + "FlowerCore__AI__Helpdesk__SentimentEscalation__Enabled": "true", + "FlowerCore__AI__IrcBridge__AllowActionExecution": "false", + "FlowerCore__AI__IrcBridge__DefaultProfileSlug": "it-helpdesk", + "FlowerCore__AI__IrcBridge__Enabled": "true", + "FlowerCore__AI__IrcBridge__MentionProfileSlug": "it-helpdesk", + "FlowerCore__AI__IrcBridge__MentionReactiveMode": "mentions-only", + "FlowerCore__AI__Memory__EmbeddingModel": "nomic-embed-text", + "FlowerCore__AI__Memory__EnableSharedIndexingBackfill": "true", + "FlowerCore__AI__Memory__SharedIndexingDatabasePath": "/data/chat-memory-index.db", + "FlowerCore__AI__Memory__UseOllamaEmbeddings": "true", + "FlowerCore__AI__Memory__UseSharedIndexingAdapter": "true", + "FlowerCore__AI__OllamaBaseUrl": "http://10.0.57.201:11434", + "FlowerCore__AI__Skills__Intranet__IntranetBaseUrl": "http://intranet-web.intranet.svc.cluster.local", + "FlowerCore__AI__Skills__Intranet__PublicBaseUrl": "https://intranet.iamworkin.lan", + "FlowerCore__AI__Skills__Intranet__SearchBaseUrl": "https://intranet.iamworkin.lan", + "FlowerCore__AI__Skills__Library__LibraryApiUrl": "http://library-web.fc-library.svc.cluster.local", + "FlowerCore__AI__Skills__Print__PrintMcpBaseUrl": "http://10.0.57.16:5200", + "FlowerCore__AI__Skills__Retail__RetailApiUrl": "http://retail-web.fc-retail.svc.cluster.local", + "FlowerCore__AI__Voice__OutputRoot": "/data/audio", + "FlowerCore__AI__Voice__Piper__Host": "10.0.57.17", + "FlowerCore__AI__Voice__Piper__Port": "10400", + "FlowerCore__AI__Voice__RetentionDays": "30", + "FlowerCore__Anthropic__BaseUrl": "https://api.anthropic.com", + "FlowerCore__Anthropic__CheapModel": "claude-haiku-4-5-20251001", + "FlowerCore__Anthropic__DeepModel": "claude-opus-4-7", + "FlowerCore__Anthropic__DefaultModel": "claude-sonnet-4-6", + "FlowerCore__Anthropic__Enabled": "false", + "FlowerCore__Auth__Enabled": "false", + "FlowerCore__Auth__Oidc__Audience": "chat", + "FlowerCore__Auth__Oidc__Authority": "https://id.iamworkin.lan/application/o/chat/", + "FlowerCore__Auth__Oidc__ClientId": "chat", + "FlowerCore__Auth__Oidc__Enabled": "true", + "FlowerCore__Budget__ResponseCacheEnabled": "true", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/chat.db", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.Chat" + }, + "kind": "ConfigMap", + "metadata": { + "name": "chat-web-config", + "namespace": "fc-chat" + } +} diff --git a/apps-gx10/fc-chat/deployment-chat-web.json b/apps-gx10/fc-chat/deployment-chat-web.json new file mode 100644 index 0000000..dd23cc5 --- /dev/null +++ b/apps-gx10/fc-chat/deployment-chat-web.json @@ -0,0 +1,159 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "chat-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "chat-web", + "namespace": "fc-chat" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "chat-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "fc.flowercore.io/healthz-anon": "true", + "fc.flowercore.io/probe-path": "/healthz", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "chat-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "FlowerCore__Auth__Oidc__Authority", + "valueFrom": { + "secretKeyRef": { + "key": "issuer_url", + "name": "chat-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientId", + "valueFrom": { + "secretKeyRef": { + "key": "client_id", + "name": "chat-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientSecret", + "valueFrom": { + "secretKeyRef": { + "key": "client_secret", + "name": "chat-oidc-client", + "optional": true + } + } + } + ], + "envFrom": [ + { + "configMapRef": { + "name": "chat-web-config" + } + }, + { + "secretRef": { + "name": "chat-web-secret", + "optional": true + } + } + ], + "image": "localhost/fc-chat-web:v20260616-chat-md-a812a81", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "chat-web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "httpGet": { + "path": "/healthz", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "chat-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-chat/ingressroute-chat-web-public.json b/apps-gx10/fc-chat/ingressroute-chat-web-public.json new file mode 100644 index 0000000..72b3db4 --- /dev/null +++ b/apps-gx10/fc-chat/ingressroute-chat-web-public.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "chat-web-public", + "namespace": "fc-chat" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`chat.flowercore.io`) && (Path(`/`) || Path(`/chat`) || PathPrefix(`/_blazor`) || PathPrefix(`/_framework`) || PathPrefix(`/_content`) || PathPrefix(`/avatars`) || PathPrefix(`/css`) || PathPrefix(`/js`) || PathPrefix(`/favicon`) || PathPrefix(`/chathub`)) && (Method(`GET`) || Method(`HEAD`) || Method(`POST`) || Method(`OPTIONS`))", + "priority": 100, + "services": [ + { + "name": "chat-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "cf-origin-flowercore-io" + } + } +} diff --git a/apps-gx10/fc-chat/ingressroute-chat-web.json b/apps-gx10/fc-chat/ingressroute-chat-web.json new file mode 100644 index 0000000..3408ebd --- /dev/null +++ b/apps-gx10/fc-chat/ingressroute-chat-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "chat-web", + "namespace": "fc-chat" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`chat.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "chat-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "chat-web-tls" + } + } +} diff --git a/apps-gx10/fc-chat/service-chat-web.json b/apps-gx10/fc-chat/service-chat-web.json new file mode 100644 index 0000000..6070a75 --- /dev/null +++ b/apps-gx10/fc-chat/service-chat-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "chat-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "chat-web", + "namespace": "fc-chat" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app.kubernetes.io/name": "chat-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-desktop/certificate-remotedesktop-tls.json b/apps-gx10/fc-desktop/certificate-remotedesktop-tls.json new file mode 100644 index 0000000..66f5d56 --- /dev/null +++ b/apps-gx10/fc-desktop/certificate-remotedesktop-tls.json @@ -0,0 +1,18 @@ +{ + "apiVersion": "cert-manager.io/v1", + "kind": "Certificate", + "metadata": { + "name": "remotedesktop-tls", + "namespace": "fc-desktop" + }, + "spec": { + "dnsNames": [ + "desktop.iamworkin.lan" + ], + "issuerRef": { + "kind": "ClusterIssuer", + "name": "step-ca-acme" + }, + "secretName": "remotedesktop-tls" + } +} diff --git a/apps-gx10/fc-desktop/deployment-remotedesktop-operator.json b/apps-gx10/fc-desktop/deployment-remotedesktop-operator.json new file mode 100644 index 0000000..16b0f4f --- /dev/null +++ b/apps-gx10/fc-desktop/deployment-remotedesktop-operator.json @@ -0,0 +1,93 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "remotedesktop-operator", + "app.kubernetes.io/part-of": "flowercore-remotedesktop" + }, + "name": "remotedesktop-operator", + "namespace": "fc-desktop" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "remotedesktop-operator" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "labels": { + "app.kubernetes.io/name": "remotedesktop-operator", + "app.kubernetes.io/part-of": "flowercore-remotedesktop" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "RemoteDesktop__WebUrl", + "value": "http://remotedesktop-web.fc-desktop.svc.cluster.local.:8080" + } + ], + "image": "localhost/fc-remotedesktop-operator:gx10-v1", + "imagePullPolicy": "IfNotPresent", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "initialDelaySeconds": 15, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "operator", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 15, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "remotedesktop-operator", + "serviceAccountName": "remotedesktop-operator", + "terminationGracePeriodSeconds": 30 + } + } + } +} diff --git a/apps-gx10/fc-desktop/deployment-remotedesktop-web.json b/apps-gx10/fc-desktop/deployment-remotedesktop-web.json new file mode 100644 index 0000000..5f3a912 --- /dev/null +++ b/apps-gx10/fc-desktop/deployment-remotedesktop-web.json @@ -0,0 +1,299 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "remotedesktop-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "remotedesktop-web", + "namespace": "fc-desktop" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "remotedesktop-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "labels": { + "app.kubernetes.io/name": "remotedesktop-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_URLS", + "value": "http://+:8080" + }, + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "FlowerCore__Database__ConnectionStrings__Sqlite", + "value": "Data Source=/app/data/remotedesktop.db" + }, + { + "name": "RemoteDesktop__Mode", + "value": "Remote" + }, + { + "name": "RemoteDesktop__EnableApiDocs", + "value": "true" + }, + { + "name": "RemoteDesktop__PoolWarmupEnabled", + "value": "false" + }, + { + "name": "RemoteDesktop__PoolWarmupIntervalSeconds", + "value": "60" + }, + { + "name": "RemoteDesktop__OrphanReconciler__Enabled", + "value": "true" + }, + { + "name": "RemoteDesktop__OrphanReconciler__IntervalSeconds", + "value": "300" + }, + { + "name": "RemoteDesktop__OrphanReconciler__GraceSeconds", + "value": "600" + }, + { + "name": "RemoteDesktop__Audit__Enabled", + "value": "true" + }, + { + "name": "RemoteDesktop__Audit__DualWrite", + "value": "true" + }, + { + "name": "RemoteDesktop__UserVolumeClaimInitializer", + "value": "KubernetesExec" + }, + { + "name": "RemoteDesktop__KubernetesNamespace", + "value": "fc-desktop" + }, + { + "name": "RemoteDesktop__GuacamoleUrl", + "value": "http://guacamole.guacamole.svc.cluster.local.:8080/guacamole" + }, + { + "name": "RemoteDesktop__GuacamolePublicUrl", + "value": "https://desktop.iamworkin.lan/guacamole" + }, + { + "name": "RemoteDesktop__GuacamoleAdminUser", + "value": "guacadmin" + }, + { + "name": "RemoteDesktop__GuacamoleJsonSecretKey", + "valueFrom": { + "secretKeyRef": { + "key": "password", + "name": "remotedesktop-guacamole-json-auth" + } + } + }, + { + "name": "RemoteDesktop__TraefikClusterIp", + "value": "10.43.234.103" + }, + { + "name": "RemoteDesktop__TraefikHostAliases__0", + "value": "chat.iamworkin.lan" + }, + { + "name": "RemoteDesktop__TraefikHostAliases__1", + "value": "desktop.iamworkin.lan" + }, + { + "name": "RemoteDesktop__TraefikHostAliases__2", + "value": "gitea.iamworkin.lan" + }, + { + "name": "RemoteDesktop__TraefikHostAliases__3", + "value": "intranet.iamworkin.lan" + }, + { + "name": "RemoteDesktop__TraefikHostAliases__4", + "value": "print.iamworkin.lan" + }, + { + "name": "RemoteDesktop__TraefikHostAliases__5", + "value": "selenium.iamworkin.lan" + }, + { + "name": "RemoteDesktop__NfsServer", + "value": "10.0.58.3" + }, + { + "name": "RemoteDesktop__NfsBasePath", + "value": "/volume1/kubernetes/remotedesktop/users" + }, + { + "name": "RemoteDesktop__SessionRecordingBasePath", + "value": "/var/lib/guacamole/recordings" + }, + { + "name": "RemoteDesktop__MaxSessionsPerUser", + "value": "3" + }, + { + "name": "FlowerCore__Auth__Oidc__Authority", + "valueFrom": { + "secretKeyRef": { + "key": "issuer_url", + "name": "remotedesktop-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientId", + "valueFrom": { + "secretKeyRef": { + "key": "client_id", + "name": "remotedesktop-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientSecret", + "valueFrom": { + "secretKeyRef": { + "key": "client_secret", + "name": "remotedesktop-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Enabled", + "value": "false" + }, + { + "name": "FlowerCore__Auth__Oidc__Enabled", + "value": "false" + } + ], + "envFrom": [ + { + "secretRef": { + "name": "remotedesktop-secrets", + "optional": true + } + } + ], + "image": "localhost/fc-remotedesktop-web:gx10-v1", + "imagePullPolicy": "IfNotPresent", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 15, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "100m", + "memory": "256Mi" + } + }, + "startupProbe": { + "failureThreshold": 60, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/app/data", + "name": "data" + }, + { + "mountPath": "/var/lib/guacamole/recordings", + "name": "recordings", + "readOnly": true, + "subPath": "guacamole/recordings" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "remotedesktop-web", + "serviceAccountName": "remotedesktop-web", + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "remotedesktop-data" + } + }, + { + "name": "recordings", + "nfs": { + "path": "/volume1/kubernetes", + "server": "10.0.58.3" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-desktop/ingressroute-remotedesktop-web.json b/apps-gx10/fc-desktop/ingressroute-remotedesktop-web.json new file mode 100644 index 0000000..4eb7a48 --- /dev/null +++ b/apps-gx10/fc-desktop/ingressroute-remotedesktop-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "remotedesktop-web", + "namespace": "fc-desktop" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`desktop.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "remotedesktop-web", + "port": 8080 + } + ] + } + ], + "tls": { + "secretName": "remotedesktop-tls" + } + } +} diff --git a/apps-gx10/fc-desktop/service-remotedesktop-web.json b/apps-gx10/fc-desktop/service-remotedesktop-web.json new file mode 100644 index 0000000..702c17b --- /dev/null +++ b/apps-gx10/fc-desktop/service-remotedesktop-web.json @@ -0,0 +1,24 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "name": "remotedesktop-web", + "namespace": "fc-desktop" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 8080, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app.kubernetes.io/name": "remotedesktop-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-desktop/serviceaccount-remotedesktop-operator.json b/apps-gx10/fc-desktop/serviceaccount-remotedesktop-operator.json new file mode 100644 index 0000000..952484b --- /dev/null +++ b/apps-gx10/fc-desktop/serviceaccount-remotedesktop-operator.json @@ -0,0 +1,8 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "name": "remotedesktop-operator", + "namespace": "fc-desktop" + } +} diff --git a/apps-gx10/fc-desktop/serviceaccount-remotedesktop-web.json b/apps-gx10/fc-desktop/serviceaccount-remotedesktop-web.json new file mode 100644 index 0000000..d42a703 --- /dev/null +++ b/apps-gx10/fc-desktop/serviceaccount-remotedesktop-web.json @@ -0,0 +1,8 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "name": "remotedesktop-web", + "namespace": "fc-desktop" + } +} diff --git a/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-operator.json b/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-operator.json new file mode 100644 index 0000000..8b45c7c --- /dev/null +++ b/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-operator.json @@ -0,0 +1,183 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "fc-devicemgmt-operator", + "app.kubernetes.io/component": "operator", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-devicemgmt-operator", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + }, + "name": "fc-devicemgmt-operator", + "namespace": "fc-devicemgmt" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app": "fc-devicemgmt-operator" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "annotations": { + "flowercore.io/audit-trace-id": "runtime-activity-trace", + "prometheus.io/path": "/metrics", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app": "fc-devicemgmt-operator", + "app.kubernetes.io/component": "operator", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-devicemgmt-operator", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", + "value": "false" + }, + { + "name": "POD_NAME", + "valueFrom": { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.name" + } + } + }, + { + "name": "POD_NAMESPACE", + "valueFrom": { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.namespace" + } + } + }, + { + "name": "FLOWERCORE_KUBERNETES_OWNER_DEPLOYMENT", + "value": "fc-devicemgmt-operator" + }, + { + "name": "FlowerCore__Service__Name", + "value": "FlowerCore.DeviceManagement.Operator" + }, + { + "name": "FlowerCore__DeviceManagement__DefaultTenantId", + "value": "system" + } + ], + "image": "localhost/fc-devicemgmt-operator:gx10-v1", + "imagePullPolicy": "IfNotPresent", + "livenessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 20, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "name": "operator", + "ports": [ + { + "containerPort": 8080, + "name": "metrics", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "50m", + "memory": "128Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/logs", + "name": "logs" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "serviceAccount": "fc-devicemgmt-operator", + "serviceAccountName": "fc-devicemgmt-operator", + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-web.json b/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-web.json new file mode 100644 index 0000000..60e6a7d --- /dev/null +++ b/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-web.json @@ -0,0 +1,211 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "fc-devicemgmt-web", + "app.kubernetes.io/component": "web", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-devicemgmt-web", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + }, + "name": "fc-devicemgmt-web", + "namespace": "fc-devicemgmt" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app": "fc-devicemgmt-web" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": 0, + "maxUnavailable": 1 + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "annotations": { + "fc.flowercore.io/healthz-anon": "true", + "fc.flowercore.io/probe-path": "/healthz", + "flowercore.io/audit-trace-id": "runtime-activity-trace", + "kubectl.kubernetes.io/restartedAt": "2026-05-20T11:29:46-05:00", + "operator.1password.io/last-restarted": "2026-05-20T16:29:03Z", + "prometheus.io/path": "/metrics", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app": "fc-devicemgmt-web", + "app.kubernetes.io/component": "web", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-devicemgmt-web", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_URLS", + "value": "http://+:8080" + }, + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", + "value": "false" + }, + { + "name": "HOME", + "value": "/data" + }, + { + "name": "FlowerCore__Service__Name", + "value": "FlowerCore.DeviceManagement.Web" + }, + { + "name": "FlowerCore__DeviceManagement__DefaultTenantId", + "value": "system" + }, + { + "name": "FlowerCore__Database__Provider", + "value": "Sqlite" + }, + { + "name": "FlowerCore__Database__ConnectionStrings__Sqlite", + "value": "Data Source=/data/devicemgmt.db" + }, + { + "name": "FlowerCore__Database__Password", + "valueFrom": { + "secretKeyRef": { + "key": "DB-Password", + "name": "fc-devicemgmt-runtime" + } + } + }, + { + "name": "FlowerCore__EventBus__Redis__Configuration", + "value": "redis.fc-redis.svc:6379" + } + ], + "image": "localhost/fc-devicemgmt-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "name": "web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "periodSeconds": 10, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "1", + "memory": "768Mi" + }, + "requests": { + "cpu": "100m", + "memory": "256Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "startupProbe": { + "failureThreshold": 30, + "initialDelaySeconds": 5, + "periodSeconds": 5, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/logs", + "name": "logs" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "fc-devicemgmt-web-data" + } + }, + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-devicemgmt/ingressroute-devicemgmt.json b/apps-gx10/fc-devicemgmt/ingressroute-devicemgmt.json new file mode 100644 index 0000000..d9507e9 --- /dev/null +++ b/apps-gx10/fc-devicemgmt/ingressroute-devicemgmt.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "devicemgmt", + "namespace": "fc-devicemgmt" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`devices.iamworkin.lan`)", + "services": [ + { + "name": "fc-devicemgmt-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "fc-devicemgmt-web-tls" + } + } +} diff --git a/apps-gx10/fc-devicemgmt/service-fc-devicemgmt-web.json b/apps-gx10/fc-devicemgmt/service-fc-devicemgmt-web.json new file mode 100644 index 0000000..ea6bc7a --- /dev/null +++ b/apps-gx10/fc-devicemgmt/service-fc-devicemgmt-web.json @@ -0,0 +1,33 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app": "fc-devicemgmt-web", + "app.kubernetes.io/component": "web", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-devicemgmt-web", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + }, + "name": "fc-devicemgmt-web", + "namespace": "fc-devicemgmt" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app": "fc-devicemgmt-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-devicemgmt/serviceaccount-fc-devicemgmt-operator.json b/apps-gx10/fc-devicemgmt/serviceaccount-fc-devicemgmt-operator.json new file mode 100644 index 0000000..2d17ef2 --- /dev/null +++ b/apps-gx10/fc-devicemgmt/serviceaccount-fc-devicemgmt-operator.json @@ -0,0 +1,16 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "labels": { + "app.kubernetes.io/component": "operator", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-devicemgmt-operator", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + }, + "name": "fc-devicemgmt-operator", + "namespace": "fc-devicemgmt" + } +} diff --git a/apps-gx10/fc-distribution/deployment-fc-distribution.json b/apps-gx10/fc-distribution/deployment-fc-distribution.json new file mode 100644 index 0000000..b4f9d26 --- /dev/null +++ b/apps-gx10/fc-distribution/deployment-fc-distribution.json @@ -0,0 +1,265 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "fc-distribution", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "fc-distribution", + "namespace": "fc-distribution" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "fc-distribution" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "flowercore.io/healthz-auth-policy": "allow-anonymous", + "prometheus.io/path": "/metrics", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "fc-distribution", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_URLS", + "value": "http://+:8080" + }, + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", + "value": "false" + }, + { + "name": "FlowerCore__Auth__Enabled", + "value": "true" + }, + { + "name": "FlowerCore__Auth__Oidc__Enabled", + "value": "true" + }, + { + "name": "FlowerCore__Auth__Oidc__Authority", + "value": "https://id.iamworkin.lan/application/o/distribution/" + }, + { + "name": "FlowerCore__Auth__Oidc__Audience", + "value": "distribution" + }, + { + "name": "FlowerCore__Auth__Oidc__ClientId", + "value": "distribution" + }, + { + "name": "FlowerCore__Auth__Oidc__ClientSecret", + "valueFrom": { + "secretKeyRef": { + "key": "client_secret", + "name": "distribution-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Database__Provider", + "value": "Sqlite" + }, + { + "name": "FlowerCore__Database__ConnectionStrings__Sqlite", + "value": "Data Source=/data/distribution.db" + }, + { + "name": "FlowerCore__Distribution__Blobs__Root", + "value": "/blobs" + }, + { + "name": "FlowerCore__Distribution__Signing__EditionCerts__kiosk-standard__CertPath", + "value": "/signing/kiosk-standard/chain.pem" + }, + { + "name": "FlowerCore__Distribution__Signing__EditionCerts__kiosk-standard__KeyPath", + "value": "/signing/kiosk-standard/private-key.pem" + }, + { + "name": "FlowerCore__Distribution__Signing__EditionCerts__aistation-field__CertPath", + "value": "/signing/aistation-field/chain.pem" + }, + { + "name": "FlowerCore__Distribution__Signing__EditionCerts__aistation-field__KeyPath", + "value": "/signing/aistation-field/private-key.pem" + }, + { + "name": "FlowerCore__Distribution__EntitlementPublic__PublicEditions__0", + "value": "*" + } + ], + "image": "localhost/fc-distribution:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "name": "web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 8080, + "scheme": "HTTP" + }, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "100m", + "memory": "256Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "startupProbe": { + "failureThreshold": 30, + "httpGet": { + "path": "/healthz", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 5, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "sqlite", + "subPath": "distribution/data" + }, + { + "mountPath": "/blobs", + "name": "blobs", + "subPath": "distribution/blobs" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/logs", + "name": "logs" + }, + { + "mountPath": "/signing/kiosk-standard", + "name": "kiosk-standard", + "readOnly": true + }, + { + "mountPath": "/signing/aistation-field", + "name": "aistation-field", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch", + "runAsNonRoot": true + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "sqlite", + "nfs": { + "path": "/volume1/kubernetes", + "server": "10.0.58.3" + } + }, + { + "name": "blobs", + "nfs": { + "path": "/volume1/kubernetes", + "server": "10.0.58.3" + } + }, + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + }, + { + "name": "kiosk-standard", + "secret": { + "defaultMode": 256, + "secretName": "edition-kiosk-standard" + } + }, + { + "name": "aistation-field", + "secret": { + "defaultMode": 256, + "secretName": "edition-aistation-field" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-distribution/ingressroute-fc-distribution-public.json b/apps-gx10/fc-distribution/ingressroute-fc-distribution-public.json new file mode 100644 index 0000000..091b15e --- /dev/null +++ b/apps-gx10/fc-distribution/ingressroute-fc-distribution-public.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "fc-distribution-public", + "namespace": "fc-distribution" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`dist.flowercore.io`) && (Method(`GET`) || Method(`HEAD`))", + "priority": 100, + "services": [ + { + "name": "fc-distribution", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "cf-origin-flowercore-io" + } + } +} diff --git a/apps-gx10/fc-distribution/ingressroute-fc-distribution.json b/apps-gx10/fc-distribution/ingressroute-fc-distribution.json new file mode 100644 index 0000000..7c96f6e --- /dev/null +++ b/apps-gx10/fc-distribution/ingressroute-fc-distribution.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "fc-distribution", + "namespace": "fc-distribution" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`dist.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "fc-distribution", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "fc-distribution-tls-secret" + } + } +} diff --git a/apps-gx10/fc-distribution/service-fc-distribution.json b/apps-gx10/fc-distribution/service-fc-distribution.json new file mode 100644 index 0000000..3113417 --- /dev/null +++ b/apps-gx10/fc-distribution/service-fc-distribution.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "fc-distribution", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "fc-distribution", + "namespace": "fc-distribution" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app.kubernetes.io/name": "fc-distribution" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-dms/configmap-dms-web-config.json b/apps-gx10/fc-dms/configmap-dms-web-config.json new file mode 100644 index 0000000..395d4b2 --- /dev/null +++ b/apps-gx10/fc-dms/configmap-dms-web-config.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:8080", + "Dms__AutoMessageDaemon__PollIntervalMinutes": "5", + "Dms__Weather__CacheFilePath": "/data/noaa-cache.json", + "Dms__Weather__State": "MN", + "FlowerCore__Auth__AcceptLegacyApiKey": "true", + "FlowerCore__Auth__AcceptLegacyJwt": "false", + "FlowerCore__Auth__Provider": "Oidc", + "FlowerCore__Auth__RoleClaimType": "fc:roles", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/dms.db", + "FlowerCore__Database__Provider": "Sqlite", + "FlowerCore__Tenant__DefaultTenantHosts__0": "dms.iamworkin.lan", + "FlowerCore__Tenant__JwtClaimsEnabled": "false", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.DMS", + "Security__AllowedOrigins__0": "https://dms.iamworkin.lan" + }, + "kind": "ConfigMap", + "metadata": { + "name": "dms-web-config", + "namespace": "fc-dms" + } +} diff --git a/apps-gx10/fc-dms/deployment-dms-web.json b/apps-gx10/fc-dms/deployment-dms-web.json new file mode 100644 index 0000000..617eb69 --- /dev/null +++ b/apps-gx10/fc-dms/deployment-dms-web.json @@ -0,0 +1,169 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "dms-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "dms-web", + "namespace": "fc-dms" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "dms-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-06-12T16:05:19-05:00", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "dms-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "Kestrel__Endpoints__Http__Url", + "value": "http://+:8080" + }, + { + "name": "Kestrel__Endpoints__Http__Protocols", + "value": "Http1" + }, + { + "name": "Kestrel__Endpoints__Grpc__Url", + "value": "http://+:8081" + }, + { + "name": "Kestrel__Endpoints__Grpc__Protocols", + "value": "Http2" + }, + { + "name": "FlowerCore__Auth__OidcClientId", + "valueFrom": { + "secretKeyRef": { + "key": "client_id", + "name": "dms-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__OidcClientSecret", + "valueFrom": { + "secretKeyRef": { + "key": "client_secret", + "name": "dms-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__OidcAuthority", + "valueFrom": { + "secretKeyRef": { + "key": "issuer_url", + "name": "dms-oidc-client", + "optional": true + } + } + } + ], + "envFrom": [ + { + "configMapRef": { + "name": "dms-web-config" + } + }, + { + "secretRef": { + "name": "dms-web-secrets" + } + } + ], + "image": "localhost/fc-dms-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 180, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "dms-web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + }, + { + "containerPort": 8081, + "name": "grpc", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 18, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "dms-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-dms/ingressroute-dms-web.json b/apps-gx10/fc-dms/ingressroute-dms-web.json new file mode 100644 index 0000000..4cacb92 --- /dev/null +++ b/apps-gx10/fc-dms/ingressroute-dms-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "dms-web", + "namespace": "fc-dms" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`dms.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "dms-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "dms-web-tls" + } + } +} diff --git a/apps-gx10/fc-dms/service-dms-web.json b/apps-gx10/fc-dms/service-dms-web.json new file mode 100644 index 0000000..f6d63f1 --- /dev/null +++ b/apps-gx10/fc-dms/service-dms-web.json @@ -0,0 +1,34 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "dms-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "dms-web", + "namespace": "fc-dms" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + }, + { + "name": "grpc", + "port": 8081, + "protocol": "TCP", + "targetPort": 8081 + } + ], + "selector": { + "app.kubernetes.io/name": "dms-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-library/configmap-library-web-config.json b/apps-gx10/fc-library/configmap-library-web-config.json new file mode 100644 index 0000000..7603423 --- /dev/null +++ b/apps-gx10/fc-library/configmap-library-web-config.json @@ -0,0 +1,20 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:5000", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/library.db", + "FlowerCore__Database__Provider": "Sqlite", + "FlowerCore__Library__BaseUrl": "https://library.iamworkin.lan", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.Library", + "PrintService__BaseUrl": "http://print.iamworkin.lan:5200" + }, + "kind": "ConfigMap", + "metadata": { + "name": "library-web-config", + "namespace": "fc-library" + } +} diff --git a/apps-gx10/fc-library/deployment-library-web.json b/apps-gx10/fc-library/deployment-library-web.json new file mode 100644 index 0000000..be7a4a0 --- /dev/null +++ b/apps-gx10/fc-library/deployment-library-web.json @@ -0,0 +1,110 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "library-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "library-web", + "namespace": "fc-library" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "library-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "fc.flowercore.io/healthz-anon": "true", + "fc.flowercore.io/probe-path": "/health", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "5000", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "library-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "library-web-config" + } + } + ], + "image": "localhost/fc-library-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "library-web", + "ports": [ + { + "containerPort": 5000, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "httpGet": { + "path": "/health", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "library-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-library/ingressroute-library-web.json b/apps-gx10/fc-library/ingressroute-library-web.json new file mode 100644 index 0000000..65a466a --- /dev/null +++ b/apps-gx10/fc-library/ingressroute-library-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "library-web", + "namespace": "fc-library" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`library.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "library-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "library-web-tls" + } + } +} diff --git a/apps-gx10/fc-library/service-library-web.json b/apps-gx10/fc-library/service-library-web.json new file mode 100644 index 0000000..5ce0041 --- /dev/null +++ b/apps-gx10/fc-library/service-library-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "library-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "library-web", + "namespace": "fc-library" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 5000 + } + ], + "selector": { + "app.kubernetes.io/name": "library-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-llm-bridge/deployment-fc-llm-bridge.json b/apps-gx10/fc-llm-bridge/deployment-fc-llm-bridge.json new file mode 100644 index 0000000..757ed46 --- /dev/null +++ b/apps-gx10/fc-llm-bridge/deployment-fc-llm-bridge.json @@ -0,0 +1,292 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "fc-llm-bridge", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "fc-llm-bridge", + "namespace": "fc-llm-bridge" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "fc-llm-bridge" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "fc.flowercore.io/healthz-anon": "true", + "fc.flowercore.io/probe-path": "/healthz", + "kubectl.kubernetes.io/restartedAt": "2026-06-14T15:12:25-05:00", + "prometheus.io/path": "/metrics", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "fc-llm-bridge", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_URLS", + "value": "http://+:8080" + }, + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", + "value": "false" + }, + { + "name": "FlowerCore__LlmBridge__SqliteConnectionString", + "value": "Data Source=/data/llm-bridge.db" + }, + { + "name": "FlowerCore__LlmBridge__DefaultTenantId", + "value": "default" + }, + { + "name": "FlowerCore__LlmBridge__DefaultAppName", + "value": "agent-zero" + }, + { + "name": "FlowerCore__LlmBridge__UtilModel", + "value": "qwen2.5:1.5b" + }, + { + "name": "FlowerCore__LlmBridge__EmbedModel", + "value": "nomic-embed-text" + }, + { + "name": "FlowerCore__LlmBridge__ApiKeys__agent-zero-ws", + "valueFrom": { + "secretKeyRef": { + "key": "agent-zero-ws", + "name": "fc-llm-bridge-api-keys", + "optional": true + } + } + }, + { + "name": "FlowerCore__LlmBridge__ApiKeys__agent-zero-k8s", + "valueFrom": { + "secretKeyRef": { + "key": "agent-zero-k8s", + "name": "fc-llm-bridge-api-keys", + "optional": true + } + } + }, + { + "name": "FlowerCore__LlmBridge__ApiKeys__spare-1", + "valueFrom": { + "secretKeyRef": { + "key": "spare-1", + "name": "fc-llm-bridge-api-keys", + "optional": true + } + } + }, + { + "name": "FlowerCore__LlmBridge__ApiKeys__spare-2", + "valueFrom": { + "secretKeyRef": { + "key": "spare-2", + "name": "fc-llm-bridge-api-keys", + "optional": true + } + } + }, + { + "name": "FlowerCore__Chat__OllamaBaseUrl", + "value": "http://10.0.56.14:30976" + }, + { + "name": "FlowerCore__Chat__HttpTimeout", + "value": "00:05:00" + }, + { + "name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Balanced__Provider", + "value": "Ollama" + }, + { + "name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Balanced__Model", + "value": "qwen2.5:14b" + }, + { + "name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Cheap__Provider", + "value": "Ollama" + }, + { + "name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Cheap__Model", + "value": "qwen2.5:7b" + }, + { + "name": "FlowerCore__Chat__Anthropic__Enabled", + "value": "true" + }, + { + "name": "FlowerCore__Chat__Anthropic__ApiKey", + "valueFrom": { + "secretKeyRef": { + "key": "password", + "name": "anthropic-api-key" + } + } + }, + { + "name": "FlowerCore__Chat__Anthropic__OrganizationId", + "valueFrom": { + "secretKeyRef": { + "key": "organization_id", + "name": "anthropic-api-key", + "optional": true + } + } + }, + { + "name": "FlowerCore__Chat__Anthropic__BaseUrl", + "value": "https://api.anthropic.com" + }, + { + "name": "FlowerCore__Chat__Anthropic__DefaultModel", + "value": "claude-sonnet-4-6" + }, + { + "name": "FlowerCore__Chat__Anthropic__AnthropicVersion", + "value": "2023-06-01" + }, + { + "name": "FlowerCore__Chat__Anthropic__Timeout", + "value": "00:05:00" + } + ], + "image": "localhost/fc-llm-bridge:gx10-v2", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 15, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "name": "web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "1", + "memory": "768Mi" + }, + "requests": { + "cpu": "100m", + "memory": "256Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/data", + "name": "app-data" + } + ] + } + ], + "dnsConfig": { + "nameservers": [ + "10.43.0.10" + ], + "options": [ + { + "name": "ndots", + "value": "2" + } + ], + "searches": [ + "fc-llm-bridge.svc.cluster.local", + "svc.cluster.local", + "cluster.local" + ] + }, + "dnsPolicy": "None", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "fc-llm-bridge-data" + } + }, + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "app-data" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-llm-bridge/ingressroute-fc-llm-bridge.json b/apps-gx10/fc-llm-bridge/ingressroute-fc-llm-bridge.json new file mode 100644 index 0000000..dbb77e8 --- /dev/null +++ b/apps-gx10/fc-llm-bridge/ingressroute-fc-llm-bridge.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "fc-llm-bridge", + "namespace": "fc-llm-bridge" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`fc-llm-bridge.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "fc-llm-bridge", + "port": 8080 + } + ] + } + ], + "tls": { + "secretName": "fc-llm-bridge-tls" + } + } +} diff --git a/apps-gx10/fc-llm-bridge/service-fc-llm-bridge.json b/apps-gx10/fc-llm-bridge/service-fc-llm-bridge.json new file mode 100644 index 0000000..50ef513 --- /dev/null +++ b/apps-gx10/fc-llm-bridge/service-fc-llm-bridge.json @@ -0,0 +1,25 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": {}, + "name": "fc-llm-bridge", + "namespace": "fc-llm-bridge" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 8080, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app.kubernetes.io/name": "fc-llm-bridge" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-media/configmap-fc-media-config.json b/apps-gx10/fc-media/configmap-fc-media-config.json new file mode 100644 index 0000000..16d9cbe --- /dev/null +++ b/apps-gx10/fc-media/configmap-fc-media-config.json @@ -0,0 +1,11 @@ +{ + "apiVersion": "v1", + "data": { + "appsettings.Production.json": "{\n \"DatabaseProvider\": \"Sqlite\",\n \"ConnectionStrings\": {\n \"Sqlite\": \"Data Source=/data/media.db\"\n },\n \"FlowerCore\": {\n \"Auth\": {\n \"Enabled\": true,\n \"Oidc\": {\n \"Authority\": \"https://id.iamworkin.lan/application/o/media/\",\n \"ClientId\": \"media\",\n \"ClientSecret\": \"\",\n \"Audience\": \"media\",\n \"RequireHttpsMetadata\": true\n }\n },\n \"Tenant\": {\n \"JwtClaimsEnabled\": false,\n \"DefaultTenantHosts\": [ \"media.iamworkin.lan\" ]\n }\n },\n \"Media\": {\n \"LibraryRoot\": \"/media/library\",\n \"Sources\": [\n {\n \"Name\": \"BlueJayNAS Video\",\n \"Driver\": \"Nfs\",\n \"MountedPath\": \"/media/library\",\n \"RemotePath\": \"nfs://10.0.58.3/volume1/video\",\n \"IsEnabled\": true,\n \"IsDefault\": true,\n \"Notes\": \"Synology NFS media share mounted read-only inside the cluster.\"\n }\n ],\n \"GeneratedRoot\": \"/data/generated\",\n \"TranscodeRoot\": \"/data/transcodes\",\n \"InboxPath\": \"/media/inbox\",\n \"InboxScanIntervalMinutes\": 5,\n \"ScanOnStartup\": false,\n \"ComputeChecksums\": false,\n \"FfmpegCommand\": \"ffmpeg\",\n \"FfprobeCommand\": \"ffprobe\",\n \"Hls\": {\n \"MaxConcurrentJobs\": 1\n },\n \"DefaultViewerName\": \"BlueJay\",\n \"Dlna\": {\n \"IsEnabled\": true,\n \"MulticastAddress\": \"239.255.255.250\",\n \"Port\": 1900,\n \"DiscoveryTimeoutSeconds\": 2,\n \"DescriptionFetchTimeoutSeconds\": 2,\n \"MaxResponsesPerSearchTarget\": 32,\n \"SearchTargets\": [\n \"urn:schemas-upnp-org:device:MediaRenderer:1\",\n \"urn:schemas-upnp-org:device:MediaServer:1\"\n ]\n }\n }\n}\n" + }, + "kind": "ConfigMap", + "metadata": { + "name": "fc-media-config", + "namespace": "fc-media" + } +} diff --git a/apps-gx10/fc-media/deployment-fc-media-web.json b/apps-gx10/fc-media/deployment-fc-media-web.json new file mode 100644 index 0000000..0ebd98f --- /dev/null +++ b/apps-gx10/fc-media/deployment-fc-media-web.json @@ -0,0 +1,242 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "fc-media-web", + "app.kubernetes.io/name": "fc-media-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "fc-media-web", + "namespace": "fc-media" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "fc-media-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "flowercore.io/healthz-auth-policy": "allow-anonymous", + "kubectl.kubernetes.io/restartedAt": "2026-04-05T14:14:28-05:00", + "prometheus.io/path": "/metrics", + "prometheus.io/port": "5200", + "prometheus.io/scrape": "true" + }, + "labels": { + "app": "fc-media-web", + "app.kubernetes.io/name": "fc-media-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "ASPNETCORE_URLS", + "value": "http://+:5200" + }, + { + "name": "FlowerCore__Auth__Enabled", + "value": "true" + }, + { + "name": "FlowerCore__Auth__Oidc__Enabled", + "value": "true" + }, + { + "name": "FlowerCore__Auth__Oidc__Audience", + "value": "media" + }, + { + "name": "FlowerCore__Auth__Oidc__ClientId", + "valueFrom": { + "secretKeyRef": { + "key": "client_id", + "name": "media-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientSecret", + "valueFrom": { + "secretKeyRef": { + "key": "client_secret", + "name": "media-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__Authority", + "valueFrom": { + "secretKeyRef": { + "key": "issuer_url", + "name": "media-oidc-client", + "optional": true + } + } + } + ], + "image": "localhost/fc-media-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "httpHeaders": [ + { + "name": "X-Forwarded-Proto", + "value": "https" + } + ], + "path": "/healthz", + "port": 5200, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "fc-media-web", + "ports": [ + { + "containerPort": 5200, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "httpHeaders": [ + { + "name": "X-Forwarded-Proto", + "value": "https" + } + ], + "path": "/healthz", + "port": 5200, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "4", + "memory": "4Gi" + }, + "requests": { + "cpu": "500m", + "memory": "1Gi" + } + }, + "startupProbe": { + "failureThreshold": 18, + "httpGet": { + "httpHeaders": [ + { + "name": "X-Forwarded-Proto", + "value": "https" + } + ], + "path": "/healthz", + "port": 5200, + "scheme": "HTTP" + }, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/app/appsettings.Production.json", + "name": "config", + "readOnly": true, + "subPath": "appsettings.Production.json" + }, + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/data/transcodes", + "name": "transcodes" + }, + { + "mountPath": "/media/library", + "name": "media-library", + "readOnly": true + }, + { + "mountPath": "/media/inbox", + "name": "media-inbox" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "configMap": { + "defaultMode": 420, + "name": "fc-media-config" + }, + "name": "config" + }, + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "fc-media-data" + } + }, + { + "name": "transcodes", + "nfs": { + "path": "/volume1/kubernetes/fc-media-transcodes", + "server": "10.0.58.3" + } + }, + { + "name": "media-inbox", + "nfs": { + "path": "/volume1/kubernetes/fc-media-inbox", + "server": "10.0.58.3" + } + }, + { + "name": "media-library", + "nfs": { + "path": "/volume1/video", + "readOnly": true, + "server": "10.0.58.3" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-media/ingressroute-fc-media-web.json b/apps-gx10/fc-media/ingressroute-fc-media-web.json new file mode 100644 index 0000000..68f4405 --- /dev/null +++ b/apps-gx10/fc-media/ingressroute-fc-media-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "fc-media-web", + "namespace": "fc-media" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`media.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "fc-media-web", + "port": 5200 + } + ] + } + ], + "tls": { + "secretName": "fc-media-tls" + } + } +} diff --git a/apps-gx10/fc-media/service-fc-media-web.json b/apps-gx10/fc-media/service-fc-media-web.json new file mode 100644 index 0000000..37798eb --- /dev/null +++ b/apps-gx10/fc-media/service-fc-media-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app": "fc-media-web", + "app.kubernetes.io/name": "fc-media-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "fc-media-web", + "namespace": "fc-media" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 5200, + "protocol": "TCP", + "targetPort": 5200 + } + ], + "selector": { + "app": "fc-media-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-menuboard/configmap-menuboard-web-config.json b/apps-gx10/fc-menuboard/configmap-menuboard-web-config.json new file mode 100644 index 0000000..bb430cb --- /dev/null +++ b/apps-gx10/fc-menuboard/configmap-menuboard-web-config.json @@ -0,0 +1,18 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:5000", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/menuboard.db", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.MenuBoard", + "Security__AllowedOrigins__0": "https://menuboard.iamworkin.lan" + }, + "kind": "ConfigMap", + "metadata": { + "name": "menuboard-web-config", + "namespace": "fc-menuboard" + } +} diff --git a/apps-gx10/fc-menuboard/deployment-menuboard-web.json b/apps-gx10/fc-menuboard/deployment-menuboard-web.json new file mode 100644 index 0000000..a005cf4 --- /dev/null +++ b/apps-gx10/fc-menuboard/deployment-menuboard-web.json @@ -0,0 +1,112 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "menuboard-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "menuboard-web", + "namespace": "fc-menuboard" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "menuboard-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "5000", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "menuboard-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "menuboard-web-config" + } + }, + { + "secretRef": { + "name": "menuboard-web-secrets" + } + } + ], + "image": "localhost/fc-menuboard-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "menuboard-web", + "ports": [ + { + "containerPort": 5000, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "httpGet": { + "path": "/health", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "menuboard-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-menuboard/ingressroute-menuboard-web.json b/apps-gx10/fc-menuboard/ingressroute-menuboard-web.json new file mode 100644 index 0000000..6955add --- /dev/null +++ b/apps-gx10/fc-menuboard/ingressroute-menuboard-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "menuboard-web", + "namespace": "fc-menuboard" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`menuboard.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "menuboard-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "menuboard-web-tls" + } + } +} diff --git a/apps-gx10/fc-menuboard/service-menuboard-web.json b/apps-gx10/fc-menuboard/service-menuboard-web.json new file mode 100644 index 0000000..693b437 --- /dev/null +++ b/apps-gx10/fc-menuboard/service-menuboard-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "menuboard-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "menuboard-web", + "namespace": "fc-menuboard" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 5000 + } + ], + "selector": { + "app.kubernetes.io/name": "menuboard-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-messageboard/configmap-messageboard-web-config.json b/apps-gx10/fc-messageboard/configmap-messageboard-web-config.json new file mode 100644 index 0000000..1ec04db --- /dev/null +++ b/apps-gx10/fc-messageboard/configmap-messageboard-web-config.json @@ -0,0 +1,18 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:8080", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/messageboard.db", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.MessageBoard", + "Security__AllowedOrigins__0": "https://messageboard.iamworkin.lan" + }, + "kind": "ConfigMap", + "metadata": { + "name": "messageboard-web-config", + "namespace": "fc-messageboard" + } +} diff --git a/apps-gx10/fc-messageboard/deployment-messageboard-web.json b/apps-gx10/fc-messageboard/deployment-messageboard-web.json new file mode 100644 index 0000000..4485f80 --- /dev/null +++ b/apps-gx10/fc-messageboard/deployment-messageboard-web.json @@ -0,0 +1,118 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "messageboard-web" + }, + "name": "messageboard-web", + "namespace": "fc-messageboard" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "messageboard-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "fc.flowercore.io/healthz-anon": "true", + "fc.flowercore.io/probe-path": "/health", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app": "messageboard-web" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "messageboard-web-config" + } + }, + { + "secretRef": { + "name": "messageboard-web-secrets", + "optional": true + } + } + ], + "image": "localhost/fc-messageboard-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 10, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 5 + }, + "name": "messageboard-web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 5 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "messageboard-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-messageboard/ingressroute-messageboard-web.json b/apps-gx10/fc-messageboard/ingressroute-messageboard-web.json new file mode 100644 index 0000000..23a3cad --- /dev/null +++ b/apps-gx10/fc-messageboard/ingressroute-messageboard-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "messageboard-web", + "namespace": "fc-messageboard" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`messageboard.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "messageboard-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "messageboard-web-tls" + } + } +} diff --git a/apps-gx10/fc-messageboard/service-messageboard-web.json b/apps-gx10/fc-messageboard/service-messageboard-web.json new file mode 100644 index 0000000..9402021 --- /dev/null +++ b/apps-gx10/fc-messageboard/service-messageboard-web.json @@ -0,0 +1,25 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": {}, + "name": "messageboard-web", + "namespace": "fc-messageboard" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app": "messageboard-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-mysql/configmap-mysql-web-config.json b/apps-gx10/fc-mysql/configmap-mysql-web-config.json new file mode 100644 index 0000000..26f4f8b --- /dev/null +++ b/apps-gx10/fc-mysql/configmap-mysql-web-config.json @@ -0,0 +1,11 @@ +{ + "apiVersion": "v1", + "data": { + "appsettings.Production.json": "{\n \"MySqlManager\": {\n \"CrdNamespace\": \"fc-tenant-default\",\n \"MySqlImage\": \"iwrk-nexus.iamworkin.lan:8444/iwrk-ubuntu-mysql:master\",\n \"PhpMyAdminImage\": \"phpmyadmin/phpmyadmin:latest\",\n \"PhpMyAdminDomain\": \"iamworkin.lan\",\n \"Advisor\": {\n \"DefaultPreset\": \"medium\",\n \"AutoDetectPreset\": true,\n \"MaxAutoPreset\": \"medium\",\n \"PresetOverride\": null\n }\n },\n \"ContainerBackend\": {\n \"Default\": \"Kubernetes\"\n },\n \"FlowerCore\": {\n \"Auth\": {\n \"Provider\": \"Oidc\",\n \"Enabled\": false,\n \"Oidc\": {\n \"Enabled\": true,\n \"Authority\": \"https://id.iamworkin.lan/application/o/mysql/\",\n \"Audience\": \"mysql\",\n \"ClientId\": \"mysql\",\n \"ClientSecret\": \"\"\n }\n },\n \"Tenant\": {\n \"JwtClaimsEnabled\": false,\n \"TenantClaimType\": \"fc:tenant\",\n \"ActorIdClaimType\": \"flowercore_actor_id\"\n },\n \"Database\": {\n \"Provider\": \"Sqlite\",\n \"ConnectionStrings\": {\n \"Sqlite\": \"Data Source=/data/mysql-manager.db\"\n }\n }\n }\n}\n" + }, + "kind": "ConfigMap", + "metadata": { + "name": "mysql-web-config", + "namespace": "fc-mysql" + } +} diff --git a/apps-gx10/fc-mysql/deployment-mysql-web.json b/apps-gx10/fc-mysql/deployment-mysql-web.json new file mode 100644 index 0000000..197bebf --- /dev/null +++ b/apps-gx10/fc-mysql/deployment-mysql-web.json @@ -0,0 +1,209 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "flowercore", + "app.kubernetes.io/name": "mysql-web" + }, + "name": "mysql-web", + "namespace": "fc-mysql" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "mysql-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-04-17T19:52:14-05:00", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "5300", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "mysql-web" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "FlowerCore__Auth__Enabled", + "value": "false" + }, + { + "name": "FlowerCore__Auth__Oidc__Authority", + "valueFrom": { + "secretKeyRef": { + "key": "issuer_url", + "name": "mysql-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientId", + "valueFrom": { + "secretKeyRef": { + "key": "client_id", + "name": "mysql-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientSecret", + "valueFrom": { + "secretKeyRef": { + "key": "client_secret", + "name": "mysql-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__Audience", + "value": "mysql" + } + ], + "image": "localhost/fc-mysql-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/metrics/prometheus", + "port": 5300, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "mysql-web", + "ports": [ + { + "containerPort": 5300, + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/metrics/prometheus", + "port": 5300, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/logs", + "name": "logs" + }, + { + "mountPath": "/app/appsettings.Production.json", + "name": "config", + "readOnly": true, + "subPath": "appsettings.Production.json" + } + ] + } + ], + "dnsConfig": { + "nameservers": [ + "10.43.0.10" + ], + "options": [ + { + "name": "ndots", + "value": "2" + } + ], + "searches": [ + "fc-mysql.svc.cluster.local", + "svc.cluster.local", + "cluster.local" + ] + }, + "dnsPolicy": "None", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "serviceAccount": "mysql-web", + "serviceAccountName": "mysql-web", + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "mysql-web-data" + } + }, + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + }, + { + "configMap": { + "defaultMode": 420, + "name": "mysql-web-config" + }, + "name": "config" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-mysql/ingressroute-mysql-web.json b/apps-gx10/fc-mysql/ingressroute-mysql-web.json new file mode 100644 index 0000000..04aeba4 --- /dev/null +++ b/apps-gx10/fc-mysql/ingressroute-mysql-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "mysql-web", + "namespace": "fc-mysql" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`mysql.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "mysql-web", + "port": 5300 + } + ] + } + ], + "tls": { + "secretName": "mysql-web-tls" + } + } +} diff --git a/apps-gx10/fc-mysql/service-mysql-web.json b/apps-gx10/fc-mysql/service-mysql-web.json new file mode 100644 index 0000000..754c172 --- /dev/null +++ b/apps-gx10/fc-mysql/service-mysql-web.json @@ -0,0 +1,23 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "name": "mysql-web", + "namespace": "fc-mysql" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "port": 5300, + "protocol": "TCP", + "targetPort": 5300 + } + ], + "selector": { + "app.kubernetes.io/name": "mysql-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-mysql/serviceaccount-mysql-web.json b/apps-gx10/fc-mysql/serviceaccount-mysql-web.json new file mode 100644 index 0000000..1663283 --- /dev/null +++ b/apps-gx10/fc-mysql/serviceaccount-mysql-web.json @@ -0,0 +1,8 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "name": "mysql-web", + "namespace": "fc-mysql" + } +} diff --git a/apps-gx10/fc-network/certificate-fc-network-web-tls.json b/apps-gx10/fc-network/certificate-fc-network-web-tls.json new file mode 100644 index 0000000..e32e72d --- /dev/null +++ b/apps-gx10/fc-network/certificate-fc-network-web-tls.json @@ -0,0 +1,18 @@ +{ + "apiVersion": "cert-manager.io/v1", + "kind": "Certificate", + "metadata": { + "name": "fc-network-web-tls", + "namespace": "fc-network" + }, + "spec": { + "dnsNames": [ + "network.iamworkin.lan" + ], + "issuerRef": { + "kind": "ClusterIssuer", + "name": "step-ca-acme" + }, + "secretName": "fc-network-web-tls" + } +} diff --git a/apps-gx10/fc-network/deployment-fc-network-web.json b/apps-gx10/fc-network/deployment-fc-network-web.json new file mode 100644 index 0000000..8b4dca4 --- /dev/null +++ b/apps-gx10/fc-network/deployment-fc-network-web.json @@ -0,0 +1,210 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "fc-network-web", + "app.kubernetes.io/component": "web", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-network-web", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + }, + "name": "fc-network-web", + "namespace": "fc-network" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app": "fc-network-web" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": 0, + "maxUnavailable": 1 + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "annotations": { + "fc.flowercore.io/healthz-anon": "true", + "fc.flowercore.io/probe-path": "/healthz", + "flowercore.io/audit-trace-id": "runtime-activity-trace", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "5340", + "prometheus.io/scrape": "true" + }, + "labels": { + "app": "fc-network-web", + "app.kubernetes.io/component": "web", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-network-web", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_URLS", + "value": "http://+:5340" + }, + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", + "value": "false" + }, + { + "name": "HOME", + "value": "/data" + }, + { + "name": "FlowerCore__Auth__Enabled", + "value": "false" + }, + { + "name": "FlowerCore__Database__Provider", + "value": "Sqlite" + }, + { + "name": "FlowerCore__Database__ConnectionStrings__Sqlite", + "value": "Data Source=/data/network.db" + }, + { + "name": "FlowerCore__Network__SnapshotStore__RootDirectory", + "value": "/data/snapshots" + }, + { + "name": "FlowerCore__Network__SnapshotStore__UseGitHistory", + "value": "true" + }, + { + "name": "FlowerCore__Network__IntendedModel__FilePath", + "value": "/data/intended.json" + } + ], + "image": "localhost/fc-network-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 5340, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "web", + "ports": [ + { + "containerPort": 5340, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 5340, + "scheme": "HTTP" + }, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "50m", + "memory": "128Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "startupProbe": { + "failureThreshold": 30, + "httpGet": { + "path": "/healthz", + "port": 5340, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 5, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/logs", + "name": "logs" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "fc-network-web-data" + } + }, + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-network/ingressroute-fc-network-web.json b/apps-gx10/fc-network/ingressroute-fc-network-web.json new file mode 100644 index 0000000..f385c4a --- /dev/null +++ b/apps-gx10/fc-network/ingressroute-fc-network-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "fc-network-web", + "namespace": "fc-network" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`network.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "fc-network-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "fc-network-web-tls" + } + } +} diff --git a/apps-gx10/fc-network/service-fc-network-web.json b/apps-gx10/fc-network/service-fc-network-web.json new file mode 100644 index 0000000..e6007a8 --- /dev/null +++ b/apps-gx10/fc-network/service-fc-network-web.json @@ -0,0 +1,33 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app": "fc-network-web", + "app.kubernetes.io/component": "web", + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "fc-network-web", + "app.kubernetes.io/part-of": "flowercore", + "flowercore.io/created-by": "bluejay-infra", + "flowercore.io/tenant-id": "system" + }, + "name": "fc-network-web", + "namespace": "fc-network" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 5340 + } + ], + "selector": { + "app": "fc-network-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-php/configmap-php-web-config.json b/apps-gx10/fc-php/configmap-php-web-config.json new file mode 100644 index 0000000..4b7b73a --- /dev/null +++ b/apps-gx10/fc-php/configmap-php-web-config.json @@ -0,0 +1,11 @@ +{ + "apiVersion": "v1", + "data": { + "appsettings.Production.json": "{\n \"PhpManager\": {\n \"Namespace\": \"fc-php\",\n \"Slowlog\": {\n \"Path\": \"/var/log/apache2/php-fpm-slow.log\",\n \"Sidecar\": {\n \"Enabled\": true,\n \"Image\": \"\"\n }\n },\n \"PoolConfig\": {\n \"StartServers\": null,\n \"MinSpareServers\": null,\n \"MaxSpareServers\": null,\n \"ProcessIdleTimeoutSeconds\": 10,\n \"RequestTerminateTimeoutSeconds\": 30\n },\n \"Certificates\": {\n \"TlsInspector\": {\n \"LogGracefulDegradeWarnings\": false\n }\n },\n \"Backups\": {\n \"StoragePath\": \"/data/backups\"\n }\n },\n \"ApplicationArchives\": {\n \"WordPressCoreUrl\": \"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/wordpress/latest.tar.gz\",\n \"WordPressProxySourceUrl\": \"https://wordpress.org/latest.tar.gz\",\n \"WordPressLocalArchivePath\": \"/data/application-archives/latest.tar.gz\",\n \"MyBbCoreUrl\": \"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/mybb/latest.zip\",\n \"MyBbProxySourceUrl\": \"https://mybb.com/download/\",\n \"MyBbLocalArchivePath\": \"/data/application-archives/mybb-latest.zip\",\n \"MediaWikiCoreUrl\": \"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/mediawiki/latest.tar.gz\",\n \"MediaWikiProxySourceUrl\": \"https://releases.wikimedia.org/mediawiki/1.45/mediawiki-1.45.3.tar.gz\",\n \"MediaWikiLocalArchivePath\": \"/data/application-archives/mediawiki-latest.tar.gz\",\n \"DrupalCoreUrl\": \"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/drupal/latest.tar.gz\",\n \"DrupalProxySourceUrl\": \"https://ftp.drupal.org/files/projects/drupal-11.3.8.tar.gz\",\n \"DrupalLocalArchivePath\": \"/data/application-archives/drupal-latest.tar.gz\",\n \"BypassUpstreamTls\": true\n },\n \"ContainerBackend\": {\n \"Default\": \"Kubernetes\"\n },\n \"FlowerCore\": {\n \"Auth\": {\n \"Provider\": \"Oidc\",\n \"Enabled\": false,\n \"Oidc\": {\n \"Enabled\": true,\n \"Authority\": \"https://id.iamworkin.lan/application/o/php/\",\n \"Audience\": \"php\",\n \"ClientId\": \"php\",\n \"ClientSecret\": \"\"\n },\n \"Impersonation\": {\n \"Enabled\": false,\n \"DebugMode\": false\n }\n },\n \"Tenant\": {\n \"StrictMode\": false,\n \"JwtClaimsEnabled\": false,\n \"TenantClaimType\": \"fc:tenant\",\n \"ActorIdClaimType\": \"flowercore_actor_id\"\n },\n \"Account\": {\n \"AppId\": \"php\",\n \"DefaultTenantId\": \"default\",\n \"Impersonation\": {\n \"Enabled\": false,\n \"StrictMode\": false,\n \"TechSupportRoles\": [ \"tech-support\" ],\n \"Targets\": []\n }\n },\n \"Hosting\": {\n \"AutoDns\": {\n \"Enabled\": true,\n \"DnsManagerBaseUrl\": \"https://dns.iamworkin.lan/\",\n \"ZoneName\": \"iamworkin.lan\",\n \"RecordType\": \"A\",\n \"TargetAddress\": \"10.0.56.200\",\n \"Ttl\": 300,\n \"BypassTls\": true\n }\n },\n \"Database\": {\n \"Provider\": \"Sqlite\",\n \"ConnectionStrings\": {\n \"Sqlite\": \"Data Source=/data/php-manager.db\"\n }\n }\n }\n}\n" + }, + "kind": "ConfigMap", + "metadata": { + "name": "php-web-config", + "namespace": "fc-php" + } +} diff --git a/apps-gx10/fc-php/deployment-php-web.json b/apps-gx10/fc-php/deployment-php-web.json new file mode 100644 index 0000000..0292344 --- /dev/null +++ b/apps-gx10/fc-php/deployment-php-web.json @@ -0,0 +1,209 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "flowercore", + "app.kubernetes.io/name": "php-web" + }, + "name": "php-web", + "namespace": "fc-php" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "php-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-06-13T01:59:27-05:00", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "5400", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "php-web" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "FlowerCore__Auth__Enabled", + "value": "false" + }, + { + "name": "FlowerCore__Auth__Oidc__Authority", + "valueFrom": { + "secretKeyRef": { + "key": "issuer_url", + "name": "php-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientId", + "valueFrom": { + "secretKeyRef": { + "key": "client_id", + "name": "php-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__ClientSecret", + "valueFrom": { + "secretKeyRef": { + "key": "client_secret", + "name": "php-oidc-client", + "optional": true + } + } + }, + { + "name": "FlowerCore__Auth__Oidc__Audience", + "value": "php" + } + ], + "image": "localhost/fc-php-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/metrics/prometheus", + "port": 5400, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "php-web", + "ports": [ + { + "containerPort": 5400, + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/metrics/prometheus", + "port": 5400, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/logs", + "name": "logs" + }, + { + "mountPath": "/app/appsettings.Production.json", + "name": "config", + "readOnly": true, + "subPath": "appsettings.Production.json" + } + ] + } + ], + "dnsConfig": { + "nameservers": [ + "10.43.0.10" + ], + "options": [ + { + "name": "ndots", + "value": "2" + } + ], + "searches": [ + "fc-php.svc.cluster.local", + "svc.cluster.local", + "cluster.local" + ] + }, + "dnsPolicy": "None", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "serviceAccount": "php-web", + "serviceAccountName": "php-web", + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "php-web-data" + } + }, + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + }, + { + "configMap": { + "defaultMode": 420, + "name": "php-web-config" + }, + "name": "config" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-php/service-php-web.json b/apps-gx10/fc-php/service-php-web.json new file mode 100644 index 0000000..11cd367 --- /dev/null +++ b/apps-gx10/fc-php/service-php-web.json @@ -0,0 +1,23 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "name": "php-web", + "namespace": "fc-php" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "port": 5400, + "protocol": "TCP", + "targetPort": 5400 + } + ], + "selector": { + "app.kubernetes.io/name": "php-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-php/serviceaccount-php-web.json b/apps-gx10/fc-php/serviceaccount-php-web.json new file mode 100644 index 0000000..0dfa500 --- /dev/null +++ b/apps-gx10/fc-php/serviceaccount-php-web.json @@ -0,0 +1,8 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "name": "php-web", + "namespace": "fc-php" + } +} diff --git a/apps-gx10/fc-presentations/configmap-presentations-web-config.json b/apps-gx10/fc-presentations/configmap-presentations-web-config.json new file mode 100644 index 0000000..75240e0 --- /dev/null +++ b/apps-gx10/fc-presentations/configmap-presentations-web-config.json @@ -0,0 +1,22 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:8080", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/presentations.db", + "FlowerCore__Database__Provider": "Sqlite", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.Presentations", + "PresentationStorage__HtmlBundlesRelativePath": "uploads/html-bundles", + "PresentationStorage__ImportsRelativePath": "uploads/imports", + "PresentationStorage__SlidesRelativePath": "uploads/slides", + "Security__AllowedOrigins__0": "https://presentations.iamworkin.lan" + }, + "kind": "ConfigMap", + "metadata": { + "name": "presentations-web-config", + "namespace": "fc-presentations" + } +} diff --git a/apps-gx10/fc-presentations/deployment-presentations-web.json b/apps-gx10/fc-presentations/deployment-presentations-web.json new file mode 100644 index 0000000..7aaddc4 --- /dev/null +++ b/apps-gx10/fc-presentations/deployment-presentations-web.json @@ -0,0 +1,143 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "presentations-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "presentations-web", + "namespace": "fc-presentations" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "presentations-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-04-23T14:47:39-05:00", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "presentations-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "presentations-web-config" + } + }, + { + "secretRef": { + "name": "presentations-web-secrets" + } + } + ], + "image": "localhost/fc-presentations:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "presentations-web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data", + "subPath": "data" + }, + { + "mountPath": "/home/app/wwwroot/uploads", + "name": "data", + "subPath": "uploads" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "initContainers": [ + { + "command": [ + "/bin/sh", + "-lc", + "set -eu\nmkdir -p /mnt/pvc/data /mnt/pvc/uploads\n\nfor file in presentations.db presentations.db-shm presentations.db-wal; do\n if [ -f \"/mnt/pvc/${file}\" ] && [ ! -f \"/mnt/pvc/data/${file}\" ]; then\n mv \"/mnt/pvc/${file}\" \"/mnt/pvc/data/${file}\"\n fi\ndone\n\nif [ -d /mnt/pvc/dp-keys ] && [ ! -d /mnt/pvc/data/dp-keys ]; then\n mv /mnt/pvc/dp-keys /mnt/pvc/data/dp-keys\nfi\n\nfor directory in imports slides html-bundles; do\n if [ -d \"/mnt/pvc/${directory}\" ] && [ ! -d \"/mnt/pvc/uploads/${directory}\" ]; then\n mv \"/mnt/pvc/${directory}\" \"/mnt/pvc/uploads/${directory}\"\n fi\ndone\n\nmkdir -p \\\n /mnt/pvc/data/dp-keys \\\n /mnt/pvc/uploads/imports \\\n /mnt/pvc/uploads/slides \\\n /mnt/pvc/uploads/html-bundles\n" + ], + "image": "localhost/fc-presentations:gx10-v1", + "imagePullPolicy": "Never", + "name": "storage-init", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/mnt/pvc", + "name": "data" + } + ] + } + ], + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "presentations-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-presentations/ingressroute-presentations-web.json b/apps-gx10/fc-presentations/ingressroute-presentations-web.json new file mode 100644 index 0000000..d9c4556 --- /dev/null +++ b/apps-gx10/fc-presentations/ingressroute-presentations-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "presentations-web", + "namespace": "fc-presentations" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`presentations.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "presentations-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "presentations-web-tls" + } + } +} diff --git a/apps-gx10/fc-presentations/service-presentations-web.json b/apps-gx10/fc-presentations/service-presentations-web.json new file mode 100644 index 0000000..cf418fc --- /dev/null +++ b/apps-gx10/fc-presentations/service-presentations-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "presentations-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "presentations-web", + "namespace": "fc-presentations" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app.kubernetes.io/name": "presentations-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-retail/configmap-retail-web-config.json b/apps-gx10/fc-retail/configmap-retail-web-config.json new file mode 100644 index 0000000..5df5f64 --- /dev/null +++ b/apps-gx10/fc-retail/configmap-retail-web-config.json @@ -0,0 +1,20 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:5000", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/retail.db", + "FlowerCore__Database__Provider": "Sqlite", + "FlowerCore__Retail__BaseUrl": "https://retail.iamworkin.lan", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.Retail", + "PrintService__BaseUrl": "http://print.iamworkin.lan:5200" + }, + "kind": "ConfigMap", + "metadata": { + "name": "retail-web-config", + "namespace": "fc-retail" + } +} diff --git a/apps-gx10/fc-retail/deployment-retail-web.json b/apps-gx10/fc-retail/deployment-retail-web.json new file mode 100644 index 0000000..df467c1 --- /dev/null +++ b/apps-gx10/fc-retail/deployment-retail-web.json @@ -0,0 +1,111 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "retail-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "retail-web", + "namespace": "fc-retail" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 3, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "retail-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "fc.flowercore.io/healthz-anon": "true", + "fc.flowercore.io/probe-path": "/healthz", + "kubectl.kubernetes.io/restartedAt": "2026-06-02T01:34:08-05:00", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "5000", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "retail-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "retail-web-config" + } + } + ], + "image": "localhost/fc-retail-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "retail-web", + "ports": [ + { + "containerPort": 5000, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "httpGet": { + "path": "/health", + "port": 5000, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "retail-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-retail/ingressroute-retail-web.json b/apps-gx10/fc-retail/ingressroute-retail-web.json new file mode 100644 index 0000000..9effd81 --- /dev/null +++ b/apps-gx10/fc-retail/ingressroute-retail-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "retail-web", + "namespace": "fc-retail" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`retail.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "retail-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "retail-web-tls" + } + } +} diff --git a/apps-gx10/fc-retail/service-retail-web.json b/apps-gx10/fc-retail/service-retail-web.json new file mode 100644 index 0000000..9b4acf3 --- /dev/null +++ b/apps-gx10/fc-retail/service-retail-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "argocd", + "app.kubernetes.io/name": "retail-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "retail-web", + "namespace": "fc-retail" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 5000 + } + ], + "selector": { + "app.kubernetes.io/name": "retail-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-scoreboard/configmap-scoreboard-web-config.json b/apps-gx10/fc-scoreboard/configmap-scoreboard-web-config.json new file mode 100644 index 0000000..e95a6ad --- /dev/null +++ b/apps-gx10/fc-scoreboard/configmap-scoreboard-web-config.json @@ -0,0 +1,21 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:8080", + "Auth__ApiKey": "change-me", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/scoreboard.db", + "FlowerCore__Database__Provider": "Sqlite", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.Scoreboard", + "Security__AllowedOrigins__0": "https://scoreboard.iamworkin.lan", + "Security__ApiKey": "change-me" + }, + "kind": "ConfigMap", + "metadata": { + "name": "scoreboard-web-config", + "namespace": "fc-scoreboard" + } +} diff --git a/apps-gx10/fc-scoreboard/deployment-scoreboard-web.json b/apps-gx10/fc-scoreboard/deployment-scoreboard-web.json new file mode 100644 index 0000000..ac8d2af --- /dev/null +++ b/apps-gx10/fc-scoreboard/deployment-scoreboard-web.json @@ -0,0 +1,132 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "scoreboard-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "scoreboard-web", + "namespace": "fc-scoreboard" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "scoreboard-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-06-12T16:43:22-05:00", + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "scoreboard-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "scoreboard-web-config" + } + } + ], + "image": "localhost/fc-scoreboard-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 5 + }, + "name": "scoreboard-web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + }, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "initContainers": [ + { + "command": [ + "/bin/sh", + "-c", + "chown -R 1654:1654 /data && chmod -R u+rwX,g+rwX /data" + ], + "image": "localhost/fc-scoreboard-web:gx10-v1", + "imagePullPolicy": "Never", + "name": "scoreboard-data-permissions", + "resources": {}, + "securityContext": { + "runAsGroup": 0, + "runAsUser": 0 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "scoreboard-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-scoreboard/ingressroute-scoreboard-web.json b/apps-gx10/fc-scoreboard/ingressroute-scoreboard-web.json new file mode 100644 index 0000000..d5fdc94 --- /dev/null +++ b/apps-gx10/fc-scoreboard/ingressroute-scoreboard-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "scoreboard-web", + "namespace": "fc-scoreboard" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`scoreboard.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "scoreboard-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "scoreboard-web-tls" + } + } +} diff --git a/apps-gx10/fc-scoreboard/service-scoreboard-web.json b/apps-gx10/fc-scoreboard/service-scoreboard-web.json new file mode 100644 index 0000000..35ec4bb --- /dev/null +++ b/apps-gx10/fc-scoreboard/service-scoreboard-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "scoreboard-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "scoreboard-web", + "namespace": "fc-scoreboard" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app.kubernetes.io/name": "scoreboard-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-segmentdisplay/configmap-segmentdisplay-web-config.json b/apps-gx10/fc-segmentdisplay/configmap-segmentdisplay-web-config.json new file mode 100644 index 0000000..6a3ccdf --- /dev/null +++ b/apps-gx10/fc-segmentdisplay/configmap-segmentdisplay-web-config.json @@ -0,0 +1,19 @@ +{ + "apiVersion": "v1", + "data": { + "ASPNETCORE_ENVIRONMENT": "Production", + "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", + "ASPNETCORE_URLS": "http://+:8080", + "FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/segmentdisplay.db", + "FlowerCore__Database__Provider": "Sqlite", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_SERVICE_NAME": "FlowerCore.SegmentDisplay", + "Security__AllowedOrigins__0": "https://segmentdisplay.iamworkin.lan" + }, + "kind": "ConfigMap", + "metadata": { + "name": "segmentdisplay-web-config", + "namespace": "fc-segmentdisplay" + } +} diff --git a/apps-gx10/fc-segmentdisplay/deployment-segmentdisplay-web.json b/apps-gx10/fc-segmentdisplay/deployment-segmentdisplay-web.json new file mode 100644 index 0000000..3c91745 --- /dev/null +++ b/apps-gx10/fc-segmentdisplay/deployment-segmentdisplay-web.json @@ -0,0 +1,113 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "segmentdisplay-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "segmentdisplay-web", + "namespace": "fc-segmentdisplay" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "segmentdisplay-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "prometheus.io/path": "/metrics/prometheus", + "prometheus.io/port": "8080", + "prometheus.io/scrape": "true" + }, + "labels": { + "app.kubernetes.io/name": "segmentdisplay-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "envFrom": [ + { + "configMapRef": { + "name": "segmentdisplay-web-config" + } + }, + { + "secretRef": { + "name": "segmentdisplay-web-secrets", + "optional": true + } + } + ], + "image": "localhost/fc-segmentdisplay-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "name": "segmentdisplay-web", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "httpGet": { + "path": "/health", + "port": 8080, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 5 + }, + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "segmentdisplay-web-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-segmentdisplay/ingressroute-segmentdisplay-web.json b/apps-gx10/fc-segmentdisplay/ingressroute-segmentdisplay-web.json new file mode 100644 index 0000000..36f0474 --- /dev/null +++ b/apps-gx10/fc-segmentdisplay/ingressroute-segmentdisplay-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "segmentdisplay-web", + "namespace": "fc-segmentdisplay" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`segmentdisplay.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "segmentdisplay-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "segmentdisplay-web-tls" + } + } +} diff --git a/apps-gx10/fc-segmentdisplay/service-segmentdisplay-web.json b/apps-gx10/fc-segmentdisplay/service-segmentdisplay-web.json new file mode 100644 index 0000000..91a2430 --- /dev/null +++ b/apps-gx10/fc-segmentdisplay/service-segmentdisplay-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "segmentdisplay-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "segmentdisplay-web", + "namespace": "fc-segmentdisplay" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app.kubernetes.io/name": "segmentdisplay-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-signage/deployment-signage-replay-web.json b/apps-gx10/fc-signage/deployment-signage-replay-web.json new file mode 100644 index 0000000..044b2f4 --- /dev/null +++ b/apps-gx10/fc-signage/deployment-signage-replay-web.json @@ -0,0 +1,151 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "signage-replay-web" + }, + "name": "signage-replay-web", + "namespace": "fc-signage" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "signage-replay-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-05-04T13:50:05-05:00" + }, + "labels": { + "app": "signage-replay-web" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_URLS", + "value": "http://+:5280" + }, + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "ReplayFederation__Signage__Enabled", + "value": "true" + }, + { + "name": "ReplayFederation__Signage__BaseUrl", + "value": "http://signage-web.fc-signage.svc.cluster.local.:5190" + }, + { + "name": "ReplayFederation__Dms__Enabled", + "value": "true" + }, + { + "name": "ReplayFederation__Dms__BaseUrl", + "value": "http://dms-web.fc-dms.svc.cluster.local.:8081" + } + ], + "image": "localhost/fc-signage-replay-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 5280, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 20, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "signage-replay-web", + "ports": [ + { + "containerPort": 5280, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 5280, + "scheme": "HTTP" + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "256Mi" + }, + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/home/app/logs", + "name": "logs" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-signage/deployment-signage-web.json b/apps-gx10/fc-signage/deployment-signage-web.json new file mode 100644 index 0000000..45249ae --- /dev/null +++ b/apps-gx10/fc-signage/deployment-signage-web.json @@ -0,0 +1,230 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "signage-web" + }, + "name": "signage-web", + "namespace": "fc-signage" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "signage-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-05-04T13:50:05-05:00" + }, + "labels": { + "app": "signage-web" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_URLS", + "value": "http://+:5190" + }, + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "TrafficSignal__RelayBridge__Enabled", + "value": "true" + }, + { + "name": "TrafficSignal__RelayBridge__BaseUrl", + "value": "http://pirelay.iamworkin.lan:5100" + }, + { + "name": "DatabaseProvider", + "value": "Sqlite" + }, + { + "name": "ConnectionStrings__DefaultConnection", + "value": "Data Source=/data/signage.db" + }, + { + "name": "Serilog__MinimumLevel__Default", + "value": "Information" + }, + { + "name": "Serilog__WriteTo__0__Name", + "value": "Console" + }, + { + "name": "Kestrel__Endpoints__Http__Url", + "value": "http://+:5190" + }, + { + "name": "Kestrel__Endpoints__Grpc__Url", + "value": "http://+:5191" + }, + { + "name": "FlowerCore__DefaultTenantId", + "value": "default" + }, + { + "name": "FlowerCore__Signage__Announcements__AudibleEnabled", + "value": "true" + }, + { + "name": "FlowerCore__Signage__Announcements__DefaultVoiceName", + "value": "en_US-amy-low" + }, + { + "name": "FlowerCore__Signage__Announcements__Piper__Host", + "value": "10.0.57.17" + }, + { + "name": "FlowerCore__Signage__Announcements__Piper__Port", + "value": "10400" + }, + { + "name": "FlowerCore__Signage__Announcements__Piper__TimeoutSeconds", + "value": "120" + } + ], + "image": "localhost/fc-signage-web:v20260616-tt2-gx10-6a4486e", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 5190, + "scheme": "HTTP" + }, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "signage-web", + "ports": [ + { + "containerPort": 5190, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": 5190, + "scheme": "HTTP" + }, + "initialDelaySeconds": 15, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "10m", + "memory": "256Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "startupProbe": { + "failureThreshold": 30, + "periodSeconds": 5, + "successThreshold": 1, + "tcpSocket": { + "port": 5190 + }, + "timeoutSeconds": 1 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/app/data", + "name": "data" + }, + { + "mountPath": "/app/Cache", + "name": "data" + }, + { + "mountPath": "/app/storage", + "name": "data" + }, + { + "mountPath": "/app/wwwroot/uploads", + "name": "data" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/app/logs", + "name": "logs" + }, + { + "mountPath": "/app/wwwroot/announcement-audio", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 1654, + "runAsGroup": 1654, + "runAsNonRoot": true, + "runAsUser": 1654 + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "signage-data" + } + }, + { + "emptyDir": {}, + "name": "tmp" + }, + { + "emptyDir": {}, + "name": "logs" + } + ] + } + } + } +} diff --git a/apps-gx10/fc-signage/ingressroute-signage-replay-web.json b/apps-gx10/fc-signage/ingressroute-signage-replay-web.json new file mode 100644 index 0000000..fb839a0 --- /dev/null +++ b/apps-gx10/fc-signage/ingressroute-signage-replay-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "signage-replay-web", + "namespace": "fc-signage" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`replay.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "signage-replay-web", + "port": 5280 + } + ] + } + ], + "tls": { + "secretName": "signage-replay-web-tls" + } + } +} diff --git a/apps-gx10/fc-signage/ingressroute-signage-web.json b/apps-gx10/fc-signage/ingressroute-signage-web.json new file mode 100644 index 0000000..c449d65 --- /dev/null +++ b/apps-gx10/fc-signage/ingressroute-signage-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "signage-web", + "namespace": "fc-signage" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`signage.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "signage-web", + "port": 5190 + } + ] + } + ], + "tls": { + "secretName": "signage-web-tls" + } + } +} diff --git a/apps-gx10/fc-signage/service-signage-replay-web.json b/apps-gx10/fc-signage/service-signage-replay-web.json new file mode 100644 index 0000000..9739f45 --- /dev/null +++ b/apps-gx10/fc-signage/service-signage-replay-web.json @@ -0,0 +1,24 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "name": "signage-replay-web", + "namespace": "fc-signage" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 5280, + "protocol": "TCP", + "targetPort": 5280 + } + ], + "selector": { + "app": "signage-replay-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-signage/service-signage-web.json b/apps-gx10/fc-signage/service-signage-web.json new file mode 100644 index 0000000..b0975b9 --- /dev/null +++ b/apps-gx10/fc-signage/service-signage-web.json @@ -0,0 +1,24 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "name": "signage-web", + "namespace": "fc-signage" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 5190, + "protocol": "TCP", + "targetPort": 5190 + } + ], + "selector": { + "app": "signage-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-signalcontrol/deployment-signalcontrol-web.json b/apps-gx10/fc-signalcontrol/deployment-signalcontrol-web.json new file mode 100644 index 0000000..ef8ff93 --- /dev/null +++ b/apps-gx10/fc-signalcontrol/deployment-signalcontrol-web.json @@ -0,0 +1,133 @@ +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app.kubernetes.io/name": "signalcontrol-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "signalcontrol-web", + "namespace": "fc-signalcontrol" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "signalcontrol-web" + } + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2026-04-22T23:55:51-05:00" + }, + "labels": { + "app.kubernetes.io/name": "signalcontrol-web", + "app.kubernetes.io/part-of": "flowercore" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "ASPNETCORE_ENVIRONMENT", + "value": "Production" + }, + { + "name": "ASPNETCORE_URLS", + "value": "http://+:5000" + }, + { + "name": "ConnectionStrings__Default", + "value": "Data Source=/data/signalcontrol.db" + }, + { + "name": "Logging__LogLevel__Default", + "value": "Information" + }, + { + "name": "Auth__ApiKey", + "valueFrom": { + "secretKeyRef": { + "key": "Auth__ApiKey", + "name": "signalcontrol-auth" + } + } + } + ], + "image": "localhost/fc-signalcontrol-web:gx10-v1", + "imagePullPolicy": "Never", + "livenessProbe": { + "failureThreshold": 3, + "initialDelaySeconds": 30, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": "http" + }, + "timeoutSeconds": 5 + }, + "name": "signalcontrol-web", + "ports": [ + { + "containerPort": 5000, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 6, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "successThreshold": 1, + "tcpSocket": { + "port": "http" + }, + "timeoutSeconds": 5 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "512Mi" + }, + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 4200, + "fsGroupChangePolicy": "OnRootMismatch" + }, + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "signalcontrol-data" + } + } + ] + } + } + } +} diff --git a/apps-gx10/fc-signalcontrol/ingressroute-signalcontrol-web.json b/apps-gx10/fc-signalcontrol/ingressroute-signalcontrol-web.json new file mode 100644 index 0000000..6bf726d --- /dev/null +++ b/apps-gx10/fc-signalcontrol/ingressroute-signalcontrol-web.json @@ -0,0 +1,29 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "signalcontrol-web", + "namespace": "fc-signalcontrol" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`signalcontrol.iamworkin.lan`)", + "priority": 100, + "services": [ + { + "name": "signalcontrol-web", + "port": 80 + } + ] + } + ], + "tls": { + "secretName": "signalcontrol-web-tls" + } + } +} diff --git a/apps-gx10/fc-signalcontrol/service-signalcontrol-web.json b/apps-gx10/fc-signalcontrol/service-signalcontrol-web.json new file mode 100644 index 0000000..7777078 --- /dev/null +++ b/apps-gx10/fc-signalcontrol/service-signalcontrol-web.json @@ -0,0 +1,28 @@ +{ + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/name": "signalcontrol-web", + "app.kubernetes.io/part-of": "flowercore" + }, + "name": "signalcontrol-web", + "namespace": "fc-signalcontrol" + }, + "spec": { + "internalTrafficPolicy": "Cluster", + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": "http" + } + ], + "selector": { + "app.kubernetes.io/name": "signalcontrol-web" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + } +} diff --git a/apps-gx10/fc-system/configmap-fc-landing-html.json b/apps-gx10/fc-system/configmap-fc-landing-html.json new file mode 100644 index 0000000..fbaacc5 --- /dev/null +++ b/apps-gx10/fc-system/configmap-fc-landing-html.json @@ -0,0 +1,11 @@ +{ + "apiVersion": "v1", + "data": { + "index.html": "\n\n
\n \n \nBlue Jay Lab
\n\n Multi-tenant service management platform built on .NET 10,\n Kubernetes, and GitOps. Digital signage, telephony IVR,\n MySQL/PHP hosting, and infrastructure automation.\n
\nGitea repositories
\n \n \nWebmail access
\n \n \nMatrix messaging
\n \n \nOpen source
\n \nbluejay.dev
\nComing Soon
\nIt's always time for tacos.
\nerckak.dev
\nComing Soon
\nflowerinsider.xyz
\nComing Soon
\nBuilding something extraordinary.
\n