Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 65 additions & 2 deletions coding-agent/docs/deployment/phase2-k8s.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ and secrets as operator-provided values.
and mounts separate `workspace` and `data` PVCs.
- The default Service is `ClusterIP` on port `8080`.
- HTTP bearer auth is enabled by default. The chart expects an existing Secret.
- The pod uses a dedicated ServiceAccount by default, does not mount a
ServiceAccount token, and the chart does not create RBAC bindings.
- Kubernetes service environment variable injection is disabled with
`enableServiceLinks=false`.
- NetworkPolicy is enabled by default. It allows inbound HTTP to the agent pod,
DNS to CoreDNS/kube-dns, and outbound public HTTPS while excluding private,
link-local, loopback, and carrier-grade NAT ranges.
- HTTPRoute support is optional and disabled by default.

## Required Operator Decisions

Expand All @@ -31,6 +39,41 @@ Fill these before live deployment:
- Kimi values: `provider=kimi-code`, `model=kimi-for-coding`
- Provider Secret values, if required by the selected provider
- Storage class and PVC sizes, if the cluster default is not acceptable
- CNI NetworkPolicy enforcement. Do not treat rendered NetworkPolicy objects as
an isolation boundary until the target cluster is confirmed to enforce them.
- Resource requests and limits for shared clusters.
- Gateway API and HTTPRoute parentRefs, if the chart is responsible for the
public route.

## Shared Or Public Cluster Prerequisites

Do not deploy the unauthenticated Orbstack values to a public or shared cluster:
they are only for local development and intentionally set
`server.allowUnauthenticated=true`.

Before deploying to a shared cluster:

- Confirm the CNI enforces Kubernetes NetworkPolicy. A cluster may accept
NetworkPolicy manifests without enforcing them.
- Set resource requests and limits. The default chart leaves `resources` empty
so operators can choose values that match the target node.
- Keep the generated ServiceAccount unprivileged. The chart does not create
Role, ClusterRole, RoleBinding, or ClusterRoleBinding resources.
- Keep `automountServiceAccountToken=false` unless there is a reviewed reason to
let the pod call the Kubernetes API.
- If `httpRoute.enabled=true`, ensure the Gateway API CRDs exist and TLS is
terminated by the Gateway, Traefik, or another reviewed edge component.
- If the provider endpoint, proxy, or dependency is on a private CIDR, add a
narrow `networkPolicy.extraEgress` rule for that destination. The default
public HTTPS rule intentionally excludes private address ranges, including
`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `100.64.0.0/10`,
`169.254.0.0/16`, and `127.0.0.0/8`.
- The default `networkPolicy.ingress.from=null` allows any pod source to the
agent HTTP port. For shared clusters, prefer setting this to the Gateway or
ingress-controller namespace/pod selector; set it to `[]` only when you want
the NetworkPolicy to deny all pod-network ingress.
- If the target cluster cannot enforce NetworkPolicy, do not count it as a safe
shared-cluster deployment target for this service.

## Build And Publish

Expand Down Expand Up @@ -91,7 +134,9 @@ helm --kube-context <kube-context> upgrade --install coding-agent ./helm \
--namespace coding-agent \
--set image.repository='<registry>/<namespace>/coding-agent' \
--set image.tag='<image-tag>' \
--set-json cors.origins='["https://<agent-domain>"]'
--set-json cors.origins='["https://<agent-domain>"]' \
--set-json resources.requests='{"cpu":"250m","memory":"512Mi"}' \
--set-json resources.limits='{"cpu":"1","memory":"2Gi"}'
```

Kimi provider:
Expand All @@ -104,7 +149,9 @@ helm --kube-context <kube-context> upgrade --install coding-agent ./helm \
--set image.tag='<image-tag>' \
--set server.auth.enabled=true \
--set server.allowUnauthenticated=false \
--set-json cors.origins='["https://<agent-domain>"]'
--set-json cors.origins='["https://<agent-domain>"]' \
--set-json resources.requests='{"cpu":"250m","memory":"512Mi"}' \
--set-json resources.limits='{"cpu":"1","memory":"2Gi"}'
```

If the target cluster has no default storage class, set PVC classes explicitly:
Expand All @@ -114,6 +161,22 @@ If the target cluster has no default storage class, set PVC classes explicitly:
--set persistence.data.storageClassName='<storage-class>'
```

If the chart should render the Gateway API route, provide the parent Gateway and
hostname explicitly:

```bash
--set httpRoute.enabled=true \
--set-json httpRoute.parentRefs='[{"name":"<gateway-name>","namespace":"<gateway-namespace>"}]' \
--set-json httpRoute.hostnames='["<agent-domain>"]'
```

If a private provider endpoint or egress proxy is required, add only that
destination:

```bash
--set-json networkPolicy.extraEgress='[{"to":[{"ipBlock":{"cidr":"<provider-or-proxy-cidr>"}}],"ports":[{"protocol":"TCP","port":443}]}]'
```

