LocalStack과 Docker로 AWS 클라우드 어플리케이션 개발·테스트하기

LocalStack과 Docker로 AWS 클라우드 어플리케이션 개발·테스트하기

이 가이드는 로컬 AWS 클라우드 스택 에뮬레이터인 LocalStack을 Docker로 실행하는 방법을 설명해요.

출처: 문서

본문

현대 어플리케이션 개발에서 실환경에 배포하기 전에 클라우드 어플리케이션을 로컬에서 테스트하면 더 빠르고 더 자신 있게 출시할 수 있어요. 이 접근법은 서비스를 로컬에서 시뮬레이션하고, 문제를 조기에 식별·수정하며, 비용이나 전체 클라우드 환경의 복잡성 없이 빠르게 반복하는 것을 포함해요. LocalStack 같은 도구는 이 과정에서 매우 귀중해져, AWS 서비스를 에뮬레이트하고 일관되고 격리된 테스트 환경을 위해 어플리케이션을 컨테이너화할 수 있게 해줘요.

이 가이드에서 배울 내용:

  • Docker로 LocalStack 컨테이너 실행하기
  • 비컨테이너화 어플리케이션에서 LocalStack에 연결하기
  • 컨테이너화 어플리케이션에서 LocalStack에 연결하기

LocalStack이란?

LocalStack은 내 노트북의 단일 컨테이너에서 실행되는 클라우드 서비스 에뮬레이터예요. AWS 기반 어플리케이션을 로컬에서 테스트·개발하는 강력하고 유연하며 비용 효율적인 방법을 제공해요.

왜 LocalStack을 사용하나요?

AWS 서비스를 로컬에서 시뮬레이션하면 실제 AWS 클라우드에 연결하지 않고도 앱이 S3, Lambda, DynamoDB 같은 서비스와 어떻게 상호작용하는지 테스트할 수 있어요. 이 단계에서 클라우드에 배포하는 비용과 복잡성을 피하면서 개발을 빠르게 반복할 수 있어요.

이 서비스들의 동작을 로컬에서 흉내 냄으로써 LocalStack은 더 빠른 피드백 루프를 가능하게 해요. 내 앱은 외부 API와 상호작용할 수 있지만 모든 것이 로컬에서 실행되므로 클라우드 프로비저닝이나 네트워크 지연을 다룰 필요가 없어요.

이로써 실환경에서 IAM 역할이나 정책을 구성하지 않고도 통합을 검증하고 클라우드 기반 시나리오를 테스트하기가 더 쉬워져요. 복잡한 클라우드 아키텍처를 로컬에서 시뮬레이션하고 준비가 되었을 때만 AWS로 변경 사항을 푸시할 수 있어요.

Docker로 LocalStack 사용하기

LocalStack 의 공식 Docker 이미지 는 개발 머신에서 LocalStack을 실행하는 편리한 방법을 제공해요. 무료로 사용할 수 있고 실행에 API 키가 필요 없어요. 심지어 LocalStack Docker Extension 을 사용해 그래픽 사용자 인터페이스로 LocalStack을 사용할 수도 있어요.

사전 요구사항

이 how-to 가이드를 따라 하려면 다음 전제조건이 필요해요:

  • Docker Desktop
  • Node.js
  • Python과 pip
  • Docker에 대한 기본 지식

LocalStack 실행

다음 단계로 LocalStack의 빠른 데모를 실행해주세요:

샘플 어플리케이션 을 클로닝하는 것으로 시작해주세요. 터미널을 열고 다음 명령을 실행해주세요:

$ git clone https://github.com/dockersamples/todo-list-localstack-docker
$ cd todo-list-localstack-docker

LocalStack 띄우기

다음 명령으로 LocalStack을 띄워주세요.

$ docker compose -f compose-native.yml up -d

이 Compose 파일에는 필요한 Mongo 데이터베이스에 대한 사양도 포함돼 있어요. Docker Desktop Dashboard를 방문해 서비스가 실행 중인지 확인할 수 있어요.

컨테이너를 선택하고 로그를 확인해 LocalStack이 실행 중인지 검증해주세요.

