diff --git a/README.md b/README.md index e49533a..db8690b 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ This project is in active use by [telegram-bot.app](https://telegram-bot.app), a ![Example of monitoring dashboard](static/monitoring-at-glance.png?raw=true) -You can find the example of the Kubernetes manifest in the [example deployment](static/kubernetes-deployment.yaml) file. - - [graphql monitoring proxy](#graphql-monitoring-proxy) - [Why this project exists](#why-this-project-exists) + - [How to deploy](#how-to-deploy) + - [Note on websocket support](#note-on-websocket-support) - [Endpoints](#endpoints) - [Features](#features) - [Configuration](#configuration) @@ -26,11 +26,55 @@ You can find the example of the Kubernetes manifest in the [example deployment]( - [Healthcheck](#healthcheck) - [Monitoring endpoint](#monitoring-endpoint) - ### Why this project exists I wanted to monitor the queries and responses of our graphql endpoint. Still, we didn't want to pay the price of the graphql server itself ( and I will not point fingers at a particular well-known project), as monitoring and basic security features should be a standard, free functionality. +### How to deploy + +You can find the example of the Kubernetes manifest in the [example standalone deployment](static/kubernetes-deployment.yaml) or [example combined deployment](static/kubernetes-single-deployment.yaml) files. Observed advantage of multideployment is that it allows the network requests to travel via localhost, without leaving the deployment which brings quite significant network performance boost. + +#### Note on websocket support + +Proxy in its current version 0.5.30 does not support websockets. If you need to proxy the websocket requests - you can use following trick whilst setting up the proxy. As I'm a big fan of Traefik - there's an example which works with the mentioned above combined deployment. + +
+ Click to show working Traefik Ingress Route example. + +```yaml +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: hasura-internal +spec: + entryPoints: + - websecure + routes: + # NON WEBSOCKET CONNECTION + - kind: Rule + match: Host(`example.com`) && PathPrefix(`/v1/graphql`) && !HeadersRegexp(`Upgrade`, `websocket`) + services: + - name: hasura-w-proxy-internal + port: proxy + middlewares: + - name: compression + namespace: default + + # WEBSOCKET CONNECTION + - kind: Rule + match: Host(`example.com`) && PathPrefix(`/v1/graphql`) && HeadersRegexp(`Upgrade`, `websocket`) + services: + - name: hasura-w-proxy-internal + port: hasura + middlewares: + - name: compression + namespace: default +``` + +In this case, both proxy and websockets will be available under the `/v1/graphql` path, and the websocket connection will be proxied directly to the hasura service, bypassing the proxy. + +
+ ### Endpoints * `:8080/*` - the graphql passthrough endpoint @@ -89,6 +133,8 @@ You can then start using the cache by setting the `ENABLE_GLOBAL_CACHE` environm In the case of the `@cached` you can add additional parameters to the directive which will set the cache for specific queries to the provided time. For example, `query MyCachedQuery @cached(ttl: 90) ....` will set the cache for the query to 90 seconds. +Since version `0.5.30` the cache is gzipped in the memory, which should optimise the memory usage quite significantly. + ### Security #### Role-based rate limiting diff --git a/static/kubernetes-single-deployment.yaml b/static/kubernetes-single-deployment.yaml new file mode 100644 index 0000000..82125cc --- /dev/null +++ b/static/kubernetes-single-deployment.yaml @@ -0,0 +1,121 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hasura-w-proxy-internal + labels: + app: hasura-w-proxy-internal + type: support +spec: + replicas: 2 + selector: + matchLabels: + app: hasura-w-proxy-internal + type: support + template: + metadata: + labels: + app: hasura-w-proxy-internal + type: support + spec: + securityContext: + runAsUser: 65534 # nobody + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/worker + operator: Exists + containers: + - name: hasura + image: hasura/graphql-engine:v2.33.1-ce + ports: + - name: hasura-internal + containerPort: 8080 + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 30 + resources: + limits: + cpu: "1" + memory: "640Mi" + requests: + cpu: "0.75" + memory: "512Mi" + env: + - name: HASURA_GRAPHQL_DATABASE_URL + value: postgres://postgres:xxx@yyy:5432/postgres + - name: HASURA_GRAPHQL_ENABLE_CONSOLE + value: "true" + - name: HASURA_GRAPHQL_DEV_MODE + value: "true" + - name: HASURA_GRAPHQL_ENABLE_TELEMETRY + value: "false" + - name: HASURA_GRAPHQL_EXPERIMENTAL_FEATURES + value: "inherited_roles" + - name: HASURA_GRAPHQL_PG_CONNECTIONS + value: "20" + - name: HASURA_GRAPHQL_LOG_LEVEL + value: "error" + - name: graphql-proxy + image: ghcr.io/lukaszraczylo/graphql-monitoring-proxy:latest + imagePullPolicy: Always + resources: + limits: + cpu: "1" + memory: "640Mi" + requests: + cpu: "0.75" + memory: "128Mi" + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 5 + timeoutSeconds: 5 + ports: + - name: web + containerPort: 8181 + - name: monitoring + containerPort: 9393 + env: + - name: PORT_GRAPHQL + value: "8181" + - name: MONITORING_PORT + value: "9393" + - name: HOST_GRAPHQL + value: http://localhost:8080/ + - name: ENABLE_GLOBAL_CACHE + value: "true" + - name: CACHE_TTL + value: "10" + +--- +apiVersion: v1 +kind: Service +metadata: + name: hasura-w-proxy-internal + labels: + app: hasura-w-proxy-internal + type: support + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9393" + prometheus.io/path: "/metrics" +spec: + ports: + - name: hasura + port: 8080 + targetPort: 8080 + - name: proxy + port: 8181 + targetPort: 8181 + - name: monitoring + port: 9393 + targetPort: 9393 + selector: + app: hasura-w-proxy-internal + type: support + type: ClusterIP \ No newline at end of file