This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
# Dedicated licensed bulk service. Keep the Service internal unless an authenticated
|
||||
# API gateway is placed in front of it.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ai-disclosure-bulk
|
||||
labels:
|
||||
app.kubernetes.io/name: ai-disclosure-bulk
|
||||
app.kubernetes.io/version: "2.0.0"
|
||||
spec:
|
||||
replicas: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 0
|
||||
maxSurge: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: ai-disclosure-bulk
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: ai-disclosure-bulk
|
||||
app.kubernetes.io/version: "2.0.0"
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/path: /metrics
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: bulk
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard-bulk:2.0.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
env:
|
||||
- name: BASE_URL
|
||||
value: http://ai-disclosure-bulk
|
||||
- name: OUTPUT_BASE_URL
|
||||
value: https://ai.example.org
|
||||
- name: DEFAULT_LANGUAGE
|
||||
value: de
|
||||
- name: SERVICE_MODE
|
||||
value: bulk
|
||||
- name: REQUIRE_LICENSE
|
||||
value: "true"
|
||||
- name: API_ALLOWED_ORIGIN
|
||||
value: ""
|
||||
- name: LICENSE_TOKEN_FILE
|
||||
value: /run/secrets/license/token
|
||||
- name: LICENSE_MODE
|
||||
value: hybrid
|
||||
- name: LICENSE_SERVER_URL
|
||||
value: https://licenses.example.org
|
||||
- name: LICENSE_INSTANCE_ID
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.uid
|
||||
- name: LICENSE_CACHE_FILE
|
||||
value: /data/license-lease.json
|
||||
- name: BULK_REQUIRE_API_KEY
|
||||
value: "true"
|
||||
- name: BULK_API_KEY_FILE
|
||||
value: /run/secrets/bulk/key
|
||||
- name: BULK_MAX_ITEMS
|
||||
value: "500"
|
||||
- name: BULK_MAX_BODY_BYTES
|
||||
value: "4194304"
|
||||
volumeMounts:
|
||||
- name: license-cache
|
||||
mountPath: /data
|
||||
- name: license-token
|
||||
mountPath: /run/secrets/license
|
||||
readOnly: true
|
||||
- name: bulk-api-key
|
||||
mountPath: /run/secrets/bulk
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 192Mi
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: http
|
||||
initialDelaySeconds: 2
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 2
|
||||
failureThreshold: 3
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: license-cache
|
||||
emptyDir: {}
|
||||
- name: license-token
|
||||
secret:
|
||||
secretName: ai-disclosure-commercial
|
||||
items:
|
||||
- key: license-token
|
||||
path: token
|
||||
- name: bulk-api-key
|
||||
secret:
|
||||
secretName: ai-disclosure-commercial
|
||||
items:
|
||||
- key: bulk-api-key
|
||||
path: key
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
whenUnsatisfiable: ScheduleAnyway
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: ai-disclosure-bulk
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ai-disclosure-bulk
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: ai-disclosure-bulk
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: http
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: ai-disclosure-bulk
|
||||
spec:
|
||||
minAvailable: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: ai-disclosure-bulk
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: ai-disclosure-bulk
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: ai-disclosure-bulk
|
||||
minReplicas: 3
|
||||
maxReplicas: 20
|
||||
behavior:
|
||||
scaleDown:
|
||||
stabilizationWindowSeconds: 300
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 65
|
||||
+28
-33
@@ -4,6 +4,7 @@ metadata:
|
||||
name: ai-disclosure
|
||||
labels:
|
||||
app.kubernetes.io/name: ai-disclosure
|
||||
app.kubernetes.io/version: "2.0.0"
|
||||
spec:
|
||||
replicas: 3
|
||||
strategy:
|
||||
@@ -18,14 +19,20 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: ai-disclosure
|
||||
app.kubernetes.io/version: "2.0.0"
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/path: /metrics
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: app
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.0
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:2.0.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
@@ -37,42 +44,18 @@ spec:
|
||||
value: AI Usage Disclosure
|
||||
- name: CONTACT_URL
|
||||
value: https://b1tsblog.org/page/ai
|
||||
- name: SALES_URL
|
||||
value: https://b1tsblog.org/page/ai
|
||||
- name: DEFAULT_LANGUAGE
|
||||
value: de
|
||||
- name: TRUST_PROXY
|
||||
value: "false"
|
||||
- name: LOG_CLIENT_IP
|
||||
value: "false"
|
||||
- name: ENABLE_HSTS
|
||||
value: "true"
|
||||
- name: METRICS_ENABLED
|
||||
value: "false"
|
||||
# Replace the following values before deployment. LEGAL_STRICT
|
||||
# deliberately prevents accidental public startup with placeholders.
|
||||
- name: LEGAL_STRICT
|
||||
value: "true"
|
||||
- name: LEGAL_NAME
|
||||
value: REPLACE_ME
|
||||
- name: LEGAL_ADDRESS
|
||||
value: REPLACE_ME
|
||||
- name: LEGAL_EMAIL
|
||||
value: REPLACE_ME
|
||||
- name: HOSTING_PROVIDER
|
||||
value: REPLACE_ME
|
||||
- name: LOG_RETENTION
|
||||
value: REPLACE_ME
|
||||
- name: CONSUMER_DISPUTE_STATUS
|
||||
value: REPLACE_ME
|
||||
- name: LICENSE_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ai-disclosure-license
|
||||
key: token
|
||||
optional: true
|
||||
- name: SERVICE_MODE
|
||||
value: full
|
||||
- name: API_ALLOWED_ORIGIN
|
||||
value: "*"
|
||||
- name: LICENSE_TOKEN_FILE
|
||||
value: /run/secrets/license/token
|
||||
- name: LICENSE_MODE
|
||||
value: offline
|
||||
value: hybrid
|
||||
- name: LICENSE_SERVER_URL
|
||||
value: ""
|
||||
- name: LICENSE_INSTANCE_ID
|
||||
@@ -81,13 +64,18 @@ spec:
|
||||
fieldPath: metadata.uid
|
||||
- name: LICENSE_CACHE_FILE
|
||||
value: /data/license-lease.json
|
||||
- name: WHITE_LABEL
|
||||
value: "false"
|
||||
volumeMounts:
|
||||
- name: license-cache
|
||||
mountPath: /data
|
||||
- name: license-token
|
||||
mountPath: /run/secrets/license
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 24Mi
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
@@ -115,6 +103,13 @@ spec:
|
||||
volumes:
|
||||
- name: license-cache
|
||||
emptyDir: {}
|
||||
- name: license-token
|
||||
secret:
|
||||
secretName: ai-disclosure-license
|
||||
optional: true
|
||||
items:
|
||||
- key: token
|
||||
path: token
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: universal-license-server
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: universal-license-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: universal-license-server
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: server
|
||||
image: ghcr.io/REPLACE_ME/universal-license-server:1.5.0
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8091
|
||||
env:
|
||||
- name: LICENSE_SERVER_ADDRESS
|
||||
value: :8091
|
||||
- name: LICENSE_SERVER_DATA
|
||||
value: /data/licenses.json
|
||||
- name: LICENSE_TRUST_STORE_FILE
|
||||
value: /config/trusted-keys.json
|
||||
- name: LEASE_SIGNING_KEY_ID
|
||||
value: lease-2026
|
||||
- name: LEASE_SIGNING_PRIVATE_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: universal-license-secrets
|
||||
key: lease-private-key
|
||||
- name: LICENSE_SERVER_ADMIN_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: universal-license-secrets
|
||||
key: admin-token
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: trust-store
|
||||
mountPath: /config
|
||||
readOnly: true
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: universal-license-data
|
||||
- name: trust-store
|
||||
configMap:
|
||||
name: universal-license-trust-store
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: universal-license-server
|
||||
spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: universal-license-server
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: http
|
||||
@@ -0,0 +1,61 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
bulk:
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard-bulk:2.0.0
|
||||
environment:
|
||||
BASE_URL: http://bulk:8080
|
||||
OUTPUT_BASE_URL: https://ai.example.org
|
||||
DEFAULT_LANGUAGE: de
|
||||
SERVICE_MODE: bulk
|
||||
API_ALLOWED_ORIGIN: ""
|
||||
LICENSE_TOKEN_FILE: /run/secrets/license_token
|
||||
LICENSE_MODE: "${LICENSE_MODE:-hybrid}"
|
||||
LICENSE_SERVER_URL: "${LICENSE_SERVER_URL:-https://licenses.example.org}"
|
||||
LICENSE_INSTANCE_ID: "${LICENSE_INSTANCE_ID:-swarm-bulk}"
|
||||
LICENSE_CACHE_FILE: /data/license-lease.json
|
||||
REQUIRE_LICENSE: "true"
|
||||
BULK_REQUIRE_API_KEY: "true"
|
||||
BULK_API_KEY_FILE: /run/secrets/bulk_api_key
|
||||
BULK_MAX_ITEMS: "${BULK_MAX_ITEMS:-500}"
|
||||
BULK_MAX_BODY_BYTES: "${BULK_MAX_BODY_BYTES:-4194304}"
|
||||
secrets:
|
||||
- license_token
|
||||
- bulk_api_key
|
||||
networks: [internal]
|
||||
volumes:
|
||||
- bulk-license-cache:/data
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp:size=16m,mode=1777
|
||||
cap_drop: [ALL]
|
||||
healthcheck:
|
||||
test: ["CMD", "/ai-disclosure", "--healthcheck"]
|
||||
interval: 15s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
deploy:
|
||||
replicas: 3
|
||||
update_config:
|
||||
order: start-first
|
||||
parallelism: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
resources:
|
||||
reservations:
|
||||
cpus: "0.05"
|
||||
memory: 32M
|
||||
limits:
|
||||
cpus: "1.0"
|
||||
memory: 192M
|
||||
secrets:
|
||||
license_token:
|
||||
external: true
|
||||
bulk_api_key:
|
||||
external: true
|
||||
networks:
|
||||
internal:
|
||||
driver: overlay
|
||||
attachable: false
|
||||
volumes:
|
||||
bulk-license-cache:
|
||||
+8
-19
@@ -1,43 +1,33 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
app:
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.0
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:2.0.0
|
||||
environment:
|
||||
BASE_URL: https://ai.example.org
|
||||
PUBLIC_NAME: AI Usage Disclosure
|
||||
CONTACT_URL: https://b1tsblog.org/page/ai
|
||||
SALES_URL: "${SALES_URL:-https://b1tsblog.org/page/ai}"
|
||||
DEFAULT_LANGUAGE: de
|
||||
TRUST_PROXY: "false"
|
||||
LOG_CLIENT_IP: "false"
|
||||
ENABLE_HSTS: "true"
|
||||
METRICS_ENABLED: "false"
|
||||
LEGAL_STRICT: "${LEGAL_STRICT:-true}"
|
||||
LEGAL_NAME: "${LEGAL_NAME:-REPLACE_ME}"
|
||||
LEGAL_ADDRESS: "${LEGAL_ADDRESS:-REPLACE_ME}"
|
||||
LEGAL_EMAIL: "${LEGAL_EMAIL:-REPLACE_ME}"
|
||||
HOSTING_PROVIDER: "${HOSTING_PROVIDER:-REPLACE_ME}"
|
||||
LOG_RETENTION: "${LOG_RETENTION:-REPLACE_ME}"
|
||||
CONSUMER_DISPUTE_STATUS: "${CONSUMER_DISPUTE_STATUS:-REPLACE_ME}"
|
||||
TRUST_PROXY: "true"
|
||||
SERVICE_MODE: full
|
||||
API_ALLOWED_ORIGIN: "*"
|
||||
LICENSE_TOKEN: "${LICENSE_TOKEN:-}"
|
||||
LICENSE_MODE: "${LICENSE_MODE:-offline}"
|
||||
LICENSE_SERVER_URL: "${LICENSE_SERVER_URL:-}"
|
||||
LICENSE_INSTANCE_ID: "${LICENSE_INSTANCE_ID:-swarm}"
|
||||
LICENSE_CACHE_FILE: /data/license-lease.json
|
||||
WHITE_LABEL: "${WHITE_LABEL:-false}"
|
||||
ports:
|
||||
- target: 8080
|
||||
published: 8080
|
||||
protocol: tcp
|
||||
mode: ingress
|
||||
networks:
|
||||
- public
|
||||
networks: [public]
|
||||
volumes:
|
||||
- license-cache:/data
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp:size=16m,mode=1777
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_drop: [ALL]
|
||||
healthcheck:
|
||||
test: ["CMD", "/ai-disclosure", "--healthcheck"]
|
||||
interval: 15s
|
||||
@@ -67,7 +57,7 @@ services:
|
||||
resources:
|
||||
reservations:
|
||||
cpus: "0.05"
|
||||
memory: 24M
|
||||
memory: 32M
|
||||
limits:
|
||||
cpus: "0.50"
|
||||
memory: 128M
|
||||
@@ -75,6 +65,5 @@ networks:
|
||||
public:
|
||||
driver: overlay
|
||||
attachable: true
|
||||
|
||||
volumes:
|
||||
license-cache:
|
||||
|
||||
Reference in New Issue
Block a user