PageSourceSearch

https://docs.authorizer.dev/assets/js/04da809a.eab5a01f.js

js authorizer.dev collected 2026-10-01 14:01:50 UTC 12,693 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkauthorizer_docs=globalThis.webpackChunkauthorizer_docs||[]).push([[1968],{4137(e,n,r){r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"deployment/kubernetes","title":"Kubernetes","description":"This guide shows how to deploy Authorizer v2 on Kubernetes using the CLI-only configuration model.","source":"@site/docs/deployment/kubernetes.md","sourceDirName":"deployment","slug":"/deployment/kubernetes","permalink":"/deployment/kubernetes","draft":false,"unlisted":false,"editUrl":"https://github.com/authorizerdev/authorizer-docs/tree/main/docs/deployment/kubernetes.md","tags":[],"version":"current","sidebarPosition":3,"frontMatter":{"sidebar_position":3,"title":"Kubernetes"},"sidebar":"docsSidebar","previous":{"title":"Binary Deployment","permalink":"/deployment/binary"},"next":{"title":"Helm Chart","permalink":"/deployment/helm-chart"}}');var t=r(4848),i=r(8453);const o={sidebar_position:3,title:"Kubernetes"},a="Kubernetes (v2)",c={},l=[{value:"1. Prerequisites",id:"1-prerequisites",level:2},{value:"2. Deployment manifest (v2-style)",id:"2-deployment-manifest-v2-style",level:2},{value:"Ports: <code>containerPort</code>, Services, and Ingress",id:"k8s-ports-services",level:3},{value:"Metrics (Prometheus)",id:"metrics-prometheus",level:3},{value:"3. Managing configuration changes",id:"3-managing-configuration-changes",level:2}];function d(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"kubernetes-v2",children:"Kubernetes (v2)"})}),"\n",(0,t.jsxs)(n.p,{children:["This guide shows how to deploy ",(0,t.jsx)(n.strong,{children:"Authorizer v2"})," on Kubernetes using the ",(0,t.jsx)(n.strong,{children:"CLI-only configuration model"}),".\nInstead of configuring env vars that the server reads directly, we pass ",(0,t.jsx)(n.strong,{children:"CLI flags"})," through the container ",(0,t.jsx)(n.code,{children:"args"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["If you are migrating from v1, compare with ",(0,t.jsx)(n.a,{href:"../deployment/kubernetes",children:"Kubernetes"})," and the ",(0,t.jsx)(n.a,{href:"../migration/v1-to-v2",children:"Migration v1 to v2"})," guide."]}),"\n",(0,t.jsx)(n.hr,{}),"\n",(0,t.jsx)(n.h2,{id:"1-prerequisites",children:"1. Prerequisites"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"A Kubernetes cluster (GKE, EKS, AKS, k3s, etc.)."}),"\n",(0,t.jsxs)(n.li,{children:["Container image for ",(0,t.jsx)(n.strong,{children:"Authorizer v2"})," built with:"]}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-dockerfile",children:'# Official image listens on 8080 (HTTP) and 8081 (metrics); see Dockerfile EXPOSE comments.\nENTRYPOINT ["./authorizer"]\nCMD []\n'})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Optional:","\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Ingress controller (for example nginx)."}),"\n",(0,t.jsx)(n.li,{children:"cert-manager for automatic TLS."}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.hr,{}),"\n",(0,t.jsx)(n.h2,{id:"2-deployment-manifest-v2-style",children:"2. Deployment manifest (v2-style)"}),"\n",(0,t.jsxs)(n.p,{children:["Below is an example ",(0,t.jsx)(n.code,{children:"Deployment"})," + ",(0,t.jsx)(n.code,{children:"Service"})," + ",(0,t.jsx)(n.code,{children:"Ingress"})," setup.\nThe key difference vs v1: ",(0,t.jsxs)(n.strong,{children:["we pass configuration as CLI flags in ",(0,t.jsx)(n.code,{children:"args"})]}),"."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: authorizer-v2\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: authorizer-v2\n  template:\n    metadata:\n      labels:\n        app: authorizer-v2\n    spec:\n      containers:\n        - name: authorizer-v2\n          image: your-registry/authorizer:v2\n          imagePullPolicy: Always\n          ports:\n            - containerPort: 8080\n              name: http\n            - containerPort: 8081\n              name: metrics\n          env:\n            - name: DATABASE_URL\n              valueFrom:\n                secretKeyRef:\n                  name: authorizer-secrets\n                  key: database-url\n            - name: CLIENT_ID\n              valueFrom:\n                secretKeyRef:\n                  name: authorizer-secrets\n                  key: client-id\n            - name: CLIENT_SECRET\n              valueFrom:\n                secretKeyRef:\n                  name: authorizer-secrets\n                  key: client-secret\n            - name: ADMIN_SECRET\n              valueFrom:\n                secretKeyRef:\n                  name: authorizer-secrets\n                  key: admin-secret\n            - name: ENCRYPTION_KEY\n              valueFrom:\n                secretKeyRef:\n                  name: authorizer-secrets\n                  key: encryption-key\n          args:\n            - "--env=production"\n            - "--http-port=8080"\n            - "--metrics-port=8081"\n            - "--metrics-host=0.0.0.0"\n            - "--rate-limit-rps=30"\n            - "--rate-limit-burst=20"\n            - "--rate-limit-fail-closed=false"\n            - "--database-type=postgres"\n            - "--database-url=$(DATABASE_URL)"\n            - "--url=https://YOUR_DOMAIN"\n            - "--client-id=$(CLIENT_ID)"\n            - "--client-secret=$(CLIENT_SECRET)"\n            - "--admin-secret=$(ADMIN_SECRET)"\n            - "--jwt-type=RS256"\n            - "--encryption-key=$(ENCRYPTION_KEY)"\n            # Example: mount keys from files or use env and expand here\n            - "--enable-login-page=true"\n            - "--enable-playground=false"\n            - "--enable-graphql-introspection=false"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: authorizer-v2\nspec:\n  selector:\n    app: authorizer-v2\n  ports:\n    - port: 80\n      name: http\n      targetPort: 8080\n  type: ClusterIP\n---\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: authorizer-v2\n  annotations:\n    kubernetes.io/ingress.class: nginx\n    cert-manager.io/cluster-issuer: letsencrypt-prod\nspec:\n  rules:\n    - host: YOUR_DOMAIN\n      http:\n        paths:\n          - path: /\n            pathType: Prefix\n            backend:\n              service:\n                name: authorizer-v2\n                port:\n                  number: 80\n  tls:\n    - hosts:\n        - YOUR_DOMAIN\n      secretName: authorizer-v2-tls\n'})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Note:"})," Use Kubernetes ",(0,t.jsx)(n.code,{children:"Secret"})," resources for sensitive values and reference them via ",(0,t.jsx)(n.code,{children:"env"})," + ",(0,t.jsx)(n.code,{children:"args"})," as shown."]}),"\n"]}),"\n",(0,t.jsxs)(n.h3,{id:"k8s-ports-services",children:["Ports: ",(0,t.jsx)(n.code,{children:"containerPort"}),", Services, and Ingress"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Declare ",(0,t.jsx)(n.strong,{children:"both"})," ",(0,t.jsx)(n.code,{children:"containerPort: 8080"})," and ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"8081"})})," on the pod so the API contract matches the image (",(0,t.jsx)(n.code,{children:"EXPOSE 8080 8081"})," in the Dockerfile). This is documentation for humans and tooling; it does not by itself expose traffic to the internet."]}),"\n",(0,t.jsxs)(n.li,{children:["The ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"Service"})})," that backs your ",(0,t.jsx)(n.strong,{children:"Ingress"})," (or cloud load balancer) should forward ",(0,t.jsx)(n.strong,{children:"only"})," the app port (",(0,t.jsx)(n.strong,{children:"80 \u2192 8080"})," in the example above). ",(0,t.jsx)(n.strong,{children:"Do not"})," add ",(0,t.jsx)(n.code,{children:"8081"})," to that same public-facing ",(0,t.jsx)(n.code,{children:"Service"})," or ",(0,t.jsx)(n.code,{children:"Ingress"}),"."]}),"\n",(0,t.jsxs)(n.li,{children:["For ",(0,t.jsx)(n.a,{href:"https://prometheus.io",children:"Prometheus"}),", scrape ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"8081"})})," via the ",(0,t.jsx)(n.strong,{children:"pod network"})," or a ",(0,t.jsxs)(n.strong,{children:["separate ClusterIP ",(0,t.jsx)(n.code,{children:"Service"})]})," (below). Set ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"--metrics-host=0.0.0.0"})})," in ",(0,t.jsx)(n.code,{children:"args"})," so the metrics listener accepts connections from other pods; without it, metrics stay on container loopback and in-cluster scrapes will fail."]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Summary:"})," expose ",(0,t.jsx)(n.strong,{children:"both"})," ports on the ",(0,t.jsx)(n.strong,{children:"Pod"}),"; expose ",(0,t.jsx)(n.strong,{children:"only HTTP (8080)"})," to clients via Ingress/LB; keep ",(0,t.jsx)(n.strong,{children:"metrics (8081)"})," internal to the cluster."]}),"\n",(0,t.jsx)(n.h3,{id:"metrics-prometheus",children:"Metrics (Prometheus)"}),"\n",(0,t.jsxs)(n.p,{children:["The app serves ",(0,t.jsxs)(n.strong,{children:[(0,t.jsx)(n.code,{children:"/metrics"})," on a second HTTP listener"]})," on port ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"8081"})}),". In Kubernetes, ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"--metrics-host=0.0.0.0"})})," is usually required so Prometheus can scrape the pod IP. ",(0,t.jsx)(n.strong,{children:"Do not"})," put port ",(0,t.jsx)(n.code,{children:"8081"})," on an internet-facing ",(0,t.jsx)(n.code,{children:"Ingress"}),". Use a ",(0,t.jsx)(n.code,{children:"ServiceMonitor"}),", PodMonitor, or a dedicated ",(0,t.jsx)(n.strong,{children:"ClusterIP"})," ",(0,t.jsx)(n.code,{children:"Service"})," and scrape config only. If Prometheus runs on the ",(0,t.jsx)(n.strong,{children:"same host"})," as a bare binary (not K8s), you can keep the default ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"127.0.0.1"})})," for metrics instead."]}),"\n",(0,t.jsxs)(n.p,{children:["Optional internal ",(0,t.jsx)(n.code,{children:"Service"})," for metrics (ClusterIP only):"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Service\nmetadata:\n  name: authorizer-v2-metrics\nspec:\n  selector:\n    app: authorizer-v2\n  ports:\n    - port: 8081\n      targetPort: metrics\n      name: metrics\n  type: ClusterIP\n"})}),"\n",(0,t.jsx)(n.p,{children:"Apply the manifest:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl apply -f authorizer-v2.yaml\n"})}),"\n",(0,t.jsx)(n.hr,{}),"\n",(0,t.jsx)(n.h2,{id:"3-managing-configuration-changes",children:"3. Managing configuration changes"}),"\n",(0,t.jsxs)(n.p,{children:["Because all configuration is now expressed as ",(0,t.jsx)(n.strong,{children:"CLI flags"}),":"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["To change a setting (for example enable playground), update the ",(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"args"})})," list."]}
1),"\n",(0,t.jsx)(n.li,{children:"Then run:"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl apply -f authorizer-v2.yaml\nkubectl rollout restart deployment authorizer-v2\n"})}),"\n",(0,t.jsxs)(n.p,{children:["You no longer update server config via ",(0,t.jsx)(n.code,{children:"_update_env"})," or dashboard; those are deprecated in v2."]}),"\n",(0,t.jsx)(n.p,{children:"For a full list of available flags, see:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"../core/server-config",children:"Server Configuration (v2)"})}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"./authorizer --help"})," in the container image"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453(e,n,r){r.d(n,{R:()=>o,x:()=>a});var s=r(6540);const t={},i=s.createContext(t);function o(e){const n=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.