<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fargate on Digi Hunch</title><link>https://static.digihunch.com/tag/fargate/</link><description>Recent content in Fargate on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 02 Apr 2025 12:51:36 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/fargate/index.xml" rel="self" type="application/rss+xml"/><item><title>EKS impression</title><link>https://static.digihunch.com/2022/12/eks-impression/</link><pubDate>Fri, 23 Dec 2022 18:18:19 -0400</pubDate><guid>https://static.digihunch.com/2022/12/eks-impression/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/eks-impression-feature.webp" alt="Featured image of post EKS impression" /&gt;&lt;p class="wp-block-paragraph"&gt;I&amp;#8217;ve worked on a few &lt;a href="https://static.digihunch.com/2021/12/aks-troubleshooting-lessons-learned/"&gt;AKS projects&lt;/a&gt; previously. Since I joined AWS I wanted to put aside some time to check out EKS (Elastic Kubernetes Service). Here in this post, I put down my first impression on EKS, and also share my Terraform template in &lt;a href="https://github.com/digihunch/cloudkube"&gt;cloudkube&lt;/a&gt; project to create an EKS cluster.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Similar to AKS, EKS exposes API endpoint and the control plane components are hidden from AWS users. When creating EKS cluster it does not create the underlying VPC and subnets. Therefore, you have create an existing VPC and at least two subnets ahead of time, and specify them during EKS creation. Bear in mind that there is a &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html"&gt;list of requirement&lt;/a&gt; for the VPC and subnets.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the cluster, the CNI that EKS officially supports is Amazon VPC CNI plugin. It is available as an add-on. Similar to Azure CNI, each Pod gets its own IP address. In addition, EKS supports other &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/alternate-cni-plugins.html"&gt;compatible CNI plugins&lt;/a&gt; such as Calico, Cilium, Weave Net and Antrea.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-computing-nodes-in-eks"&gt;Computing Nodes in EKS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are three modes to address computing capacity: self-managed nodes, EKS managed node groups and AWS Fargate. The documentation has a &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-compute.html"&gt;comparison table&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With self-managed nodes, users create EC2 instances separately and then register them to the control plane. The instances must use the same IAM role and AMI. You can use Auto Scaling groups of &lt;a href="https://aws.amazon.com/bottlerocket/"&gt;Bottlerocket&lt;/a&gt; (AWS-sponsored purpose-built Linux distro for container host) nodes. The self-managed node option is mostly for AWS outpost customers who bring in their own computing capacity from data centre.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If you provision computing capacity from AWS, it makes sense to assign EKS managed node groups when creating EKS cluster. We can turn on &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/autoscaling.html"&gt;Cluster Autoscaler&lt;/a&gt;, a Kubernetes construct to manage the auto scaling of node groups. Sometimes we want to have more than one node groups. For example, to build a multi-architecture cluster, we need one node group with amd64 nodes and the other with arm64 nodes (e.g. instances with &lt;a href="https://aws.amazon.com/ec2/graviton/"&gt;Graviton&lt;/a&gt; processor). In general, arm-based CPU delivers better performance with less power consumption and the industry is slowly moving towards more arm-based CPU architecture.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Fargate is what I call managed computing service for EKS. With Fargate you do not need to tweak Cluster Autoscaler to self-manage computing capacity. The Fargate documentation has a long list of &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/fargate.html"&gt;considerations&lt;/a&gt;. For example, Pods must match a Fargate profile (&lt;a href="https://github.com/digihunch/real-quicK-cluster/blob/main/eks/cluster-fargate.yaml"&gt;here&lt;/a&gt;&amp;#8216;s an example) at the time that they&amp;#8217;re scheduled to run on Fargate. So we need to build Fargate profile and Pod labelling properly. Also, Fargate does not support DaemonSet. Another big consideration is that Fargate does not support non-VPC CNI. In my opinion these are pretty significant limitations. Many workloads (system-level or application-level) would need Daemonset (e.g. kube-proxy, some CNI or CSI drivers, &lt;a href="https://www.dynatrace.com/support/help/setup-and-configuration/setup-on-container-platforms/kubernetes/get-started-with-kubernetes-monitoring/set-up-k8s-monitoring-daemonset"&gt;Dynatrace&lt;/a&gt; monitoring). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The pro of Fargate is the serverless computing model. The construct of a Fargate profile isn&amp;#8217;t complicated. You just specify subnets, namespace and labels. However, the downside is the long list of considerations. Some teams may consider these restrictions too much. The other overhead is the need to manage Fargate profile to ensure all Pods are scheduled somewhere. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To me, using Fargate alone impairs portability of workload. The good thing is that Fargate and Managed Node Group are not mutually exclusive on a cluster. In most cases, we can go partially serverless, and reap the benefits of both of them. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Node AutoScaling&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For workloads that don&amp;#8217;t have a matching Fargate profile, we have to figure out node autoscaling ourselves. I touched on Cluster Autoscaler in &amp;#8220;&lt;a href="https://static.digihunch.com/2022/03/autoscaling-in-kubernetes-from-metric-based-to-event-driven/"&gt;Autoscaling on Kubernetes Platform&lt;/a&gt;&amp;#8220;. CA works on AWS as well and is triggered upon a Pod coming to &lt;em&gt;unschedulable&lt;/em&gt; status in Scheduler. There is some limitations though. For example, CA interacts with Autoscaling Group (instead of EC2 instances directly). When it determines it&amp;#8217;s time to scale up, it bumps up the desired capacity by one at a time in the Autoscaling group. The configurations in Autoscaling group may also be at play and CA do not have direct control. For example, the &amp;#8220;&lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-scaling-cooldowns.html"&gt;scaling cooldown&lt;/a&gt;&amp;#8220;. The pool of nodes is homogenous as per the pre-configured launch template and CA has no control. If a Pod requires a different type of node (e.g. ARM64 CPU, spot instance, etc), then we&amp;#8217;d first have to create a node group with the desired node type. Moreover, in the worst cases, one-at-a-time scale-up does not meet the increase of demand driven by Pod increases, causing nuances such as racing conditions. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Because the Cluster Autoscaler doesn&amp;#8217;t really deal with the nodes themselves, this kind of integration is clunky and slow. Nearly half of Kubernetes customers on AWS report that configuring cluster auto scaling using the Kubernetes Cluster Autoscaler is challenging and restrictive, according to &lt;a href="https://aws.amazon.com/blogs/aws/introducing-karpenter-an-open-source-high-performance-kubernetes-cluster-autoscaler/"&gt;this&lt;/a&gt; blog post. As a result, AWS launched an open-source cluster autoscaler project, &lt;a href="https://karpenter.sh/"&gt;Karpenter&lt;/a&gt;. Karpenter first only supported EKS but now the support includes other CSPs. For EKS, Karpenter directly interact with different types of EC2 instances.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Karpenter makes node scaling work in a more cloud-native manner. In the presence of unschedulable Pods, Karpenter &lt;span style="text-decoration: underline" class="underline"&gt;bypasses the Kubernetes scheduler&lt;/span&gt; and works directly with the Cloud provider, to launch the minimal compute resources needed to fit those Pods and immediately binds the Pods to the newly provisioned Nodes without waiting for scheduler. As Pods are removed or rescheduled to other nodes, Karpenter looks for opportunities to terminate under-utilized nodes. Karpender defines a CR called Provisioner to specify node provisioning configuration, such as instance size, zone, CPU architecture, etc. It is a manifest that describes a node group so the node scaler is aware of all the available node types. You can have multiple Provisioners for different needs, just like node groups. The Provisioner CR can also set TTL for empty Nodes, such that once a Node has no pods other than DaemonSet, Karpenter will terminate the Node on TTL expiry.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Karpenter&amp;#8217;s idea is similar to the idea of AutoPilot cluster in GKE. The new EKS workshop has an &lt;a href="https://www.eksworkshop.com/docs/autoscaling/compute/karpenter/"&gt;section&lt;/a&gt; on how to set up CA and Karpenter in practice.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-identity-management-for-eks"&gt;Identity Management for EKS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For IAM, we need to be concerned with three aspects. The management traffic to the cloud service, the management traffic for Kubernetes cluster and business traffic. &lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-white-background-color has-background has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Traffic type&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;AWS&lt;/th&gt;&lt;th&gt;Azure&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;I. Cloud Service Endpoint (Management Traffic for Cloud Service)&lt;/td&gt;&lt;td&gt;AWS IAM identity&lt;/td&gt;&lt;td&gt;Azure RBAC&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;II. Kubernetes API (Management Traffic for K8s Cluster)&lt;/td&gt;&lt;td&gt;IAM mapping or OIDC&lt;/td&gt;&lt;td&gt;Azure RBAC (implementation of OIDC)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;III. Business traffic&lt;/td&gt;&lt;td&gt;Up to Kubernetes Ingress&lt;/td&gt;&lt;td&gt;Up to Kubernetes Ingress&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For business traffic (type III), it is all up to the Ingress. I&amp;#8217;ve written another article on &lt;a href="https://medium.com/slalom-build/managing-ingress-traffic-on-kubernetes-platforms-ebd537cdfb46"&gt;managing ingress traffic on Kubernetes platforms&lt;/a&gt;. We interact with cloud service endpoint (type II) with either AWS CLI or Terraform, to create any object, including resources needed for a cluster. This is generally how we work with cloud service, not specific to Kubernetes. Usually the IAM identity assumes another IAM role, which empowers it with a lot of permissions.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For access to Kubernetes API (type III), EKS supports OIDC and IAM mapping. AWS documentation refers to this as &amp;#8220;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/cluster-auth.html"&gt;Cluster Authentication&lt;/a&gt;&amp;#8220;. There is one special scenario where your identity for type II access inherits your identity for type I access. As the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html"&gt;document&lt;/a&gt; puts:&lt;/p&gt;&#10;&lt;blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When you create an Amazon EKS cluster, the AWS Identity and Access Management (IAM) entity user or role, such as a&amp;nbsp;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers.html"&gt;federated user&lt;/a&gt;&amp;nbsp;that creates the cluster, is automatically granted&amp;nbsp;&lt;code&gt;system:masters&lt;/code&gt;&amp;nbsp;permissions in the cluster&amp;#8217;s role-based access control (RBAC) configuration in the Amazon EKS control plane. This IAM entity doesn&amp;#8217;t appear in any visible configuration, so make sure to keep track of which IAM entity originally created the cluster.&amp;nbsp;&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This special scenario (I call it the &amp;#8220;&lt;strong&gt;implicit master&lt;/strong&gt; &lt;strong&gt;user&lt;/strong&gt;&amp;#8220;) allows us to perform critical activities on the cluster, such as creating IAM mapping, or OIDC configuration. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The above addressed how AWS resource access Kubernetes resource. On the other hand, to address how a Kubernetes resource access AWS resources, we need IRSA (&lt;a href="https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-enable-IAM.html"&gt;IAM Roles for Service Account&lt;/a&gt;). We have a service account in Kubernetes and map it to an IAM role.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;AppMesh&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://aws.amazon.com/blogs/compute/introducing-aws-app-mesh-service-mesh-for-microservices-on-aws/"&gt;AppMesh&lt;/a&gt; is AWS&amp;#8217; Envoy based service-mesh offering supporting Kubernetes cluster, ECS service and even EC2 instance. AppMesh&amp;#8217;s control plane is a managed AWS service, with a &lt;a href="https://aws.github.io/aws-app-mesh-controller-for-k8s/"&gt;controller&lt;/a&gt; running on the Kubernetes cluster. To install AppMesh on the cluster:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;On the EKS cluster, install AppMesh Controller using Helm&lt;/li&gt;&#10;&lt;li&gt;Associate the cluster with IAM OIDC provider&lt;/li&gt;&#10;&lt;li&gt;Create an IAM role for the appmesh-controller service account&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;After these steps, you can create a mesh using CloudFormation, Terraform, etc. The data plane (Envoy proxy) can run on Kubernetes (as sidecar). Traffic between control plane and data plane can go through private link (Interface VPC &lt;a href="https://docs.aws.amazon.com/app-mesh/latest/userguide/infrastructure-security.html"&gt;endpoint&lt;/a&gt;) for added security. Like Istio, AppMesh enables mTLS. For observability, you can export Envoy metrics with Prometheus. Coupled with XRay, AppMesh also supports distributed tracing.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="832" height="354" src="https://static.digihunch.com/wp-content/uploads/2022/12/appmesh-virtualgateway.webp" alt="" class="wp-image-12883" srcset="https://static.digihunch.com/wp-content/uploads/2022/12/appmesh-virtualgateway.webp 832w, https://static.digihunch.com/wp-content/uploads/2022/12/appmesh-virtualgateway-300x128.webp 300w, https://static.digihunch.com/wp-content/uploads/2022/12/appmesh-virtualgateway-768x327.webp 768w" sizes="auto, (max-width: 832px) 100vw, 832px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AppMesh uses a different set of CRDs than Istio. Key CRDs are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Mesh&lt;/strong&gt;: represents an entire service mesh. At mesh level you can configure Egress filter (to allow or deny external traffic) and set IP version (v4 vs v6)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VirtualGateway&lt;/strong&gt;: a CRD that represents an &lt;a href="https://aws.amazon.com/blogs/containers/introducing-ingress-support-in-aws-app-mesh/"&gt;Ingress&lt;/a&gt; in to the Mesh. A virtual gateway allows resources that are outside of your mesh to communicate to resources that are inside of your mesh. A virtual gateway references Envoy proxy deployment by podSelector. It references GatewayRoutes by namespaceSelector, and optionally gatewayRouteSelector. You also specify listeners in the manifest to reference Envoy proxy Service (LoadBalancer Type).&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;GatewayRoute&lt;/strong&gt;: A gateway route is attached to a virtual gateway and routes traffic to an existing virtual service. If a route matches a request, it can distribute traffic to a target virtual service. In the manifest, you specify a list of httpRoute, each with matching condition and action. In the action section you can specify virtualService as target.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VirtualService&lt;/strong&gt;: an abstraction of a real service provided by a virtual node directly or indirectly by means of a virtual router. Dependent services call your virtual service by its virtualServiceName, and those requests are routed to the VirtualNode or VirtualRouter that is specified as the provider for the VirtualService.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VirtualRouter&lt;/strong&gt;: Virtual routers handle traffic for virtual services. In a virtual router manifest, you can define Route to direct incoming requests to virtual nodes as target.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VirtualNode&lt;/strong&gt;: A virtual node acts as a logical pointer to a particular task group (i.e. ECS service, Kubernetes deployment). It represent a Service in the AppMesh. In the manifest, you reference Pods by podSelector, specify listeners for any inbound traffic that your virtual node expects, and specify serviceDiscovery for your task group.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can configure those Custom Resources using YAML manifests (and check the &lt;a href="https://docs.aws.amazon.com/app-mesh/latest/APIReference/Welcome.html"&gt;API reference&lt;/a&gt; a lot). Alternatively, you can configure them from AWS CLI or AWS console. The console will help you visualize what can be configured. For further details on how these CRs play together, there is a &lt;a href="https://www.appmeshworkshop.com/"&gt;workshop&lt;/a&gt; for AppMesh.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;EKS cluster using Terraform&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Officially, there is an &lt;a href="https://github.com/aws-ia/terraform-aws-eks-blueprints"&gt;EKS blueprint&lt;/a&gt; project for provisioning EKS cluster in Terraform.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I also keep my own Terraform code in the AWS directory of &lt;a href="https://github.com/digihunch/cloudkube"&gt;cloudkube&lt;/a&gt; project. It works out to be a little more complex than my Terraform template to create Azure Kubernetes Cluster (Azure directory). Because I had to create Cognito resources with initial credential to allow users to connect to cluster without using the implicit master account.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Below is the diagram of the processes.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="776" height="496" src="https://static.digihunch.com/wp-content/uploads/2022/12/eks-tf-mod.webp" alt="" class="wp-image-12881" srcset="https://static.digihunch.com/wp-content/uploads/2022/12/eks-tf-mod.webp 776w, https://static.digihunch.com/wp-content/uploads/2022/12/eks-tf-mod-300x192.webp 300w, https://static.digihunch.com/wp-content/uploads/2022/12/eks-tf-mod-768x491.webp 768w" sizes="auto, (max-width: 776px) 100vw, 776px" /&gt;&lt;figcaption class="wp-element-caption"&gt;Create EKS cluster with Terraform module&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The template configures kubectl access on a Bastion host, which assumed the same role that our IAM user uses to create the Kubernetes cluster. Therefore, the IAM role is the master identity. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that the IAM user (power-user) has very powerful permissions. Usually it is ideal to assign lots of permission to IAM Roles (temporary credential) instead of IAM user (long-term credential). So the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html"&gt;role chaining&lt;/a&gt; would look like:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;The IAM user that Terraform uses has no permission other than assuming a &amp;#8220;PowerUser&amp;#8221; role&lt;/li&gt;&#10;&lt;li&gt;The PowerUser role trusts the IAM user. It also has the permission to assume the &amp;#8220;EKS-Manager&amp;#8221; role&lt;/li&gt;&#10;&lt;li&gt;The EKS-Manager role trusts PowerUser&amp;#8217;s role session.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;However, the role chaining scenario above is not currently supported in &lt;a href="https://github.com/hashicorp/terraform-provider-aws/issues/22728"&gt;Terraform&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I use a Bastion host because the cluster endpoint is on private subnet. The bastion host is on a public subnet. However, if we do not like public subnet and public IP, we can place the bastion host on a private subnet, and use SSM system manager agent with &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/systems-manager-ssh-vpc-resources/"&gt;SSH tunnel plugin &lt;/a&gt;to have SSH access to private bastion host.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-summary"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I first came across &lt;a href="https://medium.com/@andreidascalu/the-awfulness-of-aws-eks-d7700c1eccdc"&gt;this&lt;/a&gt; article about EKS and its awfulness and then decided to check out EKS. I&amp;#8217;m not sure all points are still valid but it&amp;#8217;s generally real-life experiences. There are also many peripheral services, such as AMP (AWS Managed Prometheus), AMG (AWS Managed Grafana), ADOT (AWS Distro for Open Telemetry), AppMesh (Another &lt;a href="https://www.appmeshworkshop.com/introduction/appmesh_components/"&gt;Envoy-based Service Mesh&lt;/a&gt;, &lt;a href="https://vedcraft.com/architecture/aws-appmesh-vs-istio-comparison-of-service-mesh/"&gt;easier to manage than Istio&lt;/a&gt; but less Powerful), with a lot to explore.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/12/landing-zone-in-aws/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Landing Zone in AWS – An Introduction&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2023/01/optimize-cpu-and-memory-for-kubernetes-pods/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Optimize CPU and Memory for Kubernetes Pod&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>AWS serverless services and developer tools</title><link>https://static.digihunch.com/2022/11/aws-serverless-services-and-developer-tools/</link><pubDate>Wed, 09 Nov 2022 12:19:00 -0400</pubDate><guid>https://static.digihunch.com/2022/11/aws-serverless-services-and-developer-tools/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-server-less-devtools.webp" alt="Featured image of post AWS serverless services and developer tools" /&gt;&lt;p class="wp-block-paragraph"&gt;As &lt;a href="https://static.digihunch.com/2022/10/computing-from-paas-to-serverless/"&gt;discussed&lt;/a&gt;, serverless simply means cloud services that delegate autoscaling management to cloud platform. In my mind, the word &amp;#8220;serverless&amp;#8221; translates into &amp;#8220;managed autoscaling&amp;#8221;. As long as a service&amp;#8217;s capacity is managed automatically, we can consider it as serverless. Given that capacity scaling accounts for a good amount of work in IT operation, moving to serverless significantly reduces operation overhead. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Unlike containers, the serverless ecosystem lacks standard. Since &lt;a href="https://serverlessland.com/"&gt;AWS&lt;/a&gt; is leading the charge in this field, let&amp;#8217;s take a look at its offerings.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Lambda Function&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lambda functions have triggers. We can configure a trigger from an AWS service, or even a non-AWS service which supports AWS event bridge, to invoke Lambda function. Based on the trigger (e.g. SQS, S3, DynamoDB), you then specify event source mapping. For example, if trigger is SQS, you need to specify the queue name, batch size and batch window in event source mapping. If trigger is S3, the event source mapping needs to specify bucket, S3 action, etc. Event source mappings vary significantly among trigger types.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Depending on the trigger, a Lambda function may be invoked in one of the two ways:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-cyan-bluish-gray-background-color has-background"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-sync.html" target="_blank" rel="noreferrer noopener"&gt;Synchronous&lt;/a&gt; invocation&lt;/th&gt;&lt;th&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#async-overview" target="_blank" rel="noreferrer noopener"&gt;Asynchronous&lt;/a&gt; invocation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Summary&lt;/td&gt;&lt;td&gt;Requestor fires request and waits until it receives response before closing connection.&lt;/td&gt;&lt;td&gt;Lambda places triggering event in a queue and immediately returns a success code (202). Then a separate process reads events off the queue and sends them to your Lambda function. When the function returns a success response or exits without throwing an error, Lambda sends a record of the invocation to an EventBridge event bus.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pros&lt;/td&gt;&lt;td&gt;Requestor get invocation result as soon as function run is complete&lt;/td&gt;&lt;td&gt;The queue decouples the request and invocation.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cons&lt;/td&gt;&lt;td&gt;When load is high the function requires higher capacity for concurrency&lt;/td&gt;&lt;td&gt;Involves more parties at play and can be quite complex to troubleshoot.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/operatorguide/invocation-modes.html" target="_blank" rel="noreferrer noopener"&gt;Here&lt;/a&gt; is a chart with the triggers that support each invocation mode. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Real-life applications often need to include libraries and dependencies that requires language-specific steps. For example, NodeJS applications need &lt;a href="https://aws.amazon.com/blogs/compute/optimizing-node-js-dependencies-in-aws-lambda/"&gt;bundling&lt;/a&gt; (often using Webpack or esbuild). We can use &lt;a href="https://aws.amazon.com/blogs/compute/using-lambda-layers-to-simplify-your-development-process/"&gt;Lambda layers&lt;/a&gt; to simplify the management. The additional libraries often need to be packaged in S3 bucket or as container image.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lambda functions are subject to &lt;a href="https://aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/"&gt;cold start&lt;/a&gt; to &lt;a href="https://betterprogramming.pub/lets-stop-talking-about-serverless-cold-starts-38e4c1fda963"&gt;cope with&lt;/a&gt;. When a lot of invocations occur about the same time, the order of executions might be different than the order of upstream events that invokes the function. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-api-gateway"&gt;API Gateway&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS API Gateway is an &lt;a href="https://microservices.io/patterns/apigateway.html"&gt;API gateway&lt;/a&gt; implementation for REST and WebSocket APIs. It couples with &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/services-apigateway.html"&gt;Lambda&lt;/a&gt; in the classic &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/serverless-multi-tier-architectures-api-gateway-lambda/welcome.html"&gt;multi-tier serverless&lt;/a&gt; architecture pattern. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this classic pattern Lambda function often need to work with a database (e.g. DynamoDB etc), to perform &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete"&gt;CRUD operations&lt;/a&gt; and other custom business logics. The CRUD operations are so commonplace that it makes sense to use mapping template to configure CRUD operation instead of writing similar set of functions for each new data model. API Gateway supports such a &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/models-mappings.html"&gt;mapping template&lt;/a&gt; called &lt;a href="https://velocity.apache.org/engine/devel/vtl-reference.html"&gt;Velocity Template Language&lt;/a&gt; (VTL), a technology from Apache &lt;a href="https://velocity.apache.org/"&gt;Velocity&lt;/a&gt; Project.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;API Gateway integrate with many other AWS services. Here are the available integration types:&lt;/p&gt;&#10;&lt;table id="tablepress-20" class="tablepress tablepress-id-20 tbody-has-connected-cells"&gt;&#10;&lt;thead&gt;&#10;&lt;tr class="row-1"&gt;&#10;&#9;&lt;th class="column-1"&gt;Integration Type&lt;/th&gt;&lt;th class="column-2"&gt;Description&lt;/th&gt;&lt;th class="column-3"&gt;Integration Mode&lt;/th&gt;&lt;th class="column-4"&gt;How it works&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody class="row-striping row-hover"&gt;&#10;&lt;tr class="row-2"&gt;&#10;&#9;&lt;td rowspan="2" class="column-1"&gt;AWS integration&lt;/td&gt;&lt;td rowspan="2" class="column-2"&gt;connects gateway to an AWS service action as the end point.&lt;/td&gt;&lt;td class="column-3"&gt;AWS_PROXY&lt;/td&gt;&lt;td class="column-4"&gt;this mode only supports only one action with one service: the function invoking action for Lambda service. Therefore it is available only for Lambda integration and no other AWS services. For that reason, it is also known as Lambda proxy integration. This mode is recommended for Lambda integration and is the default mode for LambdaIntegrationOption CDK construct. It connects a method (PUT, GET, etc) to a Lambda function and pass along the request on the way in, and the response on the way out. You do not set integration request or integration response. Even if you do, there’s no effect. This “pass-along” mode is easier to understand and configure. &lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-3"&gt;&#10;&#9;&lt;td class="column-3"&gt;AWS&lt;/td&gt;&lt;td class="column-4"&gt;this mode connects an API method to a broad range of supported AWS service action. Function invoking for Lambda service is a common example but not the only service action supported in this mode. When used in Lambda integration, it is also referred to as “Lambda custom integration”, or “normal (request/response mapping) integration”. This mode is good for advanced use cases (e.g. header modification) but involves more management effort. You have to control the mapping between method request and integration request, and between integration response and method response. &lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-4"&gt;&#10;&#9;&lt;td rowspan="2" class="column-1"&gt;HTTP integration&lt;/td&gt;&lt;td rowspan="2" class="column-2"&gt;for generic HTTP service endpoint&lt;/td&gt;&lt;td class="column-3"&gt;HTTP_PROXY&lt;/td&gt;&lt;td class="column-4"&gt;the pass-along mode for upstream HTTP endpoint&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-5"&gt;&#10;&#9;&lt;td class="column-3"&gt;HTTP&lt;/td&gt;&lt;td class="column-4"&gt;the request/response mapping mode for upstream HTTP endpoint&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-6"&gt;&#10;&#9;&lt;td class="column-1"&gt;MOCK integration &lt;/td&gt;&lt;td class="column-2"&gt;the API gateway itself serves as the endpoint.&lt;/td&gt;&lt;td class="column-3"&gt;MOCK&lt;/td&gt;&lt;td class="column-4"&gt;the API gateway itself acts endpoint without an upstream. One example use case is to return CORS-related headers upon a pre-flight OPTIONS query.&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;!-- #tablepress-20 from cache --&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The table above is a summary of API Gateway integration types as covered &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-integration-types.html"&gt;here&lt;/a&gt;. In the AWS context, proxy mode suggests that the request is not being morphed (transformed). In non-proxy mode, request or response may be modified on their ways in or out.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For API gateway to invoke lambda function, synchronous invocation is used by default. You can also configure API gateway to invoke Lambda function &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-integration-async.html" target="_blank" rel="noreferrer noopener"&gt;asynchronously&lt;/a&gt; by using headers.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As with other API gateway implementations, AWS API Gateway can also connects to an authorizer (either another Lambda function or Cognito service) in order to authorize the incoming request.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;AppSync&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In a previous post, I discussed &lt;a href="https://static.digihunch.com/2022/10/graphql-and-grpc/"&gt;GraphQL&lt;/a&gt; as a modern and efficient alternative to REST API. &lt;a href="https://aws.amazon.com/appsync/"&gt;AppSync&lt;/a&gt; to GraphQL is the same as API Gateway to REST API. One of the advantages that GraphQL has over REST API is more information in the response. Oftentimes, we use a proxy that supports GraphQL in front of REST API service. AppSync can act as such proxy. I think of it as a managed &lt;a href="https://www.apollographql.com/docs/intro/platform"&gt;Apollo&lt;/a&gt; since they play the the role in the architecture. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another benefit of GraphQL is the support of subscription, obviating WebSocket configuration. AppSync supports pub/sub API for real-time experience. Client application can get near real-time update as the data on the server is changed.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can configure AppSync to connect to different data sources to formulate GraphQL response. The data source can be an HTTP endpoint, a Lambda function, a database (Relational or DynamoDB), or OpenSearch. &lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="408" src="https://static.digihunch.com/wp-content/uploads/2022/12/appsync-1024x408.png" alt="" class="wp-image-7653" srcset="https://static.digihunch.com/wp-content/uploads/2022/12/appsync-1024x408.png 1024w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-300x119.png 300w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-768x306.png 768w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-1536x612.png 1536w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-2048x816.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;figcaption class="wp-element-caption"&gt;App Sync&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Between data source and the request, AppSync uses resolver to convert GraphQL payload to the underlying protocols and executes if the caller is authorized to invoke it. Resolvers are comprised of request and response mapping templates, which contain transformation and execution logic. AppSync also uses VTL as the mapping template for resolvers.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Messaging Services&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Messaging services have three patterns: queues, pub/sub, and event buses. In AWS, the corresponding services are SQS, SNS and EventBridge. Here is a good &lt;a href="https://aws.amazon.com/blogs/compute/choosing-between-messaging-services-for-serverless-applications/"&gt;post&lt;/a&gt; about how to choose among them.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Queues are temporary storage to decouple the source and destination systems. The expectation is that the actions in response to the message can be delayed. If that is not the case and the response needs to be immediate, that is by definition an event-driven pattern. A common solution is to have the AWS service invoke Lambda function. If that is not supported, we can use SNS as an intermediary. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SNS is for simple event-driven pattern. In a more complicated event-driven architecture, we often need an event bus to route events in certain ways. We also need to support various &lt;a href="https://aws.amazon.com/eventbridge/integrations/"&gt;event sources&lt;/a&gt; by different software providers. Moreover, we want the capability to register our own event schema. These are the scenarios where EventBridge can help.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Developer tools&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In application development with serverless stack, the line between application and infrastructure is somewhat blurred. Developers often find themselves making repeated configuration on cloud resources while writing application code. For example, to test Python code (application), developer has to upload the code to S3, create Lambda function referencing the code, etc. This would require too much work with AWS CLI, or CloudFormation. The AWS &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html"&gt;SAM&lt;/a&gt; (AWS Serverless Application Model) is a better utility for serverless development workflow.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SAM comes with its own CLI and developers can feed it with template that interacts with a number of serverless &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-resources-and-properties.html"&gt;resources&lt;/a&gt; (e.g. API, SimpleTable, Function, etc). I view SAM as one layer of abstraction on top of CloudFormation that handles some resources in serverless stack. It saves developers from re-writing resources in CloudFormation templates and keeping them consistent, which would have been tedious. Once you deployed your application using SAM, it will appear as a Lambda Application in the console.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SAM templates are also declarative. It is simple but limited in feature. AWS CDK is also a powerful utility that works with general purpose programming language for IaC and interacts with all AWS resources. It is very powerful for building serverless applications. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;AWS Amplify&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We have CDK, SAM and CloudFormation but we still have to ensure integration between those resources and our applications. For example, when creating a S3 buckets, they have to get the endpoint and reference it in the application code. So is Cognito. As a result, developers still have to spend time on resource integration. They still can&amp;#8217;t focus on business logic. We need a tool that can make opinionated configuration of cloud resources and automatically reference them from the application code. This is the purpose of AWS Amplify.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amplify not only help application developers create backend resources with opinionated configurations. It also provides libraries for the application to use and connect to those resources seamlessly. Developers will need to include Amplify libraries in the application code. To create cloud resources, they can use Amplify &lt;a href="https://docs.amplify.aws/cli/"&gt;CLI&lt;/a&gt; or &lt;a href="https://docs.amplify.aws/console/uibuilder/figmatocode/#step-1-set-up-figma-file"&gt;Studio&lt;/a&gt; (a web portal from AWS console). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amplify natively supports a number of serverless resources such as API (using API gateway or AppSync), Storage (S3 and CloudFront), Lambda function, Cognito, etc. Developer may use Amplify CLI command to create such supported resources. Amplify will prompt some guiding questions in order to configure them correctly. In addition to the natively supported resources, developers can also create custom resources. They have to declare those custom resources with CloudFormation or CDK. I came across &lt;a href="https://github.com/aws-samples/amazon-location-samples/tree/main/maplibre-js-react-iot-asset-tracking"&gt;this&lt;/a&gt; project as a good illustration of how Amplify works. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Amplify Studio can save developers from using Amplify CLI commands. It also can integrate with &lt;a href="https://en.wikipedia.org/wiki/Figma_(software)"&gt;Figma&lt;/a&gt;, providing developers with a framework for &lt;a href="https://aws.amazon.com/blogs/mobile/aws-amplify-studio-figma-to-fullstack-react-app-with-minimal-programming/"&gt;frontend development.&lt;/a&gt; However, in my experience, it is still &lt;a href="https://github.com/aws-amplify/amplify-ui/issues"&gt;glitchy&lt;/a&gt;. For now I stick to Amplify CLI.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amplify also supports &lt;a href="https://docs.aws.amazon.com/amplify/latest/userguide/getting-started.html"&gt;hosting&lt;/a&gt; capability, providing users with opinionated and customizable CI/CD pipeline configuration.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;How about &amp;#8220;clientless&amp;#8221;&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lambda function can also run client-side logics. System administrators have to create lots of client-side scripting. While Lambda functions can encapsulate those logics, we&amp;#8217;d still need a script orchestrator to invoke those functions. AWS &lt;a href="https://aws.amazon.com/step-functions/"&gt;Step Function&lt;/a&gt; comes to rescue. It was even regarded as the &lt;a href="https://itnext.io/why-step-functions-is-the-best-aws-service-you-are-not-using-4f3c133d7d0d"&gt;most under-utilized service&lt;/a&gt;. As the author states, a state machine (as design pattern) is simply a flow of actions with decision making logics.&amp;nbsp;AWS Step function helps you groom the logic flow of existing actions with &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html" target="_blank" rel="noreferrer noopener"&gt;Amazon States Language&lt;/a&gt;. There are standard and express workflows. Each step is a state. A state can be of several different types, such as Choice, Task, Succeed, Fail, End, Map, Wait, Parallel. The task can be a Lambda function, and even AWS API calls. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS Step function integrate with Lambda functions. It is typically used for patterns with long process and the need to orchestrate the execution of several Lambda functions. For specific use cases, look at these &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/create-sample-projects.html" target="_blank" rel="noreferrer noopener"&gt;sample projects&lt;/a&gt;. For example, a network professional needs to run a lot of connectivity testing, reusing the same Python script but run it from different subnets. We need to create a Lambda function for commands like &amp;#8220;nc -vz&amp;#8221; then &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc-endpoints.html"&gt;invoke the lambda function from VPC&lt;/a&gt;, multiple times from different VPCs. We should use step function to drive this. It works like a Makefile on Linux, without requiring your own computer to run.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS Step function also integrates with &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/connect-supported-services.html" target="_blank" rel="noreferrer noopener"&gt;other AWS services&lt;/a&gt;, such as SNS, SQS, Dynamo, Batch, Glue, EMR, EKS, API gateway, event bridge.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Whenever we need to create a script, involving custom actions, or AWS API calls, we should consider using AWS step function to organize the actions. The benefits are: it saves you a laptop or bastion host (&amp;#8220;client-less&amp;#8221;), many ways to invoke them (not just cron&amp;#8221;). &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this post, we started with some serverless services in AWS. For server-side application, we can use API Gateway to invoke Lambda function. For client-side, we can use step function to invoke Lambda function. We then discussed some tools to speed up application development in serverless pattern. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS categorizes both Amplify and AppSync under Front-end Mobile. Amplify does not represent any computing resources in AWS cloud. It is a library and CLI tools to enhance developer experience. AppSync on the other hand is a cloud computing resource acting as GraphQL API for mobile or web application. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/10/computing-from-paas-to-serverless/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Computing services: from PaaS to Serverless&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/11/key-mapping-on-external-pc-keyboard-on-macbook/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Key mapping for external PC keyboard on Mac&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>