EKS 환경 - Volume Mount (EFS)

반영환·2023년 9월 19일
0

eks

목록 보기
6/9
post-thumbnail

EKS 환경 - Volume Mount by EFS

POD의 영구 저장소를 위해 DB 서버를 할당하는 것은 매우 비효율적인 일이다.

로그 저장, Kafka partition 보존 등을 위해 POD의 저장소를 영구 저장소에 옮겨야하는데 EKS환경에서 사용할 수 있는 볼륨으로 EBS와 EFS가 있다.

나는 EFS를 선택했는데 그 이유는 EBS는 EC2 노드에 종속성이 있으며 같은 AZ에서만 사용 가능하다는 단점이 있기 때문이다.

EFS CSI 드라이버 설치

먼저 EKS가 EFS를 사용할 수 있도록 efs-csi-driver를 설치한다.

csi란 Container Storage Interface의 약자로 Container 환경에서 스토리지를 편리하게 활용하기 위한 드라이버이다.

이를 통해 환경에 따라 ( K8S, Only Docker, Bare metal ) 드라이버를 따로 구성할 필요없이 하나의 추상화된 접근 인터페이스를 통해 접근 가능하다.

By Helm

# helm 설치
$ curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh
$ chmod 700 get_helm.sh
$ ./get_helm.sh

# 아래 에러 발생시 vi get_helm.sh을 입력한 후
# 편집기에서 HELM_INSTALL_DIR을 $PATH와 일치하도록 변경
helm not found. Is /usr/local/bin on your $PATH?
Failed to install helm
        For support, go to https://github.com/helm/helm.


# helm에 aws-efs-csi-driver repository 추가
$ helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver/

# repository 업데이트
$ helm repo update

# 드라이버 설치
# https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/add-ons-images.html
$ helm upgrade -i aws-efs-csi-driver aws-efs-csi-driver/aws-efs-csi-driver \
    --namespace kube-system \
    --set image.repository={위의 링크에서 리전별 값 확인}/eks/aws-efs-csi-driver \
    --set controller.serviceAccount.create=false \
    --set controller.serviceAccount.name=efs-csi-controller-sa

By Kustomize

EFS를 위한 IAM 정책 생성

# 정책 파일 다운로드
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/docs/iam-policy-example.json

# 정책 생성
aws iam create-policy --policy-name $ACCOUNT-AmazonEKS_EFS_CSI_Driver_Policy --policy-document file://iam-policy-example.json

# 정책을 사용해 역할과 서비스 어카운트 생성
eksctl create iamserviceaccount \
--cluster $ACCOUNT-cluster \
--namespace kube-system \
--name efs-csi-controller-sa \
--attach-policy-arn arn:aws:iam::$AWSNUM:policy/$ACCOUNT-AmazonEKS_EFS_CSI_Driver_Policy \ --approve \
--region $AWSREGION

# EFS CSI 드라이버 배포 YML 파일 다운로드
kubectl kustomize \
"github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.4" > public-ecr-driver.yaml

위 방식대로 역할을 생성하면 AmazonEFS 에 대한 Full Access가 아닌 하위 권한을 받게 된다. 필요하다면 노드 그룹의 역할에 Amazon Elastic File System Full Access 를 부여하자

EFS CSI 드라이버 배포 YML 파일 수정

파일에 있는 Service Account 생성 부분을 삭제한다. ( 이미 만들었다. )

apiVersion: v1 
kind: ServiceAccount 
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
    name: efs-csi-controller-sa
    namespace: kube-system 
    ---

EFS CSI 배포

kubectl apply -f public-ecr-driver.yaml

EFS 생성 - Shell Script

# 1. EKS 클러스터의 vpc_id 값 조회
$ vpc_id=$(aws eks describe-cluster --name $ACCOUNT-cluster --query "cluster.resourcesVpcConfig.vpcId" --output text)
    
# 2. EKS 클러스터가 속한 vpc의 network cidr 조회
$ cidr_range=$(aws ec2 describe-vpcs --vpc-ids $vpc_id --query "Vpcs[].CidrBlock" --output text --region $AWSREGION)

# 3. EFS의 보안그룹 생성
$ security_group_id=$(aws ec2 create-security-group --group-name $ACCOUNT-EfsSG --description "$ACCOUNT-EfsSG" --vpc-id $vpc_id --output text)

# 4. 보안그룹에 인바운드 정책 추가
$ aws ec2 authorize-security-group-ingress --group-id $security_group_id --protocol tcp --port 2049 --cidr $cidr_range

# 5. EFS 생성
$ file_system_id=$(aws efs create-file-system --region $AWSREGION --performance-mode generalPurpose --tag Key=Name,Value=$ACCOUNT-efs --query 'FileSystemId' --output text)

EFS Mount Target 생성

VPC 서브넷 ID와 AZ확인

aws ec2 describe-subnets --filters "Name=vpc-id,Values=$vpc_id" --query 'Subnets[*].{SubnetId: SubnetId,AvailabilityZone: AvailabilityZone,CidrBlock: CidrBlock}' --output table

EFS 콘솔에 들어가 생성된 EFS FileSystem ID를 확인한다.

