AWS EC2 + React + Docker 개발 환경 세팅

우선 제가 어떤 개발 환경을 만들고 싶은지 정리를 해보겠습니다.

현재 로컬 환경에서 React 를 이용하여 웹 페이지 등을 개발하고 있습니다. 

실제 웹 페이지는 AWS EC2 를 이용하여 베포를 하고 있습니다. 

React 에서 작성한 프로젝트 등을 AWS EC2에 쉽게 업데이트 하는 것이 목적입니다.

이를 위해서 Docker 을 이용하려 합니다. 

기본적으로 Docker 가 설치되었고, EC2 세팅이 되어 있다는 가정 하에 진행합니다. 

로컬 개발 환경 구성하기

 

React 프로젝트를 개발하기 위해서 사용하는 루트 디렉토리가 있을 것입니다.

이 루트 디렉토리에는 “src” “public” “build” 등의 폴더가 있겠지요. 

이곳에 파일을 하나 생성할 겁니다.

파일의 이름은 “Dockerfile” 입니다.

확장자명 없이 그냥 “Dockerfile” 이라는 이름만 가진 파일을 하나 만듭시다. 

VScode 상에서 만들면 쉽습니다. 

				
					# 1. Node.js 환경 설정
FROM node:18-alpine

# 2. 컨테이너 내부 작업 디렉토리 지정
WORKDIR /app

# 3. package.json과 package-lock.json 복사 및 의존성 설치
COPY package.json package-lock.json ./
RUN npm install

# 4. 프로젝트 전체 복사 (이후 변경 사항 반영)
COPY . .

# 5. 개발 모드로 React 실행 (Hot Reload 지원)
CMD ["npm", "start"]

# 6. React 개발 서버 포트 개방
EXPOSE 3000

				
			

그리고 위와 같은 내용을 넣어서 저장해주세요. 

이후에는 한 번 더 같은 경로에 파일을 하나 만듭시다.

이 파일의 이름은 “docker-compose.yml” 입니다.

				
					services:
  frontend:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    stdin_open: true
    tty: true
    command: ["npm", "start"] # ← 명시적으로 React 개발 서버 실행

				
			

내용은 위와 같이 해뒀습니다.

그럼 이제 기존에 npm start 으로 실행하던 로컬 프로젝트를 다른 방식으로 실행 가능합니다.

				
					docker-compose up
				
			

위 명령어를 기존 npm start 하던 터미널 창에서 하면 

그냥 마찬가지로 localhost:3000 부분에 현재 프로젝트 띄워줍니다. 

				
					docker-compose down
				
			

끄고 싶을 때는 이걸로 끄면 됩니다. 

EC2 세팅

이를 위해서는 우선 EC2에 Putty 통해 접속이 필요합니다.

접속을 하면 위와 같이 나타나죠.

여기에서 몇 가지 명령어로 Docker 다운로드 밑 Docker 실행을 할 것입니다. 

				
					# 1. 패키지 업데이트
sudo yum update -y

# 2. Docker 설치
sudo yum install docker -y

# 3. Docker 실행 및 자동 시작 설정
sudo systemctl start docker
sudo systemctl enable docker

# 4. Docker Compose 설치
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

				
			

위 명령어들 통해서 패키지 및 docker 을 Ec2에 다운로드 해줍시다. 

				
					docker --version
docker-compose --version

				
			

잘 됐는지는 위 명령어 통해서 확인 가능합니다. 

처음 EC2를 생성할 때 다운로드 받은 SSH Key 파일이 있는 경로를 봅시다.

PPK 파일만 있다면, PEM 파일 생성이 필요합니다.

위 버튼을 눌러서 Putty Gen 을 다운로드 하러 갑시다.

다운로드 이후에는 실행해서 다음과 같은 과정을 수행합니다.

✅ 1️⃣ PuTTYgen을 사용하여 .ppk → .pem 변환

1. PuTTYgen 실행

  • Windows 시작 메뉴에서 PuTTYgen 검색 후 실행

