[AEWS] #3์ฃผ์ฐจ ARM, AMD ์•„ํ‚คํ…์ฒ˜, Graviton์— ํŒŒ๋“œ, BottleRocketAMI ์‹ค์Šต (4)

25๋…„๋„ AWS EKS Hands-on Study ์Šคํ„ฐ๋”” ์ •๋ฆฌ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

ARM, AMD 

ARM๊ณผ AMD๋Š” CPU ์•„ํ‚คํ…์ฒ˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด๋‹ค. ARM๊ณผ AMD์˜ ์ฐจ์ด๋Š” ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„ ์ฒ ํ•™์ด ๋‹ค๋ฅด๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ์šฉ๋„๋กœ CPU๋ฅผ ์‚ฌ์šฉํ• ์ง€์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค.

 

ARM์€ RISC(Reduced Instruction Set Computing, ์ถ•์†Œ ๋ช…๋ น์–ด ์ง‘ํ•ฉ ์ปดํ“จํŒ…) ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๋œ๋‹ค. ์ด ๋ฐฉ์‹์€ ๋ช…๋ น์–ด์˜ ์ข…๋ฅ˜๋ฅผ ๋‹จ์ˆœํ™”ํ•˜์—ฌ CPU๊ฐ€ ๋” ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค. ๋ช…๋ น์–ด๊ฐ€ ๊ฐ„๋‹จํ•˜๋ฉด ์‹คํ–‰ ์†๋„๊ฐ€ ๋นจ๋ผ์ง€๊ณ ์ „๋ ฅ ์†Œ๋น„๋„ ์ค„์ผ ์ˆ˜ ์žˆ๋Š”๋ฐ ARM ๊ธฐ๋ฐ˜ ํ”„๋กœ์„ธ์„œ๋Š” ์ €์ „๋ ฅ, ๋†’์€ ์ „๋ ฅ ํšจ์œจ์„ฑ, ๋ฐœ์—ด์ด ์ ์€ ํŠน์„ฑ์„ ๊ฐ–๋Š”๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ์Šค๋งˆํŠธํฐ, ํƒœ๋ธ”๋ฆฟ, ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ, ์ €์ „๋ ฅ ์„œ๋ฒ„ ๋“ฑ์— ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๊ณ  ๋Œ€ํ‘œ์ ์œผ๋กœ ์• ํ”Œ์˜ M1, M2 ์นฉ๊ณผ ํ€„์ปด์˜ Snapdragon ํ”„๋กœ์„ธ์„œ๊ฐ€ ๋Œ€ํ‘œ์ ์ธ ARM ๊ธฐ๋ฐ˜ ์นฉ์ด๋‹ค.

 

AMD๋Š” CISC(Complex Instruction Set Computing, ๋ณตํ•ฉ ๋ช…๋ น์–ด ์ง‘ํ•ฉ ์ปดํ“จํŒ…) ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” x86 ํ”„๋กœ์„ธ์„œ๋ฅผ ์„ค๊ณ„ํ•œ๋‹ค. CISC ๋ฐฉ์‹์€ ๋ณต์žกํ•œ ๋ช…๋ น์–ด๋ฅผ ํ•œ ๋ฒˆ์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด ๋ณด๋‹ค ๊ฐ•๋ ฅํ•œ ์—ฐ์‚ฐ ๋Šฅ๋ ฅ์„ ์ œ๊ณตํ•œ๋‹ค. ํ•˜์ง€๋งŒ ๋ช…๋ น์–ด๊ฐ€ ๋ณต์žกํ•ด์งˆ์ˆ˜๋ก ์ „๋ ฅ ์†Œ๋น„๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ  ๋ฐœ์—ด์ด ๋ฐœ์ƒํ•œ๋‹ค. AMD์˜ CPU๋Š” ๊ณ ์„ฑ๋Šฅ ์—ฐ์‚ฐ์ด ํ•„์š”ํ•œ ํ™˜๊ฒฝ์—์„œ ๊ฐ•์ ์„ ๋ฐœํœ˜ํ•˜๋ฉฐ, ๋ฐ์Šคํฌํ†ฑ, ์„œ๋ฒ„, ๊ฒŒ์ž„์šฉ PC, ๋ฐ์ดํ„ฐ์„ผํ„ฐ ๋“ฑ์˜ ๊ณ ์„ฑ๋Šฅ ์ปดํ“จํŒ… ํ™˜๊ฒฝ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค. ๋Œ€ํ‘œ์ ์ธ ์ œํ’ˆ์œผ๋กœ๋Š” ๋ผ์ด์  , EPYC ์„œ๋ฒ„ ํ”„๋กœ์„ธ์„œ ๋“ฑ์ด ์žˆ๋‹ค.

 

