[IT-정보] 컴포즈 services 질문 정리 및 설정 가이드 – 설정 오류부터 실무 적용까지 한 번에 해결하는 법

services 블록 구성를 설명하는 자주 묻는 질문 정리 대표 이미지

왜 컴포즈 services 설정은 항상 헷갈릴까요

분명히 튜토리얼을 보고 그대로 따라 했는데, docker-compose up 명령어를 입력하자마자 빨간색 에러 메시지가 화면을 가득 채운 적이 있으시죠? 컨테이너는 분명히 실행되었다고 뜨는데, 정작 웹 브라우저에서 접속하려고 하면 연결할 수 없다는 메시지만 돌아오곤 해요. 이런 상황을 마주하면 내가 무엇을 잘못했는지, YAML 파일의 어느 부분이 문제인지 파악하기가 정말 어렵답니다.

도커 컴포즈의 핵심인 services 블록은 단순해 보이지만, 그 안에는 이미지 설정부터 네트워크, 볼륨, 환경 변수까지 아주 복잡한 규칙들이 얽혀 있어요. 특히 들여쓰기 하나만 잘못해도 전체 설정이 엉망이 되어버리는 YAML의 특성 때문에 초보 개발자분들이 가장 많이 좌절하는 구간이기도 해요.

단순히 명령어를 외우는 것보다, 각 설정이 실제로 컨테이너 내부에서 어떤 동작을 유도하는지 이해하는 것이 중요해요. 이 글을 끝까지 읽고 나면, 더 이상 에러 메시지를 보고 당황하지 않고 스스로 문제를 진단하며 완벽한 서비스 환경을 구축할 수 있게 될 거예요.

오늘 함께 살펴볼 내용은 다음과 같아요.

  • services 블록 구성을 위한 필수 사전 지식
  • 설정 항목별 상세 가이드와 실무 적용 시나리오
  • 자주 발생하는 실수와 즉각적인 해결 방법
  • 실제 운영 환경에서 궁금해하는 FAQ 정리

설정 전 반드시 알아야 할 기본 개념

본격적으로 컴포즈 파일을 작성하기 전에, 우리가 다루는 용어들이 정확히 무엇을 의미하는지 짚고 넘어가야 해요. 용어의 개념이 흔들리면 나중에 설정값이 왜 작동하지 않는지 이유를 찾기가 무척 힘들어지거든요.

가장 먼저 서비스(Service)라는 개념을 이해해야 해요. 도커 컴포즈에서 서비스는 단순한 컨테이너 하나를 의미하는 게 아니라, 특정 역할을 수행하는 컨테이너의 정의라고 생각하면 편해요. 예를 들어, 웹 서버 역할을 하는 서비스, 데이터베이스 역할을 하는 서비스가 각각 정의되는 방식이에요.

💡 알아두기
YAML 파일은 들여쓰기가 생명이에요. 탭(Tab) 대신 반드시 공백(Space)을 사용해야 하며, 같은 수준의 설정값은 반드시 세로 줄이 똑같이 맞아야 한답니다.

또한, 서비스를 구성할 때 어떤 옵션을 선택할지 고민되는 순간들이 많을 거예요. 상황에 맞는 최적의 설정을 선택할 수 있도록 아래 비교 표를 참고해 보세요.

구분 항목 선택 옵션 A 선택 옵션 B 추천 상황
이미지 생성 image (기존 이미지) build (직접 빌드) 커스텀 설정 필요 시 build 추천
포트 노출 ports (호스트 연결) expose (내부 연결) 외부 접속 필요 시 ports 사용
환경 변수 environment (직접 입력) env_file (.env 파일) 보안 및 관리 편의를 위해 env_file 추천

이러한 기준들을 머릿속에 넣어두고 설정을 시작하면, 훨씬 더 체계적으로 파일을 작성할 수 있어요. 단순히 따라 적는 것이 아니라, 왜 이 옵션을 사용하는지 스스로 질문하며 작성하는 습관을 가져보세요.

실패 없는 services 블록 구성 단계별 가이드

이제 실무에서 바로 사용할 수 있는 컴포즈 services 설정법을 단계별로 살펴볼게요. 단순히 코드만 나열하는 게 아니라, 각 단계에서 무엇을 놓치기 쉬운지 상세히 설명해 드릴게요.

STEP 1. 서비스의 뿌리, 이미지와 빌드 결정하기

모든 서비스의 시작은 어떤 이미지를 사용할 것인가예요. 여기에는 두 가지 길이 있어요. 도커 허브(Docker Hub) 같은 곳에 이미 만들어진 이미지를 가져다 쓰는 image 방식과, 내가 직접 만든 도커파일(Dockerfile)을 이용해 새 이미지를 만드는 build 방식이에요.

