기존 자바로 진행했던 프로젝트를 코틀린으로 migration하면서 CI/CD를 도입하기 위해 배포를 위한 클라우드 아키텍처 구성을 시도해보았다.
회의 시, 팀원들에게 프로젝트에서 인프라적으로 추가하고 싶은 부분이 있는지 조사했는데, OCR을 위한 이미지 파일 관리, 로그 수집 및 모니터링, 프로젝트 배포 이렇게 크게 3가지 의견이 나왔었다. 이에 따라 내가 간단히 그려본 아키텍처는 다음과 같다. public, private subnet은 초기에는 (개발의 편의를 위해) 분리하지 않을테지만, 나중에 분리해서, NAT를 추가하거나 해야할거같다.
1.
OCR을 위한 이미지 파일 → S3 버킷을 파서 대용량 영수증 이미지 파일은 따로 저장. (추후 모델링 시도를 하고자 해도 이는 필요한 부분이라 생각했다)
2.
로그 수집 및 모니터링 → EC2 인스턴스를 따로 파서 Grafana, Prometheus, Loki를 활용한 모니터링 서버를 따로 만들고자 했다.
3.
서비스 배포 → Github Actions을 활용해 CI/CD를 진행하고 AWS CodeDeploy를 활용해서 파이프라인을 구축한다. 이후 도커를 활용해 이미지 파일로 배포를 수행할 예정이다.
Github Actions, CodeDeploy, S3, EC2를 활용한 배포 파이프라인 아키텍처는 나중에 따로 다뤄보겠다.
따로 비용지원은 없기에 모두 프리티어로 생성해야한다.
EC2 생성
OS는 Ubuntu Linux 22.04 LTS 버전을 사용한다. 아래쪽 인스턴스 유형도 t2.micro로 설정해준다.
키페어와 보안그룹도 새로 생성해준다. 네트워크 설정시에는 SSH와 HTTP 트래픽만 허용해주었다. (사실 어차피 나중에 인바운드 다 따로 열어야해서 굳이 지금 안해도 된다)
스토리지 볼륨은 EBS 최대 30GiB까지 설정된다고 하니까 우선 20만 설정해두자.
이렇게 인스턴스를 시작하면, 프리티어 만들기 완료.
인스턴스가 중지되는 경우에도 IP 소실을 막기 위해, 아래와 같이 탄력적 IP도 하나 생성해두자.
RDS 생성
RDS는 MySQL로 생성해준다. 템플릿은 무조건 프리 티어로!
인스턴스 식별자와 암호를 설정해준다. 인스턴스 식별자는 엔드포인트에 들어가게되는, 말그대로 인스턴스 이름을 지어주는 것이다.
여기서 과금 방지를 위해 스토리지 자동 조정 옵션을 꺼준다.
위에서 말했듯 개발의 편의를 위해 subnet은 추후 분리하기로 했으니, 우선 퍼블릭 액세스도 켜준다.
쭉 내려가서 생성시 초기 데이터베이스 이름도 설정해주고, 과금 방지를 위해 자동 백업 옵션도 꺼주고, 데이터베이스 생성 버튼을 누르면 끝!
S3 생성
이제 S3을 생성해서 EC2 인스턴스와 연결해주는 작업이 필요하다. 정확히는, EC2 인스턴스에서 S3의 데이터를 건드릴 수 있는 권한을 부여해주는 작업이 필요하다.
먼저 버킷 이름을 입력하고 객체 소유권 설정을 한다. 다른 AWS 계정에서 접속할 일은 없어서 비활성화했다.
퍼블릭 액세스 차단도 모두 풀어주었다. 일단 퍼블릭으로 생성했고, 필요에 따라 차단을 풀어주면 된다.
비용 절감을 위해 버킷 버전관리는 비활성화, 객체를 암호화해서 저장하기 위해 암호화 여부도 설정했다. 이 경우 객체를 다운로드 할때는 모두 복호화해서 제공해준다. → 버킷 생성.
버킷 정책 수정
이제 버킷 정책을 수정해줘야한다. 버킷을 눌러서 권한 → 버킷 정책의 편집을 클릭한다.
버킷 ARN을 복사하고 정책 생성기를 클릭한다.
•
Select Type of Policy 에서 S3 Bucket Policy를 선택
•
Principal에 * 입력
•
Actions에 Get Object, Put Object 체크
•
Amazon Resource Name (ARN) 에 위에서 복사한 ARN을 입력한 후 /* 입력
•
ex) arn:aws:s3:::voya9e-s3/*
•
Add Statement 클릭
이러면 JSON 형식으로 정보들이 생긴다. 이를 복사하여 버킷 정책에 붙여넣는다.
이때 오류가 발생하는데, 그때는 arn:aws:s3:::voya9e-s3/* 와 같이 끝에 /*을 넣어주면 해결된다.
그 이유는,
•
리소스 지정의 정확성: AWS에서는 리소스를 정확하게 지정할 것을 권장한다. S3 버킷의 경우 버킷 이름만으로는 정확한 리소스 지정이 되지 않는다.
•
와일드카드 사용: arn:aws:s3:::voya9e-s3/ 와 같이 와일드카드()를 사용하면 해당 버킷 내의 모든 객체에 대한 정책을 적용할 수 있다. 이렇게 하면 버킷 내 모든 파일에 대한 권한 관리가 가능하다.
모두 완료되었으면 저장한다.
이후 폴더를 하나 만들어보면 잘 생성되는걸 확인할 수 있다.
EC2 인스턴스에서 S3 접속
이제 EC2 인스턴스에서 S3으로 접속하는 부분을 관리하기 위한 IAM 역할을 생성한다.
저렇게 ec2-s3 형식으로 만들어뒀다
IAM에 들어와 역할 생성 버튼을 누른다.
사용 사례에서 EC2를 선택하고, 역할 세부정보를 입력하고 넘어간다.
EC2 인스턴스에서, 인스턴스 상태 → 보안 → IAM 역할 수정으로 들어간다.
IAM 역할에서 어떠한 정책도 설정하지 않았기에, 따로 설정을 해줘야한다.
IAM 메뉴에서 정책 메뉴를 클릭하고, 정책 생성 버튼을 누른다.
•
서비스 - S3
•
작업 - ListBucket, GetObject, PutObject를 검색하여 선택한다.
•
리소스 - 특정을 선택한 후, bucket과 object에 각각 ARN 추가를 한다.
이후 검토에서 정책이름과 설명을 입력하고 정책 생성을 누른다.
이후 액세스 키를 생성한다. CLI로 생성한다. 설명 태그도 간단히 작성 후 액세스키를 생성한다.
EC2 접속 후 S3 연결
ssh를 이용하여 EC2 인스턴스에 접근한 후, aws cli를 설치한다.
sudo apt update
sudo apt install awscli
Bash
복사
다음의 명령어로 Access Key를 입력하여 설정을 마무리한다. 그리고 aws s3 ls 명령어로 확인했는데,
aws configure
aws s3 ls
Bash
복사
An error occurred (AccessDenied) when calling the ListBuckets operation: User: arn:aws:iam::484907523898:user/voya9e is not authorized to perform: s3:ListAllMyBuckets because no identity-based policy allows the s3:ListAllMyBuckets action
이런 오류가 났다. 물론 나는 ListAllMyBuckets 정책을 추가하지는 않았는데, 왜 저렇게 뜨는건지…
일단 다시 정책 편집기로 들어가서 ListAllMyBuckets를 추가해주었다. ListAllMyBuckets는 리소스 레벨에서 특정 버킷을 지정할 수 없기때문에, "Resource": "*"로 설정해야한다.
이렇게 해보니, aws s3 ls 명령어가 정상적으로 작동했다. 문제를 해결하던 도중 알게된 것은, aws s3 ls <Bucket이름> 식으로 명시적으로 입력하면, 굳이 ListAllMyBuckets 설정이 없어도 되긴 한다는 점이다. 조금만 생각해보면 유추해 볼만 했는데, 너무 참고한 블로그 내용만 고려하다가 깊이 생각하지 못했던 것 같다.
test 파일을 하나 만들어서 업로드해보았다.
잘 실행되는걸 확인할 수 있었다.
Fix
React랑 SpringBoot는 각각 Public, Private Subnet에 들어갈 것으로 계획했기에, 퍼블릭 액세스 차단 부분에 대한 설정이 필요하다.
우선 기존에 만들었던 버킷은 차단 설정 해두고, 프론트쪽 코드를 업로드할 버킷을 새로 만들고 퍼블릭 모두 열어줬다.
이후 정적 웹 사이트 호스팅을 진행한다.