From 82803db8710c34fa56fbb7ba137fd169579052b1 Mon Sep 17 00:00:00 2001 From: Eduardo Fraga Date: Tue, 8 Sep 2026 06:29:04 -0300 Subject: [PATCH] feat(content): add GLPI 12.0.0-rc1 announcement blog post (pt-br and en) --- .context/agents/README.md | 1 + .context/docs/README.md | 2 + .context/plans/README.md | 5 +- .../plans/glpi-12-0-0-rc1-announcement.md | 100 +++++++++++ content/en/blog/glpi-12-0-0-rc1.md | 153 +++++++++++++++++ content/pt-br/blog/glpi-12-0-0-rc1.md | 153 +++++++++++++++++ static/img/blog/glpi-12-0-0-rc1/cover.png | Bin 0 -> 37534 bytes .../blog/glpi-12-0-0-rc1/generate_cover.py | 158 ++++++++++++++++++ 8 files changed, 570 insertions(+), 2 deletions(-) create mode 100644 .context/plans/glpi-12-0-0-rc1-announcement.md create mode 100644 content/en/blog/glpi-12-0-0-rc1.md create mode 100644 content/pt-br/blog/glpi-12-0-0-rc1.md create mode 100644 static/img/blog/glpi-12-0-0-rc1/cover.png create mode 100644 static/img/blog/glpi-12-0-0-rc1/generate_cover.py diff --git a/.context/agents/README.md b/.context/agents/README.md index 2340b98..e29e453 100644 --- a/.context/agents/README.md +++ b/.context/agents/README.md @@ -28,3 +28,4 @@ This directory contains ready-to-customize playbooks for AI agents collaborating - [Documentation Index](../docs/README.md) - [Agent Knowledge Base](../../AGENTS.md) - [Contributor Guidelines](../../CONTRIBUTING.md) +- [Release Blog Post (GLPI 12.0.0-rc1)](../../content/en/blog/glpi-12-0-0-rc1.md) diff --git a/.context/docs/README.md b/.context/docs/README.md index 2dbcb81..973e89d 100644 --- a/.context/docs/README.md +++ b/.context/docs/README.md @@ -5,6 +5,8 @@ Welcome to the repository knowledge base. Start with the project overview, then **Blog Posts Reference** The following blog posts have been added to the documentation index: +- [GLPI 12.0.0-rc1 and Helm Chart 2.12.0: Subchart Modernization, Security Hardening, and High Availability](../../content/en/blog/glpi-12-0-0-rc1.md) (en) — EF-TECH release of GLPI 12.0.0-rc1 and Helm Chart 2.12.0 with Valkey subchart, PDB, HPA, S3 backup, and readOnlyRootFilesystem hardening +- [GLPI 12.0.0-rc1 e Helm Chart 2.12.0: modernização de subcharts, hardening e alta disponibilidade](../../content/pt-br/blog/glpi-12-0-0-rc1.md) (pt-br) — Lançamento da EF-TECH do GLPI 12.0.0-rc1 e Helm Chart 2.12.0 com subchart Valkey, PDB, HPA, backup S3 e hardening com readOnlyRootFilesystem - [Understanding P99 and Tail Latency](../../content/en/blog/p99-tail-latency/index.md) (en) — Why the mean lies and how to eliminate tail latency bottlenecks in production - [P99 e Latência de Cauda (Tail Latency)](../../content/pt-br/blog/p99-tail-latency/index.md) (pt-br) — Por que a média engana e como mitigar gargalos de latência de cauda em produção - [Understanding RFC 10008: The HTTP QUERY Method](../../content/en/blog/rfc-10008-http-query.md) (en) — Standardizing HTTP QUERY as a safe and idempotent method with a body payload diff --git a/.context/plans/README.md b/.context/plans/README.md index 364f97a..acdce10 100644 --- a/.context/plans/README.md +++ b/.context/plans/README.md @@ -6,8 +6,9 @@ This directory contains plans for coordinating work across documentation and pla 1. [Add Whatsapp Link](./add-whatsapp-link.md) 2. [Blog Hermes K8s Install](./blog-hermes-k8s-install.md) 3. [Blog Image Support](./blog-image-support.md) -4. [Oracle Always Free Post](./oracle-always-free-post.md) -5. [Rfc 10008 Blog Post](./rfc-10008-blog-post.md) +4. [Glpi 12 0 0 Rc1 Announcement](./glpi-12-0-0-rc1-announcement.md) +5. [Oracle Always Free Post](./oracle-always-free-post.md) +6. [Rfc 10008 Blog Post](./rfc-10008-blog-post.md) ## How To Create Or Update Plans - Run "ai-context plan " to scaffold a new plan template. diff --git a/.context/plans/glpi-12-0-0-rc1-announcement.md b/.context/plans/glpi-12-0-0-rc1-announcement.md new file mode 100644 index 0000000..1bb64d6 --- /dev/null +++ b/.context/plans/glpi-12-0-0-rc1-announcement.md @@ -0,0 +1,100 @@ +--- +status: active +generated: 2026-09-08 +agents: + - type: "documentation-writer" + role: "Draft clear, comprehensive announcement blog posts in PT-BR and EN" + - type: "frontend-specialist" + role: "Generate cover PNG image and integrate media into Hugo posts" + - type: "devops-specialist" + role: "Validate Hugo build, link checks, and prepare git branch and PR" +docs: + - "project-overview.md" + - "architecture.md" + - "development-workflow.md" +phases: + - id: "phase-1" + name: "Discovery & Alignment" + prevc: "P" + agent: "documentation-writer" + - id: "phase-2" + name: "Implementation & Iteration" + prevc: "E" + agent: "documentation-writer" + - id: "phase-3" + name: "Validation & Handoff" + prevc: "V" + agent: "devops-specialist" +--- + +# GLPI 12.0.0-rc1 Blog Post Announcement Plan + +> Create EN and PT-BR blog posts for GLPI 12.0.0-rc1 release, generate PNG cover image, validate with Hugo, and prepare PR. + +## Task Snapshot +- **Primary goal:** Publish announcement blog posts in Portuguese (`content/pt-br/blog/glpi-12-0-0-rc1.md`) and English (`content/en/blog/glpi-12-0-0-rc1.md`) covering GLPI 12.0.0-rc1 / Helm Chart 2.12.0 from EF-TECH, with a generated featured PNG image and validated links. +- **Success signal:** Clean Hugo production build (`hugo --gc --minify`), no broken images or links, both language versions published, and a clean Git commit / PR ready. +- **Key references:** + - [Documentation Index](../docs/README.md) + - [Agent Handbook](../agents/README.md) + - [Plans Index](./README.md) + - [GitHub Release eftechcombr/glpi](https://github.com/eftechcombr/glpi/releases/tag/v12.0.0-rc1) + +## Codebase Context +- **Hugo Site:** Multilingual setup with `pt-br` as default and `en` language section. +- **Blog Post Location:** `content/pt-br/blog/` and `content/en/blog/`. +- **Assets:** `static/img/blog/glpi-12-0-0-rc1/cover.png` generated via Python PIL script. + +## Agent Lineup +| Agent | Role in this plan | Playbook | First responsibility focus | +| --- | --- | --- | --- | +| Documentation Writer | Technical content creation | [Documentation Writer](../agents/documentation-writer.md) | Draft accurate, engaging release notes in PT-BR and EN | +| Frontend Specialist | Media & Image generation | [Frontend Specialist](../agents/frontend-specialist.md) | Design and generate cover PNG image matching site theme | +| DevOps Specialist | Build & verification | [Devops Specialist](../agents/devops-specialist.md) | Validate Hugo build, verify links, manage git PR | + +## Documentation Touchpoints +| Guide | File | Primary Inputs | +| --- | --- | --- | +| Project Overview | [project-overview.md](../docs/project-overview.md) | Site structure, multilingual content mapping | +| Development Workflow | [development-workflow.md](../docs/development-workflow.md) | Hugo commands, link trailing slash requirements, PR process | + +## Working Phases + +### Phase 1 — Discovery & Alignment +> **Primary Agent:** `documentation-writer` - [Playbook](../agents/documentation-writer.md) + +**Objective:** Inspect release details from `eftechcombr/glpi`, analyze existing blog post patterns (`glpi-11-0-8.md`), and prepare structured content outline. + +**Tasks** +| # | Task | Agent | Status | Deliverable | +|---|------|-------|--------|-------------| +| 1.1 | Analyze GLPI 12.0.0-rc1 release notes and PR details | `documentation-writer` | completed | Content outline | +| 1.2 | Design cover image concept and specifications | `frontend-specialist` | completed | Python PIL generation script | + +--- + +### Phase 2 — Implementation & Iteration +> **Primary Agent:** `documentation-writer` - [Playbook](../agents/documentation-writer.md) + +**Objective:** Generate PNG cover image and author comprehensive blog posts in PT-BR and EN with proper frontmatter, code snippets, and internal links. + +**Tasks** +| # | Task | Agent | Status | Deliverable | +|---|------|-------|--------|-------------| +| 2.1 | Generate 1200x630 cover PNG at `static/img/blog/glpi-12-0-0-rc1/cover.png` | `frontend-specialist` | pending | Cover image PNG | +| 2.2 | Write `content/pt-br/blog/glpi-12-0-0-rc1.md` | `documentation-writer` | pending | Portuguese blog post | +| 2.3 | Write `content/en/blog/glpi-12-0-0-rc1.md` | `documentation-writer` | pending | English blog post | + +--- + +### Phase 3 — Validation & Handoff +> **Primary Agent:** `devops-specialist` - [Playbook](../agents/devops-specialist.md) + +**Objective:** Validate Hugo build, verify all links and image paths, commit changes, create PR and monitor checks. + +**Tasks** +| # | Task | Agent | Status | Deliverable | +|---|------|-------|--------|-------------| +| 3.1 | Test build with `hugo --gc --minify` | `devops-specialist` | pending | Build verification | +| 3.2 | Check image rendering and link integrity | `devops-specialist` | pending | No 404 or broken links | +| 3.3 | Create git branch, commit, push, create PR and verify CI | `devops-specialist` | pending | Merged or approved PR | diff --git a/content/en/blog/glpi-12-0-0-rc1.md b/content/en/blog/glpi-12-0-0-rc1.md new file mode 100644 index 0000000..437efc9 --- /dev/null +++ b/content/en/blog/glpi-12-0-0-rc1.md @@ -0,0 +1,153 @@ +--- +title: "GLPI 12.0.0-rc1 and Helm Chart 2.12.0: Subchart Modernization, Security Hardening, and High Availability" +description: "EF-TECH announces the release of GLPI 12.0.0-rc1 and Helm Chart 2.12.0. Discover key updates: Valkey subchart, PDB, HPA, S3 backup, and readOnlyRootFilesystem hardening." +summary: "EF-TECH releases Docker images for GLPI 12.0.0-rc1 and Helm Chart 2.12.0, introducing Valkey subchart support, external cache options, PDB/HPA for php-fpm and nginx, S3 backup CronJob, and enterprise security hardening." +date: 2026-09-06 +draft: false +tags: ["glpi", "docker", "kubernetes", "helm", "cloud-native", "security"] +categories: ["infrastructure"] +featureimage: "/img/blog/glpi-12-0-0-rc1/cover.png" +featureimagecaption: "GLPI 12.0.0-rc1 and Helm Chart 2.12.0 from EF-TECH" +--- + +EF-TECH is excited to announce the release of **GLPI 12.0.0-rc1** (Release Candidate) alongside **Helm Chart version 2.12.0**. This release marks a significant architectural milestone in the evolution of EF-TECH's cloud-native GLPI distribution, bringing subchart modernization, native Valkey cache support, horizontal scalability, automated S3 backups, and enterprise-grade security hardening for Kubernetes clusters. + +![GLPI 12.0.0-rc1 and Helm Chart 2.12.0](/img/blog/glpi-12-0-0-rc1/cover.png) + +As a **Release Candidate**, this pre-release is designed for teams wanting to evaluate GLPI 12's upcoming capabilities, test new features in staging environments, and validate database and configuration migration paths ahead of the general availability release. + +--- + +## Key Updates and New Features + +### 1. Subchart Modernization: Valkey and MariaDB + +To stay aligned with current open-source standards and ensure dependable lifecycle management: + +- **Valkey Subchart (`helmforge/valkey`)**: Replaced the previous inline Redis subchart with **Valkey**, the high-performance open-source in-memory data store hosted under the Linux Foundation. Valkey handles GLPI session caching and background state efficiently. +- **MariaDB Subchart (`helmforge/mariadb`)**: Replaced inline MariaDB with the modernized and dedicated `helmforge/mariadb` subchart. +- **External Cache Configuration (`externalCache`)**: Added direct configuration parameters for teams deploying against managed cache clusters (such as AWS ElastiCache, Azure Redis, or independent Valkey/Redis instances). + +### 2. High Availability and Scalability (PDB and HPA) + +To ensure enterprise-grade resilience and smooth traffic handling under heavy loads: + +- **PodDisruptionBudget (PDB)**: Added optional PDB configurations for both `php-fpm` and `nginx` pods. This guarantees minimum available replicas during voluntary disruptions like node drains, cluster maintenance, or node pool upgrades. +- **HorizontalPodAutoscaler (HPA)**: Added optional HPA v2 autoscaling support for `php-fpm` and `nginx`, automatically adjusting pod replicas according to CPU and memory utilization thresholds. +- **Workload Scheduling with `priorityClassName`**: Added `priorityClassName` support for GLPI-owned pods, ensuring Kubernetes prioritizes GLPI workload scheduling and prevents preemption by lower-priority workloads. + +### 3. Security Hardening and Least Privilege + +Security in Kubernetes environments is a core focus at EF-TECH: + +- **Root Filesystem Hardening (`readOnlyRootFilesystem`)**: Added optional `readOnlyRootFilesystem: true` hardening, empirically tested and verified for GLPI's runtime needs using appropriate ephemeral volume mounts for temporary paths. +- **Nginx Attack Surface Reduction**: Removed unused volume mounts and database secrets from the Nginx container, strictly following the principle of least privilege. +- **Secret Separation for Databases**: The database password (`MARIADB_PASSWORD`) is now retrieved directly from the MariaDB subchart's Secret. +- **Existing Secret Support for External Databases**: When connecting to an `externalDatabase`, you can supply an `existingSecret` with fast-fail validation to ensure misconfigurations are detected before pods attempt to boot. + +### 4. Operational Reliability and S3 Backup + +- **Files Backup CronJob to S3-Compatible Storage**: Added a dedicated CronJob to automatically back up uploaded GLPI files and attachments (`/var/lib/glpi/files`) to S3-compatible storage (AWS S3, MinIO, Cloudflare R2, or Ceph). +- **Readiness-Gated Maintenance CronJob**: The maintenance CronJob now actively checks and waits for GLPI application and database readiness, preventing spurious errors during pod rollout or restarts. +- **Resource Presets (`resourcesPreset`)**: Added Bitnami-style resource tiers (`nano`, `micro`, `small`, `medium`, `large`, `xlarge`) to simplify pod resource allocations based on organizational workload requirements. +- **Chart Reorganization & Artifact Hub Compliance**: Chart files have been cleanly reorganized under the standard `helm/` directory structure, resolving all Artifact Hub metadata validations. + +--- + +## Component Matrix + +| Componente | Version | Source / Catalog | +|---|---|---| +| GLPI (Application) | `12.0.0-rc1` | [ghcr.io/eftechcombr/glpi](https://github.com/eftechcombr/glpi/packages) | +| Helm Chart | `2.12.0` | [eftech/glpi](https://github.com/eftechcombr/glpi/releases/tag/glpi-2.12.0) | +| Default Cache | Valkey | `helmforge/valkey` | +| Default Database | MariaDB | `helmforge/mariadb` | + +--- + +## Installation and Upgrade Guide + +### Upgrading via Helm Chart + +Add or update the official EF-TECH Helm repository and run the upgrade: + +```bash +# Add or update the EF-TECH Helm repository +helm repo add eftech https://eftechcombr.github.io/glpi/charts +helm repo update + +# Install or upgrade to version 2.12.0 +helm upgrade --install glpi eftech/glpi \ + --namespace glpi \ + --create-namespace \ + --version 2.12.0 +``` + +### Example `values.yaml` Configuration + +Here is an example demonstrating the new high availability, hardening, and resource preset options: + +```yaml +# Standardized resource tier +resourcesPreset: "medium" + +# Filesystem security hardening +securityContext: + readOnlyRootFilesystem: true + +# High availability with PodDisruptionBudget +podDisruptionBudget: + enabled: true + minAvailable: 1 + +# Horizontal Pod Autoscaling (HPA) +autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 8 + targetCPUUtilizationPercentage: 75 + targetMemoryUtilizationPercentage: 80 + +# Kubernetes scheduling priority +priorityClassName: "system-cluster-critical" + +# Modernized Valkey cache +valkey: + enabled: true + +# S3-compatible files backup +backup: + files: + enabled: true + schedule: "0 2 * * *" # Daily at 02:00 UTC + s3: + endpoint: "https://s3.amazonaws.com" + bucket: "my-glpi-backup-bucket" + region: "us-east-1" + existingSecret: "s3-backup-credentials" +``` + +### Upgrading via Docker + +If running standalone containers with Docker or Docker Compose: + +```bash +docker pull ghcr.io/eftechcombr/glpi:12.0.0-rc1 +``` + +--- + +## Useful Links + +- [Official EF-TECH GLPI Repository on GitHub](https://github.com/eftechcombr/glpi) +- [GLPI 12.0.0-rc1 Release Notes](https://github.com/eftechcombr/glpi/releases/tag/v12.0.0-rc1) +- [Helm Chart 2.12.0 Release](https://github.com/eftechcombr/glpi/releases/tag/glpi-2.12.0) +- [Docker Image Packages and Releases](https://github.com/eftechcombr/glpi/packages) + +--- + +## Enterprise Support & Consulting + +**EF-TECH** specializes in architecting, deploying, and maintaining high-performance ITSM and Service Desk platforms on Kubernetes. We provide enterprise support, migration assistance, and continuous maintenance for containerized GLPI deployments. + +Preparing for GLPI 12 or looking to modernize your ITSM infrastructure? [Contact our team](/en/contato/) to speak with an infrastructure specialist. diff --git a/content/pt-br/blog/glpi-12-0-0-rc1.md b/content/pt-br/blog/glpi-12-0-0-rc1.md new file mode 100644 index 0000000..e2c15e2 --- /dev/null +++ b/content/pt-br/blog/glpi-12-0-0-rc1.md @@ -0,0 +1,153 @@ +--- +title: "GLPI 12.0.0-rc1 e Helm Chart 2.12.0: modernização de subcharts, hardening e alta disponibilidade" +description: "A EF-TECH anuncia o lançamento do GLPI 12.0.0-rc1 e Helm Chart 2.12.0. Conheça as novidades: subchart Valkey, PDB, HPA, backup para S3 e hardening com readOnlyRootFilesystem." +summary: "A EF-TECH disponibiliza as imagens Docker do GLPI 12.0.0-rc1 e a versão 2.12.0 do Helm Chart, trazendo subchart Valkey, suporte a cache externo, PDB/HPA para php-fpm e nginx, backup S3 e hardening de segurança." +date: 2026-09-06 +draft: false +tags: ["glpi", "docker", "kubernetes", "helm", "cloud-native", "seguranca"] +categories: ["infraestrutura"] +featureimage: "/img/blog/glpi-12-0-0-rc1/cover.png" +featureimagecaption: "GLPI 12.0.0-rc1 e Helm Chart 2.12.0 da EF-TECH" +--- + +A EF-TECH tem o orgulho de anunciar o lançamento do **GLPI 12.0.0-rc1** (Release Candidate) e a nova versão **2.12.0 do nosso Helm Chart**. Esta atualização representa um marco arquitetural importante na evolução da distribuição cloud-native do GLPI mantida pela EF-TECH, introduzindo modernização completa de dependências, suporte a cache Valkey, escalabilidade horizontal, rotinas automatizadas de backup em S3 e reforços substanciais de segurança para clusters Kubernetes corporativos. + +![GLPI 12.0.0-rc1 e Helm Chart 2.12.0](/img/blog/glpi-12-0-0-rc1/cover.png) + +Como se trata de um **Release Candidate**, esta versão é ideal para times que desejam validar o novo ciclo do GLPI 12, testar novos recursos em ambientes de homologação e homologar fluxos de migração antes da versão final de produção. + +--- + +## Principais Novidades e Melhorias + +### 1. Modernização de Subcharts: Valkey e MariaDB + +Para acompanhar a evolução do ecossistema open-source e garantir compatibilidade a longo prazo, o Helm Chart agora adota subcharts independentes e modernos: + +- **Subchart Valkey (`helmforge/valkey`)**: substituímos o subchart inline de Redis pelo **Valkey**, fork de código aberto sob governança da Linux Foundation. O Valkey oferece alto desempenho para sessões e cache do GLPI com total aderência aos padrões abertos. +- **Subchart MariaDB (`helmforge/mariadb`)**: substituímos o MariaDB inline por um subchart dedicado e atualizado do `helmforge/mariadb`. +- **Suporte a `externalCache`**: agora é possível apontar o GLPI diretamente para clusters externos de Valkey ou Redis gerenciados (como AWS ElastiCache, Azure Redis ou instâncias dedicadas) através de configurações explícitas no `values.yaml`. + +### 2. Alta Disponibilidade e Escalabilidade (PDB e HPA) + +Para ambientes de missão crítica que necessitam de tolerância a falhas e escalabilidade dinâmica: + +- **PodDisruptionBudget (PDB)**: suporte opcional a PDB tanto para os pods de `php-fpm` quanto para o `nginx`. Garante que durante manutenções programadas de nós (como upgrades de cluster e drenagem de nós com `kubectl drain`), um número mínimo de réplicas permaneça saudável e disponível. +- **HorizontalPodAutoscaler (HPA)**: suporte opcional a HPA v2 para autoescalonamento dinâmico de réplicas de `php-fpm` e `nginx` baseado no consumo real de CPU e memória. +- **`priorityClassName` para Pods GLPI**: atribuição de classes de prioridade aos pods do GLPI, garantindo que o Kubernetes priorize o agendamento e a retenção do serviço de chamados frente a workloads não críticos. + +### 3. Hardening de Segurança Avançado + +A segurança é um dos pilares do trabalho da EF-TECH com contêineres e Kubernetes: + +- **Hardening com `readOnlyRootFilesystem`**: adicionamos suporte opcional para montar o sistema de arquivos raiz como somente leitura (`readOnlyRootFilesystem: true`), empiricamente verificado e compatível com as necessidades de escrita temporária do GLPI através de volumes efêmeros. +- **Isolamento do Nginx**: removemos montagens de volume desnecessárias e variáveis com credenciais de banco de dados do contêiner do Nginx, respeitando estritamente o princípio do menor privilégio. +- **Gestão de Segredos de Banco de Dados**: a senha `MARIADB_PASSWORD` agora é lida diretamente da Secret gerada pelo subchart MariaDB. +- **Suporte a `existingSecret` para `externalDatabase`**: ao utilizar bancos de dados externos, você pode referenciar uma Secret preexistente com validação *fast-fail* — se a Secret ou a chave não existirem, a renderização do chart falha imediatamente, evitando deploys inconsistentes. + +### 4. Confiabilidade Operacional e Backup S3 + +- **Backup Automatizado de Arquivos para S3**: introduzimos um CronJob dedicado para backup periódico dos documentos e anexos do GLPI (`/var/lib/glpi/files`) diretamente para buckets S3 compatíveis (AWS S3, MinIO, Cloudflare R2 ou Ceph). +- **Gating de Prontidão no CronJob de Manutenção**: o CronJob responsável pelas tarefas rotineiras do GLPI agora aguarda ativamente a prontidão do GLPI e do banco de dados antes de disparar os comandos, eliminando falhas transitórias durante reinicializações. +- **Presets de Recursos (`resourcesPreset`)**: inclusão de níveis padronizados de recursos estilo Bitnami (`nano`, `micro`, `small`, `medium`, `large`, `xlarge`), facilitando o dimensionamento correto de CPU e memória para cada porte de organização. +- **Estrutura Helm e Artifact Hub**: reorganização de todos os templates do chart no diretório padronizado `helm/` e conformidade completa com os requisitos de validação do Artifact Hub. + +--- + +## Matriz de Versões + +| Componente | Versão | Origem / Catálogo | +|---|---|---| +| GLPI (Aplicação) | `12.0.0-rc1` | [ghcr.io/eftechcombr/glpi](https://github.com/eftechcombr/glpi/packages) | +| Helm Chart | `2.12.0` | [eftech/glpi](https://github.com/eftechcombr/glpi/releases/tag/glpi-2.12.0) | +| Cache padrão | Valkey | `helmforge/valkey` | +| Banco padrão | MariaDB | `helmforge/mariadb` | + +--- + +## Como Instalar e Atualizar + +### Atualização via Helm Chart + +Adicione o repositório oficial de charts da EF-TECH (ou atualize seu catálogo) e execute a instalação ou upgrade: + +```bash +# Adicionar ou atualizar o repositório Helm da EF-TECH +helm repo add eftech https://eftechcombr.github.io/glpi/charts +helm repo update + +# Instalar ou atualizar para a versão 2.12.0 +helm upgrade --install glpi eftech/glpi \ + --namespace glpi \ + --create-namespace \ + --version 2.12.0 +``` + +### Exemplo de Configuração (`values.yaml`) + +Abaixo está um exemplo prático demonstrando o uso dos novos recursos de alta disponibilidade, hardening e presets de recursos: + +```yaml +# Definir preset de recursos padronizado +resourcesPreset: "medium" + +# Hardening do sistema de arquivos +securityContext: + readOnlyRootFilesystem: true + +# Alta disponibilidade com PDB +podDisruptionBudget: + enabled: true + minAvailable: 1 + +# Autoescalonamento horizontal (HPA) +autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 8 + targetCPUUtilizationPercentage: 75 + targetMemoryUtilizationPercentage: 80 + +# Prioridade no agendamento Kubernetes +priorityClassName: "system-cluster-critical" + +# Subchart Valkey ativado por padrão +valkey: + enabled: true + +# Backup automatizado para storage S3 compatível +backup: + files: + enabled: true + schedule: "0 2 * * *" # Todos os dias às 02:00 + s3: + endpoint: "https://s3.amazonaws.com" + bucket: "meu-bucket-glpi-backups" + region: "us-east-1" + existingSecret: "s3-backup-credentials" +``` + +### Imagem Docker Standalone + +Se você opera o GLPI diretamente no Docker ou Docker Compose: + +```bash +docker pull ghcr.io/eftechcombr/glpi:12.0.0-rc1 +``` + +--- + +## Links e Referências + +- [Repositório Oficial EF-TECH GLPI no GitHub](https://github.com/eftechcombr/glpi) +- [Release GLPI 12.0.0-rc1](https://github.com/eftechcombr/glpi/releases/tag/v12.0.0-rc1) +- [Release Helm Chart 2.12.0](https://github.com/eftechcombr/glpi/releases/tag/glpi-2.12.0) +- [Catálogo de Imagens e Pacotes](https://github.com/eftechcombr/glpi/packages) + +--- + +## Suporte e Consultoria Especializada + +A **EF-TECH** é referência em arquiteturas de Service Desk, ITSM e automação de infraestrutura. Projetamos, implantamos e mantemos ambientes GLPI em Kubernetes de alta performance com observabilidade, segurança e escalabilidade garantidas. + +Precisa de apoio para planejar o ciclo de homologação do GLPI 12 ou modernizar a infraestrutura da sua empresa? [Entre em contato com nossos especialistas](/pt-br/contato/). diff --git a/static/img/blog/glpi-12-0-0-rc1/cover.png b/static/img/blog/glpi-12-0-0-rc1/cover.png new file mode 100644 index 0000000000000000000000000000000000000000..18c50c8afe92a4605c4a4130fc80d6108c826e96 GIT binary patch literal 37534 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 literal 0 HcmV?d00001 diff --git a/static/img/blog/glpi-12-0-0-rc1/generate_cover.py b/static/img/blog/glpi-12-0-0-rc1/generate_cover.py new file mode 100644 index 0000000..48fc11a --- /dev/null +++ b/static/img/blog/glpi-12-0-0-rc1/generate_cover.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +""" +Generate the featured image (1200x630px PNG) for the GLPI 12.0.0-rc1 blog post. + +Design: + - Dark navy gradient background (#0e1120 -> #1e2a4a) with a grid of dots + - A terminal window showing `helm upgrade --install glpi eftech/glpi --version 2.12.0` + and key cloud-native features (Valkey, MariaDB subchart, readOnlyRootFilesystem, HPA/PDB, S3 Backup) + - Big title "GLPI 12.0.0-rc1", subtitle "Helm Chart 2.12.0 — Modernized Subcharts & Cloud-Native Hardening", + and EF-TECH branding at the bottom right + +Requires: pip install pillow +""" + +import os +import sys + +try: + from PIL import Image, ImageDraw, ImageFont +except ImportError: + print("Pillow is required. Install it with: pip install pillow") + sys.exit(1) + +WIDTH, HEIGHT = 1200, 630 + + +def find_font(size: int, bold: bool = False) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: + """Try to find a suitable monospace font on the system.""" + candidates = [] + if bold: + candidates = [ + "/System/Library/Fonts/Supplemental/SFNSMono-Bold.otf", + "/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf", + "/usr/share/fonts/truetype/ubuntu/UbuntuMono-B.ttf", + "/usr/share/fonts/truetype/liberation/LiberationMono-Bold.ttf", + ] + candidates += [ + "/System/Library/Fonts/Supplemental/SFNSMono-Regular.otf", + "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/truetype/ubuntu/UbuntuMono-R.ttf", + "/usr/share/fonts/truetype/liberation/LiberationMono.ttf", + ] + for path in candidates: + if os.path.exists(path): + return ImageFont.truetype(path, size) + return ImageFont.load_default() + + +def draw_terminal_window(draw: ImageDraw, x: int, y: int, w: int, h: int) -> None: + """Draw a terminal window with a title bar.""" + # Window shadow + shadow_offset = 4 + draw.rounded_rectangle( + [x + shadow_offset, y + shadow_offset, x + w + shadow_offset, y + h + shadow_offset], + radius=12, fill=(0, 0, 0, 60) + ) + # Window body (dark terminal bg) + draw.rounded_rectangle( + [x, y, x + w, y + h], radius=10, fill=(22, 26, 46) + ) + # Title bar area + draw.rounded_rectangle( + [x, y, x + w, y + 42], radius=10, fill=(32, 38, 64) + ) + # Flatten bottom corners of title bar + draw.rectangle([x, y + 32, x + w, y + 42], fill=(32, 38, 64)) + # Traffic light buttons + for cx, color in [(x + 20, (255, 95, 87)), (x + 46, (255, 189, 46)), (x + 72, (39, 201, 63))]: + draw.ellipse([cx, y + 14, cx + 14, y + 28], fill=color) + # Title text in title bar + font_title = find_font(15) + draw.text((x + w // 2, y + 21), "helm — eftech/glpi:2.12.0", fill=(170, 180, 210), + font=font_title, anchor="mm") + + +def create_featured_image(output_path: str) -> None: + """Create the 1200x630 OG image for the GLPI 12.0.0-rc1 post.""" + img = Image.new("RGBA", (WIDTH, HEIGHT), (14, 17, 32, 255)) + draw = ImageDraw.Draw(img) + + # Background: subtle gradient #0e1120 (top) -> #1e2a4a (bottom) + top = (14, 17, 32) + bottom = (30, 42, 74) + for i in range(HEIGHT): + t = i / HEIGHT + r = int(top[0] + (bottom[0] - top[0]) * t) + g = int(top[1] + (bottom[1] - top[1]) * t) + b = int(top[2] + (bottom[2] - top[2]) * t) + draw.line([(0, i), (WIDTH, i)], fill=(r, g, b, 255)) + + # Decorative grid dots + for x in range(0, WIDTH, 30): + for y in range(0, HEIGHT, 30): + draw.point((x, y), fill=(70, 84, 130, 60)) + + # Terminal window (central element) + tw, th = 960, 360 + tx, ty = (WIDTH - tw) // 2, 30 + draw_terminal_window(draw, tx, ty, tw, th) + + # Terminal content + font_cmd = find_font(15, bold=True) + font_out = find_font(14) + font_highlight = find_font(14, bold=True) + + prompt_x = tx + 30 + line_y = ty + 56 + + # Command line + draw.text((prompt_x, line_y), "$", fill=(82, 188, 74), font=font_cmd) + draw.text((prompt_x + 20, line_y), " helm upgrade --install glpi eftech/glpi --version 2.12.0", fill=(240, 242, 250), font=font_cmd) + line_y += 24 + + terminal_lines = [ + ("Release \"glpi\" has been upgraded. Status: DEPLOYED (app: 12.0.0-rc1)", (120, 170, 255), False), + ("✔ Subcharts: modern helmforge/valkey & helmforge/mariadb enabled", (82, 188, 74), True), + ("✔ High Availability: PodDisruptionBudget & HPA configured (php-fpm / nginx)", (160, 190, 235), False), + ("✔ Security: readOnlyRootFilesystem hardening active (empirically verified)", (160, 190, 235), False), + ("✔ Storage: S3 files backup CronJob scheduled with custom credentials", (160, 190, 235), False), + ("✔ Workload: priorityClassName support & Bitnami-style resourcesPreset", (160, 190, 235), False), + ("✔ Operations: maintenance CronJob gated on database readiness", (140, 170, 215), False), + ] + + for text, color, bold in terminal_lines: + f = font_highlight if bold else font_out + draw.text((prompt_x, line_y), text, fill=color, font=f) + line_y += 22 + + line_y += 6 + draw.text((prompt_x, line_y), "$ docker pull ghcr.io/eftechcombr/glpi:12.0.0-rc1", fill=(225, 230, 245), font=font_cmd) + + # Title overlay below the terminal + title_font = find_font(46, bold=True) + draw.text((WIDTH // 2, ty + th + 66), "GLPI 12.0.0-rc1 & Helm Chart 2.12.0", + fill=(255, 255, 255), font=title_font, anchor="mm") + + subtitle_font = find_font(23, bold=True) + draw.text((WIDTH // 2, ty + th + 118), "Modernized Subcharts · Valkey Cache · Cloud-Native Hardening · S3 Backup", + fill=(94, 170, 255), font=subtitle_font, anchor="mm") + + info_font = find_font(15) + draw.text((WIDTH // 2, ty + th + 156), "Pre-release · EF-TECH Containers & Helm · Kubernetes-Ready ITSM", + fill=(140, 150, 185), font=info_font, anchor="mm") + + # EF-TECH branding + brand_font = find_font(14, bold=True) + draw.text((WIDTH - 30, HEIGHT - 20), "EF-TECH", fill=(100, 110, 145), font=brand_font, anchor="rs") + + # Convert to RGB and save as PNG + final = Image.new("RGB", (WIDTH, HEIGHT), (14, 17, 32)) + final.paste(img, mask=img.split()[3]) + final.save(output_path, "PNG") + print(f"Image saved to {output_path} ({WIDTH}x{HEIGHT})") + + +if __name__ == "__main__": + output = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cover.png") + create_featured_image(output)