실습
해당 실습을 AWS CloudShell에서 진행한다고 가정하고 작성되었습니다.
실습환경 구성
CLI 도구 설치
바이너리를 저장할 디렉토리 생성
{
mkdir ~/bin
echo export PATH="$HOME/bin:$PATH" >> ~/.bashrc
export PATH="$HOME/bin:$PATH"
}
eksctl 설치
{
curl -sL "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl $HOME/bin
echo 'source <(eksctl completion bash)' >>~/.bashrc
source <(eksctl completion bash)
}
helm 설치
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | HELM_INSTALL_DIR=$HOME/bin bash
Krew 설치
{
curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_amd64.tar.gz"
mkdir krew && tar zvxf krew-linux_amd64.tar.gz -C krew
./krew/krew-linux_amd64 install krew
rm krew-linux_amd64.tar.gz
rm -rf krew
echo export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH" >> ~/.bashrc
export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
}
EKS 클러스터 생성
ClusterConfig 생성
cat <<EOF > mycluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: mycluster
region: $AWS_REGION
version: "1.32"
availabilityZones:
- ${AWS_REGION}a
- ${AWS_REGION}b
- ${AWS_REGION}c
- ${AWS_REGION}d
managedNodeGroups:
- name: nodegroup
instanceType: t3.small
minSize: 2
desiredCapacity: 2
maxSize: 5
volumeSize: 20
iam:
attachPolicyARNs:
- arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
addonsConfig:
disableDefaultAddons: true
addons:
- name: vpc-cni
- name: kube-proxy
- name: coredns
EOF
EKS 클러스터 생성
eksctl create cluster --config-file=mycluster.yaml
Authentication
user에 명시된 명령어 실행
$(kubectl config view \
-o=jsonpath='{.users[0].user.exec.command} {.users[0].user.exec.args[*]}')
토큰값을 환경변수로 지정 - Base64로 인코딩된 부분만 캡쳐
{
export TOKEN=$($(kubectl config view \
-o=jsonpath='{.users[0].user.exec.command} {.users[0].user.exec.args[*]}') \
| jq -r '.status.token' | grep -oP '(?<=k8s-aws-v1.).*')
echo $TOKEN
}
Base64URL 유틸리티 설치
{
mkdir $HOME/node
sudo npm install -g --prefix $HOME/node base64-url-cli
echo export PATH="$HOME/node/bin:$PATH" >> ~/.bashrc
export PATH="$HOME/node/bin:$PATH"
}
토큰값을 디코딩해서 환경변수로 지정
{
export DECODED_URL=$(base64url decode $TOKEN)
echo $DECODED_URL
}
Node에 부여된 Label을 통해서 EKS 클러스터 이름 확인하고 환경변수로 저장
{
export CLUSTER_NAME=$(kubectl get node \
-o=jsonpath='{.items[0].metadata.labels.alpha\.eksctl\.io\/cluster-name}')
echo $CLUSTER_NAME
}
디코딩한 URL 호출 - HTTP 헤더에 클러스터 이름 추가
curl -H "x-k8s-aws-id: $CLUSTER_NAME" $DECODED_URL
현재 설정된 AWS 자격증명을 확인
aws sts get-caller-identity
API 서버 주소를 확인하고 환경변수로 지정
{
export K8S_SERVER=$(kubectl config view \
-o=jsonpath='{.clusters[*].cluster.server}')
echo $K8S_SERVER
}
Node 목록을 보는 API 호출
curl -k -X GET \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
$K8S_SERVER/api/v1/nodes
토큰값을 환경변수로 지정
{
export TOKEN=$($(kubectl config view \
-o=jsonpath='{.users[0].user.exec.command} {.users[0].user.exec.args[*]}') \
| jq -r '.status.token')
echo $TOKEN
}
Node 목록을 보는 API 호출
curl -k -X GET \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
$K8S_SERVER/api/v1/nodes
IAM 유저 생성
aws iam create-user --user-name john
위에서 생성한 IAM 유저의 Access Key 생성
aws iam create-access-key --user-name john > key.txt
Access Key가 정상적으로 생성되었는지 확인
위에서 생성한 Access Key를 AWS CLI 자격증명 파일에 반영
{
mkdir -p ~/.aws
touch ~/.aws/credentials
touch ~/.aws/config
cat <<EOF >> ~/.aws/credentials
[john]
aws_access_key_id=$(cat key.txt | jq -r '.AccessKey.AccessKeyId')
aws_secret_access_key=$(cat key.txt | jq -r '.AccessKey.SecretAccessKey')
EOF
cat <<EOF >> ~/.aws/config
[profile john]
region = $AWS_REGION
EOF
}
위에서 명시한 프로필을 통해서 AWS API 호출
aws sts get-caller-identity --profile john
kubeconfig 파일 삭제
rm -rf ~/.kube/config
새로 생성한 IAM 유저의 자격증명으로 AWS CLI를 이용해서 kubeconfig 파일 생성
aws eks update-kubeconfig --name $CLUSTER_NAME --profile john
IAM 유저에서 eks:DescribeCluster 권한 부여
aws iam put-user-policy --user-name john --policy-name eks-describe --policy-document \
'{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"eks:DescribeCluster"
],
"Resource": "*",
"Effect": "Allow"
}
]
}'
IAM 정책이 부여되었는지 확인
{
aws iam list-user-policies --user-name john --no-cli-pager
aws iam get-user-policy --user-name john --policy-name eks-describe --no-cli-pager
}
새로 생성한 IAM 유저의 자격증명으로 AWS CLI를 이용해서 kubeconfig 파일 생성 - 정책 적용까지 시간이 걸릴수 있음
aws eks update-kubeconfig --name $CLUSTER_NAME --profile john
인증 토큰 검증
{
export AWS_PROFILE=john
export TOKEN=$($(kubectl config view \
-o=jsonpath='{.users[0].user.exec.command} {.users[0].user.exec.args[*]}') \
| jq -r '.status.token' | grep -oP '(?<=k8s-aws-v1.).*')
export DECODED_URL=$(base64url decode $TOKEN)
curl -v -H "x-k8s-aws-id: $CLUSTER_NAME" $DECODED_URL
}
EKS 클러스터를 생성한 IAM 유저의 자격증명으로 AWS CLI를 이용해서 kubeconfig 파일 업데이트
{
rm -rf ~/.kube/config
unset AWS_PROFILE
aws eks update-kubeconfig --name $CLUSTER_NAME
}
Authorization
EKS 클러스터에 설정된 Access Entry 확인
aws eks list-access-entries --cluster-name $CLUSTER_NAME
EKS 클러스터를 생성한 IAM 유저의 Access Entry 확인
aws eks describe-access-entry --cluster-name $CLUSTER_NAME \
--principal-arn $(aws sts get-caller-identity --query 'Arn' --output text)
AWS Workshop Studio를 통해서 로그인할 경우에는 IAM 역할을 사용하므로 아래의 명령어 실행
aws eks describe-access-entry --cluster-name $CLUSTER_NAME \
--principal-arn $(aws sts get-caller-identity --query 'Arn' --output text |\
sed -e 's#assumed-role#role#' -e 's#/[^/]*$##' | sed -e 's#sts#iam#')
EKS 클러스터를 생성한 IAM 유저에 부여된 Access Policy 확인
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME \
--principal-arn $(aws sts get-caller-identity --query 'Arn' --output text)
AWS Workshop Studio를 통해서 로그인할 경우에는 IAM 역할을 사용하므로 아래의 명령어 실행
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME \
--principal-arn $(aws sts get-caller-identity --query 'Arn' --output text |\
sed -e 's#assumed-role#role#' -e 's#/[^/]*$##' | sed -e 's#sts#iam#')
현재 kubeconfig에 설정된 유저의 자격증명으로 수행할수 있는 API 목록 확인
kubectl auth can-i --list
EKS 클러스터에 설정된 Access Entry 확인
aws eks list-access-entries --cluster-name $CLUSTER_NAME
한개의 Node의 인스턴스 ID를 확인하고 환경변수로 지정
{
export INSTANCE_ID=$(kubectl get node -o jsonpath='{.items[0].spec.providerID}' \
| grep -oE "i-[a-z0-9]+")
echo $INSTANCE_ID
}
Node에 부여된 IAM 인스턴스 프로필을 확인하고 환경변수로 지정
{
export INSTANCE_PROFILE=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID \
--query 'Reservations[0].Instances[0].IamInstanceProfile.Arn' \
--output text | grep -oE "[a-z0-9-]+$")
echo $INSTANCE_PROFILE
}
위에서 확인한 인스턴스 프로필에 연동된 IAM 역할 확인
{
export INSTANCE_ROLE=$(aws iam get-instance-profile --instance-profile-name $INSTANCE_PROFILE \
--query 'InstanceProfile.Roles[0].Arn' --output text)
echo $INSTANCE_ROLE
}
Node에 부여된 IAM 역할의 Access Entry 확인
aws eks describe-access-entry --cluster-name $CLUSTER_NAME \
--principal-arn $INSTANCE_ROLE
Node에 부여된 IAM 역할에 부여된 Access Policy 확인
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME \
--principal-arn $INSTANCE_ROLE
Kubernetes RBAC을 쉽게 확인할수 있는 플러그인 설치
kubectl krew install rbac-tool
Node에 부여된 IAM 역할에 연동된 쿠버네티스 그룹에 부여된 권한 확인
kubectl rbac-tool lookup -e system:nodes
ClusterRole 목록 확인
kubectl get clusterrole
eks:node-bootstrapper ClusterRole 리뷰
kubectl get clusterrole eks:node-bootstrapper -o yaml
ClusterRoleBinding 목록 확인
kubectl get clusterrolebinding
eks:node-bootstrapper ClusterRoleBinding 리뷰
kubectl get clusterrolebinding eks:node-bootstrapper -o yaml
EKS 클러스터가 생성되어 있는 AWS 계정번호 확인하고 환경변수로 저장
{
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo $ACCOUNT_ID
}
위에서 새로 생성한 IAM 유저에 EKS Access Entry 생성
aws eks create-access-entry --cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::$ACCOUNT_ID:user/john
IAM 유저에서 kube-system 네임스페이스에 대한 읽기 권한을 부여
aws eks associate-access-policy \
--cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::$ACCOUNT_ID:user/john \
--policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminViewPolicy \
--access-scope type=namespace,namespaces=kube-system
IAM 유저의 자격증명으로 AWS CLI를 이용해서 kubeconfig 파일 업데이트
{
rm -rf ~/.kube/config
aws eks update-kubeconfig --name $CLUSTER_NAME --profile john
}
kube-system 네임스페이스에 생성된 모든 Pod 목록 확인
kubectl get pod -n kube-system
kube-system 네임스페이스에 Pod 생성 시도
kubectl run nginx --image=nginx -n kube-system
IAM 역할 생성
{
cat > trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::$ACCOUNT_ID:root"
]
},
"Action": "sts:AssumeRole"
}
]
}
EOF
aws iam create-role --role-name eks-admin-role \
--assume-role-policy-document file://trust-policy.json
}
위에서 새로 생성한 IAM 역할에 EKS Access Entry 생성
aws eks create-access-entry \
--cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::$ACCOUNT_ID:role/eks-admin-role
IAM 역할에 EKS 클러스터 어드민 권한 부여
aws eks associate-access-policy \
--cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::$ACCOUNT_ID:role/eks-admin-role \
--policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy \
--access-scope type=cluster
IAM 유저의 자격증명으로 위에서 생성한 IAM 역할 전환하는 설정 추가해서 kubeconfig 파일 업데이트
{
rm -rf ~/.kube/config
aws eks update-kubeconfig --name $CLUSTER_NAME --profile john \
--role-arn arn:aws:iam::$ACCOUNT_ID:role/eks-admin-role
}
IAM 유저에서 sts:AssumeRole 권한 부여
aws iam put-user-policy --user-name john --policy-name assume-role --policy-document \
'{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Resource": "*",
"Effect": "Allow"
}
]
}'
IAM 정책이 부여되었는지 확인
{
aws iam list-user-policies --user-name john
aws iam get-user-policy --user-name john --policy-name assume-role
}
쿠버네티스 API 호출 시도 - 정책 적용까지 시간이 걸릴수 있음
user에 명시된 명령어 실행
{
export $(kubectl config view -o=jsonpath='{.users[0].user.exec.env[0].name}={.users[0].user.exec.env[0].value}')
$(kubectl config view \
-o=jsonpath='{.users[0].user.exec.command} {.users[0].user.exec.args[*]}')
}
토큰값을 환경변수로 지정 - Base64로 인코딩된 부분만 캡쳐
{
export AWS_PROFILE=john
export TOKEN=$($(kubectl config view \
-o=jsonpath='{.users[0].user.exec.command} {.users[0].user.exec.args[*]}') \
| jq -r '.status.token' | grep -oP '(?<=k8s-aws-v1.).*')
echo $TOKEN
}
토큰값을 디코딩해서 환경변수로 지정
{
export DECODED_URL=$(base64url decode $TOKEN)
echo $DECODED_URL
}
디코딩한 URL 호출
curl -H "x-k8s-aws-id: $CLUSTER_NAME" $DECODED_URL
AWS 관리콘솔에 로그인된 IAM 자격증명으로 AWS CLI를 이용해서 kubeconfig 파일 업데이트
{
rm -rf ~/.kube/config
unset AWS_PROFILE
aws eks update-kubeconfig --name $CLUSTER_NAME
}
리소스 삭제
{
aws iam delete-access-key --user-name john --access-key-id $(cat key.txt | jq -r '.AccessKey.AccessKeyId')
aws iam delete-user-policy --user-name john --policy-name eks-describe
aws iam delete-user-policy --user-name john --policy-name assume-role
aws iam delete-user --user-name john
aws iam delete-role --role-name eks-admin-role
aws eks delete-access-entry --cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::$ACCOUNT_ID:user/john
aws eks delete-access-entry \
--cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::$ACCOUNT_ID:role/eks-admin-role
rm ~/.aws/credentials ~/.aws/config
rm key.txt trust-policy.json
}
Scheduling
Manual Scheduling
Pod 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
nodeName: worker-1
EOF
Pod 상태 확인
kubectl get pod nginx
위의 명령어를 실행하면 아래와 같은 결과를 확인할수 있습니다.
NAME READY STATUS RESTARTS AGE
nginx 0/1 Pending 0 4s
Pod 상태를 모니터링
watch kubectl get pod nginx
spec.nodeName에 위의 명령어의 결과로 나온 첫번째 노드 이름을 넣고 Pod를 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
nodeName: $(kubectl get node -o=jsonpath='{.items[0].metadata.name}')
EOF
Pod 상태 확인
kubectl get pod nginx
spec.nodeName을 명시하지 않고 Pod 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: httpd
spec:
containers:
- image: httpd
name: httpd
EOF
spec.nodeName을 명시하지 않고 생성한 Pod에 발생한 Event 확인
kubectl describe pod httpd
spec.nodeName을 명시하고 생성한 Pod에 발생한 Event 확인
kubectl describe pod nginx
Pod 삭제
kubectl delete pod nginx httpd
Node Selector
Pod 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
nodeSelector:
env: dev
EOF
Pod 상태 확인
kubectl get pod nginx
위의 명령어를 실행하면 아래와 같은 결과를 확인할수 있습니다.
NAME READY STATUS RESTARTS AGE
nginx 0/1 Pending 0 16s
아래의 명령어를 사용해서 Pod가 배포되지 않는 이유를 찾으세요.
kubectl describe pod nginx
Node에 부여된 Label 확인
kubectl get node --show-labels
두번째 노드에 키(Key)는 env 이고 값(Value)은 dev 인 Label 부여
kubectl label node \
$(kubectl get node -o=jsonpath='{.items[1].metadata.name}') env=dev
Node에 Label이 부여되었는지 확인
kubectl get node --show-labels | grep -E 'env=dev|$'
Pending 상태였던 Pod가 배포됐는지 확인
kubectl get pod nginx
Pod에 발생한 Event 확인
kubectl describe pod nginx
Node에 부여한 Label 삭제
kubectl label node \
$(kubectl get node -o=jsonpath='{.items[1].metadata.name}') env-
Node에 Label이 삭제되었는지 확인
kubectl get node --show-labels | grep -E 'env=dev|$'
Pod 상태 확인
kubectl get pod nginx
Pod 삭제
kubectl delete pod nginx
Spread Pod Across Cluster
Node에 부여된 Label을 통해서 Node가 생성된 가용영역 확인
kubectl get node \
-o custom-columns=NAME:.metadata.name,AvailabilityZone:".metadata.labels.topology\.kubernetes\.io/zone"
첫번째 Node의 가용영역 확인
kubectl get node \
-o=jsonpath='{.items[0].metadata.labels.topology\.kubernetes\.io/zone}{"\n"}'
nodeSelector를 명시한 Pod 생성
for s in web api storage database
do
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: ${s}
labels:
app: myapp
spec:
nodeSelector:
topology.kubernetes.io/zone: $(kubectl get node -o=jsonpath='{.items[0].metadata.labels.topology\.kubernetes\.io/zone}')
containers:
- image: busybox
name: busybox
command: ["/bin/sleep"]
args: ["infinity"]
EOF
done
각 Pod가 배포된 Node 확인
kubectl get pod -l app=myapp -o wide -A --sort-by=.spec.nodeName
각 Node별로 배포된 Pod 갯수 확인
kubectl describe node | grep -E "(^Name:|^Non-terminated)"
nodeSelector를 명시하지 않은 Pod 생성
for i in {1..4}
do
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: nginx-${i}
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
EOF
done
각 Pod가 배포된 Node 확인
kubectl get pod -l app=nginx -o wide --sort-by=.spec.nodeName
각 Node별로 배포된 Pod 갯수 확인
kubectl describe node | grep -E "(^Name:|^Non-terminated)"
위에서 nodeSelector를 명시하지 않고 생성한 Pod 삭제
kubectl delete pod -l app=nginx
각 Node별로 배포된 Pod 갯수 확인
kubectl describe node | grep -E "(^Name:|^Non-terminated)"
Deployment 생성
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
EOF
Deployment를 통해서 생성된 Pod들이 배포된 Node 확인
kubectl get pod -l app=nginx -o wide --sort-by=.spec.nodeName
EKS 설정창에서 Scheduler의 로깅을 활성화하면 CloudWatch를 통해서 아래와 같은 구성으로 kube-scheduler가 구동되는 것을 확인 가능
apiVersion: kubescheduler.config.k8s.io/v1beta1
clientConnection:
acceptContentTypes: ""
burst: 100
contentType: application/vnd.kubernetes.protobuf
kubeconfig: /etc/kubernetes/scheduler.conf
qps: 50
enableContentionProfiling: true
enableProfiling: true
healthzBindAddress: 0.0.0.0:10251
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: true
leaseDuration: 15s
renewDeadline: 10s
resourceLock: leases
resourceName: kube-scheduler
resourceNamespace: kube-system
retryPeriod: 2s
metricsBindAddress: 0.0.0.0:10251
parallelism: 16
percentageOfNodesToScore: 0
podInitialBackoffSeconds: 1
podMaxBackoffSeconds: 10
profiles:
- pluginConfig:
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: DefaultPreemptionArgs
minCandidateNodesAbsolute: 100
minCandidateNodesPercentage: 10
name: DefaultPreemption
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta1
hardPodAffinityWeight: 1
kind: InterPodAffinityArgs
name: InterPodAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: NodeAffinityArgs
name: NodeAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: NodeResourcesFitArgs
name: NodeResourcesFit
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: NodeResourcesLeastAllocatedArgs
resources:
- name: cpu
weight: 1
- name: memory
weight: 1
name: NodeResourcesLeastAllocated
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta1
defaultingType: System
kind: PodTopologySpreadArgs
name: PodTopologySpread
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta1
bindTimeoutSeconds: 600
kind: VolumeBindingArgs
name: VolumeBinding
plugins:
bind:
enabled:
- name: DefaultBinder
weight: 0
filter:
enabled:
- name: NodeUnschedulable
weight: 0
- name: NodeName
weight: 0
- name: TaintToleration
weight: 0
- name: NodeAffinity
weight: 0
- name: NodePorts
weight: 0
- name: NodeResourcesFit
weight: 0
- name: VolumeRestrictions
weight: 0
- name: EBSLimits
weight: 0
- name: GCEPDLimits
weight: 0
- name: NodeVolumeLimits
weight: 0
- name: AzureDiskLimits
weight: 0
- name: VolumeBinding
weight: 0
- name: VolumeZone
weight: 0
- name: PodTopologySpread
weight: 0
- name: InterPodAffinity
weight: 0
permit: {}
postBind: {}
postFilter:
enabled:
- name: DefaultPreemption
weight: 0
preBind:
enabled:
- name: VolumeBinding
weight: 0
preFilter:
enabled:
- name: NodeResourcesFit
weight: 0
- name: NodePorts
weight: 0
- name: PodTopologySpread
weight: 0
- name: InterPodAffinity
weight: 0
- name: VolumeBinding
weight: 0
- name: NodeAffinity
weight: 0
preScore:
enabled:
- name: InterPodAffinity
weight: 0
- name: PodTopologySpread
weight: 0
- name: TaintToleration
weight: 0
- name: NodeAffinity
weight: 0
queueSort:
enabled:
- name: PrioritySort
weight: 0
reserve:
enabled:
- name: VolumeBinding
weight: 0
score:
enabled:
- name: NodeResourcesBalancedAllocation
weight: 1
- name: ImageLocality
weight: 1
- name: InterPodAffinity
weight: 1
- name: NodeResourcesLeastAllocated
weight: 1
- name: NodeAffinity
weight: 1
- name: NodePreferAvoidPods
weight: 10000
- name: PodTopologySpread
weight: 2
- name: TaintToleration
weight: 1
schedulerName: default-scheduler
Deployment 삭제
kubectl delete deploy nginx
각 Node별로 배포된 Pod 갯수 확인
kubectl describe node | grep -E "(^Name:|^Non-terminated)"
podAntiAffinity를 명시하고 Pod 생성
for i in {1..4}
do
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: nginx-${i}
labels:
app: nginx
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
containers:
- image: nginx
name: nginx
EOF
done
위에서 생성한 Pod들이 배포된 Node 확인
kubectl get pod -l app=nginx -o wide --sort-by=.spec.nodeName
위에서 생성한 Pod 삭제
kubectl delete pod -l app=nginx
topologySpreadConstraints를 명시하고 Pod 생성
for i in {1..4}
do
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: nginx-${i}
labels:
app: nginx
spec:
topologySpreadConstraints:
- maxSkew: 3
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: nginx
containers:
- image: nginx
name: nginx
EOF
done
위에서 생성한 Pod들이 배포된 Node 확인
kubectl get pod -l app=nginx -o wide --sort-by=.spec.nodeName
리소스 삭제
kubectl delete pod -l 'app in (nginx,myapp)'
Scaling
Manual Scaling
Deployment 생성
kubectl create deployment nginx --image=nginx --replicas=1
Pod 갯수 확인
kubectl get pod -l app=nginx
Deployment의 replica를 3개로 수정
kubectl scale deployment nginx --replicas=3
Pod 갯수 확인
kubectl get pod -l app=nginx
ReplicaSet 확인
kubectl get rs -l app=nginx
Deployment의 replica를 2개로 수정
kubectl scale deployment nginx --replicas=2
Deployment의 replica가 1개라면 replica를 3개로 변경
kubectl scale deployment nginx --current-replicas=1 --replicas=3
새로운 Deployment 생성
kubectl create deployment httpd --image=httpd --replicas=1
Deployment 중에서 replica가 1개인 Deployment가 있으면 replica를 3개로 변경
kubectl scale deployment --current-replicas=1 --replicas=3 --all
Pod 갯수 확인
kubectl get pod -l 'app in (nginx,httpd)'
모든 Deployment의 replica를 5개로 변경
kubectl scale deployment --replicas=5 --all
Pod 갯수 확인
kubectl get pod -l 'app in (nginx,httpd)'
모든 Deployment 삭제
kubectl delete deployment -l 'app in (nginx,httpd)'
HPA (Horizontal Pod Autoscaler)
데모 애플리케이션 배포 - https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#run-and-expose-php-apache-server
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
app: php-apache
replicas: 1
template:
metadata:
labels:
app: php-apache
spec:
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
app: php-apache
spec:
ports:
- port: 80
selector:
app: php-apache
EOF
Pod의 리소스 사용량 확인
kubectl top pod -l app=php-apache
Metrics Server 설치 확인
kubectl get pod -n kube-system
API 서버에 등록된 API 목록 확인
kubectl get apiservices.apiregistration.k8s.io
v1beta1.metrics.k8s.io API의 상세 내용 확인
kubectl get apiservices.apiregistration.k8s.io v1beta1.metrics.k8s.io -o yaml
Metrics Server 로그 확인
kubectl -n kube-system logs deploy/metrics-server
Metrics Server 로그 레벨 변경
kubectl -n kube-system patch deployment metrics-server --type=json \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--v=6"}]'
Metrics Server 로그 확인 - 새로운 Pod가 뜬 다음에 확인
kubectl -n kube-system logs deploy/metrics-server
kubelet에서 제공하는 지표에 대한 접근 권한을 가진 Pod 생성
cat <<EOF | kubectl apply -f -
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kubelet-access
rules:
- apiGroups: [""]
resources:
- nodes/stats
- nodes/metrics
verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubelet-access
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kubelet-access
namespace: default
subjects:
- kind: ServiceAccount
name: kubelet-access
namespace: default
roleRef:
kind: ClusterRole
name: kubelet-access
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Pod
metadata:
name: curl
spec:
serviceAccountName: kubelet-access
containers:
- image: curlimages/curl
name: curl
command: ["sleep", "3600"]
env:
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
EOF
kubelet에서 제공하는 모든 지표 확인
kubectl exec curl -- \
sh -c 'curl -s -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://$HOST_IP:10250/stats/summary -k'
kubelet에서 제공하는 지표중에서 CPU 및 Memory에 대한 지표만 확인
kubectl exec curl -- \
sh -c 'curl -s -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://$HOST_IP:10250/stats/summary?only_cpu_and_memory=true -k'
API 서버를 통해서 Metrics Server가 지표를 수집할때 호출하는 Endpoint 호출
kubectl get --raw /api/v1/nodes/$(kubectl get node -o=jsonpath='{.items[0].metadata.name}')/proxy/metrics/resource
Autoscaling (HPA)설정
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=5
위에서 생성한 HPA 상태 확인
kubectl get hpa php-apache
데모 애플리케이션에 부하를 발생시키는 Pod 생성
kubectl run load-generator --image=busybox:1.28 -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
HPA 상태 모니터링
kubectl get hpa php-apache -w
Ctrl+C를 입력해서 HPA 모니터링을 중지하고 실제로 Pod가 생겼는지 확인
kubectl get pod -l app=php-apache
Pod의 리소스 사용량 확인
kubectl top pod -l app=php-apache
데모 애플리케이션에 부하를 발생시키는 Pod 삭제
kubectl delete pod load-generator
HPA 상태 모니터링
kubectl get hpa php-apache -w
Ctrl+C를 입력해서 HPA 모니터링을 중지하고 HPA 상세 내용 확인
kubectl describe hpa php-apache
Pod의 리소스 사용량 확인
kubectl top pod -l app=php-apache
HPA 상태 확인
kubectl get hpa php-apache
Pod 갯수 확인
kubectl get pod -l app=php-apache
데모 애플리케이션 및 리소스 삭제
{
kubectl delete hpa php-apache
kubectl delete deployment php-apache
kubectl delete svc php-apache
kubectl delete pod curl
kubectl delete clusterrole kubelet-access
kubectl delete clusterrolebinding kubelet-access
kubectl delete sa kubelet-access
}
Cluster Autoscaler
Deployment 생성
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 5
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
resources:
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 2
memory: 2Gi
EOF
생성된 Deployment 및 Pod 확인
kubectl get deploy,pod -l app=nginx
Pending 상태의 Pod가 있다면 아래의 명령어를 통해서 그 이유를 확인
kubectl describe pod \
$(kubectl get pod -o=jsonpath='{.items[?(@.status.phase=="Pending")].metadata.name}')
Cluster Autoscaler에게 부여할 IAM 정책 JSON 파일 생성
cat <<EOF > cluster-autoscaler-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeScalingActivities",
"ec2:DescribeImages",
"ec2:DescribeInstanceTypes",
"ec2:DescribeLaunchTemplateVersions",
"ec2:GetInstanceTypesFromInstanceRequirements",
"eks:DescribeNodegroup"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup"
],
"Resource": [
"*"
]
}
]
}
EOF
IAM 정책 생성
aws iam create-policy \
--policy-name AmazonEKSClusterAutoscalerPolicy \
--policy-document file://cluster-autoscaler-policy.json
Node에 부여된 Label을 통해서 EKS 클러스터 이름 확인하고 환경변수로 저장
{
export CLUSTER_NAME=$(kubectl get node \
-o=jsonpath='{.items[0].metadata.labels.alpha\.eksctl\.io\/cluster-name}')
echo $CLUSTER_NAME
}
EKS 클러스터가 생성되어 있는 AWS 계정번호 확인하고 환경변수로 저장
{
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo $ACCOUNT_ID
}
IAM OIDC 제공자 활성화
eksctl utils associate-iam-oidc-provider --region=$AWS_REGION \
--cluster=$CLUSTER_NAME --approve
ServiceAccount 생성
eksctl create iamserviceaccount \
--cluster=$CLUSTER_NAME \
--namespace=kube-system \
--name=cluster-autoscaler \
--attach-policy-arn=arn:aws:iam::${ACCOUNT_ID}:policy/AmazonEKSClusterAutoscalerPolicy \
--override-existing-serviceaccounts \
--approve \
--region $AWS_REGION
ServiceAccount가 생성되었는지 확인
kubectl -n kube-system describe sa cluster-autoscaler
ServiceAccount에 명시된 IAM 역할 이름을 확인하고 환경변수로 지정
{
IAM_ROLE_NAME=$(kubectl -n kube-system get sa cluster-autoscaler \
-o=jsonpath='{.metadata.annotations.eks\.amazonaws\.com\/role-arn}' \
| grep -oP '(?<=role.).*')
echo $IAM_ROLE_NAME
}
ServiceAccount와 연동된 IAM 역할에 부여된 IAM 정책 확인
aws iam list-attached-role-policies --role-name $IAM_ROLE_NAME
ServiceAccount와 연동된 IAM 역할에 부여된 신뢰관계 정책 확인
aws iam get-role --role-name $IAM_ROLE_NAME
Cluster Autoscaler 설치
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
Cluster Autoscaler 로그 확인 - ASG map 확인
kubectl -n kube-system logs deploy/cluster-autoscaler
Cluster Autoscaler 설정값 확인
kubectl -n kube-system get deploy cluster-autoscaler \
-o=jsonpath='{.spec.template.spec.containers[*].command}' | jq
EKS 노드그룹와 연동된 오토스케일링 그룹 이름을 확인하고 환경변수로 지정
{
export ASG_NAME=$(aws autoscaling describe-auto-scaling-groups --query \
"AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='$CLUSTER_NAME']].AutoScalingGroupName" --output text)
echo $ASG_NAME
}
오토스케일링 그룹의 인스턴스 현황 확인
aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $ASG_NAME \
--query "AutoScalingGroups[0].{MinSize: MinSize, MaxSize: MaxSize, DesiredCapacity: DesiredCapacity}"
Cluster Autoscaler 설정값 수정
kubectl -n kube-system patch deployment cluster-autoscaler --type=json \
-p='[{"op": "replace", "path": "/spec/template/spec/containers/0/command", "value": [
"./cluster-autoscaler",
"--v=4",
"--stderrthreshold=info",
"--cloud-provider=aws",
"--skip-nodes-with-local-storage=false",
"--expander=least-waste",
"--node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/'${CLUSTER_NAME}'",
"--balance-similar-node-groups",
"--skip-nodes-with-system-pods=false"
]}]'
Cluster Autoscaler 설정값 확인
kubectl -n kube-system get deploy cluster-autoscaler \
-o=jsonpath='{.spec.template.spec.containers[*].command}' | jq
Cluster Autoscaler 로그 확인 - ASG map 확인
kubectl -n kube-system logs deploy/cluster-autoscaler
Pending 상태였던 Pod가 생성 되었는지 확인
kubectl get pod -l app=nginx
오토스케일링 그룹의 인스턴스 현황 확인
aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $ASG_NAME \
--query "AutoScalingGroups[0].{MinSize: MinSize, MaxSize: MaxSize, DesiredCapacity: DesiredCapacity}"
오토스케일링 그룹의 활동 로그 확인
aws autoscaling describe-scaling-activities --auto-scaling-group-name $ASG_NAME
Deployment 삭제
kubectl delete deployment nginx
Pod 목록 확인
kubectl get pod -l app=nginx
Cluster Autoscaler 로그 확인
kubectl -n kube-system logs deploy/cluster-autoscaler
리소스 삭제
{
rm cluster-autoscaler-policy.json
eksctl delete iamserviceaccount \
--cluster=$CLUSTER_NAME \
--namespace=kube-system \
--name=cluster-autoscaler \
--region $AWS_REGION
}
Exposing
Service
Deployment 생성
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
initContainers:
- name: index
image: curlimages/curl
command:
- "sh"
- "-c"
- "echo 'hello from $(POD_NAME), my ip is $(POD_IP)' > /data/index.html"
volumeMounts:
- name: html
mountPath: /data
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
volumes:
- name: html
emptyDir: {}
EOF
Service 생성
kubectl expose deployment nginx --port 80
생성된 Service 확인
kubectl get svc nginx -o wide
생성된 Pod의 IP주소 확인
kubectl get pod -l app=nginx -o wide
Endpoint에 타겟으로 등록되어 있는 Pod 목록 확인
kubectl get ep nginx \
-o jsonpath='{range .subsets[*].addresses[*]}{.targetRef.name}{"\t"}{.ip}{"\n"}{end}'
생성된 Deployment의 Replica 갯수를 6개로 조정
kubectl scale deployment nginx --replicas=6
생성된 Pod의 IP주소 확인
kubectl get pod -l app=nginx -o wide
Endpoint에 타겟으로 등록되어 있는 Pod 목록 확인
kubectl get ep nginx \
-o jsonpath='{range .subsets[*].addresses[*]}{.targetRef.name}{"\t"}{.ip}{"\n"}{end}'
Pod 생성
kubectl run curl --image=nginx -- sleep infinity
위에서 생성한 Pod에서 Service 호출
kubectl exec curl -- \
bash -c "for i in {1..20};do curl -s $(kubectl get svc nginx -o=jsonpath='{.spec.clusterIP}');done"
새로운 터미널을 열고 kube-proxy 로그 확인 - 아래의 명령어를 입력하고 엔터키를 몇번 입력해서 간격을 만들어두면 새로운 로그를 좀 더 쉽게 알아볼수 있음
kubectl -n kube-system logs ds/kube-proxy -f
기존 터미널로 돌아와서 생성된 Deployment의 Replica 갯수를 3개로 조정
kubectl scale deployment nginx --replicas=3
다른 터미널로 이동해서 kube-proxy 로그를 확인하고 Ctrl+C를 입력해서 프로세스 종료
Session Manager 플러그인 설치
{
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm" -o "session-manager-plugin.rpm"
sudo yum install -y session-manager-plugin.rpm
}
한개의 Node로 Session Manager 연결
aws ssm start-session --target \
$(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+")
Iptable의 NAT 규칙 확인
sudo iptables -L -t nat
KUBE-SERVICES 규칙 확인
sudo iptables -t nat -L KUBE-SERVICES -n | column -t
생성된 Service의 Cluster IP로 연결된 규칙 값을 환경변수로 저장
{
export SERVICE_CHAIN=$(sudo iptables -t nat -L KUBE-SERVICES -n | column -t | grep "default/nginx" | grep -oE "^KUBE-SVC-[A-Z0-9]+")
echo $SERVICE_CHAIN
}
Service의 Cluster IP로 연결된 규칙의 상세내용 확인
sudo iptables -t nat -L $SERVICE_CHAIN -n | column -t
위의 명령어로 나온 결과중의 한개의 Chain 규칙 확인
sudo iptables -t nat -L $(sudo iptables -t nat -L $SERVICE_CHAIN -n | column -t | grep -oE "^KUBE-SEP-[A-Z0-9]+" | head -1) \
-n | column -t
첫번째 터미널로 이동해서 생성된 Pod의 IP주소 확인
kubectl get pod -o wide -l app=nginx
생성된 Deployment의 Replica 갯수를 6개로 조정
kubectl scale deployment nginx --replicas=6
두번째 터미널로 이동해서 21번 명령어 재실행
첫번째 터미널로 이동해서 Service를 ClusterIP에서 LoadBalancer로 변경
kubectl patch svc nginx -p '{"spec": {"type": "LoadBalancer"}}'
Service가 변경되었는지 확인
kubectl get svc nginx -o wide
Service 객체에 발생한 Event 확인
kubectl describe svc nginx
웹 브라우저를 열고 Service의 External IP 주소로 접속 - 아래의 명령어로 주소 확인 가능
kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}{"\n"}'
생성된 Service 상세 내용 확인
kubectl get svc nginx -o=jsonpath='{.spec}' | jq
생성된 ELB 이름 확인
kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+'
ELB 상세 내용 확인
aws elb describe-load-balancers --load-balancer-names \
$(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+' )
ELB의 Listener 설정 확인
aws elb describe-load-balancers --load-balancer-names \
$(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+' ) \
--query 'LoadBalancerDescriptions[*].ListenerDescriptions'
ELB의 보안그룹 확인
aws elb describe-load-balancers --load-balancer-names \
$(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+' ) \
--query 'LoadBalancerDescriptions[*].SecurityGroups'
노드에 부여된 보안그룹에 ELB 보안그룹에 대한 새로운 인바운드 규칙이 추가 됐는지 확인
aws ec2 describe-security-groups --group-ids \
$(aws ec2 describe-instances --instance-ids \
$(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+") \
--query 'Reservations[0].Instances[0].SecurityGroups[*].GroupId' --output text) \
--query "SecurityGroups[*].IpPermissions"
두번째 터미널로 이동해서 Iptable 규칙 확인
sudo iptables-save | grep nginx
KUBE-SERVICES 규칙 확인
sudo iptables -t nat -L KUBE-SERVICES -n | column -t
KUBE-NODEPORTS 규칙 확인
sudo iptables -t nat -L KUBE-NODEPORTS -n | column -t
NodePort 호출
curl localhost:NODEPORT
첫번째 터미널로 이동해서 Service를 LoadBalancer에서 ClusterIP로 변경
kubectl patch svc nginx -p '{"spec": {"type": "ClusterIP"}}'
ELB가 삭제되었는지 확인
aws elb describe-load-balancers
데모 애플리케이션 삭제
{
kubectl delete deploy nginx
kubectl delete svc nginx
}
Ingress
EKS 클러스터가 생성되어 있는 AWS 계정번호 확인하고 환경변수로 저장
{
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo $ACCOUNT_ID
}
Node에 부여된 Label을 통해서 EKS 클러스터 이름 확인하고 환경변수로 저장
{
export CLUSTER_NAME=$(kubectl get node \
-o=jsonpath='{.items[0].metadata.labels.alpha\.eksctl\.io\/cluster-name}')
echo $CLUSTER_NAME
}
IAM OIDC 제공자 생성
eksctl utils associate-iam-oidc-provider \
--region $AWS_REGION \
--cluster $CLUSTER_NAME \
--approve
AWS Load Balancer Controller에 부여할 IAM 권한이 명시된 JSON 파일 다운로드
curl -o aws-loadbalancer-controller-policy.json \
https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.8.2/docs/install/iam_policy.json
다운받은 IAM 정책 JSON 파일 리뷰
cat aws-loadbalancer-controller-policy.json
IAM 정책 생성
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://aws-loadbalancer-controller-policy.json
ServiceAccount 생성
eksctl create iamserviceaccount \
--cluster $CLUSTER_NAME \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--approve \
--region $AWS_REGION
EKS 리포지토리 추가
helm repo add eks https://aws.github.io/eks-charts
위에서 추가한 리포지토리에 있는 Helm 차트 목록 확인
AWS Load Balancer Controller 설치
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
--namespace kube-system \
--set clusterName=$CLUSTER_NAME \
--set replicaCount=1 \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller
AWS Load Balancer Controller 로그 확인
kubectl -n kube-system logs deploy/aws-load-balancer-controller
데모 웹사이트 배포
{
kubectl create deployment nginx --image=nginx --port=80
kubectl expose deploy nginx
}
생성된 리소스 확인
kubectl get all -l app=nginx
Ingress 생성
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
EOF
생성된 Ingress 확인
kubectl get ing nginx
위에서 생성한 Ingress에 발생한 Event 확인
kubectl describe ingress nginx
AWS Load Balancer Controller 로그 확인
kubectl -n kube-system logs deploy/aws-load-balancer-controller
Ingress 수정
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
annotations:
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
EOF
Ingress 상태 확인
kubectl get ing nginx
Ingress에 발생한 Event 확인
kubectl describe ingress nginx
AWS Load Balancer Controller 로그 확인
kubectl -n kube-system logs deploy/aws-load-balancer-controller
아래의 명령어를 실행해서 생성된 ALB 엔드포인트를 확인하고 웹브라우저를 통해서 접근이 되는지 확인
echo $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
생성된 ALB 이름을 확인하고 환경변수로 저장
{
export LoadBalancerName=$(aws elbv2 describe-load-balancers | \
jq -r '.LoadBalancers[] |
select(.DNSName == "'"$(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')"'") |
.LoadBalancerName')
echo $LoadBalancerName
}
ALB의 상세 내용 확인
aws elbv2 describe-load-balancers --names $LoadBalancerName
ALB의 Scheme 확인
aws elbv2 describe-load-balancers --names $LoadBalancerName \
--query 'LoadBalancers[0].Scheme' --output text
ALB가 생성된 서브넷 확인
aws elbv2 describe-load-balancers --names $LoadBalancerName \
--query 'LoadBalancers[0].AvailabilityZones[*]'
ALB가 생성된 서브넷에 부여된 태그 확인
aws ec2 describe-subnets --subnet-ids --query 'Subnets[*].Tags' \
$(aws elbv2 describe-load-balancers --names $LoadBalancerName \
--query 'LoadBalancers[0].AvailabilityZones[*].SubnetId' --output text)
Ingress 수정
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
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: nginx
port:
number: 80
EOF
Ingress에 발생한 Event 확인
kubectl describe ingress nginx
AWS Load Balancer Controller 로그 확인
kubectl -n kube-system logs deploy/aws-load-balancer-controller
아래의 명령어를 실행해서 생성된 ALB 엔드포인트를 확인하고 웹브라우저를 통해서 접근이 되는지 확인
echo $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
기존에 생성된 ALB가 존재하는지 확인
aws elbv2 describe-load-balancers --names $LoadBalancerName
새롭게 생성된 ALB의 ARN를 확인하고 환경변수로 저장
{
export LoadBalancerArn=$(aws elbv2 describe-load-balancers | \
jq -r '.LoadBalancers[] |
select(.DNSName == "'"$(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')"'") |
.LoadBalancerArn')
echo $LoadBalancerArn
}
아파치 웹서버 배포
{
kubectl create deployment httpd --image=httpd
kubectl expose deployment httpd --port=80
}
Ingress 수정
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- host: nginx.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
- host: httpd.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpd
port:
number: 80
EOF
아래의 명령어를 실행해서 생성된 ALB 엔드포인트를 확인하고 웹브라우저를 통해서 접근이 되는지 확인
echo $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
cURL 명령어로 Host 값을 nginx.example.com으로 명시하고 ALB 엔드포인트 호출
curl -H "Host: nginx.example.com" \
$(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
cURL 명령어로 Host 값을 httpd.example.com으로 명시하고 ALB 엔드포인트 호출
curl -H "Host: httpd.example.com" $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
ALB의 리스너 ARN를 확인하고 환경변수로 저장
{
export ListnerArn=$(aws elbv2 describe-listeners \
--load-balancer-arn $LoadBalancerArn \
--query "Listeners[0].ListenerArn" --output text)
echo $ListnerArn
}
ALB 리스너 확인
aws elbv2 describe-listeners --listener-arns $ListnerArn
ALB 리스너 규칙 확인
aws elbv2 describe-rules --listener-arn $ListnerArn
ALB에 연동된 대상그룹들의 ARN을 확인하고 환경변수로 저장
{
export TG=$(aws elbv2 describe-target-groups \
--load-balancer-arn $LoadBalancerArn \
--query "TargetGroups[*].TargetGroupArn" \
--output text)
echo $TG
}
대상그룹 확인
aws elbv2 describe-target-groups --target-group-arns $TG
대상그룹에 포함된 대상 목록 확인
for target in $TG
do
aws elbv2 describe-target-health --target-group-arn $target --no-cli-pager
done
Pod 목록 확인
kubectl get pod -o wide -l 'app in (nginx,httpd)'
아파치 Deployment의 Replica 갯수를 3개로 조정
kubectl scale deployment httpd --replicas=3
Pod 목록 확인
kubectl get pod -o wide -l 'app in (nginx,httpd)'
대상그룹에 포함된 대상 목록 확인
for target in $TG
do
aws elbv2 describe-target-health --target-group-arn $target --no-cli-pager
done
Ingress 삭제
kubectl delete ing nginx
AWS Load Balancer Controller 로그 확인
kubectl -n kube-system logs deploy/aws-load-balancer-controller
ALB가 삭제되었는지 확인
aws elbv2 describe-load-balancers --load-balancer-arns $LoadBalancerArn
리소스 삭제
{
kubectl delete svc httpd nginx
kubectl delete deploy httpd nginx
}