
이번 실습에서는 AWS 서비스만 사용해서 애플리케이션 소스 변경부터 EC2 배포까지 자동화하는 CI/CD 파이프라인을 구성함.
구성 흐름은 다음과 같음.
개발자
↓
CodeCommit 에 소스 push
↓
CodePipeline 이 변경 감지
↓
CodeBuild 가 빌드 수행
↓
CodeDeploy 가 EC2 에 배포
↓
EC2 웹서버 반영
즉, 개발자가 소스를 직접 서버에 복사하는 방식이 아니라
Git 저장소에 push만 하면 자동으로 빌드와 배포가 수행되는 구조를 만드는 실습임.
이 실습을 통해 다음 내용을 확인함.
이번 실습에서는 복잡한 프로그램 대신 정적 HTML 웹페이지를 사용함.
사용자 브라우저
↓
EC2 (Nginx)
↑
CodeDeploy
↑
CodePipeline
├─ Source : CodeCommit
├─ Build : CodeBuild
└─ Deploy : CodeDeploy
실습 리전 예시
ap-northeast-2 (서울)
전체 순서는 아래와 같음.
1. EC2 생성
2. EC2에 nginx 설치
3. EC2에 CodeDeploy Agent 설치
4. CodeCommit 저장소 생성
5. 로컬에 프로젝트 파일 작성
6. Git으로 CodeCommit에 push
7. CodeDeploy Application / Deployment Group 생성
8. CodeBuild Project 생성
9. CodePipeline 생성
10. 변경 사항 push
11. 자동 빌드 / 자동 배포 확인
이름 예시
이니셜-cicd-web-ec2
운영체제
Amazon Linux 2023
인스턴스 타입
t3.micro
보안 그룹 인바운드 규칙
SSH TCP 22 내 IP
HTTP TCP 80 0.0.0.0/0
설명
EC2에 연결할 IAM Role 예시
EC2CodeDeployRole
다음 정책을 포함.
실제로는 CodeDeploy Agent 동작에 필요한 최소 권한만 부여하는 것이 더 좋음.

EC2에 다음 태그를 추가함.
Key : Deploy
Value : 이니셜-Web

이 태그는 나중에 CodeDeploy Deployment Group에서 배포 대상을 식별할 때 사용함.
ssh-i mykey.pem ec2-user@EC2_PUBLIC_IP
sudo dnf update -y
sudo dnf install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
브라우저에서 접속
http://EC2_PUBLIC_IP
nginx 기본 페이지가 보이면 정상임.
CodeDeploy는 EC2에 파일을 복사하고 스크립트를 실행하기 위해
대상 서버에 CodeDeploy Agent가 필요함.
sudo dnf install ruby -y
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
chmod +x install
sudo ./install auto
auto 옵션은 자동 설치 방식임sudo systemctl status codedeploy-agent
정상이라면 active (running) 상태가 보여야 함.
추가로 부팅 후 자동 시작도 확인함.
sudo systemctl enable codedeploy-agent
CodePipeline과 CodeBuild는 중간 산출물을 저장할 위치가 필요함.
버킷 이름 예시
이니셜-cicd-artifact-계정식별자
aws s3 mb s3://버킷-이름
CodeCommit 콘솔에서 생성
이름 예시
이니셜-cicd-repo
aws codecommit create-repository --repository-name 저장소-이름