만약 Nginx나 MySQL처럼 이미 검증된 소프트웨어를 그대로 쓴다면 image: nginx:latest와 같이 작성하면 돼요. 하지만 우리 앱만의 특수한 설정이 필요하다면 반드시 build: . 설정을 넣어야 해요. 이때 주의할 점은 build를 사용할 때는 반드시 해당 폴더에 Dockerfile이 존재해야 한다는 사실이에요. 파일이 없으면 컴포즈는 무엇을 빌드해야 할지 몰라 에러를 내뱉게 된답니다.

STEP 2. 외부 세계와 연결하는 포트 매핑

컨테이너가 아무리 잘 돌아가도, 우리 컴퓨터(호스트)에서 접속할 수 없다면 아무 소용이 없겠죠? 이때 사용하는 게 바로 ports 설정이에요. 포트 설정은 반드시 “호스트포트:컨테이너포트” 형식을 따라야 해요.

예를 들어, 컨테이너 내부의 웹 서버가 80번 포트에서 돌고 있고, 내 컴퓨터의 8080번 포트로 접속하고 싶다면 ports: - "8080:80"이라고 적어야 해요. 여기서 많은 분이 하는 실수가 순서를 반대로 적는 거예요. 앞의 숫자가 내 컴퓨터의 번호라는 것을 꼭 기억하세요. 만약 이미 내 컴퓨터에서 8080 포트를 다른 프로그램이 쓰고 있다면 충돌이 발생하므로, 다른 번호를 할당해야 해요.

STEP 3. 보안을 지키는 환경 변수 관리

데이터베이스 비밀번호나 API 키 같은 민감한 정보를 YAML 파일에 직접 적는 것은 매우 위험해요. 파일이 GitHub 같은 곳에 올라가는 순간 보안 사고로 이어지거든요. 그래서 우리는 environment 대신 env_file를 사용하는 것을 강력히 권장해요.

.env 파일을 따로 만들어서 그 안에 값을 저장하고, 컴포즈 파일에서는 파일 이름만 지정해 주는 방식이에요. 이렇게 하면 실제 설정값은 내 컴퓨터에만 안전하게 보관할 수 있고, 설정 파일 자체는 팀원들과 공유하기가 훨씬 수월해진답니다.

STEP 4. 데이터 유실을 막는 볼륨 설정

컨테이너는 기본적으로 ‘휘발성’이에요. 즉, 컨테이너를 삭제하면 그 안에서 작업했던 파일이나 데이터베이스 데이터도 모두 사라져 버려요. 소중한 데이터를 지키려면 반드시 volumes 설정을 통해 호스트 컴퓨터의 폴더와 컨테이너의 폴더를 연결해 줘야 해요.

주로 두 가지 방식을 써요. 내 컴퓨터의 특정 경로를 직접 연결하는 바인드 마운트(Bind Mount)와, 도커가 관리하는 가상 공간을 사용하는 네임드 볼륨(Named Volume)이 있어요. 개발 중에는 코드를 수정하면 바로 반영되도록 바인드 마운트를 쓰고, 실제 운영 단계에서는 성능과 관리가 편한 네임드 볼륨을 쓰는 것이 일반적이에요.

STEP 5. 서비스 간의 순서와 네트워크 지정

웹 서버가 실행될 때 데이터베이스가 아직 준비되지 않았다면 어떻게 될까요? 아마 웹 서버는 DB 연결에 실패하고 즉시 종료될 거예요. 이를 방지하기 위해 depends_on 설정을 사용해요. 이 설정을 통해 서비스 간의 실행 순서를 정해줄 수 있어요.

또한, 여러 서비스가 서로 통신할 수 있도록 하나의 네트워크(Network)로 묶어주는 것도 잊지 마세요. 같은 네트워크에 속한 서비스들은 서로의 서비스 이름을 호스트 이름처럼 사용하여 통신할 수 있어요. 예를 들어, 웹 서비스 설정에서 DB 주소를 db:3306처럼 적기만 해도 도커가 알아서 찾아준답니다. 정말 편리하죠?

💡 알아두기
복잡한 설정을 한 번에 다 하려고 하지 마세요. 하나씩 추가하면서 docker-compose up을 실행해 확인하는 과정이 가장 빠른 학습 방법이에요.

마지막으로, 실제 적용할 수 있는 간단한 시나리오 예시를 보여드릴게요. 웹 서버와 데이터베이스가 함께 움직이는 구조예요.

[예시 시나리오: Web + DB 구성]

services:
  web:
    build: .
    ports:
      - "80:80"
    depends_on:
      - db
    environment:
      - DB_HOST=db
  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

이 구조를 바탕으로 여러분의 프로젝트에 맞게 하나씩 변형해 나가시면 돼요.

자주 하는 실수와 해결법

