feat: add development kubernetes mtls overlay
This commit is contained in:
parent
2124523cef
commit
4f49473cdd
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@ -22,10 +22,13 @@ jobs:
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PROXY_POOL_GATEWAY_USERNAME: ci-gateway-user
|
||||
PROXY_POOL_GATEWAY_PASSWORD: ci-gateway-password
|
||||
PROXY_POOL_EXTRACT_TOKEN: ci-extract-token
|
||||
PROXY_POOL_ADMIN_TOKEN: ci-admin-token
|
||||
PROXY_POOL_CONFIG_FINGERPRINT_KEY: ci-config-fingerprint-key-at-least-32-bytes
|
||||
PROXY_POOL_POSTGRES_URL: postgres://ci:ci@postgres.example:5432/proxy_pool?sslmode=verify-full
|
||||
PROXY_POOL_REDIS_URL: rediss://:ci@redis.example:6379/0
|
||||
PROVIDER_A_TOKEN: ci-provider-a-token
|
||||
PROVIDER_B_TOKEN: ci-provider-b-token
|
||||
steps:
|
||||
@ -34,6 +37,10 @@ jobs:
|
||||
run: docker compose -f deploy/docker-compose.yml config --quiet
|
||||
- name: Render Kubernetes base
|
||||
run: kubectl kustomize deploy/kubernetes/base > /dev/null
|
||||
- name: Render Kubernetes development mTLS overlay
|
||||
run: kubectl kustomize deploy/kubernetes/overlays/development-mtls > /dev/null
|
||||
- name: Validate development mTLS configuration
|
||||
run: go run ./deploy/tools/configcheck deploy/kubernetes/overlays/development-mtls/config.yaml
|
||||
|
||||
test:
|
||||
strategy:
|
||||
|
||||
@ -164,7 +164,7 @@ go run ./deploy/tools/configcheck deploy/config/local.yaml
|
||||
```
|
||||
|
||||
`package-docs.ps1` 默认生成被忽略的 `dist/proxy-pool-docs-v1.0.zip`;包内包含 README、
|
||||
`docs/`、图表、OpenAPI 和 Proto 契约,并以 `manifest.json` 记录 Git revision、文件大小和
|
||||
`docs/`、图表、OpenAPI、Proto 契约和部署手册,并以 `manifest.json` 记录 Git revision、文件大小和
|
||||
SHA-256。可使用 `-Version vMAJOR.MINOR[.PATCH]` 与 `-OutputPath OUTPUT.zip` 生成指定交付物。
|
||||
`benchmark-gateway.ps1` 固定执行一次 100k 索引调度、Routing Round Robin 和 Snapshot Apply
|
||||
微基准,并把版本与原始输出写入 `dist/gateway-benchmarks.txt`;它用于回归比较,不构成
|
||||
|
||||
@ -14,9 +14,11 @@ SPIFFE URI 证书,私钥只写入被忽略的 `deploy/.control-plane-tls/`。
|
||||
docker compose -f deploy/docker-compose.yml up -d --build
|
||||
```
|
||||
|
||||
Kubernetes Base 仍保持 `controlPlane.enabled: false`,并保留 `checker.yaml` 作为
|
||||
环境 Overlay 模板。生产 Overlay 必须为每个弹性 Gateway/Checker 工作负载配置唯一
|
||||
身份与证书轮换,不能复用 Compose 的固定开发证书。
|
||||
Kubernetes Base 仍保持 `controlPlane.enabled: false`。`kubernetes/overlays/development-mtls`
|
||||
启用单副本 Controller/Gateway/Checker mTLS 拓扑,挂载三组外部 TLS Secret,并固定
|
||||
`gateway-a`、`checker-a` 身份。具体创建 Secret 和部署步骤见
|
||||
[development mTLS overlay](kubernetes/overlays/development-mtls/README.md)。生产 Overlay
|
||||
必须为每个弹性 Gateway/Checker 工作负载配置唯一身份与证书轮换,不能复用固定开发证书。
|
||||
|
||||
当前可执行验证:
|
||||
|
||||
@ -24,6 +26,7 @@ Kubernetes Base 仍保持 `controlPlane.enabled: false`,并保留 `checker.yam
|
||||
docker compose -f deploy/docker-compose.yml config --quiet
|
||||
docker compose -f deploy/docker-compose.test.yml config --quiet
|
||||
kubectl kustomize deploy/kubernetes/base | Out-Null
|
||||
kubectl kustomize deploy/kubernetes/overlays/development-mtls | Out-Null
|
||||
go run ./deploy/tools/configcheck deploy/config/local.yaml
|
||||
```
|
||||
|
||||
|
||||
@ -31,6 +31,8 @@ func TestCIValidatesProtocolAndDeploymentAssets(t *testing.T) {
|
||||
"./scripts/verify-proto.ps1",
|
||||
"docker compose -f deploy/docker-compose.yml config --quiet",
|
||||
"kubectl kustomize deploy/kubernetes/base",
|
||||
"kubectl kustomize deploy/kubernetes/overlays/development-mtls",
|
||||
"go run ./deploy/tools/configcheck deploy/kubernetes/overlays/development-mtls/config.yaml",
|
||||
} {
|
||||
if !strings.Contains(workflow, required) {
|
||||
t.Errorf("ci workflow does not validate %q", required)
|
||||
|
||||
56
deploy/kubernetes/overlays/development-mtls/README.md
Normal file
56
deploy/kubernetes/overlays/development-mtls/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
# Kubernetes development mTLS overlay
|
||||
|
||||
该 Overlay 在 base 资源之上启用 Controller 控制面 mTLS,并启动一个固定身份的 Gateway
|
||||
和 Checker。它只用于开发或预发布的单副本控制面验证,不是生产弹性身份方案。
|
||||
|
||||
## Prepare certificates
|
||||
|
||||
先生成未提交的开发证书。输出目录必须为空;生成器的 `controller` 证书包含
|
||||
`DNS:controller`,Overlay 中的客户端也只拨号 `controller:8443`。
|
||||
|
||||
```powershell
|
||||
./scripts/generate-local-controlplane-certs.ps1
|
||||
kubectl apply -f deploy/kubernetes/base/namespace.yaml
|
||||
```
|
||||
|
||||
将生成的三组证书写入 Kubernetes Secret。下面的命令可重复执行,只更新对应 Secret:
|
||||
|
||||
```powershell
|
||||
kubectl -n proxy-pool create secret generic proxy-pool-controlplane-server-tls `
|
||||
--from-file=tls.crt=deploy/.control-plane-tls/controller/tls.crt `
|
||||
--from-file=tls.key=deploy/.control-plane-tls/controller/tls.key `
|
||||
--from-file=ca.crt=deploy/.control-plane-tls/controller/ca.crt `
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
kubectl -n proxy-pool create secret generic proxy-pool-controlplane-gateway-tls `
|
||||
--from-file=tls.crt=deploy/.control-plane-tls/gateway-a/tls.crt `
|
||||
--from-file=tls.key=deploy/.control-plane-tls/gateway-a/tls.key `
|
||||
--from-file=ca.crt=deploy/.control-plane-tls/gateway-a/ca.crt `
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
kubectl -n proxy-pool create secret generic proxy-pool-controlplane-checker-tls `
|
||||
--from-file=tls.crt=deploy/.control-plane-tls/checker-a/tls.crt `
|
||||
--from-file=tls.key=deploy/.control-plane-tls/checker-a/tls.key `
|
||||
--from-file=ca.crt=deploy/.control-plane-tls/checker-a/ca.crt `
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
```
|
||||
|
||||
另行从私密配置系统创建 `proxy-pool-secrets`。可参考 base 目录的
|
||||
`secret.example.yaml`,但不要把实际数据库、Redis、Provider 或 API 凭据写入 Git。
|
||||
|
||||
## Deploy
|
||||
|
||||
```powershell
|
||||
kubectl apply -k deploy/kubernetes/overlays/development-mtls
|
||||
kubectl -n proxy-pool rollout status deployment/proxy-controller --timeout=5m
|
||||
kubectl -n proxy-pool rollout status deployment/proxy-gateway --timeout=5m
|
||||
kubectl -n proxy-pool rollout status deployment/proxy-checker --timeout=5m
|
||||
```
|
||||
|
||||
Overlay 的 Gateway 固定为 `worker_id=gateway-a`,Checker 固定为
|
||||
`checker_id=checker-a`,并把 Gateway HPA 限制为 `minReplicas=maxReplicas=1`。
|
||||
因此不得在此 Overlay 上增加副本数或放宽 HPA;重复使用同一 Worker 身份会破坏
|
||||
session、ownership 和证书角色边界。
|
||||
|
||||
生产环境需要由工作负载身份系统为每个副本签发独立、可轮换的证书,并将该副本的
|
||||
身份注入 `worker_id`、`instance_id`、Gateway Client TLS 或 Checker Client TLS。
|
||||
@ -0,0 +1,24 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: checker-control-plane
|
||||
namespace: proxy-pool
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels: {app.kubernetes.io/name: proxy-checker}
|
||||
policyTypes: [Ingress, Egress]
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: monitoring}}
|
||||
ports: [{port: 9090, protocol: TCP}]
|
||||
egress:
|
||||
- to:
|
||||
- namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: kube-system}}
|
||||
ports: [{port: 53, protocol: UDP}, {port: 53, protocol: TCP}]
|
||||
- to:
|
||||
- podSelector: {matchLabels: {app.kubernetes.io/name: proxy-controller}}
|
||||
ports: [{port: 8443, protocol: TCP}]
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except: [10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16]
|
||||
@ -0,0 +1,24 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: proxy-checker
|
||||
namespace: proxy-pool
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: checker
|
||||
env:
|
||||
- {name: PROXY_POOL_CONTROL_PLANE_ADDRESS, value: controller:8443}
|
||||
- {name: PROXY_POOL_CHECKER_ID, value: checker-a}
|
||||
- {name: PROXY_POOL_CHECKER_INSTANCE_ID, value: checker-a-1}
|
||||
- {name: PROXY_POOL_CHECKER_MAX_IN_FLIGHT, value: "200"}
|
||||
volumeMounts:
|
||||
- name: controlplane-checker-tls
|
||||
mountPath: /run/proxy-pool-tls/client
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: controlplane-checker-tls
|
||||
secret:
|
||||
secretName: proxy-pool-controlplane-checker-tls
|
||||
65
deploy/kubernetes/overlays/development-mtls/checker.yaml
Normal file
65
deploy/kubernetes/overlays/development-mtls/checker.yaml
Normal file
@ -0,0 +1,65 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: proxy-checker
|
||||
namespace: proxy-pool
|
||||
labels: {app.kubernetes.io/name: proxy-checker, app.kubernetes.io/part-of: proxy-pool}
|
||||
spec:
|
||||
replicas: 1
|
||||
minReadySeconds: 5
|
||||
revisionHistoryLimit: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate: {maxUnavailable: 1, maxSurge: 1}
|
||||
selector:
|
||||
matchLabels: {app.kubernetes.io/name: proxy-checker}
|
||||
template:
|
||||
metadata:
|
||||
labels: {app.kubernetes.io/name: proxy-checker, app.kubernetes.io/part-of: proxy-pool}
|
||||
annotations: {prometheus.io/scrape: "true", prometheus.io/port: "9090", prometheus.io/path: /metrics}
|
||||
spec:
|
||||
serviceAccountName: proxy-pool
|
||||
automountServiceAccountToken: false
|
||||
terminationGracePeriodSeconds: 45
|
||||
securityContext: {runAsNonRoot: true, seccompProfile: {type: RuntimeDefault}}
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
whenUnsatisfiable: ScheduleAnyway
|
||||
labelSelector: {matchLabels: {app.kubernetes.io/name: proxy-checker}}
|
||||
containers:
|
||||
- name: checker
|
||||
image: REGISTRY/proxy-pool:VERSION
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: [proxy-checker]
|
||||
env:
|
||||
- {name: PROXY_POOL_CONFIG, value: /etc/proxy-pool/config.yaml}
|
||||
envFrom:
|
||||
- secretRef: {name: proxy-pool-secrets}
|
||||
ports:
|
||||
- {name: metrics, containerPort: 9090}
|
||||
readinessProbe:
|
||||
httpGet: {path: /readyz, port: metrics}
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
livenessProbe:
|
||||
httpGet: {path: /livez, port: metrics}
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 2
|
||||
lifecycle:
|
||||
preStop: {exec: {command: [sh, -c, "sleep 3"]}}
|
||||
resources:
|
||||
requests: {cpu: "1", memory: 512Mi}
|
||||
limits: {cpu: "2", memory: 1Gi}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities: {drop: [ALL]}
|
||||
volumeMounts:
|
||||
- {name: config, mountPath: /etc/proxy-pool, readOnly: true}
|
||||
- {name: tmp, mountPath: /tmp}
|
||||
volumes:
|
||||
- name: config
|
||||
configMap: {name: proxy-pool-config}
|
||||
- name: tmp
|
||||
emptyDir: {sizeLimit: 64Mi}
|
||||
216
deploy/kubernetes/overlays/development-mtls/config.yaml
Normal file
216
deploy/kubernetes/overlays/development-mtls/config.yaml
Normal file
@ -0,0 +1,216 @@
|
||||
version: 1
|
||||
|
||||
security:
|
||||
requireProtectionOnPublicListen: true
|
||||
|
||||
gateway:
|
||||
enabled: true
|
||||
listen: 0.0.0.0:8080
|
||||
access:
|
||||
allowCIDRs: [0.0.0.0/0]
|
||||
trustedProxies: []
|
||||
auth:
|
||||
mode: usernamePassword
|
||||
username: "${PROXY_POOL_GATEWAY_USERNAME}"
|
||||
password: "${PROXY_POOL_GATEWAY_PASSWORD}"
|
||||
limits:
|
||||
maxConcurrentConnections: 20000
|
||||
requestsPerMinutePerClient: 60000
|
||||
transport:
|
||||
maxIdleConns: 20000
|
||||
maxIdleConnsPerHost: 32
|
||||
maxConnsPerHost: 32
|
||||
tunnelBufferBytes: 32768
|
||||
retry:
|
||||
maxAttempts: 2
|
||||
retryMethods: [GET, HEAD]
|
||||
destinationPolicy:
|
||||
denyPrivateNetworks: true
|
||||
denyLoopback: true
|
||||
denyLinkLocal: true
|
||||
denyCIDRs: [169.254.169.254/32]
|
||||
|
||||
distribution:
|
||||
enabled: true
|
||||
listen: 0.0.0.0:8081
|
||||
access:
|
||||
allowCIDRs: [10.0.0.0/8]
|
||||
trustedProxies: [10.0.0.0/8]
|
||||
auth:
|
||||
mode: apiKey
|
||||
header: X-API-Key
|
||||
token: "${PROXY_POOL_EXTRACT_TOKEN}"
|
||||
limits:
|
||||
requestsPerMinute: 6000
|
||||
requestsPerMinutePerClient: 600
|
||||
clientIdentification:
|
||||
mode: sourceIP
|
||||
extraction:
|
||||
fulfillment: partial
|
||||
maxCountPerRequest: 100
|
||||
minRemainingTTL: 30s
|
||||
maxHealthCheckAge: 30s
|
||||
reserveForGateway: 1000
|
||||
idempotencyTTL: 5m
|
||||
|
||||
admin:
|
||||
enabled: true
|
||||
listen: 0.0.0.0:8082
|
||||
access:
|
||||
allowCIDRs: [10.0.0.0/8]
|
||||
auth:
|
||||
mode: apiKey
|
||||
header: X-Admin-Key
|
||||
token: "${PROXY_POOL_ADMIN_TOKEN}"
|
||||
|
||||
controlPlane:
|
||||
enabled: true
|
||||
listen: 0.0.0.0:8443
|
||||
protocolVersion: 1
|
||||
heartbeatInterval: 10s
|
||||
sessionTTL: 30s
|
||||
maxStaleAge: 30s
|
||||
maxMessageBytes: 4194304
|
||||
maxRuntimeCounters: 100000
|
||||
maxConcurrentStreams: 1000
|
||||
tls:
|
||||
mode: mtls
|
||||
certFile: /run/proxy-pool-tls/server/tls.crt
|
||||
keyFile: /run/proxy-pool-tls/server/tls.key
|
||||
clientCAFile: /run/proxy-pool-tls/server/ca.crt
|
||||
trustDomain: proxy-pool.local
|
||||
environment: development
|
||||
gatewayTLS:
|
||||
certFile: /run/proxy-pool-tls/client/tls.crt
|
||||
keyFile: /run/proxy-pool-tls/client/tls.key
|
||||
serverCAFile: /run/proxy-pool-tls/client/ca.crt
|
||||
checkerTLS:
|
||||
certFile: /run/proxy-pool-tls/client/tls.crt
|
||||
keyFile: /run/proxy-pool-tls/client/tls.key
|
||||
serverCAFile: /run/proxy-pool-tls/client/ca.crt
|
||||
|
||||
metrics:
|
||||
enabled: true
|
||||
listen: 0.0.0.0:9090
|
||||
|
||||
storage:
|
||||
postgresURL: "${PROXY_POOL_POSTGRES_URL}"
|
||||
redisURL: "${PROXY_POOL_REDIS_URL}"
|
||||
|
||||
routing:
|
||||
- name: gateway-default
|
||||
enabled: true
|
||||
purpose: gateway
|
||||
upstreams: [provider-a, provider-b]
|
||||
strategy:
|
||||
type: sequential
|
||||
switchAfterEmptyFetch: 5
|
||||
endBehavior: stayLast
|
||||
onUnavailable:
|
||||
action: reject
|
||||
- name: extract-default
|
||||
enabled: true
|
||||
purpose: extract
|
||||
upstreams: [provider-a, provider-b]
|
||||
strategy:
|
||||
type: sequential
|
||||
switchAfterEmptyFetch: 5
|
||||
endBehavior: stayLast
|
||||
onUnavailable:
|
||||
action: reject
|
||||
|
||||
upstreams:
|
||||
provider-a:
|
||||
enabled: true
|
||||
exposure: [gateway, extract]
|
||||
provider:
|
||||
billingMode: fetch
|
||||
protocols: [http]
|
||||
api:
|
||||
url: https://provider-a.invalid/api/proxies
|
||||
method: GET
|
||||
auth:
|
||||
type: apiKey
|
||||
location: header
|
||||
name: Authorization
|
||||
value: "${PROVIDER_A_TOKEN}"
|
||||
template: '{{ . }}'
|
||||
proxyAuth:
|
||||
type: response
|
||||
pool:
|
||||
maxSize: 5000
|
||||
shrinkDelay: 30s
|
||||
capacity:
|
||||
maxConcurrencyPerProxy: 20
|
||||
refill:
|
||||
reconcileInterval: 1s
|
||||
minimumAvailableSlots: 8000
|
||||
targetAvailableSlots: 12000
|
||||
lifecycle:
|
||||
ttl: 5m
|
||||
allocationSafetyMargin: 20s
|
||||
fetch:
|
||||
estimatedIPsPerCall: 100
|
||||
requestInterval: 1s
|
||||
timeout: 3s
|
||||
maxAttempts: 3
|
||||
maxInFlight: 1
|
||||
maxTotal: 100000
|
||||
maxResponseBytes: 4194304
|
||||
templateTimeout: 100ms
|
||||
retry: {initial: 500ms, max: 30s, jitter: 20}
|
||||
check:
|
||||
interval: 30s
|
||||
jitter: 20
|
||||
maxInFlight: 200
|
||||
timeout: 3s
|
||||
maxAttempts: 2
|
||||
maxConsecutiveFailures: 3
|
||||
urls: [https://example.com/]
|
||||
provider-b:
|
||||
enabled: true
|
||||
exposure: [gateway, extract]
|
||||
provider:
|
||||
billingMode: fetch
|
||||
protocols: [http]
|
||||
api:
|
||||
url: https://provider-b.invalid/api/proxies
|
||||
method: GET
|
||||
auth:
|
||||
type: apiKey
|
||||
location: header
|
||||
name: Authorization
|
||||
value: "${PROVIDER_B_TOKEN}"
|
||||
template: '{{ . }}'
|
||||
proxyAuth:
|
||||
type: response
|
||||
pool:
|
||||
maxSize: 5000
|
||||
shrinkDelay: 30s
|
||||
capacity:
|
||||
maxConcurrencyPerProxy: 20
|
||||
refill:
|
||||
reconcileInterval: 1s
|
||||
minimumAvailableSlots: 8000
|
||||
targetAvailableSlots: 12000
|
||||
lifecycle:
|
||||
ttl: 5m
|
||||
allocationSafetyMargin: 20s
|
||||
fetch:
|
||||
estimatedIPsPerCall: 100
|
||||
requestInterval: 1s
|
||||
timeout: 3s
|
||||
maxAttempts: 3
|
||||
maxInFlight: 1
|
||||
maxTotal: 100000
|
||||
maxResponseBytes: 4194304
|
||||
templateTimeout: 100ms
|
||||
retry: {initial: 500ms, max: 30s, jitter: 20}
|
||||
check:
|
||||
interval: 30s
|
||||
jitter: 20
|
||||
maxInFlight: 200
|
||||
timeout: 3s
|
||||
maxAttempts: 2
|
||||
maxConsecutiveFailures: 3
|
||||
urls: [https://example.com/]
|
||||
@ -0,0 +1,19 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: proxy-controller
|
||||
namespace: proxy-pool
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: controller
|
||||
volumeMounts:
|
||||
- name: controlplane-server-tls
|
||||
mountPath: /run/proxy-pool-tls/server
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: controlplane-server-tls
|
||||
secret:
|
||||
secretName: proxy-pool-controlplane-server-tls
|
||||
@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: controller
|
||||
namespace: proxy-pool
|
||||
labels: {app.kubernetes.io/name: proxy-controller}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector: {app.kubernetes.io/name: proxy-controller}
|
||||
ports:
|
||||
- {name: control, port: 8443, targetPort: control}
|
||||
@ -0,0 +1,8 @@
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: proxy-gateway
|
||||
namespace: proxy-pool
|
||||
spec:
|
||||
minReplicas: 1
|
||||
maxReplicas: 1
|
||||
@ -0,0 +1,25 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: proxy-gateway
|
||||
namespace: proxy-pool
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: gateway
|
||||
env:
|
||||
- {name: PROXY_POOL_CONTROL_PLANE_ADDRESS, value: controller:8443}
|
||||
- {name: PROXY_POOL_CLUSTER_ID, value: kubernetes-development}
|
||||
- {name: PROXY_POOL_WORKER_ID, value: gateway-a}
|
||||
- {name: PROXY_POOL_INSTANCE_ID, value: gateway-a-1}
|
||||
- {name: PROXY_POOL_ZONE, value: kubernetes-development}
|
||||
volumeMounts:
|
||||
- name: controlplane-gateway-tls
|
||||
mountPath: /run/proxy-pool-tls/client
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: controlplane-gateway-tls
|
||||
secret:
|
||||
secretName: proxy-pool-controlplane-gateway-tls
|
||||
@ -0,0 +1,20 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../../base
|
||||
- checker.yaml
|
||||
- controller-service.yaml
|
||||
- checker-networkpolicy.yaml
|
||||
configMapGenerator:
|
||||
- name: proxy-pool-config
|
||||
namespace: proxy-pool
|
||||
behavior: replace
|
||||
files:
|
||||
- config.yaml
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
patches:
|
||||
- path: controller-patch.yaml
|
||||
- path: gateway-patch.yaml
|
||||
- path: checker-patch.yaml
|
||||
- path: gateway-hpa-patch.yaml
|
||||
39
deploy/kubernetes_overlay_test.go
Normal file
39
deploy/kubernetes_overlay_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKubernetesDevelopmentMTLSOverlayRendersStaticWorkerIdentities(t *testing.T) {
|
||||
kubectl, err := exec.LookPath("kubectl")
|
||||
if err != nil {
|
||||
t.Skip("kubectl is required to render the Kubernetes development mTLS overlay")
|
||||
}
|
||||
command := exec.Command(kubectl, "kustomize", "kubernetes/overlays/development-mtls")
|
||||
command.Dir = "."
|
||||
payload, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("render development mTLS overlay: %v\n%s", err, payload)
|
||||
}
|
||||
rendered := string(payload)
|
||||
for _, required := range []string{
|
||||
"mode: mtls",
|
||||
"trustDomain: proxy-pool.local",
|
||||
"value: controller:8443",
|
||||
"value: gateway-a",
|
||||
"value: checker-a",
|
||||
"secretName: proxy-pool-controlplane-server-tls",
|
||||
"secretName: proxy-pool-controlplane-gateway-tls",
|
||||
"secretName: proxy-pool-controlplane-checker-tls",
|
||||
"name: proxy-checker",
|
||||
"name: checker-control-plane",
|
||||
"minReplicas: 1",
|
||||
"maxReplicas: 1",
|
||||
} {
|
||||
if !strings.Contains(rendered, required) {
|
||||
t.Errorf("development mTLS overlay does not render %q", required)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,7 +374,9 @@ OpenAPI 结构契约由 Go 测试在双平台 CI 执行。
|
||||
Gateway 热路径。`platform/logging` 以 JSON `slog` 输出进程级致命错误,字段、URL
|
||||
用户信息、查询 Secret 和错误对象均经过脱敏,且不在请求热路径逐条写日志。
|
||||
CI 另有独立 Deployment job,在占位凭据下渲染 Compose,并使用 `kubectl kustomize`
|
||||
渲染 Kubernetes base;它不启动容器、不访问真实存储或密钥。
|
||||
渲染 Kubernetes base 和单副本 development mTLS Overlay;它不启动容器、不访问真实存储或密钥。
|
||||
development Overlay 已挂载独立 Controller/Gateway/Checker TLS Secret、启用 Checker 和最小
|
||||
网络策略,但固定 `gateway-a`、`checker-a` 身份且 HPA 锁为单副本,不能代替生产证书轮换。
|
||||
|
||||
## Task 14: Documentation, Examples, and Diagrams
|
||||
|
||||
@ -386,7 +388,7 @@ CI 另有独立 Deployment job,在占位凭据下渲染 Compose,并使用 `k
|
||||
- [x] Provide at least 30 Mermaid architecture, flow, sequence, state, and failure diagrams.
|
||||
- [x] Generate `proxy-pool-docs-v1.0.zip` from versioned documentation assets.
|
||||
|
||||
`scripts/package-docs.ps1` 会将 README、`docs/`、图表、OpenAPI 与 Proto 契约复制至临时目录,
|
||||
`scripts/package-docs.ps1` 会将 README、`docs/`、图表、OpenAPI、Proto 契约与部署手册复制至临时目录,
|
||||
生成包含 Git revision、文件大小和 SHA-256 的 `manifest.json`,再以临时 ZIP 原子替换目标。
|
||||
默认输出为被 Git 忽略的 `dist/proxy-pool-docs-v1.0.zip`;Go 回归测试实际执行脚本并校验归档内容。
|
||||
|
||||
|
||||
@ -76,6 +76,8 @@ func TestPackageDocsCreatesTraceableArchive(t *testing.T) {
|
||||
}
|
||||
for _, required := range []string{
|
||||
"README.md",
|
||||
"deploy/README.md",
|
||||
"deploy/kubernetes/overlays/development-mtls/README.md",
|
||||
"docs/design/architecture.md",
|
||||
"docs/operations/runbook.md",
|
||||
"diagrams/README.md",
|
||||
|
||||
@ -103,8 +103,10 @@ Windows 环境为 `CGO_ENABLED=0` 且没有 C 编译器,`go test -race` 在本
|
||||
CI 已配置 Linux race job。PostgreSQL 18 和 Redis 8.2 的隔离 Adapter fixture
|
||||
已经运行;本地 Compose 已声明 Controller、两个独立 Gateway 身份和一个 Checker 的
|
||||
mTLS 运行拓扑,并由配置、证书、命令装配和部署契约测试覆盖。Kubernetes base 刻意不直接
|
||||
启用 Checker,因为生产环境必须通过 Overlay 为每个弹性 Worker 注入唯一身份与证书;
|
||||
该 Overlay 和容器端到端启动仍待具备镜像网络的环境验证。
|
||||
启用 Checker;`development-mtls` Overlay 已为单副本 Controller、Gateway 和 Checker
|
||||
提供固定开发身份、mTLS Secret 挂载、最小出站 NetworkPolicy 与渲染/配置契约验证。
|
||||
生产环境仍必须通过独立 Overlay 为每个弹性 Worker 注入唯一、可轮换的身份与证书,且
|
||||
容器端到端启动仍待具备镜像网络的环境验证。
|
||||
|
||||
## 3. 后续实现范围
|
||||
|
||||
@ -116,8 +118,9 @@ mTLS 运行拓扑,并由配置、证书、命令装配和部署契约测试覆
|
||||
与 p99 告警;仍需代表性环境的流量压测和容量报告。
|
||||
3. Provider 长期凭据回收与累计额度的生产运营策略仍需结合实际供应商合同、失效时间和
|
||||
密钥平台完成演练。
|
||||
4. Kubernetes 需要按工作负载身份系统提供 mTLS Overlay、证书轮换、唯一 Worker ID 和
|
||||
Checker 出站 NetworkPolicy;base 清单不假定或伪造这些生产环境能力。
|
||||
4. Kubernetes 的开发 mTLS Overlay 已覆盖单副本固定身份和 Checker 出站
|
||||
NetworkPolicy;生产环境仍需要按工作负载身份系统提供证书轮换、每副本唯一 Worker ID
|
||||
与可弹性扩缩容的身份注入,base 清单不假定或伪造这些能力。
|
||||
5. Redis/PostgreSQL 故障转移、控制面断线恢复、Snapshot 回滚、Drain 回收和 Extract
|
||||
库存不足的完整故障演练。
|
||||
6. 10k 稳态、100k 峰值、CONNECT 活跃连接和建连速率的代表性集群负载测试。
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|---|---|---|---|
|
||||
| ARCH-001 | 数据面 Worker 与控制面 Controller 分离 | 1-70 | 包、协议和部署拓扑已分离;Controller 已运行 Worker Register/Watch/ACK/Runtime/Outcome 与 Checker Observation gRPC,并发布 Proxy/Gateway Routing/按引用去重凭据完整快照;Checker 任务流已具备有界领取、租约栅栏和任务期凭据契约。Gateway 已将快照编译为同版本动态 View,并由独立进程维护控制面会话。`proxy-checker` 与 Redis BASIC/EGRESS/TARGET 共享任务运行态、`proxy-loadgen` 有界 HTTP/CONNECT/Extract 校验场景均已实现 |
|
||||
| ARCH-002 | 热路径只做认证、本地路由和网络转发 | 1-70, 380-430 | Gateway bootstrap 集成测试验证启动期控制面会话与快照就绪,HTTP 请求只走本地 Snapshot/Dispatch;Outcome 仅写入有界非阻塞本地队列,代表性性能剖析待完成 |
|
||||
| ARCH-003 | Gateway、Distribution、Admin、Metrics 独立入口 | 8904-8958 | Controller 命令已装配 Distribution/Admin/Metrics 三个独立监听及联动停机;Gateway 命令已装配代理与 Metrics 监听。本地 Compose 已声明 Controller/Gateway/Checker mTLS 拓扑;Kubernetes 的工作负载身份 Overlay 仍待环境实现 |
|
||||
| ARCH-003 | Gateway、Distribution、Admin、Metrics 独立入口 | 8904-8958 | Controller 命令已装配 Distribution/Admin/Metrics 三个独立监听及联动停机;Gateway 命令已装配代理与 Metrics 监听。本地 Compose 已声明 Controller/Gateway/Checker mTLS 拓扑;Kubernetes `development-mtls` Overlay 已通过渲染与配置契约验证单副本固定身份链路,生产工作负载身份仍待环境实现 |
|
||||
| ARCH-004 | Controller 集中 Provider 获取与切换 | 1403-1580 | Redis Leader、动态 Provider Supervisor 与 Bootstrap 生产装配已完成;静态配置与 Admin 管理态共同决定 Provider 启停,停用策略以 Upstream revision 栅栏驱动既有 ownership Drain;Routing 切换会向本进程 Worker 快照流广播完整刷新,多副本按定时刷新与权威 HMAC 指纹/revision 栅栏收敛并拒绝旧配置换主 |
|
||||
| ARCH-005 | 100k QPS 峰值使用多 Worker 集群 | 当前会话 | 未验证设计目标;待代表性集群负载报告 |
|
||||
|
||||
|
||||
@ -31,7 +31,9 @@ $sources = @(
|
||||
"docs",
|
||||
"diagrams",
|
||||
"api/openapi",
|
||||
"api/proto"
|
||||
"api/proto",
|
||||
"deploy/README.md",
|
||||
"deploy/kubernetes/overlays/development-mtls/README.md"
|
||||
)
|
||||
$stagingRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("proxy-pool-docs-" + [Guid]::NewGuid().ToString("N"))
|
||||
$temporaryArchive = ""
|
||||
|
||||
@ -75,8 +75,8 @@
|
||||
与 PostgreSQL 18 的隔离 Adapter fixture 已运行。Docker Desktop 缺少镜像 HTTPS
|
||||
代理配置,未能在本机完成 Compose 容器端到端启动。
|
||||
- Controller、Gateway、Checker、Loadgen、Provider Fleet、WorkerControlPlane、业务指标和
|
||||
Redis 故障边界均有实现与定向测试。真实容器故障转移、Kubernetes 工作负载身份 Overlay
|
||||
与代表性集群压测仍属于后续验证范围。
|
||||
- `implementation-plan.md` 当前按 74 个验收项统计;验收勾选数不等同于生产就绪度。
|
||||
Redis 故障边界均有实现与定向测试。Kubernetes `development-mtls` Overlay 已静态验证
|
||||
单副本固定身份链路;真实容器故障转移、生产工作负载身份与代表性集群压测仍属于后续验证范围。
|
||||
- `implementation-plan.md` 当前按 75 个验收项统计;验收勾选数不等同于生产就绪度。
|
||||
Compose 本地 mTLS 控制面运行链已实现并通过配置、证书、单元与构建验证;受本机 Docker
|
||||
Desktop 镜像 HTTPS 代理缺失影响,容器端到端启动仍待具备镜像网络的环境复核。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user