로컬 Amazon S3 버킷 만들기

LocalStack으로 로컬 S3 버킷을 만들 때는 본질적으로 AWS에서 S3 버킷을 만드는 것을 시뮬레이션하는 거예요. 이렇게 하면 실제 AWS 계정 없이도 S3와 상호작용하는 어플리케이션을 테스트·개발할 수 있어요.

로컬 Amazon S3 버킷을 만들려면 시스템에 awscli-local CLI 를 설치해주세요. awslocal 명령은 LocalStack과 함께 사용하기 위한 AWS 명령줄 인터페이스의 얇은 래퍼예요. 실제 AWS 서비스에 접근할 필요 없이 로컬 머신의 시뮬레이션 환경에 대해 테스트·개발할 수 있게 해줘요.

$ pip install awscli-local

다음 명령으로 LocalStack 환경 안에 새 S3 버킷을 만들어주세요:

$ awslocal s3 mb s3://mysamplebucket

s3 mb s3://mysamplebucket 명령은 AWS CLI에 mysamplebucket 이라는 새 S3 버킷 마들기( mb 는 make bucket 을 뜻함)를 지시해요.

Docker Desktop Dashboard에서 LocalStack 컨테이너를 선택하고 로그를 보면 S3 버킷이 생성됐는지 확인할 수 있어요. 로그는 내 LocalStack 환경이 올바르게 구성됐고 이제 mysamplebucket 을 객체 저장·검색에 사용할 수 있다는 것을 나타내요.

개발에서 LocalStack 사용하기

이제 LocalStack에 익숙해졌으니 실제로 사용되는 것을 볼 차례예요. 이 데모에서는 React 프론트엔드와 Node.js 백엔드를 갖춘 샘플 어플리케이션을 사용할 거예요. 이 어플리케이션 스택은 다음 구성 요소를 활용해요:

  • React: todo-list 어플리케이션에 접근하는 사용자 친화적인 프론트엔드
  • Node: HTTP 요청을 처리하는 백엔드
  • MongoDB: 모든 할 일 목록 데이터를 저장하는 데이터베이스
  • LocalStack: Amazon S3 서비스를 에뮬레이트하고 이미지를 저장·검색

비컨테이너화 앱에서 LocalStack에 연결하기

이제 앱을 LocalStack에 연결할 차례예요. backend/ 디렉터리에 있는 index.js 파일이 백엔드 어플리케이션의 메인 엔트리 포인트 역할을 해요.

이 코드는 LocalStack의 S3 서비스와 상호작용하며, S3_ENDPOINT_URL 환경 변수로 정의된 엔드포인트를 통해 접근하고, 로컬 개발에서는 보통 http://localhost:4566 으로 설정돼요.

AWS SDK의 S3Client 가 이 LocalStack 엔드포인트를 사용하도록 구성되고, 환경 변수에서도 가져오는 테스트 자격 증명( AWS_ACCESS_KEY_ID 와 AWS_SECRET_ACCESS_KEY )이 함께 사용돼요. 이 설정은 어플리케이션이 실제 AWS S3와 상호작용하는 것처럼 로컬로 시뮬레이션된 S3 서비스에서 작업을 수행할 수 있게 해, 코드를 여러 환경에 유연하게 만들어요.

이 코드는 파일 업로드를 처리하기 위해 multer 와 multer-s3 를 사용해요. 사용자가 /upload 라우트를 통해 이미지를 업로드하면 파일은 LocalStack이 시뮬레이션한 S3 버킷에 직접 저장돼요. 버킷 이름은 S3_BUCKET_NAME 환경 변수에서 가져와요. 각 업로드 파일에는 원본 파일 이름에 현재 타임스탬프를 추가해 고유한 이름이 부여돼요. 라우트는 업로드된 파일의 로컬 S3 서비스 내 URL을 반환해, 실제 AWS S3 버킷에서 호스팅될 때처럼 접근 가능하게 해요.

실제로 확인해볼게요. Node.js 백엔드 서비스를 시작해주세요.

backend/ 디렉터리로 이동해주세요:

$ cd backend/

