๋งค์ฐ๋งค์ฐ๋งค์ฐ ์ค์!
Karpenter v0.32 ๋ฒ์ ๋ถํฐ ๋ฆฌ์์ค ์ด๋ฆ๋ค์ด ๋ณ๊ฒฝ๋์ด ์ฐธ๊ณ ๋ฐ๋๋๋ค. ๊ฐ๋ ์ ๋๊ฐ์ต๋๋ค.
(ex. Provisioners -> NodePools)
AWS EKS ๋ฅผ ํตํด ํด๋ฌ์คํฐ๋ฅผ ๊ตฌ์ถํ๋ฉด Data Plane (์ดํ Node) ๋ฅผ ๋ค์ํ ๋ฐฉ์์ผ๋ก ๊ตฌ์ถํ ์ ์์ต๋๋ค.
Managed Node Group, Fargate ๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ๋ฆฌ์์ค๋ฅผ ์ ์ฐํ๊ฒ ๊ด๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ AWS Auto Scaling, Karpenter ๊ฐ ์์ต๋๋ค.
์ด๋ฒ ๊ธ์์๋ Karpenter ๋ฅผ ํตํด AWS Auto Scaling ๋ณด๋ค ์ ์ฐํ๊ฒ Node ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ณ ์ ํฉ๋๋ค.
์ฐ์ ๊ฐ๋จํ๊ฒ ์์๋ณด๋๋ก ํ์ฃ .
๋ ์ธ ๋๋์ฝ๋!
Karpenter ๊ฐ ๋ญ์ฃ ?
์ฌ๊ธฐ์ ๋งํ๋ ๋ ธ๋ == ์ธ์คํด์ค == ์๋ฒ ๋ ๋ชจ๋ ๊ฐ์ ๊ฐ๋ ์ ๋๋ค.
Karpenter ๋ฅผ ์์๋ณด๊ธฐ ์ ์ AWS Auto Scaling ์ ๋ํด ๋จผ์ ์์๋ณด์ฃ .
AWS Auto Scaling ์ Auto Scaling Group ์ผ๋ก ๋ฌถ์ธ ์ธ์คํด์ค๋ฅผ ์ ์ฐํ๊ฒ ๋์์ํฌ ์ ์๋๋ก ๋์์ค๋๋ค.
์คํ๋๋ ์ต์ ๊ฐฏ์์ ์ต๋ ๊ฐฏ์๋ฅผ ์ง์ ํ ์ ์์ฃ .
์์ ๋ฐฐ๋ฌ ์ฑ์์ ๋ฐค 10์์ ๋ง์ ํ ์ธ๋๋ ์นํจ ํ ์ธ ์ฟ ํฐ์ 1์๊ฐ ๋์ 1000 ์ฅ์ ์ ์ฐฉ์์ผ๋ก ๋ฐ์ ์ ์๋ ์ด๋ฒคํธ๋ฅผ ์งํํ๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค.
๋ฐค 10์์ ์๋ ํธ๋ํฝ์ด ํ์จํ๋ค๊ฐ~ 10์๊ฐ ๋๋ ์๊ฐ ์์ ๋ฐฐ๋ฌ ์ฑ์ ํ์ ๊ฐ์ง ์๋ ํธ๋ํฝ์ ๋๋ผ ์ฃฝ์ด๋ฒ๋ฆด ๊ฒ๋๋ค.
์ฑ์ด ์คํ๋๊ณ ์๋ ์๋ฒ์๋ ์ด๋ฅผ ๊ฐ๋นํ ๋งํ ๋ฆฌ์์ค๊ฐ ์๋๊ฑฐ์ฃ .
์ด๋ AWS Auto Scaling ์ ์ฌ์ฉํ๋ฉด ์ด๋ฐ ์ํฉ์ ๋์ฒํ๊ธฐ ์์ํฉ๋๋ค.
์ฑ์ด ์คํ๋๊ณ ์๋ ์ธ์คํด์ค๋ฅผ Auto Scaling Group ์ผ๋ก ๋ฌถ์ด์ ์ต์ ๊ฐฏ์ 1๊ฐ, ์ต๋ ๊ฐฏ์ 3๊ฐ๋ฅผ ์ง์ ํ๊ณ ์ธ์คํด์ค์ ๋ฆฌ์์ฑ์ด 50% ์ด์ ์ฌ์ฉ๋๋ฉด ์๋์ผ๋ก ์ค์ผ์ผ ์์์ ํด๋ฒ๋ฆฌ๋ฉด ๋์ฃ .
๊ทธ๋ผ ์์์ ์ธ์คํด์ค๊ฐ ์ฆ๊ฐํ๊ฒ ๋ ๊ฒ์ด๊ณ , ์ถ๊ฐ๋ ์ธ์คํด์ค์ ๋ํด์๋ ๋ก๋ ๋ฐธ๋ฐ์ฑ ์ฒ๋ฆฌ๋ฅผ ํด๋ฒ๋ฆฌ๋ฉด ๋ฉ๋๋ค.
Karpenter ๋ํ AWS Auto Scaling ์ฒ๋ผ ์ ๋์ ์ผ๋ก ์ธ์คํด์ค์ ๊ฐฏ์๋ฅผ ๋๋ฆฌ๊ณ , ์ค์ผ ์ ์์ต๋๋ค. ๋ค๋ง ์ฐจ์ด์ ์ด ์๋ค๋ฉด Karpenter ๊ฐ ํจ์ฌ ์ ์ฐํ๋ค๋ ๊ฒ์ ๋๋ค.
Karpenter ๋ ์ฟ ๋ฒ๋คํฐ์ค ํ๊ฒฝ์์ ํ ๋นํ ์ ์๋ ๋ ธ๋๊ฐ ์์ด pending ์ํ์ ์๋ ํ๋๊ฐ ์์ ๊ฒฝ์ฐ ์ด๋ฅผ ๊ฐ์งํ์ฌ ์๋์ผ๋ก ๋ ธ๋๋ฅผ ๋๋ ค์ค๋๋ค. ์ฌ๊ธฐ๊น์ง๋ ๋น์ทํด๋ณด์ด์ง๋ง ํ์ด๊ธฐ๊ฐ ์์ต๋๋ค.
AWS Auto Scaling ์ ์ฌ์ฉ์๊ฐ ์ง์ ํ ์ธ์คํด์ค ์ ํ ๋ด์์๋ง ๋์ํ๊ฒ ๋๋๋ฐ Karpenter ๋ ํ๋๋ฅผ ๋ฐฐํฌํ๋๋ฐ ์์ด ํ์ํ ๋ฆฌ์์ค๋ฅผ ๊ณ์ฐํ์ฌ ๋ณธ์ธ์ด ์์์ ๋ ธ๋๋ฅผ ํ๋ก๋น์ ๋ ํฉ๋๋ค. ์ด ๋ฟ๋ง ์๋๋ผ Karpenter ๋ ์ ๊ทธ๋ฆผ์ฒ๋ผ ์๋ก ๋ค๋ฅธ ๋ ธ๋์ ๋ฐฐํฌ๋ ํ๋๋ค์ ๋ฆฌ์์ค๋ฅผ ๊ณ์ฐํ์ฌ ํ๋์ ๋ ธ๋์ ์ฌ๋ฐฐ์น ํด์ค๋๋ค.
์ด๊ฒ ๋ฌด์จ ๋ง์ด๋๋ฉด, 4๊ฐ์ ํ๋๋ฅผ ๋ฐฐํฌ ํ ์ ์๋ ์ธ์คํด์ค๊ฐ 2๊ฐ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ 8๊ฐ์ ํ๋๊ฐ ์ด๋ฏธ ์ ์คํ๋๊ณ ์์ฃ .
์ด๋ ์ถ๊ฐ์ ์ผ๋ก 3๊ฐ์ ํ๋๋ฅผ ๋ ๋ฐฐํฌํ๋ ค๊ณ ํฉ๋๋ค. ๋ฐฐํฌํ ์ธ์คํด์ค๊ฐ ์์ผ๋ฏ๋ก ํ๋๋ค์ pending ์ํ๊ฐ ๋ ๊ฒ์ด๊ณ , ์ด๋ฅผ Karpenter ๊ฐ ๊ฐ์งํ์ฌ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ๋ง๋ค ๊ฒ์ ๋๋ค. ์ถ๊ฐ์ ์ธ ์ธ์คํด์ค๊ฐ ํ๋ก๋น์ ๋๋๊ณ pending ์ํ์ ๋น ์ ธ์๋ ํ๋๋ค์ ์ถ๊ฐ๋ ์ธ์คํด์ค์ ๋ฐฐํฌ๊ฐ ๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ฐ๋ฐ ์์์ ์ธ๊ธํ๋ฏ์ด ํ ์ธ์คํด์ค๋ฅผ ์ด 4๊ฐ์ ํ๋๋ฅผ ๋ฐฐํฌํ ์ ์๋๋ฐ 3๊ฐ์ ํ๋๋ง ์ถ๊ฐ ๋ฐฐํฌ๋ฅผ ํ์ผ๋ฏ๋ก 1๊ฐ์ ํ๋๋ฅผ ๋ฐฐํฌํ ์ ์๋ ๋งํผ์ ๋ฆฌ์์ค๊ฐ ์ฌ๊ธฐ์๋ ๋๊ณ ์๋ ๊ฒ๋๋ค. ๋ฆฌ์์ค ๋ํ ๋น์ฉ์ผ๋ก ์ด์ด์ง๊ฒ ๋๋ฌธ์ ์ต๋ํ ํ์ฉํ๋ ๊ฒ์ด ์ข๊ฒ ์ฃ ?
์ด๋ Karpenter ๋ฅผ ์ด์ฉํ๋ฉด ๋ฆฌ์์ค๋ฅผ ์ต๋ํ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋น๊ณต๊ฐ์ ์ต์ง๋ก ์ฑ์์ฃผ๋ ๊ฒ์ ์๋๊ณ , ์ ์ด์ ์ด 3๊ฐ์ ์ธ์คํด์ค๋ฅผ ํฉ์ณ๋ฒ๋ฆฝ๋๋ค. ์ฆ, ์ต๋ 11๊ฐ์ ํ๋๋ฅผ ๋ฐฐํฌํ ์ ์๋ ์ธ์คํด์ค๋ฅผ ์๋กญ๊ฒ ๋ง๋ค๊ณ ์ฌ๊ธฐ์ ๋ค์ ์ฌ๋ฐฐ์นํด์ค๋๋ค.
ํ๋ก๋น์ ๋ ์๋ ๋๋ฌธ์ ์ค์ผ์ผ ์์์ด ๋๋ฆด ๊ฑฐ๋ผ๊ณ ์๊ฐํ๋๋ฐ ์๊ฐ๋ณด๋ค ๋นจ๋์ต๋๋ค
์ด๋ฐ ๊ธฐ๋ฅ ๋ง๊ณ ๋ Karpenter ๋ฅผ ์ด์ฉํ๋ฉด AWS Auto Scaling ๋ฅผ ์ด์ฉํ์ ๋๋ณด๋ค ๋ ๋ง์ ์ด์ ์ ๊ฐ์ ธ๊ฐ ์ ์์ต๋๋ค.
Karpenter ๋ฅผ ์ฌ์ฉํด๋ณด์
๊ทธ๋ผ ์ด์ Karpenter ๊ฐ ๋ฌด์์ธ์ง ์์๋ดค์ผ๋ EKS ์ ํ๊ฒฝ์์ ์ค์นํด์ ํ๋ฒ ์ฌ์ฉํด๋ณด์ฃ !
์งํ๋ ํ๊ฒฝ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค
- EKS v1.23
- Terraform v1.2.7
Terraform ์ด ์๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์งํํ๋ ค๋ฉด ์ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์!
Terraform ์ผ๋ก ์์ฑ๋ Karpenter ์ฝ๋๋ ์ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์!
eks_managed_node_groups = {
karpenter = {
instance_types = ["t3.medium"]
min_size = 1
max_size = 2
desired_size = 1
iam_role_additional_policies = [
# Required by Karpenter
"arn:${local.partition}:iam::aws:policy/AmazonSSMManagedInstanceCore"
]
}
}
...
resource "aws_iam_instance_profile" "karpenter" {
name = "KarpenterNodeInstanceProfile-${local.name}"
role = module.eks.eks_managed_node_groups["karpenter"].iam_role_name
}
Kapenter ๋ฅผ ์คํํ ๊ด๋ฆฌํ ๋ ธ๋ ๊ทธ๋ฃน์ ์์ฑํฉ๋๋ค. ๊ด๋ฆฌํ ๋ ธ๋ ๊ทธ๋ฃน ๋ฟ๋ง ์๋๋ผ ํ๊ฒ์ดํธ๋ก๋ ๋ฐฐํฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
Karpenter ๋ฅผ Karpenter ๋ก ๊ด๋ฆฌ๋๋ ๋ ธ๋์ ๋ฐฐํฌํ๋ ๊ฒ์ ๊ถ์ฅ๋์ง ์์ต๋๋ค
์ฝ๋๋ฅผ ๋ณด๋ฉด iam_role_additional_policies ๋ถ๋ถ์ AmazonSSMManagedInstanceCore ๋ผ๋ AWS ๊ด๋ฆฌํ ์ ์ฑ ์ด ์ถ๊ฐ๋ฉ๋๋ค.
AmazonSSMManagedInstanceCore
์ด ์ ์ฑ ์ EC2 ์ธ์คํด์ค์ ์ฐ๊ฒฐํ๋ฉด, ์ธ์คํด์ค๊ฐ Systems Manager ์ ํต์ฌ ๊ธฐ๋ฅ๊ณผ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, Session Manager, CloudWatch, S3 ๋ฑ์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ์ ์ฑ ์ ์ธ์คํด์ค์ ๋ํ ์ต์ํ์ ๊ถํ์ ๋ถ์ฌํ๋ฏ๋ก, ๋ณด์์ ์ผ๋ก ์ข์ต๋๋ค.
๊ด๋ฆฌํ ๋ ธ๋ ๊ทธ๋ฃน์ผ๋ก ๊ด๋ฆฌ๋๋ EC2 ์ธ์คํด์ค์๋ ์๋์ ์ผ๋ก IAM Profile ์ด ์ง์ ๋๋๋ฐ ๊ธฐ๋ณธ ์ ์ฑ ์ผ๋ก๋ AmazonEKSWorkerNodePolicy, AmazonEC2ContainerRegistryReadOnly, AmazonEKS_CNI_Policy ๊ฐ ์ ํ๋๋๋ฐ AmazonSSMManagedInstanceCore ๋ํ ์ถ๊ฐ์ ์ผ๋ก ํ์ํ๊ธฐ ๋๋ฌธ์ ์ถ๊ฐํด์ค๋๋ค.
aws_iam_instance_profile ์ ํตํด์ Karpenter ๊ฐ ์์ฑํ๋ ์ธ์คํด์ค์ IAM Profile ์ ์ง์ ํฉ๋๋ค.
node_security_group_additional_rules = {
# Control plane invoke Karpenter webhook
ingress_karpenter_webhook_tcp = {
description = "Control plane invoke Karpenter webhook"
protocol = "tcp"
from_port = 8443
to_port = 8443
type = "ingress"
source_cluster_security_group = true
}
}
Karpenter Webhook ์ ํด๋ฌ์คํฐ๊ฐ ํ ์ ์๊ฒ ํ์ฉํด์ค๋๋ค.
Terraform ์ผ๋ก EKS ๋ฅผ ์์ฑํ๋ฉด ๊ธฐ๋ณธ์ผ๋ก ํด๋ฌ์คํฐ ๋ณด์ ๊ทธ๋ฃน๊ณผ ์ถ๊ฐ ๋ณด์ ๊ทธ๋ฃน์ด ์์ฑ๋ฉ๋๋ค.
ํด๋ฌ์คํฐ ๋ณด์ ๊ทธ๋ฃน : ๊ด๋ฆฌํ ๋ ธ๋ ๊ทธ๋ฃน, ํ๊ฒ์ดํธ๋ฅผ ํฌํจํ ํด๋ฌ์คํฐ ๋ด ํต์ ์ ์ ์ดํ๋ ๋ณด์ ๊ทธ๋ฃน
์ถ๊ฐ ๋ณด์ ๊ทธ๋ฃน : ํด๋ฌ์คํฐ ๋ณด์ ๊ทธ๋ฃน ์ธ ๊ท์น์ ์ง์ ํ ์ ์๋ ๋ณด์ ๊ทธ๋ฃน
์ถ๊ฐ ๋ณด์ ๊ทธ๋ฃน์๋ ๋ค์ ํ๋ฒ ํด๋ฌ์คํฐ์ฉ ๋ณด์ ๊ทธ๋ฃน๊ณผ ๋ ธ๋์ฉ ๋ณด์ ๊ทธ๋ฃน์ด ์กด์ฌํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ค์ง์ ์ผ๋ก ํด๋ฌ์คํฐ์ ํ์ํ ์ถ๊ฐ์ ์ธ ๋ณด์ ๊ทธ๋ฃน ๊ท์น์ ์ถ๊ฐ ๋ณด์ ๊ทธ๋ฃน์์ ์ด๋ค์ง๋๋ค. (์ด ๋ถ๋ถ์ ์ ํํ์ง ์์ต๋๋ค)
์ด๋ฌํ ๊ท์น๋ค์ด ์์ฑ๋๋ ์ด์ ๋ Karpenter ๊ฐ ์ธ์คํด์ค๋ฅผ ์ถ๊ฐ๋ก ์์ฑํ๋ค๊ณ ํด์ ๊ณง๋ฐ๋ก EKS ํด๋ฌ์คํฐ์ ํต์ ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํ๊ฐ์ง ๋ ์ฌ๊ฒจ๋ณผ ๋ถ๋ถ์ ์ฒซ๋ฒ์งธ ๊ท์น์ ๋๋ค. ์ค๋ช ์ "Cluster API to node groups" ๋ผ๊ณ ๋์์๋๋ฐ ์ด ๊ท์น์ผ๋ก ์ธํด ํด๋ฌ์คํฐ๊ฐ Karpenter ๋ก ์์ฑ๋ ์ธ์คํด์ค์ API ํต์ ์ ๋ณด๋ผ ์ ์๊ฒ ๋ฉ๋๋ค. ์ฆ, kubelet ๊ณผ ํต์ ์ ๊ฐ๋ฅ์ผ ํด์ฃผ๋ ๊ท์น์ธ๊ฑฐ์ฃ .
๋ํ ๋ ธ๋์ฉ ์ถ๊ฐ ๋ณด์ ๊ทธ๋ฃน ๋ง๊ณ ํด๋ฌ์คํฐ์ฉ ์ถ๊ฐ ๋ณด์ ๊ทธ๋ฃน์ ์ดํด๋ณด๋ฉด ๊ท์น์ด ๋ฐ๋๋ก ๋์ด์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
ํด๋ฌ์คํฐ์ฉ ์ถ๊ฐ ๋ณด์ ๊ทธ๋ฃน์ ์ฒซ๋ฒ์งธ ๊ท์น์ "Node groups to cluster API" ์ ๋๋ค.
์งํํ๊ธฐ ์์ ๋ณด์ ๊ทธ๋ฃน ์์ค๋ผ๋ ํ๋์๋ 192.168.0.10/24 ์ ๊ฐ์ CIDR ๊ฐ ์๋ ๋ณด์ ๊ทธ๋ฃน์ด ์ง์ ์ด ๋์ด ์๋๋ฐ ์ด์ ๋ํด ์ ๊น ์ค๋ช ๋๋ฆฌ๊ฒ ์ต๋๋ค.
๋ณด์๊ทธ๋ฃน ์ธ๋ฐ์ด๋ ๋ฃฐ์์ ์์ค๋ก ๋ค๋ฅธ ๋ณด์๊ทธ๋ฃน์ ์ง์ ํ๋ ์๋ฏธ (์ฌ๊ธฐ ์ฐธ๊ณ )
AWS ๋ณด์๊ทธ๋ฃน์์ ์์ค๋ฅผ ์ง์ ํ ๋ ๋ค๋ฅธ ๋ณด์๊ทธ๋ฃน์ ์ง์ ํ๋ฉด, ํด๋น ๋ณด์๊ทธ๋ฃน์ ์ฐ๊ฒฐ๋ ๋ฆฌ์์ค๋ค์ด ํธ๋ํฝ์ ๋ณด๋ผ ์ ์๊ฒ ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, EC2 ์ธ์คํด์ค์ ์ธ๋ฐ์ด๋ ๋ฃฐ์์ ์์ค๋ก RDS ๋ณด์๊ทธ๋ฃน์ ์ง์ ํ๋ฉด, RDS ๋ณด์๊ทธ๋ฃน์ ์ฐ๊ฒฐ๋ DB ์ธ์คํด์ค๋ค์ด EC2 ์ธ์คํด์ค๋ก ํธ๋ํฝ์ ๋ณด๋ผ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด, IP ์ฃผ์๋ CIDR ๋ธ๋ก์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ๋ณด์๊ทธ๋ฃน์ ๋ฆฌ์์ค๋ค์ด ๋ณ๊ฒฝ๋์ด๋ ๋ฃฐ์ ์์ ํ ํ์๊ฐ ์์ต๋๋ค. ๋ค๋ง, ๋ค๋ฅธ AWS ๊ณ์ ์ ๋ณด์๊ทธ๋ฃน์ ์ง์ ํ ๋๋ ๊ณ์ ๋ฒํธ๋ ํจ๊ป ์ง์ ํด์ผ ํ๊ณ , ๋ค๋ฅธ ๋ฆฌ์ ์ ๋ณด์๊ทธ๋ฃน์ ์ง์ ํ ์ ์์ต๋๋ค.
๋ณด์๊ทธ๋ฃน ์ธ๋ฐ์ด๋ ๋ฃฐ์์ ์์ค๋ก ์๊ธฐ ์์ ์ ์ง์ ํ๋ ์๋ฏธ (์ฌ๊ธฐ ์ฐธ๊ณ )
AWS ๋ณด์๊ทธ๋ฃน์์ ์์ค๋ฅผ ์ง์ ํ ๋ ์๊ธฐ ์์ ์ ์ง์ ํ๋ฉด, ํด๋น ๋ณด์๊ทธ๋ฃน์ ์ฐ๊ฒฐ๋ ๋ชจ๋ ๋ฆฌ์์ค๋ค์ด ์๋ก ํธ๋ํฝ์ ์ฃผ๊ณ ๋ฐ์ ์ ์๊ฒ ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, EC2 ์ธ์คํด์ค์ ์ธ๋ฐ์ด๋ ๋ฃฐ์์ ์์ค๋ก ์๊ธฐ ์์ ์ ์ง์ ํ๋ฉด, ๊ฐ์ ๋ณด์๊ทธ๋ฃน์ ์ฐ๊ฒฐ๋ ๋ค๋ฅธ EC2 ์ธ์คํด์ค๋ค์ด ํธ๋ํฝ์ ๋ณด๋ผ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด, ๋ฆฌ์์ค๋ค์ IP ์ฃผ์๊ฐ ๋ณ๊ฒฝ๋์ด๋ ๋ฃฐ์ ์์ ํ ํ์๊ฐ ์์ต๋๋ค. ๋ค๋ง, ์๊ธฐ ์์ ์ ์ง์ ํ ๋๋ ๋ณด์๊ทธ๋ฃน์ ID๋ฅผ ์ฌ์ฉํด์ผ ํ๊ณ , ์ด๋ฆ์ด๋ ํ๊ทธ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
node_security_group_additional_rules ์์ source_cluster_security_group = true ์ธ ๊ฒ์ ๋ณผ ์ ์๋๋ฐ ์ด ๊ท์น์ ์์ค๋ฅผ cluster ๊ฐ ๊ฐ์ง๊ณ ์๋ ๋ณด์ ๊ทธ๋ฃน์ผ๋ก ์ง์ ํ๊ฒ ๋ค๋ ๊ฒ๋๋ค. ์ฆ, ์์ค๋ก ํด๋ฌ์คํฐ์ฉ ๋ณด์ ๊ทธ๋ฃน์ ์ง์ ํจ์ผ๋ก์จ ํด๋ฌ์คํฐ์ ๋ ธ๋ ๊ฐ ํต์ ์ ํ์ฉํด์ฃผ๋ ๊ฒ์ด์ง์.
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 3.0"
name = local.name
cidr = "10.0.0.0/16"
azs = ["${local.region}a", "${local.region}b", "${local.region}c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
public_subnet_tags = {
"kubernetes.io/cluster/${local.name}" = "shared"
"kubernetes.io/role/elb" = 1
}
private_subnet_tags = {
"kubernetes.io/cluster/${local.name}" = "shared"
"kubernetes.io/role/internal-elb" = 1
# Tags subnets for Karpenter auto-discovery
"karpenter.sh/discovery" = local.name
}
tags = local.tags
}
Karpenter ๋ ํ๋ผ์ด๋น ์๋ธ๋ท์์๋ง ๋์ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ ํ๋ผ์ด๋น ์๋ธ๋ท์ ์ฌ์ฉํ ๊ฒ์ธ์ง ์ง์ ์ ํด์ฃผ์ด์ผํ๊ธฐ ๋๋ฌธ์ private_subnet_tags ์ karpenter.sh/discovery ๋ฅผ ์ถ๊ฐํฉ๋๋ค. local.name ์ eks ์ด๋ฆ์ ๋๋ค.
๋ํ ์ด๋ ๊ฒ ์ถ๊ฐ๋ ๋ถ๋ถ์ ์ดํ K8S Karpenter Provisioner ๋ฆฌ์์ค์์ subnetSelector ๋ถ๋ถ์์ ์ฌ์ฉ๋ฉ๋๋ค.
์ง๊ธ๊น์ง karpenter ๊ฐ ์์ฑํ ์ธ์คํด์ค์์ ํ์ํ ๋ถ๋ถ๋ค์ Terraform ์ผ๋ก ์์ฑํ๋ค๋ฉด, ์ด๋ฒ์๋ karpenter pod ์์ ํ์ํ ๋ถ๋ถ์ ์ค์ ํฉ๋๋ค.
karpenter pod ๋ ์์์ ์ง์ ํ ๊ด๋ฆฌํ ๋ ธ๋ ๊ทธ๋ฃน์ ์์ฑ์ด ๋ฉ๋๋ค. ์ดํ ํ์ํ ๋ฆฌ์์ค๊ฐ ์์ ๊ฒฝ์ฐ karpenter pod ์ ์ํด ์์ ์ด ์คํ์ด ๋๋๋ฐ, karpenter pod ๋ AWS ์ ์ ๊ทผํ ์๊ฒฉ์ด ๋น์ฐํ ์์ต๋๋ค.
๋ฐ๋ผ์ karpenter pod ๊ฐ AWS ์ ์ ๊ทผํ ์ ์๋๋ก IRSA ๋ฅผ ์์ฑํฉ๋๋ค. (IRSA ๊ฐ ๊ถ๊ธํ๋ค๋ฉด ์ฌ๊ธฐ ์ฐธ๊ณ )
module "karpenter_irsa" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 4.21.1"
role_name = "karpenter-controller-${local.name}"
attach_karpenter_controller_policy = true
karpenter_controller_cluster_id = module.eks.cluster_id
karpenter_controller_ssm_parameter_arns = [
"arn:${local.partition}:ssm:*:*:parameter/aws/service/*"
]
karpenter_controller_node_iam_role_arns = [
module.eks.eks_managed_node_groups["karpenter"].iam_role_arn
]
oidc_providers = {
ex = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["karpenter:karpenter"]
}
}
}
Terraform ์์ ์ค์ ์ด ํ์ํ ๋ถ๋ถ์ ๋ชจ๋ ๋๋ฌ์ต๋๋ค. ๊ทธ๋ผ EKS ๋ฅผ ์ ์ฉ์ ํ๊ณ , ์ถ๊ฐ์ ์ผ๋ก Helm ์ ํตํด Karpenter ๋ฅผ ์ค์นํด๋ณด์ฃ .
#!/bin/bash
set -e
KARPENTER_VERSION="v0.27.0"
CLUSTER_NAME="<cluster name>"
KARPENTER_IAM_ROLE_ARN="arn:aws:iam::<id>:role/karpenter-controller-<cluster name>"
docker logout public.ecr.aws
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter --version ${KARPENTER_VERSION} --namespace karpenter --create-namespace \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \
--set settings.aws.clusterName=${CLUSTER_NAME} \
--set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${CLUSTER_NAME} \
--set settings.aws.interruptionQueueName=${CLUSTER_NAME} \
--wait
๊ทธ๋ผ ์ด์ Karpenter ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์ค์น๋์๋์ง ํ๋ฒ ํ์ธํด๋ณด์ฃ .
์๋ ๋ฆฌ์์ค๋ฅผ ๋ฐฐํฌํด์ค๋๋ค.
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: provisioner
spec:
# ์์ฑํ ์ธ์คํด์ค ์ ํ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ ์
requirements:
- key: "node.kubernetes.io/instance-type"
operator: In
values: [ "g4dn.xlarge" ]
- key: "topology.kubernetes.io/zone"
operator: In
values: [ "ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c", "ap-northeast-2d" ]
- key: "karpenter.sh/capacity-type"
operator: In
values: [ "on-demand"]
- key: "kubernetes.io/arch"
operator: In
values: [ "amd64" ]
# ์์ฑํ ์ธ์คํด์ค์ ์ต๋ ๋ฆฌ์์ค
limits:
resources:
cpu: "100"
memory: 100Gi
nvidia.com/gpu: 16
# karpenter ํ๋ก๋น์ ๋ ๋ฉ์ปค๋์ฆ ์ฌ์ฉ
# ttlSecondsAfterEmpty ์ consolidation ์ ๋์์ ์ฌ์ฉ ๋ถ๊ฐ
consolidation:
enabled: true
# ttlSecondsUntilExpired: 2592000 # 30 Days = 60 * 60 * 24 * 30 Seconds;
# ttlSecondsAfterEmpty: 30
# ์์ฑ๋ ์ธ์คํด์ค(worker node)์ ์ง์ ๋๋ label
labels:
role: ops
provision: karpenter
# ์์ฑ๋ ์ธ์คํด์ค(worker node)์ ์ง์ ๋๋ taints
taints:
- key: nvidia.com/gpu
value: "true"
effect: NoSchedule
provider:
# ์์ฑํ ์ธ์คํด์ค์ ์ด๋ ๋ณด์ ๊ทธ๋ฃน์ ์ ์ฉํ ๊ฒ์ธ์ง ๋ณด์ ๊ทธ๋ฃน์ ํ๊ทธ๋ก ์ง์
securityGroupSelector:
Name: eks-node
kubernetes.io/cluster/eks: owned
# ์ด๋ ์๋ธ๋ท์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ๊ฒ์ธ์ง ํ๊ทธ๋ก ์ง์
subnetSelector:
karpenter.sh/discovery: eks
# ์์ฑ๋ ์ธ์คํด์ค์ ํ๊ทธ๋ฅผ ์ง์
tags:
karpenter.sh/discovery: eks
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 0
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
terminationGracePeriodSeconds: 10
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
resources:
limits:
nvidia.com/gpu: "1"
tolerations:
- key: nvidia.com/gpu
value: "true"
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions: # OR
- key: "topology.kubernetes.io/zone" # AND
operator: "In"
values: [ "ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c", "ap-northeast-2d" ]
- key: "karpenter.sh/capacity-type" # AND
operator: "In"
values: [ "on-demand" ]
- key: "kubernetes.io/arch" # AND
operator: In
values: [ "amd64" ]
- key: "node.kubernetes.io/instance-type" # AND
operator: In
values: [ "g4dn.xlarge" ]
limits ๋ถ๋ถ์ karpenter๊ฐ ์์ฑํ ์ ์๋ ๋ ธ๋์ ์ต๋ ๋ฆฌ์์ค๋ฅผ ์ค์ ํ๋ ๋ถ๋ถ์ ๋๋ค.
์๋ฅผ ๋ค์ด, limits.resources.cpu: "1000"์ karpenter๊ฐ ์์ฑํ ์ ์๋ ๋ ธ๋์ ์ต๋ CPU ์ฝ์ด ์๋ฅผ 1000๊ฐ๋ก ์ ํํ๋ค๋ ์๋ฏธ์ ๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก limits.resources.memory: 1000Gi๋ karpenter๊ฐ ์์ฑํ ์ ์๋ ๋ ธ๋์ ์ต๋ ๋ฉ๋ชจ๋ฆฌ ์ฉ๋์ 1000Gi๋ก ์ ํํ๋ค๋ ์๋ฏธ์ ๋๋ค.
์ด๋ฌํ ์ ํ์ karpenter๊ฐ ๋๋ฌด ๋ง์ ๋ ธ๋๋ฅผ ์์ฑํ์ฌ ๋น์ฉ์ด ์ฆ๊ฐํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ , ์ ์ ํ ํฌ๊ธฐ์ ๋ ธ๋๋ฅผ ์ ํํ๋๋ก ๋์ต๋๋ค.
๋์ฌ๊ฒจ ๋ณผ ์ต์ ์ ๋ฐ๋ก Karpenter ์ ํต์ฌ ๊ธฐ๋ฅ๊ณผ ๊ด๋ จ๋ ttlSecondsAfterEmpty ์ ๋๋ค.
ttlSecondsAfterEmpty ๋ง๊ณ ๋ ๊ด๋ จ๋ ๊ธฐ๋ฅ ์ต์ ์ผ๋ก๋ ttlSecondsUntilExpired, consolidation ๊ฐ ์์ต๋๋ค.
karpenter์์ ttlSecondsAfterEmpty์ ttlSecondsUntilExpired์ ์ฐจ์ด๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
ttlSecondsAfterEmpty๋ ๋ ธ๋๊ฐ ๋น์ด์์ ๋ karpenter๊ฐ ๋ ธ๋๋ฅผ ์ข ๋ฃํ๋๋ก ์ค์ ํ๋ ๊ฐ์ ๋๋ค. ์ด ๊ธฐ๋ฅ์ ๊ฐ์ ์ ์ํ์ง ์์ผ๋ฉด ๋นํ์ฑํ๋ฉ๋๋ค.
ttlSecondsUntilExpired๋ ๋ ธ๋๊ฐ ์ต๋ ๋์ด์ ๋๋ฌํ์ ๋ karpenter๊ฐ ๋ ธ๋๋ฅผ ์ข ๋ฃํ๋๋ก ์ค์ ํ๋ ๊ฐ์ ๋๋ค. ์ด ๊ธฐ๋ฅ์ ๊ฐ์ ์ ์ํ์ง ์์ผ๋ฉด ๋นํ์ฑํ๋ฉ๋๋ค. ์ด ์ต์ ๊ฐ์ ๊ฒฝ์ฐ ์ค๋๋ ์ธ์คํด์ค๋ฅผ ์๋์ผ๋ก ์ ๋ฐ์ดํธ ํ๋ ค๊ณ ํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
consolidation ์ ๋ํด์
karpenter์์ consolidation์ ๋ ธ๋์ ๋ฆฌ์์ค ํ์ฉ๋๋ฅผ ๋์ด๊ณ ๋น์ฉ์ ์ ๊ฐํ๊ธฐ ์ํด ์์ ๋ถํ๋ฅผ ๋ค๋ฅธ ๋ ธ๋๋ก ์ด๋์ํค๋ ๊ธฐ๋ฅ์ ๋๋ค. karpenter๋ consolidation์ ์ํด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
๋ ธ๋ ์ญ์ : karpenter๋ ๋ ธ๋์ ์๋ ๋ชจ๋ ํ๋๊ฐ ๋ค๋ฅธ ๋ ธ๋๋ก ์ฎ๊ฒจ์ง ์ ์๋์ง ํ์ธํ๊ณ , ๊ทธ๋ ๋ค๋ฉด ํด๋น ๋ ธ๋๋ฅผ ์ญ์ ํฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ ttlSecondsAfterEmpty ๊ฐ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค.
๋ ธ๋ ๊ต์ฒด: karpenter๋ ์๋ก์ด ์ธ์คํด์ค ํ์ ์ด๋ ์ฉ๋ ์ ํ์ผ๋ก ์ ํฉํ ๋ ธ๋๋ฅผ ์์ฑํ๊ณ , ๊ธฐ์กด์ ๋นํจ์จ์ ์ธ ๋ ธ๋์ ์๋ ํ๋๋ฅผ ์๋ก์ด ๋ ธ๋๋ก ์ฎ๊ธด ํ, ๊ธฐ์กด์ ๋ ธ๋๋ฅผ ์ญ์ ํฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ consolidation.enabled ๊ฐ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค.
consolidation ๊ธฐ๋ฅ์ ํด๋ฌ์คํฐ์ ์์ ์ฑ๊ณผ ์ฑ๋ฅ์ ํฅ์์ํค๊ณ , ์คํ ์ธ์คํด์ค๋ ์จ๋๋งจ๋ ์ธ์คํด์ค์ ๊ฐ์ ๋ค์ํ ์ฉ๋ ์ ํ์ ํผํฉํ์ฌ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋๋ค.
consolidation ์ ttlSecondsAfterEmpty ๊ฐ์ด ์ฌ์ฉ ํ ์ ์์๊น?
consolidation๊ณผ ttlSecondsAfterEmpty๋ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ ๊ธฐ๋ฅ์ ์๋ก ๋ฐฐํ์ ์ธ ๋ฐฉ์์ผ๋ก ๋ ธ๋๋ฅผ ์ญ์ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. consolidation์ ์๋ก์ด ๋ ธ๋๋ฅผ ์์ฑํ๊ณ ๊ธฐ์กด์ ๋ ธ๋์ ์๋ ํ๋๋ฅผ ์ฎ๊ธด ํ์ ๋ ธ๋๋ฅผ ์ญ์ ํฉ๋๋ค.
๋ฐ๋ฉด์ ttlSecondsAfterEmpty์ ๋ ธ๋๊ฐ ๋น์ด์๋ ์ํ์์ ์ผ์ ์๊ฐ์ด ์ง๋๋ฉด ๋ฐ๋ก ๋ ธ๋๋ฅผ ์ญ์ ํฉ๋๋ค.
๋ฐ๋ผ์ consolidation๊ณผ ttlSecondsAfterEmpty์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ์ถฉ๋์ด ๋ฐ์ํ ์ ์์ต๋๋ค. karpenter๋ provisioner ๋จ์๋ก consolidation๊ณผ ttlSecondsAfterEmpty ์ค ํ๋๋ง ์ค์ ํ ์ ์๋๋ก ์ ํํ๊ณ ์์ต๋๋ค.
karpenter pod ์ ๋ก๊ทธ๋ฅผ ํ์ธํด๋ณด์ฃ .
2023-03-16T06:35:03.384Z INFO controller.provisioner computed new node(s) to fit pod(s) {"commit": "dc3af1a", "nodes": 1, "pods": 1}
2023-03-16T06:35:03.384Z INFO controller.provisioner launching machine with 1 pods requesting {"cpu":"1155m","memory":"120Mi","pods":"6"} from types t3.xlarge, t3.medium, t3.large {"commit": "dc3af1a", "provisioner": "karpenter-provisioner"}
2023-03-16T06:35:03.509Z DEBUG controller.provisioner.cloudprovider discovered security groups {"commit": "dc3af1a", "provisioner": "karpenter-provisioner", "security-groups": ["sg-0b874fd0cb8b74351"]}
2023-03-16T06:35:03.708Z DEBUG controller.provisioner.cloudprovider created launch template {"commit": "dc3af1a", "provisioner": "karpenter-provisioner", "launch-template-name": "Karpenter-csg-sd-dev-eks-8333440626470183087", "launch-template-id": "lt-084967c0de086c425"}
2023-03-16T06:35:05.780Z INFO controller.provisioner.cloudprovider launched new instance {"commit": "dc3af1a", "provisioner": "karpenter-provisioner", "id": "i-0c206dbe4cb2d08e1", "hostname": "ip-10-146-5-13.ap-northeast-2.compute.internal", "instance-type": "t3.medium", "zone": "ap-northeast-2c", "capacity-type": "on-demand"}
2023-03-16T06:36:12.275Z ERROR controller.interruption getting messages from queue, discovering queue url, fetching queue url, AWS.SimpleQueueService.NonExistentQueue: The specified queue does not exist for this wsdl version.
๋ฌธ์ ์์ด ์ ์คํ๋๊ณ ์์ต๋๋ค.
์ดํ deployment ์ replica ๋ฅผ 0 ์ผ๋ก ์ค์ ํ๋ฉด ttlSeocondsAfterEmpty: 30 ๋ก ํ๊ธฐ ๋๋ฌธ์ ํด๋น ์ธ์คํด์ค๋ 30์ด ๋ค ์ญ์ ๋ฉ๋๋ค.
ํธ๋ฌ๋ธ ์ํ
k logs -f -n karpenter karpenter-xxxx-xxxx ๋ฅผ ํตํด์ ๋ก๊ทธ ํ์ธ์ด ๊ฐ๋ฅํฉ๋๋ค.
eks:DescribeCluster ๊ถํ๋ฌธ์
iam-role-for-service-accounts-eks ํ ๋ผํผ ๋ชจ๋์ ๊ฐ์ฅ ์ต์ ๋ฒ์ ์ผ๋ก ์ ๋ฐ์ดํธ ํฉ๋๋ค.
๊ตฌ ๋ฒ์ ์๋ ์ด ๊ถํ์ด ์ถ๊ฐ๋์ด์์ง ์์ ๋ฐ์ํ๋ ์๋ฌ์ ๋๋ค.
Karpenter ๋ก ์์ฑํ ์ธ์คํด์ค ์ํ๊ฐ ๊ณ์ NotReady
์๋ฌด๋ฆฌ ๊ธฐ๋ค๋ ค๋ Ready ๋ก ๋ฐ๋์ง ์๋๋ค๋ฉด ์์ฑ๋ ์ธ์คํด์ค์ ๋ณด์๊ทธ๋ฃน์ ํ์ธํฉ๋๋ค. ํด๋ฌ์คํฐ์ karpenter web hook ์ ํต์ ํ ์ ์๋ ๊ท์น์ด ์์ด์ผ ํฉ๋๋ค.
securityGroupSelector ๋ถ๋ถ์์ ์ด๋ ๋ณด์ ๊ทธ๋ฃน์ด ์ ํ๋์๋์ง ํ์ธํ๊ณ , ์ด๋ ๊ท์น์ ํ์ฉํ๊ณ ์๋์ง๋ ํ์ธํฉ๋๋ค.
๋ง์ฝ ๋ณด์ ๊ทธ๋ฃน์ ๋ฌธ์ ๊ฐ ์๋ค๋ฉด, aws-auth configmap ์ Karpenter ์์ ์ฌ์ฉํ๋ ์ธ์คํด์ค ํ๋กํ์ ์๋์ ๊ฐ์ด ์ถ๊ฐํด์ฃผ์ธ์.
๋ง๋ฌด๋ฆฌ
์ด์ EKS ์์ Karpenter ๋ฅผ ์ค์นํด๋ณด๊ณ ๋์ํ๋ ์ง ํ์ธํด๋ณด์์ต๋๋ค.
Terraform ์ผ๋ก EKS ๋ฅผ ์์ฑํ์ ๋ ์์ฑ๋ ๋ณด์ ๊ทธ๋ฃน์ ๋ํด์๋ ์์ธํ ๋ค์ฌ๋ค ๋ณด์ง ์์๋๋ฐ ์ด๋ฒ์ Karpenter ๋ฅผ ์ค์นํ๋ฉด์ ์ด๋ค ๋ณด์ ๊ทธ๋ฃน์ด ์์ฑ๋๊ณ ์ด๋ ๊ท์น ๋๋ถ์ ํด๋ฌ์คํฐ์ ๋ ธ๋๋ค์ด ํต์ ์ด ๊ฐ๋ฅํ์ง ์ ์ ์์์ต๋๋ค.
๋ํ Karpenter ๋ฅผ ์ด์ฉํ๋ฉด ๋น์ฉ์ ํจ์ฌ ๋ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ ๊ฑฐ ๊ฐ์ต๋๋ค.
๊ทธ๋ฌ๋ฉด ์ค๋์ ์ฌ๊ธฐ๊น์ง!
'DevOps > Karpenter' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Karpenter] NVIDIA GPU ๊ฐ ์ฌ๋ผ์ง์ง ์์์! (0) | 2023.06.19 |
---|---|
[Karpenter] ๋ ธ๋์ Deprovisioning ์ ์ข ๋ ์๋ฆ๋ต๊ฒ~ (0) | 2023.05.17 |