AWS ECS 인프라 구축(2)

hbjs97·2023년 8월 3일
0

AWS-ECS

목록 보기
2/4

시스템 구성도

AWS ECS 인프라 구축(1) 편에서 네트워크 구성 후 배포테스트에 성공했다.
이번에는 테스트용 ecs 클러스터를 제거하고 spring boot 애플리케이션을 배포해보려고한다.
시스템 구성도는 다음과같이 수정되었다.

수정사항

  • vpc 외부에서 public subnet으로 향하는 NLB 제거
  • public subnet의 테스트용 ecs 클러스터 제거
  • secret manager 대신 parameter store 사용

이번에는 두 AZ를 포함하는 private subnet에 spring boot 애플리케이션을 배포해보려고한다.
환경변수는 parameter store에서 가져와 사용한다.


로드밸런서 생성

VPC 외부의 요청을 내부의 private subnet으로 라우팅해줄 로드밸런서를 만든다.


ECS 클러스터 생성

서비스를 배포할 private subnet을 선택하고, ecs 클러스터를 생성한다.


Parameter Store 설정

우선, 배포할 서버 애플리케이션에 사용될 환경변수가 어떻게 이용되는지 정의한다.
당장은 db를 붙이지 않고 환경변수가 잘 로드되어 사용되는지만 확인할 예정이다.\

엔드포인트를 하나 만들고, parameter store 에서 값을 가져와 출력하려고한다.
이를위해 의존성을 추가해야한다.
위 프로젝트의 스프링부트 버전은 2.7.0이다.
스프링부트 버전과 parameter-store-config 의존성 버전이 맞지않아 여러 문제가 발생했었다.
충돌없는 버전을 찾아 진행해야한다.

dependencyManagement {
    imports {
        mavenBom("io.awspring.cloud:spring-cloud-aws-dependencies:2.3.3")
    }
}

...

implementation("io.awspring.cloud:spring-cloud-starter-aws-parameter-store-config")

의존성을 설치했으면 설정파일에 추가해줘야한다.

active profile에 따라 두개의 설정을 구분했다.

# application.yaml
spring:
    config:
        import: 'aws-parameterstore:'
    profiles:
        active: prod
#    application:
#        name: release-me

---

spring:
    config:
        import: 'aws-parameterstore:'
    profiles:
        active: local
#    application:
#        name: release-me
# applicaiton-{profile}.yaml
server:
    port: 7000

# 전적으로 spring.application.name을 참조한다.
# name 설명보면 spring.application.name를 override 한다고 되어있는데, override 하지 않는다.
# defaultContext 역시 영향일 끼치지 못한다.
aws:
    paramstore:
        enabled: true
        region: ap-northeast-2
        prefix: /config
        #        name: application # 의미없음
        profileSeparator: _
        #        defaultContext: application # 의미없음

parameter store 사용법에 대해 여러 블로그의 포스팅을 찾아봤는데, 나와 일치하는 경우가 없었다.
파라미터를 사용 시 다음 규칙이 있다고한다.
{prefix}/{name}{profileSeparator}{profile}/key

prefix: 파라미터의 접두사로, / 로 시작해야한다.
name: 애플리케이션 이름으로, 지정하지 않으면 spring.application.name 값을 참조한다.
profile-separator: 여러 환경을 구분할 수 있게 하는 profile 구분자
profile: active profile

위 내용이 검색해서 나온 내용들이었는데, 어떻게 적용되지 않았는지 알아본다.

우선 로컬환경에서 테스트하기 위해 iam 역할을 부여한다.

그리고 로컬환경에 key 값을 등록한다.

vi ~/.aws/credentials
[default]
aws_access_key_id =
aws_secret_access_key =

vi ~/.aws/config
[default]
region = ap-northeast-2
output = json

인증 설정이 끝났으면 parameter store에 값을 추가한다.

위와같이 파라미터를 4개 생성했고, 각 파라미터의 값은 이름과 같다.

만약, /config/release-me_local/word 값을 가져오고 싶다면

aws:
    paramstore:
        enabled: true
        region: ap-northeast-2
        prefix: /config
        name: release-me
        profileSeparator: _

위와같이 설정하면 될거라 생각했다.
하지만 예상과 달리 name이 정상적으로 작동하지 않았다.

application 이 name 필드에 들어가있었다.
혹시 defaultContext 값에 영향을 받는건가 싶어 수정해봤지만 아무변화가 없었다.
값을 바꿔가며 테스트해본결과 spring.application.name 값에 전적으로 의존하고있었다.
aws.paramstore.name 에 어떤값을 정의하든 spring.application.name을 참조한다.
spring.application.name에 값을 부여하지 않으면, 기본적으로 application 이 설정된다.

위와같이 설정하고 다시 확인해보면

정상적으로 조회된다.

profile 값도 정상적으로 처리되나 해서 확인해봤다.

파라미터를 추가하고 active profile = prod 로 테스트했다.

정상적으로 작동한다.


ECR 생성

리포지토리를 만들고 이미지 푸시가 정상적으로 되는지 테스트한다.
빌드해 jar 파일을 생성하고 도커 이미지를 만들어 푸시한다.

FROM openjdk:11
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]


ECS Fargate 서비스 배포

태스크 정의 후 서비스를 배포하는데 실패했다.

ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve ecr registry auth: service call has been retried 3 time(s): RequestError: send request failed caused by: Post "https://api.ecr.ap-northeast-2.amazonaws.com/": dial tcp 10.0.128.205:443: i/o timeout. Please check your task network configuration.

이전에 봤던 에러인데, ECR에서 이미지를 가져오지 못하는 문제로보인다. 생각해보니 private subnet에 엔드포인트를 구성하지 않았다.
엔드포인트를 구성하고 다시 배포테스트를 했으나, 여전히 같은 에러가 발생했다.
엔드포인트에 문제가 없다면 security group의 문제인가 싶어 확인해봤지만, 특별히 의심가는 부분이 보이지 않았다.

배포할 private subnet의 security group 정책은
inbound: 7000
outbound: 80, 443, 3306, 6379(database security group)
정도로 생각했다.

혹시나 하는 마음에 inbound, outbound 모두 트래픽을 열고 배포테스트를 진행했는데, 배포에 성공했다.
ecr, s3에서 데이터를 가져오는건 outbound 영역이니, 이 부분이 문제인가 싶어 수정해봤지만, 오히려 inbound가 문제였다.

inbound: 443, 7000
outbound: 80, 443, 3306, 6379(database security group)

위와같이 정책을 수정하니 배포에 성공했다. 하지만 api 요청을 정상적으로 받을 수 있는 상태는 아니었다.
private subnet으로 라우팅하는 NLB에서 health check 같은걸 해서 그런가 싶어 로그를 확인해보니 NLB에서 타겟그룹으로 요청이 제대로 가지않는 것 같다.

inbound 의 7000 포트가 서비스 애플리케이션 포트인데, 소스가 public subnet security group 으로 특정되어있었다.
0.0.0.0/0 로 소스를 수정하니 성공적으로 실행되었다.

security group

서비스 생성

1개의 댓글

comment-user-thumbnail
2023년 8월 3일

좋은 글이네요. 공유해주셔서 감사합니다.

답글 달기