mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-01 06:32:14 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fbcbc89ed |
@@ -389,6 +389,12 @@ build-k8s-cluster: \
|
|||||||
./bin/start-kind.sh
|
./bin/start-kind.sh
|
||||||
.PHONY: build-k8s-cluster
|
.PHONY: build-k8s-cluster
|
||||||
|
|
||||||
|
build-k8s-cluster-orbstack: ## setup the kubernetes environment on OrbStack's built-in cluster (macOS)
|
||||||
|
build-k8s-cluster-orbstack: \
|
||||||
|
env.d/development/kube-secret
|
||||||
|
./bin/start-orbstack.sh
|
||||||
|
.PHONY: build-k8s-cluster-orbstack
|
||||||
|
|
||||||
start-tilt-keycloak: ## start the kubernetes cluster using kind, without Pro Connect for authentication, use keycloak
|
start-tilt-keycloak: ## start the kubernetes cluster using kind, without Pro Connect for authentication, use keycloak
|
||||||
DEV_ENV=dev-keycloak tilt up --namespace=meet -f ./bin/Tiltfile
|
DEV_ENV=dev-keycloak tilt up --namespace=meet -f ./bin/Tiltfile
|
||||||
.PHONY: build-k8s-cluster
|
.PHONY: build-k8s-cluster
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
load('ext://uibutton', 'cmd_button', 'bool_input', 'location')
|
load('ext://uibutton', 'cmd_button', 'bool_input', 'location')
|
||||||
load('ext://namespace', 'namespace_create', 'namespace_inject')
|
load('ext://namespace', 'namespace_create', 'namespace_inject')
|
||||||
|
|
||||||
|
# OrbStack's built-in cluster (macOS) is a supported alternative to kind.
|
||||||
|
# Recent Tilt versions (>= 0.33) detect it as a local dev cluster; this is
|
||||||
|
# a no-op for kind and a safety net for older Tilt versions.
|
||||||
|
allow_k8s_contexts('orbstack')
|
||||||
|
|
||||||
namespace_create('meet')
|
namespace_create('meet')
|
||||||
|
|
||||||
DEV_ENV = os.getenv('DEV_ENV', 'dev-keycloak')
|
DEV_ENV = os.getenv('DEV_ENV', 'dev-keycloak')
|
||||||
|
|||||||
Executable
+182
@@ -0,0 +1,182 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Bootstrap the local dev environment on OrbStack's built-in Kubernetes
|
||||||
|
# cluster (macOS) instead of kind.
|
||||||
|
#
|
||||||
|
# This replicates what bin/start-kind.sh (numerique-gouv/tools
|
||||||
|
# kind/create_cluster.sh) provides, minus what OrbStack makes unnecessary:
|
||||||
|
# - no kind cluster: OrbStack ships a lightweight single-node cluster
|
||||||
|
# - no local registry (kind-registry): OrbStack's cluster shares the
|
||||||
|
# Docker image store, so images built by Tilt are directly visible
|
||||||
|
# to pods. Tilt detects the "orbstack" context as a local cluster
|
||||||
|
# and skips pushing images entirely.
|
||||||
|
#
|
||||||
|
# Requirements: OrbStack (with Kubernetes enabled), kubectl, mkcert, curl.
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
|
APPLICATION=${1:-meet}
|
||||||
|
CONTEXT="orbstack"
|
||||||
|
|
||||||
|
echo "0. Check OrbStack Kubernetes is available"
|
||||||
|
if ! command -v mkcert >/dev/null 2>&1; then
|
||||||
|
echo "❌ mkcert is not installed. Install it first: brew install mkcert"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! kubectl config get-contexts -o name | grep -qx "${CONTEXT}"; then
|
||||||
|
echo "Context '${CONTEXT}' not found. Trying to start OrbStack Kubernetes..."
|
||||||
|
if command -v orb >/dev/null 2>&1; then
|
||||||
|
orb start k8s
|
||||||
|
else
|
||||||
|
echo "❌ Enable Kubernetes in OrbStack (Settings > Kubernetes) and retry."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
kubectl config use-context "${CONTEXT}"
|
||||||
|
|
||||||
|
echo "0b. Check ports 80/443 are free on localhost"
|
||||||
|
# OrbStack forwards LoadBalancer service ports to 127.0.0.1. If the kind
|
||||||
|
# cluster is still running, its docker proxy already holds 80/443.
|
||||||
|
# Skip the check if ingress-nginx is already installed here: in that case
|
||||||
|
# the listener on 80/443 is our own LoadBalancer.
|
||||||
|
if ! kubectl -n ingress-nginx get deployment ingress-nginx-controller >/dev/null 2>&1; then
|
||||||
|
for port in 80 443; do
|
||||||
|
if lsof -nP -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1; then
|
||||||
|
echo "❌ Port ${port} is already in use on the host."
|
||||||
|
echo " If the kind cluster is running, delete it first:"
|
||||||
|
echo " kind delete cluster --name suite"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "1. Create ca"
|
||||||
|
CURRENT_DIR=$(pwd)
|
||||||
|
mkcert -install
|
||||||
|
cd /tmp
|
||||||
|
mkcert "127.0.0.1.nip.io" "*.127.0.0.1.nip.io"
|
||||||
|
cd "${CURRENT_DIR}"
|
||||||
|
|
||||||
|
echo "2. Install ingress-nginx (cloud provider: LoadBalancer service)"
|
||||||
|
# OrbStack exposes LoadBalancer services on 127.0.0.1, so the cloud
|
||||||
|
# manifest replaces kind's hostPort-based deploy. Every sub-step below is
|
||||||
|
# guarded individually so the script is safe to re-run after a partial
|
||||||
|
# failure (unlike the upstream kind script, which guards the whole block
|
||||||
|
# on namespace existence).
|
||||||
|
|
||||||
|
# Make sure no stale registry configmap tells Tilt to push to localhost:5001
|
||||||
|
# (there is no registry on OrbStack).
|
||||||
|
kubectl -n kube-public delete configmap local-registry-hosting --ignore-not-found
|
||||||
|
|
||||||
|
if ! kubectl -n ingress-nginx get deployment ingress-nginx-controller >/dev/null 2>&1; then
|
||||||
|
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml
|
||||||
|
fi
|
||||||
|
if ! kubectl -n ingress-nginx get deployment nginx-errors >/dev/null 2>&1; then
|
||||||
|
kubectl apply -n ingress-nginx -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/refs/heads/main/docs/examples/customization/custom-errors/custom-default-backend.yaml
|
||||||
|
fi
|
||||||
|
kubectl -n ingress-nginx create secret tls mkcert --key /tmp/127.0.0.1.nip.io+1-key.pem --cert /tmp/127.0.0.1.nip.io+1.pem || echo ok
|
||||||
|
|
||||||
|
# The meet charts render Ingresses without ingressClassName. The kind
|
||||||
|
# provider manifest handles this via --watch-ingress-without-class=true;
|
||||||
|
# the cloud manifest does not, so add it here (otherwise: 404 everywhere).
|
||||||
|
if ! kubectl -n ingress-nginx get deployment ingress-nginx-controller -o jsonpath='{.spec.template.spec.containers[0].args}' | grep -q 'watch-ingress-without-class'; then
|
||||||
|
kubectl -n ingress-nginx patch deployments.apps ingress-nginx-controller --type 'json' -p '[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value":"--watch-ingress-without-class=true"},{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value":"--default-ssl-certificate=ingress-nginx/mkcert"},{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value":"--default-backend-service=ingress-nginx/nginx-errors"}
|
||||||
|
]'
|
||||||
|
fi
|
||||||
|
if ! kubectl -n ingress-nginx get deployment nginx-errors -o jsonpath='{.spec.template.spec.containers[0].image}' | grep -q 'error-pages'; then
|
||||||
|
kubectl -n ingress-nginx patch deployment nginx-errors --type=json -p='[
|
||||||
|
{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "ghcr.io/tarampampam/error-pages:3.3.0"},
|
||||||
|
{"op": "add", "path": "/spec/template/spec/containers/0/env", "value": [{"name": "TEMPLATE_NAME", "value": "ghost"}, {"name": "SHOW_DETAILS", "value": "false"}, {"name": "SEND_SAME_HTTP_CODE", "value": "true"}]}
|
||||||
|
]'
|
||||||
|
fi
|
||||||
|
cat <<EOF | kubectl apply -n ingress-nginx -f -
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
allow-snippet-annotations: "true"
|
||||||
|
annotations-risk-level: Critical
|
||||||
|
custom-http-errors: 500,501,502,503,504
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: ingress-nginx-controller
|
||||||
|
namespace: ingress-nginx
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "2b. Wait for the ingress controller to be ready"
|
||||||
|
kubectl -n ingress-nginx rollout status deployment/ingress-nginx-controller --timeout=180s
|
||||||
|
|
||||||
|
echo "3. Patch CoreDNS so in-cluster pods resolve *.127.0.0.1.nip.io to the ingress"
|
||||||
|
# nip.io resolves to 127.0.0.1, which inside a pod is the pod itself.
|
||||||
|
# Rewrite these names to the ingress-nginx service, like the kind setup does.
|
||||||
|
# Unlike kind, we amend OrbStack's existing Corefile instead of replacing it.
|
||||||
|
if ! kubectl -n kube-system get configmap coredns -o jsonpath='{.data.Corefile}' | grep -q '127\.0\.0\.1\.nip\.io'; then
|
||||||
|
kubectl -n kube-system get configmap coredns -o jsonpath='{.data.Corefile}' \
|
||||||
|
| awk '/forward \./ && !done { print " rewrite stop {"; print " name regex (.*).127.0.0.1.nip.io ingress-nginx-controller.ingress-nginx.svc.cluster.local answer auto"; print " }"; done=1 } { print }' \
|
||||||
|
>/tmp/Corefile.orbstack
|
||||||
|
kubectl -n kube-system create configmap coredns --from-file=Corefile=/tmp/Corefile.orbstack --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
kubectl -n kube-system rollout restart deployments/coredns
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! kubectl get ns "${APPLICATION}" >/dev/null 2>&1; then
|
||||||
|
echo "4. Setup namespace"
|
||||||
|
kubectl create ns "${APPLICATION}"
|
||||||
|
fi
|
||||||
|
kubectl config set-context --current --namespace="${APPLICATION}"
|
||||||
|
kubectl -n "${APPLICATION}" create secret generic mkcert --from-file=rootCA.pem="$(mkcert -CAROOT)/rootCA.pem" || echo ok
|
||||||
|
|
||||||
|
if ! kubectl get configmap certifi -n "${APPLICATION}" >/dev/null 2>&1; then
|
||||||
|
echo "5. Inject our custom CA in a configmap for certifi"
|
||||||
|
curl https://raw.githubusercontent.com/certifi/python-certifi/refs/heads/master/certifi/cacert.pem -o /tmp/cacert.pem
|
||||||
|
cat "$(mkcert -CAROOT)/rootCA.pem" >>/tmp/cacert.pem
|
||||||
|
kubectl -n "${APPLICATION}" create configmap certifi --from-file=cacert.pem=/tmp/cacert.pem
|
||||||
|
kubectl -n "${APPLICATION}" create secret generic certifi --from-file=/tmp/cacert.pem || echo ok
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "5b. Smoke test: the ingress chain answers on https://127.0.0.1"
|
||||||
|
# Before Tilt deploys the app this returns the styled 404 from the default
|
||||||
|
# backend — that still proves LB -> controller works. 000 means the
|
||||||
|
# LoadBalancer is not bound to localhost.
|
||||||
|
HTTP_CODE=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 10 https://127.0.0.1/ || true)
|
||||||
|
if [ "${HTTP_CODE}" = "000" ]; then
|
||||||
|
echo "⚠️ Nothing answered on https://127.0.0.1 — check the LoadBalancer:"
|
||||||
|
echo " kubectl -n ingress-nginx get svc ingress-nginx-controller"
|
||||||
|
else
|
||||||
|
echo "✅ Ingress reachable (HTTP ${HTTP_CODE})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "6. Check pod readiness across all namespaces..."
|
||||||
|
|
||||||
|
sleep_interval=10
|
||||||
|
|
||||||
|
echo "Initial wait time: $((sleep_interval * 2)) seconds…"
|
||||||
|
sleep $((sleep_interval * 2))
|
||||||
|
|
||||||
|
check_pods_ready() {
|
||||||
|
local max_attempts=60 # Maximum number of attempts (10 minutes with 10s intervals)
|
||||||
|
local attempt=1
|
||||||
|
|
||||||
|
while [ $attempt -le $max_attempts ]; do
|
||||||
|
echo "Attempt $attempt/$max_attempts - Checking pod status..."
|
||||||
|
|
||||||
|
not_ready_count=$( kubectl get po -A --no-headers | grep -v -E "Running|Completed"| wc -l | tr -d ' ')
|
||||||
|
|
||||||
|
if [ "$not_ready_count" -eq 0 ]; then
|
||||||
|
echo "✅ All pods are ready!"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "⏳ $not_ready_count pod(s) still not ready. Waiting $sleep_interval seconds…"
|
||||||
|
sleep $sleep_interval
|
||||||
|
((attempt++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "❌ Timeout: Some pods are still not ready after 10 minutes"
|
||||||
|
echo "Final pod status:"
|
||||||
|
kubectl get po -A
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if check_pods_ready; then
|
||||||
|
echo "🎉 Cluster is fully ready!"
|
||||||
|
else
|
||||||
|
echo "⚠️ Some pods may need manual intervention"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -143,3 +143,24 @@ $ make start-tilt-keycloak
|
|||||||
```
|
```
|
||||||
|
|
||||||
Monitor Tilt’s progress at [http://localhost:10350/](http://localhost:10350/). After Tilt actions finish, you can access the app at [https://meet.127.0.0.1.nip.io/](https://meet.127.0.0.1.nip.io/).
|
Monitor Tilt’s progress at [http://localhost:10350/](http://localhost:10350/). After Tilt actions finish, you can access the app at [https://meet.127.0.0.1.nip.io/](https://meet.127.0.0.1.nip.io/).
|
||||||
|
|
||||||
|
### Alternative: OrbStack's built-in Kubernetes (macOS)
|
||||||
|
|
||||||
|
If you use [OrbStack](https://orbstack.dev/) on macOS, you can run the stack on its built-in Kubernetes cluster instead of kind. It uses noticeably less RAM (no nested kubeadm node container) and no local registry is needed: OrbStack's cluster shares the Docker image store, so Tilt uses images directly without pushing.
|
||||||
|
|
||||||
|
Enable Kubernetes in OrbStack (Settings > Kubernetes), then:
|
||||||
|
|
||||||
|
```shellscript
|
||||||
|
$ make build-k8s-cluster-orbstack
|
||||||
|
```
|
||||||
|
|
||||||
|
This installs ingress-nginx (exposed by OrbStack on `127.0.0.1:80/443`), the mkcert TLS certificates, and the CoreDNS rewrite for `*.127.0.0.1.nip.io`, then you start Tilt as usual:
|
||||||
|
|
||||||
|
```shellscript
|
||||||
|
$ make start-tilt-keycloak
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Ports 80/443 must be free: delete the kind cluster first if you used it (`kind delete cluster --name suite`).
|
||||||
|
- If you "Reset Kubernetes" in OrbStack, re-run `make build-k8s-cluster-orbstack`.
|
||||||
|
- kind remains the reference setup (matches CI and lets you pin the Kubernetes version).
|
||||||
|
|||||||
Reference in New Issue
Block a user