노드가 할당되지 않은 새로 생성된 Pod를 감지하고, 스케줄러가 발견한 모든 Pod에 대해 스케줄러는 해당 Pod가 실행시 최상의 노드를 찾는 책임을 가짐
Pod를 생성할때 특정 노드에서만 실행 하거나, 특정 조건에 맞춰 Node에서 실행하도록 설정 할수 있다.
접근 방식은 모두 Node labels를 사용하여 선택을 용이하게 한다.
kubernetes가 특정 Pod를 예약할 위치를 선택하는 방법에는 여러가지가 존재한다.
노드에도 파드와 마찬가지로 키-값 쌍의 레이블이 붙는다.
운영자는 수동으로 레이블을 추가 할수 있으며, 기본적으로 클러스터 내 노드들이 가진 레이블을 통하여 노드를 분류 할 수 있다.
이 레이블은 나중에 파드 스케줄링 제약 조건 (nodeSelector, affinity 등)에서 참조 한다.
kubectl label nodes sample disktype=ssd environment=production
apiVersion: v1
kind: Node
metadata:
name: sample
labels:
disktype: ssd
environment: production
...
파드 스펙 내에 nodeSelector 필드를 사용하여 특정 레이블을 가진 노드로만 스케줄 되도록 제한한다.
여러 키-값 쌍으로 지정할 수 있으며, 파드가 모든 조건을 만족하는 노드에만 배포된다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx-container
image: nginx
nodeSelector:
disktype: ssd
nodeSelector보다 정의할수 있는 제약 유형을 확장 시키며, 강제(hard), 선호(soft) 규칙을 구분 할수 있다.
apiVersion: v1
kind: Pod
metadata:
name: node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# 반드시 만족해야 하는 조건 (hard)
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
preferredDuringSchedulingIgnoredDuringExecution:
# 선호하는 조건 (soft)
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx-container
image: nginx
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
topologyKey: "kubernetes.io/hostname"
containers:
- name: nginx-container
image: nginx
pod 스펙의 nodeName 필드를 사용하면 스케줄러를 거치지 않고 지정된 노드에서 파드를 바로 실행한다.
단 노드가 존재하지 않거나, 리소스가 부족할 경우 파드 실행에 실패한다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx-container
image: nginx
nodeName: node1
파드를 클러스터의 장애 도메인 (노드,. 가용영역 등) 전반에 균등하게 분산 하여 배포 할수 있도록 제어가 가능하다.
이를 통해 특정 영역에 파드가 몰리지 않아 고가용성과 균형 잡힌 리소스 사용이 가능해진다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: nginx
containers:
- name: nginx
image: nginx
각 방식은 제어하려는 목적과 요구사항에 맞게 사용된다.
k8s에서 Pod 오버헤드는 컨테이너 실행에 필요한 리소스 이외에, Pod 인프라 자체가 소비하는 추가적인 시스템 리소스를 나타낸다. 이러한 오버헤드는 주로 Pod의 RuntimeClass에 정의된 오버 헤드에 따라 결정 된다.
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: kata-fc
handler: kata-fc
overhead:
podFixed:
memory: "120Mi"
cpu: "250m"
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
runtimeClassName: kata-fc
containers:
- name: busybox-ctr
image: busybox:1.28
resources:
limits:
cpu: 500m
memory: 100Mi
- name: nginx-ctr
image: nginx
resources:
limits:
cpu: 1500m
memory: 100Mi
위의 코드를 기반으로 구성시
해당 방식으로 k8s는 Pod 오버헤드를 고려하여 리소스 할당과 스케줄링 정확성을 보장한다.
Pod 스케줄링 준비 상태를 제어하며, 필수 리소스 부족으로 인하여 스케줄러와 클러 오토 스케일러에 불 필요한 부하가 발생하는 것을 방지한다.
이를 위해 Pod의 .spec.schedulingGates 필드를 사용하여 스케줄링 준비 상태를 관리할 수 있다.
출처 : https://kubernetes.io/docs/concepts/scheduling-eviction/pod-scheduling-readiness/
스케줄링되지 않도록 설정된 Pod 생성
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
schedulingGates:
- name: example.com/foo
- name: example.com/bar
containers:
- name: pause
image: registry.k8s.io/pause:3.6
파드 생성후 아래 명령어를 이용하여 SchedulingGated 상태를 확인한다.
kubectl get pods test-pod
kubectl get pod test-pod -o jsonpath='{.spec.schedulingGates}'
스케줄링 게이트 제거를 통항 스케줄링 준비 완료
Pod의 스케줄링 게이트를 제거하여 스케줄러가 해당 Pod를 스케줄링 하도록 한다.
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: pause
image: registry.k8s.io/pause:3.6
스케줄링 게이트가 제거되면, 스케줄러는 Pod를 스케줄링하며, 리소스 요청이 없는 경우 Running 상태로 전환한다.
kubectl get pod test-pod -o wide
scheduler_pending_pods 메트릭에는 새로운 “gated” 라벨이 추가되어, 스케줄링이 시도 되었지만 스케줄링 되지 않는 Pod와 명시적으로 스케줄링 준비가 되어 있지 않는 Pod를 구분할 수 있다.
.spec.nodeSelector에는 항목 추가만 허용되며, .spec.affinity.nodeAffinity가 비어 있는 경우에는 설정이 허용된다.이러한 기능을 통해 Kubernetes에서 Pod의 스케줄링 준비 상태를 세밀하게 제어하고, 스케줄러의 효율성을 향상시킬 수 있다.
kubectl taint nodes <노드명> key=value:NoSchedule
kubectl taint nodes <노드명> key=value:NoSchedule- # 제거
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
| 효과 | 설명 |
|---|---|
| NoSchedule | Pod 스케줄링 불가 (기존 Pod는 유지). |
| PreferNoSchedule | 되도록 스케줄링하지 않음 (강제성 없음). |
| NoExecute | 매칭되지 않는 Pod는 즉시 퇴출 (tolerationSeconds 지정 가 |
dedicated=groupName:NoSchedule).special=true:NoSchedule Taint 추가.node.kubernetes.io/not-ready: 노드 준비 안됨node.kubernetes.io/unreachable: 노드 통신 불가node.kubernetes.io/memory-pressure: 메모리 부족not-ready, unreachable Taint는 300초 후 Pod를 퇴출.DaemonSet은 not-ready, unreachable에 대한 NoExecute Toleration을 기본적으로 포함.Taints와 Tolerations는 특정 Pod를 특정 노드에서 실행하거나 배제하는 데 유용하며, 노드 상태에 따른 자동 조정을 가능하게 한다.
k8s 스케줄링 프레임워크는 플러그형 아키텍처로, 스케줄링 기능을 확장 하고 유지관리 쉽게 설계되었다.
해당 프레임워크는 다양한 스케줄링 플러그인을 통해 클러스터의 스케줄링 동작을 세밀하게 제어할수 있도록 도와준다.
스케줄링은 아래의 순차적 단계로 진행이 되며 Extension, Point로 노출되어 커스텀 할수 있다.

