Gom3rye

AWS- EKS 본문

현대 오토에버 클라우드 스쿨

AWS- EKS

Gom3rye 2025. 7. 29. 17:50
728x90
반응형

클러스터 구축

  • EKS 클러스터 구축 도구 eksctl을 이용
  • AWS 관리 콘솔 또는 AWS CLI를 이용
  • AWS CloudFormation을 이용한 구축
    • AWS에 리소스를 구출할 때 AWS에서 제공하는 환경 구축 도구로는 CloudFormation과 HashiCorp사의 Terraform을 많이 이용한다.
    • AWS CloudFormation
      • IaC도구
        • Yaml 또는 Json으로 작성된 템플릿을 기반으로 리소스를 관리하는 도구
        • 반복 가능한 환경 구축(동일한 스택을 일관성있게 반복 배포, 팀원 간 공유 쉽다.)
        • Git 등과 사용하면 버전 관리 및 변경을 추적하고 배포 간소화 및 오류가 감소한다.
      • AWS 관리 콘솔
        • 웹 사용자 인터페이스
        • GUI 기반이라 쉽게 사용 가능
        • AWS 리소스 환경 구축을 하는 것은 CloudFormation으로 하지만 CloudFormation 자체는 AWS 관리 콘솔을 이용해 실행하고 구축 환경 확인도 관리 콘솔을 이용한다.
      • AWS CLI를 이용
        • AWS가 제공하는 명령줄 도구
        • 파이썬으로 만들어져 있음

EKS 구축에 사용하는 도구 설치

AWS CLI 설치 (eksctl 사용을 하기 위해서 설치)

→ 설치 확인: aws --version

  • 설치를 하고자 하는 경우는 access-key와 secret access-key를 발급 받아야 한다.
  • aws configure --profile 이름 명령을 이용해서 키를 등록
  • 프로필 확인: aws configure list-profiles

eksctl

kubectl 설치: 쿠버네티스 명령을 사용하기 위해 사용

Region: 논리 + 물리 (클러스터)

AZ: 물리 (데이터 센터, 워커 노드)

클러스터 구척

설치를 위해서 yaml 파일 작성(base_resource_cfn.yaml)

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  ClusterBaseName:
    Type: String
    Default: eks-work

  TargetRegion:
    Type: String
    Default: ap-northeast-2

  AvailabilityZone1:
    Type: String
    Default: ap-northeast-2a

  AvailabilityZone2:
    Type: String
    Default: ap-northeast-2b

  AvailabilityZone3:
    Type: String
    Default: ap-northeast-2c

  VpcBlock:
    Type: String
    Default: 192.168.0.0/16

  WorkerSubnet1Block:
    Type: String
    Default: 192.168.0.0/24

  WorkerSubnet2Block:
    Type: String
    Default: 192.168.1.0/24

  WorkerSubnet3Block:
    Type: String
    Default: 192.168.2.0/24

Resources:
  EksWorkVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-VPC

  WorkerSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone1
      CidrBlock: !Ref WorkerSubnet1Block
      VpcId: !Ref EksWorkVPC
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-WorkerSubnet1

  WorkerSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone2
      CidrBlock: !Ref WorkerSubnet2Block
      VpcId: !Ref EksWorkVPC
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-WorkerSubnet2

  WorkerSubnet3:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone3
      CidrBlock: !Ref WorkerSubnet3Block
      VpcId: !Ref EksWorkVPC
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-WorkerSubnet3

  InternetGateway:
    Type: AWS::EC2::InternetGateway

  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref EksWorkVPC

  WorkerSubnetRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref EksWorkVPC
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-WorkerSubnetRouteTable

  WorkerSubnetRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref WorkerSubnetRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  WorkerSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WorkerSubnet1
      RouteTableId: !Ref WorkerSubnetRouteTable

  WorkerSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WorkerSubnet2
      RouteTableId: !Ref WorkerSubnetRouteTable

  WorkerSubnet3RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WorkerSubnet3
      RouteTableId: !Ref WorkerSubnetRouteTable

