Skip to main content

CLI로 정적 빌드 파일 CICD 배포

AWS, Terraform, GH CLI 설치

AWS 같은 경우는 굳이 CLI로 할 필요가 있나 생각이 들 수 있습니다. CLI에서는 되지만 GUI에서는 안되는 기능들이 있고 그러한 자동화를 하려면 CLI가 필수이기 때문에 설치를 해줘야합니다.

  • AWS CLI Install 저는 macOS를 사용중이고, GUI Installer로 설치하셔도 되지만 저는 command line installer로 진행을 했습니다. 둘이 차이는 없지만 CLI가 훨씬 빠르고 편하기 때문에 저는... 그리 진행하였습니다. 그리고 여기서 All usersCurrent user로 나뉘게 되는데 AWS CLI가 시스템 내에서 어떻게 접근 가능한지와 관련된 범위를 정의합니다. 쉽게 말하면 본인 개인 PC에서는 All users로 설치하시면 되고, 만약 회사 노트북을 사용하는데, 공유하는 노트북에 멀티 프로필을 사용하고 계시다면 current user로 진행하시면 될 것 같습니다.
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /
aws --version
  • Terraform CLI Install 저는 Homebrew를 통해서 바로 설치 할 수 있었고, 설치 후 버전 확인만 하면 될 것 같습니다.
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
terraform --version
  • GH CLI Install 저희가 기존에 사용하던 git commit 이 커맨드가 아닌 Github PR, issue, 레포지토리 시크릿 셋업 같은 작업을 CLI를 통해서 할 수 있도록 해주는 CLI 툴입니다.
brew install gh

Terraform 이란 ?

오픈 소스 인프라스트럭처 as Code(IaC) 소프트웨어 툴입니다. 구성 파일들은 HCL(HashiCorp Configuration Language)로 작성되며 여러 클라우드 서비스(예: Amazon Web Services, Microsoft Azure, Google Cloud Platform) 및 온-프레미스 자원(예: VMware vSphere)을 포함한 다양한 서비스의 인프라를 안전하고 효율적으로 구축, 변경 및 버전 관리할 수 있습니다.

  1. 자동화된 인프라 관리
  2. 복잡한 인프라의 간소화
  3. 멀티 클라우드 지원
  4. 버전 관리 및 협업
  5. 변경 계획 및 인사이트

AWS IAM 생성

앞서 설치한 AWS CLI를 통해서 AWS Resoure를 관리 및 제어를 하기 위해서 Identity and Access Management(IAM)를 생성해서 엑세스 키를 만들어서 등록을 해줘야하는 과정이 필요하기 때문에 생성을 해줘야합니다.

PATH : AWS IAM -> 액세서 관리 -> 사용자 -> 사용자 생성

  1. 사용자 이름 입력
  2. 권한 설정
  • 그룹에 사용자 추가
  • 권한 복사
  • 직접 정책 연결
    • 기존에 존재하던 그룹과 복사할 권한은 따로 없으므로 이 권한 옵션을 선택
    • AdministratorAccess 말 그대로 모든 권한을 위임하는 정책 ( 유출되면 굉장히 위험할 것 )
  1. 유저 생성

PATH : AWS IAM -> 액세서 관리 -> 사용자 -> 생성된 사용자 -> 보안 자격 증명 -> 액세스 키

  1. Command Line Interface ( CLI ) 선택
  2. 설명 태그 ( optional ) 작성
  3. 액세스 키 생성 및 복사

그러면 아래 3개를 인지 혹은 가지고 계셔야합니다.

  • 사용자 이름 ( User Name )
  • 액세스 키
  • 액세스 키 시크릿

AWS CLI Profile 설정

  • ap-northeast-2가 서울이다.
aws configure --profile USER_NAME
AWS Access Key ID [None]: YOUR_ACCESS_KEY
AWS Secret Access Key [None]: YOUR_ACCESS_KEY_SECRET
Default region name [None]: ap-northeast-2
Default output format [None]: json

인프라 설명 - 실습 진행한 레포

Infra

DNS 리소스 배포

terraform init : Terraform 초기화 명령입니다. Terraform이 작업을 시작하기 전에 필요한 여러 설정을 수행합니다. 이는 Terraform이 사용하는 모든 플러그인 및 모듈을 다운로드하는 등의 준비 작업을 포함합니다.

terraform apply : Terraform을 사용하여 인프라를 생성, 업데이트 또는 삭제하는 데 사용됩니다. Terraform 구성 파일들의 정의에 따라 클라우드 리소스를 실제로 생성, 변경 또는 제거합니다.

