서론: 왜 Docker인가?

홈서버를 운영하다 보면 이것저것 설치하고 싶은 프로그램이 많아집니다. 미디어 서버, 파일 동기화, 광고 차단, 비밀번호 관리자... 하지만 프로그램을 직접 설치하면 여러 가지 문제가 생깁니다. 의존성 충돌, 업데이트 시 설정 날아감, 다른 서버로 이전할 때 처음부터 다시 설정해야 하는 번거로움 등이 대표적이죠.

Docker는 이런 문제를 깔끔하게 해결해줍니다. 컨테이너라는 격리된 환경에서 프로그램을 실행하기 때문에 서로 영향을 주지 않고, 설정 파일 몇 줄만으로 복잡한 서비스를 배포할 수 있습니다. 이번 편에서는 Docker의 기본 개념부터 실제로 유용한 서비스들을 배포하는 방법까지 상세히 알아보겠습니다.

1. Docker란 무엇인가?

1.1 컨테이너의 개념

컨테이너는 애플리케이션과 그 실행에 필요한 모든 것(라이브러리, 설정 파일 등)을 하나의 패키지로 묶은 것입니다. 가상 머신과 비슷해 보이지만 훨씬 가볍고 빠릅니다.

  • 가상 머신(VM): 전체 운영체제를 포함하므로 무겁고 부팅에 시간이 걸립니다.
  • 컨테이너: 호스트 OS의 커널을 공유하므로 가볍고 거의 즉시 시작됩니다.

쉽게 비유하자면, 가상 머신은 집 전체를 통째로 옮기는 것이고, 컨테이너는 필요한 가구만 컨테이너 박스에 담아 옮기는 것입니다.

1.2 Docker의 주요 개념

  • 이미지(Image): 컨테이너를 만들기 위한 템플릿입니다. 프로그램과 필요한 환경이 모두 포함되어 있습니다.
  • 컨테이너(Container): 이미지를 실행한 인스턴스입니다. 실제로 돌아가는 프로그램이라고 보면 됩니다.
  • 레지스트리(Registry): 이미지를 저장하고 배포하는 저장소입니다. Docker Hub가 대표적입니다.
  • 볼륨(Volume): 컨테이너의 데이터를 영구적으로 저장하는 공간입니다.

1.3 Docker의 장점

  • 격리성: 각 컨테이너는 독립된 환경에서 실행되어 서로 영향을 주지 않습니다.
  • 이식성: 한 번 만든 이미지는 어디서든 동일하게 실행됩니다.
  • 재현성: 설정 파일만 있으면 언제든 같은 환경을 재현할 수 있습니다.
  • 효율성: 가상 머신보다 훨씬 적은 리소스를 사용합니다.
  • 생태계: 수많은 이미지가 Docker Hub에 공개되어 있어 바로 사용 가능합니다.

2. Docker 설치

2.1 Ubuntu/Debian에서 설치

공식 저장소를 사용하여 최신 버전의 Docker를 설치합니다.

# 기존 패키지 제거
sudo apt remove docker docker-engine docker.io containerd runc

# 필요 패키지 설치
sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release

# Docker GPG 키 추가
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Docker 저장소 추가
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Docker 설치
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 서비스 시작 및 부팅 시 자동 시작
sudo systemctl start docker
sudo systemctl enable docker

2.2 현재 사용자를 docker 그룹에 추가

매번 sudo를 입력하지 않으려면 현재 사용자를 docker 그룹에 추가합니다.

sudo usermod -aG docker $USER
# 로그아웃 후 다시 로그인하면 적용됩니다

2.3 설치 확인

# Docker 버전 확인
docker --version

# Docker Compose 버전 확인
docker compose version

# 테스트 컨테이너 실행
docker run hello-world

3. Docker 기본 명령어

3.1 이미지 관련 명령어

# 이미지 다운로드
docker pull nginx

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

# 이미지 삭제
docker rmi nginx

# 사용하지 않는 이미지 정리
docker image prune

3.2 컨테이너 실행 (docker run)

docker run은 가장 많이 사용하는 명령어입니다. 주요 옵션을 알아봅시다.

# 기본 실행
docker run nginx

# 백그라운드 실행 (-d)
docker run -d nginx

# 컨테이너 이름 지정 (--name)
docker run -d --name my-nginx nginx

# 포트 매핑 (-p 호스트포트:컨테이너포트)
docker run -d -p 8080:80 nginx

# 볼륨 마운트 (-v 호스트경로:컨테이너경로)
docker run -d -v /my/content:/usr/share/nginx/html nginx

# 환경 변수 설정 (-e)
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql

# 재시작 정책 설정 (--restart)
docker run -d --restart unless-stopped nginx

# 여러 옵션 조합
docker run -d \
  --name webserver \
  -p 80:80 \
  -v /var/www:/usr/share/nginx/html:ro \
  --restart unless-stopped \
  nginx

3.3 컨테이너 관리 (docker ps)

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

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

# 컨테이너 중지
docker stop my-nginx

