# Portainer 部署指南 ## 概述 本文档记录了在 k3s 集群中部署 Portainer 的完整过程,包括域名绑定、KEDA 自动缩放和 CSRF 校验问题的解决方案。 ## 部署步骤 ### 1. 使用 Helm 安装 Portainer ```bash # 添加 Helm 仓库 helm repo add portainer https://portainer.github.io/k8s/ helm repo update # 安装 Portainer(使用 Longhorn 作为存储类) helm install --create-namespace -n portainer portainer portainer/portainer \ --set persistence.enabled=true \ --set persistence.storageClass=longhorn \ --set service.type=NodePort ``` ### 2. 配置域名访问 #### 2.1 Caddy 反向代理配置 修改 Caddy ConfigMap,添加 Portainer 的反向代理规则: ```yaml # Portainer 容器管理 - 直接转发到 Portainer HTTPS 端口 portainer.u6.net3w.com { reverse_proxy https://portainer.portainer.svc.cluster.local:9443 { transport http { tls_insecure_skip_verify } } } ``` **关键点:** - 直接转发到 Portainer 的 HTTPS 端口(9443),而不是通过 Traefik - 这样可以避免协议不匹配导致的 CSRF 校验失败 #### 2.2 更新 Caddy ConfigMap ```bash kubectl patch configmap caddy-config -n default --type merge -p '{"data":{"Caddyfile":"..."}}' ``` #### 2.3 重启 Caddy Pod ```bash kubectl delete pod -n default -l app=caddy ``` ### 3. 配置 KEDA 自动缩放(可选) 如果需要实现访问时启动、空闲时缩容的功能,应用 KEDA 配置: ```bash kubectl apply -f keda-scaler.yaml ``` **配置说明:** - 最小副本数:0(空闲时缩容到 0) - 最大副本数:3 - 缩容延迟:5 分钟无流量后缩容 ### 4. 解决 CSRF 校验问题 #### 问题描述 登录时提示 "Unable to login",日志显示: ``` Failed to validate Origin or Referer | error="origin invalid" ``` #### 问题原因 Portainer 新版本对 CSRF 校验非常严格。当通过域名访问时,协议不匹配导致校验失败: - 客户端发送:HTTPS 请求 - Portainer 接收:x_forwarded_proto=http #### 解决方案 **步骤 1:添加环境变量禁用 CSRF 校验** ```bash kubectl set env deployment/portainer -n portainer CONTROLLER_DISABLE_CSRF=true ``` **步骤 2:添加环境变量配置 origins** ```bash kubectl set env deployment/portainer -n portainer PORTAINER_ADMIN_ORIGINS="*" ``` **步骤 3:重启 Portainer** ```bash kubectl rollout restart deployment portainer -n portainer ``` **步骤 4:修改 Caddy 配置(最关键)** 直接转发到 Portainer 的 HTTPS 端口,避免通过 Traefik 导致的协议转换问题: ```yaml portainer.u6.net3w.com { reverse_proxy https://portainer.portainer.svc.cluster.local:9443 { transport http { tls_insecure_skip_verify } } } ``` ## 配置文件 ### portainer-server.yaml 记录 Portainer deployment 的环境变量配置: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: portainer namespace: portainer spec: template: spec: containers: - name: portainer env: - name: CONTROLLER_DISABLE_CSRF value: "true" - name: PORTAINER_ADMIN_ORIGINS value: "*" ``` ### keda-scaler.yaml KEDA 自动缩放配置,实现访问时启动、空闲时缩容。 ## 访问 Portainer 部署完成后,访问: ``` https://portainer.u6.net3w.com ``` ## 常见问题 ### Q: 登录时提示 "Unable to login" **A:** 这通常是 CSRF 校验失败导致的。检查以下几点: 1. 确认已添加环境变量 `CONTROLLER_DISABLE_CSRF=true` 2. 确认 Caddy 配置直接转发到 Portainer HTTPS 端口 3. 检查 Portainer 日志中是否有 "origin invalid" 错误 4. 重启 Portainer pod 使配置生效 ### Q: 为什么要直接转发到 HTTPS 端口而不是通过 Traefik? **A:** 因为通过 Traefik 转发时,协议头会被转换为 HTTP,导致 Portainer 接收到的协议与客户端发送的协议不匹配,从而 CSRF 校验失败。直接转发到 HTTPS 端口可以保持协议一致。 ### Q: KEDA 自动缩放是否必须配置? **A:** 不是必须的。KEDA 自动缩放是可选功能,用于节省资源。如果不需要自动缩放,可以跳过这一步。 ## 相关文件 - `portainer-server.yaml` - Portainer deployment 环境变量配置 - `keda-scaler.yaml` - KEDA 自动缩放配置 - `ingress.yaml` - 原始 Ingress 配置(已弃用,改用 Caddy 直接转发) ## 下次部署检查清单 - [ ] 使用 Helm 安装 Portainer - [ ] 修改 Caddy 配置,直接转发到 Portainer HTTPS 端口 - [ ] 添加 Portainer 环境变量(CONTROLLER_DISABLE_CSRF、PORTAINER_ADMIN_ORIGINS) - [ ] 重启 Caddy 和 Portainer pods - [ ] 测试登录功能 - [ ] (可选)配置 KEDA 自动缩放 ## 参考资源 - Portainer 官方文档:https://docs.portainer.io/ - k3s 官方文档:https://docs.k3s.io/ - KEDA 官方文档:https://keda.sh/