AWS Architecture Blog

How BMW Group accelerated connected vehicle workloads on AWS Graviton

This post is co-written with Tomislav Lozancic, Hrvoje Lukavski from BMW Group, and Hugo Cardoso from CTW.

BMW Connected Company, a division within BMW Group, develops and operates premium digital services for BMW’s connected vehicle fleet of more than 24.5 million vehicles worldwide. Critical TechWorks (CTW), established in September 2018, focuses exclusively on developing software for BMW Group’s future connected vehicle fleet.

In 2024, BMW Connected Company began migrating its Connected Vehicle platform, known internally as Orbit, from x86 to Arm-based compute as part of a broader modernization strategy to advance BMW Group’s economic and environmental goals.

In this post, we share the methodology behind the migration, tooling and patterns that helped application teams move to AWS Graviton at their own pace, without service disruption.

Laying the groundwork

Before applications could adopt a new processor architecture, the platform needed a more flexible provisioning layer. The team adopted Karpenter, replacing fixed Managed Node Groups with dynamic, policy-driven node pools that could provision the right instance type automatically. You can read more about this migration in Transforming the BMW Connected Vehicle Backend with Karpenter.

With the compute foundation in place, the next challenge was supporting multi-architecture builds. Building, testing, and deploying the same application for two architectures without slowing teams down required extending the continuous integration and continuous delivery (CI/CD) platform. Build runners needed to target both x86 and Arm while producing dual build pipelines, as described in the following section.

Introducing Graviton-based CI/CD runners

The Connected Vehicle CI/CD platform facilitates over 130,000 builds and deployments daily through self-hosted GitHub Actions runners. You can read more about the evolution of this platform in An Engine of Efficiency: BMW Group’s CI/CD Modernization Journey with AWS.

To surface potential issues early and minimize disruption, the team first validated Graviton on a set of self-contained services. Dedicated Graviton runners operated alongside the existing x86 fleet during this phase. The price-performance advantage of Graviton was confirmed immediately, with lower cost per build minute and faster build times, justifying the business case for wider adoption.

Building on these initial results, the team designed the wider platform rollout around two complementary tracks.

  1. Dual build pipelines: Building and shipping both CPU architectures in parallel, giving applications a non-disruptive path to transition independently.
  2. Container hosting: Extending support into the centralized container platform, so applications could be hosted on Graviton.

The following figure shows the six-stage journey to adopt AWS Graviton. The stages are grouped into two phases: a build-foundation phase and a workload-migration phase.

Six-stage AWS Graviton adoption journey grouped into a build-foundation phase and a workload-migration phase

Figure 1: AWS Graviton adoption journey across the Connected Vehicle platform

Supporting adoption

Getting teams onto Graviton depended less on policy than on removing friction. The following practices lowered the barrier to entry, beginning with the build pipeline.

1 – Multi-architecture builds

As outlined earlier, every container image needed to support both architectures before workloads could run on Arm-based instances. To achieve this, two complementary build approaches were used: emulated builds using Docker Buildx with QEMU, and native builds on Graviton-based runners.

Both approaches produce multi-arch images by publishing a manifest list (OCI image index) alongside the architecture-specific images. When a container runtime pulls a tagged image, it reads the manifest and automatically selects the correct variant for the node’s architecture. This means a single image tag serves both arm64 and amd64 nodes transparently.

2 – Mirroring base images

Public images are mirrored into a private Amazon Elastic Container Registry (Amazon ECR) to achieve availability, immutability, and CVE compliance. To preserve multi-arch support during mirroring, the team uses Google’s Crane. Crane transfers images directly between registries and filters the manifest to only the required platforms, which avoids wasted storage from unused architectures.

Besides public images, custom application workloads also needed support for both architectures. Most Dockerfiles required no changes, because their base images and dependencies already supported multiple architectures. In some cases, an alternative or dependency with Arm support needed to be found. For the builds, two approaches were considered:

  1. Native build per architecture: Each architecture is built and pushed separately on a runner with the matching architecture, followed by a final job that creates and pushes the image index. In GitHub Actions, this means one runner per architecture plus one index-creation step. This approach is more reliable but requires a dedicated runner for each target architecture.
  2. Emulated builds from a single machine: Using Docker Buildx with QEMU, all architectures can be built and pushed from a single x86 or Arm runner. This streamlines the pipeline but introduces emulation overhead, often making builds significantly slower for compute-intensive workloads.

The team opted to support both approaches. For platform-scale adoption, Graviton runners were preferred because they ran arm64 builds natively. This avoided the QEMU emulation overhead and surfaced architecture-specific issues earlier in the pipeline. With GitHub Actions reusable workflows, teams can select the right fit for each use case. Dockerfiles use the QEMU path to avoid spinning up additional runners. Those with significant complexity, large dependency downloads, or long build times use native builds, where the overhead becomes problematic.

Graviton runner labels mirror the existing x86 labels, so adoption involves swapping x64 for arm64 in a single label.

3 – Defining Graviton NodePools

The following diagram shows the mixed-architecture Amazon Elastic Kubernetes Service (Amazon EKS) cluster, including how on-premises systems connect and how the Graviton and x86 node pools coexist.

Mixed-architecture Amazon EKS cluster showing on-premises connectivity and coexisting Graviton and x86 node pools

Figure 2: Mixed-architecture Amazon EKS cluster with dedicated Graviton node pools and opt-in scheduling

Dedicated Graviton node pools let teams adopt without friction across each environment. The pools are shared and general-purpose by default, not tailored to individual workloads. This keeps the underlying infrastructure model consistent and predictable while still allowing teams to migrate on their own schedule. Karpenter’s automatic scaling foundation supports efficient resource allocation and rapid provisioning for both Arm and x86 workloads.