파일명설명주요 구성 요소
_.output.tfAWS Route 53의 DNS 네임서버(NS) 레코드 출력- aws_route53_zone.zone.name_servers: Route 53에서 생성된 호스팅 영역의 DNS 네임서버 참조
_.provider.tfAWS 프로바이더 설정- provider "aws": AWS 프로바이더 선언 profile = var.profile: 사용할 AWS CLI 프로필 지정 - region = var.region: 사용할 AWS 리전 지정
_.variables.tf변수 정의- profile: AWS CLI 프로필 이름 - region: AWS 리전, 기본값 "us-east-1" - domain_name: 도메인 이름, Route 53 호스팅 영역 및 S3 버킷 설정에 사용
acm_recordRoute 53 레코드 생성- resource "aws_route53_record" "acm_record": Route 53 레코드 생성 선언 - zone_id, name, type, records, ttl: 레코드 속성 설정 - depends_on: 의존성 설정
acm.tfAWS ACM 인증서 생성- resource "aws_acm_certificate" "acm": ACM 인증서 생성 선언 - domain_name = var.domain_name, validation_method = "DNS", lifecycle, depends_on, tags: 인증서 속성 및 설정
sample.tfvarsTerraform 변수 값 설정- profile = "edint_official", region = "us-east-1", domain_name = "unchaptered.shop": 프로바이더 설정 및 도메인 이름 설정에 필요한 변수 값 지정
zone.tfRoute 53 호스팅 영역 생성- resource "aws_route53_zone" "zone": 호스팅 영역 생성 선언 - name = var.domain_name, comment = "Created by monthly-cs", tags: 호스팅 영역 이름, 설명, 태그 설정
cd ./infra/dns
terraform init
terraform apply -var="profile=YOUR_USER_NAME" -var="domain_name=YOUR_DOMAIN"
  • terraform apply를 입력하고 Do you want to perform these actions? 이라는 질문에 yes를 입력해야 비로소 리소스 생성을 시작합니다.

![terraform](/img/study/terraform apply.png)

AWS Route 53 호스팅 영역이 생성되고, 그 결과로 네임서버(NS) 주소 4개가 반환되는 것을 확인하고, 해당 네임 서버를 도메인 구매한 기관에 등록해줍니다.

네임서버 gabia

CloudFront, S3 배포하기

cd ./infra/website
terraform init
terraform apply -var="profile=YOUR_USER_NAME" -var="domain_name=YOUR_DOMAIN"
파일명설명주요 구성 요소
_.datasource.acm.tfAWS ACM 인증서 데이터 조회- data "aws_acm_certificate" "acm": 인증서 데이터 조회 선언 - domain = var.domain_name: 조회할 도메인 이름 지정 - statuses = ["PENDING_VALIDATION", "ISSUED"]: 조회할 인증서 상태 지정
_.datasource.zone.tfAWS Route 53 호스팅 영역 데이터 조회- data "aws_route53_zone" "zone": 호스팅 영역 데이터 조회 선언 - name = "${var.domain_name}.": 조회할 호스팅 영역 이름 지정
_.providier.tfAWS 프로바이더 설정- provider "aws": AWS 프로바이더 선언 - profile = var.profile: 사용할 AWS CLI 프로필 지정 - region = var.region: 사용할 AWS 리전 지정
_.variables.tfTerraform 변수 정의- variable "profile", variable "region", variable "domain_name": AWS CLI 프로필 이름, AWS 리전, 도메인 이름 변수 정의
cloudfront_acm.tfAWS Route 53 A 레코드 생성- resource "aws_route53_record" "acm": A 레코드 생성 선언 - zone_id = data.aws_route53_zone.zone.id: 호스팅 영역 ID 지정 - name = var.domain_name: 레코드 이름 지정 - type = "A": 레코드 타입 지정
cloudfront_oac.tfAWS CloudFront Origin Access Control 생성- resource "aws_cloudfront_origin_access_control" "cf_dist_oac": OAC 생성 선언 - name, description, origin_access_control_origin_type, signing_behavior, signing_protocol: OAC 속성 설정
cloudfront.tfAWS CloudFront 배포 생성- resource "aws_cloudfront_distribution" "cf_dist": CloudFront 배포 생성 선언 - enabled, price_class, aliases, is_ipv6_enabled, default_root_object, origin, default_cache_behavior, restrictions, viewer_certificate, custom_error_response, depends_on: 배포 속성 설정
s3_bucket_policy.tfAWS S3 버킷 정책 생성- resource "aws_s3_bucket_policy" "bucket_policy": S3 버킷 정책 생성 선언 - bucket, policy, depends_on: 버킷 정책 속성 및 의존성 설정
s3.tfAWS S3 버킷 생성- resource "aws_s3_bucket" "bucket": S3 버킷 생성 선언 - bucket = var.domain_name: 버킷 이름 지정 - tags: 버킷 태그 설정

도메인 이름을 가진 웹 사이트를 위한 인프라를 AWS 상에 구축합니다. 이 과정에는 SSL/TLS 인증서의 관리, 도메인의 DNS 설정, 웹 콘텐츠의 저장 및 전세계 배포가 포함됩니다. Terraform을 통해 이 모든 작업을 코드화함으로써 인프라의 버전 관리, 재사용, 자동화가 가능해집니다.

로컬에서 정적 빌드파일 업로드

현재 프로젝트를 빌드하고 정적 파일 저장되는 폴더가 ./build 라는 경로라는 가정하에 명령어는 아래와 같습니다.

