mydocker에서 데이터 볼륨 마운트 기능 구현

이 글은 mydocker 프로젝트를 통해 컨테이너의 데이터 지속성을 구현하는 과정을 설명합니다. 특히 -v 옵션을 활용해 호스트 시스템의 디렉터리를 컨테이너 내부에 마운트하는 방식으로, 컨테이너 종료 후에도 데이터가 유지되도록 구현했습니다.

기본 개념: bind mount

bind mount은 하나의 파일 시스템 위치를 다른 위치에 연결하는 기술입니다. 이는 두 디렉터리 간에 동일한 내용을 공유하게 하며, 파일 복사 없이도 실시간 동기화가 가능합니다. 예시:

mount -o bind /host/path /container/path

이렇게 설정하면 컨테이너 내부에서 작성된 데이터는 직접 호스트의 디렉터리에 반영됩니다. 이 원리는 데이터 볼륨의 핵심 기반이 됩니다.

구현 단계

  1. CLI 인자 처리: run 명령어에 -v 플래그 추가. 형식은 -v <호스트 경로>:<컨테이너 경로>.
  2. 컨테이너 시작 전 마운트:
    • 오버레이 파일시스템(overlayfs) 생성 후, volumeExtract 함수로 매핑 정보 분석.
    • mountVolume 함수에서 실제 bind mount 수행.
  3. 컨테이너 종료 후 정리:
    • 먼저 볼륨 마운트 제거 (umount).
    • 오버레이 파일시스템 언마운트 및 임시 디렉터리 삭제.

주요 함수 분석

volumeExtract

입력된 문자열을 콜론(:)으로 분할하여 호스트 경로와 컨테이너 경로를 추출합니다.

func volumeExtract(volume string) (string, string, error) {
	parts := strings.Split(volume, ":")
	if len(parts) != 2 {
		return "", "", fmt.Errorf("invalid volume format")
	}
	return parts[0], parts[1], nil
}

mountVolume

호스트 디렉터리 생성 → 컨테이너 내 경로 계산 → mount -o bind 실행.

func mountVolume(mntPath, hostPath, containerPath string) {
	os.Mkdir(hostPath, 0777)
	containerPathInHost := path.Join(mntPath, containerPath)
	os.Mkdir(containerPathInHost, 0777)
	cmd := exec.Command("mount", "-o", "bind", hostPath, containerPathInHost)
	cmd.Run()
}

umountVolume

반대 순서로 마운트 해제. 반드시 bind mount 이후에만 삭제 가능.

func umountVolume(mntPath, containerPath string) {
	path := path.Join(mntPath, containerPath)
	exec.Command("umount", path).Run()
}

테스트 결과

  • 비존재 디렉터리 마운트: /root/volume가 없더라도 자동 생성되며, 컨테이너 내부에서 파일 쓰기 시 호스트에 즉시 반영됨.
  • 기존 디렉터리 재사용: 이미 존재하는 디렉터리에 마운트해도 기존 데이터 보존 확인.
  • 지속성 검증: 컨테이너 종료 후에도 호스트의 볼륨 디렉터리에 파일이 그대로 유지됨.

핵심 포인트 요약

  • 컨테이너의 루트는 /root/merged이며, 이는 호스트 상의 실제 디렉터리입니다.
  • 따라서 컨테이너 내 /tmp는 호스트의 /root/merged/tmp에 대응됩니다.
  • 결국 bind mount/root/volume/root/merged/tmp로 이루어져야 합니다.

이 구현은 실제로 도커의 볼륨 기능과 동일한 동작을 제공하며, 파일 시스템 격리와 리소스 관리 기능을 통합한 진정한 컨테이너 환경을 구성하는 데 중요한 한 걸음입니다.

태그: go linux container bind mount OverlayFS

5월 28일 09:01에 게시됨