출처 : https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/
| 확장 포인트 | 설명 | 주요 특징 | 실행 순서 | 예시 사용 사례 |
|---|---|---|---|---|
| PreEnqueue | Pod이 스케줄링 대기열에 추가되기 전 조건 검사 | 모든 플러그인이 성공해야 대기열 진입 가능 | 1 | Pod 우선순위 기반 대기열 제어 |
| QueueSort | 스케줄링 대기열의 Pod 정렬 규칙 정의 | 동시에 하나의 플러그인만 활성화 가능 | 2 | 우선순위/생성 시간 기준 정렬 |
| PreFilter | Pod 메타데이터 전처리 또는 클러스터 사전 검증 | 실패 시 즉시 스케줄링 중단 | 3 | 리소스 요구량 계산, 의존성 검사 |
| Filter | 실행 불가능한 노드 필터링 | 노드별 병렬 평가 가능, 하나라도 실패 시 중단 | 4 | 리소스 가용성/테인트 검사 |
| PostFilter | 실행 가능 노드 없을 때 호출 | 주로 선점(Preemption) 로직 구현 | 5 | 다른 Pod 종료를 통한 자원 확보 |
| PreScore | 점수 계산 전 공유 데이터 생성 | Score 단계를 위한 사전 작업 | 6 | 노드 그룹핑 정보 생성 |
| Score | 노드 점수 부여 (범위: 0-100) | 가중치 적용 가능한 점수 체계 | 7 | 리소스 밸런스/노드 친화성 계산 |
| NormalizeScore | 점수 표준화 | 모든 Score 플러그인 실행 후 호출 | 8 | 점수 범위 정규화 |
| Reserve | 자원 예약 | 성공 시 바인딩 진행, 실패 시 Unreserve 역순 실행 | 9 | 볼륨/네트워크 자원 예약 |
| Permit | 최종 승인 제어 | Approve/Deny/Wait(타임아웃) 3가지 액션 | 10 | 외부 승인 시스템 연동 |
| PreBind | 바인딩 전 작업 수행 | 실패 시 Pod을 대기열로 반환 | 11 | 네트워크 볼륨 마운트 준비 |
| Bind | 실제 노드 바인딩 | 하나의 플러그인이 처리하면 나머지 생략 | 12 | 기본 바인딩 또는 커스텀 바인딩 로직 |
| PostBind | 바인딩 후 리소스 정리 | 정보 제공용으로만 사용 (실행 실패 무시) | 13 | 로깅/모니터링, 임시 리소스 삭제 |
AWS가 제공하는 서버리스 컨테이너 실행 서비스로, 인프라 관리 없이 컨테이너화된 애플리케이션을 배포하고 관리할수 있도록 설계 되어 있다.
또한 Amazon ECS, EKS와 통합되어 컨테이너의 실행을 단순화 한다.

