3sky's notes

Minimal blog about IT

EKS on speed

2021-08-01 4 min read 3sky

Welcome

Let’s build some stuff. Today on AWS(EKS). Today with popular solutions and almost without coding(in YAML). Today focus on speed and simplicity. Additionally no CI/CD.

Components

I will keep it simple.

Building infrastructure

Setup

First steps. I need to build some infrastructure. As almost everyone use Terraform for building and managing resources I decided to use it too. Based on Terrafrom EKS module I’ve created a sample manifest. Also, I decided to add ECR and configure output in a specific way.

# I'd like to have control plane endpoint
output "cluster_endpoint" {
  description = "Endpoint for EKS control plane."
  value       = module.eks.cluster_endpoint
}

# get kubectl config based on cluster_name
output "cluster_name" {
  description = "Name of created cluster"
  value       = local.cluster_name
}

# upload to ECR with dynamic name
output "ecr_url" {
  description = "URL of ECR registry"
  value       = aws_ecr_repository.ecr.repository_url
}

# also region could be dynamic
output "region" {
  description = "AWS region."
  value       = var.region
}

Variables.tf and main.tf weren’t very interesting, so it will be pushed to the repo.

Commands flow

# get modules
terraform init

# take a look at plan, if it's correct go-ahead
terraform plan | less

# this step will take some time to finish. (9:33.03 total)
# if correct enter yes or terraform apply -auto-approve
terraform apply

Kubectl and ECR

Is anybody there?

After successful cluster creation, we could want to check if the cluster is running. First I need to update my kubeconfig for the purpose of cluster authentication. For this event, I will AWS CLI and kubectl.

# variables are based on Terraform outputs
aws eks update-kubeconfig \
    --region $(terraform output -raw region) \
    --name $(terraform output -raw cluster_name)
kubectl get pod

Docker login

Now I need to login into ECR and push some images.

aws ecr get-login-password \
    --region $(terraform output -raw region) \
    | docker login --username AWS \
    --password-stdin $(terraform output -raw ecr_url | cut -d'/' -f1)

Then I can push an awesome Nginx image to ECR.

docker tag nginx:latest $(terraform output -raw ecr_url):1.0.0
docker push $(terraform output -raw ecr_url):1.0.0

Helming

After all this preparation we can finally deploy an app. For this process I decided to use helm. It’s a standard, very popular, and flexible solution. Again Helm Chart is attached to the repository. There is no hack or magic - just boring templates.

Command flow

# dry run
helm template <app name> -f <file with values> --dry-run <chart name>
# for example
# helm template example-app -f example-app.yaml --dry-run ./example-app

# install chart
helm install <app name> -f <file with values> --namespace <namespace> <chart name>
# for example
# helm install example-app -f example-app.yaml --namespace example ./example-app

# upgrade app
helm upgrade <app name> <chart> --set.image=<tag>
# for example
# helm upgrade example-app ./example-app --set=image.tag=2.0.0

DNS

Now all I need is a DNS record change. Ah, I forgot about LoadBalancer. For this article, I’m using LoadBalancer. After adding a service ELB provides an AWS endpoint for our application. My primary domain 3sky.dev is delegated to CloudFlare, so I will add a CNAME record with API. To do that I need four commands, and sometimes (for DNS propagation).

# token
TOKEN=my-private-token
ZONE=my-domain-zone
ELB=$(kubectl get svc example-app -n example --output jsonpath='{.status.loadBalancer.ingress[0].hostname}')

curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records" \
     -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/json" \
     --data '{"type":"CNAME","name":"app","content":"'"$ELB"'","ttl":1,"proxied":true}' | jq .

Finally, I can check my app on app.3sky.dev. Trust me It was working(the app was stopped after checks).

Summary

In case of summary. The whole setup was faster than writing this post based on the ready README.md file. ~10 minutes for EKS, 30 for DNS propagation, command execution was fast - I have a fast keyboard. What can I say more? Testing and implementing stuff is still fun. What next? I don’t know. I’m starting Elixir again, so maybe some sophisticated CI/CD for functional language?