
로컬에서의 성공, 서버에서도 보장할 수 있을까?
안녕하세요! 내 계좌를 위한 견고한 시스템을 구축하는 [계좌 리팩토링] 시리즈 14편입니다. 지난 13편에서는 GitHub Actions를 통해 코드를 Push하기만 하면 VRT 테스트가 자동으로 수행되는 세련된 CI/CD 파이프라인을 구축했습니다.
테스트도 통과했고, 이제 클라우드 서버(AWS EC2, Oracle Cloud 등)나 집에 있는 미니 PC에 봇을 올려서 24시간 돌릴 일만 남았습니다. 그런데 막상 서버에 접속해서 코드를 받고 실행해 보면, 당황스러운 에러들을 마주하게 됩니다.
"어? 내 맥북에서는 잘 되는데, 왜 우분투 서버에서는 에러가 나지?"
"Node.js 버전이 달라서 패키지 설치가 안 되네..."
이러한 '내 PC에선 되는데 환경(It works on my machine)' 문제를 영구적으로 해결하고, 배포 과정을 놀랍도록 단순하게 만들어주는 마법의 도구, Docker(도커)를 우리 봇에 도입해 보겠습니다.
Docker란 무엇인가? (컨테이너의 마법)
Docker는 여러분의 애플리케이션(자동매매 봇)과 그 애플리케이션이 실행되는 데 필요한 모든 환경(Node.js 버전, 설치된 라이브러리, OS 설정 등)을 하나의 '컨테이너(Container)'라는 박스에 포장하는 기술입니다.
이 박스를 만들어두면, 윈도우든 맥이든 리눅스든 Docker가 깔려있는 곳이라면 어디서든 로컬 개발 환경과 100% 동일한 상태로 봇을 실행할 수 있습니다.
1단계: Dockerfile 작성하기
봇을 박스에 포장하는 설명서 역할을 하는 Dockerfile을 프로젝트 최상단에 생성합니다.
# 1. 가볍고 안정적인 Node.js 20버전 Alpine 리눅스를 베이스 이미지로 사용합니다.
FROM node:20-alpine
# 2. 컨테이너 내부의 작업 디렉토리를 설정합니다.
WORKDIR /app
# 3. pnpm을 전역으로 설치합니다.
RUN npm install -g pnpm
# 4. 패키지 정보 파일들을 먼저 복사하여 의존성을 설치합니다. (캐싱 최적화)
COPY package.json pnpm-lock.yaml ./
# 💡 실전 팁: 보안이 엄격한 사내망/폐쇄망 등 제한된 내부 네트워크 환경에서 배포해야 한다면,
# 외부 npm 레지스트리 접근이 차단될 수 있습니다. 이럴 때는 내부 Nexus 등
# 사설 저장소를 바라보도록 pnpm 설정을 추가해야 의존성 설치 에러를 방지할 수 있습니다.
# RUN pnpm config set registry https://your-internal-nexus-url.com/repository/npm-group/
# 5. 의존성 패키지를 설치합니다.
RUN pnpm install --frozen-lockfile
# 6. 나머지 프로젝트 소스 코드 전체를 복사합니다.
COPY . .
# 7. 11편에서 만든 대시보드 API용 포트(3001)를 개방합니다.
EXPOSE 3001
# 8. 컨테이너가 켜질 때 봇을 실행할 기본 명령어를 지정합니다.
# (PM2를 컨테이너 내부에서 쓸 수도 있지만, Docker 자체가 프로세스를 관리하므로 순수 node 명령어 실행을 권장합니다.)
CMD ["node", "app.js"]
2단계: docker-compose.yml로 환경 변수 우아하게 관리하기
자동매매 봇에는 KIS API 토큰, 계좌번호, 텔레그램 토큰 등 민감한 정보가 .env 파일에 들어있습니다. 이 파일은 GitHub에 올라가면 절대 안 되기 때문에, 서버에서 컨테이너를 실행할 때 안전하게 주입해 주어야 합니다.
이를 쉽게 관리하기 위해 docker-compose.yml 파일을 작성합니다.
# (프로젝트 루트의 docker-compose.yml)
version: '3.8'
services:
stock-bot:
build: . # 현재 폴더의 Dockerfile을 기반으로 이미지를 빌드합니다.
container_name: my-quant-bot
restart: always # 에러로 봇이 꺼지거나, 서버가 재부팅되면 자동으로 봇을 다시 실행합니다. (PM2 대체)
ports:
- "3001:3001" # 대시보드 접근용 포트 매핑 (호스트:컨테이너)
env_file:
- .env # 서버에 업로드해둔 .env 파일을 읽어와 컨테이너 내부에 주입합니다.
environment:
- TZ=Asia/Seoul # 주식 시장 시간에 맞춰 컨테이너의 타임존을 한국 시간으로 강제 설정합니다.
3단계: 서버에서 단 한 줄의 명령어로 봇 실행하기
이제 클라우드 서버에 접속하여 소스코드와 .env 파일만 가져다 놓은 뒤, 터미널에서 다음 명령어 딱 한 줄만 입력하면 됩니다.
# 백그라운드(-d) 모드로 컨테이너 빌드 및 실행
docker-compose up -d --build
이 명령어를 치면 Docker가 알아서 필요한 Node.js 환경을 다운로드하고, 패키지를 설치한 뒤 봇을 실행해 줍니다. 봇이 잘 돌아가는지 확인하고 싶다면 아래 명령어로 실시간 로그를 볼 수 있습니다.
docker-compose logs -f
마무리: 인프라 고민 끝, 오직 로직에만 집중하라
이제 여러분의 봇은 그 어떤 서버에 던져놔도 완벽하게 동일하게 동작하는 '무결점 컨테이너'가 되었습니다. PM2를 따로 설치하거나 버전을 맞출 필요도 없고, 서버를 옮길 때도 docker-compose.yml과 .env만 들고 가면 그만입니다.
13편의 CI/CD와 이번 14편의 Docker를 결합하면, "GitHub에 코드를 푸시하면 -> 테스트가 통과되고 -> 자동으로 새로운 Docker 이미지가 빌드되어 -> 서버에서 갈아끼워지는" 궁극의 자동화 배포 파이프라인을 완성할 수도 있습니다.
복잡하고 피곤한 서버 세팅은 Docker에게 맡기고, 우리는 계속해서 봇을 더 똑똑하게 만들 '알고리즘'과 '전략' 개발에만 몰두합시다!