Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/conformance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ env:
CARGO_TERM_COLOR: always
CONTAINER_ENGINE: docker
KIND_CLUSTER_NAME: praxis-conformance
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.5.2
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.7.5
OPERATOR_IMAGE: praxis-operator:dev

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ env:
KIND_CLUSTER_NAME: ci
V: ${{ inputs.debug && '1' || '' }}
OPERATOR_IMAGE: praxis-operator:dev
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.5.2
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.7.5

jobs:
# ---------------------------------------------------------------------------
Expand Down
123 changes: 123 additions & 0 deletions .github/workflows/rollout.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: Rollout

on:
schedule:
- cron: "23 3 * * *"
workflow_dispatch:
push:
tags:
- "v*"
pull_request:
branches: [main]
paths:
- ".github/workflows/rollout.yaml"
- "Cargo.toml"
- "Cargo.lock"
- "Containerfile"
- "Containerfile.*"
- "src/**"
- "deploy/**"

concurrency:
group: rollout-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

permissions: {}

env:
CARGO_TERM_COLOR: always
CONTAINER_ENGINE: docker

jobs:
kind:
runs-on: ubuntu-24.04
timeout-minutes: 75
permissions:
contents: read
steps:
- name: Check out operator
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Check out praxis
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: praxis-proxy/praxis
path: praxis
ref: f5a79aa36bebbaf542ce109c81144354926f52a9
persist-credentials: false

- name: Set up Rust
uses: praxis-proxy/conventions/.github/actions/setup-rust@f671c1215f89562d286310a6cabdcbaa5da9605c # v0.4.0

- name: Install KIND
run: |
curl --fail --location --show-error --silent \
--output ./kind-linux-amd64.sha256sum \
https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64.sha256sum
curl --fail --location --show-error --silent \
--output ./kind-linux-amd64 \
https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64
sha256sum --check ./kind-linux-amd64.sha256sum
chmod +x ./kind-linux-amd64
sudo mv ./kind-linux-amd64 /usr/local/bin/kind

- name: Install kubectl
run: |
curl --fail --location --show-error --silent \
--output ./kubectl.sha256 \
"https://dl.k8s.io/release/v1.33.3/bin/linux/amd64/kubectl.sha256"
curl --fail --location --show-error --silent \
--output ./kubectl \
"https://dl.k8s.io/release/v1.33.3/bin/linux/amd64/kubectl"
echo "$(cat ./kubectl.sha256) kubectl" | sha256sum --check --strict -
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl

- name: Run rollout suite (source image)
working-directory: praxis
run: >-
cargo xtask rollout
Comment thread
cooktheryan marked this conversation as resolved.
Resolved
--manifest-dir ../deploy/rollout-test
--operator-dir ..
--keep-cluster

- name: Pull the deployed default Praxis image
id: published
run: |
published_praxis_image=$(sed -n 's/^const DEFAULT_PRAXIS_IMAGE: &str = "\(.*\)";$/\1/p' src/context.rs)
test -n "$published_praxis_image"
docker pull "$published_praxis_image"
echo "image=$published_praxis_image" >> "$GITHUB_OUTPUT"

- name: Start the published-image case with a fresh cluster
run: kind delete cluster --name praxis-rollout

- name: Run rollout suite (published default image)
working-directory: praxis
env:
PRAXIS_RELEASE_IMAGE: ${{ steps.published.outputs.image }}
run: >-
cargo xtask rollout
--manifest-dir ../deploy/rollout-test
--operator-dir ..
--image "$PRAXIS_RELEASE_IMAGE"
--operator-image localhost/praxis-operator:rollout
--skip-build
--keep-cluster
Comment thread
cooktheryan marked this conversation as resolved.
Resolved

- name: Dump cluster state
if: failure()
run: |
kubectl --request-timeout=30s --context kind-praxis-rollout -n praxis get pods -o wide || true
kubectl --request-timeout=30s --context kind-praxis-rollout get nodes -o wide || true
kubectl --request-timeout=30s --context kind-praxis-rollout get events -A --sort-by=.lastTimestamp || true
kubectl --request-timeout=30s --context kind-praxis-rollout get crd gatewayclasses.gateway.networking.k8s.io gateways.gateway.networking.k8s.io httproutes.gateway.networking.k8s.io || true

- name: Delete test cluster
if: always()
run: |
if command -v kind >/dev/null 2>&1; then
kind delete cluster --name praxis-rollout
fi
20 changes: 18 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,35 @@ The format follows [Keep a Changelog], and this project adheres to

### Added

