Skip to main content

Production Guides

Cloud Deployment

Summary

A GoFr container is a stock Linux Go binary listening on HTTP_PORT (default 8000), GRPC_PORT (default 9000), and METRICS_PORT (default 2121). It runs unchanged on EKS, GKE, and AKS — what differs is the Ingress controller, the LoadBalancer flavor, and how the pod gets credentials for managed datasources.

Common Kubernetes shape

Regardless of cloud, your pod exposes:

  • 8000 — HTTP API (overridable via HTTP_PORT)
  • 9000 — gRPC (overridable via GRPC_PORT)
  • 2121 — Prometheus metrics (overridable via METRICS_PORT; set to 0 to disable)
  • /.well-known/alive — liveness
  • /.well-known/health — readiness (covers dependencies)

These defaults are confirmed in pkg/gofr/default.go and pkg/gofr/factory.go.

AWS EKS

Cluster bring-up. Minimal eksctl invocation:

Bash
eksctl create cluster \
  --name <name> \
  --region <region> \
  --nodegroup-name <ng> \
  --node-type t3.medium \
  --nodes 2 \
  --managed

Ingress controller install. Install the AWS Load Balancer Controller via Helm (after IRSA is set up for the controller's ServiceAccount — see the controller's install docs for the IAM policy and ServiceAccount creation):

Bash
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=<name> \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller

Ingress. Use the AWS Load Balancer Controller, which provisions an ALB from an Ingress resource:

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gofr-api
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/healthcheck-path: /.well-known/alive
spec:
  ingressClassName: alb
  rules: [...]

For raw TCP (e.g., gRPC) prefer a Service: type=LoadBalancer annotated with service.beta.kubernetes.io/aws-load-balancer-type: nlb. ALB is L7-only.

IAM. Use IRSA (IAM Roles for Service Accounts). Annotate the ServiceAccount with eks.amazonaws.com/role-arn: arn:aws:iam::.... The AWS SDK inside any GoFr S3 / SQS / SNS datasource will pick the credentials up automatically. Do not bake static keys into env vars.

YAML
apiVersion: v1
kind: ServiceAccount
metadata:
  name: orders
  namespace: default
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/<role-name>

Datasources. RDS for PostgreSQL/MySQL works directly with GoFr's SQL driver — set DB_HOST, DB_PORT, etc. ElastiCache Redis works via the Redis datasource. Aurora's failover is handled by the cluster endpoint; GoFr will reconnect on failure.

Persistent storage. Only relevant if you use the local file storage driver. Use an EBS-backed PersistentVolumeClaim. For multi-AZ, switch to S3 file storage instead.

Smoke test.

Bash
# Apply the manifests from /docs/guides/deploying-to-kubernetes
kubectl apply -f k8s/
kubectl wait --for=condition=available --timeout=120s deployment/orders
kubectl port-forward svc/orders 8080:80 &
curl -s http://localhost:8080/.well-known/health

Cost note. A 2-node t3.medium managed node group is the smallest commonly-used EKS shape; you also pay the EKS control plane hourly fee per cluster. Expect a low-double-digit USD/day for an idle cluster at list price, before egress, NAT Gateway, EBS, ALB hours, and CloudWatch ingestion. Use the AWS Pricing Calculator for an account-accurate figure.

For canonical syntax see: https://kubernetes-sigs.github.io/aws-load-balancer-controller/.

GCP GKE

Cluster bring-up. Minimal gcloud invocation:

Bash
gcloud container clusters create <name> \
  --region <region> \
  --num-nodes 2 \
  --machine-type e2-standard-2 \
  --release-channel regular

Ingress controller install. GKE ships the GCE Ingress controller enabled by default — no install step needed. If you'd rather use NGINX or another controller, install it the same way you would on any cluster.

Ingress. GKE has a built-in GCE Ingress controller that provisions an HTTP(S) Load Balancer:

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gofr-api
spec:
  ingressClassName: gce
  rules: [...]

For container-native load balancing (recommended), expose the Service as type: ClusterIP with the cloud.google.com/neg: '{"ingress": true}' annotation.

LoadBalancer tier. A Service: type=LoadBalancer defaults to the Premium network tier. To force Standard, set cloud.google.com/network-tier: Standard. Premium gives lower latency but higher cost.

IAM. Use Workload Identity. Bind a Kubernetes ServiceAccount to a Google IAM service account with iam.gke.io/gcp-service-account annotation. GoFr's GCS file storage and Pub/Sub datasources will use those credentials.

