1. 기본 개념 이해
백엔드 개발에서 발생하는 문제
백엔드 개발자가 만든 프로그램을 다른 사람(팀원이나 서버)에 옮겨서 실행하려고 할 때 '왜 내 컴퓨터에서는 잘 되는데 서버에서는 오류가 나지?' , '버전이 달라서 쿼리가 안돌아간다고?' 와 같이 실행이 안되는 경우가 정말 많다. 나도 처음 UMC 프로젝트를 하는데 Docker를 사용하지 않아, 각자 환경이 달라서 '제 로컬에서는 되는데요...?' 라고 했던 경험이 있다.
→ Docker는 이 문제를 해결하는 도구이다.
Docker의 핵심 아이디어
Docker는 프로그램을 실행하기 위해 필요한 모든 것(코드, 라이브러리, 설정, 운영체제 일부)을 하나의 상자 안에 담는다. 그리고, 그 상자를 우리는 `이미지(Image)`라고 한다. 이미지를 실행하면 `컨테이너(Container)`가 된다.
이미지 = 프로그램 실행을 위한 설계도
컨테이너 = 이미지를 켜서 돌아가는 실제 프로그램
VM(가상머신)과 다른 점 ?
사람들이 종종 Docker를 "가상머신과 비슷하다" 라고 생각하는데, 사실 많이 다르다.
- 가상머신(VM)은 운영체제(OS) 전체를 가상으로 올려 무겁고, 느리고, 리소스를 많이 사용하게 된다.
- 반면 Docker는 프로그램 실행에 꼭 필요한 부분만 격리시켜 가볍고, 빠르고, 리소스를 적게 사용한다.
왜 Docker가 필요할까 ?
환경을 통일할 수 있다. 개발자, 서버, 노트북 어디에서 실행해도 똑같이 동작하도록 할 수 있다. 또한, 배포에 편리하다. `docker run` 한 줄로 서버에 편리하게 배포를 할 수 있다. 또한 MySQL이나 Redis와 같은 프로그램을 매번 설치할 필요 없이 Docker Hub에서 이미지를 받아 바로 실행할 수 있다.
2. Docker의 주요 구성 요소
1) Docker Engine
Docker의 심장 같은 역할을 하며 개발자가 `docker run`, `docker build` 와 같은 명령어를 입력하면, 실제로 컨테이너를 만들고 실행하는 엔진이다. 운영체제 안에서 돌아가는 하나의 프로그램이고, 이미지 → 컨테이너 실행 과정을 담당한다.
2) Docker Image
이미지는 프로그램 실행을 위한 설계도 또는 완성된 요리 레시피라고 생각하면 된다. 안에는 코드, 라이브러리, 환경 설정, 실행 방법까지 다 들어있으며 이미지를 실행하면 컨테이너가 된다.
3) Docker Containers
컨테이너는 이미지를 실제로 켜서 돌아가는 실행 중인 프로그램이다. 컨테이너는 격리된 환경에서 실행되기 때문에 다른 프로그램과 충돌하지 않는다.
4) Docker Hub
이미지 저장소이다. 전 세계 사람들이 만든 이미지를 무료로 공유하는 곳이다. MySQL, Redis, Nginx 등 유명한 소프트웨어는 공식 이미지가 존재하며 그냥 바로 가져다 실행하면 된다.
3. Dockerfile
Dockerfile 이란 ?
내가 만든 프로그램을 Docker 이미지로 만드는 설계도 파일이다. 이미지를 만들기 위해 어떤 운영체제를 사용할지, 어떤 프로그램을 설치할지, 어떤 파일을 복사할지 등의 과정을 순서대로 적어두면 `docker build` 명령어를 통해 새로운 이미지를 만들 수 있다.
예를 들어, 아래와 같이 작성했다고 가정해보자.
FROM openjdk:17
WORKDIR /app
COPY build/libs/kkinikong.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
- `FROM openjdk:17` : 베이스 이미지 지정 (Java 17이 설치된 환경을 가져다 쓰겠다는 의미이다. 공식 Docker Hub에서 제공하는 openjdk:17 이미지를 기반으로 한다는 의미이다.)
- `WORKDIR / app` : 컨테이너 안에서의 작업 디렉토리를 `/app`으로 지정한다.
- `COPY build/libs/kkinicong.jar app.jap` : 내 로컬 프로젝트에 있는 `build/libs'/kkinicong.jar` 파일을 컨테이너 안의 `/app/app.jar` 로 복사한다는 의미이다. 이 jar파일이 바로 Spring Boot 빌드 결과물이다.
- `ENTRYPOINT ["java", "-jar", "app.jar"]` : 컨테이너가 시작되면 무조건 실행할 명령어이다. 여기서는 `java -jar app.jar` 이 실행되고 이는 Spring Boot 서버가 키는 작업이다.
4. Docker Compose
Dockerfile이 하나의 앱을 이미지로 만드는 설명서라면, Docker Compose는 여러 컨테이너를 한꺼번에 실행하고 관리하는 도구이다.
왜 필요할까 ?
보통 일반적으로 백엔드 서비스에서는 Spring Boot 앱, MySQL, Redis, Nginx 이 있고 이거를 하나하나 docker run으로 띄우려면 옵션도 많고 귀찮다. 그래서 Compose 파일에 서비스 전체 구성을 한 번 정의해두고 `docker-compose up -d` 와 같은 명령어 한 줄로 실행할 수 있다.
기본 문법
아래는 `handDoc` 프로젝트를 하면서 사용한 `docker-compose.yml` 이다.
version: "3.8" # compose 파일 버전 (3.8은 가장 많이 사용되는 최신 안정 버전)
services: # 실행할 컨테이너(서비스)들을 정의하는 영역
mongodb: # 서비스 이름 (컨테이너 네트워크에서 이 이름이 호스트명이 됨)
image: mongo:6.0 # 사용할 이미지 (mongo 6.0 공식 이미지)
container_name: handdoc-mongo # 컨테이너 이름
restart: always # 컨테이너가 꺼져도 자동 재시작
ports:
- "37017:27017" # 호스트:컨테이너 포트 매핑 (외부에서 접근 가능)
environment:
MONGO_INITDB_ROOT_USERNAME: ${DOCKER_MONGO_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${DOCKER_MONGO_PASSWORD}
volumes:
- mongo_data:/data/db # 데이터 저장소 (컨테이너 삭제돼도 데이터 유지)
networks:
- handdoc-net # 같은 네트워크에 있는 서비스끼리 통신 가능
mysql:
image: mysql:8.0 # 사용할 이미지 (mysql 8.0 공식 이미지)
container_name: handdoc-mysql
restart: always
ports:
- "53306:3306" # 호스트:컨테이너 포트 매핑
environment:
MYSQL_DATABASE: handdoc
MYSQL_ROOT_PASSWORD: ${DOCKER_DB_PASS}
TZ: Asia/Seoul
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
volumes:
- mysql_data:/var/lib/mysql
networks:
- handdoc-net
volumes: # 데이터 영속성 설정
mongo_data:
mysql_data:
networks: # 네트워크 설정 (서비스끼리 같은 네트워크 안에서 이름으로 통신)
handdoc-net:
해석
- `services` : 컨테이너 단위를 정의하는 블록이다. service: 아래에 적힌 것들이 각 각 하나의 컨테이너가 된다.
- `ports` : 호스트의 포트와 컨테이너 내부 포트를 연결하는 설정이다. `"호스트포트:컨테이너포트"` 형식이다.
- `volumes` : 컨테이너 안의 데이터를 호스트 저장소에 영구 저장하는 기능이다. 컨테이너를 삭제해도 데이터는 날아가지 않는다.
- `networks` : 컨테이너들끼리 서로 통신할 수 있도록 묶어주는 가상 네트워크
실행 방법
# 컨테이너 전체 실행
docker-compose up -d
'DevOps' 카테고리의 다른 글
| Docker로 MySQL 환경 구성해서 팀원들에게 제공하기 (0) | 2025.08.05 |
|---|