필요한 의존성을 설치해주세요:

$ npm install

AWS 환경 변수 설정

backend/ 디렉터리에 있는 .env 파일에는 LocalStack이 AWS 서비스를 에뮬레이트하는 데 사용하는 자리 표시자 자격 증명과 구성 값이 이미 들어 있어요. AWS_ACCESS_KEY_ID 와 AWS_SECRET_ACCESS_KEY 는 자리 표시자 자격 증명이고, S3_BUCKET_NAME 과 S3_ENDPOINT_URL 은 구성 설정이에요. 이 값들은 LocalStack에 맞게 이미 올바르게 설정되어 있으므로 변경이 필요 없어요.

팁: Mongo를 Docker 컨테이너에서, 백엔드 Node 앱을 호스트에서 네이티브로 실행하므로 .env 파일에 MONGODB_URI=mongodb://localhost:27017/todos 가 설정되어 있는지 확인하세요.

MONGODB_URI=mongodb://localhost:27017/todos
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
S3_BUCKET_NAME=mysamplebucket
S3_ENDPOINT_URL=http://localhost:4566
AWS_REGION=us-east-1

AWS SDK는 보통 AWS_ 로 시작하는 환경 변수를 사용하지만, 이 특정 어플리케이션은 index.js 파일(backend/ 디렉터리 아래)에서 다음 S3_* 변수를 직접 참조해 S3Client 를 구성해요.

const s3 = new S3Client({
  endpoint: process.env.S3_ENDPOINT_URL, // Use the provided endpoint or fallback to defaults
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID || 'default_access_key', // Default values for development
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || 'default_secret_key',
  },
});

백엔드 서버를 시작해주세요:

$ node index.js

백엔드 서비스가 포트 5000에서 성공적으로 시작됐다는 메시지를 보게 될 거예요.

프론트엔드 서비스 시작

프론트엔드 서비스를 시작하려면 새 터미널을 열고 다음 단계를 따르세요:

frontend 디렉터리로 이동해주세요:

$ cd frontend

필요한 의존성을 설치해주세요:

$ npm install

프론트엔드 서비스를 시작해주세요:

$ npm run dev

이제 다음 메시지가 보여야 해요:

VITE v5.4.2 ready in 110 ms
➜  Local: http://localhost:5173/
➜  Network: use --host to expose
➜  press h + enter to show help

이제 http://localhost:5173 으로 앱에 접근할 수 있어요. 이미지 파일을 선택하고 Upload 버튼을 클릭해 이미지를 업로드해보세요.

LocalStack 컨테이너 로그를 확인해 이미지가 S3 버킷에 업로드됐는지 확인할 수 있어요:

200 상태 코드는 S3 버킷에 객체를 업로드하는 putObject 작업이 LocalStack 환경 내에서 성공적으로 실행됐음을 나타내요. LocalStack은 수행 중인 작업에 대한 가시성을 제공하기 위해 이 항목을 로깅해요. 이는 내 어플리케이션이 에뮬레이트된 AWS 서비스와 올바르게 상호작용하고 있는지 디버깅하고 확인하는 데 도움이 돼요.

LocalStack은 AWS 서비스를 로컬에서 시뮬레이션하도록 설계됐으므로, 이 로그 항목은 내 어플리케이션이 로컬 샌드박스 환경에서 클라우드 작업을 수행할 때 예상대로 작동한다는 것을 보여줘요.

컨테이너화된 Node 앱에서 LocalStack에 연결하기

비컨테이너화된 Node.js 어플리케이션을 LocalStack에 연결하는 방법을 배웠으니, 이제 전체 어플리케이션 스택을 컨테이너화된 환경에서 실행하는 데 필요한 변경 사항을 탐구할 차례예요. 이를 위해 frontend, backend, database, LocalStack 등 필요한 모든 서비스를 지정하는 Compose 파일을 만들 거예요.

Docker Compose 파일 살펴보기

다음 Docker Compose 파일은 네 개의 서비스( backend , frontend , mongodb , localstack )를 정의해요. backend 와 frontend 서비스는 내 Node.js 어플리케이션이고, mongodb 는 데이터베이스를 제공하며, localstack 은 S3 같은 AWS 서비스를 시뮬레이션해요.

