Recent Posts
Archives

Posts Tagged ‘Kubernetes’

PostHeaderIcon [DevoxxBE2023] Securing the Supply Chain for Your Java Applications by Thomas Vitale

At Devoxx Belgium 2023, Thomas Vitale, a software engineer and architect at Systematic, delivered an authoritative session on securing the software supply chain for Java applications. As the author of Cloud Native Spring in Action and a passionate advocate for cloud-native technologies, Thomas provided a comprehensive exploration of securing every stage of the software lifecycle, from source code to deployment. Drawing on the SLSA framework and CNCF research, he demonstrated practical techniques for ensuring integrity, authenticity, and resilience using open-source tools like Gradle, Sigstore, and Kyverno. Through a blend of theoretical insights and live demonstrations, Thomas illuminated the critical importance of supply chain security in today’s threat landscape.

Safeguarding Source Code with Git Signatures

Thomas began by defining the software supply chain as the end-to-end process of delivering software, encompassing code, dependencies, tools, practices, and people. He emphasized the risks at each stage, starting with source code. Using Git as an example, Thomas highlighted its audit trail capabilities but cautioned that commit authorship can be manipulated. In a live demo, he showed how he could impersonate a colleague by altering Git’s username and email, underscoring the need for signed commits. By enforcing signed commits with GPG or SSH keys—or preferably a keyless approach via GitHub’s single sign-on—developers can ensure commit authenticity, establishing a verifiable provenance trail critical for supply chain security.

Managing Dependencies with Software Bills of Materials (SBOMs)

Moving to dependencies, Thomas stressed the importance of knowing exactly what libraries are included in a project, especially given vulnerabilities like Log4j. He introduced Software Bills of Materials (SBOMs) as a standardized inventory of software components, akin to a list of ingredients. Using the CycloneDX plugin for Gradle, Thomas demonstrated generating an SBOM during the build process, which provides precise dependency details, including versions, licenses, and hashes for integrity verification. This approach, integrated into Maven or Gradle, ensures accuracy over post-build scanning tools like Snyk, enabling developers to identify vulnerabilities, check license compliance, and verify component integrity before production.

Thomas further showcased Dependency-Track, an OWASP project, to analyze SBOMs and flag vulnerabilities, such as a critical issue in SnakeYAML. He introduced the Vulnerability Exploitability Exchange (VEX) standard, which complements SBOMs by documenting whether vulnerabilities affect an application. In his demo, Thomas marked a SnakeYAML vulnerability as a false positive due to Spring Boot’s safe deserialization, demonstrating how VEX communicates security decisions to stakeholders, reducing unnecessary alerts and ensuring compliance with emerging regulations.

Building Secure Artifacts with Reproducible Builds

The build phase, Thomas explained, is another critical juncture for security. Using Spring Boot as an example, he outlined three packaging methods: JAR files, native executables, and container images. He critiqued Dockerfiles for introducing non-determinism and maintenance overhead, advocating for Cloud Native Buildpacks as a reproducible, secure alternative. In a demo, Thomas built a container image with Buildpacks, highlighting its fixed creation timestamp (January 1, 1980) to ensure identical outputs for unchanged inputs, enhancing security by eliminating variability. This reproducibility, coupled with SBOM generation during the build, ensures artifacts are both secure and traceable.

Signing and Verifying Artifacts with SLSA

To ensure artifact integrity, Thomas introduced the SLSA framework, which provides guidelines for securing software artifacts across the supply chain. He demonstrated signing container images with Sigstore’s Cosign tool, using a keyless approach to avoid managing private keys. This process, integrated into a GitHub Actions pipeline, ensures that artifacts are authentically linked to their creator. Thomas further showcased SLSA’s provenance generation, which documents the artifact’s origin, including the Git commit hash and build steps. By achieving SLSA Level 3, his pipeline provided non-falsifiable provenance, ensuring traceability from source code to deployment.

Securing Deployments with Policy Enforcement

The final stage, deployment, requires validating artifacts to ensure they meet security standards. Thomas demonstrated using Cosign and the SLSA Verifier to validate signatures and provenance, ensuring only trusted artifacts are deployed. On Kubernetes, he introduced Kyverno, a policy engine that enforces signature and provenance checks, automatically rejecting non-compliant deployments. This approach ensures that production environments remain secure, aligning with the principle of validating metadata to prevent unauthorized or tampered artifacts from running.

Conclusion: A Holistic Approach to Supply Chain Security

Thomas’s session at Devoxx Belgium 2023 provided a robust framework for securing Java application supply chains. By addressing source code integrity, dependency management, build reproducibility, artifact signing, and deployment validation, he offered a comprehensive strategy to mitigate risks. His practical demonstrations, grounded in open-source tools and standards like SLSA and VEX, empowered developers to adopt these practices without overwhelming complexity. Thomas’s emphasis on asking “why” at each step encouraged attendees to tailor security measures to their context, ensuring both compliance and resilience in an increasingly regulated landscape.

Links:

PostHeaderIcon [SpringIO2022] How to foster a Culture of Resilience

Benjamin Wilms, founder of Steadybit, delivered a compelling session at Spring I/O 2022, exploring how to build a culture of resilience through chaos engineering. Drawing from his experience and the evolution of chaos engineering since his 2019 Spring I/O talk, Benjamin emphasized proactive strategies to enhance system reliability. His presentation combined practical demonstrations with a framework for integrating resilience into development workflows, advocating for collaboration and automation.

Understanding Resilience and Chaos Engineering