To avoid accidental scheduling, the Graviton node pools use taints. Workloads must explicitly opt in using a node selector and matching toleration. This supports controlled rollout and predictable behavior:

nodeSelector:
  bmw.de/stateless-arm: supported

tolerations:
- key: "bmw.de/stateless-arm"
  operator: "Equal"
  value: "supported"
  effect: "NoSchedule"

With this in place, only Arm-ready workloads are scheduled on Graviton nodes, while other workloads continue to run on amd64 nodes without disruption.

4 – Phased rollout

Before supporting broad adoption for application workloads, the team first validated the migration path by running core platform services (Karpenter, Prometheus, and operational tooling). This platform-first approach identified compatibility gaps early, refined node pool configuration, and established rollback patterns. Teams had a proven reference model before they were encouraged to opt in.

A key design principle was minimizing rollback risk by keeping both architectures viable simultaneously. Dual-arch images and a dedicated NodePool mean every application can run on both CPU architectures. If issues arise, workloads fall back to x86 without image rebuilds or pipeline changes.

Kubernetes node affinity rules prefer Arm without forcing it, so workloads naturally gravitate toward Graviton instances:

{{/*
Workload node affinity
*/}}
{{- define "common.nodeaffinity" -}}
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
  preference:
    matchExpressions:
    - key: kubernetes.io/arch
      operator: In
      values:
      - arm64
{{- end -}}

{{/*
Workload node tolerations
*/}}
{{- define "common.tolerations" -}}
- key: bmw.de/arm
  operator: Equal
  value: supported
  effect: NoSchedule
{{- end -}}

If a full rollback is needed, the GitOps-based ArgoCD deployment model makes recovery straightforward by reverting to the previous version in Git and letting ArgoCD reconcile the cluster state.

Results

The migration delivered approximately $600,000 in annualized infrastructure savings and measurable performance improvements. After moving the NGINX-based ingress controller from x86 to Graviton, key results included:

  • CPU consumption decreased by approximately 57 percent, while maintaining the same ingress profile.
  • Price-performance improved by around 40 percent, as lower CPU consumption per request increased throughput capacity per dollar spent.
  • Scaling efficiency improved at peak loads, with workloads requiring less compute capacity to handle equivalent traffic volumes.

Today, more than 65 percent of the platform runs on Graviton across production environments, a shift that supports BMW Group’s sustainability goals by reducing compute energy demand.

Lessons learned

Migrating a platform of this scale surfaced practical lessons that shaped the team’s approach and would benefit others considering a similar transition:

  • Opt-in scheduling: Use taints, selectors, and tolerations to make sure that only ready workloads migrate.
  • Multi-architecture images: One manifest-based tag for both architectures keeps releases straightforward and rollback instant.
  • Platform-first adoption: Validate on shared infrastructure first to reduce risk before teams opt in.
  • Optimization of emulated builds: This approach is useful for straightforward pipelines. Compute-heavy builds should use native or cross-compilation paths instead, which avoids unnecessary QEMU overhead and long build times.

Conclusion

BMW Group migrated its Connected Vehicle platform to AWS Graviton, achieving over $600,000 in annual cost savings and a 40 percent improvement in price-performance. The more than 130,000 daily builds and deployments that power more than 24.5 million connected vehicles continued without disruption.

The migration succeeded because of deliberate, incremental choices: taint-based node isolation, multi-arch container builds, and Karpenter’s ability to provision the right instance at the right time. Each layer reduced risk while keeping the rollout optional for individual teams. What started as a platform experiment is now the default compute path.

To get started with Graviton-based workloads on Amazon EKS, see the AWS Graviton Getting Started guide. To learn how BMW Group adopted Karpenter at scale, read Transforming the BMW Connected Vehicle Backend with Karpenter.


About the authors

Tomislav Lozančić

Tomislav Lozančić

Tomislav is Lead Cloud Solution Architect at BMW Group, responsible for the Connected Vehicle platform overseeing more than 400 Amazon EKS clusters supporting 24.5+ million connected vehicles. With a degree in Computer Science, he specializes in cloud-native technologies and Kubernetes at scale. Tomislav focuses on optimizing cloud infrastructure for performance, cost efficiency, and reliability, playing a key role in BMW Group’s cloud strategy and mission-critical services.

Brendan Jones

Brendan Jones

Brendan is a Senior Solutions Architect at AWS for BMW Group. He is passionate about helping automotive customers build innovative, highly scalable, and resilient cloud architectures which maximize business impact for their customers.

Akshay Gupta

Akshay Gupta

Akshay is a Cloud Infrastructure Architect at AWS with over 14 years of experience in designing and implementing scalable, secure, and cost-efficient cloud solutions. He leads cloud transformation initiatives across multiple industries, helping customers modernize their infrastructure and optimize cloud operations. Akshay specializes in DevOps automation, FinOps strategies, and infrastructure-as-code frameworks to drive efficiency and innovation. In his free time, Akshay enjoys contributing to the cloud and DevOps community through technical writing, open-source projects, and mentoring professionals in their cloud journey.

Hrvoje Lukavski

Hrvoje Lukavski

Hrvoje is Lead Product Manager at BMW Group, driving the development of the Connected Vehicle Platform and ensuring its quality and future-readiness. A FinOps Champion and Chaos Engineering pioneer, he advises executive leadership on cloud strategy and believes the best engineering disappears into the product.

Hugo Cardoso

Hugo Cardoso

Hugo is a DevOps Engineer at Critical TechWorks. With a background in software engineering, he applies a developer’s mindset to platform and infrastructure challenges by connecting systems and extending them with software when needed. He focuses on breaking down complex problems while maintaining strong security and tenancy boundaries, delivering solutions that keep platforms simple and intuitive for both their users and maintainers.