backend 서비스는 localstack 과 mongodb 서비스에 의존해 시작되기 전에 실행 중임을 보장해요. 환경 변수용 .env 파일도 사용해요. frontend 서비스는 backend 에 의존하고 API URL을 설정해요. mongodb 서비스는 데이터 저장용 영구 볼륨을 사용하고, localstack 은 S3 서비스를 실행하도록 구성돼요. 이 설정으로 AWS 같은 서비스로 내 어플리케이션을 로컬에서 개발·테스트할 수 있어요.

services:
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - 5000:5000
    depends_on:
      - localstack
      - mongodb
    env_file:
      - backend/.env
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - 5173:5173
    depends_on:
      - backend
    environment:
      - REACT_APP_API_URL=http://backend:5000/api
  mongodb:
    image: mongo
    container_name: mongodb
    volumes:
      - mongodbdata:/data/db
    ports:
      - 27017:27017
  localstack:
    image: localstack/localstack
    container_name: localstack
    ports:
      - 4566:4566
    environment:
      - SERVICES=s3
      - GATEWAY_LISTEN=0.0.0.0:4566
    volumes:
      - ./localstack:/etc/localstack/init/ready.d
volumes:
  mongodbdata:

backend/ 디렉터리 아래 .env 파일이 내부 네트워크 이름을 사용해 리소스에 연결하도록 수정해주세요.

팁: 이전 Compose 파일을 고려하면 앱은 hostname localstack 을 사용해 LocalStack에, hostname mongodb 를 사용해 Mongo에 연결할 거예요.

MONGODB_URI=mongodb://mongodb:27017/todos
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
S3_BUCKET_NAME=mysamplebucket
S3_ENDPOINT_URL=http://localstack:4566
AWS_REGION=us-east-1

실행 중인 서비스를 중지해주세요. 이전 단계의 Node 프론트엔드와 백엔드 서비스를 터미널에서 "Ctrl+C"를 눌러 중지했는지 확인하세요. 또한 Docker Desktop Dashboard에서 LocalStack과 Mongo 컨테이너를 선택하고 "Delete" 버튼을 선택해 중지해야 해요.

클론된 프로젝트 디렉터리 루트에서 다음 명령을 실행해 어플리케이션 스택을 시작해주세요:

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

잠시 후 어플리케이션이 실행될 거예요.

S3 버킷 수동 생성

AWS S3 버킷은 Compose 파일이 미리 만들지 않아요. 다음 명령으로 LocalStack 환경 내에 새 버킷을 만들어주세요:

$ awslocal s3 mb s3://mysamplebucket

이 명령은 mysamplebucket 이라는 S3 버킷을 만들어요.

팁: 로컬 ./localstack 디렉터리 아래에 셸 스크립트(예: init.sh )를 배치해 이 단계를 자동화할 수 있어요. 스크립트가 실행 가능한지 확인하세요( chmod +x ./localstack/init.sh ). LocalStack은 준비되면 /etc/localstack/init/ready.d 에 마운트된 파일을 실행해요. LocalStack init hooks 에서 자세한 내용을 참고하세요.

http://localhost:5173 을 열어 완전한 할 일 목록 어플리케이션에 접근하고 Amazon S3 버킷에 이미지 업로드를 시작해주세요.

팁: 개발 중 성능을 최적화하고 업로드 시간을 줄이려면 더 작은 이미지 파일을 업로드하는 것을 고려하세요. 더 큰 이미지는 처리하는 데 시간이 더 걸리고 어플리케이션의 전체 응답성에 영향을 줄 수 있어요.

요약

이 가이드는 LocalStack과 Docker를 사용해 로컬 개발 환경을 설정하는 과정을 안내했어요. 로컬에서 AWS 기반 어플리케이션을 테스트해 비용을 줄이고 개발 워크플로의 효율성을 높이는 방법을 배웠어요.

더 알아보기 (Learn more)

  • LocalStack
  • Docker Compose
  • Amazon S3