Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Doing Multi-Cloud the Easy Way... But should you?

Nico Krijnen
October 19, 2023

Doing Multi-Cloud the Easy Way... But should you?

In today's rapidly evolving technological landscape, organizations are increasingly adopting cloud computing as a means to enhance scalability and flexibility. However, multi-cloud makes this a complex decision process.

Tools like Kubernetes, Terraform, and Dapr simplify multi-cloud by providing a unified programming model that work seamlessly across different clouds.

That sounds great! Almost too good to be true? What are the trade-offs that they bring? Do they truly prevent vendor lock-in? And what are you loosing by not making full use of what your cloud vendor has to offer?

Nico Krijnen

October 19, 2023
Tweet

More Decks by Nico Krijnen

Other Decks in Business

Transcript

  1. Mixed Cloud ≠ Multi Cloud • Services only offered by

    specific cloud vendors • Services already in-place and integratable to any cloud platform
  2. Go Multi-Cloud? • You require extreme redundancy and reliability •

    You want to avoid vendor lock-in • It happened to you • You're build a non-SaaS product • You want to minimize costs
  3. Multi-Cloud is not trivial • Manage diverse infrastructure • Complex

    in deployment and maintenance • Performance & data transfer concerns • Fragmented security solutions • Explosion of required knowledge
  4. Doing Multi-Cloud the Easy Way But should you? Nico Krijnen

    Doing Multi-Cloud the Easy Way @nicokrijnen nkrijnen nicokrijnen
  5. k-proxy kubelet sched sched sched Control Plane Node etcd Kubernetes

    cluster api api api c-c-m c-c-m c-c-m c-m c-m c-m Node Node k-proxy kubelet kubelet k-proxy Control plane Scheduler sched Cloud controller manager (optional) c-c-m Controller manager c-m kubelet kubelet kube-proxy k-proxy (persistence store) etcd etcd Node API server api
  6. AWS Azure GCP Kubernetes / EKS Database Pod Application Pod

    Database Pod Application Pod Application Pod Sidecar Sidecar Sidecar Sidecar Sidecar Sidecar Sidecar Sidecar Redis Pod Sidecar Sidecar Grafana Pod ArgoCD Pod Prometheus Pod Ingress Controller Cilium CNI External Secrets Operator
  7. AWS Azure GCP On premise Kubernetes / EKS Database Pod

    Application Pod Database Pod Application Pod Application Pod Sidecar Sidecar Sidecar Sidecar Sidecar Sidecar Sidecar Sidecar Redis Pod Sidecar Sidecar Grafana Pod ArgoCD Pod Prometheus Pod Ingress Controller Cilium CNI External Secrets Operator
  8. !

  9. !

  10. Where does it break? "When we think about building cloud

    abstractions, finding suitable abstractions is difficult enough. But even that is only half the story. We also need to find a “stack trace”, a path back from any failure point to determining what to change at the abstraction layer to correct it." – Gregor Hohpe architectelevator.com/architecture/stacktrace-abstraction/
  11. Dapr - Queue pub/sub private val daprClient = DaprClientBuilder().build() fun

    publishEvent(event: CarEnteredEvent) { println("Publishing $event") val publishEventRequest = PublishEventRequest( pubsubName = "eventbus", topic = "cartelemetry", data = event ) daprClient.publishEvent(publishEventRequest).block() } !!" @Topic(name = "cartelemetry", pubsubName = "eventbus") @PostMapping("/cartelemetry") fun handleQueueMessage( @RequestBody(required = false) cloudEvent: CloudEvent<CarEnteredEvent> ) { handleCarTelemetry(cloudEvent.data) } private fun handleCarTelemetry(event: CarEnteredEvent) { println("Car ${event.licensePlate} at ${event.time}") } apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: cartelemetry spec: type: bindings.aws.sqs version: v1 metadata: - name: queueName value: "cartelemetry" - name: region value: "us-west-2" - name: accessKey value: "*****************" - name: secretKey value: "*****************" - name: sessionToken value: "*****************" - name: direction value: "input, output"
  12. Dapr vs AWS native private val daprClient = DaprClientBuilder().build() fun

    publishEvent(event: CarEnteredEvent) { println("Publishing $event") val publishEventRequest = PublishEventRequest( pubsubName = "eventbus", topic = "cartelemetry", data = event ) daprClient.publishEvent(publishEventRequest).block() } !!" @Topic(name = "cartelemetry", pubsubName = "eventbus") @PostMapping("/cartelemetry") fun handleQueueMessage( @RequestBody(required = false) cloudEvent: CloudEvent<CarEnteredEvent> ) { handleCarTelemetry(cloudEvent.data) } private fun handleCarTelemetry(event: CarEnteredEvent) { println("Car ${event.licensePlate} at ${event.time}") } private val sqs = AmazonSQSClientBuilder.defaultClient() fun publishEvent(event: CarEnteredEvent) { println("Publishing $event") val sendMessageRequest = SendMessageRequest() .withQueueUrl(queueUrl) .withMessageBody(event.toJson()) sqs.sendMessage(sendMessageRequest) } !!" @PostConstruct private fun handleQueueMessages() { while (true) { val result = sqs.receiveMessage(queueUrl) result.messages.forEach { msg !" handleCarTelemetry(msg.body.fromJson()) sqs.deleteMessage(queueUrl, msg.receiptHandle) } } } private fun handleCarTelemetry(event: CarEnteredEvent) { println("Car ${event.licensePlate} at ${event.time}") }
  13. Dapr vs AWS native private val daprClient = DaprClientBuilder().build() fun

    publishEvent(event: CarEnteredEvent) { println("Publishing $event") val publishEventRequest = PublishEventRequest( pubsubName = "eventbus", topic = "cartelemetry", data = event ) daprClient.publishEvent(publishEventRequest).block() } !!" @Topic(name = "cartelemetry", pubsubName = "eventbus") @PostMapping("/cartelemetry") fun handleQueueMessage( @RequestBody(required = false) cloudEvent: CloudEvent<CarEnteredEvent> ) { handleCarTelemetry(cloudEvent.data) } private fun handleCarTelemetry(event: CarEnteredEvent) { println("Car ${event.licensePlate} at ${event.time}") } private val sqs = AmazonSQSClientBuilder.defaultClient() fun publishEvent(event: CarEnteredEvent) { println("Publishing $event") val sendMessageRequest = SendMessageRequest() .withQueueUrl(queueUrl) .withMessageBody(event.toJson()) .withDelaySeconds(5) sqs.sendMessage(sendMessageRequest) } !!" @PostConstruct private fun handleQueueMessages() { while (true) { val request = ReceiveMessageRequest(queueUrl) .withVisibilityTimeout(10) val result = sqs.receiveMessage(request) result.messages.forEach { msg !" handleCarTelemetry(msg.body.fromJson()) sqs.deleteMessage(queueUrl, msg.receiptHandle) } } } private fun handleCarTelemetry(event: CarEnteredEvent) { println("Car ${event.licensePlate} at ${event.time}") }
  14. • Developer experience! " • Local simulation # $ •

    Auto-generate least privilege IAM policies %& • Built for the cloud from the start (it's still the start ')
  15. Spread your wings class Backend { api: cloud.Api; pub storage:

    cloud.Bucket; init() { this.api = new cloud.Api(); this.storage = new cloud.Bucket(); this.api.put("/car/entered", inflight (request) => { log("Received ${request.body}"); let body = Json.tryParse(request.body); let event: events.CarEnteredEvent = events.CarEnteredEvent.fromJson(body); let fileKey = "${event.licensePlate}.json"; let records: Json? = this.storage.tryGetJson(fileKey); let addRecord = (records: Json?, toAdd: Json): Json => { if records? { let newRecords = Json.deepCopyMut(records); let count: num = newRecords.get("length").asNum(); log("Adding to ${count} records"); newRecords.setAt(count, toAdd); return Json.deepCopy(newRecords); } else { log("Adding first record"); return Json [ event ]; } }; let fileBody = addRecord(records, Json event); this.storage.putJson(fileKey, fileBody); return cloud.ApiResponse { status: 200, headers: { "Content-Type" => "text/plain" }, body: "Ok" }; }); this.api.get("/license-plates/unique", inflight (request) => { let files = this.storage.list(); return cloud.ApiResponse { status: 200, headers: { "Content-Type" => "application/json" }, body: Json.stringify(Json { "uniquePlateCount": files.length }) }; }); } pub getApiUrl(): str { return this.api.url; } }
  16. Go Multi-Cloud? • You require [extreme] redundancy and reliability ,

    • You want to avoid vendor lock-in • It happened to you • You want to minimize costs you have lock-in anyway ! let each org unit stay on the cloud they're on ☁ ☁ operating multiple clouds is not free .
  17. Infra code vs Domain code @Path("/car") @Produces(MediaType.APPLICATION_JSON) class CarTelemetryApi( private

    val eventBus: EventBus ) { @POST @Path("/entered") fun receiveEvent(event: CarEnteredEvent): Response { eventBus.publish(event) return Response.noContent().build() } } !!" class SQSEventBus( private val sqs: SqsClient, @ConfigProperty(name = "queue.url") private val queueUrl: String, ) : EventBus { override fun publish(event: DomainEvent) { sqs.sendMessage { it.queueUrl(queueUrl).messageBody(event.toJson()) } } } !!" @ApplicationScoped class SQSMessageListener( private val sqs: SqsClient, @ConfigProperty(name = "queue.url") private val queueUrl: String, private val eventHandler: (event: DomainEvent) !# Unit ) { @PostConstruct fun handleQueueMessages() { while (true) { val messages = sqs.receiveMessage { it.queueUrl(queueUrl).maxNumberOfMessages(10) }.messages() messages.forEach { message !" eventHandler(message.body().fromJson()) sqs.deleteMessage { it.queueUrl(queueUrl).receiptHandle(message.receiptHandle()) } } } } } interface EventBus { fun publish(event: DomainEvent) } !!" sealed interface Command data class SignalFraudAttemptCommand( val licensePlate: LicensePlate, val time: Instant, val reason: String, ) : Command !!" sealed interface DomainEvent data class CarEnteredEvent( val time: Instant, val licensePlate: LicensePlate, ) : DomainEvent !!" class FraudDetectionPolicy( private val carpark: CarPark ) { fun whenCarEntered(event: CarEnteredEvent): Command? { if (carpark.alreadyEntered(event.licensePlate)) { return SignalFraudAttemptCommand( event.licensePlate, event.time, "Car with this license plate already entered the car park" ) } return null } }
  18. But should you? Doing Multi-Cloud the Easy Way Do we

    have tools that make Multi-Cloud easy?
  19. But should you? Doing Multi-Cloud the Easy Way Maximize adding

    value now, while reducing the cost of being wrong.