# 컨테이너 시작
docker start my-nginx

# 컨테이너 재시작
docker restart my-nginx

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

# 실행 중인 컨테이너 강제 삭제
docker rm -f my-nginx

# 중지된 컨테이너 모두 삭제
docker container prune

3.4 로그 확인 (docker logs)

# 로그 보기
docker logs my-nginx

# 실시간 로그 보기 (-f: follow)
docker logs -f my-nginx

# 마지막 100줄만 보기
docker logs --tail 100 my-nginx

# 타임스탬프 포함
docker logs -t my-nginx

3.5 컨테이너 내부 접근 (docker exec)

# 컨테이너 내부에서 명령 실행
docker exec my-nginx ls /etc/nginx

# 컨테이너 쉘 접속 (-it: 대화형 터미널)
docker exec -it my-nginx /bin/bash

# 쉘이 bash가 아닌 경우 (Alpine 등)
docker exec -it my-nginx /bin/sh

4. Docker Compose 활용

4.1 Docker Compose란?

Docker Compose는 여러 컨테이너를 정의하고 관리하기 위한 도구입니다. YAML 파일에 서비스 구성을 정의하면 한 번의 명령으로 모든 서비스를 시작하거나 중지할 수 있습니다.

4.2 docker-compose.yml 기본 구조

version: "3.8"

services:
  web:
    image: nginx:latest
    container_name: my-web
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped

  db:
    image: mariadb:latest
    container_name: my-db
    environment:
      - MYSQL_ROOT_PASSWORD=secretpassword
      - MYSQL_DATABASE=myapp
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  db_data:

4.3 Docker Compose 명령어

# 서비스 시작 (백그라운드)
docker compose up -d

# 서비스 중지 및 컨테이너 삭제
docker compose down

# 서비스 중지 (컨테이너 유지)
docker compose stop

# 서비스 재시작
docker compose restart

# 로그 보기
docker compose logs -f

# 특정 서비스만 재시작
docker compose restart web

# 이미지 업데이트 후 재배포
docker compose pull
docker compose up -d

4.4 실전 예제: WordPress + MariaDB

version: "3.8"

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress
    ports:
      - "8080:80"
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=wordpress_password
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: mariadb:latest
    container_name: wordpress-db
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=wordpress_password
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  wordpress_data:
  db_data:

5. Portainer로 웹 GUI 관리

5.1 Portainer 소개

Portainer는 Docker를 웹 브라우저에서 관리할 수 있게 해주는 도구입니다. 컨테이너 시작/중지, 로그 확인, 이미지 관리 등 대부분의 작업을 GUI로 할 수 있어서 터미널에 익숙하지 않은 분들께 특히 유용합니다.

5.2 Portainer 설치

# 볼륨 생성
docker volume create portainer_data

# Portainer 실행
docker run -d \
  -p 9443:9443 \
  --name portainer \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

5.3 Portainer 초기 설정

  1. 웹 브라우저에서 https://서버IP:9443 접속
  2. 관리자 계정 생성 (비밀번호 12자 이상)
  3. "Get Started" 또는 "Local" 환경 선택
  4. 대시보드에서 컨테이너, 이미지, 볼륨 등 관리

5.4 Portainer 주요 기능

  • 컨테이너 관리: 시작, 중지, 재시작, 삭제, 로그 확인
  • 스택(Stack): docker-compose 파일을 웹에서 관리
  • 이미지 관리: 이미지 다운로드, 삭제, 빌드
  • 볼륨 관리: 볼륨 생성, 삭제, 백업
  • 네트워크 관리: Docker 네트워크 설정
  • 템플릿: 미리 정의된 앱 템플릿으로 빠른 배포

6. 유용한 Docker 앱들

6.1 Pi-hole: 네트워크 광고 차단

Pi-hole은 DNS 레벨에서 광고를 차단하는 서비스입니다. 한 번 설정하면 네트워크에 연결된 모든 기기에서 광고가 차단됩니다.

version: "3.8"

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      TZ: 'Asia/Seoul'
      WEBPASSWORD: 'your_password_here'
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    restart: unless-stopped

설치 후 공유기의 DNS 서버를 Pi-hole 서버 IP로 변경하면 전체 네트워크에 적용됩니다.

6.2 Nginx Proxy Manager: 리버스 프록시

Nginx Proxy Manager는 여러 서비스에 도메인을 연결하고 SSL 인증서를 자동으로 관리해주는 도구입니다.

version: "3.8"

services:
  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    restart: unless-stopped

초기 로그인 정보: Email admin@example.com, Password changeme

6.3 Homepage: 홈서버 대시보드

Homepage는 홈서버의 모든 서비스를 한눈에 볼 수 있는 대시보드입니다. 깔끔한 디자인과 다양한 서비스 위젯을 제공합니다.

version: "3.8"

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    ports:
      - 3000:3000
    volumes:
      - ./config:/app/config
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped

6.4 Uptime Kuma: 서비스 모니터링