Benjamin began by defining resilience as the outcome of well-architected, automated, and thoroughly tested systems capable of recovering from faults while delivering customer value. Unlike traditional stability, resilience involves handling partial outages with fallbacks or alternatives, ensuring service continuity. He introduced chaos engineering as a method to test this resilience by intentionally injecting faults—latency, exceptions, or service outages—to build confidence in system capabilities.

Chaos engineering involves defining a steady state (e.g., successful Netflix play button clicks), forming hypotheses (e.g., surviving a payment service outage), and running experiments to verify outcomes. Benjamin highlighted its evolution from a niche practice at Netflix to a growing community discipline, but noted its time-intensive nature often deters teams. He stressed that resilience extends beyond systems to organizational responsiveness, such as detecting incidents in seconds rather than minutes.

Pitfalls of Ad-Hoc Chaos Engineering

To illustrate common mistakes, Benjamin demonstrated a flawed approach using a Kubernetes-based microservice system with a gateway and three backend services. Running a random “delete pod” attack on the hotel service caused errors in the gateway’s product list aggregation, visible in a demo UI. However, the experiment yielded little insight, as it only confirmed the attack’s impact without actionable learnings. He critiqued such ad-hoc attacks—using tools like Pumbaa—for disrupting workflows and requiring expertise in CI/CD integration, diverting focus from core development.

This approach fails to generate knowledge or improve systems, often becoming a “rabbit hole” of additional work. Benjamin argued that starting with tools or attacks, rather than clear objectives, undermines the value of chaos engineering, leaving teams with vague results and no clear path to enhancement.

Building a Culture of Resilience

Benjamin proposed a structured approach to foster resilience, starting with the “why”: understanding motivations like surviving AWS zone outages or ensuring checkout services handle payment downtimes. The “what” involves defining specific capabilities, such as maintaining 95% request success during pod failures or implementing retry patterns. He advocated encoding these capabilities as policies—code-based checks integrated into the development pipeline.

In a demo, Benjamin showed how to define a policy for the gateway service, specifying pod redundancy and steady-state checks via a product list endpoint. The policy, stored in the codebase, runs in a CI/CD pipeline (e.g., GitHub Actions) on a staging environment, verifying resilience after each commit. This automation ensures continuous validation without manual intervention, embedding resilience into daily workflows. Policies include pre-built experiments from communities (e.g., Zalando) or static weak spot checks, like missing Kubernetes readiness probes, making resilience accessible to all developers.

Organizational Strategies and Community Impact

Benjamin addressed organizational adoption, suggesting a central component to schedule experiments and avoid overlapping tests in shared environments. For consulting scenarios, he recommended analyzing past incidents to demonstrate resilience gaps, such as running experiments to recreate outages. He shared a case where a client’s system collapsed during a rolling update under load, underscoring the need for combined testing scenarios.

He encouraged starting with static linters to identify configuration risks and replaying past incidents to prevent recurrence. By integrating resilience checks into pipelines, teams can focus on feature delivery while maintaining reliability. Benjamin’s vision of a resilience culture—where proactive testing is instinctive—resonates with developers seeking to balance velocity and stability.

Links:

PostHeaderIcon [DevoxxPL2022] From Private Through Hybrid to Public Cloud – Product Migration • Paweł Piekut

At Devoxx Poland 2022, Paweł Piekut, a seasoned software developer at Bosch, delivered an insightful presentation on the migration of their e-bike cloud platform from a private cloud to a public cloud environment. Drawing from his expertise in Java, Kotlin, and .NET, Paweł narrated the intricate journey of transitioning a complex IoT ecosystem, highlighting the technical challenges, strategic decisions, and lessons learned. His talk offered a practical roadmap for organizations navigating the complexities of cloud migration, emphasizing the balance between innovation, scalability, and compliance.

Navigating the Private Cloud Landscape

Paweł began by outlining the initial deployment of Bosch’s e-bike cloud on a private cloud developed internally by the company’s IT group. This proprietary platform, designed to support the e-bike ecosystem, facilitated communication between hardware components—such as drive units, batteries, and controllers—and the mobile app, which interfaced with the cloud. The cloud served multiple stakeholders, including factories for device flashing, manufacturers for configuration, authorized services for diagnostics, and end-users for features like activity tracking and bike locking. However, the private cloud faced significant limitations. Scalability was constrained, requiring manual capacity requests and investments, which hindered agility. Downtimes were frequent, acceptable for development but untenable for production. Additionally, the platform’s bespoke nature made it challenging to hire experienced talent and limited developer engagement due to its lack of market-standard tools.

Despite these drawbacks, the private cloud offered advantages. Its deployment within Bosch’s secure network ensured high performance and simplified compliance with data privacy regulations, critical for an international product subject to data localization laws. Costs were predictable, and the absence of vendor lock-in, thanks to open-source frameworks, provided flexibility. However, the need for modern scalability and developer-friendly tools drove the decision to explore public cloud solutions, with Amazon Web Services (AWS) selected for its robust support.

The Hybrid Cloud Conundrum

Transitioning to a hybrid cloud model introduced a blend of private and public cloud environments, creating new challenges. Bosch’s internal policy of “on-transit data” required data processed in the public cloud to be returned to the private cloud, necessitating complex and secure data transfers. While AWS Direct Connect facilitated this, the hybrid setup led to operational complexities. Only select services ran on AWS, causing a divide among developers eager to work with widely recognized public cloud tools. Technical issues, such as Kafka’s inaccessibility from the private cloud, required significant effort to resolve. Error tracing across clouds was cumbersome, with Splunk used in the private cloud and Elasticsearch in the public cloud, complicating root-cause analysis. The simultaneous migration of Jenkins added further complexity, with duplicated jobs and confusing configurations.