출처 : https://www.eksworkshop.com/docs/fundamentals/fargate/
KVM 기반의 경량 가상화 기술로, 마이크로 VM 을 통해 컨테이너의 효율성과 VM의 격리 보안을 결합한 오픈 소스 솔루션이다.

출처 : https://github.com/firecracker-microvm/firecracker/blob/main/docs/design.md

출처 : https://github.com/firecracker-microvm/firecracker/blob/main/docs/design.md
공식적으로 작성된 Fargate Architecture 가 존재하지 않아 정확하게 확인 할 수는 없으나 몇가지 기능을 통하여 추측해 볼수 있다.

출처 : 기시다 AEWS 3기 스터디 - 7주차
즉, Fargate는 EKS 클러스터에서 자동으로 파드를 배포하고 관리하며, 외부 통신 시 NAT Gateway와 IGW를 통해 연결하고, 인입 트래픽은 ALB/NLB를 통해 파드로 전달된다

출처 : 기시다 AEWS 3기 스터디 - 7주차
#
git clone https://github.com/aws-ia/terraform-aws-eks-blueprints
tree terraform-aws-eks-blueprints/patterns
cd terraform-aws-eks-blueprints/patterns/fargate-serverless
리전 등 일부 실습 편리를 위해 수정, Sample App 배포 부분 삭제
provider "aws" {
region = local.region
}
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
# This requires the awscli to be installed locally where Terraform is executed
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
}
}
provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
# This requires the awscli to be installed locally where Terraform is executed
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
}
}
}
data "aws_availability_zones" "available" {
# Do not include local zones
filter {
name = "opt-in-status"
values = ["opt-in-not-required"]
}
}
locals {
name = basename(path.cwd)
region = "ap-northeast-2"
vpc_cidr = "10.10.0.0/16"
azs = slice(data.aws_availability_zones.available.names, 0, 3)
tags = {
Blueprint = local.name
GithubRepo = "github.com/aws-ia/terraform-aws-eks-blueprints"
}
}
################################################################################
# Cluster
################################################################################
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.11"
cluster_name = local.name
cluster_version = "1.30"
cluster_endpoint_public_access = true
# Give the Terraform identity admin access to the cluster
# which will allow resources to be deployed into the cluster
enable_cluster_creator_admin_permissions = true
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
# Fargate profiles use the cluster primary security group so these are not utilized
create_cluster_security_group = false
create_node_security_group = false
fargate_profiles = {
study_wildcard = {
selectors = [
{ namespace = "study-*" }
]
}
kube_system = {
name = "kube-system"
selectors = [
{ namespace = "kube-system" }
]
}
}
fargate_profile_defaults = {
iam_role_additional_policies = {
additional = module.eks_blueprints_addons.fargate_fluentbit.iam_policy[0].arn
}
}
tags = local.tags
}
################################################################################
# EKS Blueprints Addons
################################################################################
module "eks_blueprints_addons" {
source = "aws-ia/eks-blueprints-addons/aws"
version = "~> 1.16"
cluster_name = module.eks.cluster_name
cluster_endpoint = module.eks.cluster_endpoint
cluster_version = module.eks.cluster_version
oidc_provider_arn = module.eks.oidc_provider_arn
# We want to wait for the Fargate profiles to be deployed first
create_delay_dependencies = [for prof in module.eks.fargate_profiles : prof.fargate_profile_arn]
# EKS Add-ons
eks_addons = {
coredns = {
configuration_values = jsonencode({
computeType = "Fargate"
# Ensure that the we fully utilize the minimum amount of resources that are supplied by
# Fargate https://docs.aws.amazon.com/eks/latest/userguide/fargate-pod-configuration.html
# Fargate adds 256 MB to each pod's memory reservation for the required Kubernetes
# components (kubelet, kube-proxy, and containerd). Fargate rounds up to the following
# compute configuration that most closely matches the sum of vCPU and memory requests in
# order to ensure pods always have the resources that they need to run.
resources = {
limits = {
cpu = "0.25"
# We are targeting the smallest Task size of 512Mb, so we subtract 256Mb from the
# request/limit to ensure we can fit within that task
memory = "256M"
}
requests = {
cpu = "0.25"
# We are targeting the smallest Task size of 512Mb, so we subtract 256Mb from the
# request/limit to ensure we can fit within that task
memory = "256M"
}
}
})
}
vpc-cni = {}
kube-proxy = {}
}
# Enable Fargate logging this may generate a large ammount of logs, disable it if not explicitly required
enable_fargate_fluentbit = true
fargate_fluentbit = {
flb_log_cw = true
}
enable_aws_load_balancer_controller = true
aws_load_balancer_controller = {
set = [
{
name = "vpcId"
value = module.vpc.vpc_id
},
{
name = "podDisruptionBudget.maxUnavailable"
value = 1
},
]
}
tags = local.tags
}
################################################################################
# Supporting Resources
################################################################################
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = local.name
cidr = local.vpc_cidr
azs = local.azs
private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
enable_nat_gateway = true
single_nat_gateway = true
public_subnet_tags = {
"kubernetes.io/role/elb" = 1
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = 1
}
tags = local.tags
}
terraform init
tree .terraform
cat .terraform/modules/modules.json | jq
tree .terraform/providers/registry.terraform.io/hashicorp -L 2
# plan
terraform plan




