• 도커로 블로그 배포 시 DB 연결 막히는 거 있나요?

    요즘 다들 도커 기반으로 개인 웹 서비스를 띄우는 게 대세라길래, 저도 제 블로그를 컨테이너 환경에 올려보려고 만져보고 있습니다.
    옛날엔 그냥 VM 하나 띄우고 그 안에 모든 걸 설치하는 게 국룰이었는데, 컨테이너 구조가 워낙 깔끔해서 좋긴 해요.

    근데 막상 블로그 컨테이너(웹 앱)랑 데이터베이스 컨테이너(DB)를 분리해서 띄우려고 하니까, 로컬 환경에서 컨테이너들끼리 서로 '얘기'하게 만드는 게 꽤 까다롭더라고요.
    특히 DB 연결 문자열 같은 거 설정할 때, 호스트 이름이나 포트 매핑 같은 부분에서 자꾸 헷갈리는 지점들이 생겨요.

    혹시 비슷한 경험 하신 분들 계신가요?
    도커 컴포즈로 구성할 때, 컨테이너 간의 네트워크 네임스페이스나 서비스 디스커버리 측면에서 '이건 이렇게 잡는 게 맞는지' 헷갈리는 부분이 있다면 조언 좀 부탁드립니다.
    진짜 맥락 이해가 필요한 부분이라 막히네요.

  • 도커로 블로그 배포 시 DB 연결 문제, 정말 많은 분들이 처음 겪는 벽 같은 부분이에요.
    저도 처음 컨테이너 환경으로 웹 서비스 옮기려고 할 때, 이 '컨테이너들끼리 대화 시키기' 부분이 제일 헷갈렸던 기억이 납니다.
    VM에 다 때려박는 거랑 컨테이너로 쪼개는 거랑 체감하는 난이도 차이가 꽤 크거든요.
    일단 질문자님이 '도커 컴포즈'를 사용하고 계신다고 하니, 가장 표준적이고 추천하는 방법으로 답변을 드릴게요.
    결론부터 말씀드리자면, 대부분의 경우 별도의 복잡한 설정 없이 도커 컴포즈의 내부 네트워크 기능을 활용하면 '서비스 디스커버리' 문제는 자동으로 해결됩니다. 다만, 이 자동 해결된다는 걸 믿고 그냥 포트만 열어두면 안 되고, 몇 가지 개념을 확실히 잡으셔야 합니다.
    --- ### 1.
    핵심 개념 정리: 왜 헷갈리는가?
    (호스트 vs 서비스명) 이게 가장 중요한 포인트예요.
    VM 환경에서는 DB 서버가 물리적으로 혹은 가상적으로 하나의 고정된 IP 주소(예: 192.168.1.100)를 가지잖아요.
    그런데 도커 컴포즈 환경에서는 컨테이너들이 마치 독립된 작은 컴퓨터들처럼 네트워크 상에 존재합니다.
    만약 웹 앱 컨테이너에서 DB 컨테이너로 접속할 때, DB 컨테이너의 실제 IP를 하드코딩하려고 하면?

    • 문제 발생: 컨테이너가 재시작되거나, 다른 컨테이너가 올라오면 내부 IP 주소는 언제든지 바뀔 수 있습니다.
    • 결과: 연결 문자열에 잘못된 IP를 넣으면, 서비스는 아예 시작조차 못 하거나, 실행되다가 갑자기 DB 연결이 끊기는 현상이 발생합니다.
      💡 해결책: 컨테이너 이름(서비스명)을 호스트 이름으로 사용하세요.
      도커 컴포즈는 기본적으로 **브릿지 네트워크(Bridge Network)**를 만들어주고, 이 네트워크 내부에서는 서비스 이름이 DNS 역할을 대신 해주도록 설계되어 있습니다.
      예를 들어, docker-compose.yml 파일에 DB 서비스를 db라고 이름을 지정했다면, 웹 앱 컨테이너에서는 DB에 접속할 때 IP 주소 대신 db 라는 호스트 이름만 써주면 됩니다.
      yaml # 웹 앱 컨테이너에서 DB 접속 시 사용해야 할 호스트명 DB_HOST=db DB_PORT=5432 # 예시 --- ### 2.
      docker-compose.yml 설정 가이드 (실전 예시) DB 연결 문제를 피하려면, 네트워크 정의를 명확하게 하는 것이 핵심입니다.
      A.
      기본 구조 잡기:
      yaml version: '3.8' services: web: # 블로그 웹 앱 서비스 build: ./web # 웹 앱이 있는 폴더 경로 ports: - "80:80" # 외부 포트 80 -> 컨테이너 포트 80 environment: # 여기에 DB 연결 정보를 환경변수로 넘겨주는 것이 가장 깔끔합니다. DATABASE_URL: postgres://user:password@db:5432/mydatabase depends_on: - db # web이 시작되기 전에 db가 먼저 올라오도록 의존성 설정 networks: - app-network db: # 데이터베이스 서비스 (PostgreSQL 예시) image: postgres:latest environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: mydatabase volumes: - db_data:/var/lib/postgresql/data # 데이터 영속성을 위해 볼륨 연결 필수 networks: - app-network restart: always # 컨테이너가 멈춰도 자동으로 재시작하게 설정 (권장) networks: app-network: # 사용자 정의 네트워크 이름 지정 driver: bridge volumes: db_data: # 데이터 저장을 위한 볼륨 B.
      핵심 설명 및 체크리스트:
      1.
      networks: app-network: 모든 서비스를 이 사용자 정의 네트워크에 묶어주세요.
      이렇게 하면 이 네트워크 내의 모든 서비스는 서로를 서비스 이름으로 찾을 수 있게 됩니다.

    environment 변수 처리 (가장 중요!): 웹 앱의 환경 변수(DATABASE_URL 등)를 설정할 때, 절대 localhost127.0.0.1을 쓰지 마세요. 무조건 DB 서비스의 이름(db)을 사용해야 합니다.

    • user:password@db:5432/mydatabase (여기서 db가 호스트입니다.) 3.
      depends_on vs healthcheck: depends_on은 "컨테이너가 시작되는 순서"만 보장해줍니다.
      DB가 "실제로 접속할 준비가 되었는지"는 보장해주지 않아요.
    • 실무 팁: 웹 앱이 시작되자마자 DB 연결을 시도하다가 실패하는 경우가 많습니다.
      만약 연결 시도 로직을 직접 구현할 수 있다면, 재시도(Retry) 로직을 웹 앱 코드 레벨에 심어주는 게 가장 안정적입니다.
      (예: 5초 간격으로 5번 시도 후 실패 시 에러 처리) 4.
      볼륨 (volumes): DB 데이터는 컨테이너가 삭제되면 사라집니다.
      반드시 volumes를 설정해서 데이터를 호스트 시스템이나 볼륨에 영구 저장해주셔야 합니다.
      --- ### 3.
      흔하게 하는 실수 3가지와 해결책 실수 1: 포트 매핑과 내부 통신을 혼동하는 경우 * 오해: "내가 외부에서 웹 앱에 80 포트로 접속하니까, DB도 80 포트로 열어줘야 하는 거 아닐까?" * 진실: ports: 섹션은 오직 외부(호스트 머신)와 컨테이너 간의 통신에만 관여합니다.
      컨테이너 내부 서비스 간의 통신은 포트 매핑과는 무관하게 내부 네트워크 이름으로 통신합니다.
      DB는 외부 포트 매핑을 할 필요가 없습니다.
      실수 2: DB 연결 문자열에서 로컬호스트를 고집하는 경우 * 오해: "내 노트북에서 테스트했으니까, DB 주소도 localhost로 해야지." * 진실: 컨테이너 환경에서는 localhost웹 앱 컨테이너 자신을 가리킵니다.
      DB 컨테이너가 아니라 웹 앱 컨테이너가 자기 자신에게 연결하라는 의미가 되어 DB에 접속할 수 없습니다.
      (다시 한번, db 서비스를 쓰세요.) 실수 3: 네트워크를 아예 안 지정하는 경우 * 오해: docker-compose.yml에 네트워크 정의를 아예 빼먹거나, 서비스별로 포트를 열어만 두고 네트워크 정의를 누락하는 경우.
    • 결과: 서비스들이 서로를 찾지 못하거나, 예상치 못한 네트워크 격리가 발생할 수 있습니다.
      항상 networks: 섹션을 명시적으로 정의하고 사용하는 것이 좋습니다.
      --- ### 📝 요약 정리 (Cheat Sheet) | 항목 | VM 환경 | 도커 컴포즈 (컨테이너) | 주의사항 | | :--- | :--- | :--- | :--- | | DB 접속 호스트명 | 고정 IP 주소 (예: 192.x.x.x) | 서비스 이름 (예: db) | 절대 localhost 사용 금지.
      | | 포트 매핑 (ports:) | 거의 사용 안 함 (전체 서버에 적용) | 외부 접근용으로만 사용.
      | 컨테이너 내부 통신에는 영향 없음.
      | | 데이터 영속성 | OS 레벨의 디스크 할당 | 볼륨 (volumes:) 사용 필수.
      | 볼륨 없으면 컨테이너 삭제 시 데이터 소멸.
      | | 연결 안정성 확보 | OS 재부팅 시 수동 점검 | 재시도 로직 (코드 레벨) + depends_on (구조 레벨) | 연결 실패 시 재시도하는 로직이 제일 중요합니다.
      | 도커 환경에 익숙해지려면, 실제로 작은 프로젝트(예: 간단한 ToDo 리스트)를 DB와 연동하는 과정을 최소 3번 이상 반복해보시는 걸 추천드립니다.
      처음에는 '왜 이렇게 복잡하지?' 싶을 수 있지만, 일단 서비스 이름 기반으로 연결하는 개념이 머리에 박히면, 이후의 배포 과정은 훨씬 수월해지실 거예요.
      혹시 사용하시는 블로그 프레임워크(예: Django, Laravel, Node.js 등)가 있다면, 해당 프레임워크별로 환경변수를 로드하는 더 구체적인 팁도 드릴 수 있습니다!
      일단 이 내용들이 헷갈리시는 부분 정리하는 데 도움이 되었으면 좋겠습니다.
      화이팅하세요!