Despite these hurdles, the hybrid model offered benefits. It allowed Bosch to leverage the private cloud’s security for sensitive data while tapping into the public cloud’s scalability for peak loads. This setup supported disaster recovery and compliance with data localization requirements. However, the on-transit data concept proved overly complex, leading to dissatisfaction and prompting a strategic shift toward a cloud-first approach, prioritizing public cloud deployment unless justified otherwise.

Embracing the Public Cloud

The full migration to AWS marked a pivotal phase, divided into three stages. First, the team focused on exploration and training to master AWS products and the pay-as-you-go pricing model, which made every developer accountable for costs. This stage emphasized understanding managed versus unmanaged services, such as Kubernetes and Kafka, and ensuring backup compatibility across clouds. The second stage involved building new applications on AWS, addressing unknowns and ensuring secure communication with external systems. Finally, existing services were migrated from private to public cloud, starting with development and progressing to production. Throughout, the team maintained services in both environments, managing separate repositories and addressing critical bugs, such as Log4j vulnerabilities, across both.

To mitigate vendor lock-in, Bosch adopted a cloud-agnostic approach, using Terraform for infrastructure-as-code instead of AWS-specific CloudFormation. While tools like S3 and DynamoDB were embraced for their market-leading performance, backups were standardized to ensure portability. The public cloud’s vast community, extensive documentation, and readily available resources reduced knowledge silos and enhanced developer satisfaction, making the migration a transformative step for innovation and agility.

Lessons for Cloud Migration

Paweł’s experience underscores the importance of aligning cloud strategy with organizational needs. The public cloud’s immediate resource availability and developer-friendly tools accelerated development, but required careful cost management. Hybrid cloud offered flexibility but introduced complexity, particularly with data transfers. Private cloud provided security and control but lacked scalability. Paweł emphasized defining precise requirements—budget, priorities, and compliance—before choosing a cloud model. Startups may favor public clouds for agility, while regulated industries might opt for private or hybrid solutions to prioritize data security and network performance. This strategic clarity ensures a successful migration tailored to business goals.

Links:

PostHeaderIcon [DevoxxPL2022] Challenges Running Planet-Wide Computer: Efficiency • Jacek Bzdak, Beata Strack

Jacek Bzdak and Beata Strack, software engineers at Google Poland, delivered an engaging session at Devoxx Poland 2022, exploring the intricacies of optimizing Google’s planet-scale computing infrastructure. Their talk focused on achieving efficiency in a distributed system spanning global data centers, emphasizing resource utilization, auto-scaling, and operational strategies. By sharing insights from Google’s internal cloud and Autopilot system, Jacek and Beata provided a blueprint for enhancing service performance while navigating the complexities of large-scale computing.

Defining Efficiency in a Global Fleet

Beata opened by framing Google’s data centers as a singular “planet-wide computer,” where efficiency translates to minimizing operational costs—servers, CPU, memory, data centers, and electricity. Key metrics like fleet-wide utilization, CPU/RAM allocation, and growth rate serve as proxies for these costs, though they are imperfect, often masking quality issues like inflated memory usage. Beata stressed that efficiency begins at the service level, where individual jobs must optimize resource consumption, and extends to the fleet through an ecosystem that maximizes resource sharing. This dual approach ensures that savings at the micro level scale globally, a principle applicable even to smaller organizations.

Auto-Scaling: Balancing Utilization and Reliability

Jacek, a member of Google’s Autopilot team, delved into auto-scaling, a critical mechanism for achieving high utilization without compromising reliability. Autopilot’s vertical scaling adjusts resource limits (CPU/memory) for fixed replicas, while horizontal scaling modifies replica counts. Jacek presented data from an Autopilot paper, showing that auto-scaled services maintain memory slack below 20% for median cases, compared to over 60% for manually managed services. Crucially, automation reduces outage risks by dynamically adjusting limits, as demonstrated in a real-world case where Autopilot preempted a memory-induced crash. However, auto-scaling introduces complexity, particularly feedback loops, where overzealous caching or load shedding can destabilize resource allocation, requiring careful integration with application-specific metrics.

Java-Specific Challenges in Auto-Scaling

The talk transitioned to language-specific hurdles, with Jacek highlighting Java’s unique challenges in auto-scaling environments. Just-in-Time (JIT) compilation during application startup spikes CPU usage, complicating horizontal scaling decisions. Memory management poses further issues, as Java’s heap size is static, and out-of-memory errors may be masked by garbage collection (GC) thrashing, where excessive CPU is devoted to GC rather than request handling. To address this, Google sets static heap sizes and auto-scales non-heap memory, though Jacek envisioned a future where Java aligns with other languages, eliminating heap-specific configurations. These insights underscore the need for language-aware auto-scaling strategies in heterogeneous environments.

Operational Strategies for Resource Reclamation

Beata concluded by discussing operational techniques like overcommit and workload colocation to reclaim unused resources. Overcommit leverages the low probability of simultaneous resource spikes across unrelated services, allowing Google to pack more workloads onto machines. Colocating high-priority serving jobs with lower-priority batch workloads enables resource reclamation, with batch tasks evicted when serving jobs demand capacity. A 2015 experiment demonstrated significant machine savings through colocation, a concept influencing Kubernetes’ design. These strategies, combined with auto-scaling, create a robust framework for efficiency, though they demand rigorous isolation to prevent interference between workloads.

Links:

PostHeaderIcon [DevoxxPL2022] How We Migrate Customers and Internal Teams to Kubernetes • Piotr Bochyński

