본문 바로가기
AWS Cloud School 8기/CICD

[CI/CD] EKS 환경에서 동적 프로비저닝/ EBS/ EFS/ NFS/ EKS

by YUNZEE 2025. 5. 12.
728x90

📌 EBS (Elastic Block Store)

✅ EBS(Block) - 하드웨어(디스크)

-> 블록 스토리지 서비스: 데이터를 블록 단위로 저장하는 방식임. 하드 드라이브와 비슷한 개념

-> EC2 인스턴스와 함께 사용되며, EC2에서 실행되는 애플리케이션의 데이터를 저장하는 데 사용됨

-> 단일 EC2 인스턴스에 연결(attach)돼서 동작하고, 데이터베이스, 로그 파일 등을 저장하는 데 적합함

-> 파일 시스템이 구성이 안되어있음

특정 노드(attach 된)에 존재하는 pod만 접근 가능함

 

주요 특징:

  • 지속적 저장: EC2가 종료돼도 데이터가 유지됨.
  • 성능 최적화: IOPS, 처리량, 지연 시간을 설정하여 성능을 조정할 수 있어.
  • 확장성: 스냅샷을 통해 데이터 백업 및 복원 가능.

📌 EFS (Elastic File System)

✅ EFS는 파일 스토리지 서비스

- EFS는 파일 시스템으로, 여러 EC2 인스턴스나 컨테이너에서 동시에 파일을 공유할 수 있음

- NFS 프로토콜을 사용해서, 네트워크를 통해 파일 시스템을 공유하고 확장 가능한 장소를 제공함

-> 다수의 인스턴스에서 접근 가능

여러 노드에 존재하는 다수의 pod들이 접근 가능함

-> 그래서 EKS환경에서 동적 프로비저닝을 할 때는 이걸 사용해야 됨

 

주요 특징:

  • 파일 시스템: 여러 EC2 인스턴스나 애플리케이션에서 공유된 파일 시스템을 사용.
  • 자동 확장: 사용량에 따라 자동으로 용량을 확장함.
  • NFS 호환: NFS 프로토콜을 지원해, Linux와 다른 시스템에서 쉽게 연결 가능.

📌 NFS (Network File System)

NFS네트워크를 통한 파일 시스템 공유 프로토콜

- NFS는 파일 시스템을 네트워크를 통해 공유할 수 있게 해주는 프로토콜

- 여러 컴퓨터나 서버에서 파일을 공유하거나 접근할 수 있도록 돕는 기술

 

주요 특징:

  • 파일 공유: 여러 시스템이 동일한 파일 시스템을 사용하도록 만들어 줌.
  • 유연성: 다양한 시스템에서 접근할 수 있기 때문에, 여러 서버 간 파일 공유 시 유용.
  • 로컬 파일 시스템처럼 사용할 수 있지만, 네트워크를 통해 접근함.

여기서 EFS와 NFS가 밀접한 관련이 있는데 어떤 관련일까? 

- EFS는 NFS을 기반으로 AWS에서 제공되는 파일 시스템 서비스로, 여러 서버가 동일한 파일 시스템에 접근할 수 있게 해 줌

 

📌 EKS (Elastic Kubernetes Service)

EKS는 Kubernetes 관리형 서비스

-  Kubernetes는 컨테이너화된 애플리케이션을 관리하는 오케스트레이션 툴인데, EKS는 이 Kubernetes 클러스터를 AWS에서 관리해주는 서비스임

- 자동화된 클러스터 관리를 제공하며, 컨테이너화된 애플리케이션의 배포와 관리를 쉽게 만들어줌

 

주요 특징:

  • 관리형 서비스: Kubernetes 클러스터의 설치, 유지보수, 업그레이드를 AWS가 대신해줌.
  • 확장성: EKS는 자동으로 컨테이너를 확장하고, 애플리케이션의 부하에 맞춰 인프라를 관리해.
  • 보안: IAM과 연동되어 사용자 권한을 세밀하게 설정할 수 있음.

서비스 설명 연관성

EBS EC2 인스턴스에 블록 스토리지 제공 EC2와 연동, EKS에서도 사용 가능
EKS Kubernetes 클러스터 관리 서비스 EBS와 연결 가능, EFS도 연결 가능
EFS 여러 인스턴스에서 파일 시스템 공유 NFS 프로토콜 기반, EKS와 EC2에서 사용
NFS 네트워크를 통한 파일 시스템 공유 EFS는 NFS를 기반으로 작동

📌EKS 환경에서 동적 프로비저닝

CSI(Container Stroage Interface) = 다이나믹 프로비저닝을 위한 애드온

ALB 생성을 위한 LB controller를 설치했던 것과 유사함

더보기
export CLUSTER_NAME=<본인꺼>
export ACCOUNT_ID=<본인꺼>
export VPC_ID=<본인꺼>
export REGION=ap-northeast-2
export ROLE_NAME=AmazonEKS_EFS_CSI_DriverRole

 

OIDC 활성화

eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --approve

 

- 원래 있는 정책을 사용할 예정