HTTPS + Git credentials 또는 HTTPS + credential helper 방식 사용 가능함.
AWS 자격증명을 사용하는 것이 편함.
이번 실습에서는 아래 구조로 프로젝트를 만듦.
cicd-demo/
├─ index.html
├─ buildspec.yml
├─ appspec.yml
└─ scripts/
├─ install_dependencies.sh
├─ start_server.sh
└─ validate_service.sh
<!DOCTYPE html>
<htmllang="ko">
<head>
<metacharset="UTF-8">
<title>AWS Native CI/CD Demo</title>
</head>
<body>
<h1>AWS Native CI/CD Demo - Version 1</h1>
<p>This page was deployed from CodeCommit through CodePipeline.</p>
</body>
</html>
Version 2로 수정해서 재배포를 확인할 예정임version: 0.2
phases:
install:
commands:
- echo "Install phase started"
build:
commands:
- echo "Build phase started"
- mkdir -p output
- cp -r index.html appspec.yml scripts output/
post_build:
commands:
- echo "Build phase completed"
artifacts:
files:
- '**/*'
base-directory: output
설명
version: 0.2CodeBuild가 해석하는 빌드 스펙 버전임.
phases빌드 과정을 단계별로 정의함.
install : 패키지 설치, 환경 준비build : 실제 빌드, 파일 복사, 압축 등 수행post_build : 빌드 후 후처리 수행mkdir -p outputoutput 디렉터리를 생성함p는 디렉터리가 이미 있어도 오류 없이 넘어감cp -r index.html appspec.yml scripts output/output 폴더로 복사함r 옵션은 디렉터리 복사 시 필요함scripts 폴더를 함께 복사해야 하므로 r 사용함artifacts다음 단계로 넘길 결과물을 정의함.
files: '**/*'output 디렉터리 안의 모든 파일을 아티팩트에 포함함base-directory: outputoutput으로 설정함즉, 최종적으로 CodeDeploy는 output 내부 파일을 받아서 배포하게 됨.
version: 0.0
os: linux
files:
- source: /
destination: /usr/share/nginx/html # Nginx 기본 경로
permissions:
- object: /usr/share/nginx/html
pattern: "**"
owner: nginx
group: nginx
mode: 755
hooks:
BeforeInstall:
- location: scripts/install_dependencies.sh
timeout: 300
runas: root
ApplicationStart:
- location: scripts/start_server.sh
timeout: 300
runas: root
ValidateService:
- location: scripts/validate_service.sh
timeout: 300
runas: root
설명
version: 0.0EC2/온프레미스 배포용 AppSpec 버전임.
os: linux대상 서버 운영체제가 Linux임을 지정함.
files배포 파일 복사 규칙임.
source: /destination: /usr/share/nginx/html즉, 배포 패키지의 파일들을 /usr/share/nginx/html 아래로 복사함.
permissions배포된 파일의 권한과 소유자를 지정함.
owner: nginxgroup: nginxmode: 755웹서버가 파일을 읽을 수 있도록 맞춰줌.
hooks배포 라이프사이클별 실행 스크립트 정의함.
BeforeInstallApplicationStartValidateService#!/bin/bash
set -e
echo "=== BeforeInstall 시작 ==="
dnf install nginx -y || true
mkdir -p /usr/share/nginx/html
# 중요: 기존에 있던 기본 Welcome 페이지를 지워야 우리 파일이 보입니다.
rm -f /usr/share/nginx/html/index.html
chown -R nginx:nginx /usr/share/nginx/html
#!/bin/bash
set -e
echo "=== ApplicationStart started ==="
systemctl enable nginx
systemctl restart nginx
echo "=== ApplicationStart completed ==="
설명
systemctl enable nginx부팅 후 자동 시작되게 등록함.
systemctl restart nginxnginx 재시작함.
여기서 restart를 사용한 이유는 다음과 같음.
즉, start보다 재배포 환경에서 더 유연하게 사용 가능함.
#!/bin/bash
set-e
echo "=== ValidateService started ==="
curl -f http://localhost/index.html
echo "=== ValidateService completed ==="
설명
curl -fcurl은 HTTP 요청 테스트 명령어임f 옵션은 HTTP 오류 발생 시 실패 코드 반환함즉, 웹서버가 정상 동작하지 않으면 이 스크립트가 실패하고 CodeDeploy도 배포 실패로 판단함.
단순 파일 복사만 끝났다고 배포 성공으로 보면 안 되고, 실제 서비스 가능 상태까지 확인해야 하기 때문임.
chmod +x scripts/*.sh
cd cicd-demo
git init
git init은 현재 디렉터리를 Git 로컬 저장소로 초기화함git config user.name"your-name"
git config user.email"your-email@example.com"
git add .
git commit -m "Initial commit"
git remote add origin codecommit::ap-northeast-2://이니셜-cicd-repo
설명
origin은 원격 저장소의 별칭임git branch -M main
설명
main으로 변경함M은 강제 이름 변경 옵션임git push -u origin main
설명
push로컬 커밋을 원격 저장소에 업로드함.
-u현재 브랜치와 원격 브랜치를 추적 관계로 설정함.
즉, 이후부터는 git push만 입력해도 자동으로 origin main에 반영됨.
pip3 install git-remote-codecommit을 해줘야 push가 된다.
1. 환경 변수 파일에 파이썬 스크립트 경로 추가
echo 'export PATH=$PATH:/Users/DONGSEUP/Library/Python/3.9/bin' >> ~/.zshrc
2. 변경사항 현재 터미널에 즉시 적용
source ~/.zshrc
3. 적용 후 push
git push -u origin main

이름 예시
이니셜-cicd-app
컴퓨팅 플랫폼
EC2


이름 예시
CodeDeployServiceRole
이 역할은 CodeDeploy가 EC2 대상을 찾아 배포 작업을 수행할 때 사용함.
이름 예시
이니셜-cicd-dg
환경 구성
Amazon EC2 instances
대상 선택 방식
태그 기반 선택
태그 조건
Deploy = 이니셜-Web

이름 예시
이니셜-cicd-build
소스 공급자
AWS CodeCommit

설명
환경
Managed image
Amazon Linux

Buildspec
Use a buildspec file

서비스 역할
CodeBuildServiceRole
"s3:GetObject" => artifact에 추가

아티팩트
S3

설명
사용자지정 파이프라인
이름 예시
이니셜-cicd-pipeline
서비스 역할
CodePipelineServiceRole
기본 권한 외에 codedeploy:GetApplicationRevision, codedeploy:GetDeploymentConfig 권한 추가

아티팩트 저장소
기존 S3 버킷 선택
이니셜-cicd-artifact-계정식별자
소스 공급자
AWS CodeCommit
Repository name
my-cicd-repo
Branch name
main
변경 감지 방식
CloudWatch Events / EventBridge 기반 변경 감지
설명
main 브랜치에 push가 발생하면 파이프라인이 자동 실행됨
빌드 공급자
AWS CodeBuild
Project name
my-cicd-build
입력 아티팩트 이름은 기본값으로 두어도 무방함.

배포 공급자
AWS CodeDeploy
Application name
my-cicd-app
Deployment group
my-cicd-dg
설명

CodePipeline 생성 후
이미 CodeCommit에 소스가 올라가 있다면 첫 실행이 가능함.
확인 순서
1. Source 성공
2. Build 성공
3. Deploy 성공

브라우저에서 확인
http://EC2_PUBLIC_IP
정상이라면 아래 문구가 보임.
AWS Native CI/CD Demo - Version 1

기존 문구를 아래처럼 수정함.
<!DOCTYPE html>
<htmllang="ko">
<head>
<metacharset="UTF-8">
<title>AWS Native CI/CD Demo</title>
</head>
<body>
<h1>AWS Native CI/CD Demo - Version 2</h1>
<p>This page was redeployed automatically after git push.</p>
</body>
</html>
git add .
git commit -m "Update version to 2"
git push
확인 항목
CodePipeline이 자동 실행되었는지 확인
CodeBuild가 다시 수행되었는지 확인
CodeDeploy가 다시 수행되었는지 확인

브라우저 새로고침 시 Version 2가 보이는지 확인

이번 실습 전체 동작은 다음과 같음.
CodeCommit main 브랜치에 코드 변경이 push됨.
CodeBuild가 buildspec.yml을 읽고
배포에 필요한 파일만 정리해서 아티팩트 생성함.
CodeDeploy가 appspec.yml을 읽고
EC2의 /var/www/html로 파일을 복사함.
CodeDeploy가 훅 스크립트를 순서대로 실행함.
브라우저에서 최신 배포 결과가 확인됨.
원인
확인
Deploy=Web인지 확인원인
확인 포인트
저장소 루트
├─ index.html
├─ buildspec.yml
├─ appspec.yml
└─ scripts/
appspec.yml은 루트에 있어야 함.
원인
확인
chmod +x scripts/*.sh
추가로 로컬에서 직접 실행 테스트해보는 것도 좋음.
원인
확인
cp -r 경로 확인output 폴더 구조 확인원인
/var/www/html/index.html 누락EC2에서 직접 점검
sudo systemctl status nginx
curl -I http://localhost
ls -al /var/www/html
원인
확인
CodeCommit은 소스 저장소임.
실제 서비스는 EC2에서 실행됨.
즉,
이 역할 분리가 핵심임.
CodePipeline은 직접 코드를 빌드하거나 배포하는 서비스가 아님.
각 단계를 연결하고 흐름을 제어하는 서비스임.
즉,
이 과정을 연결해주는 역할을 함.
CodeDeploy는 단순 파일 복사만 하는 것이 아니라
라이프사이클 이벤트에 따라 스크립트를 실행할 수 있음.
그래서 다음과 같은 자동화가 가능함.
그래서 ValidateService 훅이 중요함.
단순히 /var/www/html에 파일이 들어갔다고 끝이 아니라
실제로 curl http://localhost가 성공해야 진짜 배포 성공이라고 볼 수 있음.