At Devoxx Poland 2022, Piotr Bochyński, a seasoned cloud native expert at SAP, shared a compelling narrative on transitioning customers and internal teams from a Cloud Foundry-based platform to Kubernetes. His presentation illuminated the strategic imperatives, technical challenges, and practical solutions that defined SAP’s journey toward a multi-cloud Kubernetes ecosystem. By leveraging open-source projects like Kyma and Gardener, Piotr’s team addressed the limitations of their legacy platform, fostering developer productivity and operational scalability. His insights offer valuable lessons for organizations contemplating a similar migration.

Understanding Platform as a Service

Piotr began by contextualizing Platform as a Service (PaaS), a model that abstracts infrastructure complexities, allowing developers to focus on application development. Unlike Infrastructure as a Service (IaaS), which provides raw virtual machines, PaaS delivers managed runtimes, middleware, and automation, accelerating time-to-market. However, this convenience comes with trade-offs, such as reduced control and potential vendor lock-in, often tied to opinionated frameworks like the 12-factor application methodology. Piotr highlighted SAP’s initial adoption of Cloud Foundry, an open-source PaaS, to avoid vendor dependency while meeting multi-cloud requirements driven by legal and business needs, particularly in sectors like banking. Yet, Cloud Foundry’s constraints, such as single HTTP port exposure and reliance on outdated technologies like BOSH, prompted SAP to explore Kubernetes as a more flexible alternative.

Kubernetes: A Platform for Platforms

Kubernetes, as Piotr elucidated, is not a traditional PaaS but a container orchestration framework that serves as a foundation for building custom platforms. Its declarative API and extensibility distinguish it from predecessors, enabling consistent management of diverse resources like deployments, namespaces, and custom objects. Piotr illustrated this with the thermostat analogy: developers declare a desired state (e.g., 22 degrees), and Kubernetes controllers reconcile the actual state to match it. This pattern, applied uniformly across resources, empowers developers to extend Kubernetes with custom controllers, such as a hypothetical thermostat resource. The Kyma project, an open-source initiative led by SAP, builds on this extensibility, providing opinionated building blocks like Istio-based API gateways, NATS eventing, and serverless functions to bridge the gap between raw Kubernetes and a developer-friendly PaaS.

Overcoming Migration Challenges

The migration to Kubernetes presented multifaceted challenges, from technical complexity to cultural adoption. Piotr emphasized the steep learning curve associated with Kubernetes’ vast resource set, compounded by additional components like Prometheus and Istio. To mitigate this, SAP employed Kyma to abstract complexities, offering simplified resources like API rules that encapsulate Istio configurations for secure service exposure. Another hurdle was ensuring multi-cloud compatibility. SAP’s Gardener project, a managed Kubernetes solution, addressed this by providing a consistent, Kubernetes-compliant layer across providers like AWS, Azure, and Google Cloud. Piotr also discussed operational scalability, managing thousands of clusters for hundreds of teams. By applying the Kubernetes controller pattern, SAP automated cluster provisioning, upgrades, and security patching, reducing manual intervention and ensuring reliability.

Lessons from the Journey

Reflecting on the migration, Piotr candidly shared missteps that shaped SAP’s approach. Early attempts to shield users from Kubernetes’ complexity by mimicking Cloud Foundry’s API failed, as developers craved direct control over Kubernetes resources. Similarly, restricting cluster admin roles to prevent misconfigurations stifled innovation, leading SAP to grant greater flexibility. Some technology choices, like the Service Catalog project, proved inefficient, underscoring the importance of aligning with Kubernetes’ operator pattern. License changes in tools like Grafana also necessitated pivots, highlighting the need for vigilance in open-source dependencies. Piotr’s takeaways resonate broadly: Kubernetes is a long-term investment, requiring a balance of opinionated tooling and developer freedom, with automation as a cornerstone for scalability.

Links:

PostHeaderIcon [SpringIO2022] Distributed Systems Patterns with Spring Cloud, Service Meshes, and eBPF

At Spring I/O 2022 in Barcelona, Matthias Haeussler delivered an insightful session exploring distributed systems patterns, comparing Spring Cloud, Kubernetes, service meshes, and the emerging eBPF technology. As a consultant at Novatec and a university lecturer, Matthias combined theoretical clarity with a live demo to illustrate how these technologies address challenges like service discovery, routing, and resilience in distributed architectures. His talk offered a practical guide for developers navigating modern microservice ecosystems.

Why Distributed Systems? Understanding the Motivation

Matthias began by addressing the rationale behind distributed systems, emphasizing their ability to enhance client experiences—whether for human users or other applications. By breaking systems into smaller components, developers can execute tasks in parallel, manage heterogeneous environments, and ensure scalability. For instance, running multiple Java versions (e.g., Java 11 and 17) in a single application server is impractical, but distributed systems allow such flexibility. Matthias also highlighted resilience benefits, such as load balancing, traffic throttling, and blue-green deployments, which minimize downtime and maintain system health under varying loads. Security, including authentication and authorization, further underscores the need for distributed architectures to protect and scale services effectively.

However, these benefits come with challenges. Distributed systems require robust mechanisms for service discovery, traffic management, and observability. Matthias framed his talk around comparing how Spring Cloud, Kubernetes, service meshes, and eBPF tackle these requirements, providing a roadmap for choosing the right tool for specific scenarios.

Spring Cloud and Kubernetes: Framework vs. Orchestration

Spring Cloud, dubbed the “classic” approach, integrates distributed system features directly into application code. Matthias outlined key components like Eureka (service registry), Spring Cloud Gateway (routing), and Resilience4j (circuit breaking), which rely on dependencies, annotations, and configuration properties. This in-process approach makes Spring Cloud independent of the runtime environment, allowing deployment on single machines, containers, or clouds without modification. However, changes to dependencies or code require rebuilding, which can slow iterations.