eksctl create iamserviceaccount \
    --name efs-csi-controller-sa \
    --namespace kube-system \
    --cluster $CLUSTER_NAME \
    --role-name $ROLE_NAME \
    --role-only \
    --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEFSCSIDriverPolicy \
    --approve

--attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEFSCSIDriverPolicy \

- IRSA =  ROLE_NAME = AmazonEKS_EFS_CSI_DriverRole 생성

- IAM SA = efs-csi-controller-sa 생성

- 정책은 이미 존재하는 관리형 정책 = AmazonEFSCSIDriverPolicy

kubectl get sa -n kube-system | grep -i  efs-csi-controller-sa

- 스택 충돌이 발생해서 안 생길 수도 있으니 만약에 생성이 안된다면 지우기

- 그래도 안 생김 

 

롤만 잘 만들어졌는지 확인?

role only로 해서 sa는 안 만들어진 상태임

정책 편집

- 정책을 편집할 필요는 없고, 이런 것도 있구나라고 생각하면 될 듯

애드온 설치

eksctl create addon --cluster $CLUSTER_NAME --name  aws-efs-csi-driver --version latest \
    --service-account-role-arn arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME --force

 - 생성이 잘 된 걸 확인할 수 있음

vi sc.yml

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: fs-0983c418c25220e37 #<자신의 efs 아이디>
  directoryPerms: "700"
kubectl apply -f sc.yml

 

vi pvc.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim-1
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Mi

RDS의 인증정보

- pod에서 불러온 시크릿 생성

- 데이터베이스가 없으면 생성이 안되기 때문에 생성해 주자

 

- 내가 생성한 시크릿

시크릿 CSI 드라이버 설치

OIDC 활성화

eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --approve

 

IAM SA생성

eksctl create iamserviceaccount --name secret-sa --region=$REGION --cluster $CLUSTER_NAME --attach-policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite --approve --override-existing-serviceaccounts

헬름으로 시크릿 CSI 드라이버를 설치

helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts

 

kube-system에 릴리스 생성

helm install -n kube-system csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver

 ASCP(AWS Secrets and Configuration Provider) 설치

- aws의 시크릿을 eks의 시크릿처럼 쓸 수 있게 만들어줌

더보기

 ASCP를 위한 헬름 레포 추가

helm repo add aws-secrets-manager https://aws.github.io/secrets-store-csi-driver-provider-aws

 

 ASCP 릴리스 생성

helm install -n kube-system secrets-provider-aws aws-secrets-manager/secrets-store-csi-driver-provider-aws

SecretProviderClass 생성

- 보안 암호 ARN을 넣어주면 됨

vi spc.yml

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: aws-secrets
spec:
  provider: aws
  parameters:
    objects: |
        - objectName: "<내 시크릿의 ARN>"
# metadata.name: aws-secrets 이거는 나중에 파드 정의시 SecretProviderClass를 명시할때 쓰이는 이름.

pod 공간 부족으로 안 생길 수도 있으니 파드를 늘려줌

eksctl scale nodegroup   --cluster rapa   --name mycng   --nodes 4   --nodes-max 4

ArgoCD(Continuous Deployment)

- k8s환경에서 CD를 하기 위한 툴

- CNCF에서 강추하는 CD툴

더보기

ArgoCD 설치

네임 스페이스 생성

kubectl create ns argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

 

LoadBalancer로 타입변경

kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'

 - 서비스 타입이 잘 바뀐 걸 확인할 수 있음

만약에 안 바뀐다면 용량이슈가 있을 수 있으니

eksctl scale nodegroup --cluster <클러스터이름> --name <노드그룹이름> --nodes <변경할노드수> --nodes-max <변경할최대노드수>

node의 상을 늘려주면 됨. 한 4개 정도 

 

주소 확인

kubectl get svc -n argocd | grep -i argocd-server

 초기 패스워드 조회 

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo

 

- 그리고 다시 로그인해주기

 vi argo-svc.yml

apiVersion: v1
kind: Service
metadata:
  name: svc-ip
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80

- 누구는 annotation 안 붙이고, classic으로 생성됨

-> LB Controller가 설치 안된 경우

- LB Controller가 설치되어 있다면 기본 ELB가 NLB였던 걸로 기억

-> 따라서 LBC가 설치되어 있는 사람은 NLB가 생성되면서 annotation 설정이 없었으면 private 서브넷이니까 internal로 생성됐을 것

-> 그런 경우엔 annotation에서 그냥 internet-facing으로 하면 됨

 

내가 배포할 deployment는 github의 레포에 둘 예정

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-dep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      name: nginx-pod
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-con
        image: oolralra/ipnginx
kubectl delete svc --all
kubectl delete deploy --all

- deployment 파일을 생성.

- (강사님 이미지)

- argoCD가 모니터링할 레포의 파일

ArgoCD에서 위 레포를 모니터링하도록 설정

더보기

 

- 위의 내 주소 넣어주기

- connect 해주고

 

레포를 등록했다면,  이번에는 앱을 띄우면 됨

