Kubernetes

EKS에 EFS Mount하기

백셀건전지 2021. 8. 31. 15:24

0. 개요

Amazon Elastic File System(Amazon EFS)은 AWS 클라우드 서비스와 온프레미스 리소스에서 사용할 수 있는 간단하고 확장 가능하며 탄력적인 완전 관리형 탄력적 NFS 파일 시스템을 제공한다.

아래의 내용에서는 helm을 이용하여 생성한 EFS 볼륨을 pod에 붙여 Gitlab Runner를 통해 자동 배포하는 과정을 기술한다.

1. EFS 생성하기

1.1 보안 그룹 생성

EFS에 적용할 보안 그룹을 생성한다.

EC2 - Security Group - 'Create security group'을 클릭한다.

 

보안 그룹의 이름과 Description을 기입하고, VPC를 선택한 후, Inbound rule을 추가한다.

Inbound는 EKS의 Worker Node 보안 그룹을 추가한다.

EKS 보안 그룹의 Port는 2049로 입력한 후 생성한다

보안 그룹 생성 후 해당 그룹을 다시 클릭하여 inbound rule에 자기 자신의 보안 그룹:2049번 포트를 추가한다.

1.2 EFS 생성

AWS Console의 EFS에서 'Create file system' 버튼을 클릭하여 EFS를 생성한다.

VPC 설정 후 Subnet과 1.1에서 생성한 Security Group을 선택한다.

Name Tag를 입력한 후, 데이터 암호화가 필요하면 아래에 'Enable encryption of data at rest'을 클릭하고, KMS를 선택한 후, 'Next Step'을 선택한다.

이후에는 Default 세팅으로 EFS를 생성한다.

2. EKS에 Mount하기

2.1 StorageClass, ConfigMap  EKS에 적용

EFS를 EKS에 마운트하기 위한 Storage Class와 Config Map을 EKS에 적용한다,

아래의 명령어를 통해 Storage Class와 Config Map을 로컬에 다운로드한다.

wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/aws/efs/deploy/class.yaml
wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/aws/efs/deploy/configmap.yaml

다운로드 후 configmap.yml의 file.system.id와 aws.region을 EFS에 알맞게 수정한다.

수정 후 아래의 명령어를 입력하여 kubectl에 Storage Class와 Config Map을 적용한다.

kubectl apply -f class.yaml
kubectl apply -f configmap.yaml

2.2 deployment.yml 수정

deployment.yml의 spec 하위에 volumeMount를, spec에 volume을 아래와 같이 추가한다.

deployment.yml파일은 helm template을 기반으로 작성되어, 중괄호 내의 값은 helm의 values.yaml파일에서 자동적으로 가져온다.

containers 하위의 volumeMount와 volume 속성을 추가한다.

containers:
  - name: {{ .Chart.Name }}
    securityContext:
      {{- toYaml .Values.securityContext | nindent 12 }}
    image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}"
    imagePullPolicy: {{ .Values.image.pullPolicy }}
    ports:
      - name: http
        containerPort: <PORT_NO>
        protocol: TCP
    livenessProbe:
      httpGet:
        path: /healthcheck
        port: http
    readinessProbe:
      httpGet:
        path: /healthcheck
        port: http
    resources:
      {{- toYaml .Values.resources | nindent 12 }}
    env:
      - name: spring.profiles.active
        value: {{ .Values.envVariables.profiles }}
      - name: SPRING_DATASOURCE_URL
        value: {{ .Values.envVariables.datasource_url }}
      - name: SPRING_DATASOURCE_USERNAME
        value: {{ .Values.envVariables.datasource_username }}
      - name: SPRING_DATASOURCE_PASSWORD
        value: {{ .Values.envVariables.datasource_password }}
    volumeMounts:
      - name: share
        mountPath: /share
volumes:
  - name: share
    nfs:
      server: {{ .Values.persistence.shareServer }}
      path: /

2.3 values.yml 수정

위의 volumes 속성의 nfs: server: 에 들어간 persistence.shareServer 값을 values.yaml에 추가한다.

값은 직접 입력하지 않고, CI/CD 환경에서 EFS ID를 동적으로 read하여 helm upgrade할 때 변수를 set할 것이므로 비워둔다.

persistence:
  shareServer:

2.4 .gitlab-ci.yml 수정

helm chart 기반으로 배포하는 helm upgrade 명령어에 EFS의 dns name을 변수로 추가한다.

deploy stage에서 EFS ID를 가져오는 명령어를 실행하고, 그 EFS ID 변수를 heml upgrade의 변수로 넘겨준다.

아래의 명령어를 참고하여 helm upgrade를 수정한다.

- EFSID=$(aws efs describe-file-systems --region ap-northeast-2 --query 'FileSystems[?Name==`${EFS_NAME}`].FileSystemId' --output text)
 
- helm upgrade --install --namespace ${APPLICATION_NAME} --set persistence.shareServer="${EFSID}.efs.ap-northeast-2.amazonaws.com" --debug ${APPLICATION_NAME}-dev ./chart

Gitlab Runner의 log를 확인하여 volume 변수가 정상적으로 입력되었는지 확인한다.

3. EKS Mount되었는지 확인하기

3.1 Pod 접속

kubectl get po 명령어로 신규로 배포된 pod의 ID를 확인한 후, kubectl exec 명령어로 신규로 생성된 두개의 pod 중 하나에 접속한다.

접속 후 mount 된 share 디렉토리에 들어가 cat 명령어로 임시 파일을 생성한 후 다른 하나의 pod에 접속하여 share 디렉토리가 접근이 가능한지 확인한다.

정상적으로 mount되어 같은 파일을 두 개의 pod에서 접근이 가능하다.