In contrast, Kubernetes offers native orchestration for distributed systems, with its own service registry (DNS), load balancing (via Kubernetes Services), and configuration (ConfigMaps/Secrets). Matthias explained how Spring Cloud Kubernetes bridges these worlds, enabling Spring applications to use Kubernetes’ registry without code changes. For example, annotating with @EnableDiscoveryClient queries Kubernetes’ DNS instead of Eureka. While Kubernetes excels at scaling and deployment, it lacks advanced traffic control (e.g., circuit breaking), where Spring Cloud shines. Matthias suggested combining both for a balanced approach, leveraging Kubernetes’ orchestration and Spring Cloud’s resilience patterns.

Service Meshes: Network-Level Control

Service meshes, such as Istio, introduce a new paradigm by injecting proxy sidecars into Kubernetes pods. Matthias described how these proxies handle network traffic—routing, encryption, and throttling—without altering application code. This separation of concerns allows developers to manage traffic policies (e.g., mutual TLS, percentage-based routing) via YAML configurations, offering granular control unavailable in base Kubernetes. A live demo showcased Istio’s traffic distribution for a Spring Pet Clinic application, visualizing load balancing between service versions.

However, service meshes add overhead. Each pod’s proxy increases latency and memory usage, and managing configurations across scaled deployments can become complex—hence the term “service mess.” Matthias cautioned against adopting service meshes unless their advanced features, like fault injection or network policies, are necessary, especially for simpler Spring Cloud Gateway setups.

eBPF: A Lightweight Future for Service Meshes

The talk’s final segment introduced eBPF (extended Berkeley Packet Filter), a Linux kernel technology enabling low-level network event processing. Unlike service meshes, eBPF injects proxies at the node level, reducing overhead compared to per-pod sidecars. Matthias likened eBPF to JavaScript for HTML, embedding sandboxed code in the kernel to monitor and manipulate traffic. Tools like Cilium leverage eBPF for Kubernetes, offering observability, encryption, and routing with minimal latency.

In his demo, Matthias contrasted Istio and Cilium, showing Cilium’s Hubble UI visualizing traffic for the Spring Pet Clinic. Though still nascent, eBPF promises a sidecar-less service mesh, simplifying deployment and reducing resource demands. Matthias noted its youth, with features like encryption still in beta, but predicted growing adoption as tools mature.

Conclusion: Choosing the Right Approach

Matthias concluded without a definitive recommendation, urging developers to assess their needs. Spring Cloud offers simplicity and runtime independence, ideal for smaller setups. Kubernetes and service meshes suit complex, containerized environments, while eBPF represents a lightweight, future-proof option. His talk underscored the importance of aligning technology choices with project requirements, leaving attendees equipped to evaluate these patterns in their own systems.

Links:

PostHeaderIcon [SpringIO2022] Cloud-Native Healthcare Data Integration with Dapr

Jake Smolka’s Spring I/O 2022 talk offered a compelling case study on building a cloud-native healthcare data integration platform using Dapr, the Distributed Application Runtime. As a health information specialist, Jake shared his journey transforming a Spring Boot prototype into a Kubernetes-based microservice architecture, leveraging Dapr to simplify complexity. His session blended domain insights with technical depth, appealing to both microservice novices and seasoned developers.

Healthcare Data: The Complexity of Interoperability

Jake began with a primer on healthcare data, emphasizing its role in improving clinical outcomes. Clinical data, like blood pressure readings, supports primary care (e.g., diagnoses) and secondary use (e.g., research in university hospitals). However, interoperability remains a challenge due to legacy systems and incompatible standards. Hospitals often manage decades-old data alongside modernized systems, complicating data exchange between clinics. Jake highlighted two standards: OpenEHR, which focuses on semantic interoperability through clinical modeling, and FHIR, designed for lean data exchange. In Catalonia, where the conference was held, public healthcare is shifting to OpenEHR, underscoring its growing importance.

The complexity arises from mismatched standards and real-world data deviations, as illustrated by a colleague’s meme about idealized specifications versus chaotic reality. Jake’s project, FireConnect, aims to bridge OpenEHR and FHIR, enabling bidirectional data mapping for reusable clinical concepts like medication dosages or growth charts. This domain knowledge set the stage for the technical challenges of building a scalable, interoperable solution.

From Prototype to Microservices: The Spring Boot Journey

Jake recounted FireConnect’s evolution, starting as a monolithic Spring Boot application written in Kotlin with Apache Camel for integration. This prototype validated the concept of mapping clinical data but lacked scalability and future-proofing. Stakeholders soon demanded cloud-native features, agnostic deployment, and customer flexibility. Jake adopted Spring Cloud to introduce microservices, incorporating service discovery, load balancing, and distributed configuration. However, the resulting architecture grew unwieldy, with complex internal dependencies (illustrated by a “horror show” diagram). He found himself spending more time managing infrastructure—Kafka, resiliency, and configurations—than writing business logic.

Spring Cloud’s JVM-centric nature limited its agnosticism in mixed-language environments, and its binders (e.g., for Kafka or RabbitMQ) introduced dependencies. Jake realized that while Spring Cloud suited homogeneous Spring ecosystems, FireConnect needed a more flexible, infrastructure-agnostic solution to meet diverse customer needs and simplify development.

Dapr: Streamlining Distributed Systems

