3/11
목표
3 가지를 이해 하자
1 . 파드 내부의 데이터는 파드가 정지되면 모두 삭제됨
2 . 데이터베이스(파드)처럼 데이터 보존이 필요
로컬 볼륨(hostPath) ⇒ 퍼시스턴트 볼륨(Persistent Volume, PV) - 어느 노드에서도 연결하여 사용 가능함.
3 . EBS 컨트롤러로 Pod에 EBS연결하기
워커 노드가 c5 이상인 경우 아래 테스트가 가능하다.
CloudFormation으로 한번에 구축해보자.
콘솔에서 사용
1
# default NS 지정
kubectl ns default
2
c5d.large 의 EC2 인스턴스는 스토어(임시 블록 스토리지)가 제공된다.
# '인스턴스 스토어' 볼륨이 있는 c5 모든 타입의 스토리지 크기
aws ec2 describe-instance-types --filters "Name=instance-type,Values=c5*" "Name=instance-storage-supported,Values=true" --query "InstanceTypes[].[InstanceType, InstanceStorageInfo.TotalSizeInGB]" --output table
---------------------------------
| DescribeInstanceTypes |
+---------------+--------+-----
| c5d.large | 50 |
| c5d.12xlarge | 1800 |
:
3
# 워커 노드 Public IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value}" --filters Name=instance-state-name,Values=running --output table
4
# 워커 노드 Public IP 변수 지정
W1PIP=<워커 노드 1 Public IP>
W2PIP=<워커 노드 2 Public IP>
W1PIP=3.38.212.122
W2PIP=43.201.99.109
echo "export W1PIP=$W1PIP" >> /etc/profile
echo "export W2PIP=$W2PIP" >> /etc/profile
5
# 워커 노드 스토리지 확인 : NVMe SSD 인스턴스 스토어 볼륨 확인
툴 설치
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo apt install -y nvme-cli
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo apt install -y nvme-cli
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo nvme list
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo nvme list
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP lsblk -e 7 -d
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP lsblk -e 7
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP df -hT -t ext4
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP df -hT -t ext4
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP lspci | grep Non-Volatile
00:04.0 Non-Volatile memory controller: Amazon.com, Inc. Device 8061
00:1f.0 Non-Volatile memory controller: Amazon.com, Inc. NVMe SSD Controller
# 파일시스템 생성 및 /data 마운트
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo mkfs -t xfs /dev/nvme1n1
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo mkfs -t xfs /dev/nvme1n1
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo mkdir /data
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo mkdir /data
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo mount /dev/nvme1n1 /data
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo mount /dev/nvme1n1 /data
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP df -hT -t ext4 -t xfs
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP df -hT -t ext4 -t xfs
파드 내부의 데이터는 파드가 정지되면 모두 삭제됨
1
# 파드 배포
# date 명령어로 현재 시간을 10초 간격으로 /home/pod-out.txt 파일에 저장
cat ~/pkos/3/date-busybox-pod.yaml | yh
kubectl apply -f ~/pkos/3/date-busybox-pod.yaml
2
# 파일 확인
kubectl get pod
kubectl exec busybox -- tail -f /home/pod-out.txt
Sat Jan 28 15:33:11 UTC 2023
Sat Jan 28 15:33:21 UTC 2023
3
# 파드 삭제 후 다시 생성 후 파일 정보 확인 > 이전 기록이 보존되어 있는지?
kubectl delete pod busybox
4
kubectl apply -f ~/pkos/3/date-busybox-pod.yaml
kubectl exec busybox -- tail -f /home/pod-out.txt
5
# 실습 완료 후 삭제
kubectl delete pod busybox
6
데이터베이스(파드)처럼 데이터 보존이 필요
로컬 볼륨(hostPath) ⇒ 퍼시스턴트 볼륨(Persistent Volume, PV) - 어느 노드에서도 연결하여 사용 가능함.
pv/ pvc 사용하면 데이터의 연속성이 보장 된다.
1
# 마스터노드의 이름 확인해두기
kubectl get node | grep control-plane | awk '{print $1}'
i-0f2e56dfc93f28e98
2
# 배포 : vim 직접 편집할것
curl -s -O https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.23/deploy/local-path-storage.yaml
3
아래 내용은 마스터 노드에서 뜨도록 설정한다.
호스트 path의 단점을 재현하고자 해당 설정으로 진행한다.
nodeSelector:
kubernetes.io/hostname: "<각자 자신의 마스터 노드 이름 입력>i-0f2e56dfc93f28e98"
vim local-path-storage.yaml
----------------------------
# 아래 빨간 부분은 추가 및 수정
apiVersion: apps/v1
kind: Deployment
metadata:
name: local-path-provisioner
namespace: local-path-storage
spec:
replicas: 1
selector:
matchLabels:
app: local-path-provisioner
template:
metadata:
labels:
app: local-path-provisioner
spec:
nodeSelector:
kubernetes.io/hostname: "<각자 자신의 마스터 노드 이름 입력>i-0f2e56dfc93f28e98"
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
operator: Exists
...
kind: ConfigMap
apiVersion: v1
metadata:
name: local-path-config
namespace: local-path-storage
data:
config.json: |-
{
"nodePathMap":[
{
"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
"paths":["/data/local-path"]
}
]
}
----------------------------
/data/local-path 는 파드의 로컬 스토리지 이다. 속도가 얼마나 나오는지 테스트하기 위해 지정하는 것이다.
4
# 배포
kubectl apply -f local-path-storage.yaml
5
# 확인 : 마스터노드에 배포됨을 확인하자.
kubectl get-all -n local-path-storage
kubectl get pod -n local-path-storage -owide
kubectl describe cm -n local-path-storage local-path-config
kubectl get sc local-path
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local-path rancher.io/local-path Delete WaitForFirstConsumer false 34s
1
watch -d kubectl get pods
# PVC 생성
cat ~/pkos/3/localpath1.yaml | yh
kubectl apply -f ~/pkos/3/localpath1.yaml
2
# PVC 확인
kubectl get pvc
kubectl describe pvc
3
# 파드 생성
cat ~/pkos/3/localpath2.yaml | yh
kubectl apply -f ~/pkos/3/localpath2.yaml
4
# 파드 확인 : df-pv는 인스턴스 스토어라서 정보가 나오지 않음 >> 뒤 EBS Ctrl PV/PVC 실습에서는 확인됨
kubectl get pod,pv,pvc
kubectl krew install df-pv && kubectl df-pv
5
5초에 한번씩 날자를 찍고 , PV에 저장한다.
kubectl exec -it app -- tail -f /data/out.txt
Sun Jan 29 05:13:45 UTC 2023
...
6
# 워커노드에 툴 설치
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo apt install -y tree jq sysstat
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo apt install -y tree jq sysstat
7
# 워커노드 중 현재 파드가 배포되어 있다만, 아래 경로에 out.txt 파일 존재 확인
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP tree /data
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP tree /data
/opt/local-path-provisioner
└── pvc-bb81ef9e-0bcc-466d-8971-568642028593_default_localpath-claim
└── out.txt
# 해당 워커노드 자체에서 out.txt 파일 확인 : 아래 굵은 부분은 각자 실습 환경에 따라 다름
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP tail -f /data/local-path/pvc-ce742b90-755a-4b52-9693-595cbf55dfb0_default_localpath-claim/out.txt
Sun Jan 29 05:13:45 UTC 2023
...
1
# 파드 삭제 후 PV/PVC 확인
kubectl delete pod app
kubectl get pod,pv,pvc
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP tree /data
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP tree /data
# 파드 다시 실행
kubectl apply -f ~/pkos/3/localpath2.yaml .
# 확인
kubectl exec -it app -- head /data/out.txt
kubectl exec -it app -- tail -f /data/out.txt
1
# 파드와 PVC 삭제
kubectl delete pod app
kubectl get pv,pvc
kubectl delete pvc localpath-claim
2
# 확인
kubectl get pv
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP tree /data
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP tree /data
1
# kubestr 툴 다운로드
wget https://github.com/kastenhq/kubestr/releases/download/v0.4.37/kubestr_0.4.37_Linux_amd64.tar.gz
tar xvfz kubestr_0.4.37_Linux_amd64.tar.gz && mv kubestr /usr/local/bin/ && chmod +x /usr/local/bin/kubestr
2
# 스토리지클래스 점검
kubestr -h
kubestr
3
# 모니터링
watch 'kubectl get pod -owide;echo;kubectl get pv,pvc'
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP iostat -xmdz 1 -p nvme1n1
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP iostat -xmdz 1 -p nvme1n1
--------------------------------------------------------------
# rrqm/s : 초당 드라이버 요청 대기열에 들어가 병합된 읽기 요청 횟수
# wrqm/s : 초당 드라이버 요청 대기열에 들어가 병합된 쓰기 요청 횟수
# r/s : 초당 디스크 장치에 요청한 읽기 요청 횟수
# w/s : 초당 디스크 장치에 요청한 쓰기 요청 횟수
# rMB/s : 초당 디스크 장치에서 읽은 메가바이트 수
# wMB/s : 초당 디스크 장치에 쓴 메가바이트 수
# await : 가장 중요한 지표, 평균 응답 시간. 드라이버 요청 대기열에서 기다린 시간과 장치의 I/O 응답시간을 모두 포함 (단위: ms)
현재 디스크를 측정해 보자 ~~~~~
iostat -xmdz 1 -p xvdf
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
xvdf 0.00 0.00 2637.93 0.00 10.30 0.00 8.00 6.01 2.28 2.28 0.00 0.33 86.21
--------------------------------------------------------------
4
# 측정 : Read
curl -s -O https://raw.githubusercontent.com/wikibook/kubepractice/main/ch10/fio-read.fio
kubestr fio -f fio-read.fio -s local-path --size 10G
// kubestr가 자동으로 부하를 발생시키는 파드를 생성해서 io에 대해 측정한다.
# [NVMe] 4k 디스크 블록 기준 Read 평균 IOPS는 20309 >> 4분 정도 소요
kubestr fio -f fio-read.fio -s local-path --size 10G
PVC created kubestr-fio-pvc-ncx6p
Pod created kubestr-fio-pod-w5cgr
Running FIO test (fio-read.fio) on StorageClass (local-path) with a PVC of Size (10G)
Elapsed time- 3m42.14412586s
FIO test results:
FIO version - fio-3.30
Global options - ioengine=libaio verify= direct=1 gtod_reduce=
JobName:
blocksize= filesize= iodepth= rw=
read:
IOPS=20300.531250 BW(KiB/s)=81202
iops: min=17304 max=71653 avg=20309.919922 - 2만 iops 나온다.
bw(KiB/s): min=69216 max=286612 avg=81239.710938
Disk stats (read/write):
nvme1n1: ios=2433523/10 merge=0/3 ticks=7649660/20 in_queue=7649680, util=99.958305%
- OK
5
# 측정 : Write
curl -s -O https://raw.githubusercontent.com/wikibook/kubepractice/main/ch10/fio-write.fio
sed -i '/directory/d' fio-write.fio
kubestr fio -f fio-write.fio -s local-path --size 10G
# [NVMe] 4k 디스크 블록 기준 Write 평균 IOPS는 9082 >> 9분 정도 소요
kubestr fio -f fio-write.fio -s local-path --size 10G
PVC created kubestr-fio-pvc-58j52
Pod created kubestr-fio-pod-rc9lj
Running FIO test (fio-write.fio) on StorageClass (local-path) with a PVC of Size (10G)
Elapsed time- 8m52.522138847s
FIO test results:
FIO version - fio-3.30
Global options - ioengine=libaio verify= direct=1 gtod_reduce=
JobName:
blocksize= filesize= iodepth= rw=
write:
IOPS=9077.357422 BW(KiB/s)=36309
iops: min=8292 max=14203 avg=9082.347656
bw(KiB/s): min=33168 max=56822 avg=36329.429688
Disk stats (read/write):
nvme1n1: ios=0/1087555 merge=0/4 ticks=0/29941255 in_queue=29941255, util=99.965790%
- OK
1
PV / PVC 파드 테스트
2
콘솔 EBS에서 확인
3
동작은?
볼륨을 생성한다.
ebs-csi-controller 파드가 AWS API통해 GP3 만듬.
볼륩을 파드에 연결
4
# kOps 설치 시 기본 배포됨
kubectl get pod -n kube-system -l app.kubernetes.io/instance=aws-ebs-csi-driver
NAME READY STATUS RESTARTS AGE
ebs-csi-controller-6b66df46d6-dvhcc 5/5 Running 0 2d15h
ebs-csi-node-cg2qk 3/3 Running 0 2d15h
ebs-csi-node-n8gnb 3/3 Running 0 2d15h
ebs-csi-node-r8xp7 3/3 Running 0 2d15h
5
# 스토리지 클래스 확인
kubectl get sc kops-csi-1-21 kops-ssd-1-17
masterseo1:default) [root@kops-ec2 home]# kubectl get sc kops-csi-1-21 kops-ssd-1-17
NAME PROVISION RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
kops-csi-1-21 (default) ebs.csi.aws.com Delete WaitForFirstConsumer true
kops-ssd-1-17 kubernetes.io/aws-ebs Delete WaitForFirstConsumer true
kubectl describe sc kops-csi-1-21 | grep Parameters
Parameters: encrypted=true,type=gp3
kubectl describe sc kops-ssd-1-17 | grep Parameters
Parameters: encrypted=true,type=gp2
3
# 워커노드의 EBS 볼륨 확인 : tag(키/값) 필터링 - 링크
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --output table
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments" | jq
[
[
{
"AttachTime": "2023-03-12T10:44:06+00:00",
"Device": "/dev/sda1",
"InstanceId": "i-0ef0fcd239c580b23",
"State": "attached",
"VolumeId": "vol-0293af551ee363f7a",
"DeleteOnTermination": true
}
],
[
{
"AttachTime": "2023-03-12T10:44:08+00:00",
"Device": "/dev/sda1",
"InstanceId": "i-0059292ee2b9f6019",
"State": "attached",
"VolumeId": "vol-0652ee044096d1b90",
"DeleteOnTermination": true
}
]
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[*].State" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[*].State" --output text
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[].State" --output text
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[?State=='attached'].VolumeId[]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[?State=='attached'].VolumeId[]" --output text
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[?State=='attached'].InstanceId[]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].{ID:VolumeId,Tag:Tags}" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].[VolumeId, VolumeType]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].[VolumeId, VolumeType, Attachments[].[InstanceId, State]]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].[VolumeId, VolumeType, Attachments[].[InstanceId, State][]][]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].{VolumeId: VolumeId, VolumeType: VolumeType, InstanceId: Attachments[0].InstanceId, State: Attachments[0].State}" | jq
4
# 워커노드에서 파드에 추가한 EBS 볼륨 확인
aws ec2 describe-volumes --filters Name=tag:ebs.csi.aws.com/cluster,Values=true --output table
aws ec2 describe-volumes --filters Name=tag:ebs.csi.aws.com/cluster,Values=true --query "Volumes[*].{ID:VolumeId,Tag:Tags}" | jq
aws ec2 describe-volumes --filters Name=tag:ebs.csi.aws.com/cluster,Values=true --query "Volumes[].{VolumeId: VolumeId, VolumeType: VolumeType, InstanceId: Attachments[0].InstanceId, State: Attachments[0].State}" | jq
5
# 워커노드에서 파드에 추가한 EBS 볼륨 모니터링
while true; do aws ec2 describe-volumes --filters Name=tag:ebs.csi.aws.com/cluster,Values=true --query "Volumes[].{VolumeId: VolumeId, VolumeType: VolumeType, InstanceId: Attachments[0].InstanceId, State: Attachments[0].State}" --output text; date; sleep 1; done
6
# PVC 생성
cat ~/pkos/3/awsebs-pvc.yaml | yh
kubectl apply -f ~/pkos/3/awsebs-pvc.yaml
7
# 파드 생성
cat ~/pkos/3/awsebs-pod.yaml | yh
kubectl apply -f ~/pkos/3/awsebs-pod.yaml
8
# PVC, 파드 확인
kubectl get pvc,pv,pod
9
사용 용량 쉽게 확인하기
k krew install df-pv
kubectl df-pv
(masterseo1:default) [root@kops-ec2 ~]# kubectl df-pv
PV NAME PVC NAME NAMESPACE NODE NAME POD NAME VOLUME MOUNT NAME SIZE USED AVAILABLE %USED IUSED IFREE %IUSED
pvc-686a3da0-8fe3-4c8a-b886-4803d5c78c0d ebs-claim default i-084961883568b7489 app persistent-storage 3Gi 28Ki 3Gi 0.00 12 262132 0.00
10
# 추가된 EBS 볼륨 상세 정보 확인
aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq
10
# 파일 내용 추가 저장 확인
kubectl exec app -- tail -f /data/out.txt
Fri Apr 28 03:55:10 UTC 2023
Fri Apr 28 03:55:15 UTC 2023
Fri Apr 28 03:55:20 UTC 2023
Fri Apr 28 03:55:25 UTC 2023
Fri Apr 28 03:55:30 UTC 2023
Fri Apr 28 03:55:35 UTC 2023
Fri Apr 28 03:55:40 UTC 2023
Fri Apr 28 03:55:45 UTC 2023
Fri Apr 28 03:55:50 UTC 2023
Fri Apr 28 03:55:55 UTC 2023
11
# 파드 내에서 볼륨 정보 확인
kubectl exec -it app -- sh -c 'df -hT --type=ext4'
Filesystem Type Size Used Avail Use% Mounted on
/dev/nvme1n1 ext4 3.9G 16M 3.8G 1% /data
/dev/root ext4 124G 4.9G 120G 4% /etc/hosts
12
볼륨 증가
- 늘릴수는 있어도 줄일수는 없다.
# 현재 pv 의 이름을 기준하여 4G > 10G 로 증가 : .spec.resources.requests.storage의 4Gi 를 10Gi로 변경
kubectl edit pvc ebs-claim
kubectl get pvc ebs-claim -o jsonpath={.spec.resources.requests.storage} ; echo
10G
kubectl get pvc ebs-claim -o jsonpath={.status.capacity.storage} ; echo
10G
// patch로 10G 로 늘려보자
kubectl patch pvc ebs-claim -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
kubectl patch pvc ebs-claim -p '{"status":{"capacity":{"storage":"10Gi"}}}'
# status 는 바로 위 커멘드 적용 후 EBS 10Gi 확장 후 알아서 10Gi 반영됨
13
# 확인 : 볼륨 용량 수정 반영이 되어야 되니, 수치 반영이 조금 느릴수 있다
kubectl exec -it app -- sh -c 'df -hT --type=ext4'
Filesystem Type Size Used Avail Use% Mounted on
/dev/nvme1n1 ext4 9.8G 28K 9.7G 1% /data
/dev/root ext4 124G 5.9G 118G 5% /etc/hosts
kubectl df-pv
aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq
14
삭제
kubectl delete pod app & kubectl delete pvc ebs-claim
1 . 파드 내부의 데이터는 파드가 정지되면 모두 삭제됨
2 . 데이터베이스(파드)처럼 데이터 보존이 필요
로컬 볼륨(hostPath) ⇒ 퍼시스턴트 볼륨(Persistent Volume, PV) - 어느 노드에서도 연결하여 사용 가능함.
3 . EBS 컨트롤러로 Pod에 EBS연결하기
4. AWS Volume SnapShots Controller
https://kops.sigs.k8s.io/addons/#snapshot-controller
https://kubernetes.io/docs/concepts/storage/volume-snapshots/
https://github.com/kubernetes-sigs/aws-ebs-csi-driver/tree/master/examples/kubernetes/snapshot
5. EFS도 테스트 하자.
EFS 파일시스템 생성 및 EFS Controller 설치
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/efs-csi.html
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/efs-csi.html
https://artifacthub.io/packages/helm/aws-efs-csi-driver/aws-efs-csi-driver
다음과정
https://brunch.co.kr/@topasvga/3109
https://brunch.co.kr/@topasvga/3144
감사합니다.