Bitbucket Pipelines로 S3와 CloudFront에 웹사이트 배포하기
이 글에서는 정적 웹사이트를 S3 버킷에 배포하고 CloudFront 캐시 무효화를 자동으로 수행하는 방법을 배우게 된다.

Bitbucket은 Atlassian 제품으로, Jira를 사용하는 협업 팀을 위한 Git 기반 코드 저장 및 CI/CD 최적화 도구다. 코드를 변경하고 Bitbucket에서 개정 및 이력을 유지할 때, 배포를 위한 일부 자동화도 필요하다.
CI/CD는 모든 자동화를 위한 것이며, Continuous Integration(지속적 통합)과 Continuous Delivery(지속적 배포)를 의미한다. 이 글에서는 CI와 CD를 동시에 사용한다.
"Bitbucket을 어떻게 사용하는가?"는 건너뛰고, 전 세계로의 배포를 위해 CloudFront를 사용하는 AWS S3로의 지속적 배포를 위한 Bitbucket Pipelines에 대해 소개한다.
정적 호스팅이 지원되는 S3 버킷을 생성하면, 로컬 폴더에서 S3 버킷으로 sync해야 한다. 일반적으로 로컬 폴더를 S3 버킷과 100% 동기화하기 위해 aws s3 sync LOCAL_FOLDER/ s3://STATIC_HOSTING_ENABLED_BUCKET_NAME --delete 명령을 실행해야 한다.
배포를 위해 CloudFront를 사용 중이라면, 웹사이트를 방문할 때 이전 콘텐츠가 표시된다. 그 이유는 CloudFront가 모든 엣지 로케이션에 모든 콘텐츠를 캐싱하고 엣지 로케이션에서 콘텐츠를 제공하기 때문이다. 새로운 콘텐츠를 위해 "캐시 무효화(invalidate cache)"를 수행하고 엣지 로케이션에서 재캐싱해야 한다.
S3 및 CloudFront에 어떤 IAM Policy를 사용해야 하는가?
최대 보안을 위해 IAM Policy에 최대 제한과 최소 허용을 적용하는 것을 정말 좋아한다. 아래 정책을 확인할 수 있다:
S3 Bucket IAM Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3BucketPolicy",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME",
"arn:aws:s3:::BUCKET_NAME/*"
],
"Condition": {
"ForAnyValue:IpAddress": {
"aws:SourceIp": [
"34.199.54.113/32",
"34.232.25.90/32",
"34.232.119.183/32",
"34.236.25.177/32",
"35.171.175.212/32",
"52.54.90.98/32",
"52.202.195.162/32",
"52.203.14.55/32",
"52.204.96.37/32",
"34.218.156.209/32",
"34.218.168.212/32",
"52.41.219.63/32",
"35.155.178.254/32",
"35.160.177.10/32",
"34.216.18.129/32",
"3.216.235.48/32",
"34.231.96.243/32",
"44.199.3.254/32",
"174.129.205.191/32",
"44.199.127.226/32",
"44.199.45.64/32",
"3.221.151.112/32",
"52.205.184.192/32",
"52.72.137.240/32"
]
}
}
}
]
}배포는 Bitbucket Pipelines에서 실행되며, 이 IP 주소들은 Bitbucket Pipelines의 아웃바운드 IP다. 참조는 https://support.atlassian.com/bitbucket-cloud/docs/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall/에서 확인할 수 있다.
CloudFront Cache Invalidation IAM Policy
Bitbucket Pipelines를 통해 CloudFront 캐시 무효화 명령을 실행하려면 아래 IAM Policy를 사용할 수 있다. S3 Sync 작업이 허용된 동일한 AWS 사용자에게 이 정책을 연결할 수 있다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudFrontCacheInvalidationPolicy",
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "arn:aws:cloudfront::ACCOUNT_ID:distribution/CF_DISTRIBUTION_ID",
"Condition": {
"ForAnyValue:IpAddress": {
"aws:SourceIp": [
"34.199.54.113/32",
...생략...
"52.72.137.240/32"
]
}
}
}
]
}
Bitbucket Pipelines
이전에 CI/CD 작업을 위한 Bitbucket Pipelines 실행용 AWS 사용자를 이미 생성했다. 이제 리포지토리에 환경 변수를 설정할 시간이다. AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY로 충분하다.

Pipeline File
이제 이 단계에서 S3 Sync와 CloudFront Cache Invalidation을 실행하기 위한 bitbucket-pipelines.yml 파일을 생성할 수 있다.
pipelines:
branches:
main:
- step:
name: Deploy to S3 Bucket
deployment: Production
script:
- pipe: atlassian/aws-s3-deploy:1.1.0
variables:
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION: AWS-REGION
S3_BUCKET: 'S3_BUCKET_NAME'
DELETE_FLAG: 'true'
LOCAL_PATH: './'
- pipe: atlassian/aws-cloudfront-invalidate:0.1.1
variables:
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION: AWS-REGION
DISTRIBUTION_ID: CLOUDFRONT-DIST-IDmain 브랜치에 새 커밋이 있으면 파이프라인이 트리거되어 즉시 실행을 시작한다. 그 후 Bitbucket 리포지토리 루트 경로 "/"가 S3 버킷에 동기화되고, 새 웹사이트를 모든 엣지 로케이션에 적용하기 위해 캐시 무효화가 즉시 실행된다.
이 글이 도움이 되길 바란다. 질문이 있으면 댓글을 남기기 바란다. 최대한 빨리 답변하겠다.
Ercan의 다른 글
같은 저자, 다른 영역의 사이트 두 개.