YAML
apiVersion: v1
kind: ServiceAccount
metadata:
  name: orders
  namespace: default
  annotations:
    iam.gke.io/gcp-service-account: <gsa-name>@<project-id>.iam.gserviceaccount.com

Datasources. Cloud SQL: connect via the Cloud SQL Auth Proxy as a sidecar, or use Private IP and a VPC-native cluster. For Memorystore Redis, set REDIS_HOST to the private IP.

Persistent storage. pd-ssd PersistentDisk works for the local file storage driver. PD is zonal — use Regional PD for multi-zone availability.

Smoke test.

Bash
# Apply the manifests from /docs/guides/deploying-to-kubernetes
kubectl apply -f k8s/
kubectl wait --for=condition=available --timeout=120s deployment/orders
kubectl port-forward svc/orders 8080:80 &
curl -s http://localhost:8080/.well-known/health

Cost note. Two e2-standard-2 nodes is a common minimal shape; GKE Standard also charges a per-cluster management fee (Autopilot bills differently — per-pod). Idle list-price cost is typically a low-double-digit USD/day before egress, NAT, persistent disks, LB forwarding rules, and Cloud Logging ingestion. The Google Cloud Pricing Calculator gives an account-accurate figure.

Canonical docs: https://cloud.google.com/kubernetes-engine/docs/concepts/ingress.

Azure AKS

Cluster bring-up. Minimal az invocation:

Bash
az aks create \
  --resource-group <rg> \
  --name <name> \
  --node-count 2 \
  --node-vm-size Standard_DS2_v2 \
  --enable-managed-identity \
  --generate-ssh-keys

Ingress controller install. Either install NGINX via Helm:

Bash
helm install ingress-nginx ingress-nginx/ingress-nginx \
  -n ingress-nginx \
  --create-namespace

or enable the Application Gateway Ingress Controller (AGIC) for an Azure-native L7 path — see Microsoft's AGIC install docs for the exact flags, which depend on whether you bring your own Application Gateway or let AKS create one.

Ingress. Two common options:

  • Application Gateway Ingress Controller (AGIC) — uses an Azure Application Gateway, integrates with WAF.
  • NGINX Ingress Controller — vendor-neutral, runs anywhere.

AGIC sample (modern form): set spec.ingressClassName: azure-application-gateway on the Ingress instead of using the deprecated kubernetes.io/ingress.class annotation.

LoadBalancer. A Service: type=LoadBalancer provisions an Azure Standard Load Balancer by default. For internal-only, add service.beta.kubernetes.io/azure-load-balancer-internal: "true".

IAM. Use AKS Managed Identity with workload federation. Bind a UserAssignedIdentity via federated credentials. The Azure SDK in GoFr's Azure file storage and Event Hub datasources picks them up automatically.

YAML
apiVersion: v1
kind: ServiceAccount
metadata:
  name: orders
  namespace: default
  annotations:
    azure.workload.identity/client-id: <client-id>

Datasources. Azure Database for PostgreSQL/MySQL works with GoFr's SQL driver over private endpoints. Azure Cache for Redis works via the Redis datasource.

Persistent storage. Azure Disk (managed-csi) for single-zone; Azure Files (CSI) when you need ReadWriteMany.

Smoke test.

Bash
# Apply the manifests from /docs/guides/deploying-to-kubernetes
kubectl apply -f k8s/
kubectl wait --for=condition=available --timeout=120s deployment/orders
kubectl port-forward svc/orders 8080:80 &
curl -s http://localhost:8080/.well-known/health

Cost note. Two Standard_DS2_v2 nodes is a common minimal AKS shape; the AKS control plane is free in the Free tier (paid in Standard/Premium tiers, which add an SLA fee per cluster-hour). Expect a low-double-digit USD/day at list price for an idle cluster before egress, public IPs, managed disks, Application Gateway hours, and Log Analytics ingestion. Use the Azure Pricing Calculator for an account-accurate figure.

Canonical docs: https://learn.microsoft.com/azure/aks/.

Common gotchas

  • Set terminationGracePeriodSeconds longer than your slowest in-flight request so GoFr's graceful shutdown can drain.
  • If you front gRPC with an L7 LB (ALB, GCE), confirm HTTP/2 end-to-end — ALB needs BackendProtocolVersion=GRPC.
  • Use cloud-native logging (CloudWatch / Cloud Logging / Azure Monitor) only after confirming GoFr's structured JSON logs are not double-parsed.

Frequently asked