Back to Articles
25 min read

Building a Production-Ready GitOps Platform on Talos Kubernetes

A technical deep dive into implementing infrastructure as code with ArgoCD, Sealed Secrets, and microservices architecture. This guide details the design of a secure, automated deployment pipeline capable of managing encrypted secrets within a public Git repository.

Talos LinuxKubernetesArgoCDGitOpsSealed SecretsMicroservicesInfrastructure as Code

Executive Summary

This architectural reference documents the design and implementation of a resilient GitOps platform orchestrated on Talos Linux Kubernetes. The system solves core infrastructure challenges including secret encryption at rest, microservice isolation, cross-namespace service discovery, and declarative continuous deployment.

Key Technologies

  • • Talos Linux v1.11.3 (Immutable OS)
  • • Kubernetes v1.34.1
  • • ArgoCD (GitOps Controller)
  • • Bitnami Sealed Secrets (Asymmetric Encryption)
  • • PostgreSQL 16 & Redis 7

Outcomes

  • • 100% declarative infrastructure state
  • • Zero-trust secret management in Git
  • • Fully automated synchronization pipelines
  • • Namespace-isolated microservices
  • • Reduced operational overhead via self-healing

The Challenge

Production-grade Kubernetes environments require rigorous solutions to several fundamental problems. The primary challenge lies in reconciling the transparency of GitOps with the confidentiality required for credentials. Storing sensitive data in public repositories exposes systems to immediate compromise, yet maintaining secrets outside of version control breaks the "single source of truth" paradigm essential to GitOps.

Furthermore, managing shared resources across distinct applications without sacrificing isolation presents complex networking and access control hurdles. The objective was to architect a platform that enables continuous deployment and efficient resource utilization while enforcing strict security boundaries.

Architecture Overview

Git Repository
GitHub - Source of Truth
SOURCE
SSH Auth • Sync ~3m
ArgoCD Controller
Running in Kubernetes
CONTROLLER
Applies Manifests
Kubernetes Cluster
Data Services
PostgreSQL
Redis
Applications
Chatbot
Future Apps

Infrastructure Topology

Control Plane:1 node (talos-6jj-ne0) - API Server & Etcd
Workers:2 nodes (talos-adj-2hp, talos-gey-agp) - Workloads
CNI:Flannel (VXLAN overlay network 10.244.0.0/16)
Storage:local-path provisioner (Dynamic PV binding)

Multi-Namespace Architecture

The cluster employs a multi-namespace architecture to enforce logical separation of concerns. This design pattern allows for granular resource quotas, network policies, and access controls while enabling efficient resource sharing where appropriate.

Infrastructure Namespace (data)

The data namespace functions as a shared service layer. By centralizing stateful workloads here, the architecture reduces the operational overhead of managing redundant database instances for every microservice.

Components:

  • • PostgreSQL 16 (10Gi persistent volume claim)
  • • Redis 7 (In-memory cache with Append Only File persistence)

Service Endpoints:

postgres.data.svc.cluster.local:5432
redis.data.svc.cluster.local:6379

Application Namespace (chatbot)

Application namespaces host the stateless microservices associated with specific business domains. Each service maintains its own deployment lifecycle, with configuration injected at runtime via Kubernetes ConfigMaps and Secrets.

  • • API service (backend logic)
  • • UI service (frontend presentation)
  • • Worker service (async task processing)

Secret Management with Sealed Secrets

The Problem

Standard Kubernetes Secrets are merely base64-encoded strings, offering no encryption at rest within the configuration files. This limitation effectively prevents the commitment of secret manifests to version control systems, creating a divergence between the desired state (Git) and the actual state (Cluster).

The Solution

Bitnami Sealed Secrets implements asymmetric cryptography to secure credentials. The cluster maintains a private key known only to the Sealed Secrets controller, while a public key is distributed to developers. This allows secrets to be encrypted offline ("sealed") and safely committed to public repositories.

Workflow Lifecycle

1Developer defines secret payload locally
2Payload is encrypted using the cluster's public key (kubeseal)
3Encrypted SealedSecret manifest is pushed to Git
4ArgoCD synchronizes the manifest to the cluster
5Controller decrypts the payload using the private key
6Standard Kubernetes Secret is generated in the target namespace