현장에서 개발자들이 가장 흔하게 저지르는 실수들을 모아봤어요. 에러 메시지가 뜨기 전에 미리 체크해 보세요.

  • YAML 들여쓰기 오류 → 왜 발생하는가: 탭과 공백을 혼용하거나 수준이 맞지 않아서 발생해요. → ✅ 해결법: 에디터(VS Code 등)의 ‘Render Whitespace’ 기능을 켜서 공백 수를 눈으로 확인하세요.
  • 포트 충돌 발생 → 왜 발생하는가: 호스트 포트가 이미 다른 프로세스에 의해 사용 중일 때 발생해요. → ✅ 해결법: ports: - "9000:80"처럼 앞쪽 숫자를 다른 번호로 바꿔보세요.
  • 데이터 유실 문제 → 왜 발생하는가: 볼륨 설정을 하지 않고 컨테이너를 재시작/삭제해서 발생해요. → ✅ 해결법: 중요한 데이터가 담긴 경로는 반드시 volumes 항목을 추가하세요.
  • 환경 변수 미반영 → 왜 발생하는가: .env 파일을 수정했지만 컨테이너가 재빌드되지 않아서 발생해요. → ✅ 해결법:docker-compose up --force-recreate 명령어를 사용하세요.
  • 컨테이너 즉시 종료 → 왜 발생하는가: 실행할 프로세스(Command)가 없거나 에러로 인해 바로 종료된 경우예요. → ✅ 해결법:docker-compose logs 명령어로 에러 내용을 확인하세요.

자주 묻는 질문

Q. docker-compose stop과 down의 차이가 무엇인가요?

stop은 실행 중인 컨테이너를 잠시 멈추는 것이고, 컨테이너와 네트워크 설정은 그대로 남아 있어요. 반면 down은 컨테이너를 완전히 삭제하고 네트워크까지 정리해 버려요. 완전히 깨끗한 상태로 다시 시작하고 싶다면 down을 사용하는 게 좋아요.

Q. 서비스 이름으로 접속이 안 되는데 어떻게 하나요?

두 서비스가 같은 네트워크 안에 있는지 확인해 보세요. 컴포즈 파일에서 별도의 networks를 지정하지 않았다면 기본적으로는 같은 네트워크로 묶이지만, 명시적으로 분리했다면 서로를 찾을 수 없답니다.

Q. 이미지 버전을 latest로 쓰는 게 좋을까요?

학습 단계에서는 편리하지만, 실무에서는 위험할 수 있어요. mysql:latest를 쓰다가 어느 날 갑자기 버전이 올라가서 설정 방식이 바뀌면 전체 시스템이 멈출 수 있거든요. 가급적 mysql:8.0처럼 구체적인 버전을 명시하는 습관을 가지세요.

Q. 설정 파일을 수정했는데 적용이 안 돼요.

도커는 이미 만들어진 이미지를 재사용하려 하기 때문이에요. docker-compose up --build를 입력해서 이미지를 다시 빌드하고 컨테이너를 재생성하도록 강제해 보세요.

완벽한 서비스 운영을 위한 마지막 정리

지금까지 컴포즈 services 블록의 구성부터 실무 활용법까지 꼼꼼하게 살펴봤어요. 처음에는 복잡해 보이지만, 원리만 이해하면 이보다 더 강력하고 편리한 도구도 없답니다. 오늘 배운 내용을 잊지 않도록 핵심만 다시 정리해 드릴게요.

✅ 핵심 요약

  • 서비스 정의는 image 또는 build 중 하나를 반드시 포함해야 해요.
  • 외부 접속을 원한다면 ports: "호스트:컨테이너" 형식을 지켜주세요.
  • 민감한 정보는 .env 파일을 활용해 보안을 지키세요.
  • 데이터를 보존하려면 volumes 설정은 선택이 아닌 필수예요.
  • 서비스 간 순서 제어가 필요할 땐 depends_on을 사용하세요.

이제 이론은 충분해요. 지금 바로 여러분의 터미널을 열고 작은 서비스 하나를 직접 구성해 보세요. 에러를 마주하고 그것을 해결하는 과정이 여러분을 진짜 실력 있는 개발자로 만들어 줄 거예요.

오늘 바로 해볼 일: 기존에 만들었던 docker-compose.yml 파일을 열어 환경 변수가 하드코딩되어 있지는 않은지 확인해 보세요.
이번 주 목표: 서비스 간의 네트워크를 직접 정의하고, 서비스 이름으로 통신하는 환경을 구축해 보세요.

설정 과정에서 해결되지 않는 궁금한 점이 있다면 언제든 댓글로 남겨 주세요. 여러분의 고민을 함께 나누고 정답을 찾아 드릴게요. 함께 성장해 나가요!

관련해서 더 깊이 있는 공부를 원하신다면 도커 컴포즈 기본 개념 완벽 정리 — 개념부터 실무 활용까지 한눈에 보는 가이드 글도 함께 읽어보시는 것을 추천드려요.

댓글 남기기