## Health Checks

Wait for rollout:
Expand Down
8 changes: 8 additions & 0 deletions coding-agent/helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,11 @@ app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/name: {{ include "coding-agent.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

{{- define "coding-agent.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{- default (include "coding-agent.fullname" .) .Values.serviceAccount.name -}}
{{- else -}}
{{- default "default" .Values.serviceAccount.name -}}
{{- end -}}
{{- end -}}
3 changes: 3 additions & 0 deletions coding-agent/helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "coding-agent.serviceAccountName" . }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
enableServiceLinks: {{ .Values.enableServiceLinks }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
Expand Down
27 changes: 27 additions & 0 deletions coding-agent/helm/templates/httproute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{- if .Values.httpRoute.enabled }}
{{- if not .Values.httpRoute.parentRefs }}
{{- fail "httpRoute.parentRefs must be set when httpRoute.enabled=true" }}
{{- end }}
{{- if not .Values.httpRoute.hostnames }}
{{- fail "httpRoute.hostnames must be set when httpRoute.enabled=true" }}
{{- end }}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ include "coding-agent.fullname" . }}
labels:
{{- include "coding-agent.labels" . | nindent 4 }}
spec:
parentRefs:
{{- toYaml .Values.httpRoute.parentRefs | nindent 4 }}
hostnames:
{{- toYaml .Values.httpRoute.hostnames | nindent 4 }}
rules:
- matches:
- path:
type: PathPrefix
value: {{ .Values.httpRoute.path | quote }}
backendRefs:
- name: {{ include "coding-agent.fullname" . }}
port: {{ .Values.service.port }}
{{- end }}
63 changes: 63 additions & 0 deletions coding-agent/helm/templates/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{{- if .Values.networkPolicy.enabled }}
{{- if and (not .Values.networkPolicy.ingress.enabled) (not .Values.networkPolicy.egress.enabled) }}
{{- fail "networkPolicy.ingress.enabled or networkPolicy.egress.enabled must be true when networkPolicy.enabled=true" }}
{{- end }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "coding-agent.fullname" . }}
labels:
{{- include "coding-agent.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "coding-agent.selectorLabels" . | nindent 6 }}
policyTypes:
{{- if .Values.networkPolicy.ingress.enabled }}
- Ingress
{{- end }}
{{- if .Values.networkPolicy.egress.enabled }}
- Egress
{{- end }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
{{- if .Values.networkPolicy.ingress.enabled }}
ingress:
- ports:
- port: {{ .Values.server.port }}
protocol: TCP
{{- if ne .Values.networkPolicy.ingress.from nil }}
from:
{{- toYaml .Values.networkPolicy.ingress.from | nindent 8 }}
{{- end }}
{{- range .Values.networkPolicy.extraIngress }}
- {{- toYaml . | nindent 6 }}
{{- end }}
{{- end }}
{{- if .Values.networkPolicy.egress.enabled }}
egress:
{{- if .Values.networkPolicy.egress.dns.enabled }}
- to:
- namespaceSelector:
{{- toYaml .Values.networkPolicy.egress.dns.namespaceSelector | nindent 12 }}
podSelector:
{{- toYaml .Values.networkPolicy.egress.dns.podSelector | nindent 12 }}
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
{{- end }}
{{- if .Values.networkPolicy.egress.publicHttps.enabled }}
- to:
- ipBlock:
cidr: {{ .Values.networkPolicy.egress.publicHttps.cidr | quote }}
except:
{{- toYaml .Values.networkPolicy.egress.publicHttps.except | nindent 14 }}
ports:
- port: 443
protocol: TCP
{{- end }}
{{- range .Values.networkPolicy.extraEgress }}
- {{- toYaml . | nindent 6 }}
{{- end }}
{{- end }}
{{- end }}
13 changes: 13 additions & 0 deletions coding-agent/helm/templates/serviceaccount.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "coding-agent.serviceAccountName" . }}
labels:
{{- include "coding-agent.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}
48 changes: 48 additions & 0 deletions coding-agent/helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,54 @@ service:
type: ClusterIP
port: 8080

enableServiceLinks: false

serviceAccount:
create: true
name: ""
automountServiceAccountToken: false
annotations: {}

networkPolicy:
enabled: true
ingress:
enabled: true
# null allows any source to the HTTP port. Set [] to deny all ingress or
# provide NetworkPolicyPeer entries to allow only a gateway/controller.
from: null
egress:
enabled: true
dns:
enabled: true
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- kube-dns
- coredns
publicHttps:
enabled: true
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
- 100.64.0.0/10
- 169.254.0.0/16
- 127.0.0.0/8
extraIngress: []
extraEgress: []

httpRoute:
enabled: false
parentRefs: []
hostnames: []
path: /

agent:
dataDir: /var/lib/coding-agent/data
extraEnv: []
Expand Down
Loading
Loading