如何自定义 Portainer 主题以符合企业 CI
解读
在国内金融、运营商、政务云等甲方场景,Portainer 常被选为 Docker 可视化管理平台,但默认蓝白配色与企业 CI(Corporate Identity)的 Logo、主色、字体规范冲突。面试官想验证两点:
- 你是否了解 Portainer 的前端架构与可插拔主题机制;
- 你是否能把“改颜色”这件小事做成可灰度、可版本化、可一键回滚的企业级交付方案,而不是手动改完就丢。
知识点
- Portainer 2.x 前端基于Angular 12 + TypeScript,样式层使用**Sass 变量 + CSS 自定义属性(:root)**混合方案。
- 官方提供**“Theme Override”目录**:
/public/assets/css/theme-override.css,在容器启动时若存在即自动注入,无需重新打包镜像。 - 企业 CI 通常给出主色(Primary)、辅色(Secondary)、警告色(Warning)、字体家族、Logo 矢量文件五要素,需映射到 Portainer 的 Sass 变量:
$color-primary、$color-secondary、$color-danger、$color-warning、$color-info、$color-success、$color-ui-1~$color-ui-9。 - 国内等保要求所有静态资源必须走内网,因此自定义主题需随镜像构建阶段打入,而不是运行时拉外网 CDN。
- 交付流程需符合 GitLab CI “配置即代码”:把主题文件、Dockerfile、helm values 统一放在仓库
.ci/portainer-theme/目录,MR 触发自动构建并推送至Harbor 私有仓库,再经Swarm stack 滚动升级到预发环境,最后由SRE 在 Jenkins 点单键发布到生产。 - 回滚策略:利用 Swarm 的
rollback_config,把stop-grace-period设为 30s,确保10 秒内完成新旧主题切换,降低业务感知。
答案
步骤一:提取企业 CI 规范
拿到市场部给出的Pantone 185C 主色、思源黑体字体、Logo SVG,用工具转成 CSS 变量值:
:root {
--color-primary: #E60012;
--color-secondary: #FFFFFF;
--font-family-sans-serif: "Source Han Sans CN", sans-serif;
}
步骤二:创建 theme-override.css
在源码仓库新建 .ci/portainer-theme/theme-override.css,仅覆盖必要变量,避免全量复制导致后续升级冲突:
/* 顶部导航栏 */
.navbar-default {
background-color: var(--color-primary) !important;
}
/* 按钮 */
.btn-primary {
background-color: var(--color-primary);
border-color: var(--color-primary);
}
/* Logo 替换 */
.navbar-brand {
background-image: url('assets/img/ci-logo.svg');
background-size: contain;
background-repeat: no-repeat;
width: 160px;
}
步骤三:构建企业版镜像
Dockerfile 片段:
FROM portainer/portainer-ce:2.19.4-alpine
COPY .ci/portainer-theme/theme-override.css /public/assets/css/
COPY .ci/portainer-theme/ci-logo.svg /public/assets/img/
关键点:使用精确版本号而非 latest,保证可审计;构建完成后立即 docker scan 做Trivy 漏洞扫描,高危≥HIGH 一律打回。
步骤四:CI/CD 集成
GitLab CI 阶段:
build-theme:npm 安装 sass,验证变量语法;docker-build:多阶段构建,推送至 Harbor 的私有项目ops/portainer:ci-{commit-sha};deploy-staging:通过 Swarmdocker stack deploy -c portainer-stg.yml滚动升级,设置 update-order: start-first,零中断;test-e2e:用 Cypress 跑登录页截图比对,确保主色色值偏差 ΔE≤3;manual-prod:SRE 点击确认后,镜像重打prod标签,再次 Trivy 扫描,通过后发布。
步骤五:灰度与回滚
Swarm 配置:
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 30s
failure_action: rollback
monitor: 60s
rollback_config:
parallelism: 1
delay: 5s
若主题导致控制台白屏,60 秒内自动回滚到旧版本,同时飞书机器人告警。
拓展思考
- 多租户场景:Portainer Business 版支持“每团队独立主题”,可通过
teamId动态注入 CSS,实现子公司 A 红色、子公司 B 蓝色的隔离需求。 - 暗黑模式:Angular 12 支持
prefers-color-scheme,可在 theme-override.css 追加@media (prefers-color-scheme: dark),自动切换深色变量,满足研发人员熬夜值班体验。 - 合规水印:在等保三级环境,审计要求**“页面必须带用户姓名水印”**,可通过 Angular Directive 注入 Canvas 水印,与主题文件一起版本化,避免人工贴图。
- 性能优化:主题 SVG Logo 若大于 30 KB,需转内联 base64 并走
gzip_static on,减少一次 TLS 往返;同时利用 HTTP Cache-Control: max-age=31536000, immutable,让浏览器永久缓存,控制台首屏加载时间从 1.8 s 降到 1.1 s。