예시: WordPress와 MySQL을 퍼시스턴트 볼륨에 배포하기

이번 글에서는 쿠버네티스 공식 문서에 있는 튜토리얼을 하나 따라해 보고자 한다!

위 링크에서는 minikube 위에 kustomize를 이용해서 WordPress와 MySQL을 구축했지만 나는 EKS 위에 올릴 것이다! EKS 애드온을 사용할 건데 특히 aws-load-balancer-controller로 LB를 자동으로 프로비저닝하여 wordpress를 노출시킬 것이다.

POD는 Stateless 성질을 띄고 있어서 데이터베이스 특성에는 어울리지 않는다. 하지만 그럼에도 쿠버네티스 상에서 운영을 해 보고자 한다면 StatefulSets와 PV,PVC를 사용할 수 있다.

하지만 여기서는 StatfulSets이 아닌 Deployment를 사용했고 MySQL을 영속성있게 사용하기 위해 PV,PVC를 사용하였다. PV는 POD와는 독립적으로 POD가 종료되어도 데이터를 보존할 수 있다.

PV는 클러스터 리소스로 관리자의 역할에 가깝고 PVC는 namespace에 제한되는 리소스로 사용자의 역할에 가깝다. 여러 POD가 하나의 PVC를 공유할 수 있지만, PV와 PVC는 1대1 매칭임을 잊지 말아야 한다.

AWS에서 PV를 사용할 때 Node의 로컬 볼륨을 사용할 수도 있고 새롭게 EBS 또는 EFS를 생성하여 사용할 수도 있다.

로컬 볼륨

Node의 로컬 볼륨은 지양한다고 한다. 기본 Node의 가용성을 따르게 되어 만약 Node가 비정상 상태가 되면 로컬 볼륨도 접근할 수도 없고 POD도 실행할 수 없게 되기 때문이다.

로컬 볼륨은 hostPath 또는 local을 사용할 수 있는데 hostPath는 아무 Node를 로컬 볼륨으로 사용할 수 있고 POD에 설정한다.

Untitled

그러나 local은 nodeAffinity 설정으로 지정한 Node를 로컬 볼륨으로 사용할 수 있으며, PV에 설정할 수 있다.

Untitled 1

hostPath는 보안 위험이 있으며 아래와 같은 주의사항이 있다.

Untitled 2

kubernetes docs 볼륨 참

CSI Driver

AWS EBS나 EFS를 사용하기 위해서 CSI(Container Storage Interface) Driver가 필요하다.

CSI Driver 플러그인 중에서 프로비저너는 클러스터에 PVC가 생성되는 것을 모니터링하다 PVC가 생성되면 PV 생성을 담당한다. 이는 동적 프로비저닝에 해당되며, 관리자 개입없이 사용자가 PVC 생성하는 것만으로 PVC,PV를 사용할 수 있게 해준다. 이러면 사용자 요청이 많아져도 관리포인트를 줄일 수 있는 요소가 된다.

Untitled 3

출처 : AWS 문서

CSI Driver는 StorageClass에 사전 정의를 해 둬야 한다. 그리고 스토리지마다 CSI Driver를 설치해야 한다.

위 사진과 같은 프로세스로 PVC를 생성하면 PV가 생성되고 동적으로 매핑되어 사용자는 해당 볼륨을 사용할 수 있게 되는 것이다.

처음 쿠버네티스를 공부할 때는 이해하지 못했는데 다시 정리하는 지금 CSI Driver의 역할에 대해 알게 되었다.

EBS CSI Driver

볼륨으로 EBS를 사용하고자 한다. 근데 EBS 볼륨을 사용하려면 PV와 PVC의 accessModes는 ReadWriteOnce로 설정해야 한다. 왜냐하면 EBS스토리지 기본 설정이 동일 AZ에 있는 EC2 인스턴스에 연결해야 하기 때문이다. ReadWriteOnce는 하나의 Node에서 해당 볼륨이 읽기-쓰기로 마운트될 수 있으며, 동일 Node에서 구동되는 경우 다수의 POD에서 볼륨에 접근할 수 있다.

Untitled 4

EBS는 Multi Attach 기능이 있는데 이를 사용하게 되면 어떻게 되는지 궁금했다. 찾아보니 이는 쿠버네티스와 CSI Driver에서 지원하지 않는 기능이라고 한다.

Multi-attach EBS as a persistent storage for EKS

다중 POD가 하나의 EBS 볼륨을 사용해야 한다면 POD의 스케줄링 방안에 대해서도 고려해야 한다. 그렇게 되면 그 볼륨이 필요한 모든 POD는 특정 Node에 스케줄링되어야 하니 Node Affinity 설정을 해야 할 것이다.

그럼 EBS CSI Driver를 설치해 보자!

먼저 AmazonEBSCSIDriverPolicy 정책을 가진 역할을 하나 생성하고 SA에 해당 역할을 부여해 줬다. 해당 역할로 EBS를 제어할 수 있게 IRSA를 생성한 것이다.

# eksctl create iamserviceaccount \
>   --name ebs-csi-controller-sa \
>   --namespace kube-system \
>   --cluster ${CLUSTER_NAME} \
>   --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
>   --approve \
>   --role-only \
>   --role-name AmazonEKS_EBS_CSI_DriverRole

Untitled 5

IRSA를 생성하고 나면 아래와 같이 확인할 수 있다

Untitled 6

kubectl get sa -n kube-system으로 찾으면 해당 정보를 찾을 수 없다. SA에 IAM Role을 적용한 IRSA는 eksctl 명령어로 확인이 가능했다.

그리고 eksctl 명령어로 해당 IRSA를 가지고 EBS CSI Driver 애드온을 생성하였다.