Outputs:
  VPC:
    Value: !Ref EksWorkVPC

  WorkerSubnets:
    Value: !Join
      - ","
      - [!Ref WorkerSubnet1, !Ref WorkerSubnet2, !Ref WorkerSubnet3]

  RouteTable:
    Value: !Ref WorkerSubnetRouteTable
  • AWS의 CloudFormation 페이지로 이동
    • 스택 생성 버튼 클릭
    • 기존 템플릿 선택하고 템플릿 파일 업로드를 선택하고 파일을 선택
    • 다음 화면에서 스택에 대한 설정
      • 스택 이름을 설정하면 나머지 파라미터는 자동으로 읽어서 설정을 한다.
    • 나머지 옵션은 기본 설정 가능
    • 스택을 생성한다고 하고 VPC 서비스에 접속해 VPC가 제대로 생성되었는지 확인
    • CloudFormation에서 스택이 생성되었는지 확인하고 스택을 클릭
      • 출력을 눌러서 WorkSubnets 값을 복사(EKS 클러스터 만들 때 필요하다.)
      • subnet-~~~~~~
  • 클러스터 생성(시간이 조금 소모됨)
eksctl create cluster
--vpc-public-subnets 복사한서브넷값
--name 클러스터이름
--region 리전이름
--version eks클러스터버전
--nodegroup-name 노드그룹이름
--node-type 워커노드 인스턴스 타입
--nodes 워커 노드 개수
--nodes-min 워커 노드의 최소 개수
--nodes-max 워커 노드의 최대 개수