# 배포 : EKS, Add-ons, fargate profile - 13분 소요
terraform apply -auto-approve
# 배포 완료 후 확인
terraform state list
terraform output
# EKS 자격증명
$(terraform output -raw configure_kubectl) # aws eks --region ap-northeast-2 update-kubeconfig --name fargate-serverless
cat ~/.kube/config
# kubectl context 변경
kubectl ctx
kubectl config rename-context "arn:aws:eks:ap-northeast-2:$(aws sts get-caller-identity --query 'Account' --output text):cluster/fargate-serverless" "fargate-lab"
# k8s 노드, 파드 정보 확인
kubectl ns default
kubectl cluster-info
kubectl get node
kubectl get pod -A
# 상세 정보 확인
terraform show
terraform state list








# k8s api service 확인 : ENDPOINTS 의 IP는 EKS Owned-ENI 2개
kubectl get svc,ep
# node 확인 : 노드(Micro VM) 4대
kubectl get csr
kubectl get node -owide
kubectl describe node | grep eks.amazonaws.com/compute-type
# 파드 확인 : 파드의 IP와 노드의 IP가 같다!
kubectl get pdb -n kube-system
kubectl get pod -A -owide
# aws-load-balancer-webhook-service , eks-extension-metrics-api?
kubectl get svc,ep -n kube-system
# eks-extension-metrics-api?
kubectl get apiservices.apiregistration.k8s.io | grep eks
kubectl get --raw "/apis/metrics.eks.amazonaws.com" | jq
kubectl get --raw "/apis/metrics.eks.amazonaws.com/v1" | jq
# configmap 확인
kubectl get cm -n kube-system
...
# aws-auth 보다 우선해서 IAM access entry 가 있음을 참고.
# 기본 관리노드 보다 system:node-proxier 그룹이 추가되어 있음.
# fargate profile 이 2개인데, 그 profile 갯수만큼 있음.
kubectl get cm -n kube-system aws-auth -o yaml
kubectl rbac-tool lookup system:node-proxier
kubectl rolesum -k Group system:node-proxier
#
kubectl get cm -n kube-system amazon-vpc-cni -o yaml
# coredns 설정 내용
kubectl get cm -n kube-system coredns -o yaml
# 인증서 작성되어 있음 : client-ca-file , requestheader-client-ca-file
kubectl get cm -n kube-system extension-apiserver-authentication -o yaml
#
kubectl get cm -n kube-system kube-proxy -o yaml
kubectl get cm -n kube-system kube-proxy-config -o yaml
# coredns 파드 상세 정보 확인
kubectl get pod -n kube-system -l k8s-app=kube-dns -o yaml