๋‘ ์•„ํ‚คํ…์ฒ˜๋Š” ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์šฉ๋„์™€ ์žฅ์ ์„ ๊ฐ–๊ณ  ์žˆ๋‹ค. ARM ๊ธฐ๋ฐ˜ ์นฉ์€ ์ €์ „๋ ฅ, ๊ธด ๋ฐฐํ„ฐ๋ฆฌ ์ˆ˜๋ช…, ๋ชจ๋ฐ”์ผ ๋ฐ ์—๋„ˆ์ง€ ํšจ์œจ์ ์ธ ํ™˜๊ฒฝ์—์„œ ๊ฐ•์ ์„ ๋ณด์ด๋ฉฐ, AMD์˜ x86 ๊ธฐ๋ฐ˜ ์นฉ์€ ๊ณ ์„ฑ๋Šฅ ์—ฐ์‚ฐ๊ณผ ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น์ด ํ•„์š”ํ•œ ํ™˜๊ฒฝ์—์„œ ๋” ์ ํ•ฉํ•˜๋‹ค. ์ตœ๊ทผ์—๋Š” ARM ๊ธฐ๋ฐ˜ ์นฉ๋„ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋ฉด์„œ ์„œ๋ฒ„์™€ ๋ฐ์Šคํฌํ†ฑ ์‹œ์žฅ์œผ๋กœ ํ™•์žฅํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ๋ฐ˜๋Œ€๋กœ AMD๋„ ์ „๋ ฅ ํšจ์œจ์„ฑ์„ ๊ฐœ์„ ํ•˜๊ณ  ์žˆ๋‹ค.

 

AWS graviton

AWS Graviton์€ AWS๊ฐ€ ์ž์ฒด ์„ค๊ณ„ํ•œ ARM ๊ธฐ๋ฐ˜์˜ ํ”„๋กœ์„ธ์„œ๋กœ, ๊ณ ์„ฑ๋Šฅ๊ณผ ์—๋„ˆ์ง€ ํšจ์œจ์„ฑ์„ ๋™์‹œ์— ์ œ๊ณตํ•œ๋‹ค.

Graviton ํ”„๋กœ์„ธ์„œ๋Š” ํด๋ผ์šฐ๋“œ ํ™˜๊ฒฝ์—์„œ ์ตœ์ ํ™”๋œ ์„ฑ๋Šฅ๊ณผ ๋น„์šฉ ํšจ์œจ์„ฑ์„ ์ œ๊ณตํ•˜๋„๋ก ์„ค๊ฒŒ๋˜์—ˆ์œผ๋ฉฐ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜, ์ปจํ…Œ์ด๋„ˆ, ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค, ๋น…๋ฐ์ดํ„ฐ ๋ถ„์„, ML ๋“ฑ ๋‹ค์–‘ํ•œ ์›Œํฌ๋กœ๋“œ์—์„œ ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ์„ ๋ฐœํœ˜ํ•œ๋‹ค.

eksctl create nodegroup -c $CLUSTER_NAME -r ap-northeast-2 --subnet-ids "$PubSubnet1","$PubSubnet2","$PubSubnet3" \
  -n ng3 -t t4g.medium -N 1 -m 1 -M 1 --node-volume-size=30 --node-labels family=graviton --dry-run > myng3.yaml

eksctl create nodegroup -f myng3.yaml

kubectl get nodes --label-columns eks.amazonaws.com/nodegroup,kubernetes.io/arch,eks.amazonaws.com/capacityType
NAME                                               STATUS   ROLES    AGE     VERSION               NODEGROUP   ARCH    CAPACITYTYPE
ip-192-168-1-127.ap-northeast-2.compute.internal   Ready    <none>   2m24s   v1.31.5-eks-5d632ec   ng3         arm64   ON_DEMAND
...


kubectl describe nodes --selector family=graviton
...
System Info:
  Machine ID:                 ec22fa7316c4486fe019bf98a12d486b
  System UUID:                ec22fa73-16c4-486f-e019-bf98a12d486b
  Boot ID:                    837ae6ee-0bb0-4615-bd23-da6bc27ecf56
  Kernel Version:             5.10.233-224.894.amzn2.aarch64
  OS Image:                   Amazon Linux 2
  Operating System:           linux
  Architecture:               arm64
  Container Runtime Version:  containerd://1.7.25
  Kubelet Version:            v1.31.5-eks-5d632ec
  Kube-Proxy Version:         v1.31.5-eks-5d632ec