2. .ppk 키 파일 불러오기

  • Load 버튼 클릭C:\Key\MyKey.ppk 파일 선택

3. .pem 키 파일로 저장

  • ConversionsExport OpenSSH Key 클릭
  • 파일 이름: MyKey.pem
  • “Save as type”을 “All Files”로 설정 후 저장

✅ 이제 C:/Key/MyKey.pem 파일이 생성됨.

위 내용은 내 C 드라이브 내부에 Key 라는 폴더가 있고,

그 안에 나의 SSH Key 를 넣어다는 가정으로 작성된 과정입니다. 

위 내용 따라서 pem 파일을 같은 경로에 만들었다면…

Git Bash 실행해서 EC2 에 SSH 접속을 할 것입니다. 

				
					ssh -i C:/Key/MyKey.pem ec2-user@[EC2 Public IP]

				
			

접속 명령어는 다음과 같습니다.

이를 위해서는 내가 방금 생성한 pem 파일의 정확한 경로와 

내가 접속하려는 EC2 의 Public IP를 알아야 합니다. 

이렇게 하면 Git Bash 창에서도 SSH 접속이 성공된 것을 볼 수 있습니다.

이렇게 Git Bash 에서 새가 보이면 잘 접속 되는 겁니다.

여기서 Docker 빌드를 위해서 몇 가지를 설치할 겁니다.

				
					sudo yum install git -y

				
			
				
					sudo yum install docker -y
sudo systemctl start docker
sudo systemctl enable docker
				
			

하나는 git 설치를 위함이고,

그 아래 명령어들은 docker 을 설치하고 실행하는 과정입니다.

 

				
					sudo usermod -aG docker ec2-user

				
			

또한 다음과 같이 EC2에 접속한 계정으로 권한을 부여합니다.

내가 ec2-tester 이라는 계정으로 접속했다면 “ec2-user” 부분을 그걸로 대체하면 되는 거죠. 

				
					exit
				
			

이제 다시 EC2 나가서 원래 Git Bash 입력창으로 돌아가 줍니다.

 

				
					scp -i "C:/Key/MyKey.pem" -r "C:/project" ec2-user@[Ec2 ip]:/home/ec2-user/

				
			

그럼 이제 여기서 위와 같은 명령어로 로컬에 있는 내 프로젝트 파일을 EC2로 업로드 가능합니다.

업로드가 완료 되었나요?

그럼 간단하게 현재 서버가 80 포트를 먹고 있는지 보겠습니다. 

다시 SSH 접속을 통해 EC2에 접속합시다. 

				
					sudo netstat -tulnp | grep :80


				
			

요걸 쓰면 현재 80 포트에 실행되는 프로세스가 있는지 나타납니다.

				
					tcp6       0      0 :::80                   :::*                    LISTEN      1234/nginx

				
			

위와 같이 나타납니다.

여기서 LISTEN 부분이 “httpd” 이느냐, “nginx” 이느냐에 따라서 80 포트 끄는 작업이 다릅니다.

				
					sudo systemctl stop nginx
sudo systemctl disable nginx

				
			
				
					sudo systemctl stop httpd
sudo systemctl disable httpd

				
			

차례대로 nginx 끄는 법과 httpd 끄는 방식입니다.

이렇게 80 포트를 차지했던 프로세스를 종료했다면 Docker 빌드를 할 차례입니다. 

				
					docker-compose -f docker-compose.prod.yml up -d --build

				
			

위 명령어로 docker compose 를 실행하면 됩니다.

그럼 이제 80 포트에 제대로 React 프로젝트가 나타납니다. 

프로젝트 업데이트가 되었다면?

 

지금 React 개발된 프로젝트를 올리고 확인은 했습니다.

그렇다면, 이 프로젝트를 변경하고 업데이트를 한 이후에는 어떻게 반영할까요?

				
					npm run build
				
			

