About Karafs and Luna
Karafs is a digital health company. Its Karafs product focuses on nutrition, meal planning, and healthier lifestyles, while Luna is the company’s women’s health product. Both depend on a shared infrastructure platform to deliver reliable services to their users, while remaining logically isolated from one another.
Karafs and Luna run on the same Kubernetes cluster at Sotoon, but each product has its own namespace and independent data services. This separation allows deployments, resource allocation, and product-specific changes to be managed without unnecessarily affecting the other workload.
The relationship began with Dropp supporting Karafs in mobile software development. Following that successful engagement, Karafs expanded the partnership to include DevOps and infrastructure operations. The migration therefore started with established context and trust between the two teams.
The challenge: infrastructure without clear operational ownership
When the DevOps engagement began, Karafs was not facing an active infrastructure crisis or a widespread outage. The more important issue was the absence of clear ownership for day-to-day operations. Monitoring needed continuous attention, alerts needed accountable responders, and incidents required a team responsible for diagnosis and resolution.
This ownership gap appeared just as Sotoon made migration from the first to the second generation of its Kubernetes service mandatory and set a deadline for completion. Karafs therefore needed two outcomes at once: immediate ownership of the existing environment and a team capable of planning and executing a sensitive migration without compromising service continuity or data integrity.
The business risk extended beyond downtime. Missing the provider deadline, operating with limited visibility into the cluster, and relying on fragmented interventions could pull the product team away from developing Karafs and Luna and back into reactive infrastructure work.
The starting infrastructure
Both products were deployed on the first generation of Sotoon’s Kubernetes service. The application stack included Node.js backend services, a Next.js frontend, MongoDB and PostgreSQL databases, Redis, RabbitMQ, Nginx, and Object Storage. Karafs and Luna shared a cluster while running in separate namespaces with independent data services.
The CI/CD process used GitLab CI and Helm. After a build, GitLab CI executed `helm upgrade` directly against the cluster. The process worked, but it did not clearly separate CI from production delivery, and the desired deployment state was not managed end to end through Git.
Backups were already running, and access controls were being managed. However, monitoring did not provide sufficient visibility across the cluster, nodes, pods, and services, and operational documentation needed to be completed. The project did not begin with a broken platform; it began with the need to expose hidden risks and make operations observable, repeatable, and supportable.
Constraints and deadline
The primary constraint was the deadline for leaving the first generation of Sotoon’s Kubernetes service. Karafs wanted to remain on Sotoon, so the solution had to support a safe migration between two generations of the same managed platform rather than a broader replatforming or cloud-provider change.
The project also coincided with wartime conditions and widespread Internet access restrictions in Iran. Unreliable access to external registries and package repositories could interrupt builds and deployments. This was not a peripheral inconvenience; it directly influenced the strategy for managing dependencies and container images.
Both Karafs and Luna were live products. Moving them simultaneously would have increased the blast radius of any issue, so the migration plan needed to be phased, testable, and backed by a clear rollback path.
Initial audit: what needed to change?
Before migration work began, Dropp Tempo assessed the cluster, deployment process, external dependencies, monitoring, backups, access management, and resource consumption. The goal was not to redesign everything. It was to identify what already worked, which risks had to be addressed before cutover, and which improvements could be delivered alongside the migration.
The audit confirmed that backups were in place and could be retained and validated. Access controls were also being managed. The main gaps were limited operational visibility, incomplete documentation, a CD process that applied changes directly from GitLab CI, and exposure to interruptions in external dependency and image sources.
Resource usage also indicated an opportunity to tune deployment requests and limits and optimize worker capacity after migration. The audit became an execution roadmap: prepare and validate the target environment first, then improve delivery, observability, security, and resource efficiency.
Engineering decisions: why a phased migration?
The first major decision was to avoid cutting over Karafs and Luna at the same time. Luna moved first, allowing the destination cluster, deployment model, and operating process to be exercised with a narrower scope. Once Luna was stable and validated, the team proceeded with Karafs. This sequence reduced the blast radius of each change and simplified troubleshooting.
For Karafs’s primary database, relying entirely on a one-time transfer during the final window was not a suitable option. The dataset size and limited throughput between source and destination could have extended downtime. Continuous synchronization with Debezium and Kafka Connect therefore began early, moving existing data progressively while capturing changes created during the transfer.
Two additional decisions shaped the target platform: moving CD to an ArgoCD-based GitOps model and introducing a dedicated Nexus repository to reduce build and deployment dependence on external registries and package sources. The migration was designed to remove operational friction after cutover, not merely relocate workloads.
Migration execution: from staging to continuous data sync
The team first prepared the required components on Sotoon’s second-generation Kubernetes platform and rebuilt the namespace, ingress, storage, and deployment structure for each product in the destination environment. A staging version of each product was deployed in a separate namespace so the Karafs team could validate application behavior and infrastructure integrations before production traffic moved.
Luna was migrated first. Beyond moving a live product, this phase tested the migration sequence, target-cluster configuration, and coordination between the two teams. After it was approved, work continued on Karafs, with particular attention to its primary database.
Debezium and Kafka Connect synchronized the existing dataset and captured changes created on the source while that transfer was still running. Once source and destination were sufficiently aligned, the final cutover window was scheduled. The Karafs team performed functional testing. Load testing with k6 was not performed in this project, and no such result is claimed.
- First-generation Setoon Kubernetes cluster
- GitLab CI running helm upgrade directly
- Dependencies and images reliant on external sources
- Limited monitoring
- No unified operational ownership
- Second-generation Setoon Kubernetes cluster
- Independent namespaces for Karafs and Luna
- GitLab CI for builds
- Nexus for images and dependencies
- ArgoCD for GitOps CD
- Vault for secrets
- Prometheus and Grafana for monitoring
- Uptime Kuma for external endpoint checks
- Daily backups to object storage
- Managed DevOps by Dropp Tempo
A four-hour cutover with a defined rollback path
Karafs’s final cutover took place in a pre-planned maintenance window. Users were notified in advance, and Karafs entered read-only mode during the transition. Luna had already been migrated and was not part of this cutover.
During the window, the final data changes were synchronized, services were validated at the destination, and traffic was directed to the new cluster. The Karafs team also verified application behavior and data integrity. The full cutover took approximately four hours and completed with zero data loss.
The old cluster was not removed immediately. It remained untouched for one week so a rollback path would still be available if a post-migration issue appeared. This allowed the new production environment to be observed under real conditions without closing the route back prematurely.
Migrate Luna
Start of the phased migration with the first product.
Set up staging
Deploy the staging version in an independent namespace.
Functional test
Functional testing of the staging version before any cutover.
Start sync with Debezium and Kafka Connect
Syncing initial data and in-flight changes between the two clusters.
Read-only window
Putting the service into read-only mode before the final cutover.
Final cutover
The final switch to the new cluster within a four-hour window.
Validation
Verifying data integrity and service health after the cutover.
Keep the old cluster for one week
Leaving the old cluster untouched to allow for a rollback.
End of rollback window
Wrapping up the migration after one week with no rollback needed.
From direct Helm deployments to GitOps with ArgoCD
In the previous architecture, GitLab CI handled both builds and the direct execution of `helm upgrade` against the cluster. Dropp Tempo separated these responsibilities. GitLab CI remains responsible for builds and prepares the required artifacts and images, while ArgoCD applies the desired state to Kubernetes.
With GitOps in place, the expected state of each service is maintained in Git, and ArgoCD reconciles the cluster against it. This made deployments more observable and traceable while reducing the need for production changes to be applied directly from inside the CI pipeline.
The outcome was not simply the addition of another tool. The operations team gained clearer visibility into synchronization status, the difference between desired and actual cluster state, and the history of changes—capabilities that matter when several products share a production platform.
Nexus and reduced dependence on external sources
Access problems affecting external registries and package repositories can stop a build or deployment even when the Kubernetes cluster itself is healthy. That risk became more tangible during the project as Internet restrictions intensified.
Dropp Tempo deployed a dedicated Nexus repository for Karafs to host and cache the dependencies and Docker images required by its delivery process. In the new architecture, builds and deployments retrieve the resources they need from Karafs’s own Nexus wherever practical.
This reduced real-time dependence on external sources and gave the team more control over the availability of required artifacts. The objective was not to claim complete independence from the Internet, but to ensure that an external disruption had less power to break the product’s delivery rhythm.
Multi-layer observability and alerting
One of the audit’s most important findings was the need for fuller operational visibility. Prometheus and Grafana were introduced to collect metrics and expose infrastructure health, extending monitoring from nodes and pods to services, databases, and endpoints.
Public endpoints are also checked through Dropp Tempo’s independent monitoring system and Uptime Kuma. This external layer measures availability from outside the managed cluster, ensuring that detection does not depend exclusively on tools running inside the same environment.
Alerts are delivered simultaneously by email and team communication channels to both Dropp Tempo and Karafs. Monitoring therefore functions as an operating process rather than a set of dashboards: observe, alert, assign ownership, and act.
Secrets management and security hardening
HashiCorp Vault was added to the new environment to centralize secrets management and reduce reliance on scattered service configurations or manual handling. Policy and access details are intentionally not disclosed, but the objective was clear: establish a controlled location for managing the lifecycle of sensitive values.
All new servers were also hardened before entering the production path. Security was therefore incorporated into preparation of the target environment rather than treated as a separate activity after migration, while sensitive information about Karafs’s topology and internal controls remained private.
Daily backups validated through a real restore test
Karafs already had backup jobs in place when the project began, and the initial audit confirmed their presence and health. In the final architecture, backups are created daily and transferred to Object Storage.
Dropp Tempo did not stop at successful job reports or the existence of backup files. The team performed a real restore test to verify that the available copies could be recovered when needed. This validated the difference between retaining backup data and maintaining a dependable recovery path.
Backup execution and monitoring remain part of the ongoing infrastructure service alongside observability and incident response.
20% fewer worker nodes through resource optimization
Once better resource visibility was available, deployment requests and limits were reviewed against actual consumption. The objective was not simply to remove servers; the team first needed to understand the capacity each service required and where resources could be reduced without introducing unnecessary operational risk.
As a result, the Kubernetes cluster’s worker-node count was reduced from 15 to 12—a 20% reduction. The smaller footprint also lowered ongoing infrastructure costs.
The significance of this result lies in how it was achieved: through observation and tuning rather than guesswork or an arbitrary capacity cut. The new monitoring foundation also supports continued optimization during the retained service.
Technical results and business impact
The platform migration was completed in approximately three months. Karafs’s final cutover took place during a four-hour read-only window with zero data loss, while the previous cluster remained available for one week as a rollback option. Moving Luna and Karafs in separate phases kept the scope and risk of each step controlled.
Technically, direct CD from GitLab CI was replaced with an ArgoCD-based GitOps model; Nexus reduced build and deployment dependence on external sources; Vault centralized secrets management; monitoring expanded from nodes and pods to databases and endpoints; and daily backups were validated through a real restore test.
Resource tuning reduced the worker-node count from 15 to 12. From a business perspective, Karafs moved from an operational ownership gap to a model in which one accountable team manages monitoring, incident response, deployment, backup, and continuous improvement. The most important result was not only completing the migration, but creating conditions in which the product team could stay focused on Karafs and Luna instead of returning to reactive infrastructure work.
From migration project to ongoing Managed DevOps
Dropp Tempo’s work with Karafs did not end at cutover. After migration, Kubernetes management, monitoring and alert response, incident response, deployments, backups, infrastructure troubleshooting, and resource optimization continued under a Managed DevOps engagement.
This is the Retain stage of the Dropp Tempo model in practice: the platform is not handed over only to become ownerless again. The team that understands the migration context and the reasoning behind the architecture continues to own daily operations and incremental improvement.
For Karafs, the outcome was not a one-off infrastructure project. It was a sustainable operating model in which platform health is continuously visible, alerts have accountable owners, and future changes can be delivered with the same disciplined risk control used during the migration.