ProviderID:                   aws:///ap-northeast-2a/i-008befacce404ca12
Non-terminated Pods:          (4 in total)
  Namespace                   Name                  CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                  ------------  ----------  ---------------  -------------  ---
  kube-system                 aws-node-f4kld        50m (2%)      0 (0%)      0 (0%)           0 (0%)         2m29s
  kube-system                 ebs-csi-node-4wdqw    30m (1%)      0 (0%)      120Mi (3%)       768Mi (23%)    2m29s
  kube-system                 efs-csi-node-kv8rj    0 (0%)        0 (0%)      0 (0%)           0 (0%)         2m29s
  kube-system                 kube-proxy-gktwf      100m (5%)     0 (0%)      0 (0%)           0 (0%)         2m29s
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests    Limits
  --------           --------    ------
  cpu                180m (9%)   0 (0%)
  memory             120Mi (3%)  768Mi (23%)
  ephemeral-storage  0 (0%)      0 (0%)
  hugepages-1Gi      0 (0%)      0 (0%)
  hugepages-2Mi      0 (0%)      0 (0%)
  hugepages-32Mi     0 (0%)      0 (0%)
  hugepages-64Ki     0 (0%)      0 (0%)
Events:
  Type     Reason                   Age                    From                   Message
  ----     ------                   ----                   ----                   -------
  Normal   Starting                 2m26s                  kube-proxy
  Normal   Starting                 2m30s                  kubelet                Starting kubelet.
  Warning  CgroupV1                 2m30s                  kubelet                Cgroup v1 support is in maintenance mode, please migrate to Cgroup v2.
  Warning  InvalidDiskCapacity      2m30s                  kubelet                invalid capacity 0 on image filesystem
  Normal   NodeHasSufficientMemory  2m30s (x2 over 2m30s)  kubelet                Node ip-192-168-1-127.ap-northeast-2.compute.internal status is now: NodeHasSufficientMemory
  Normal   NodeHasNoDiskPressure    2m30s (x2 over 2m30s)  kubelet                Node ip-192-168-1-127.ap-northeast-2.compute.internal status is now: NodeHasNoDiskPressure
  Normal   NodeHasSufficientPID     2m30s (x2 over 2m30s)  kubelet                Node ip-192-168-1-127.ap-northeast-2.compute.internal status is now: NodeHasSufficientPID
  Normal   NodeAllocatableEnforced  2m30s                  kubelet                Updated Node Allocatable limit across pods
  Normal   Synced                   2m29s                  cloud-node-controller  Node synced successfully
  Normal   RegisteredNode           2m27s                  node-controller        Node ip-192-168-1-127.ap-northeast-2.compute.internal event: Registered Node ip-192-168-1-127.ap-northeast-2.compute.internal in Controller
  Normal   NodeReady                2m15s                  kubelet                Node ip-192-168-1-127.ap-northeast-2.compute.internal status is now: NodeReady

 

aws eks update-nodegroup-config --cluster-name $CLUSTER_NAME --nodegroup-name ng3 \
--taints "addOrUpdateTaints=[{key=frontend, value=true, effect=NO_EXECUTE}]"

kubectl describe nodes --selector family=graviton | grep Taints
Taints:             frontend=true:NoExecute

aws eks describe-nodegroup --cluster-name $CLUSTER_NAME --nodegroup-name ng3 | jq .nodegroup.taints[
  {
    "key": "frontend",
    "value": "true",
    "effect": "NO_EXECUTE"
  }
]

 

๋…ธ๋“œ์— taint ์„ค์ •์„ ๊ฑธ์–ด์ค€ ํ›„ ํŒŒ๋“œ๋ฅผ ๋ฐฐํฌํ•œ๋‹ค.

 

cat <<EOF | kubectl apply -f -
> apiVersion: v1
> kind: Pod
> metadata:
>   name: busybox
> spec:
>   terminationGracePeriodSeconds: 3
>   containers:
>   - name: busybox
>     image: busybox
>     command:
>     - "/bin/sh"
>     - "-c"
>     - "while true; do date >> /home/pod-out.txt; cd /home; sync; sync; sleep 10; done"
>   tolerations:
>     - effect: NoExecute
>       key: frontend
>       operator: Exists
>   nodeSelector:
>     family: graviton
> EOF
pod/busybox created

kubectl get pod -owide
NAME                    READY   STATUS    RESTARTS   AGE   IP              NODE                                               NOMINATED NODE   READINESS GATES
busybox                 1/1     Running   0          6s    192.168.1.244   ip-192-168-1-127.ap-northeast-2.compute.internal   <none>           <none>

 

busybox๋ฅผ graviton ๋…ธ๋“œ์— ๋„์šด๋‹ค. 

 

kubectl exec -it busybox -- arch
aarch64

