β¨ Red Hat OpenShift¶
OpenShift (both OKD and Red Hat OpenShift Container Platform) adds opinionated security (SCC), integrated routing, and optional build pipelines on top of Kubernetes. Deploying MCP Gateway therefore means (1) building or pulling a compatible image, (2) wiring database + cache back-ends, (3) obeying the default restricted-v2 SCC, and (4) exposing the service through a Route instead of an Ingress. This guide walks through each step, offers ready-made YAML snippets, and explains the differences from the vanilla Kubernetes.
π Prerequisites¶
oc
CLI - log in as a developer to a project/namespace you can create objects in.- A storage class for PVCs (or local PVs) to back the Postgres template.
- Either Podman or Docker on your workstation if you build locally.
- Access to an image registry that your cluster can pull from (e.g.
quay.io
).
π οΈ Build & push images¶
Option A - Use Make¶
Target | Builds | Dockerfile | Notes |
---|---|---|---|
make podman | mcpgateway-dev:latest | Containerfile | Rootless Podman build |
make podman-prod | mcpgateway:latest | Containerfile.lite | UBI 9-micro, multi-stage |
make docker | mcpgateway-dev:latest | Containerfile | Docker Desktop |
make docker-prod | mcpgateway:latest | Containerfile.lite | Same slim image |
Push afterwards, for example:
podman tag mcpgateway:latest quay.io/YOUR_NS/mcpgateway:latest
podman push quay.io/YOUR_NS/mcpgateway:latest
Apple-silicon note -
Containerfile.lite
usesubi9-micro
(x86_64). Buildx/QEMU works, but the image will run under emulation on macOS. If you need native arm64 choose the dev image or add--platform linux/arm64
.
Option B - Raw CLI equivalents¶
# Dev (Containerfile)
podman build -t mcpgateway-dev:latest -f Containerfile .
# Prod (UBI micro, AMD64, squashed layers)
docker build --platform=linux/amd64 --squash \
-t mcpgateway:latest -f Containerfile.lite .
π Secrets & ConfigMaps¶
Create a ConfigMap from your .env
file:
OpenShift lets you inject all keys via envFrom:
in the pod template.
If you keep sensitive values (e.g. JWT_SECRET_KEY
) separate, store them in a Secret and reference both resources under envFrom:
.
π PostgreSQL & Redis back-ends¶
PostgreSQL (persistent template)¶
oc new-app -f https://raw.githubusercontent.com/openshift/origin/master/examples/db-templates/postgresql-persistent-template.json \
-p POSTGRESQL_USER=postgres,POSTGRESQL_PASSWORD=secret,POSTGRESQL_DATABASE=mcp
The template creates a DeploymentConfig, Service and a 1 Gi PVC bound to the cluster's default storage class.
Redis¶
On OpenShift 4.x use the Redis Enterprise Operator from OperatorHub (UI or CLI) then create a RedisEnterpriseCluster CR; it provisions StatefulSets plus PVCs out-of-the-box.
π¦ Deployment & Service (gateway)¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcpgateway
spec:
replicas: 1
selector:
matchLabels:
app: mcpgateway
template:
metadata:
labels:
app: mcpgateway
spec:
securityContext: # Must satisfy restricted-v2 SCC
runAsNonRoot: true
containers:
- name: gateway
image: quay.io/YOUR_NS/mcpgateway:latest
ports:
- containerPort: 4444
envFrom:
- configMapRef:
name: mcpgateway-env
readinessProbe:
httpGet:
path: /health
port: 4444
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 4444
initialDelaySeconds: 15
periodSeconds: 20
securityContext:
allowPrivilegeEscalation: false
runAsUser: 1001 # UBI non-root UID works with restricted SCC
---
apiVersion: v1
kind: Service
metadata:
name: mcpgateway
spec:
selector:
app: mcpgateway
ports:
- port: 80
targetPort: 4444
The readiness/liveness probes follow OpenShift's health-check guidance.
π Route (public URL)¶
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: mcpgateway
spec:
to:
kind: Service
name: mcpgateway
port:
targetPort: 80
tls:
termination: edge
Routes are OpenShift's native form of ingress; the router automatically provisions a hostname such as mcpgateway-myproj.apps.cluster.example.com
.
π Putting it together¶
# Apply manifests
oc apply -f postgres-template.yaml # or Operator YAML
oc apply -f redis-operator.yaml # if using Redis Operator
oc apply -f mcpgateway-deployment.yaml
oc apply -f mcpgateway-route.yaml
Verify:
oc get pods
oc get route mcpgateway -o jsonpath='{.spec.host}{"\n"}'
curl https://$(oc get route mcpgateway -o jsonpath='{.spec.host}')/health
π OpenShift BuildConfig (optional)¶
If you prefer in-cluster builds, create a BuildConfig
with the docker strategy. You can override the Dockerfile path via spec.strategy.dockerStrategy.dockerfilePath
. Then trigger:
The resulting image lands in an internal ImageStream, and the Deployment can auto-deploy the new tag.
π Persistence & PVCs¶
The Postgres template already generates a PVC; you can create extra PVCs manually or via the web console. A general PVC manifest is shown in OpenShift Storage docs.
π¦ Non-Make cheat-sheet¶
Action | Command |
---|---|
Build dev image (local) | podman build -t mcpgateway-dev -f Containerfile . |
Build prod (UBI lite) | docker build -t mcpgateway -f Containerfile.lite . |
Push to Quay | podman push mcpgateway quay.io/NS/mcpgateway |
Create project | oc new-project mcp-demo |
Load .env | oc create configmap mcpgateway-env --from-env-file=.env |
Deploy | oc apply -f mcpgateway-deployment.yaml |
Expose | oc apply -f mcpgateway-route.yaml |
Tail logs | oc logs -f deployment/mcpgateway |
π Troubleshooting¶
Issue | Fix |
---|---|
Error: container has runAsNonRoot and image has non-numeric user | Add runAsUser: 1001 or pick nonroot-v2 SCC. |
PVC stuck in Pending | Check storage class or request size > quota. |
Route returns 503 | Verify pod readiness probe passes and the Service targets port 80 -> 4444. |