파드의 IP와 노드의 IP가 같다.
















# helm 배포
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system
# 포트 포워딩
kubectl port-forward deployment/kube-ops-view -n kube-system 8080:8080 &
# kube-ops-vieww 접근
open "http://127.0.0.1:8080/#scale=1.5" # macOS



# node 확인 : 노드(Micro VM)
kubectl get csr
kubectl get node -owide
kubectl describe node | grep eks.amazonaws.com/compute-type
# 디플로이먼트 상세 정보
kubectl get deploy -n kube-system kube-ops-view -o yaml
# 파드 상세 정보 : admission control 이 동작했음을 알 수 있음
kubectl get pod -n kube-system -l app.kubernetes.io/instance=kube-ops-view -o yaml
#
kubectl describe pod -n kube-system -l app.kubernetes.io/instance=kube-ops-view | grep Events: -A10





cpu 500m, memory 1GiB로 생성된다.| vCPU value | Memory value |
|---|---|
| .25 vCPU | 0.5 GB, 1 GB, 2 GB |
| .5 vCPU | 1 GB, 2 GB, 3 GB, 4 GB |
| 1 vCPU | 2 GB, 3 GB, 4 GB, 5 GB, 6 GB, 7 GB, 8 GB |
| 2 vCPU | Between 4 GB and 16 GB in 1-GB increments |
| 4 vCPU | Between 8 GB and 30 GB in 1-GB increments |
| 8 vCPU | Between 16 GB and 60 GB in 4-GB increments |
| 16 vCPU | Between 32 GB and 120 GB in 8-GB increments |
# 네임스페이스 생성
kubectl create ns study-aews
# 테스트용 파드 netshoot 디플로이먼트 생성 : 0.5vCPU 1GB 할당되어, 아래 Limit 값은 의미가 없음. 배포 시 대략 시간 측정해보자!
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot
namespace: study-aews
spec:
replicas: 1
selector:
matchLabels:
app: netshoot
template:
metadata:
labels:
app: netshoot
spec:
containers:
- name: netshoot
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
resources:
requests:
cpu: 500m
memory: 500Mi
limits:
cpu: 2
memory: 2Gi
terminationGracePeriodSeconds: 0
EOF
kubectl get events -w --sort-by '.lastTimestamp'
# 확인 : 메모리 할당 측정은 어떻게 되었는지?
kubectl get pod -n study-aews -o wide
kubectl get pod -n study-aews -o jsonpath='{.items[0].metadata.annotations.CapacityProvisioned}'
0.5vCPU 1GB
# 디플로이먼트 상세 정보
kubectl get deploy -n study-aews netshoot -o yaml
...
template:
...
spec:
...
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 0
...
# 파드 상세 정보 : admission control 이 동작했음을 알 수 있음
kubectl get pod -n study-aews -l app=netshoot -o yaml
...
metadata:
annotations:
CapacityProvisioned: 0.5vCPU 1GB
Logging: LoggingEnabled
...
preemptionPolicy: PreemptLowerPriority
priority: 2000001000
priorityClassName: system-node-critical
restartPolicy: Always
schedulerName: fargate-scheduler
...
qosClass: Burstable
#
kubectl describe pod -n study-aews -l app=netshoot | grep Events: -A10
# Mutating Webhook, Validating Webhook 확인
kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io
kubectl describe mutatingwebhookconfigurations 0500-amazon-eks-fargate-mutation.amazonaws.com
kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io
-----------------------------------------------------