eksctl create cluster --vpc-public-subnets subnet-04f~~~ --name eks-work-cluster --region ap-northeast-2 --version 1.19 --nodegroup-name eks-work-nodegroup --node-type t2.small --nodes 2 --nodes-min 2 --nodes-max 5
  • IAM 유저에게 인라인 정책 생성을 이용해서 권한을 추가
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Statement1",
      "Effect": "Allow",
      "Action": [
        "*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
  • 클러스터 구축에 성공하면 CloudFormation에 스택이 2개가 추가된다.
  • EC2를 확인해보면 worker node의 개수만큼 인스턴스가 추가된다.

로컬에서 클러스터 명령을 수행하기 위한 kubeconfig 설정

  • eksctl은 EKS 클러스터 구축 중에 kubeconfig(kubectl을 설치하면 생성되는 ~/.kube/config) 파일을 자동으로 업데이트
  • kubeconfig는 쿠버네티스 클라이언트인 kubectl이 이용할 설정 파일로 접속 대상 쿠버네티스 접속 정보를 저장하고 있다.
  • eks 클러스터에 접속하기 위한 인증 정보는 AWS CLI로 확인 가능하면 eksctl을 사용하면 AWS CLI를 호출하여 인증하기 위한 설정을 kubeconfig 파일에 포함할 수 있다.
  • kubeconfig 설정
- clusters: 쿠버네티스 클러스터 정보
- users
클러스트에 접근할 유저 정보
각 환경마다 필요한 값들
- context: cluster와 user의 조합
- current-context: 현재 사용하는 context를 지정하는 부분
  • eks 클러스터 연결 확인: aws eks get-token --cluster-name eks-worker-cluster
  • ./kube/config 파일에 eks 클러스터 설정이 없는 경우
    • aws eks update-kubeconfig --region 리전이름 --name 클러스터이름
  • 현재 사용 중인 context 확인: kubectl config get-contexts
  • 노드 상태 조회: kubectl get nodes

동작 확인

  • pod 배포를 위한 yaml파일 작성
# pod-sample.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx-app
spec:
  containers:
  - name: nginx-container
    image: nginx
    ports:
    - containerPort: 80
    
# 리소스 생성
kubectl apply -f pod-sample.yaml
# 파드 확인
kubectl get pods -o wide
# 포트포워딩
kubectl port-forward nginx-pod 8088:80
# 브라우저에서 localhost:8088

BackEnd Application 배포

  • 로컬에서 테스트
    • 도커로 postgresql 설치
    docker run -d -p 외부포트번호:5432 -e POSTGRES_PASSWORD="관리자비밀번호" --name 컨테이너이름 postgres
    관리자 계정은 postgres
    
    docker run -d -p 5432:5432 -e POSTGRES_PASSWORD="~~~" --name postgres postgres
    
    • 데이터베이스 접속 도구로 접속
    • 사용자 및 데이터베이스 생성
      • create USER 유저이름 PASSWORD 비밀번호 권한;
      • create USER mywork PASSWORD ‘~~~’ SUPERUSER;
      • create DATABASE myworkdb OWNER mywork;
    • 샘플 테이블 생성
    CREATE TABLE region(
        region_id SERIAL PRIMARY KEY,
        region_name VARCHAR(100) NOT NULL,
        creation_timestamp TIMESTAMP NOT NULL
    );
    
    CREATE TABLE location(
        location_id BIGSERIAL PRIMARY KEY,
        location_name VARCHAR(200) NOT NULL,
        region_id BIGINT NOT NULL,
        note TEXT,
        FOREIGN KEY (region_id) REFERENCES region (region_id)
    );
    
    CREATE TABLE batch_processing(
        batch_name VARCHAR(20) PRIMARY KEY,
        last_execution_date_time TIMESTAMP
    );
    
    CREATE TABLE batch_processing_file(
        batch_processing_file_id BIGSERIAL PRIMARY KEY,
        batch_name VARCHAR(20) NOT NULL,
        file_name VARCHAR(300) NOT NULL
    );
    
    • 샘플 데이터 작성 → 6.AWS_EKS_1.pdf 36페이지에 있다.
    • Spring Boot Application 생성
      • 의존성: Spring Boot DevTools, Lombok, Spring Data JPA, PostgreSQL Driver, Spring Web)
      • build.gradle에 dependencies 에 아래 내용 추가하고 build
      dependencies {
          implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
          implementation 'org.springframework.boot:spring-boot-starter-web'
          compileOnly 'org.projectlombok:lombok'
          developmentOnly 'org.springframework.boot:spring-boot-devtools'
          runtimeOnly 'org.postgresql:postgresql'
          annotationProcessor 'org.projectlombok:lombok'
          implementation 'org.apache.commons:commons-lang3:3.9'
          testImplementation ('org.springframework.boot:spring-boot-starter-test'){
              exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
          }
          testImplementation 'com.ninja-squad:DbSetup:2.1.0'
          testImplementation 'org.assertj:assertj-db:1.3.0'
          testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
      }
      
      spring:
        application:
          name: eks_backend
          
       datasource:
         url: jdbc:postgresql://localhost:5432/myworkdb
         username: mywork
         password: ~~~~
         driver-class-name: org.postgresql.Drive
         type: com.zaxxer.hikari.HikariDataSource
         
         jpa: # jpa는 interface고 hibernate가 실제 구현체
           database-platform=org.hibernate.dialect.PostgreSQLDialect
      
      • src/main/resources/logback.xml 파일 생성
      <?xml version="1.0" encoding="UTF-8" ?>
      <configuration>
          <appender name="SDTOUT" class="ch.qos.logback.core.ConsoleAppender">
              <encoder>
                  <pattern>%d{yyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
              </encoder>
          </appender>
          
          <root level="info">
              <appender-ref ref="STDOUT" />
          </root>
      </configuration>
      
      • 이미 포트가 쓰였다고 나오면 application.yaml에서
        • server: port: 9000 작성해주면 된다.
      • 모든 Entity(데이터베이스 테이블과 매핑되는 클래스)가 공통으로 가져야 하는 메서드를 소유한 추상 클래스 생성
      // /entity/AbstractEntity.java
      
      public abstract class AbstractEntity {
          @Override
          public String toString() {
              return ToStringBuilder.reflectionToString(this);
          }
          @Override
          public boolean equals(Object obj) {
              if(obj == null) {
                  return false;
              }
              if(obj == this) {
                  return true;
              }
              if(obj.getClass() != this.getClass()) {
                  return false;
              }
              return EqualsBuilder.reflectionEquals(this, obj);
          }
          @Override
          public int hashCode() {
              return HashCodeBuilder.reflectionHashCode(this);
          }
      }
      
      • Region 테이블과 연동되는 RegionEntity 클래스 생성
      // /entity/RegionEntity.java
      @Entity
      @Table(name="REGION")
      @Getter
      @Setter
      public class RegionEntity extends AbstractEntity {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          @Column(name="REGION_ID")
          private Integer regionId;
          @Column(name="REGION_NAME")
          private String regionName;
          @Column(name="CREATION_TIMESTAMP")
          private LocalDateTime creationTimestamp;
      }
      
      • Location 테이블과 연동되는 LocationEntity 클래스 생성
      // /entity/LocationEntity.java
      @Entity
      @Table(name = "LOCATION")
      public class LocationEntity extends AbstractEntity {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          @Column(name = "LOCATION_ID")
          private Long locationId;
          @Column(name="LOCATION_NAME")
          private String locationName;
          @ManyToOne
          @JoinColumn(name = "REGION_ID")
          private RegionEntity region;
          @Column(name = "NOTE")
          private String note;
      }
      
      • BatchProcessing 테이블 과 연동하는 Entity 클래스
      // /entity/BatchProcessingEntity.java
      @Entity
      @Table(name="BATCH_PROCESSING")
      @Data
      public class BatchProcessingEntity extends AbstractEntity{
          @Id
          @Column(name = "BATCH_NAME", length=20, nullable=false)
          private String batchName;
          @Column(name="LAST_EXECUTION_DATE_TIME")
          private LocalDateTime lastExecutionDateTime;
          @OneToMany(mappedBy="batchProcessing", cascade= CascadeType.ALL)
          private List<BatchProcessingFileEntity> fileList;
      }
      
      • BATCH_PROCESSING_FILE 테이블 과 연동할 Entity
      // /entity/BatchProcessingFileEntity.java
      @Entity
      @Table(name="BATCH_PROCESING_FILE")
      @Data
      public class BatchProcessingFileEntity {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private Long batchProcessingFileId;
          @ManyToOne
          @JoinColumn(name = "BATCH_NAME", nullable = false)
          private BatchProcessingFileEntity batchProcessingFileEntity;
          @Column(name = "FILE_NAME", length=300, nullable = false)
          private String fileName;
      }
      
      • Region 테이블의 CRUD 작업을 위한 Repository 생성
      // /repository/RegionRepository.java
      @Repository
      public interface RegionRepository extends JpaRepository<RegionEntity, Integer> {
          //메서드 이름으로 sql을 생성
          //regionName으로 데이터를 조회해주는 메서드
          Optional<RegionEntity> findByRegionName(String regionName);
      }
      
      • Location 테이블의 CRUD 작업을 위한 Repository 생성
      // /repository/LocationRepository.java
      @Repository
      public interface LocationRepository extends JpaRepository<LocationEntity,Long> {
          //RegionEntity를 대입하면 동일한 값을 갖는 Location을 전부 조회
          List<LocationEntity> findByRegion(RegionEntity region);
      }
      
      • BatchProcessing 테이블의 CRUD 작업을 위한 Repository 생성
      // /repository/BatchProcessingRepository.java
      @Repository
      public interface BatchProcessingRepository extends JpaRepository<BatchProcessingEntity,Long> {
          @Lock(LockModeType.PESSIMISTIC_WRITE)
          @QueryHints(@QueryHint(name = "javax.persistence.lock.timeout", value = "0"))
          @Query("Select bp from BatchProcessingEntity bp where bp.batchName = :batchName")
          Optional<BatchProcessingEntity> fineByIdWithLock(String batchName);
      }
      
      • BatchProcessingFile 테이블을 연동할 Repositoy 생성
      // /repository/BatchProcessingFileRepository.java
      public interface BatchProcessingFileRepository extends JpaRepository<> {
          void deleteByFileName(String fileName );
      }
      
      • RegionRepository를 테스트하기 위한 클래스를 test 디렉토리 패키지에 생성

To be continued...

  • 애플리케이션을 이미지로 배포
  • 쿠버네티스에 데이터베이스와 애플리케이션 배포
728x90
반응형

'현대 오토에버 클라우드 스쿨' 카테고리의 다른 글

AWS- EKS  (4) 2025.08.04
작심 큰일 챌린지 - 달빛 여우 (파이썬)  (4) 2025.08.04
AWS- ECS  (1) 2025.07.28
AWS Container Service  (5) 2025.07.25
AWS의 Database  (3) 2025.07.23