# 타겟 서브넷에 Mount Target을 생성하고 보안그룹 적용
aws efs create-mount-target --file-system-id $file_system_id --subnet-id <subnet-id> --security-groups $security_group_id

aws efs create-mount-target --file-system-id $file_system_id --subnet-id <subnet-id> --security-groups $security_group_id

EFS 콘솔에서 네트워크에 해당 VPC가 탑재됐는지 확인한다.

EFS 생성 - Terraform

provider "aws" {
  region = var.region # 원하는 AWS 리전으로 변경
  access_key = var.access_key
  secret_key = var.secret_key

}
# 1. EKS 클러스터의 vpc_id 값 조회
data "aws_eks_cluster" "eks_cluster" {
  name = var.cluster_name
}

# 2. EKS 클러스터가 속한 vpc의 network cidr 조회
data "aws_vpc" "vpc" {
  id = data.aws_eks_cluster.eks_cluster.vpc_config[0].vpc_id
}


# 3. EFS의 보안그룹 생성
resource "aws_security_group" "efs_security_group" {
  name        = "${var.tag_name}-mongo-EfsSG"  # 보안 그룹 이름에 맞게 수정
  description = "EFS Security Group"
  vpc_id      = data.aws_vpc.vpc.id
}

# 4. 보안그룹에 인바운드 정책 추가
resource "aws_security_group_rule" "efs_inbound_rule" {
  type              = "ingress"
  from_port         = 2049
  to_port           = 2049
  protocol          = "tcp"
  security_group_id = aws_security_group.efs_security_group.id
  cidr_blocks       = [data.aws_vpc.vpc.cidr_block]
}

# 5. EFS 생성
resource "aws_efs_file_system" "mongoDB-EFS" {
  performance_mode = "generalPurpose"
  tags = {
    Name = "suite-mongo-test-efs"  # EFS 이름에 맞게 수정
  }
}

# JSON 데이터 구문 분석
locals {
  
  terraform_outputs = jsondecode(file("../../terraform_outputs.json"))
  
}


# 타겟 서브넷에 Mount Target을 생성하고 보안그룹 적용
resource "aws_efs_mount_target" "mongoDB" {
  count           = length(local.terraform_outputs.private_subnet_ids) - 1
  file_system_id  = aws_efs_file_system.mongoDB-EFS.id
  subnet_id       = local.terraform_outputs.private_subnet_ids.value[count.index]
  security_groups = [aws_security_group.efs_security_group.id]
}


output "efs_dns_name" {
  value = aws_efs_file_system.mongoDB-EFS.dns_name
}

json 파일의 경우 vpc를 만든 후 shell script를 통해 만들어 준다.
Terraform 참조 링크

#!/bin/bash

# Terraform output 명령을 사용하여 출력 값을 추출합니다.
output_values=$(terraform output -json)

# JSON 파일로 저장합니다. 원하는 파일 이름으로 변경하세요.
echo $output_values > terraform_outputs.json

echo "Terraform outputs have been saved to terraform_outputs.json"

EFS Storage Class 생성

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: efs-sc
parameters:
  directoryPerms: "700"
  fileSystemId: <fs-system-id>
  provisioningMode: efs-ap
provisioner: efs.csi.aws.com
kubectl create -f ./efs-sc.yml

Dynamic & Static Mountain

K8S 볼륨
위에서 살펴봤듯이 인프라 관리자가 PV를 만들어놓으면, 어플리케이션 개발자가 PVC를 POD에 붙여 볼륨을 얻어온다.

PV를 미리 만들어놓고, 나눠주는 방식이면 Static Mountain,
PVC를 만들어서 요청만하면 자동으로 볼륨이 붙는게 Dynamic Mountain이다.

PV하나에 PVC 하나만 붙기 때문에 관리해야 할 YML파일이 늘어나기 때문에
프로젝트의 규모가 크지 않고 체계적인 볼륨 관리의 긍정적 효과보다 관리의 비용이 더 크기 때문에 Dynamic Mountain을 선택했다.

볼륨 테스트

cat <<EOF | kubectl create -f - apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
	name: efs-pvc
spec: 
	accessModes:
		- ReadWriteMany 
    storageClassName: efs-sc 
    resources:
		requests: 
        	storage: 5Gi
--- 
apiVersion: v1 
kind: Pod 
metadata:
	name: efs-pod1 
spec:
	containers: 
    	- name: app
		  image: redis 
          volumeMounts:
			- name: efs-pv 
              mountPath: /mount1
	volumes:
		- name: efs-pv
		  persistentVolumeClaim: 
          	claimName: efs-pvc
--- 
apiVersion: v1 
kind: Pod 
metadata:
	name: efs-pod2 
spec:
	containers: 
    	- name: app
		  image: redis 
          volumeMounts:
			- name: efs-pv 
              mountPath: /mount2
	volumes:
	  - name: efs-pv
		persistentVolumeClaim: 
        claimName: efs-pvc
EOF
kubectl exec -it efs-pod1 -- /bin/bash

cd /mount1
echo hello efs > test.txt 
exit

kubectl exec -it efs-pod2 -- /bin/bash

cd /mount2 
echo test.txt 
exit

kubectl delete pod,pvc --all

출처

AWS EKS에서 EFS 활용하기

profile
최고의 오늘을 꿈꾸는 개발자

0개의 댓글