CS: Docker 이해하기

hyeppy·2025년 8월 10일

CS

목록 보기
2/11
post-thumbnail

개발 환경 통합을 위한 솔루션, Docker


협업을 진행하는 개발자라면 한 번은 겪는 문제

보통의 개발 흐름?
개발용 컴퓨터에서 코드를 작성하고 실행 → 서버용 컴퓨터에서 빌드와 배포
하지만 이 과정이 항상 순탄한 것은 아님.

환경 충돌 문제
한 컴퓨터에서 여러 프로젝트를 동시에 진행하게 되었을 때, 각 프로젝트가 서로 다른 버전의 프레임워크를 사용한다면 충돌이나 오류가 발생할 가능성이 높음.

A 프로젝트: Node.js 14, Python 3.8
B 프로젝트: Node.js 18, Python 3.10

환경 일치성 문제
"내 컴퓨터에서는 잘 됐는데..." 여러 개발자가 함께하는 복잡한 서비스일수록 서버 환경을 개발 환경과 동일하게 맞추는 것이 중요함. 하지만 프로젝트가 크고 복잡할수록 이 작업은 쉽지 않으며, 작은 설정 하나만 잘못되어도 서버가 제대로 동작하지 않는 오류가 발생할 가능성이 높음.

기존 해결 방법과 한계

가상 환경 (Virtual Machine)
내 OS 안에 또 다른 OS를 설치해, 각 프로젝트를 서로 다른 환경에서 실행하는 방식으로, 환경을 완전히 분리해 충돌을 발생할 가능성이 줄어든다는 장점이 있음. 하지만 이 방법의 경우 각각의 가상 환경이 컴퓨터 자원을 나누어 사용하기 때문에 리소스 낭비가 심하고, 시작 시간도 오래 걸릴뿐더러, 운영체제까지 모두 포함하므로 용량이 크고 무거움.


Docker의 등장 - 컨테이너 기술

Docker(도커)는 이러한 문제들을 컨테이너 기술로 해결

Docker 컨테이너의 장점

  1. 효율적인 자원 사용
    : 컨테이너들은 호스트 OS의 커널을 공유하여, 각자 필요한 만큼의 공간만 차지함.
  2. 완벽한 격리
    : 각각의 작업 공간이 확실히 분리되어 서로 영향을 주지 않음.
  3. 일관성 보장
    : 컨테이너의 설계도(dockerfile 등)에 모든 환경이 명시되어, 누구나 동일한 환경에서 서비스를 실행할 수 있음.
  4. 확장성
    : 한 컨테이너 안에 여러 서비스를 넣거나, 여러 컨테이너를 연결해 복합 서비스를 구성할 수 있음.

Docker의 핵심 개념

1. Docker 이미지 (Image)

Docker 이미지는 특정 실행 환경을 그대로 저장해 둔 설계도이자 완제품. 마치 급속된 완제품을 클라우드에 보관해 두는 것과 같음

  • 프로젝트 실행에 필요한 프레임워크나 라이브러리가 내 컴퓨터에 없어도 Docker는 Docker Hub에서 필요한 이미지를 다운로드해 사용
  • 이미지는 컨테이너를 생성하는 템플릿 역할로,
    하나의 이미지로 여러 개의 컨테이너를 만들 수 있음

2. Docker 컨테이너 (Container)

이미지를 실행한 결과물(인스턴스)가 컨테이너로, 실제로 애플리케이션이 동작하는 격리된 공간과 같음.
예를 들어, 아래는 Ubuntu 이미지를 기반으로 한 컨테이너를 실행하는 코드

docker run -it ubuntu:latest /bin/bash
# 여기서 `-it` 옵션은
# i: 컨테이너와 상호작용 가능 (Interactive)
# t: 터미널 환경 제공 (TTY)

즉, 위 명령을 실행하면 Ubuntu라는 작은 가상 환경 속에 직접 들어가 터미널을 사용할 수 있음. 이 환경 안에서는 다른 컨테이너나 호스트 OS에 영향을 주지 않고 독립적으로 작업 가능.

3. Dockerfile

Dockerfile은 나만의 이미지를 만들기 위한 미시적 설계도.
보통 공식 이미지(node.js, python 등)를 기반으로 시작해, 여기에 프로젝트에 필요한 라이브러리, 설정, 파일 등을 추가해 커스텀 이미지를 만들 수 있음.

# Node.js 프로젝트용 Dockerfile
# 1. Node.js 공식 이미지를 기반으로 시작
FROM node:20-alpine

# 2. 컨테이너 안에서 작업할 디렉터리 지정
WORKDIR /app

# 3. package.json과 package-lock.json만 먼저 복사
COPY package*.json ./

# 4. 의존성 설치
RUN npm install

# 5. 나머지 프로젝트 파일 복사
COPY . .

# 6. 앱이 사용할 포트 개방
EXPOSE 3000

# 7. 컨테이너 시작 시 실행할 명령
CMD ["npm", "start"]

- `FROM`: 기반이 되는 이미지 지정
- `WORKDIR`: 컨테이너 내부 작업 디렉터리
- `COPY`/`RUN`: 파일 복사, 명령 실행
- `EXPOSE`: 외부에서 접근할 포트
- `CMD`: 컨테이너 실행 시 기본으로 수행할 명령