로컬에서 변경된 프로젝트를 위와 같이 build 합니다. 

				
					rsync -avz --progress -e "ssh -i C:/Key/MyKey.pem" C:/project/build/ ec2-user@[EC2 ip]:/home/ec2-user/project/build/

				
			

그리고 git bash 에서 위와 같은 명령어로 업데이트 가능합니다. 

더욱 밀접한 연동 환경 구축하기

 

위 방식으로만 업데이트 하는 것도 가능은 합니다.

하지만, 그때 그때 git bash 켜고 명령어 넣는 방식이 썩 만족스럽지는 못합니다.

더 편하고 쉽게 진행하기 위해서 Docker Desktop 과 Git Action을 이용한 방식도 보겠습니다.

				
					# 1. Node.js 환경에서 React 빌드
FROM node:18-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# 2. Nginx로 정적 파일 배포
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

				
			

 위와 같은 내용을 가진 파일을 내 React 프로젝트 루트에 생성합시다.

파일의 이름은 “Dockerfile.prod” 입니다.

				
					# 1. Node.js 이미지 사용 (개발 환경)
FROM node:18-alpine

# 2. 작업 디렉토리 설정
WORKDIR /app

# 3. package.json 복사 후 의존성 설치
COPY package.json package-lock.json ./
RUN npm install

# 4. 전체 소스 코드 복사
COPY . .

# 5. 개발 모드 실행 (Hot Reload 지원)
CMD ["npm", "start"]

# 6. React 개발 서버(3000번 포트) 노출
EXPOSE 3000

				
			

 위와 같은 내용을 가진 파일을 내 React 프로젝트 루트에 생성합시다.

파일의 이름은 “Dockerfile.dev” 입니다.

				
					version: "3.8"
services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true
    restart: always

				
			

 위와 같은 내용을 가진 파일을 내 React 프로젝트 루트에 생성합시다.

파일의 이름은 “docker-compose.dev.yml” 입니다.

				
					version: "3.8"
services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile.prod
    ports:
      - "80:80"
    restart: always

				
			

 위와 같은 내용을 가진 파일을 내 React 프로젝트 루트에 생성합시다.

파일의 이름은 “docker-compose.prod.yml” 입니다.

				
					name: Deploy React App