Implementation Details

# Install Sealed Secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/\
  releases/download/v0.26.0/controller.yaml

# Fetch the public key
kubeseal --fetch-cert > sealed-secrets-cert.pem

# Create and encrypt a secret
kubectl create secret generic my-secret \
  --namespace=my-namespace \
  --from-literal=password=super-secret \
  --dry-run=client -o yaml | \
kubeseal --format yaml --cert sealed-secrets-cert.pem \
  > my-sealed-secret.yaml

# Commit the encrypted version
git add my-sealed-secret.yaml
git commit -m "Add encrypted secret"
git push

GitOps with ArgoCD

Repository Structure

Repository Structure
tree -L 3
homelab-gitops
apps
data
data-namespace.yaml
postgres-deployment.yaml
postgres-sealed-secret.yaml
redis-deployment.yaml
chatbot
chatbot-namespace.yaml
chatbot-api-deployment.yaml
chatbot-ui-deployment.yaml
argocd-apps
app-of-apps.yaml
data-app.yaml
chatbot-app.yaml
scripts
seal-secret.sh

App-of-Apps Pattern

The "App of Apps" pattern is utilized to manage the application landscape declaratively. A root "meta-application" tracks a directory of Application manifests, allowing the entire cluster state to be bootstrapped from a single entry point. This approach ensures scalability and consistent policy enforcement across all deployed workloads.

Benefits:

  • Single Source of Truth: Complete cluster reproducibility.
  • Automated Lifecycle: Creating a new app is as simple as committing a YAML file.
  • Consistency: Global sync settings and prune policies applied uniformly.
  • Hierarchy: Structured dependency management between infrastructure and applications.

Automated Sync Configuration

Each application defines strict synchronization policies to ensure the cluster state always converges with the Git repository.

Auto-sync:Enabled; controller polls Git every ~3 minutes.
Self-healing:Enabled; manual deviations in the cluster are immediately reverted.
Pruning:Enabled; resources removed from Git are garbage collected from the cluster.
Retry logic:Exponential backoff for transient failure resilience.

Cross-Namespace Communication

Reliable inter-service communication is established using Kubernetes native DNS service discovery. By addressing services via their Fully Qualified Domain Names (FQDNs), the architecture decouples networking from IP addressing, allowing for dynamic pod rescheduling without service interruption.

DNS Resolution Strategy:

<service-name>.<namespace>.svc.cluster.local:<port>

Implementation Example:

postgresql://user:pass@postgres.data.svc.cluster.local:5432/chatbot_db

Service Mesh Architecture

ns: chatbot
UI
Frontend
:80
API
Backend
:8000
ns: data
PG
PostgreSQL
:5432
RD
Redis
:6379
Cross-Namespace Communication via K8s DNS

Operational Constraints & Resolutions

Constraint 1: Sealed Secret Ownership

Error State:

Resource "postgres-secret" already exists and is not managed by SealedSecret

The Sealed Secrets controller employs strict ownership checks to prevent accidental overwrites of existing resources. Secrets created manually prior to the GitOps implementation will block the synchronization process.

Resolution:

# Purge unmanaged secrets
kubectl delete secret postgres-secret -n data
kubectl delete secret chatbot-secret -n chatbot

# Force controller cache refresh
kubectl delete pod -n kube-system \
  -l name=sealed-secrets-controller

Policy: All secrets in managed namespaces must be originated via SealedSecret manifests.

Constraint 2: Automated Repository Authentication

Automated GitOps agents (ArgoCD) require non-interactive authentication methods. SSH keys protected by passphrases will cause the synchronization loop to fail, as the agent cannot provide the decryption password at runtime.

# Generate passphrase-less ed25519 key
ssh-keygen -t ed25519 -C "argocd@homelab" \
  -f ~/.ssh/argocd_nopass -N "" 

Constraint 3: Distributed Development State

Insight: GitOps fundamentally decouples the development environment from the runtime environment. Modifications made directly to the cluster (via kubectl) are ephemeral and will be overwritten by the controller. All persistent changes must be committed to the remote Git repository, which serves as the sole authority for cluster state.

Performance & Efficiency

Resource Optimization