Enter Dapr, a Cloud Native Computing Foundation project that abstracts microservice complexities through a sidecar model. Jake introduced Dapr’s building blocks—state management, pub/sub, service invocation, and more—accessible via a simple HTTP/gRPC API. These pluggable components allow applications to switch backends (e.g., RabbitMQ to AWS SQS) without code changes, supporting any language or framework. Dapr’s sidecar offloads tasks like retries, timeouts, and distributed tracing, freeing developers to focus on logic. Observability is built-in, with OpenTelemetry for tracing and metrics, and resiliency features like circuit breakers are preconfigured.

In a demo, Jake showcased a pub/sub quickstart, where a Spring Boot application published orders to a queue, processed by another service via Dapr’s sidecar. The Java SDK’s @Topic annotation integrated seamlessly with Spring, requiring minimal configuration. This setup highlighted Dapr’s ability to simplify communication and ensure portability across clouds or on-premises environments, aligning with FireConnect’s agnostic deployment goals.

FireConnect’s Dapr-Powered Future

Applying Dapr to FireConnect, Jake rearchitected the application for simplicity and scalability. The core translation component now communicates via Dapr’s pub/sub and state management, with pluggable facades for FHIR or OpenEHR APIs. External triggers, like Azure Event Hubs, integrate effortlessly, enhancing flexibility. The leaner architecture reduces infrastructure overhead, allowing Jake to prioritize clinical data mapping over managing glue components. Deployable on Kubernetes or bare metal, FireConnect meets customer demands for platform choice.

Jake’s talk inspired attendees to explore Dapr for distributed systems and consider healthcare data challenges. As his first conference presentation, it was a passionate call to bridge technology and healthcare for better patient outcomes.

Links:

PostHeaderIcon [SpringIO2022] JobRunr: Simplifying Distributed Job Scheduling with Spring

At Spring I/O 2022 in Barcelona, Ronald Dehuysser introduced JobRunr, an open-source Java library designed to streamline distributed background job processing. His engaging session, blending practical insights with live coding, showcased how JobRunr empowers developers to transform Java 8 lambdas into scalable, fault-tolerant jobs without complex infrastructure. Tailored for businesses handling moderate data volumes, Ronald’s talk highlighted JobRunr’s seamless integration with Spring and its potential to revolutionize job scheduling.

The Genesis of JobRunr: Solving Real-World Challenges

Ronald, a contractor from Belgium, kicked off by sharing the origins of JobRunr, born from a challenging “greenfield” fintech project. Tasked with building an invoicing platform on Google Cloud, he encountered a microservice architecture plagued by issues: no retry mechanisms, poor monitoring, and lost invoices due to untracked failures. The project’s eight microservices led to code duplication, prompting Ronald to question the microservice hype and advocate for simpler, modular monoliths. Frustrated by the lack of developer-friendly, open-source job scheduling tools, he created JobRunr to address these gaps, emphasizing ease of use, existing infrastructure, and automatic retries.

JobRunr’s philosophy is rooted in simplicity and practicality. Unlike solutions requiring heavy infrastructure like Apache Kafka or vendor-specific cloud services, JobRunr leverages SQL or NoSQL databases for persistence, making it embeddable with a single JAR. Ronald stressed that most businesses don’t need to process terabytes daily like tech giants. Instead, JobRunr targets complex business processes with gigabytes of data, offering a plug-and-play solution with built-in monitoring and fault tolerance.

Core Features: From Lambdas to Distributed Jobs

The heart of JobRunr lies in its ability to convert Java 8 lambdas into distributed background jobs. Ronald demonstrated this with a Spring service example, where a static BackgroundJob.enqueue method schedules jobs without altering existing code. Jobs are serialized as JSON, stored in a database, and processed by BackgroundJobServer instances across JVMs, enabling horizontal scaling in Kubernetes. A dashboard provides real-time insights into job status, with automatic retries (up to 10 by default) using an exponential backoff policy to handle failures gracefully.

For scheduling flexibility, JobRunr supports immediate, delayed, or recurring jobs. Ronald showcased the schedule API for jobs running after a delay (e.g., 24 hours) and the scheduleRecurrently method for daily tasks, using a readable Cron class to simplify cron expressions. The dashboard allows manual triggering of recurring jobs for testing, enhancing developer control. To prevent duplicate processing, JobRunr offers mutex support, though advanced features like this are part of the paid Pro version, balancing open-source accessibility with sustainability.

Under the Hood: Bytecode Magic and Spring Native

Delving into JobRunr’s internals, Ronald revealed its use of ASM for bytecode manipulation, translating lambdas into executable jobs. While some criticized this as “black magic,” he countered with assurances of binary compatibility, backed by Oracle’s Java Language Specification and his participation in Oracle’s Quality Outreach Program. JobRunr’s compatibility spans Java 8 to 17, tested across JVMs using Testcontainers, ensuring robustness. The introduction of JobRequest and JobRequestHandler in version 4 further simplifies job definition, aligning with the command handler pattern for explicit job processing.

A highlight was JobRunr’s integration with Spring Native, enabling compilation to GraalVM native images for millisecond startup times and low memory usage. Ronald collaborated with the Spring team to ensure reflection compatibility, making JobRunr a natural fit for cloud-native deployments. The live coding demo, despite minor hiccups, showcased JobRunr’s ease of use: Ronald built an uptime monitoring service, scheduling recurring website checks with a few lines of code, monitored via the dashboard. This practicality resonated with attendees, who appreciated JobRunr’s developer-friendly approach.

Impact and Future: Empowering Developers

JobRunr’s adoption spans medical image processing, web crawling, and document generation, with 30,000 monthly Maven downloads. Ronald shared a compelling anecdote: a company reported a 20% developer productivity boost by using the dashboard’s requeue feature for first-line support, reducing interruptions. Looking ahead, JobRunr aims to enhance GraalVM support, add OpenID Connect for dashboard authentication, and incorporate community-driven features. The Pro version funds development, with 5% of profits supporting environmental causes like tree planting.