on:
  push:
    branches:
      - main # ✅ 'main' 브랜치에 push하면 자동 실행됩니다.

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      # 1️⃣ GitHub Repository에서 최신 코드 가져오기
      - name: Checkout Repository
        uses: actions/checkout@v2

      # 2️⃣ Docker Buildx 설정 (멀티 플랫폼 빌드를 지원)
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      # 3️⃣ Docker Hub 로그인
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}  # 🔹 본인의 Docker Hub 사용자명 (GitHub Secrets에 저장)
          password: ${{ secrets.DOCKER_PASSWORD }}  # 🔹 본인의 Docker Hub 비밀번호 또는 액세스 토큰 (GitHub Secrets에 저장)

      # 4️⃣ React 프로젝트를 빌드하고 Docker Hub에 Push
      - name: Build and Push Docker Image
        run: |
          docker build -t ${{ secrets.DOCKER_USERNAME }}/my-app:latest -f Dockerfile.prod .  
          docker push ${{ secrets.DOCKER_USERNAME }}/my-app:latest  

          # 🔹 `my-app` 부분을 본인의 프로젝트명으로 변경하세요.
          # 🔹 `Dockerfile.prod`이 없을 경우, `Dockerfile`을 사용하도록 변경하세요.

      # 5️⃣ GitHub Secrets에서 SSH Key를 디코딩하여 private_key.pem 파일로 저장
      - name: Decode SSH Key and Save to File
        run: |
          echo "${{ secrets.SSH_KEY }}" | tr -d '\r' | base64 --decode > private_key.pem  
          chmod 600 private_key.pem  

          # 🔹 GitHub Secrets에 SSH Key를 추가해야 합니다.
          # 🔹 EC2에서 사용한 `.pem` 키를 base64로 인코딩한 후 GitHub Secrets에 `SSH_KEY`로 저장하세요.

      # 6️⃣ EC2에 접속하여 컨테이너를 배포 (Zero-Downtime 방식)
      - name: Deploy to EC2 (Zero-Downtime)
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.EC2_HOST }}  # 🔹 본인의 EC2 퍼블릭 IP (GitHub Secrets에 저장)
          username: ec2-user  # 기본적인 Amazon Linux 2의 사용자명 (필요하면 변경)
          key_path: private_key.pem

          script: |
            # 최신 Docker 이미지 가져오기
            docker pull ${{ secrets.DOCKER_USERNAME }}/my-app:latest  

            # 현재 실행 중인 컨테이너 확인
            CURRENT_CONTAINER=$(docker ps --filter "name=my-app" -q)

            # 새로운 컨테이너 실행 (포트 8080에서 우선 실행)
            docker run -d -p 8080:80 --name my-app-new ${{ secrets.DOCKER_USERNAME }}/my-app:latest  

            # 새 컨테이너가 정상 실행되는지 확인 (헬스 체크)
            sleep 10  
            if [ "$(docker ps -q -f name=my-app-new)" ]; then  
              echo "✅ 새로운 컨테이너가 정상 실행됨. 트래픽 전환 진행..."

              # 기존 컨테이너 중지 및 삭제
              if [ ! -z "$CURRENT_CONTAINER" ]; then  
                docker stop my-app  
                docker rm my-app  
              fi  

              # 새 컨테이너를 기존 컨테이너로 대체
              docker rename my-app-new my-app  

              # 새 컨테이너를 포트 80으로 실행 (포트 변경)
              docker stop my-app  
              docker rm my-app  
              docker run -d -p 80:80 --name my-app ${{ secrets.DOCKER_USERNAME }}/my-app:latest  

              echo "🚀 배포 완료! 새로운 컨테이너가 포트 80에서 실행 중입니다."
            else  
              echo "❌ 새 컨테이너 실행 실패. 기존 컨테이너 유지."
              exit 1  
            fi  

            # 🔹 EC2의 기존 실행 중인 컨테이너를 안전하게 교체하는 방식입니다.
            # 🔹 `my-app` 부분을 본인의 프로젝트명으로 변경하세요.

				
			

 위와 같은 내용을 가진 파일을 내 React 프로젝트 루트에 “.github” 라는 디렉토리를 생성하고, 그 내부에 “workflows” 라는 디렉토리를 하나 더 만들어서 내부에 넣습니다.

파일의 이름은 “deploy.yml” 입니다.

이 파일은 git hub에 내가 프로젝트를 push 하면 알아서 EC2 내부로 업데이트를 하도록 하는 도구입니다.

 

꼭꼭! 주석을 읽으면서 파일을 확인하고 여러분 개인의 정보에 맞도록 설정해야 하는 부분은 파일 내부에서 바꿔주세요!

(secret 부분은 아래에서 설명을 더하겠습니다.)

Git Hub 세팅

				
					git remote add origin https://github.com/your-github-username/project.git

				
			

Git hub 에서 저장소 하나 만듭시다.

생성한 저장소의 경로로 Git Bash 에서 연결을 합시다. 

				
					git remote -v


				
			

이걸로 확인하면 됩니다.

해당 저장소 경로로 fetch, push 뜨면 성공입니다. 

				
					cd C:/project

				
			

그럼 이제 내 React 프로젝트 루트 디렉토리로 이동을 합시다.

목적은 루트 디렉토리 내부에 있는 파일 구조를 통째로 저장소로 올리는 겁니다. 

				
					git commit -m "250216 version 1"

				
			
				
					git push origin main
				
			

위 명령어를 차례대로 하면 해당 commit 을 가진 main branch 로 파일들이 업로드가 됩니다.

웹에서 github 저장소로 가면 실제로 파일들이 쭉 업로드가 되어 있을 겁니다.