kubectl exec -it busybox -- tail -f /home/pod-out.txt
Sat Feb 22 02:43:11 UTC 2025
Sat Feb 22 02:43:21 UTC 2025
Sat Feb 22 02:43:31 UTC 2025
Sat Feb 22 02:43:41 UTC 2025
Sat Feb 22 02:43:51 UTC 2025
Sat Feb 22 02:44:01 UTC 2025
Sat Feb 22 02:44:11 UTC 2025

 

busybox ํŒŒ๋“œ๊ฐ€ x86์ด ์•„๋‹Œ ARM(Graviton)๊ธฐ๋ฐ˜์˜ ์ธ์Šคํ„ด์Šค์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

BottleRocket AMI

ํด๋ผ์šฐ๋“œ ํ™˜๊ฒฝ์—์„œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์ผ๋ฐ˜์ ์œผ๋กœ Amazon Linux, Ubuntu ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ ๋ฆฌ๋ˆ…์Šค ๋ฐฐํฌํŒ์„ ์‚ฌ์šฉํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ์šด์˜์ฒด์ œ๋Š” ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ ๋งŽ์€ ์—ฌ๋Ÿฌ ํŒจํ‚ค์ง€์™€ ์„œ๋น„์Šค๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด ๋ณด์•ˆ ๊ด€๋ฆฌ์™€ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ณต์žกํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด AWS์—์„œ๋Š” Bottlerocket์ด๋ผ๋Š” ์ปจํ…Œ์ด์ € ์ „์šฉ ์šด์˜์ฒด์ œ๋ฅผ ๊ฐœ๋ฐœํ–ˆ๋‹ค.

Bottlerocket์€ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰์— ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ๊ตฌ์„ฑ๋งŒ ํฌํ•จํ•˜์—ฌ ๊ฒฝ๋Ÿ‰ํ™”๋œ OS์ด๋ฉฐ ๋ณด์•ˆ๊ณผ ์„ฑ๋Šฅ ์ตœ์ ํ™”์— ์ดˆ์ ์„ ๋งž์ถ”์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค.

 

cat << EOF > ng-br.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: myeks
  region: ap-northeast-2
  version: "1.31"

managedNodeGroups:
- name: ng-bottlerocket
  instanceType: m5.large
  amiFamily: Bottlerocket
  bottlerocket:
    enableAdminContainer: true
    settings:
      motd: "Hello, eksctl!"
  desiredCapacity: 1
  maxSize: 1
  minSize: 1
  labels:
    alpha.eksctl.io/cluster-name: myeks
    alpha.eksctl.io/nodegroup-name: ng-bottlerocket
    ami: bottlerocket
  subnets:
  - $PubSubnet1
  - $PubSubnet2
  - $PubSubnet3
  tags:
    alpha.eksctl.io/nodegroup-name: ng-bottlerocket
    alpha.eksctl.io/nodegroup-type: managed

- name: ng-bottlerocket-ssh
  instanceType: m5.large
  amiFamily: Bottlerocket
  desiredCapacity: 1
  maxSize: 1
  minSize: 1
  ssh:
    allow: true
    publicKeyName: $SSHKEYNAME
  labels:
    alpha.eksctl.io/cluster-name: myeks
    alpha.eksctl.io/nodegroup-name: ng-bottlerocket-ssh
    ami: bottlerocket
  subnets:
  - $PubSubnet1
  - $PubSubnet2
  - $PubSubnet3
  tags:
    alpha.eksctl.io/nodegroup-name: ng-bottlerocket-ssh
    alpha.eksctl.io/nodegroup-type: managed
EOF

eksctl create nodegroup -f ng-br.yaml

 

 

kubectl get node --label-columns=alpha.eksctl.io/nodegroup-name,ami,node.kubernetes.io/instance-type


kubectl get node --label-columns=alpha.eksctl.io/nodegroup-name,ami,node.kubernetes.io/instance-type
NAME                                               STATUS   ROLES    AGE     VERSION               NODEGROUP-NAME        AMI            INSTANCE-TYPE
ip-192-168-1-13.ap-northeast-2.compute.internal    Ready    <none>   5d15h   v1.31.5-eks-5d632ec   ng1                                  t3.medium
ip-192-168-1-69.ap-northeast-2.compute.internal    Ready    <none>   2m40s   v1.31.4-eks-0f56d01   ng-bottlerocket-ssh   bottlerocket   m5.large
ip-192-168-2-229.ap-northeast-2.compute.internal   Ready    <none>   5d15h   v1.31.5-eks-5d632ec   ng1                                  t3.medium
ip-192-168-2-249.ap-northeast-2.compute.internal   Ready    <none>   2m40s   v1.31.4-eks-0f56d01   ng-bottlerocket       bottlerocket   m5.large
ip-192-168-3-122.ap-northeast-2.compute.internal   Ready    <none>   5d15h   v1.31.5-eks-5d632ec   ng1                                  t3.medium