일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Project
- 리엑트 네이티브 아이콘
- error
- img upload
- fire base
- react native font
- Next.js
- babel.config.js
- firebase 라이브러리
- aws bucket 정책
- react native 개발
- react native picker
- 백준
- react native 세팅
- js
- AWS
- React
- AWS Access Key
- 문자열 대소문자
- 리액트 네이티브
- GIT
- react native
- 에러
- s3 upload
- PongWorld
- 리액트
- Access Key 생성
- 리액트 네이티브 에러
- 문자열 대소문자 구별
- react native CLI
- Today
- Total
밝을희 클태
[ AWS ] CloudFront를 활용해 S3 GET요청 최적화 본문
두 명이서 개발을 진행하던 중, S3 GET요청 횟수를 봤는데 2만 회의 GET요청을 보내고 있는 걸 확인했다. 두 명이서 개발을 하고 있고 사이트에 s3 버킷의 이미지가 그렇게 많지 않아 큰 문제가 없을 거라 예상을 했는데 실제 사용자가 생기면 이것보다 훨씬 많은 GET 요청이 생길 거라 예상을 하고 요청을 최소화해야겠다고 생각을 했다.
그래서 알아본 게 AWS CloudFront이다.
CloudFront란?
CDN(Content Delivery Network) 서비스다.
CDN은 클라이언트가 요청한 콘텐츠를 제공할 때, 이전에 요청된 콘텐츠라면 엣지 로케이션(Edge Location)에 캐시 된 콘텐츠를 빠르게 제공하는 역할을 한다. 만약 처음 제공되는 콘텐츠라면 해당 콘텐츠를 엣지 로케이션에 캐시로 저장해 두고, 다음 요청 시 빠르게 콘텐츠를 제공할 수 있도록 한다.
Edge Location란?
Edge Location은 콘텐츠를 캐시하고 있는 서버다. Edge Location은 전 세계에 분산되어 있으며, 클라이언트의 위치로부터 가장 가까운 Edge Location에서 캐시 된 데이터를 제공함으로써 빠르게 콘텐츠를 서빙할 수 있다.
그래서 S3에 직접적으로 접근하지 않고 CloudFront를 사용해서 접근을 하면 어떤 이점이 있을까?
CloudFront에서 DDos 공격으로 부터 콘텐츠 보호
- CloudFront - Shield DDoS 완화 기능은 웹 애플리케이션에 유효한 트래픽만 서비스로 전달하도록 허용합니다. 이를 통해 UDP 반사 공격과 같은 여러 일반적인 DDoS 벡터로부터 자동으로 보호됩니다.
- CloudFront DNS 트래픽 방향과 애니캐스트 라우팅을 함께 사용합니다. 이러한 기술은 소스에 가까운 공격을 완화하고, 장애를 격리하고, 알려진 최대 규모의 공격을 완화할 수 있는 용량에 대한 액세스를 보장함으로써 애플리케이션의 복원력을 개선합니다.
- CloudFront 애플리케이션 오리진에 대한 지속적인 연결을 유지하고, Shield TCP SYN 프록시 기능과의 통합을 통해 TCP SYN 플러드를 자동으로 완화하며 엣지에서 전송 계층 보안 (TLS)을 종료합니다. 이러한 결합 특성을 통해 애플리케이션 오리진은 올바른 형식의 웹 요청만 수신하고 하위 계층 DDoS 공격, 연결 flood 및 TLS 남용으로부터 보호됩니다.
빠른 콘텐츠 제공
- CloudFront는 전 세계에 분산된 엣지 로케이션(Edge Location)을 통해 콘텐츠를 제공하므로, 사용자가 S3 버킷이 위치한 리전에 상관없이 더 빠르게 콘텐츠를 받을 수 있다.
S3 버킷 부하 감소
- Edge Location의 캐시 데이터를 사용해 S3 버킷에 직접적인 접근을 줄여 S3 버킷의 부하를 줄이고 비용을 줄일 수 있다.
이 외에도 많은 이점이 있다.
CloudFront를 사용해 S3 버킷의 GET 요청 최소화 하기
이번 글에서 나의 목표는 S3 버킷에 대한 GET 요청을 최소화하는 것이다. 그러기 위해선 사용 중인 S3 버킷의 퍼블릭 엑세스 차단을 활성화시켜 준다. 그러면 객체의 URL로 해당 객체에 접근할 수 없다. CloudFront로 우회를 해서 접근을 해야 한다.
그리고 CloudFront로 이동해서 배포 생성을 눌러준다.
위처럼 origin domain은 사용 중인 s3 버킷을 선택해 주면 이름은 자동으로 입력이 된다. 그러고 Create new OAC를 눌러준다.
이름과 설명을 입력해 주고 만들어준다.
Origin Shield란?
Origin Shield는 오리진 서버에 대한 요청을 줄이고 오리진 서버를 보호하기 위한 최종 캐싱 계층이다. 예시로 미국의 엣지 로케이션에 해당 캐시 데이터가 없다면, Regional Edge Cache를 통해 캐시 데이터를 확인한다. Regional Edge Cache에도 캐시가 없다면, 그다음에 Origin Shield에서 데이터를 요청하며, Origin Shield에도 캐시가 없다면 마지막으로 오리진 서버로 요청이 전달된다.
즉, Origin Shield는 오리진 서버 바로 앞에 위치하여 여러 엣지 로케이션이나 Regional Edge Caches에서 오리진 서버로의 요청을 처리하기 전에 한번 더 캐시를 확인하는 최종 보호 계층이다.
Origin Shield는 일정 수준 이상의 요청이 발생하면 가성비가 아주 훌륭한 편이라고 한다. 나의 경우 3차 캐시인 Origin Shield까지 사용할 필요는 없을 거라 생각해 활성화를 해주지 않았다.
아래의 이미지는 AWS Elemental에 대한 다이어그램인데 지금의 예제와 차이가 없어서 약간 수정한 다이어그램이다.
기본 캐시 동작의 뷰어 프로토콜 정책만 아래와 같이 바꿔주고
WAF는 비활성화해줬다. 따로 필요한 사람들 활성화를 해주면 될 거 같다. 비용은 추가로 나감
이제 새 배포를 생성해 주면 아래와 같이 노란색 바에 뜬 정책 복사를 눌러 정책을 복사해 준다.
S3 버킷으로 돌아가 권한 -> 버킷 정책 -> 편집으로 가서 붙여 넣고 저장해 준다.
이제 다시 CloudFront 콘솔로 돌아가서 방금 생성한 배포 도메인 이름을 확인한고,
브라우저의 주소창에 {배포 도메인 이름}/{S3 버킷 객체 URL}를 입력해 GET 요청을 보내 정상적으로 GET 요청이 되는지 확인한다.
그런데 프로젝트에서 사용할 때마다 저 외우지도 못할 이상한 규칙으로 만들어진 도메인 이름을 사용하기엔 너무 싫다. 그러면 대체 도메인을 설정하면 된다.
대체 도메인 설정
대체 도메인을 설정하기 위해서는 먼저 도메인을 구입해야 한다. 나는 가비아에서 도메인을 구입했다.
구입한 도메인에 서브 도메인을 만들어 해당 서브 도메인을 CloudFront의 대체 도메인으로 설정할 수 있다. 이렇게 하면 사용자들이 긴 CloudFront 배포 도메인 대신, 기억하기 쉽고 더 깔끔한 도메인으로 접속할 수 있다. 예를 들어, example.com이라는 도메인을 가지고 있다면, cdn.example.com 같은 서브 도메인을 만들어 CloudFront 배포와 연결할 수 있다.
우선 서브 도메인을 만들어야 한다.
CloudFront 탭으로 가서 방금 만든 배포 도메인 이름을 복사하고
가비아 DNS 설정으로 가서 아래와 같이 작성을 하는데 호스트는 사용할 서브 도메인을 입력해야 한다. 내가 image.keynut.co.kr 이라는 서브 도메인을 만들 거면 호스트에는 image를 적어줘야 한다.
Certbot은 수동으로 관리되는 웹사이트에서 Let's Encrypt 인증서를 자동으로 사용하여 HTTPS를 활성화하기 위한 무료 오픈 소스 소프트웨어 도구이다.
MAC에서 SSL 인증받는 법은 아래와 같이 하면 된다.
-d 뒤에는 원하는 서브 도메인을 적으면 된다.
$ brew install certbot
$ sudo certbot certonly --manual --preferred-challenges dns -d test.example.com
나는 이전에 이미 등록을 해서 안 뜨지만 이메일과 서비스 동의 절차가 있는데 실제 사용 중인 이메일을 입력하고 동의를 해준다.
잠시 기다리면 아래와 같은 내용이 나오고 여기서 Enter를 바로 누르면 안 된다!!
본인의 도메인 DNS 관리 툴에서 레코드를 아래와 같이 추가해 준다.
등록 후 자신의 호스트로 변경하고 제대로 등록이 됐는지 확인을 하고, 다시 터미널로 돌아가 Enter를 입력해 준다.
등록되는데 시간이 좀 걸릴 수 있어 처음에 Record not found!가 나오면 잠시 후 다시 시도해 보자
https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.test.keynut.co.kr.
성공적으로 등록이 됐으면 인증용 레코드는 삭제를 해도 된다.
이제 SSL 인증서가 발급 됐다.
인증서 위치
/etc/letsencrypt/live/도메인
인증서 등록
인증서 등록은 Certificate Manager 탭으로 이동후 CloudFront 인증서는 버지니아 북부(us-esat-1)에 등록돼 있어야 하기 때문에 리전을 버지니아 북부로 이동후 인증서 가져오기로 들어간다.
각각의 항목에 맞는 인증서를 입력해 주면 된다. 파일의 모든 내용을 복사해서 붙여 넣어줘야 한다. 이것도 해줘야 해?? 싶은 내용들 모두 복붙 해주자
$ sudo cat /etc/letsencrypt/live/서브도메인/cert.pem
$ sudo cat /etc/letsencrypt/live/서브도메인/privkey.pem
$ sudo cat /etc/letsencrypt/live/서브도메인/fullchain.pen
인증서를 등록해 주고 다시 CloudFront 탭으로 가서 편집탭으로 이동해 준다.
그리고 최종으로 대체 도메인을 입력하고 방금 만든 인증서를 넣어주면 끝이다!
https://test.example.com/S3 객체 URL
이제 S3의 객체에 접근하려면 위처럼 접근할 수 있다.
Next.js 사용자
개발자 도구 네트워크 탭에서 cloudfront로 캐싱이 잘 되고 있는지 확인을 하고 싶은데 아래의 사진처럼 안 뜨고 두 번째 사진처럼 뜨는 사람들이 있을 거다. 이거는 Image 태그를 사용했을 때 그런데 넥스트js 자체적으로 이미지를 가져올 때 서버에서 최적화를 하기 때문에 그렇다.
CloudFornt에서 캐싱이 되고 있는지 직접 확인을 하고 싶다면 Custom Image Loader를 사용하거나 기본 태그인 img 태그를 사용하면 된다.
Custom Image Loader
// next.config.js
module.exports = {
images: {
loader: 'custom',
loaderFile: './my/image/loader.js',
},
}
// loader.js
export default function cloudfrontLoader({ src, width, quality }) {
const url = new URL(`https://example.com/${src}`)
url.searchParams.set('format', 'auto')
url.searchParams.set('width', width.toString())
url.searchParams.set('quality', (quality || 75).toString())
return url.href
}
잘못된 정보가 있으면 댓글 부탁드립니다.