이때 앞서 생성했던 “Deploy.yml” 파일이 작동하는 겁니다.

 Deploy.yml 에서 “Secret” 부분이 있었지요?

				
					      # 3️⃣ Docker Hub 로그인
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}  # 🔹 본인의 Docker Hub 사용자명 (GitHub Secrets에 저장)
          password: ${{ secrets.DOCKER_PASSWORD }}  # 🔹 본인의 Docker Hub 비밀번호 또는 액세스 토큰 (GitHub Secrets에 저장)
				
			

바로 여기 단계입니다.

Docker Hub 로그인 단계에서 secrets.DOCKER_USERNAME 및 PASSWORD를 사용합니다.

이거 설정을 위해서 github 로그인을 해봅시다.

그리고 내 저장소로 이동을 합시다.

위쪽에 보면 Settings 있습니다.

저거 눌러서 이동합니다.

이동한 페이지의 왼쪽 대쉬보드를 봅니다.

“Secrets and Variable” 를 선택하고 “Actions” 를 선택합니다.

그리고 “New repository secret” 을 클릭해서 생성을 할 겁니다. 

그럼 다음과 같은 양식으로 새로운 Secret 생성이 가능합니다.

Name 부분과 Value 부분이 있습니다.

Name 부분이 변수 이름이 되는 거고, Secret 부분에 Value 를 넣으면 그 값을 이용하게 되는 거죠.

				
					Name : EC2_HOST
Value : 15.15.15.15 (EC2 IP)
				
			

우선은 EC2_HOST 라는 Secret 을 생성합니다.

이곳의 Value는 업데이트를 하고 싶은 EC2의 Public IP를 넣어주면 됩니다. 

				
					Name : SSH_KEY
Value : (.pem 파일을 디코딩한 값 )
				
			

두 번째는 SSH_KEY를 넣을 겁니다.

내 EC2로 접근하기 위해서 필요한 Key 값인데요.

이를 위해서는 Git Bash 통해서 파일을 디코딩해야 합니다. 

				
					base64 -w 0 C:/Key/ssh_key.pem > C:/Key/ssh_key_base64.txt

				
			

앞서 .pem 파일을 생성했죠?

그 pem 파일의 경로를 이용해서, 동일한 경로 내부에 디코딩 된 텍스트 파일을 생성합니다.

이 텍스트 파일의 값을 그대로 복사하고, SSH_KEY 의 Value 부분에 넣으면 됩니다.

다음 Secret 생성 전에 Docker Hub 이동해서 로그인을 합시다.

로그인이 됐다면 우측 상단 프로필을 클릭해서 “Account Setting” 으로 들어갑시다.

좌측 대쉬보드에서 “Personal access tokens” 를 선택합니다.

메인 화면에서 “Generate New Token” 을 통해서 토큰 생성을 해줄 겁니다.

클릭해주세요.

위와 같이 적절하게 설정을 해주세요.

Access permissions 는 “Read, Write, Delete” 모두 가능하게 합니다. 

생성 버튼을 누릅니다.

그럼 위와 같이 토큰 전반적인 정보를 알 수 있습니다.

여기서 사용자의 유저명과 토큰을 확인 가능합니다.

이 확인한 2가지 정보를 secret 에 넣어줄 겁니다.

				
					Name : DOCKER_USERNAME
Value : (확인한 유저명)
				
			
				
					Name : DOCKER_PASSWORD
Value : (복사한 토큰값)
				
			

위와 같이 각각의 정보를 해당하는 Name 에 맞춰서 Secret 생성하면 끝입니다.

마치며...

				
					npm run build
				
			

로컬에서 프로젝트를 수정하면 그에 맞춰서 빌드를 하게 되겠죠.

				
					git add .
				
			
				
					git commit -m "new version"
				
			
				
					git push origin main
				
			

이후에 다음과 같이 git push 명령어를 이용하면…

저장소로 프로젝트가 업데이트가 되면서 동시에 

실제 EC2 도커가 업데이트가 됩니다.

				
					cd C:/project