Uptime Kuma는 웹사이트, 서비스, 포트 등의 가동 상태를 모니터링하고 알림을 보내주는 도구입니다.

version: "3.8"

services:
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    container_name: uptime-kuma
    ports:
      - "3001:3001"
    volumes:
      - ./data:/app/data
    restart: unless-stopped

다운타임 발생 시 텔레그램, 디스코드, 이메일 등으로 알림을 받을 수 있습니다.

6.5 Vaultwarden: 비밀번호 관리자

Vaultwarden은 Bitwarden 호환 비밀번호 관리자입니다. 공식 Bitwarden 서버보다 훨씬 가볍고 셀프 호스팅에 최적화되어 있습니다.

version: "3.8"

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    ports:
      - "8000:80"
    environment:
      - SIGNUPS_ALLOWED=true
      - ADMIN_TOKEN=your_random_admin_token
    volumes:
      - ./data:/data
    restart: unless-stopped

HTTPS 없이는 보안상 위험하므로 반드시 리버스 프록시를 통해 SSL을 적용하세요.

7. 데이터 백업과 볼륨 관리

7.1 볼륨의 종류

  • Named Volume: Docker가 관리하는 볼륨. docker volume create로 생성
  • Bind Mount: 호스트의 특정 경로를 컨테이너에 마운트

일반적으로 설정 파일이나 백업이 필요한 데이터는 Bind Mount를 사용하는 것이 관리하기 편합니다.

7.2 볼륨 관리 명령어

# 볼륨 목록 확인
docker volume ls

# 볼륨 상세 정보
docker volume inspect volume_name

# 볼륨 삭제
docker volume rm volume_name

# 사용하지 않는 볼륨 정리
docker volume prune

7.3 데이터 백업 전략

방법 1: Bind Mount 디렉토리 직접 백업

# 서비스 중지 후 백업
docker compose stop
tar -czvf backup_$(date +%Y%m%d).tar.gz ./data
docker compose start

방법 2: 실행 중인 컨테이너에서 백업

# MySQL/MariaDB 백업
docker exec my-db mysqldump -u root -p'password' --all-databases > backup.sql

# PostgreSQL 백업
docker exec my-postgres pg_dumpall -U postgres > backup.sql

방법 3: Named Volume 백업

# 임시 컨테이너로 볼륨 내용 백업
docker run --rm \
  -v volume_name:/source:ro \
  -v $(pwd):/backup \
  alpine tar -czvf /backup/volume_backup.tar.gz -C /source .

7.4 자동 백업 스크립트

#!/bin/bash
# backup.sh

BACKUP_DIR="/backup/docker"
DATE=$(date +%Y%m%d_%H%M%S)

# 백업 디렉토리 생성
mkdir -p $BACKUP_DIR

# 각 서비스 데이터 백업
for dir in /opt/docker/*/; do
    service=$(basename $dir)
    tar -czvf "$BACKUP_DIR/${service}_${DATE}.tar.gz" -C $dir .
done

# 30일 이상된 백업 삭제
find $BACKUP_DIR -type f -mtime +30 -delete

echo "Backup completed: $DATE"

crontab에 등록하여 자동 실행할 수 있습니다.

# 매일 새벽 3시 백업
0 3 * * * /opt/scripts/backup.sh >> /var/log/docker-backup.log 2>&1

8. Docker 문제 해결

8.1 자주 발생하는 문제들

포트가 이미 사용 중일 때

# 포트 사용 중인 프로세스 확인
sudo lsof -i :80
# 또는 docker-compose.yml에서 다른 포트로 변경

권한 문제로 볼륨 접근이 안 될 때

# 호스트 디렉토리 권한 확인
ls -la ./data
# 권한 변경
sudo chown -R 1000:1000 ./data

컨테이너가 계속 재시작될 때

# 로그 확인
docker logs container_name
# 재시작 정책 변경
docker update --restart no container_name

8.2 디스크 공간 정리

# Docker가 사용하는 디스크 용량 확인
docker system df

# 사용하지 않는 모든 것 정리 (주의!)
docker system prune -a

# 볼륨 제외하고 정리
docker system prune

마무리

이번 편에서는 Docker의 기본 개념부터 실제 활용까지 폭넓게 다뤘습니다. Docker를 익히면 홈서버 운영이 정말 편해집니다. 새로운 서비스를 설치할 때 의존성 걱정 없이 docker-compose 파일 하나로 끝낼 수 있고, 문제가 생기면 컨테이너만 삭제하고 다시 시작하면 됩니다.

처음에는 명령어가 낯설게 느껴질 수 있지만, Portainer 같은 GUI 도구를 함께 사용하면 훨씬 쉽게 적응할 수 있습니다. 이 글에서 소개한 서비스들부터 하나씩 설치해보면서 Docker에 익숙해지시길 권합니다.

다음 편에서는 홈서버 보안을 강화하는 방법에 대해 알아보겠습니다. 방화벽 설정, VPN 구축, 침입 탐지 등 안전한 홈서버 운영을 위한 필수 지식을 다룰 예정입니다.