• 도커로 개인 웹 배포 시 환경 차이점 궁금합니다

    도커로 간단한 개인 웹페이지 배포 건을 생각 중이라 알아보고 있습니다.
    로컬에서 테스트하고 돌려보는 건 비교적 쉬운데, 실제 클라우드나 서버 환경으로 넘기면 뭔가 설정 이슈가 있을 것 같아서요.

    주로 포트 매핑이나 네트워크 관련해서 로컬에서 되던 게 실제 배포 환경에서 막히는 경우가 많다고 들었습니다.

    혹시 도커 환경에서 웹 서비스 배포할 때, 로컬 테스트와 실제 운영 환경 간에 가장 흔하게 놓치거나 주의해야 할 설정 포인트 같은 게 있을까요?
    감사합니다.

  • 질문 주신 내용 보니까 딱 개발자들이 가장 많이 부딪히는 지점을 정확히 짚으신 것 같네요.
    로컬에서 되던 게 서버에서 안 되는 케이스, 정말 흔하고 짜증나죠.
    이건 기술적인 문제라기보다는 '환경의 차이'를 개발자가 간과하기 쉬운 영역들이 많아서 생기는 문제들이거든요.
    딱 포트나 네트워크 이슈만 생각하시는데, 사실 그 외에도 몇 가지 큰 축에서 차이점을 대비하셔야 실전에서 막히는 걸 줄이실 수 있어요.
    제가 직접 몇 군데 배포 경험을 해보면서 체감했던, 로컬 테스트 환경과 실제 운영 환경 간에 가장 흔하게 놓치거나 주의해야 할 핵심 포인트들을 몇 가지로 나눠서 설명드릴게요.
    1.
    네트워크 및 포트 매핑 (가장 기초적이지만 가장 많이 놓치는 부분)
    이건 질문자님이 가장 염두에 두신 부분이라 가장 먼저 자세히 말씀드릴게요.
    로컬에서 docker run -p 8080:80 이렇게 했을 때, 8080 포트는 내 컴퓨터의 '호스트' 포트이고, 80은 컨테이너 내부 웹 서버가 듣는 포트잖아요.
    문제는 이 호스트 포트 8080을 누가 막고 있느냐예요.
    첫째, 로컬 테스트 환경의 함정: 로컬에서는 보통 아무도 쓰지 않는 임의의 포트(예: 8080, 3000 등)를 잡으면 되니까 되기 쉬워요.
    둘째, 실제 서버 환경의 함정 (가장 중요): 실제 클라우드 서버(AWS EC2, GCP Compute Engine 등)에 배포한다고 가정했을 때, 단순히 docker run 명령만으로는 부족합니다.
    1.
    클라우드 보안 그룹/방화벽 설정: * 이게 90%의 실패 원인입니다.

    • 서버 자체의 운영체제 방화벽(UFW, iptables 등) 설정과, 클라우드 서비스 제공자가 제공하는 외부 네트워크 방화벽(보안 그룹) 두 군데를 모두 열어줘야 합니다.
    • 만약 웹 서비스가 80 포트(HTTP)로 노출되어야 한다면, 인바운드 규칙에 80 포트를 허용해야 합니다.
    • 이걸 안 하면, 컨테이너가 정상적으로 돌아가고 있더라도 외부에서 접속 자체가 차단됩니다.
    • 팁: 운영 환경에서는 보통 80(HTTP)과 443(HTTPS) 포트는 무조건 열어두고, 이 포트들을 리버스 프록시(Nginx/Traefik 등)가 받아서 내부 컨테이너로 트래픽을 넘겨주는 구조를 짜는 게 표준입니다.

    포트 충돌 및 바인딩 문제: * 만약 서버에 이미 Nginx나 다른 서비스가 80 포트를 사용하고 있다면, Docker 컨테이너가 80 포트를 바인딩할 때 충돌이 날 수 있어요.

    • 이럴 때는 포트 매핑을 포기하고, 컨테이너를 내부적으로만 돌린 뒤, 서버 레벨의 리버스 프록시(Nginx)를 호스트 OS 레벨에서 80 포트를 점유하게 하고, Nginx가 컨테이너 내부의 포트로 요청을 전달하는 방식으로 우회하는 게 가장 안정적입니다.
      2.
      환경 변수 및 시크릿 관리 (가장 개발자가 실수하는 지점)
      로컬에서는 .env 파일을 만들어서 데이터베이스 접속 정보나 API 키 같은 걸 돌려서 쓰기만 하면 되잖아요.
      근데 이게 운영 서버로 넘어가면 절대 .env 파일을 그대로 쓰면 안 돼요.
      첫째, 민감 정보의 노출 위험: * .env 파일은 Git에 올라가면 안 되지만, 개발 과정에서 실수로 커밋할 가능성이 높아요.
    • 프로덕션 환경에서는 이 민감한 정보(DB 비밀번호, 외부 API Key 등)를 **운영체제나 컨테이너 오케스트레이터(Docker Compose, Kubernetes)**가 제공하는 Secret Management 기능을 사용해야 합니다.
    • 예를 들어, Docker Compose를 쓰더라도, 비밀번호 같은 건 environment 변수에 직접 넣기보다 별도의 Secret 볼륨으로 마운트하는 방식을 고려해보세요.
      둘째, 환경별 설정 분리: * 개발(Development) 환경에서는 디버그 모드로, 테스트(Staging) 환경에서는 실제와 유사하게, 운영(Production) 환경에서는 가장 최적화된 모드로 돌아가야 해요.
    • 코드 내에서 if (process.env.NODE_ENV === 'production') 같은 방식으로 환경에 따라 다른 로직을 실행하도록 강제하는 게 필수적입니다.
    • 로컬에서 테스트할 때는 이 환경 변수 설정을 잊기 쉬워서, 배포 전에 docker-compose.yml이나 배포 스크립트에서 이 환경 변수 체크 로직을 한 번 더 거쳐줘야 해요.
      3.
      프로세스 관리 및 지속성 (Container Lifecycle)
      도커 컨테이너는 기본적으로 '일회성' 프로세스 개념에 가깝습니다.
      첫째, CMDENTRYPOINT의 이해: * 어떤 프로세스가 메인 프로세스(PID 1)로 실행되어야 하는지 명확히 해야 해요.
    • 만약 웹 서버 외에 백그라운드에서 데이터 처리나 큐(Queue)를 돌려야 하는 작업이 있다면, 단순히 웹 서버만 띄우는 게 아니라, 메인 컨테이너가 이 모든 서비스를 감시하고 재시작하는 역할을 하도록 설정해야 합니다.
    • 이런 경우 supervisord 같은 프로세스 매니저를 컨테이너 내부에 넣거나, Docker Compose의 depends_on과 함께 컨테이너 오케스트레이션 툴을 쓰는 것이 좋습니다.
      둘째, 재시작 정책 (Restart Policy): * 로컬에서 껐다 켜는 건 괜찮지만, 서버는 전원이 꺼지거나 프로세스가 죽으면 알아서 다시 켜져야 하잖아요?
    • docker run--restart unless-stopped 같은 옵션을 붙여서, 컨테이너가 예기치 않게 종료되거나 서버가 재부팅될 때 자동으로 재시작하도록 설정해야 합니다.
      4.
      데이터 영속성 (Volume Management)
      웹 배포만 하는 게 아니라, 만약 사용자 업로드 파일이나 로그 등을 저장해야 한다면 이 부분이 제일 중요합니다.
    • 절대 컨테이너 내부의 파일 시스템에만 의존하면 안 돼요. * 컨테이너는 언제든지 지워지고 재생성될 수 있는 휘발성(Volatile) 공간이에요.
    • 데이터베이스의 데이터나, 사용자가 올린 이미지 파일 같은 것은 반드시 Docker Volume을 사용하거나, AWS S3 같은 외부 객체 스토리지에 저장해야 합니다.
    • 볼륨을 제대로 연결하지 않고 개발했다가 배포하고 컨테이너를 재구축하면, 모든 데이터가 사라지는 걸 경험하게 될 거예요.
      5.
      로깅 및 모니터링 (실무 필수 요소)
      개발자 입장에서는 로그가 잘 찍히는 게 중요하지만, 운영 환경에서는 로그를 **'어떻게 볼 것인가'**가 중요합니다.
    • 컨테이너 로그는 docker logs [container_id]로 볼 수는 있지만, 서비스가 커지면 수많은 컨테이너의 로그가 섞여서 뭐가 문제인지 찾기가 불가능에 가까워져요.
    • **EFK 스택 (Elasticsearch, Fluentd, Kibana)**이나 Loki 같은 중앙 집중식 로깅 시스템을 도입하는 것을 반드시 염두에 두셔야 해요.
    • 이렇게 해야만 "어제 오후 3시 15분쯤, 사용자 A가 결제 버튼을 눌렀을 때, 이 컨테이너의 이 로그 라인에서 에러가 났다"와 같이 추적하는 것이 가능해집니다.
      요약 정리하자면, 로컬 테스트는 '내가 쓰기 좋은 환경'에 최적화되어 있고, 운영 환경은 '안정성', '보안', '외부 접속 가능 여부', '데이터 영속성'이라는 네 가지 제약 조건에 의해 움직인다고 보시면 됩니다.
      가장 먼저 건드릴 부분은 1) 클라우드 보안 그룹 열기2) 환경 변수 관리를 Secret Store로 바꾸는 것 두 가지입니다.
      이것들만 잘 대비하셔도, 로컬에서 되던 게 서버에서 막히는 문제는 80% 이상 해결될 거라고 자신 있게 말씀드릴 수 있어요.
      너무 많은 걸 한 번에 하려고 하지 마시고, 작은 단위로 나누어서, 한 번에 '네트워크'만, 다음 주에 '환경 변수'만 점검해보시는 걸 추천드립니다.
      궁금한 점 있으시면 또 질문해주세요.
      응원하겠습니다.