cpu 500m, memory 500MiB으로 설정하였으나 memory는 1GiB로 세팅됨








kubectl exec -it deploy/netshoot -n study-aews -- zsh
-----------------------------------------------------
ip -c a
cat /etc/resolv.conf
curl ipinfo.io/ip # 출력되는 IP는 어떤것? , 어떤 경로를 통해서 인터넷이 되는 걸까?
ping -c 1 <다른 파드 IP ex. coredns pod ip>
lsblk
df -hT /
cat /etc/fstab
exit



fargate의 경우는 탈취 시도가 어려움, fargate 가 아닌 경우
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: root-shell
namespace: study-aews
spec:
containers:
- command:
- /bin/cat
image: alpine:3
name: root-shell
securityContext:
privileged: true
tty: true
stdin: true
volumeMounts:
- mountPath: /host
name: hostroot
hostNetwork: true
hostPID: true
hostIPC: true
tolerations:
- effect: NoSchedule
operator: Exists
- effect: NoExecute
operator: Exists
volumes:
- hostPath:
path: /
name: hostroot
EOF
kubectl get pod -n study-aews root-shell
kubectl describe pod -n study-aews root-shell | grep Events: -A 10
# 테스트 후 삭제
kubectl delete pod -n study-aews root-shell

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: study-aews
name: deployment-2048
spec:
selector:
matchLabels:
app.kubernetes.io/name: app-2048
replicas: 2
template:
metadata:
labels:
app.kubernetes.io/name: app-2048
spec:
containers:
- image: public.ecr.aws/l6m2t8p7/docker-2048:latest
imagePullPolicy: Always
name: app-2048
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: study-aews
name: service-2048
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: ClusterIP
selector:
app.kubernetes.io/name: app-2048
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: study-aews
name: ingress-2048
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service-2048
port:
number: 80
EOF
# 모니터링
watch -d kubectl get pod,ingress,svc,ep,endpointslices -n study-aews
# 생성 확인
kubectl get-all -n study-aews
kubectl get ingress,svc,ep,pod -n study-aews
kubectl get targetgroupbindings -n study-aews
# Ingress 확인
kubectl describe ingress -n study-aews ingress-2048
kubectl get ingress -n study-aews ingress-2048 -o jsonpath="{.status.loadBalancer.ingress[*].hostname}{'\n'}"
# 게임 접속 : ALB 주소로 웹 접속
kubectl get ingress -n study-aews ingress-2048 -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | awk '{ print "Game URL = http://"$1 }'
# 파드 IP 확인
kubectl get pod -n study-aews -owide
# 파드 증가
kubectl scale deployment -n study-aews deployment-2048 --replicas 4
# 게임 실습 리소스 삭제
kubectl delete ingress ingress-2048 -n study-aews
kubectl delete svc service-2048 -n study-aews && kubectl delete deploy deployment-2048 -n study-aews







확인 : 노드 7개 → 9개로 증가 되는 것을 확인