The shared services architectural pattern yields measurable efficiency gains compared to isolated deployments. By consolidating stateful services, we eliminate the overhead of redundant runtime environments and caching layers.

Isolated Model (3 apps)

  • • PostgreSQL Overhead: 3 × 256Mi = 768Mi RAM
  • • Redis Overhead: 3 × 128Mi = 384Mi RAM
  • • Total Reservation: 1,152Mi RAM

Shared Model (3 apps)

  • • PostgreSQL Reservation: 1 × 256Mi = 256Mi RAM
  • • Redis Reservation: 1 × 128Mi = 128Mi RAM
  • • Total Reservation: 384Mi RAM
  • • Efficiency Gain: ~67% reduction

Sync Latency

Bootstrap time (Cold):30-60 seconds
Incremental Sync:10-20 seconds
Drift Detection:~3 minutes (poll interval)

Security Posture

Credential Rotation Policy

The Sealed Secrets workflow simplifies credential rotation. New secrets are generated, sealed, and committed to Git. A subsequent pod restart is required to mount the new secrets, ensuring no stale credentials remain in memory.

RBAC & Least Privilege

Service accounts are scoped strictly to their required permissions. Default service accounts are deprecated in favor of custom accounts with minimal role bindings, reducing the blast radius of compromised workloads.

Disaster Recovery

  • Infrastructure: Reconstructible from Git (ArgoCD).
  • Secrets: Recoverable via backup of the Sealed Secrets master key.
  • Data: PostgreSQL/Redis volume snapshots.

Operational Metrics

< 2 min
Mean Time to Deploy
commit to healthy state
< 5 min
Mean Time to Recover
via Git revert
< 3 min
Secret Rotation Cycle
generation to activation
< 15 min
Service Onboarding
scaffold to production

Roadmap

Phase 1: Ingress & Automated TLS

Implementation of nginx-ingress-controller coupled with cert-manager to automate Let's Encrypt certificate issuance and renewal.

Phase 2: Service Mesh Integration

Deployment of Linkerd to establish mTLS encryption in transit, providing zero-trust networking and advanced traffic shaping capabilities (canary/blue-green).

Phase 3: Database High Availability

Migration to a Patroni-managed PostgreSQL cluster to support automatic failover and read-scaling.

Conclusion

This architecture validates that enterprise-grade reliability and security patterns are attainable in compact Kubernetes environments. By leveraging Talos Linux for immutable infrastructure, ArgoCD for declarative state management, and Sealed Secrets for encrypted configuration, the platform achieves a high degree of automation and security.

The transition to GitOps fundamentally reframes infrastructure management as a software engineering discipline. It enables the application of rigorous version control, peer review, and automated testing to the infrastructure itself, resulting in a system that is audit-friendly, resilient to drift, and rapid to recover.

Architectural Summary

  • Auditability: Complete infrastructure history preserved in Git.
  • Security: Asymmetric encryption enables safe public repository usage.
  • Efficiency: Shared service layers reduce resource overhead by ~67%.
  • Reliability: Automated self-healing corrects configuration drift.

Appendix: Deployment Reference

The following procedure illustrates the standard operating procedure for onboarding a new microservice:

# 1. Clone repository
git clone git@github.com:T4Bu/homelab-gitops.git
cd homelab-gitops

# 2. Define Application Manifests
mkdir -p apps/newapp
vim apps/newapp/deployment.yaml

# 3. Generate Encrypted Secret
./scripts/create-sealed-secret.sh app-secret newapp \
  API_KEY=secret123 \
  DATABASE_URL=postgresql://...

# 4. Register Application with ArgoCD
cat > argocd-apps/newapp.yaml <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: newapp
  namespace: argocd
spec:
  project: default
  source:
    repoURL: git@github.com:T4Bu/homelab-gitops.git
    targetRevision: HEAD
    path: apps/newapp
  destination:
    server: https://kubernetes.default.svc
    namespace: newapp
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
EOF

# 5. Commit to Trigger Deployment
git add apps/newapp/ argocd-apps/newapp.yaml
git commit -m "feat: onboard newapp service"
git push

# 6. Verify Convergence
argocd app get newapp --watch

# 7. Validation
kubectl get all -n newapp