**eksctl create addon --name aws-ebs-csi-driver --cluster ${CLUSTER_NAME} --service-account-role-arn arn:aws:iam::${ACCOUNT_ID}:role/AmazonEKS_EBS_CSI_DriverRole --force**

아래와 같이 CSI-Controller와 CSI-Node가 생성된 걸 확인할 수 있다.

Untitled 7

이제 해당 CSI Driver가 볼륨을 만들어주기 위한 Storage Class를 선언할 차례이다. Untitled 8

또는 default로 생성되어 있는 Storage Class를 사용해도 된다. 사실 이 SC를 생성하면서 기존에 생성해 둔 PVC가 default SC를 바라 보고 있어서 CSI Controller POD 생성되자마자 볼륨이 하나 생성돼서 놀랐다.

지금 생성한 SC는 provisioner: ebs.csi.aws.com라고 설정해 두고 default SC는 provisioner: kubernetes.io/aws-ebs라고 설정되어 있는데 default SC도 볼륨이 동적 프로비저닝된 것이 놀랐다.

# kubectl get sc -o jsonpath='{range .items[*]}{.provisioner}{"\n"}{end}'
	kubernetes.io/aws-ebs
	ebs.csi.aws.com

기존 사용하던 CSI 플러그인이 바껴서 그런 것 같다. EBS CSI Dirver를 사용하려면 ebs.csi.aws.com으로 설정하는게 맞다!

Untitled 9

Amazon EBS CSI 마이그레이션 관련 자주 묻는 질문 - Amazon EKS

이번엔 위에서 SC를 생성한 대로 gp3 볼륨을 사용하기 위해 기존 PVC yaml 파일에 storageClassName: gp3를 추가해 줬다. SC명을 안적으면 default SC로 설정된다.

Untitled 10

Untitled 11

자동으로 볼륨과 PV가 생성된 걸 볼 수 있는데 여기서 AZ는 요청 POD가 올라가 있는 Node에 따라 달라졌다.

MySQL & WordPress

이제야 본 내용을 시작하겠다.

먼저 MySQL과 WordPress 파일을 다운로드한다.

curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml

apply를 진행하기 전에 secrets 리소스를 생성해야 한다. Secrets은 MySQL 패스워드를 저장할 리소스이다.

# kubectl create secret generic mysql-pass --from-literal 'password=mysql0102'
	secret/mysql-pass created

명령어로 생성할 수 있는데 평문으로 넣으면 base64로 암호화된 value 값이 들어간다.

# kubectl describe secrets mysql-pass
	Name:         mysql-pass
	Namespace:    default
	Labels:       <none>
	Annotations:  <none>
	
	Type:  Opaque
	
	Data
	====
	password:  9 bytes

# kubectl get secrets mysql-pass -o yaml
	apiVersion: v1
	data:
	  password: bXlzcWwwMTAy
	kind: Secret
	metadata:
	  creationTimestamp: "2024-03-23T10:33:11Z"
	  name: mysql-pass
	  namespace: default
	  resourceVersion: "9898"
	  uid: fcaf3e48-c731-4573-ad06-4e1ed6c71194
	type: Opaque

이제 다운받은 MySQL과 WordPress를 생성할 것이다.

그 전에 수정해 줄 것이 있다.

  • storageClassName: gp3
    • MySQL과 WordPress의 PVC에 각각 넣어준다.
  • service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    • WordPress의 Service annotations에 넣어준다.

특히 internet-facing 때문에 생각지 못한 시간이 소요됐다. aws-load-balancer-controller 덕분에 service를 LoadBalancer 타입으로 노출시키면 자동으로 AWS LB를 프로비저닝해 준다. 근데 annotations에 저 값이 없으니 default로 Internal NLB를 생성했다. internet-facing으로 설정하면 퍼블릭존에 NLB를 생성해서 외부에서 접근이 가능해 진다. (어쩐지 bastion에서는 접근이 되고 내 로컬에서는 접근이 안됐다)

Untitled 12

Untitled 13

처음에 보안그룹 때문인줄 알았지만 전혀 아니었다. 사실 IP 대역만 봐도 눈치챘어야 했다..

LB의 보안그룹은 아래와 같이 자동으로 80은 애니오픈으로 들어가고

Untitled 14

대상은 노드그룹의 32205 포트로 향한다. 이는 노출된 노드포트를 의미한다.

Untitled 15

그리고 노드의 보안그룹에도 LB를 대상으로 32205 포트는 열려 있다!

Untitled 16

이제 진짜 리소스를 생성해 보자!

# kubectl apply -f mysql-deployment.yaml
	service/wordpress-mysql created
	persistentvolumeclaim/mysql-pv-claim created
	deployment.apps/wordpress-mysql created
	
# kubectl apply -f wordpress-deployment.yaml
	service/wordpress created
	persistentvolumeclaim/wp-pv-claim created
	deployment.apps/wordpress created

이제 생성이 완료되었다.

사전에 생성해 둔 Storage Class에 따라 pvc는 Bound 상태로 바뀌고 POD는 Running 상태로 바뀐다.

Untitled 17

이제 kubectl get svc에서 보이는 EXTERNAL-IP로 접근하면 WordPress에 접근할 수 있다!

Untitled 6

Untitled 19

최종적으로 위와 같은 그림이 만들어 진다.

Untitled 20

df-pv 플러그인으로 사용중인 PV를 쉽게 볼 수 있다!

이제 실습을 다했으므로 리소스를 삭제해 주면 되는데

PV의 RECLAIM Policy가 Delete라서 PV 리소스를 삭제하면 자동으로 실제 EBS까지 삭제된다!

kubectl delete -f 해 주고 실습은 마무리한다!

Categories:

Updated:

Leave a comment