Fargate의 EKS는 별도의 Fluent Bit 사이드 카 없이 내장 로그 라우터를 제공한다.
aws-logging, 네임스페이스는 aws-observability, 5300자 이하cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-app
namespace: study-aews
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:latest
name: nginx
ports:
- containerPort: 80
name: http
resources:
requests:
cpu: 500m
memory: 500Mi
limits:
cpu: 2
memory: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: sample-app
namespace: study-aews
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
protocol: TCP
type: ClusterIP
EOF
# 확인
kubectl get pod -n study-aews -l app=nginx
kubectl describe pod -n study-aews -l app=nginx
# 반복 접속
kubectl exec -it deploy/sample-app -n study-aews -- curl sample-app | grep title
while true; do kubectl exec -it deploy/sample-app -n study-aews -- curl sample-app | grep title; sleep 1; echo ; date; done;
# 로그 확인
kubectl stern -n study-aews -l app=nginx


#aws-observability라는 이름의 전용 네임스페이스 확인
kubectl get ns --show-labels
# Fluent Conf 데이터 값이 포함된 ConfigMap : 컨테이너 로그를 목적지로 배송 설정
## Amazon EKS Fargate 로깅은 ConfigMap의 동적 구성을 지원하지 않습니다.
## ConfigMap에 대한 모든 변경 사항은 새 포드에만 적용됩니다. 기존 포드에는 변경 사항이 적용되지 않습니다.
kubectl get cm -n aws-observability
kubectl get cm -n aws-observability aws-logging -o yaml




# 게임 실습 리소스 삭제
kubectl delete ingress ingress-2048 -n study-aews
kubectl delete svc service-2048 -n study-aews && kubectl delete deploy deployment-2048 -n study-aews
# netshoot 삭제
kubectl delete deploy netshoot -n study-aews
# kube-ops-view 삭제
helm uninstall kube-ops-view -n kube-system# 테라폼 삭제 : vpc 삭제가 잘 안될 경우 aws 콘솔에서 vpc 수동 삭제 -> vnic 등 남아 있을 경우 해당 vnic 강제 삭제
terraform destroy -auto-approve
# VPC 삭제 확인
aws ec2 describe-vpcs --filter 'Name=isDefault,Values=false' --output yaml
# kubeconfig 삭제
rm -rf ~/.kube/configEKS Auto Mode는 클러스터 관리 작업은 AWS으로 넘김으로서 k8s 실행을 간소화 하고, 애플리케이션의 성능 및 보안을 강화하며, 컴퓨팅 비용을 최적화하는데 초점을 맞췄다.
기존에 사용해오던 EKS는 기본적으로 다음과 같이 구성되었다.

출처 : AWS re:Invent 2024 - The future of Kubernetes on AWS (KUB201)
EKS Auto Mode에서는 아래와 같이 AWS에 더 많은 부분을 관리하도록 하였다.

출처 : AWS re:Invent 2024 - The future of Kubernetes on AWS (KUB201)

위와 같이 compute, network, storage, observe에 관한 driver들과 addon들은 모두 AWS에서 관리해준다.
고객 관리 영역에는 OSS/ETC들이 존재한다.
git clone https://github.com/aws-samples/sample-aws-eks-auto-mode.git
cd sample-aws-eks-auto-mode/terraform
# eks.tf : "system" 은 '전용인스턴스'로 추가하지 않는다
...
cluster_compute_config = {
enabled = true
node_pools = ["general-purpose"]
}
...
variable "name" {
description = "Name of the VPC and EKS Cluster"
default = "automode-cluster"
type = string
}
variable "region" {
description = "region"
default = "ap-northeast-2"
type = string
}
variable "eks_cluster_version" {
description = "EKS Cluster version"
default = "1.31"
type = string
}
# VPC with 65536 IPs (10.0.0.0/16) for 3 AZs
variable "vpc_cidr" {
description = "VPC CIDR. This should be a valid private (RFC 1918) CIDR range"
default = "10.20.0.0/16"
type = string
}
terraform init
terraform plan
terraform apply -auto-approve
#kube config 설정
$(terraform output -raw configure_kubectl)
# kubectl context 변경
kubectl ctx
kubectl config rename-context "arn:aws:eks:ap-northeast-2:$(aws sts get-caller-identity --query 'Account' --output text):cluster/automode-cluster" "automode-lab"
kubectl ns default
kubectl get svc,ep 
terraform state list
terraform show
terraform state show 'module.eks.aws_eks_cluster.this[0]'


