Bulan April 2019, saya berkesempatan hadir dalam AWS Summit Singapore yang diselenggarakan di Changi Expo. Salah satu workshop session yang diselenggarakan adalah yang berkaitan dengan AWS managed Kubernetes Cluster, lebih sering disingkat EKS. Sessionnya sendiri tidak terlalu dalam, oleh sebab itu saya perlu lanjutkan hands-on. Berikut saya share mengenai cara Autoscale menggunakan Spot Instances.

Spot Instance

Spot Instance adalah kapasitas komputasi sisa yang dimiliki AWS, biasa ditawarkan dengan harga discount yang sangat kompetitif. Namun Spot Instance sewaktu-waktu bisa diminta kembali oleh AWS saat kapasitas komputasi dibutuhkan oleh customer lain.

Workload production kami menggunakan approach yang berbeda dalam menjalankan memanage cluster Spot Instances, dimana kami gunakan layanan 3rd party integration berupa SpotInst.

EKS

Amazon Elastic Container Service for Kubernetes (Amazon EKS) adalah layanan managed service yang memudahkan dalam menjalankan cluster Kubernetes di AWS.

Deployment EKS cluster dalam tulisan ini menggunakan eksctl, kami buat sebuah cluster di region Singapore dengan hanya 1 instance type t3.medium sebagai membernya

eksctl create cluster --name=belajar-eks --nodes=1 --node-type=t3.medium --tags Owner=Sandbox --node-ami=auto --region=ap-southeast-1

Kita tambahkan tag Owner=Sandbox, agar memudahkan identifikasi billing yang akan muncul dari pembuatan tulisan ini. Perintah ini butuh hingga 30 menit untuk menyelesaikan task pembuatan cluster EKS yang akan kita gunakan dalam tulisan ini.

Setelah selesai kubectl bisa kita gunakan untuk manage cluster baru ini

wisu:~/environment $ kubectl get nodes
NAME                                                STATUS   ROLES    AGE     VERSION
ip-192-168-168-61.ap-southeast-1.compute.internal   Ready    <none>   34s   v1.12.7

Instalasi Helm

Paket manager yang kita gunakan dalam tulisan ini adalah helm instalasi dilakukan dengan cara

curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh

chmod +x get_helm.sh

./get_helm.sh

Sebelum bisa jalankan helm init kita perlu konfigurasi RBAC, dengan file

cat <<EoF > rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
EoF

file ini bisa kita apply dengan perintah

wisu:~/environment $ kubectl apply -f rbac.yaml
serviceaccount/tiller created
clusterrolebinding.rbac.authorization.k8s.io/tiller created

baru bisa kita jalankan helm init, dengan perintah

wisu:~/environment $ helm init --service-account tiller
$HELM_HOME has been configured at /home/ec2-user/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation

Sekarang kita perlu update helm charts nya

wisu:~/environment $ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈ 

Konfigurasi Autoscaling

Untuk autoscaling, pertama kita tambahkan Metric Server dengan cara

wisu:~/environment $ helm install stable/metrics-server \
    --name metrics-server \
    --version 2.0.4 \
    --namespace metrics

Metrics selanjutnya bisa kita lihat melalui

wisu:~/environment $ kubectl get apiservice v1beta1.metrics.k8s.io -o yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  creationTimestamp: 2019-05-12T07:41:38Z
  labels:
    app: metrics-server
    chart: metrics-server-2.0.4
    heritage: Tiller
    release: metrics-server
  name: v1beta1.metrics.k8s.io
  resourceVersion: "3536"
  selfLink: /apis/apiregistration.k8s.io/v1/apiservices/v1beta1.metrics.k8s.io
  uid: 60660d3f-7489-11e9-8d29-0217022bb5fc
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: metrics-server
    namespace: metrics
  version: v1beta1
  versionPriority: 100
status:
  conditions:
  - lastTransitionTime: 2019-05-12T07:41:45Z
    message: all checks passed
    reason: Passed
    status: "True"
    type: Available
wisu:~/environment $ 

Spot Instance sebagai Workers

Selanjutnya untuk konfigurasi Spot Instance sebagai worker kita perlu ketahui 2 hal, pertama INSTANCE_PROFILE_ARN, bisa melalui perintah

INSTANCE_PROFILE_NAME=$(aws iam list-instance-profiles | jq -r '.InstanceProfiles[].InstanceProfileName' | grep belajar-eks-nodegroup) &&
INSTANCE_PROFILE_ARN=$(aws iam get-instance-profile --instance-profile-name $INSTANCE_PROFILE_NAME | jq -r '.InstanceProfile.Arn') &&
echo $INSTANCE_PROFILE_ARN

hasilnya

arn:aws:iam::986794076402:instance-profile/eksctl-belajar-eks-nodegroup-ng-dbfb886c-NodeInstanceProfile-1RFV8ZFOXIEG2

adalah Node Instance Profile ARN yang kita perlukan untuk langkah selanjutnya

Selajutnya kita perlu ketahui security group dari nodegroup kita

STACK_NAME=$(aws cloudformation describe-stacks | jq -r '.Stacks[].StackName' | grep belajar-eks-nodegroup) && SG_ID=$(aws cloudformation describe-stack-resources --stack-name $STACK_NAME --logical-resource-id SG | jq -r '.StackResources[].PhysicalResourceId') && echo $SG_ID

hasilnya

sg-0f3994a71cafbf2ce

adalah Security Group nodegroup dalam tulisan ini

selanjutnya melalui AWS Console kita gunakan cloudformation template berikut untuk membuat Auto Scaling group yang akan men-spin-up Spot Instances kita

https://raw.githubusercontent.com/bigwisu/belajar-eks/master/amazon-eks-nodegroup-with-mixed-instances.yml

Cloudformation

Cloudformation

Cloudformation

Saat ini cluster kita sukses bertambah menjadi 4 nodes

wisu:~/environment $ kubectl get node
NAME                                                 STATUS   ROLES    AGE    VERSION
ip-192-168-114-51.ap-southeast-1.compute.internal    Ready    <none>   34m    v1.12.7
ip-192-168-168-61.ap-southeast-1.compute.internal    Ready    <none>   109m   v1.12.7
ip-192-168-183-172.ap-southeast-1.compute.internal   Ready    <none>   34m    v1.12.7
ip-192-168-52-254.ap-southeast-1.compute.internal    Ready    <none>   34m    v1.12.7

Kita bisa inspect lebih dalam lagi mana saja yang merupakan Spot Instance

Ec2Spot-Instances

Selanjutnya kita install spot-interupt hanlder

wisu:~/environment $ wget -q https://raw.githubusercontent.com/bigwisu/belajar-eks/master/spot-interrupt-handler.yml
wisu:~/environment $ kubectl apply -f spot-interrupt-handler.yml 
clusterrole.rbac.authorization.k8s.io/spot-interrupt-handler created
serviceaccount/spot-interrupt-handler created
clusterrolebinding.rbac.authorization.k8s.io/spot-interrupt-handler created
daemonset.apps/spot-interrupt-handler created

Seperti saya sudah state diatas, solusi ini kami gunakan dalam development env kami, untuk production workload, kami gunakan integrasi dengan SpotInst