반응형
0. 배포 방식
- 먼저 배포 방법이 어떻게 발전했는지, 그리고 최근 동향을 알아보자.
서버
- 중소/중견 기업은 아직 온프레미스 환경에서 서버 구축도 많이 한다.
- 기존 시스템 + 보안 및 예산의 문제 등으로
- 하지만 대부분의 회사에서 AWS와 같은 클라우드 전환도 빠르게 진행 중
소스코드 관리 & CI/CD 방법
- 한국 기업의 국룰 조합인 ‘React + SpringBoot’ 프로젝트라고 가정해보자.
1. 기본 조합 (외주 많거나 소규모)
- 프런트
- S3 + CloudFront
- 또는 Vercel / Netify (React 기반일 경우)
- 백
- 형상관리: GitHub
- CI: GitHub Actions / Jenkins
- Jenkins : 금융권, 전통적인 시스템, 온프레미스, 다양한 커스터마이징 필요할 때
- CD :
- GitHub Acitons에서 SSH 방식으로 직접 EC2에 직접 배포
- 또는 CodeDeploy 활용
- Docker 도입 시:
- 빌드된 이미지 → Registry에 push (ECR, DockerHub 등) → EC2 Pull 받음
- ECS (K8s의 AWS ver.) or EKS (K8s 매니지드 서비스) 연계 가능
2. 사내 시스템 (보안 중요)
- 보안 민감 기업, 사내망 중심 (GitHub 사용 어려울 때)
- 프런트
- 내부 Nginx 서버 / S3
- 백
- 형상관리: GitLab (Self-Hosted)
- CI : GitLab Runner / Jenkins
- CD : GitLab Runner or CodeDeploy
- Docker 사용 많이 함 : GitLab CI에서 docker build → Registry에 업로드 후 ECS/EKS로 배포
- CodeDeploy + ECS
- [Registry 선택]
- AWS ECR: AWS 환경
- Docker Hub: 간단한 공개용
- Private Registry: 사내망 사용 시
3. 대규모 서버 (Cloud Native)
- 컨테이너, 마이크로서비스, 자동 확장, CI/CD, 무중단 배포!
- 프런트
- S3 + CloudFront 캐시 무효화
- 백
- 형상관리: GitHub or GitLab
- CI/CD: GitHub Actions or GitLab Runner
- Docker 이미지 → AWS ECR
- 배포: EKS + ArgoCD (GitOps 방식)
- Argo CD가 Git에 있는 K8s 배포 환경을 자동으로 읽고, EKS에 적용 = 배포 자동화
- 인프라 관리: Terraform
- 모니터링: Prometheus + Grafana
- 배포 전략: Canary / Blue-Green
[실습 순서]
[1단계] 레포 생성 및 구조 구성
- GitHub에 FE, BE 레포 생성
- FE에 기본 React 프로젝트 구성 (create-react-app 또는 Vite)
- BE에 기본 SpringBoot 프로젝트 구성 (게시글 등록/삭제 등 최소 구현)
- .gitignore, .env 등 기본 환경 구성
[2단계] 프론트 CI/CD 구축
- FE 레포에 GitHub Actions Workflow 파일 작성 (deploy.yml)
- build 결과물을 S3에 업로드하고, CloudFront 캐시 무효화
- GitHub Secrets에 AWS 인증 정보 등 설정
- S3 버킷 권한 및 OAC 연결 상태 점검
[3단계] 백엔드 CI/CD 구축
- BE 레포에 appspec.yml, scripts/ 디렉토리 구성
- GitHub Actions에서 .zip 생성 후 S3에 업로드, CodeDeploy로 배포 트리거
- EC2 인스턴스에 CodeDeploy Agent 설치
- CodeDeploy Application, Deployment Group, IAM 역할 연결 확인
- 게시글 API (/posts) 배포 후 정상 작동 확인
[4단계] 프론트와 백엔드 연동
- 프론트에서 백엔드 API (https://api.3tierwebtest.shop/count) 호출
- React에서 fetch 또는 axios로 API 연동
- CORS 설정이 필요할 경우 백엔드에서 설정 추가
- 정적 웹 페이지에서 API 연동 결과 정상 동작 확인
1. 레포 생성 및 구조 구성
1-1. GitHub에 FE, BE 레포 생성
- 실제 프로젝트면 Organization에 Private으로 생성
- KTB-3tier-web-architecture-FE
- KTB-3tier-web-architecture-BE
- ReadMe나 .gitignore 생성 X
1-2. FE에 기본 React 프로젝트 구성 (create-react-app 또는 Vite)
- Vite로 한 번 해보자
## FE 프로젝트 루트 디렉토리로 이동
cd KTB-3tier-web-architecture-FE
## Vite로 React 프로젝트 생성
npm create vite@latest .
## 물어보는 항목 답변:
## ✔ Project name: . (현재 폴더 그대로)
## ✔ Select a framework: → React
## ✔ Select a variant: → JavaScript (또는 TypeScript 원하면 선택 가능)
## 설치
npm install
npm run dev
→ http://localhost:5173 에서 접속 확인
GitIgnore 추가
- React.js 관련 구글링 후 루트 디렉토리에 추가
GitHub에 프로젝트 연결
## FE 루트 디렉토리로 이동 후
git init
git add .
git commit -m "initial: vite react setup"
## 이후 BE는 BE로
git remote add origin https://github.com/your-id/KTB-3tier-web-architecture-FE.git
git branch -M main
git push -u origin main
2. 프론트 CI/CD 구축
2-1. GitHub Actions 워크플로우 파일 작성
- .github/workflows/deploy.yml 생성:
name: Deploy to S3
on:
push:
branches: [ "main" ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: Build project
run: npm run build
- name: Upload to S3
uses: jakejarvis/s3-sync-action@master
with:
args: --acl public-read --delete
env:
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ap-northeast-2
SOURCE_DIR: dist
- name: Invalidate CloudFront cache
uses: chetan/invalidate-cloudfront-action@master
env:
DISTRIBUTION: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
PATHS: "/*"
AWS_REGION: ap-northeast-2
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- 변수 값들은 아래 내용으로
2-2. 필요한 IAM 설정
배포 전용 IAM 사용자 생성
- 이름 예시: github-actions-deploy
- 직접 정책 연결
- AmazonS3FullAccess
- AWSCodeDeployFullAccess
- CloudFrontFullAccess
- [생성]
- [보안 자격 증명] → [엑세스 키]
- [새 엑세스 키 생성] → [서드 파티 서비스]
- Access Key ID + Secret Access Key 복사해서 저장해두기
- 주의 : 완료 누르면 절대 볼 수 없음
- GitHub Secrets 등록
- GitHub → Settings → Secrets and variables → Actions → Repository secrets
- AWS_ACCESS_KEY_ID : 방금 생성한 엑서스 키
- AWS_SECRET_ACCESS_KEY : 방금 생성한 시크릿 키
- AWS_S3_BUCKET : 3tierwebtest.shop
- CLOUDFRONT_DISTRIBUTION_ID : CloudFront 배포 ID (예: E23DDFO3TDM9BF)
2-3. 테스트 배포 트리거
화면 내용 수정
- src/App.jsx 간단히 수정
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
return (
<div style={{ padding: '2rem' }}>
<h1>✅ S3 정적 웹 호스팅 성공</h1>
<p>이 페이지는 GitActions를 통해 자동 배포되고 있습니다.</p>
</div>
);
}
export default App;
git add .
git commit -m "S3 정적 웹 호스팅 자동 배포 테스트"
git push origin main
3. 백엔드 CI/CD 구축 사전 작업
3-1. 기존 EC2 인스턴스에서 NGINX 제거
- 이제 ALB 사용, 리버스 프록시도 필요가 없다.
## 기존 EC2 인스턴스에서 NGINX 제거
sudo systemctl stop nginx
sudo systemctl disable nginx
sudo yum remove nginx -y # Amazon Linux인 경우
참고 : 해결해야 할 사항
- nginx 내리고 springboot를 올리고 싶은데,
- nginx를 내리면, 대상그룹에서 unhealthy 판정을하고 nginx 이미지로 만들어진 시작 템플릿이 autoscaling으로 계속 띄워지는 상태.(어차피 ACM 등 새로 만들어야 함)
- ⇒ 인스턴스를 새로 띄우고 ALB 새로 연결해주자.
3-2. SpringBoot 기본 프로젝트 구성
- SpringBoot 기본 프로젝트 구성
- 3tier-BE에 아주 간단한 테스트 코드 + DB 연동 + CORS 허용 예제
- https://start.spring.io/ 에서 기본 구조 다운로드
- Gradle - Groovy, 3.4.4, Jar, Java 17 기준
- 코드는 아무거나 만들어보세요!
- /healthy : 헬스체크 api 꼭 생성 (autoScaling을 위해)
- application.yml에 RDS 정보 잘 넣기
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://db-web-3tier.cd8keiamgs3x.ap-northeast-2.rds.amazonaws.com:3306/web3tier
username: admin
password: admin123
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
로컬에서 DB 연결 테스트
- OpenVPN 열고,
- RDS 보안그룹에서 VPN 클라이언트 IP 대역 (192.168.10.0/24) 열어주기
- RDS 설정할 때 만든 admin / admin123으로 접근 (DataGrip)등
- 추가 구성 - 데이터베이스 옵션 web3tier이 잘 들어있다.
로컬에서 API 테스트 by Postman
- (현재 Postman 오류로 curl로 테스트만…)
4. 백엔드 CI/CD by CodeDeploy
4-1. CodeDeploy
CodeDeploy
- AWS에서 제공하는 “자동 배포 서비스”
- 코드 변경이 생기면 자동으로 EC2, Lambda, ECS에 애플리케이션을 배포해준다.
- GitHub, S3, CodePipeline 등에서 코드를 받아
- EC2 인스턴스(또는 다른 대상)에 배포해줌
- 배포 순서, 스크립트, 디렉토리 구조 등을 제어할 수 있다.
AppSpec.yaml
- CodeDeploy가 배포할 때 어떤 식으로 작업을 수행할지 정의하는 설정 파일
- 이게 없으면 어떤 파일을 어디에 둘지, 어떤 스크립트를 실행할지 CodeDeploy는 모른다.
4-2. GitHub Action SSH CI/CD vs CodeDeploy
- 나는 간단한 프로젝트에서는 GitHub Action SSH 방식을 애용했다.
- cicd.ym 하단에 SSH에 접속해서 Public Repo에서 .jar 을 가져오거나, Docker Hub에서 이미지를 가져오는 방식
- 물론 간단하고 직관적이긴 하지만 다음과 같은 단점이 있다.
- 롤백, 로깅, ASG 대응 등은 직접 구현이 필요함
- 하지만, CodeDeploy는 안전하고 구조화된 배포 방식을 제공하고, CI와 CD의 관심사를 분리할 수 있다.
- 또한, AWS 리소스를 직접 관여하여 Auto Scaling + 롤백 + 배포 단계별 통제가 가능하므로, 연계가 편리하다.
4-3. 파이프라인 구축 순서
- EC2 인스턴스 준비
- IAM 역할에 ‘CodeDeploy agent’ 관련 권한 부여
- EC2에 CodeDeploy Agent 설치 (sudo yum install codedeploy-agent -y)
- Agent 실행 확인 (sudo service codedeploy-agent status)
- S3 or GitHub 배포용 앱 코드 준비
appspec.yml
,scripts/*.sh
포함.zip
으로 묶어서 S3에 업로드 (또는 GitHub에 푸시)
- CodeDeploy 구성
- Application 생성
- Deployment Group 생성
- EC2 대상 지정 (태그 or Auto Scaling Group)
- 서비스 역할(IAM Role), 배포 방식 설정
- GitHub Actions에 배포 트리거 추가 (선택사항)
- CodePipeline이나 GitHub Actions에서 코드 푸시 시 자동 배포되도록 연결 가능
- 실제 배포 테스트
- 수동이든 자동이든 배포 수행 후 EC2 접속해서 결과 확인
5. CI/CD를 위한 AWS 리소스 준비
5-1. EC2 태그 생성
- 인스턴스를 새로 띄우기 (EC2-web-3tier-BE)
- CodeDeploy가 EC2 인스턴스를 인식할 수 있도록 태그를 부여하자.
- 태그를 추가하자.
- 만약 Auto Scaling을 사용할 예정이라면
- Auto Scaling Group의 [태그]에서도 수정해준다.
- → 이후 생성되는 모든 인스턴스가 자동으로 해당 태그를 가진다.
Service : web-3tier-test
5-2. IAM 역할 생성
- EC2 인스턴스가 S3와 CodeDeploy에 접근할 수 있도록 IAM 역할을 부여해준다.
- [IAM] → [역할 생성]
- 신뢰할 수 있는 엔티티 유형 : AWS 서비스
- 서비스 : CodeDeploy
- 역할 이름 : codedeploy-access-role
- 만들어진 역할에 [권한 추가] → [정책 연결] → AmazonS3FullAccess 추가
- EC2 인스턴스에도 같은 권한을 준다.
- 새 IAM 역할
- ec2-codedeploy-access-role :
- AmazonS3FullAccess
- AWSCodeDeployFullAccess
5-3. S3
- CodeDeploy를 활용한 EC2 기반 CI/CD를 구성할 때 S3 버킷의 용도
- 배포 아티팩트 저장소
- CodeDeploy는 EC2 인스턴스에 배포할 애플리케이션의 버전을
revision
이라고 부르며, 이revision
파일(아티팩트)을 S3 버킷에 업로드해 저장한다. 이후 CodeDeploy 에이전트가 이 파일을 S3에서 다운로드하여 배포를 진행하는 구조이다.
- CodeDeploy는 EC2 인스턴스에 배포할 애플리케이션의 버전을
- 버전 관리 및 롤백:
- S3는 여러 버전의 배포 파일을 안전하게 저장할 수 있으므로, 필요 시 이전 버전으로 롤백하는 것도 용이하다.
- 통합 및 자동화:
- AWS CodePipeline과 함께 사용하면, 빌드가 완료된 후 자동으로 S3에 아티팩트를 저장하고, CodeDeploy가 해당 아티팩트를 참조하여 배포를 실행하도록 설정할 수 있다.
- 배포 아티팩트 저장소
- 배포 아티팩트(애플리케이션 코드, 스크립트, appspec.yml 파일 등)를 저장하고 관리하기 위해서이다.
- GitHub Actions 또는 수동으로 압축한 배포 파일 .zip을 저장
- CodeDeploy는 여기서 다운로드해서 EC2에 배포
- 버킷 생성 - 다른건 기본으로 냅두고 버저닝만 활성화
- 버저닝 활성화 체크 (중요: 롤백, 버전 관리에 필요)
- 이름 : codedeploy-web3tier
5-4. CodeDeploy
- [CodeDeploy] 서비스 → [애플리케이션 생성]**
- codedeploy-web-3tier-BE
- EC2
배포 그룹 생성
- 이름 : DG-springboot-BE
- 서비스 역할 : CodeDeploy용 IAM 역할
- 배포 유형 : 현재 위치
- 환경 구성 : Amazon EC2 인스턴스
- 직전에 생성한 EC2 인스턴스 태그(Service: web-3tier-test) 지정
- AWS Systems Manager를 사용한 에이전트 구성 : 한 번만
- 로드 밸런서 비활성화
5-5. GitHub Actions 관련 파일 추가
- .github/workflows/deploy.yml
name: Deploy Spring Boot to EC2 via CodeDeploy
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: 📁 Checkout source code
uses: actions/checkout@v2
- name: Create application.yml
run: |
mkdir -p src/main/resources
echo "${{ secrets.APP_YML }}" > src/main/resources/application.yml
- name: ☕ Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'temurin'
- name: 🛠 Build Spring Boot Project
run: ./gradlew clean build -x test
- name: ✅ Make scripts executable
run: chmod +x scripts/*.sh
- name: 📦 Create deployment package
run: |
mkdir -p codedeploy-package
cp -r appspec.yml scripts/ build/libs/*.jar codedeploy-package/
cd codedeploy-package
zip -r deployment.zip .
- name: ☁️ Upload to S3
uses: jakejarvis/s3-sync-action@v0.5.1
with:
args: --acl private
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
SOURCE_DIR: ./codedeploy-package
DEST_DIR: code-deploy-artifacts
- name: 🚀 Trigger AWS CodeDeploy Deployment
run: |
aws deploy create-deployment \
--application-name codedeploy-web-3tier-BE \
--deployment-group-name DG-springboot-BE \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--s3-location bucket=${{ secrets.S3_BUCKET_NAME }},bundleType=zip,key=code-deploy-artifacts/deployment.zip
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
- AWS_ACCESS_KEY_ID : IAM 사용자 Access Key
- AWS_SECRET_ACCESS_KEY : IAM 사용자 Secret Key
- 해당 IAM은 GitHub Actions가 사용하는 IAM이다. 아까 Front에서 만든 거 쓰자.
- github-actions-deploy 꺼
- AWS_REGION 예: ap-northeast-2
- S3_BUCKET_NAME : 예: codedeploy-web3tier
- APP_YML : application.yml 전체 내용
Application.yml 처리
- 민감한 비밀번호 등이 있다면?
- .gitignore에 *.yml 추가
5-6. SpringBoot CodeDeploy 관련 파일 추가
디렉토리 구조
KTB_3tier_web_architecture_BE/
├── .github
│ └── workflows
│ └── deploy.yml
├── appspec.yml
├── scripts/
│ ├── setting.sh
│ ├── start.sh
│ └── stop.sh
├── build/
│ └── libs/
│ └── KTB_3tier_web_architecture_BE-0.0.1-SNAPSHOT.jar
├── src/
├── ...
appspec.yml
- jar을 루트로 복사했었음
version: 0.0
os: linux
files:
- source: .
destination: /home/ec2-user/app/
hooks:
ApplicationStop:
- location: scripts/stop.sh
timeout: 60
runas: ec2-user
BeforeInstall:
- location: scripts/setting.sh
timeout: 60
runas: ec2-user
AfterInstall:
- location: scripts/start.sh
timeout: 60
runas: ec2-user
setting.sh
- Java 설치 등
#!/bin/bash
echo "🔧 [Setting] EC2 초기 설정 시작..."
## Java 설치 확인 및 설치
echo "☕ Java 설치 여부 확인..."
if type -p java; then
echo "✅ Java 이미 설치됨: $(java -version 2>&1 | head -n 1)"
else
echo "⏬ Java 설치 중..."
sudo yum install -y java-17-amazon-corretto
fi
## 디렉토리 생성
APP_DIR="/home/ec2-user/app"
if [ ! -d "$APP_DIR" ]; then
echo "📁 $APP_DIR 디렉토리 생성"
mkdir -p $APP_DIR
chmod 755 $APP_DIR
else
echo "📁 $APP_DIR 이미 존재"
fi
echo "✅ [Setting] EC2 초기 설정 완료
start.sh
#!/bin/bash
echo "🚀 [Start] Spring Boot 앱 실행 중..."
JAR_NAME=$(ls /home/ec2-user/app/*SNAPSHOT.jar | tail -n 1)
echo "✅ 실행할 JAR: $JAR_NAME"
nohup java -jar $JAR_NAME > /home/ec2-user/app/nohup.out 2>&1 &
stop.sh
#!/bin/bash
echo "🛑 [Stop] 기존 Spring Boot 앱 종료 시도..."
PID=$(pgrep -f 'java -jar')
if [ -n "$PID" ]; then
echo "🛑 기존 프로세스 종료: PID=$PID"
kill -9 $PID
else
echo "✅ 종료할 프로세스 없음"
fi
5-7. CodeDeploy Agent 설치
- Push 하기 EC2-web-3tier-BE 에 접속하여 CodeDeploy Agent를 설치해주자.
sudo yum update -y
sudo yum install ruby wget -y
cd /home/ec2-user
wget https://aws-codedeploy-ap-northeast-2.s3.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto
sudo service codedeploy-agent status
⇒ Push
AWS 콘솔 확인
GitHub Actions 확인
6. 재설정
6-1. Route53 레코드
- 현재 루트 도메인과 서브 도메인은 S3 정적호스팅 사용하는 데에 프런트가 사용중이다.
- 백엔드 서버는 api.3tierwebtest.shop으로 바꿔주자.
- → ALB로!
6-2. ACM
- 서울 리전에 api.3tierwebtest.shop ACM 새로 만들기
- 리전 잘 체크하기
- → Route53 등록
6-3. ALB 재연결
- 리스너 (443) → 대상그룹
HTTPS:443의 SSL/TLS 변경
- [인증서]
- 기본 루트 도메인 SNI용 리스너 인증서 제거
- api. 인증서 추가
- api. 인증서 기본값으로 변경
- 보안 리스너 설정 → 인증서 변경
- api.로
보안그룹 확인
- ALB 보안그룹 수정
- EC2 보안그룹의 인바운드 8080 포트 열어주기
- 소스는 자기자신
- 같은 보안 그룹을 사용하는 ALB가 EC2에게 요청을 보낼 수 있도록 허용.
대상그룹
- HTTP: 80으로 현재 대상그룹 Health Check 중
- Target Group의 헬스체크 경로가 Spring Boot에 맞게 설정
- (SpringBoot) 8080 포트
- /health 등
포트 변경
NGINX 제거
Health Check 경로 수정
- ALB에서 설정한 Health Check 경로 (/health)를
- 꼭 스프링부트에 /health api가 있어야 함
- 새로 Auto Scaling - AMI 등 생성
참고
- AutoScaling하고 싶으면 해당 AMI로 다시 만들기~
- (다시 적용은 안해놓았음)
7. 테스트
7-1. BackEnd CI/CD Test
GitAcitons
CodeDeploy
대상그룹
- Healthy
7-2. FrontEnd CI/CD Test 및 백엔드&DB 연결 테스트
App.jsx 코드 수정 → CI/CD TEST
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [count, setCount] = useState(0);
const [loading, setLoading] = useState(false);
const API_BASE = 'https://api.3tierwebtest.shop';
const fetchCount = async () => {
try {
const res = await fetch(`${API_BASE}/counter`);
const text = await res.text();
const parsed = parseInt(text);
setCount(parsed);
} catch (e) {
alert('카운트를 불러오는 데 실패했습니다.');
console.error(e);
}
};
const updateCount = async (type) => {
setLoading(true);
try {
const res = await fetch(`${API_BASE}/counter/${type}`, {
method: 'POST'
});
const parsed = parseInt(await res.text());
setCount(parsed);
} catch (e) {
alert(`${type === 'up' ? '증가' : '감소'}에 실패했습니다.`);
console.error(e);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchCount();
}, []);
return (
<div style={{ padding: '2rem', textAlign: 'center' }}>
<h1>✅ S3 정적 웹 호스팅 성공</h1>
<p>이 페이지는 GitActions를 통해 자동 배포되고 있습니다.</p>
<h2>🔥 현재 카운트: {count}</h2>
<div style={{ marginTop: '1rem' }}>
<button onClick={() => updateCount('up')} disabled={loading}>
🔼 증가
</button>
<button onClick={() => updateCount('down')} disabled={loading} style={{ marginLeft: '1rem' }}>
🔽 감소
</button>
<button onClick={fetchCount} disabled={loading} style={{ marginLeft: '1rem' }}>
🔄 새로고침
</button>
</div>
</div>
);
}
export default App;
- 참고 : 디테일하게 표현하면, “CloudFront를 통한 S3 정적 웹 호스팅 성공”으로 변경해주자.
GitAcitons
S3 Bucket
실제 웹사이트 테스트 (백엔드&DB 연결 테스트)
최종 아키텍쳐
반응형