- A five-second preStop delay for data-plane pods so Service endpoints can
be removed before the proxy stops accepting connections.

- Health, readiness and metrics endpoints on port 8080, with matching
probes on the operator Deployment.
- Leader election over a coordination `Lease`, so the operator can run
more than one replica safely.
- Kubernetes events explaining why a Gateway was rejected.
- Configurable data-plane replicas via the `praxis.sh/replicas`
annotation, a `PodDisruptionBudget`, and pod spread across nodes.
- Configurable positive data-plane replica counts via the
`praxis.sh/replicas` annotation, a `PodDisruptionBudget`, zero-unavailable
rolling updates, and zone and hostname pod spread.
- Kubernetes reference and rollout-test assets, plus the GitHub Actions
workflow that runs the Praxis rollout acceptance suite against them.
- `method` and `queryParams` route matches are now detected and
reported rather than silently ignored.
- Listener protocol and hostname conflict detection.

### Fixed

- Return HTTP 404 for unmatched requests on Gateway listeners without routes.

- Remove stale proxy children when no usable Gateway listeners remain, including
conflict-only configurations, and refresh HTTPRoute parent rejection statuses
after listeners move to or from the reserved metrics port.

- Gateway listeners on the reserved health/metrics port 9902 now report
`PortUnavailable` without blocking other valid listeners.
- Generated data-plane configuration now targets Praxis 0.7.5, including its
metrics-only admin endpoint and routeless-listener support.
- Status writes no longer restamp unchanged conditions, which had kept
the operator in a permanent reconcile loop.
- Endpoint weight distribution no longer overflows `i32` and aborts the
Expand Down
126 changes: 126 additions & 0 deletions deploy/rollout-test/backend.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: praxis
labels:
app.kubernetes.io/name: backend
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: backend
template:
metadata:
labels:
app.kubernetes.io/name: backend
spec:
# Keep fixture backends stable while worker nodes hosting proxies drain.
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: backend
image: busybox:1.37.0
args: [httpd, -f, -p, "8080", -h, /www]
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /healthy
port: http
periodSeconds: 2
volumeMounts:
- name: www
mountPath: /www
readOnly: true
volumes:
- name: www
configMap:
name: backend-content
---
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-content
namespace: praxis
data:
config-v1: config-v1
config-v2: config-v2
healthy: ok
index.html: ok
---
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: praxis
spec:
selector:
app.kubernetes.io/name: backend
ports:
- name: http
port: 8080
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: healthy-backend
namespace: praxis
labels:
app.kubernetes.io/name: healthy-backend
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: healthy-backend
template:
metadata:
labels:
app.kubernetes.io/name: healthy-backend
spec:
# Keep fixture backends stable while worker nodes hosting proxies drain.
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: backend
image: busybox:1.37.0
args: [httpd, -f, -p, "8080", -h, /www]
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /healthy
port: http
periodSeconds: 2
volumeMounts:
- name: www
mountPath: /www
readOnly: true
volumes:
- name: www
configMap:
name: backend-content
---
apiVersion: v1
kind: Service
metadata:
name: healthy-backend
namespace: praxis
spec:
selector:
app.kubernetes.io/name: healthy-backend
ports:
- name: http
port: 8080
targetPort: http
25 changes: 25 additions & 0 deletions deploy/rollout-test/gateway.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: rollout
namespace: praxis
annotations:
praxis.sh/replicas: "2"
spec:
gatewayClassName: praxis
listeners:
- name: http
port: 8080
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
port: 8443
protocol: HTTPS
tls:
certificateRefs:
- name: praxis-tls
allowedRoutes:
namespaces:
from: All
32 changes: 32 additions & 0 deletions deploy/rollout-test/httproute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rollout
namespace: praxis
spec:
parentRefs:
- name: rollout
rules:
- matches:
- path:
type: Exact
value: /config-version
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplaceFullPath
replaceFullPath: /config-v1
backendRefs:
- name: backend
port: 8080
- matches:
- path:
type: Exact
value: /healthy
backendRefs:
- name: healthy-backend
port: 8080
- backendRefs:
- name: backend
port: 8080
11 changes: 11 additions & 0 deletions deploy/rollout-test/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../rbac.yaml
- ../deployment.yaml
- ../gatewayclass.yaml
- backend.yaml
- gateway.yaml
- httproute.yaml
- namespace.yaml
- service.yaml
7 changes: 7 additions & 0 deletions deploy/rollout-test/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Namespace
metadata:
name: praxis
labels:
app.kubernetes.io/name: praxis
praxis-rollout/test: "true"
Loading