kubectl get crd
kubectl api-resources | grep -i node
kubectl get nodeclasses.eks.amazonaws.com
kubectl get nodepools
kubectl get mutatingwebhookconfiguration
kubectl get validatingwebhookconfiguration









disruption.budgets 에 평일 오전 9시~17시에는 disruption 동작하지 않게 설정 및 검증 해보기# 모니터링
eks-node-viewer --node-sort=eks-node-viewer/node-cpu-usage=dsc --extra-labels eks-node-viewer/node-age
watch -d kubectl get node,pod -A
# helm 배포
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system
kubectl get events -w --sort-by '.lastTimestamp' # 출력 이벤트 로그 분석해보자
# 확인
kubectl get nodeclaims
NAME TYPE CAPACITY ZONE NODE READY AGE
general-purpose-528mt c5a.large on-demand ap-northeast-2c i-09cf206aee76f0bee True 54s
# OS, KERNEL, CRI 확인
kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
i-09cf206aee76f0bee Ready <none> 2m14s v1.31.4-eks-0f56d01 10.20.44.40 <none> Bottlerocket (EKS Auto) 2025.3.9 (aws-k8s-1.31) 6.1.129 containerd://1.7.25+bottlerocket
# CNI 노드 확인
kubectl get cninodes.eks.amazonaws.com
NAME AGE
i-09cf206aee76f0bee 3m24s
#[신규 터미널] 포트 포워딩
kubectl port-forward deployment/kube-ops-view -n kube-system 8080:8080 &
open "http://127.0.0.1:8080/#scale=1.5" # macO



)

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 1
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
terminationGracePeriodSeconds: 0
nodeSelector:
eks.amazonaws.com/compute-type: auto
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
resources:
requests:
cpu: 1
securityContext:
allowPrivilegeEscalation: false
EOF
kubectl get nodes
kubectl get pods

#
kubectl scale deployment inflate --replicas 100 && kubectl get events -w --sort-by '.lastTimestamp'
#
kubectl scale deployment inflate --replicas 99 && kubectl get events -w --sort-by '.lastTimestamp'
# 실습 확인 후 삭제
kubectl delete deployment inflate && kubectl get events -w --sort-by '.lastTimestamp'

# custom node pool 생성 : 고객 NodePool : Karpenter 와 키가 다르니 주의!
cat ../nodepools/graviton-nodepool.yaml
kubectl apply -f ../nodepools/graviton-nodepool.yaml
# Node Clsss 확인
kubectl get NodeClass
# Node Pool 확인
kubectl get NodePool
# game-2048 배포
kubectl apply -f ../examples/graviton/game-2048.yaml


# nodeclaims 확인
kubectl get nodeclaims
kubectl get cninodes.eks.amazonaws.com
eks-node-viewer --resources cpu,memory
kubectl get node -owide
kubectl describe node





EC2 - 1대 생성 확인


cat ../examples/graviton/2048-ingress.yaml
kubectl apply -f ../examples/graviton/2048-ingress.yaml
# 배포 확인
kubectl get ingressclass,ingressclassparams,ingress,svc,ep -n game-2048


# Get security group IDs
ALB_SG=$(aws elbv2 describe-load-balancers \
--query 'LoadBalancers[?contains(DNSName, `game2048`)].SecurityGroups[0]' \
--output text)
EKS_SG=$(aws eks describe-cluster \
--name automode-cluster \
--query 'cluster.resourcesVpcConfig.clusterSecurityGroupId' \
--output text)
echo $ALB_SG $EKS_SG # 해당 보안그룹을 관리콘솔에서 정책 설정 먼저 확인해보자
# Allow ALB to communicate with EKS cluster : 실습 환경 삭제 때, 미리 $EKS_SG에 추가된 규칙만 제거해둘것.
aws ec2 authorize-security-group-ingress \
--group-id $EKS_SG \
--source-group $ALB_SG \
--protocol tcp \
--port 80
# 아래 웹 주소로 http 접속!
kubectl get ingress ingress-2048 \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}' \
-n game-2048
k8s-game2048-ingress2-db993ba6ac-782663732.ap-northeast-2.elb.amazonaws.com


