Sarıkaya Dev Logo

Deploy .NET 8 Native AOT Apps with Cloud Native Buildpacks on Kubernetes

Mahmut Sarıkaya 3 min read 4 Views 0
Deploy .NET 8 Native AOT Apps with Cloud Native Buildpacks on Kubernetes

Why Native AOT is a game changer

Imagine a microservice that starts in under 50 ms, uses 30 % less memory, and produces a single executable that can run without a runtime installed. .NET 8 Native AOT delivers exactly that, turning managed code into a statically linked binary. The reduction in cold‑start latency is especially valuable for serverless platforms and edge nodes where every millisecond counts.

Preparing the .NET 8 project for AOT

First, make sure you are on .NET SDK 8.0.202 or later. Add the <PublishAot>true</PublishAot> flag to the project file and enable trimming. A minimal .csproj looks like this:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <PublishAot>true</PublishAot>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishTrimmed>true</PublishTrimmed>
  </PropertyGroup>
</Project>

Run dotnet publish -c Release -r linux-x64 --self-contained false to verify that the AOT binary is produced. The output folder will contain a single myapp executable alongside a few native DLLs.

Leveraging Cloud Native Buildpacks

Cloud Native Buildpacks (CNB) automate the conversion of source code into OCI images without a Dockerfile. The Paketo .NET Buildpack has been updated for .NET 8 and supports the native-aot environment variable. Install the pack CLI (version 0.33 or later) and then execute:

pack build myapp-aot \
  --builder paketobuildpacks/builder:base \
  --buildpack paketo-buildpacks/dotnet-core \
  --env BP_DOTNET_NATIVE_AOT=true \
  --path ./src/MyApp

The command creates a lightweight OCI image that contains only the native binary and the minimal libc dependencies. No JIT compiler, no extra runtime layers, and the resulting image size is typically under 30 MB for a simple API.

Deploying to Kubernetes without Docker

Kubernetes accepts any OCI‑compatible image, so you can push the Buildpack image directly to a registry like Azure Container Registry or GitHub Packages. After pushing, define a Deployment manifest that references the image and sets the appropriate security context to run as a non‑root user.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-aot
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp-aot
  template:
    metadata:
      labels:
        app: myapp-aot
    spec:
      containers:
      - name: myapp
        image: ghcr.io/yourorg/myapp-aot:latest
        ports:
        - containerPort: 8080
        securityContext:
          runAsNonRoot: true
          runAsUser: 1000
      restartPolicy: Always

Apply the manifest with kubectl apply -f deployment.yaml. The pod will start in less than a second because the container image already contains the native executable. Expose the service with a ClusterIP or an Ingress, depending on your traffic pattern.

Monitoring, logging and troubleshooting

Even though the binary is native, .NET 8 still emits structured logs when you use ILogger. Forward logs to a sidecar like Fluent Bit or to a managed service such as Azure Monitor. For performance metrics, Prometheus exporters are available via the dotnet-monitor sidecar, which works with AOT binaries without additional configuration.

If the container fails to start, inspect the pod logs with kubectl logs <pod-name>. Common issues include missing native libraries (glibc version mismatch) or insufficient permissions for the non‑root user. The Buildpack adds a RUN chmod +x /layers/paketo-buildpacks_dotnet-core/launcher step, but you may need to add securityContext.allowPrivilegeEscalation: false to comply with stricter policies.

Conclusion

Combining .NET 8 Native AOT with Cloud Native Buildpacks gives you a Dockerless workflow that produces ultra‑small, fast‑starting containers ready for Kubernetes. The approach reduces operational overhead, improves scaling latency, and aligns perfectly with modern cloud‑native best practices. Start with a simple API, enable BP_DOTNET_NATIVE_AOT, and watch your pods spin up in milliseconds.

Sources

Microsoft .NET 8 Documentation, Paketo Buildpacks Official Site, Kubernetes Official Documentation

Author: Mahmut Sarıkaya — sarikayadev.com

Tags: #dotnet 8 #native AOT #cloud native buildpacks #kubernetes deployment #dockerless containers
Share:
M

Written by

Mahmut Sarıkaya

Software Developer

Comments

No comments yet. Be the first to share your thoughts!

Leave a Comment

7 + 1 =