[{"data":1,"prerenderedAt":464},["ShallowReactive",2],{"service-articles-en-scalable-cloud-software":3},[4,171,315],{"id":5,"title":6,"body":7,"category":157,"date":158,"description":13,"extension":159,"meta":160,"navigation":161,"order":162,"path":163,"published":164,"seo":165,"service":166,"stem":167,"summary":168,"updated":169,"__hash__":170},"blog\u002Fen\u002Fblog\u002Fgitops-argocd-helm-regulated-environments.md","GitOps with ArgoCD and Helm: Auditable Releases for Regulated Industries",{"type":8,"value":9,"toc":140},"minimark",[10,14,19,38,42,50,57,60,64,67,72,75,79,82,86,89,93,100,104,107,111,114,117,124,128,131],[11,12,13],"p",{},"An auditor wants to know which software version was running in production on a given day, and who approved it. In many teams that starts a tedious search through logs, tickets, and people's memories. With GitOps the answer is always in Git, and a faulty release can be undone with a single revert.",[15,16,18],"h2",{"id":17},"key-takeaways","Key takeaways",[20,21,22,26,29,32,35],"ul",{},[23,24,25],"li",{},"With GitOps, the desired state of every Kubernetes cluster lives in Git, and ArgoCD corrects any drift automatically.",[23,27,28],{},"Without direct cluster access, every change to running infrastructure is a reviewed, merged commit.",[23,30,31],{},"Promotion and rollback become Git operations: a merge or a revert, with no bespoke tooling.",[23,33,34],{},"Security scans belong in the CI pipeline, before a change is even proposed for deployment.",[23,36,37],{},"The audit trail comes out of the deployment model itself and does not need to be maintained as a separate system.",[15,39,41],{"id":40},"why-push-based-deployments-fail-audits","Why push-based deployments fail audits",[11,43,44,45,49],{},"I still see teams deploying to Kubernetes by running ",[46,47,48],"code",{},"kubectl apply"," from a laptop, or by letting a CI pipeline push straight into a cluster on every merge. Both work, until someone asks the question every regulated environment eventually asks: what was running in production on a given date, who approved it, and can you prove it?",[11,51,52,53,56],{},"With push-based deployments, the honest answer is usually \"we're not entirely sure.\" The cluster's actual state and the record of intended state drift apart the moment a manual ",[46,54,55],{},"kubectl edit"," or an emergency hotfix bypasses the pipeline.",[11,58,59],{},"Auditors don't accept \"check the deployment logs\" as a satisfying answer, and neither should I.",[15,61,63],{"id":62},"how-gitops-works-with-argocd-and-helm","How GitOps works with ArgoCD and Helm",[11,65,66],{},"The fix I reach for is GitOps. The desired state of every cluster lives in a Git repository. A reconciliation controller, in my case ArgoCD, continuously compares that declared state against what is running in the cluster and corrects any drift automatically.",[68,69,71],"h3",{"id":70},"helm-charts-and-values-files-per-environment","Helm charts and values files per environment",[11,73,74],{},"Helm charts template the Kubernetes manifests. A single chart describes an application, and environment-specific values files supply the differences between dev, staging, and production.",[68,76,78],{"id":77},"the-one-rule-no-direct-cluster-access","The one rule: no direct cluster access",[11,80,81],{},"Nothing reaches a cluster except through a change to Git, and every change to Git is a reviewed merge request. That single constraint is what turns \"trust me\" into \"here's the commit.\"",[15,83,85],{"id":84},"promotion-from-staging-to-production","Promotion from staging to production",[11,87,88],{},"With this structure, promoting a release between environments stops being a deploy script and becomes a Git operation. The same chart version moves from staging to production by merging a values-file change that bumps the image tag or config for that environment.",[68,90,92],{"id":91},"rollback-with-git-revert","Rollback with git revert",[11,94,95,96,99],{},"Rollback is a ",[46,97,98],{},"git revert",", not a scramble to remember the previous Helm release number. Because ArgoCD reconciles continuously, the cluster follows the moment the revert lands. There is no separate rollback tooling and no manual intervention.",[68,101,103],{"id":102},"commit-history-as-release-history","Commit history as release history",[11,105,106],{},"The promotion history is the commit history. I can point at a pull request and show exactly when a version reached production and who approved it.",[15,108,110],{"id":109},"security-stages-in-the-ci-pipeline","Security stages in the CI pipeline",[11,112,113],{},"GitOps handles what happens after a change is approved. I still want confidence in what is being proposed.",[11,115,116],{},"So build, test, and security scanning run as distinct stages in GitLab CI before an image or chart is even eligible for a values-file bump. Dependency scanning, container image scanning, and policy checks all gate the pipeline.",[11,118,119,120,123],{},"Built artifacts are pushed to a central registry and referenced by an immutable tag, never by ",[46,121,122],{},"latest",". What's described in Git is exactly what gets deployed, and there is no doubt about which build is running.",[15,125,127],{"id":126},"what-this-means-for-your-company","What this means for your company",[11,129,130],{},"In regulated industries, the question \"who approved what, and when?\" will come, at the latest in your next audit. An uncertain answer then costs time and trust, and reconstructing the history ties up exactly the people who should be working on your product. On top of that there is a concentration risk: if only a few individuals know what runs where, that knowledge is missing precisely when those people are on holiday or leave the company.",[11,132,133,134,139],{},"With GitOps, that evidence is a by-product of everyday work. Your team documents nothing extra, because every change is created as a reviewed commit anyway. Releases also become more predictable, since a faulty update is undone with a revert and no manual emergency work in the cluster. I describe how I set up release processes and deployments on AWS on the page about ",[135,136,138],"a",{"href":137},"\u002Fen\u002Fservices\u002Fscalable-cloud-software","AWS costs and scaling",".",{"title":141,"searchDepth":142,"depth":142,"links":143},"",2,[144,145,146,151,155,156],{"id":17,"depth":142,"text":18},{"id":40,"depth":142,"text":41},{"id":62,"depth":142,"text":63,"children":147},[148,150],{"id":70,"depth":149,"text":71},3,{"id":77,"depth":149,"text":78},{"id":84,"depth":142,"text":85,"children":152},[153,154],{"id":91,"depth":149,"text":92},{"id":102,"depth":149,"text":103},{"id":109,"depth":142,"text":110},{"id":126,"depth":142,"text":127},"Tutorials","August 11, 2026","md",{},true,1,"\u002Fen\u002Fblog\u002Fgitops-argocd-helm-regulated-environments","2026-08-11",{"title":6,"description":13},"scalable-cloud-software","en\u002Fblog\u002Fgitops-argocd-helm-regulated-environments","GitOps with ArgoCD and Helm makes every release auditable: who approved what and when is in the commit. Rollback through Git, security scans in the CI pipeline.","2026-11-06","fsMDbK4Mk7WB5M_8RU1S4NOwEm_in8Dk103JXLhB_Hk",{"id":172,"title":173,"body":174,"category":157,"date":307,"description":178,"extension":159,"meta":308,"navigation":161,"order":149,"path":309,"published":310,"seo":311,"service":166,"stem":312,"summary":313,"updated":169,"__hash__":314},"blog\u002Fen\u002Fblog\u002Fkafka-topic-design-idempotency.md","Setting Up Kafka Right: Topic Design, Partitioning, and Idempotency",{"type":8,"value":175,"toc":290},[176,179,181,198,202,205,209,212,216,219,223,226,229,233,236,240,243,246,250,253,257,260,263,267,270,274,277,280,282,285],[11,177,178],{},"Failures in streaming systems rarely show up right away. Events processed twice, a single overloaded consumer, or processing that falls further and further behind often surface only when downstream data stops adding up. Most of these problems can be prevented when the Kafka topics are designed.",[15,180,18],{"id":17},[20,182,183,186,189,192,195],{},[23,184,185],{},"Every Kafka topic is a contract between producers and consumers and deserves deliberate decisions about naming, schema, and retention.",[23,187,188],{},"The partition key controls ordering and load distribution at the same time, and a badly chosen key creates hot partitions.",[23,190,191],{},"With at-least-once delivery, duplicates are unavoidable over time, so consumers have to be idempotent.",[23,193,194],{},"Idempotent consumers turn replaying a topic into a non-event instead of a data-corruption risk.",[23,196,197],{},"Consumer lag is the earliest warning signal of a bottleneck anywhere in the pipeline.",[15,199,201],{"id":200},"treating-kafka-topics-as-contracts","Treating Kafka topics as contracts",[11,203,204],{},"I treat every Kafka topic as a contract between whoever produces to it and whoever consumes from it. Being a name in a config file comes second. For every topic I make three decisions deliberately.",[68,206,208],{"id":207},"naming-conventions","Naming conventions",[11,210,211],{},"A topic's name should tell you what domain event it carries and who owns it. Which service happens to write to it today is irrelevant for that.",[68,213,215],{"id":214},"schema-evolution-with-a-schema-registry","Schema evolution with a schema registry",[11,217,218],{},"Schema evolution needs to be an explicit, versioned decision. It must not happen implicitly because a producer added a field. A schema registry with compatibility rules enforced at write time catches such changes before they become a consumer's runtime exception.",[68,220,222],{"id":221},"retention","Retention",[11,224,225],{},"The third decision is retention: how long events need to live, and whether a topic is a transient message bus or a durable log that downstream systems might replay from the beginning.",[11,227,228],{},"I don't answer any of these three questions with a default. I decide them once, up front, because changing them later means coordinating every producer and consumer at once.",[15,230,232],{"id":231},"partitioning-ordering-and-load-distribution","Partitioning: ordering and load distribution",[11,234,235],{},"Partition count and partition key are where most of the design work lives. They determine ordering guarantees and how evenly load spreads across consumers.",[68,237,239],{"id":238},"choosing-the-right-partition-key","Choosing the right partition key",[11,241,242],{},"Kafka only guarantees ordering within a partition. Events that must be processed in order relative to each other therefore need the same partition key, typically an entity ID.",[11,244,245],{},"Get the key wrong and you either lose ordering you needed or, more commonly, create a hot partition. One key's volume then dwarfs the rest, and a single consumer becomes the bottleneck for the whole topic.",[68,247,249],{"id":248},"sizing-consumer-groups","Sizing consumer groups",[11,251,252],{},"I size consumer groups to partition count deliberately. A group can never have more active consumers than partitions, and extra consumers just sit idle.",[15,254,256],{"id":255},"idempotent-consumers-instead-of-duplicates","Idempotent consumers instead of duplicates",[11,258,259],{},"At-least-once delivery is the practical default for Kafka. Over a long enough time window, that makes duplicates a certainty, whether from producer retries or consumer rebalances.",[11,261,262],{},"Rather than trying to guarantee exactly-once delivery at the broker level, I design consumers to be idempotent. Every handler produces the same end state whether an event is processed once or twice. Usually that works through an idempotency key checked against a store before a side effect runs.",[68,264,266],{"id":265},"replay-without-risk","Replay without risk",[11,268,269],{},"That same property is what makes replay safe. If I need to reprocess a topic from an earlier offset to recover from a bug, idempotent consumers make that a non-event instead of a data-corruption risk.",[15,271,273],{"id":272},"running-kafka-retention-and-consumer-lag","Running Kafka: retention and consumer lag",[11,275,276],{},"Day to day, I watch two levers. The first is retention strategy: time-based, size-based, or compacted for topics that represent current state rather than a log of events. It directly affects storage cost and how far back a replay can reach.",[11,278,279],{},"The second is consumer lag, by far the most useful health signal a streaming system gives you. A consumer group falling behind its produced offsets is the earliest warning of a downstream bottleneck, well before anything looks broken from the outside.",[15,281,127],{"id":126},[11,283,284],{},"If your systems exchange data through Kafka, these design decisions have tangible consequences. An event processed twice can mean a duplicate booking or a wrong report. A bottleneck in the pipeline eventually shows up as late data in systems your business departments rely on. That is why consumer lag is a metric that belongs on the IT lead's dashboard, because it reports these problems before anyone in a business department notices them.",[11,286,287,288,139],{},"These failures can largely be avoided when topics, keys, and consumers are designed deliberately from the start. Fixing them later gets expensive, because every team involved then has to switch over at the same time. I describe how I plan event-driven systems and design them for growing load on the page about ",[135,289,138],{"href":137},{"title":141,"searchDepth":142,"depth":142,"links":291},[292,293,298,302,305,306],{"id":17,"depth":142,"text":18},{"id":200,"depth":142,"text":201,"children":294},[295,296,297],{"id":207,"depth":149,"text":208},{"id":214,"depth":149,"text":215},{"id":221,"depth":149,"text":222},{"id":231,"depth":142,"text":232,"children":299},[300,301],{"id":238,"depth":149,"text":239},{"id":248,"depth":149,"text":249},{"id":255,"depth":142,"text":256,"children":303},[304],{"id":265,"depth":149,"text":266},{"id":272,"depth":142,"text":273},{"id":126,"depth":142,"text":127},"July 14, 2026",{},"\u002Fen\u002Fblog\u002Fkafka-topic-design-idempotency","2026-07-14",{"title":173,"description":178},"en\u002Fblog\u002Fkafka-topic-design-idempotency","Kafka topic design decides your data quality: how partition keys, schema rules, and idempotent consumers prevent duplicates and hot partitions in production.","fdDoFkawOKytTUypezrnfOrLOqVpSMi_0UV38e1vuts",{"id":316,"title":317,"body":318,"category":454,"date":455,"description":322,"extension":159,"meta":456,"navigation":161,"order":457,"path":458,"published":459,"seo":460,"service":166,"stem":461,"summary":462,"updated":169,"__hash__":463},"blog\u002Fen\u002Fblog\u002Faws-cost-right-sizing-spot.md","Reduce AWS Costs: Right-Sizing and Spot Instances Done Right",{"type":8,"value":319,"toc":440},[320,323,325,342,346,349,352,363,366,370,373,377,380,384,387,390,394,397,401,404,408,411,414,418,421,424,427,429,432],[11,321,322],{},"The AWS bill goes up every month, and nobody in the company can say exactly why. Behind it there is usually an architecture decision made months or years ago and never revisited. Here is where I start in those cases, and which levers bring the bill down for good.",[15,324,18],{"id":17},[20,326,327,330,333,336,339],{},[23,328,329],{},"An oversized AWS bill is usually an architecture question first and a pricing question second.",[23,331,332],{},"Right-sizing needs real utilization data over a window that captures actual peaks, and it has to be repeated regularly.",[23,334,335],{},"Spot instances are the largest lever for compute savings, but they only suit workloads that can tolerate interruption.",[23,337,338],{},"Databases and other stateful or latency-critical systems do not belong on spot.",[23,340,341],{},"Budgets with several alert thresholds, cost dashboards per service, and enforced tagging make a cost spike traceable within minutes.",[15,343,345],{"id":344},"why-high-cloud-costs-are-an-architecture-signal","Why high cloud costs are an architecture signal",[11,347,348],{},"When I get called in to look at a runaway AWS bill, I don't start in Cost Explorer. I start with the architecture, because an oversized fleet is almost never a pricing problem.",[11,350,351],{},"Behind it there is almost always a design assumption from six months or two years ago that nobody revisited. Typical examples:",[20,353,354,357,360],{},[23,355,356],{},"An instance type chosen for a peak load that never materialized.",[23,358,359],{},"A database sized for a migration that got postponed.",[23,361,362],{},"A service that scaled out instead of up because that was easier at the time, and nobody went back later to check whether it still made sense.",[11,364,365],{},"Treating cost as an architecture signal rather than a finance problem changes where I look first. A consistently underutilized instance tells me how far a workload's original specification is from the way it actually behaves.",[15,367,369],{"id":368},"right-sizing-based-on-real-utilization-data","Right-sizing based on real utilization data",[11,371,372],{},"I never resize on intuition. Before touching an instance type, I pull real utilization data: CloudWatch metrics at minimum and, where available, Prometheus for finer-grained application metrics. The window has to be long enough to capture actual peak behavior. A quiet afternoon is not enough.",[68,374,376],{"id":375},"which-metrics-matter","Which metrics matter",[11,378,379],{},"CPU and memory utilization tell the obvious story. I also look at network throughput and, for anything stateful, disk I\u002FO. That can be where the actual constraint sits, even when CPU looks comfortably low.",[68,381,383],{"id":382},"right-sizing-as-a-recurring-loop","Right-sizing as a recurring loop",[11,385,386],{},"Right-sizing isn't a one-time exercise. I treat it as a loop: resize, observe the new utilization pattern under real load, adjust again.",[11,388,389],{},"The reason is simple. Workloads drift, and a fleet that was correctly sized at launch quietly stops being correctly sized as traffic patterns change.",[15,391,393],{"id":392},"spot-instances-where-they-are-safe-and-where-they-are-not","Spot instances: where they are safe and where they are not",[11,395,396],{},"Spot instances are the single largest lever I have for compute savings. They only suit workloads that can tolerate interruption without breaking anything, though.",[68,398,400],{"id":399},"good-candidates-for-spot","Good candidates for spot",[11,402,403],{},"The clearest fits are batch processing jobs, CI runners, and stateless inference behind a load balancer. If AWS reclaims an instance, the job retries or the load balancer routes around it. Nothing user-facing notices.",[68,405,407],{"id":406},"what-stays-on-on-demand","What stays on on-demand",[11,409,410],{},"Anything stateful or latency-critical, where an interruption has a real cost, stays on on-demand. That means a primary database, a session-holding service, and anything where \"just retry\" isn't actually free.",[11,412,413],{},"The savings on spot are large enough that it is worth deliberately identifying every workload that qualifies. Staying on on-demand everywhere out of caution leaves that money on the table.",[15,415,417],{"id":416},"guardrails-budgets-dashboards-and-tagging","Guardrails: budgets, dashboards, and tagging",[11,419,420],{},"None of this stays correct without guardrails. I set budgets with alerts at several thresholds rather than one. That way runaway spend shows up before it becomes a surprise at month-end.",[11,422,423],{},"On top of that come cost dashboards broken out by service. A spike can then be traced to a specific team or workload within minutes, not after a multi-day investigation.",[11,425,426],{},"Tagging discipline is what makes that attribution possible. Every resource is tagged by owner and environment, and this is enforced at provisioning time instead of hoped for after the fact.",[15,428,127],{"id":126},[11,430,431],{},"For management, a rising AWS bill is a budget topic first. The cause almost always sits in the technology, though, and that is the only place it can be fixed for good. Across-the-board cuts easily hit the wrong systems, such as a database that cannot tolerate interruption, while oversized instances keep running.",[11,433,434,435,439],{},"The sensible first step is visibility: which workloads cause which costs, and which of them run far below their capacity all the time. For a first estimate of your own environment, the ",[135,436,438],{"href":437},"\u002Fen\u002Ftools\u002Faws-cost-check","free AWS cost check"," gives you a starting point for where your largest levers might be.",{"title":141,"searchDepth":142,"depth":142,"links":441},[442,443,444,448,452,453],{"id":17,"depth":142,"text":18},{"id":344,"depth":142,"text":345},{"id":368,"depth":142,"text":369,"children":445},[446,447],{"id":375,"depth":149,"text":376},{"id":382,"depth":149,"text":383},{"id":392,"depth":142,"text":393,"children":449},[450,451],{"id":399,"depth":149,"text":400},{"id":406,"depth":149,"text":407},{"id":416,"depth":142,"text":417},{"id":126,"depth":142,"text":127},"Articles","June 16, 2026",{},5,"\u002Fen\u002Fblog\u002Faws-cost-right-sizing-spot","2026-06-16",{"title":317,"description":322},"en\u002Fblog\u002Faws-cost-right-sizing-spot","Reduce AWS costs without risk: right-sizing based on real utilization data, spot instances where they are safe, and budgets that flag runaway spend early.","qlSeIhOAsw0y8RHEHNg1a807-YLL4Rg6X-iRo2FlhFE",1794305788749]