# Keycloak dedicado do tenant `plataforma` (IdP proprio da Athletic Map), persistindo no Postgres apiVersion: apps/v1 kind: Deployment metadata: name: keycloak namespace: plataforma-prod spec: replicas: 1 # Recreate: o Keycloak migra o esquema do banco ao subir uma versao nova, e # duas versoes no mesmo banco ao mesmo tempo (RollingUpdate) e o que nao se # quer. Tambem cabe na cota do namespace (o rolling pedia +512Mi de request). # `rollingUpdate: null` apaga o campo que o API server preencheu sozinho. strategy: type: Recreate rollingUpdate: null selector: matchLabels: app: keycloak template: metadata: labels: app: keycloak spec: containers: - name: keycloak image: quay.io/keycloak/keycloak:26.7.5 # Modo de PRODUCAO (05/10/2026). Era start-dev: cache e temas sem otimizacao, perfil de desenvolvimento. # Atras do Traefik: HTTP interno + cabecalhos X-Forwarded (KC_PROXY_HEADERS) e hostname fixo. args: ["start", "--import-realm"] env: - name: KC_DB value: postgres - name: KC_DB_URL value: "jdbc:postgresql://postgres:5432/keycloak?sslmode=require" - name: KC_DB_USERNAME value: atm - name: KC_DB_PASSWORD valueFrom: secretKeyRef: name: db-credentials key: password - name: KC_BOOTSTRAP_ADMIN_USERNAME value: admin - name: KC_BOOTSTRAP_ADMIN_PASSWORD valueFrom: secretKeyRef: name: keycloak-admin key: password # Uma replica so: cache local, sem tentar formar cluster (JGroups) com ninguem. - name: KC_CACHE value: local - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED value: "true" - name: KC_PROXY_HEADERS value: xforwarded # URL COMPLETA, e nao so o hostname. A diferenca nao e estetica. # # Com so o hostname, o Keycloak resolve esquema e porta A PARTIR DA # REQUISICAO. Isso funciona para quem chega pelo ingress (que manda # X-Forwarded-Proto), e quebra para quem chega por DENTRO: o # provisionamento chama a Admin API em http://keycloak:8080, e o link # do e-mail de boas-vindas saiu # `http://auth-plataforma.athleticmap.com:8080/...` — hostname certo, # esquema e porta da conexao interna. O cliente clicava e dava # ERR_CONNECTION_TIMED_OUT. # # Medido em 2026-09-24, no primeiro convite que chegou a uma caixa de # verdade. Com a URL completa, o Keycloak para de deduzir e passa a # montar todo link externo com este endereco — inclusive os que nascem # de chamadas internas. - name: KC_HOSTNAME value: "https://auth-plataforma.athleticmap.com" - name: KC_HOSTNAME_STRICT value: "true" ports: - containerPort: 8080 - containerPort: 9000 resources: requests: cpu: 250m memory: 512Mi limits: cpu: "1" memory: 1Gi readinessProbe: httpGet: path: /health/ready port: 9000 initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 40 volumeMounts: - name: realm-import mountPath: /opt/keycloak/data/import readOnly: true # O tema de login Athletic Map, o mesmo que o `escolinha` usa. # # Vem por ConfigMap e nao por imagem: o `login.ftl` traz as imagens # embutidas em data URI, porque o ConfigMap e montado READ-ONLY sobre # o diretorio do tema e nao sobra `resources/` para o Keycloak # servir. Gerado por scripts/tema_login_escolinha.py --destino # plataforma. # # Aqui ele vale para TODO tenant provisionado: eles nao tem Keycloak # proprio, usam este, um realm cada. - name: theme-athleticmapv2 mountPath: /opt/keycloak/themes/athleticmap-v2/login readOnly: true # O tema de E-MAIL, no mesmo `athleticmap-v2`. # # Sao quatro arquivos em tres diretorios, e ConfigMap nao tem # diretorio: as chaves sao achatadas e o `items[].path` do volume # remonta a hierarquia. Gerado por # scripts/tema_email_athleticmap.py. - name: email-athleticmapv2 mountPath: /opt/keycloak/themes/athleticmap-v2/email readOnly: true volumes: - name: realm-import configMap: name: kc-realm-import - name: theme-athleticmapv2 configMap: name: kc-theme-athleticmapv2 - name: email-athleticmapv2 configMap: name: kc-email-athleticmapv2 # Os caminhos TEM de bater com o mapa ARQUIVOS do gerador. items: - { key: theme.properties, path: theme.properties } - { key: template.ftl, path: html/template.ftl } - { key: executeActions.ftl, path: html/executeActions.ftl } - { key: messages_pt_BR.properties, path: messages/messages_pt_BR.properties } - { key: messages_en.properties, path: messages/messages_en.properties } --- apiVersion: v1 kind: Service metadata: name: keycloak namespace: plataforma-prod spec: selector: app: keycloak ports: - port: 8080 targetPort: 8080