Ronald’s session underscored JobRunr’s mission to simplify distributed job scheduling, making it an invaluable tool for Spring developers tackling real-world business challenges with minimal overhead.

Links:

PostHeaderIcon [SpringIO2019] Cloud Native Spring Boot Admin by Johannes Edmeier

At Spring I/O 2019 in Barcelona, Johannes Edmeier, a seasoned developer from Germany, captivated attendees with his deep dive into managing Spring Boot applications in Kubernetes environments using Spring Boot Admin. As the maintainer of this open-source project, Johannes shared practical insights into integrating Spring Boot Admin with Kubernetes via the Spring Cloud Kubernetes project. His session illuminated how developers can gain operational visibility and control without altering application code, making it a must-know tool for cloud-native ecosystems. This post explores Johannes’ approach, highlighting its relevance for modern DevOps.

Understanding Spring Boot Admin

Spring Boot Admin, a four-and-a-half-year-old project boasting over 17,000 GitHub stars, is an Apache-licensed tool designed to monitor and manage Spring Boot applications. Johannes, employed by ConSol, a German consultancy, dedicates 20% of his work time—and significant personal hours—to its development. The tool provides a user-friendly interface to visualize metrics, logs, and runtime configurations, addressing the limitations of basic monitoring solutions like plain metrics or logs. For Kubernetes-deployed applications, it leverages Spring Boot Actuator endpoints to deliver comprehensive insights without requiring code changes or new container images.

The challenge in cloud-native environments lies in achieving visibility into distributed systems. Johannes emphasized that Kubernetes, a common denominator across cloud vendors, demands robust monitoring tools. Spring Boot Admin meets this need by integrating with Spring Cloud Kubernetes, enabling service discovery and dynamic updates as services scale or fail. This synergy ensures developers can manage applications seamlessly, even in complex, dynamic clusters.

Setting Up Spring Boot Admin on Kubernetes

Configuring Spring Boot Admin for Kubernetes is straightforward, as Johannes demonstrated. Developers start by including the Spring Boot Admin starter server dependency, which bundles the UI and REST endpoints, and the Spring Cloud Kubernetes starter for service discovery. These dependencies, managed via Spring Cloud BOM, simplify setup. Johannes highlighted the importance of enabling the admin server, discovery client, and scheduling annotations in the application class to ensure health checks and service updates function correctly. A common pitfall, recently addressed in the documentation, is forgetting to enable scheduling, which prevents dynamic service updates.

For Kubernetes deployment, Johannes pre-built a Docker image and configured a service account with role-based access control (RBAC) to read pod, service, and endpoint data. This minimal RBAC setup avoids unnecessary permissions, enhancing security. An ingress and service complete the deployment, allowing access to the Spring Boot Admin UI. Johannes showcased a wallboard view, ideal for team dashboards, and demonstrated real-time monitoring by simulating a service failure, which triggered a yellow “restricted” status and subsequent recovery as Kubernetes rescheduled the pod.

Enhancing Monitoring with Actuator Endpoints

Spring Boot Admin’s power lies in its integration with Spring Boot Actuator, which exposes endpoints like health, info, metrics, and more. By default, only health and info endpoints are exposed, but Johannes showed how to expose all endpoints using a Kubernetes environment variable (management.endpoints.web.exposure.include=*). This unlocks detailed views for metrics, environment properties, beans, and scheduled tasks. For instance, the health endpoint provides granular details when set to “always” show details, revealing custom health indicators like database connectivity.

Johannes also highlighted advanced features, such as rendering Swagger UI links via the info endpoint’s properties, simplifying access to API documentation. For security, he recommended isolating Actuator endpoints on a separate management port (e.g., 9080) to prevent public exposure via the main ingress. Spring Cloud Kubernetes facilitates this by allowing developers to specify the management port for discovery, ensuring Spring Boot Admin accesses Actuator endpoints securely while keeping them hidden from external traffic.

Customization and Security Considerations

Spring Boot Admin excels in customization, catering to specific monitoring needs. Johannes demonstrated how to add top-level links to external tools like Grafana or Kibana, or embed them as iframes, reducing the need to memorize URLs. For advanced use cases, developers can create custom views using Vue.js, as Johannes did to toggle application status (e.g., setting a service to “out of service”). This flexibility extends to notifications, supporting Slack, Microsoft Teams, and email via simple configurations, with a test SMTP server like MailHog for demos.

Security is a critical concern, as Spring Boot Admin proxies requests to Actuator endpoints. Johannes cautioned against exposing the admin server publicly, citing an unsecured instance found via Google. He outlined three security approaches: no authentication (not recommended), session-based authentication with cookies, or OAuth2 with token forwarding, where the target application validates access. A service account handles background health checks, ensuring minimal permissions. For Keycloak integration, Johannes referenced a blog post by his colleague Tomas, showcasing Spring Boot Admin’s compatibility with modern security frameworks.

Runtime Management and Future Enhancements

Spring Boot Admin empowers runtime management, a standout feature Johannes showcased. The loggers endpoint allows dynamic adjustment of logging levels, with a forthcoming feature to set levels across all instances simultaneously. Other endpoints, like Jolokia for JMX interaction, enable runtime reconfiguration but require caution due to their power. Heap and thread dump endpoints aid debugging but risk exposing sensitive data or overwhelming resources. Johannes also previewed upcoming features, like minimum instance checks, enhancing Spring Boot Admin’s robustness in production.