이렇게 만든 Dockerfile로 이미지를 빌드하면, 이미지를 갖고 있는 누구나 동일 환경에서 프로젝트를 실행할 수 있음.

5. Docker Compose

여러 컨테이너로 구성된 애플리케이션을 한 번에 실행하고 관리할 수 있는 거시적 설계도. 예를 들어, 웹 서비스 하나를 운영하려면

  • 프론트엔드 컨테이너
  • 백엔드 컨테이너
  • 데이터베이스 컨테이너

이 세 가지를 각각 실행하고 서로 연결하는 것은 꽤 복잡함.
Docker Compose는 이 모든 설정을 하나의 설정 파일로 정의해 한 명령어로 실행 및 종료할 수 있게 해 줌.

# docker-compose.yml
version: "3.9"

services:
  db:
    image: mysql:8.0
    container_name: my-db
    environment:
      MYSQL_ROOT_PASSWORD: xxxxxx
      MYSQL_DATABASE: xxxxxx
      MYSQL_USER: xxxxxx
      MYSQL_PASSWORD: xxxxxx
    ports:
      - "3306:3306"
    volumes:
      - dbdata:/var/lib/mysql
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -prootpass || exit 1"]
      interval: 5s
      timeout: 3s
      retries: 10
    restart: unless-stopped

  web:
    build:
      context: ./web
      dockerfile: Dockerfile
    container_name: my-web
    environment:
      NODE_ENV: production
      DB_HOST: db
      DB_USER: appuser
      DB_PASSWORD: apppass
      DB_NAME: myapp
      DB_PORT: "3306"
    ports:
      - "3000:3000"
    depends_on:
      - db
    restart: unless-stopped

volumes:
  dbdata:

dockerfile, Docker compose 보안에 민감한 정보는 따로 관리되는 파일에 넣거나 하는 식으로 안전하게 관리하는 것이 중요

Docker Volume과 COPY 차이

  • COPY
    - 이미지 빌드 시점에, 호스트 파일을 이미지 내부로 복사
    • 복사된 내용은 변하지 않는 정적 데이터
    • 프로젝트 소스, 설정 파일 등을 이미지에 포함
  • Volume
    - 컨테이너 실행 시점에 호스트와 컨테이너의 폴더를 연결
    - 연결된 폴더는 실시간으로 동기화, 빌드할 필요 X
    - DB 데이터, 개발 중인 소스 코드가 이에 해당
    => 개발 단계에서는 Volume, 배포 단계에서는 COPY를 주로 사용

Docker의 동작 원리

어떤 OS(Windows, macOS, Linux)에서 실행하더라도 Docker 컨테이너는 리눅스 환경에서 동작. Docker 엔진이 바로 컨테이너를 실행하는 Linux 외에 Windows나 macOS에서는 내부적으로 작은 가상머신을 띄워 그 안에서 컨테이너를 실행함. 이렇게 하면 운영체제가 달라져도 동일한 리눅스 커널을 사용하므로, 컨테이너 내부 환경이 항상 동일함.

실제 개발 워크플로우

  1. 개발
    : 로컬에서 Docker로 개발 환경 구성
  2. 테스트
    : 동일한 컨테이너 환경에서 테스트 수행, 환경 차이로 인한 오류 최소화
  3. 배포
    : 같은 이미지를 서버에서 실행 → 개발·테스트·운영 환경이 100% 일치
  4. 스케일링
    : 필요에 따라 컨테이너 인스턴스 증가시켜 부하 분산

자주 사용하는 Docker 명령어

이미지 관련 명령어

# 이미지 검색
docker search ubuntu

# 이미지 다운로드
docker pull ubuntu:latest

# 로컬 이미지 목록 확인
docker images

# 이미지 삭제
docker rmi ubuntu:latest

컨테이너 관련 명령어

# 컨테이너 실행 (새로 생성)
docker run -it --name my-container ubuntu /bin/bash

# 백그라운드에서 컨테이너 실행
docker run -d --name web-server nginx

# 실행 중인 컨테이너 목록
docker ps

# 모든 컨테이너 목록 (정지 포함)
docker ps -a

# 컨테이너 시작 / 정지 / 재시작
docker start my-container
docker stop my-container
docker restart my-container

# 실행 중인 컨테이너에 접속
docker exec -it my-container /bin/bash

# 컨테이너 로그 확인
docker logs my-container

# 컨테이너 삭제
docker rm my-container

빌드 및 관리 명령어

# Dockerfile로 이미지 빌드
docker build -t my-app:latest .

# 컨테이너와 호스트 간 파일 복사
docker cp my-file.txt my-container:/app/

# Docker 시스템 정보
docker info

# 사용하지 않는 리소스 정리
docker system prune

# Docker Compose 실행
docker compose up -d

# Docker Compose 정지
docker compose down

자주 사용하는 옵션

-d (detach): 백그라운드에서 실행

-p (port): 포트 포워딩
예: -p 8080:80 → 호스트 8080 → 컨테이너 80

-v (volume): 볼륨 마운트
예: -v ./data:/app/data

--name: 컨테이너에 이름 지정

--rm: 컨테이너 종료 시 자동 삭제

Docker는 복잡한 환경 설정 문제를 해결하고,
팀원들이 같은 환경에서 작업할 수 있게 하며,
배포와 확장 과정을 훨씬 단순하고 빠르게 만들어 줍니다.

가장 쉽게 배우는 도커

profile
Backend

0개의 댓글