aws s3 cp --recursive ./build s3://YOUR_DOMAIN --profile YOUR_PROFILE

Github Action을 통한 CD 구현

 gh auth login
? What account do you want to log into? GitHub.com
? What is your preferred protocol for Git operations on this host? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Login with a web browser

! First copy your one-time code: C157-6EA4
Press Enter to open github.com in your browser...

위와 같이 진행을 해서 로그인을 진행합니다. 내 Repository에 아래와 같이 필요한 Github secret을 CLI로 등록을 할 수 있습니다.

gh secret set AWS_ACCESS_KEY -R <유저네임>/<저장소명> -b <AWS ACCESS KEY>
gh secret set AWS_SECRET_ACCESS_KEY -R <유저네임>/<저장소명> -b <AWS SECRET ACCESS KEY>
gh secret set AWS_S3_BUCKET -R <유저네임>/<저장소명> -b <가비아에서 구매한 도메인 이름>
gh secret set AWS_CF_DIST_ID -R <유저네임>/<저장소명> -b <CloudFront 배포 ID>

수동으로 추가할 수 있는데

PATH: Repository -> Settings -> Security -> Secrets and variables -> Actions

github_secret

Github Secret이란 ?

깃헙(GitHub) 시크릿(GitHub Secrets)은 깃헙 리포지토리(repository)에서 사용되는 비공개 데이터를 안전하게 저장하기 위한 방법인데, 주로 깃헙 액션(GitHub Actions)이나 다른 자동화된 프로세스에서 사용되는 중요한 정보나 구성 데이터를 포함합니다.

.github
└ workflows
└ deploy.yml

루트에서 위와 같이 deploy.yml 파일을 생성해줍니다.

name: 배포 자동화

on:
push:
branches: ["*"]

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Check Node v
run: node -v

- name: setup-node
uses: actions/setup-node@v3
with:
node-version: 20

- name: Install Dependencies
run: yarn install

- name: Build
run: yarn build

- name: Upload to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: aws s3 cp --recursive --region us-east-1 ./build s3://${{ secrets.AWS_S3_BUCKET }}

- name: Invalidate CloudFront Cache
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_EC2_METADATA_DISABLED: true
run: aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_CF_DIST_ID }} --paths "/*"

deploy.yml에 위 코드를 작성해줍니다. 각 역할은 아래와 같습니다.

on: 이 워크플로우가 언제 실행될지를 정의합니다. 여기서는 push 이벤트에 대해 설정되어 있으며, 모든 브랜치(["*"])로부터의 푸시 이벤트에 반응하여 실행됩니다.

jobs: 워크플로우 내에서 실행될 작업들을 정의합니다. 여기서는 build라는 하나의 작업을 정의하고 있습니다.

  • runs-on: 작업이 실행될 환경을 ubuntu-latest로 설정합니다. 즉, 최신 버전의 우분투 가상 환경에서 작업이 실행됩니다.

  • steps: 작업을 구성하는 단계들을 나열합니다.

    • Checkout: actions/checkout@v4를 사용하여 소스 코드를 체크아웃합니다. 이는 작업이 실행되는 가상 환경에 소스 코드를 복사하는 과정입니다.
    • Check Node v: node -v 명령어를 실행하여 현재 노드 버전을 확인합니다.
    • setup-node: actions/setup-node@v3를 사용하여 노드 환경을 설정합니다. 여기서는 node-version20으로 설정하여, 해당 버전의 Node.js를 사용합니다.
    • Install Dependencies: yarn install 명령을 실행하여 필요한 의존성들을 설치합니다.
    • Build: yarn build 명령을 실행하여 애플리케이션을 빌드합니다. 이 과정에서 생성된 빌드 파일들은 배포를 위해 사용됩니다.
    • Upload to S3: aws s3 cp 명령을 사용하여 빌드된 파일들을 AWS S3 버킷으로 업로드합니다.
    • Invalidate CloudFront Cache: aws cloudfront create-invalidation 명령을 사용하여 CloudFront 캐시를 무효화합니다. 이는 새로 배포된 컨텐츠가 CloudFront를 통해 제공될 때 이전 버전의 캐시된 컨텐츠가 아닌 최신 컨텐츠가 제공되도록 합니다.

S3, cloudfront, dns 정리 command 🗑️

aws s3 rm s3://YOUR_DOMAIN --recursive --profile YOUR_PROFILE

s3 bucket에 들어있는 정적 파일 전부 삭제

cd ./infra/website
terraform destroy -var="profile=YOUR_PROFILE" -var="domain_name=YOUR_DOMAIN"

생성된 AWS 리소스 (예: EC2 인스턴스, S3 버킷, Route53 DNS 레코드 등) 삭제

cd ../dns
terraform destroy -var="profile=YOUR_PROFILE" -var="domain_name=YOUR_DOMAIN"

DNS 레코드, 도메인 등록, SSL/TLS 인증서 등의 도메인 관련 리소스 삭제

참고