For Johannes, Spring Boot Admin is more than a monitoring tool—it’s a platform for operational excellence. By integrating seamlessly with Kubernetes and Spring Boot Actuator, it addresses the complexities of cloud-native applications, empowering developers to focus on delivering value. His session at Spring I/O 2019 underscores its indispensable role in modern software ecosystems.

Links:

PostHeaderIcon Navigating the Application Lifecycle in Kubernetes

At Devoxx France 2019, Charles Sabourdin and Jean-Christophe Sirot, seasoned professionals in cloud-native technologies, delivered an extensive exploration of managing application lifecycles within Kubernetes. Charles, an architect with over 15 years in Linux and Java, and Jean-Christophe, a Docker expert since 2002, combined their expertise to demystify Docker’s underpinnings, Kubernetes’ orchestration, and the practicalities of continuous integration and delivery (CI/CD). Through demos and real-world insights, they addressed security challenges across development and business-as-usual (BAU) phases, proposing organizational strategies to streamline containerized workflows. This post captures their comprehensive session, offering a roadmap for developers and operations teams navigating Kubernetes ecosystems.

Docker’s Foundations: Isolation and Layered Efficiency

Charles opened the session by revisiting Docker’s core principles, emphasizing its reliance on Linux kernel features like namespaces and control groups (cgroups). Unlike virtual machines (VMs), which bundle entire operating systems, Docker containers share the host kernel, isolating processes within lightweight environments. This design achieves hyper-density, allowing more containers to run on a single machine compared to VMs. Charles demonstrated launching a container, highlighting its process isolation using commands like ps within a containerized bash session, contrasting it with the host’s process list. He introduced Docker’s layer system, where images are built as immutable, stacked deltas, optimizing storage through shared base layers. Tools like Dive, he noted, help inspect these layers, revealing command histories and suggesting size optimizations. This foundation sets the stage for Kubernetes, enabling efficient, portable application delivery across environments.

Kubernetes: Orchestrating Scalable Deployments

Jean-Christophe transitioned to Kubernetes, describing it as a resource orchestrator that manages containerized applications across node pools. Kubernetes abstracts infrastructure complexities, using declarative configurations to maintain desired application states. Key components include pods—the smallest deployable units housing containers—replica sets for scaling, and deployments for managing updates. Charles demonstrated creating a namespace and deploying a sample application using kubectl run, which scaffolds deployments, replica sets, and pods. He showcased rolling updates, where Kubernetes progressively replaces pods to ensure zero downtime, configurable via parameters like maxSurge and maxUnavailable. The duo emphasized Kubernetes’ auto-scaling capabilities, which adjust pod counts based on load, and the importance of defining resource limits to prevent performance bottlenecks. Their demo underscored Kubernetes’ role in achieving resilient, scalable deployments, aligning with hyper-density goals.

CI/CD Pipelines: Propagating Versions Seamlessly

The session delved into CI/CD pipelines, illustrating how Docker tags facilitate version propagation across development, pre-production, and production environments. Charles outlined a standard process: developers build Docker images tagged with version numbers (e.g., 1.11.2) or environment labels (e.g., prodstaging). These images, stored in registries like Docker Hub or private repositories, are pulled by Kubernetes clusters for deployment. Jean-Christophe highlighted debates around tagging strategies, noting that version-based tags ensure traceability, while environment tags simplify environment-specific deployments. Their demo integrated tools like Jenkins and JFrog Artifactory, automating builds, tests, and deployments. They stressed the need for robust pipeline configurations to avoid resource overuse, citing Jenkins’ default manual build triggers for tagged releases as a safeguard. This pipeline approach ensures consistent, automated delivery, bridging development and production.

Security Across the Lifecycle: Development vs. BAU

Security emerged as a central theme, with Charles contrasting development and BAU phases. During development, teams rapidly address Common Vulnerabilities and Exposures (CVEs) with frequent releases, leveraging tools like JFrog Xray and Clair to scan images for vulnerabilities. Xray integrates with Artifactory, while Clair, an open-source solution, scans registry images for known CVEs. However, in BAU, where releases are less frequent, unpatched vulnerabilities pose greater risks. Charles shared an anecdote about a PHP project where a dependency switch broke builds after two years, underscoring the need for ongoing maintenance. They advocated for practices like running containers in read-only mode and using non-root users to minimize attack surfaces. Tools like OWASP Dependency-Track, they suggested, could enhance visibility into library vulnerabilities, though current scanners often miss non-package dependencies. This dichotomy highlights the need for automated, proactive security measures throughout the lifecycle.

Organizational Strategies: Balancing Complexity and Responsibility

Drawing from their experiences, Charles and Jean-Christophe proposed organizational solutions to manage Kubernetes complexity. They introduced a “1-2-3 model” for image management: Level 1 uses vendor-provided images (e.g., official MySQL images) managed by operations; Level 2 involves base images built by dedicated teams, incorporating standardized tooling; and Level 3 allows project-specific images, with teams assuming maintenance responsibilities. This model clarifies ownership, reducing risks like disappearing maintainers when projects transition to BAU. They emphasized cross-team collaboration, encouraging developers and operations to share knowledge and align on practices like Dockerfile authorship and resource allocation in YAML configurations. Charles reflected on historical DevOps silos, advocating for shared vocabularies and traceable decisions to navigate evolving best practices. Their return-of-experience underscored the importance of balancing automation with human oversight to maintain robust, secure Kubernetes environments.

Hashtags: #Kubernetes #Docker #DevOps #CICD #Security #DevoxxFR #CharlesSabourdin #JeanChristopheSirot #JFrog #Clair