create 해주면 네임스페이가 잘 배포된 걸 확인할 수 있음

 

- rev(=revision number는 1)

- rs의 레플리카수는 1

- 현재 replicas: 1인데 이걸 바꿔보자

- 말하고자 하는 포인트는, 결국 github 레포의 매니페스트를 수정하면, 그걸 모니터링하고 있는 argoCD가 자동으로(=Continuous) 그 수정된 사항을 반영시켜줌

- 2로 변경 후 apply

- 물론 자동으로 반영을 해주긴 하지만 10분 정도까지 걸릴 수 있기 때문에

sync를 눌러주면 즉시 반영됨

 

애플리케이션이 업데이트 됐다고 가정을 해보자

앱 업데이트(CD 관점)

CI

1. 프로그래밍 언어로 짜인 코드를 수정

2. 새로 앱빌드

3. 새로 컨테이너이미지 빌드 = 이미지의 태그가 변경이 됐다는 뜻함.

4. 그렇다면 이미지의 태그가 변경이 됐다는 사실을 어디에 명시? => 매니페스트 파일에 명시

 

CD

5. argoCD가 이를 인지해서 자동으로 apply를 해준다.

더보기

oolralra/ipnginx:latest 가 배포가 되어있는 상태 = 이미 만들어져 있는 구버전의 앱

oolralra/ipnginx:2 => 새로 업데이트된 앱. (hnginx) 호스트네임을 호출하는 앱

- rs가 두 개 => 기존 rs가 남아있음

- 새로 생성된 파드는 당연히 oolralra/ipnginx:2 라는 이미지로 구성되어있음. 즉 앱이 업데이트가 됐다는 의미임

- 아까는 ip주소가 나왔는데 지금은 호스트네임을 반환하는 것을 확인할 수 있음


- 기존이미지로 돌아간 상태.

- 다시 ipnginx로 돌아온 걸 확인할 수 있음

다시 SYNC를 클릭하면 전 상태로 돌아가는 걸 확인할 수 있음

 

argoCD의 장점

1. 설치가 쉽다

2. CD구성도 쉽다

3. 편리하게 버전 업데이트 및 롤백도 가능함

4. 시각화

실습 1)

ECR이나 도커허브를 통해 앱을 업데이트해보세요.

<여러분들 ECR이나 허브주소>/web-argo:1 은

nginx를 기반으로 'CD is difficult'라는 내용을 배포

<여러분들 ECR이나 허브주소>/web-argo:2 는

nginx를 기반으로 'CD is easy'라는 내용을 배포하는 이미지 일 때

github/<본인아이디>/web-argo 라는 레포에 매니페스트를 등록해 두고 매니페스트의 이미지를 web-argo:1에서 web-argo:2로 변경했을 때 10분 정도 대기후 자동으로 앱이 변경되는지 확인해 보세요.

더보기

디렉토리 구조

web-argo/
├── Dockerfile
└── index.html

web-argo:1 만들고 빌드 푸시 후, 다시 내용만 변경해서 빌드 후

<!-- index.html -->
<h1>CD is difficult</h1>

web-argo:2

<!-- index.html -->
<h1>CD is easy</h1>

Dockerfile 예시

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html

 이미지 빌드 & 푸시

# difficult 버전
docker build -t choyunji/web-argo:1 .
docker push choyunji/web-argo:1

# easy 버전 (index.html 수정 후 다시 빌드)
# index.html 내용 변경 후 ↓
docker build -t choyunji/web-argo:2 .
docker push choyunji/web-argo:2

 위에 방식처럼 deployment 디렉토리를 생성하고 

근데 잘못 만들고 다시 빌드랑 푸시를 했을 때

kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
web-argo-7d57c787fd-nnb5l   1/1     Running   0          21m
web-dep-555c7f6b5b-g5n78    1/1     Running   0          62m
web-dep-555c7f6b5b-wtl8s    1/1     Running   0          62m

-> 전에 잘못 만든 거 푸시했을 때 web-argo를 지우고 다시 해야 됨

-> 그래야 변경된 내용이 다시 반영됨

kubectl delete pod web-argo-7d57c787fd-nnb5l
#pod "web-argo-7d57c787fd-nnb5l" deleted

-> 지우면 자동으로 다시 생성됨

kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
web-argo-7d57c787fd-nnb5l   1/1     Running   0          21m
web-dep-555c7f6b5b-g5n78    1/1     Running   0          62m
web-dep-555c7f6b5b-wtl8s    1/1     Running   0          62m

 

-> 바로 다시 생성된 걸 볼 수 있음

curl k8s-default-svcip-1db558bd67-2c2a46f438a8d8bd.elb.ap-northeast-2.amazonaws.com
#<h1>CD is difficult<h1>

-> 결과가 잘 나오는 걸 확인 할 수 있음

 

변경한 후

 

 

 

728x90

'AWS Cloud School 8기 > CICD' 카테고리의 다른 글

[CI/CD] Github-action을 통한 CI/CD  (1) 2025.05.11