Amazon Elastic Kubernetes Service or Amazon Elastic Container Service for Kubernetes.
Prerequisites: Docker image #
The following Docker container lists the hostname of the container. This is very helpful the test the scaling of a Kubernetes pod, as it lists the different hostnames when it’s curled.
Node.js #
- Create the following file:
app.js
const http = require('http');
const os = require('os');
console.log("Kubernetes testing");
var handler = function(request, response) {
console.log("Received request from " + request.connection.remoteAddress);
response.writeHead(200);
response.end("Container runs on: " + os.hostname() + "\n");
};
var www = http.createServer(handler);
www.listen(8080);
Dockerfile #
FROM node:lts-alpine3.19
Copy app.js /app.js
EXPOSE 8080
ENTRYPOINT ["node", "app.js"]
Build & Push the Docker Image #
# Build the image
docker build -t jueklu/container-2 .
# Push the image to the registry
docker push jueklu/container-2
Test the Image #
# Run the container
docker run -d --name container-2 -p 8080:8080 jueklu/container-2
# Use curl to check the container host
curl localhost:8080
# Optional: Open container terminal
docker exec -it container-2 /bin/ash
# Verify the container hostname
hostname
Prerequisites: Packages #
AWS CLIv2 #
Install AWS CLIv2 #
# Install AWS CLI version 2
sudo apt install curl zip -y &&
cd /tmp &&
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" &&
unzip awscliv2.zip &&
sudo ./aws/install
# Verify / check version
aws --version
IAM User & Policies #
Create an IAM user, create access keys for the user and add the following managed policy AdministratorAccess
. In a production environment only the least necessary permissions should be granted!
Configure AWS CLIv2 #
# Add the IAM user access key, secret access key & define the default region
aws configure
Install Eksctl #
Eksctl is a command-line tool for creating and managing Kubernetes clusters on EKS.
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp &&
sudo mv /tmp/eksctl /usr/local/bin
# Verify / check version
eksctl version
Install Kubectl #
# Install Kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" &&
chmod +x kubectl &&
sudo mv kubectl /usr/local/bin/
# Verify installation
kubectl version --client
EKS Cluster #
Create Cluster #
# Create an EKS cluster: Default region
eksctl create cluster \
--name my-cluster \
--nodegroup-name linux-nodes \
--node-type t3.micro \
--nodes 3
# Create an EKS cluster: Define Kubernetes version & region
eksctl create cluster \
--name my-cluster \
--version 1.29 \
--region us-east-1 \
--nodegroup-name linux-nodes \
--node-type t3.micro \
--nodes 3
More Options:
--node-volume-size 20
Define the volume size of the worker nodes
Note: Creating the necessary CloudFormation resources can take up to 10 - 20 minutes.
List Resources in AWS Management Console #
# EKS Cluster
https://eu-central-1.console.aws.amazon.com/eks/
# Cloudformation stack
https://eu-central-1.console.aws.amazon.com/cloudformation
List Nodes #
# List nodes
kubectl get nodes
# Shell output:
NAME STATUS ROLES AGE VERSION
ip-192-168-17-98.eu-central-1.compute.internal Ready <none> 14m v1.29.0-eks-5e0fdde
ip-192-168-55-216.eu-central-1.compute.internal Ready <none> 14m v1.29.0-eks-5e0fdde
ip-192-168-71-245.eu-central-1.compute.internal Ready <none> 14m v1.29.0-eks-5e0fdde
# List nodes: More details
kubectl get nodes -o wide
# Shell output:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-192-168-17-98.eu-central-1.compute.internal Ready <none> 14m v1.29.0-eks-5e0fdde 192.168.17.98 3.72.87.1 Amazon Linux 2 5.10.213-201.855.amzn2.x86_64 containerd://1.7.11
ip-192-168-55-216.eu-central-1.compute.internal Ready <none> 14m v1.29.0-eks-5e0fdde 192.168.55.216 3.75.229.65 Amazon Linux 2 5.10.213-201.855.amzn2.x86_64 containerd://1.7.11
ip-192-168-71-245.eu-central-1.compute.internal Ready <none> 13m v1.29.0-eks-5e0fdde 192.168.71.245 52.28.67.132 Amazon Linux 2 5.10.213-201.855.amzn2.x86_64 containerd://1.7.11
List & Delete Clusters #
# List all cluster: Define region
eksctl get cluster --region eu-central-1
# Shell output:
NAME REGION EKSCTL CREATED
my-cluster eu-central-1 True
# Delete Cluster: Define name & region
eksctl delete cluster --name my-cluster --region eu-central-1
Create HTTP Deployment #
Deploy Pod & Load Balancer #
# Create a Deployment
kubectl create deployment my-container --image=jueklu/container-2
# Create a load balancer service for the deployment
kubectl expose deployment my-container --type=LoadBalancer --port=8080 --target-port=8080 --name my-container-http
Scale the Deployment #
# Scale the Deployment
kubectl scale deployment my-container --replicas=3
# List the deployed pods
kubectl get pods
# Shell output:
NAME READY STATUS RESTARTS AGE
my-container-69f894487d-jfbzn 1/1 Running 0 97s
my-container-69f894487d-rw9xz 1/1 Running 0 115s
my-container-69f894487d-zc86s 1/1 Running 0 97s
List External IP #
# List load balancer service details: List external IP
kubectl get svc my-container-http
# Shell output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-container-http LoadBalancer 10.100.145.106 a6f48ac532c55486b88dc421a8671a91-1612496629.eu-central-1.elb.amazonaws.com 8080:32477/TCP 3m29s
Test the Deployment #
The AWS Elastic Load Balancer (ELB) URL randomly hit different pods and should output the different container hostnames when it’s curled:
# Test the deployment
curl a6f48ac532c55486b88dc421a8671a91-1612496629.eu-central-1.elb.amazonaws.com:8080
# Shell output:
Container runs on: my-container-69f894487d-jfbzn
# Test the deployment
curl a6f48ac532c55486b88dc421a8671a91-1612496629.eu-central-1.elb.amazonaws.com:8080
# Shell output:
Container runs on: my-container-69f894487d-zc86s
# Test the deployment
curl a6f48ac532c55486b88dc421a8671a91-1612496629.eu-central-1.elb.amazonaws.com:8080
# Shell output:
Container runs on: my-container-69f894487d-rw9xz
Delete the Deployment #
# Delete the Deployment
kubectl delete deployment my-container
# Delete the load balancer service
kubectl delete svc my-container-http
Create HTTPS Deployment #
Note: For this deployment I use a wildcard certificate *.jklug.work
from the AWS certificate manager.
Deploy Pod: CLI #
# Create a Deployment
kubectl create deployment my-container --image=jueklu/container-2
Note: Kubernetes automatically uses the deployment name as a key for a label named “app”.
# Scale the Deployment
kubectl scale deployment my-container --replicas=3
# List the deployed pods
kubectl get pods
# Shell output:
NAME READY STATUS RESTARTS AGE
my-container-69f894487d-pcqbj 1/1 Running 0 59m
my-container-69f894487d-w2dsb 1/1 Running 0 2m27s
my-container-69f894487d-wsf7m 1/1 Running 0 2m27s
Deploy Pod: YML #
vi my-container.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-container
spec:
replicas: 3
selector:
matchLabels:
app: my-container
template:
metadata:
labels:
app: my-container
spec:
containers:
- name: container-2
image: jueklu/container-2
ports:
- containerPort: 8080
# Apply the deployment
kubectl apply -f my-container.yml
LoadBalancer Service #
# Create yml file
vi loadbalancer.yml
apiVersion: v1
kind: Service
metadata:
name: my-container-https
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:...
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
spec:
selector:
app: my-container
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8080
type: LoadBalancer
service.beta.kubernetes.io/aws-load-balancer-ssl-cert:
Define the ARN of the TLS certificate from AWS Certificate Manager (ACM)
# Apply the deployment
kubectl apply -f loadbalancer.yml
List External DNS Name #
Note: The “EXTERNAL-IP” / DNS name of a load balancer service is listed as “
# List load balancer service details: List DNS name
kubectl get svc my-container-https
# Shell output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-container-https LoadBalancer 10.100.41.226 abcfad6f62e1a42bba95c282eea0c998-672012549.us-east-1.elb.amazonaws.com 80:31022/TCP,443:32030/TCP 37s
Create CNAME DNS Entry #
Manually #
Create a Route 53 DNS entry with the following values:
-
Record name: For example
eks.jklug.work
-
Record type:
CNAME
-
Value:
abcfad6f62e1a42bba95c282eea0c998-672012549.us-east-1.elb.amazonaws.com
-
TTL:
300
AWS CLI #
# Identify the hosted zone ID
aws route53 list-hosted-zones
# Shell output:
{
"HostedZones": [
{
"Id": "/hostedzone/...",
"Name": "jklug.work.",
"CallerReference": "...",
"Config": {
"Comment": "",
"PrivateZone": false
},
"ResourceRecordSetCount": 18
},
]
}
- Create a JSON file for the DNS record
vi cname-record.json
{
"Comment": "Create CNAME record for custom domain",
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "eks.jklug.work",
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [
{
"Value": "abcfad6f62e1a42bba95c282eea0c998-672012549.us-east-1.elb.amazonaws.com"
}
]
}
}
]
}
Action: "UPSERT"
Create the record if it doesn’t exist or update it if it does.
# Create the record
aws route53 change-resource-record-sets --hosted-zone-id /hostedzone/... --change-batch file://cname-record.json
Test the Deployment #
The AWS Elastic Load Balancer (ELB) URL randomly hit different pods and should output the different container hostnames when it’s curled:
# Test the deployment
curl eks.jklug.work
# Shell output:
Container runs on: my-container-69f894487d-pcqbj
# Test the deployment
curl eks.jklug.work
# Shell output:
Container runs on: my-container-69f894487d-wsf7m
Delete the Deployment #
# Delete the Deployment
kubectl delete deployment my-container
# Delete the load balancer service
kubectl delete svc my-container-https
Troubleshooting #
# List logs
kubectl get events --sort-by=.metadata.creationTimestamp
# List load balancer details
aws elb describe-load-balancers --region us-east-1
# Retrieves headers / TLS details
curl -Iv https://abcfad6f62e1a42bba95c282eea0c998-672012549.us-east-1.elb.amazonaws.com
Links #
# Install AWS CLIv2
https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
# Install AWS Eksctl
https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-eksctl.html
# Create Cluster
https://eksctl.io/usage/creating-and-managing-clusters/
# Create Cluster
https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html