Docker 환경 구축 방법 – Windows

Windows 환경에서의 Docker 설치

Docker Desktop은 기업 사용자의 경우, 2022년 02월 01일부터 전면 유료화 되어, 해당 프로그램을 사용하려면, 유료 계정을 생성하여 사용하여야 한다.

다만, Docker engine, CLI, Compose 등은 아직 무료로 사용할 수 있기에, 해당 프로그램들을 사용하면, 유료 환경에 대한 문제를 해결할 수 있다.

Docker에서 제공하는 프로그램들에 대한 설명이다.

 

Docker Engine

Docker Engine은 Docker의 핵심 컴포넌트로, 실제로 컨테이너를 실행하는 역할을 합니다.

Docker는 클라이언트-서버 아키텍처를 기반으로 하며, Docker Engine은 서버 역할을 하는 부분입니다.

Linux 기반에서 컨테이너화된 애플리케이션을 실행하고, Windows와 Mac에서는 Docker Desktop을 통해 제공됩니다.

주요 기능은 다음과 같습니다.

  1. 컨테이너 생성 및 관리: Docker Engine은 Docker 이미지에서 컨테이너를 생성하고 실행할 수 있게 해줍니다.
  2. 이미지 관리: Docker Hub와 같은 레지스트리에서 Docker 이미지를 다운로드하고 업로드합니다.
  3. 컨테이너 실행 및 스케일링: 컨테이너의 시작, 중지, 삭제, 리소스 관리 등과 같은 기본적인 관리 작업을 수행합니다.
  4. 네트워크 및 스토리지: 컨테이너들 간의 네트워크 설정 및 데이터 볼륨을 관리합니다.

 

Docker CLI (Command Line Interface)

Docker CLI는 명령어 인터페이스로, 사용자가 Docker Engine과 상호작용할 수 있도록 해줍니다.

Docker 명령어를 사용하여 이미지를 빌드하거나, 컨테이너를 실행하거나, 다양한 Docker 관리 작업을 수행합니다.

  1. 컨테이너 및 이미지 관리: docker run, docker build, docker pull, docker ps 등의 명령어를 통해 컨테이너와 이미지를 실행하고 관리할 수 있습니다.
  2. 로그 및 상태 모니터링: docker logs를 통해 컨테이너의 로그를 확인하고, docker stats로 컨테이너의 리소스 사용 상태를 모니터링할 수 있습니다.
  3. 네트워크 및 볼륨 관리: docker network, docker volume 명령어를 통해 Docker의 네트워크와 볼륨을 관리할 수 있습니다.

Docker Compose

Docker Compose는 여러 개의 Docker 컨테이너를 정의하고 실행할 수 있도록 돕는 툴입니다.

주로 멀티 컨테이너 애플리케이션을 관리하는 데 사용되며, YAML 파일 형식으로 컨테이너 설정을 구성합니다.

  1. 멀티 컨테이너 애플리케이션 정의: docker-compose.yml 파일을 사용하여 여러 컨테이너의 설정, 네트워크, 볼륨 등을 정의할 수 있습니다.
  2. 컨테이너 간 의존성 관리: 여러 개의 서비스가 상호작용하는 복잡한 애플리케이션에서 서비스 간의 의존성을 관리할 수 있습니다.
  3. 애플리케이션 시작/중지: docker-compose up으로 정의된 모든 컨테이너를 한 번에 시작하고, docker-compose down으로 종료할 수 있습니다.
  4. 편리한 개발 환경 설정: 복잡한 개발 환경을 손쉽게 설정하고, 여러 환경에서 동일한 애플리케이션을 실행할 수 있도록 도와줍니다.

Docker Desktop

Docker Desktop은 Windows와 macOS에서 Docker Engine을 실행할 수 있게 해주는 애플리케이션입니다.

Windows나 macOS에서는 Docker가 기본적으로 Linux에서 동작하기 때문에, Docker Desktop이 필요한 가상화 기술을 제공합니다.

  1. 그래픽 UI: Docker Desktop은 GUI를 제공하여 명령어 기반의 Docker CLI를 보조합니다.
  2. Windows, macOS에서 Docker 사용: 리눅스 환경을 가상화하여, Windows나 macOS에서도 Docker 컨테이너를 실행할 수 있도록 지원합니다.
  3. Docker Compose 및 Kubernetes 통합: Docker Desktop에는 Docker Compose와 간단히 통합할 수 있으며, Kubernetes 클러스터를 로컬에서 실행하여 애플리케이션을 테스트할 수 있습니다.

 

Docker Registry (예: Docker Hub)

Docker Registry는 Docker 이미지의 저장소로, Docker Hub는 가장 많이 사용되는 공개 이미지 레지스트리입니다.

  1. 이미지 저장 및 배포: Docker 이미지를 레지스트리에 업로드하고 다른 사용자와 공유할 수 있습니다.
  2. 공식 및 커스텀 이미지: 공식 Docker 이미지뿐만 아니라, 사용자 정의 이미지를 저장하고 관리할 수 있습니다.

 

Docker Engine 설치 방법

WSL 설치

Docker Engine은 Linux 기반으로 동작한다. 따라서, Windows 환경에서, Docker Engine을 설치하려면, Linux 환경을 구축해 주어야 한다.

Linux 환경을 구축하는 방법은 다음과 같다.

  1. WSL (Windows Subsystem for Linux)를 활용한 방법
  2. VM Machine을 활용한 방밥

WSL을 이용한 방법

WSL을 사용하려면, Windows 10버전 2004 이상 또는 Windows 11을 사용해야 한다.

다음 명령을 통해 WSL 을 설치할 수 있다.

C:\> wsl –install

다만 이렇게 설치를 진행하게 되면, 명령 실행 시점 기준, 기본값으로 설정된 Ubuntu 가 설치되며, 다른 버전을 사용하려면, 아래와 같이 사용 가능한 버전을 확인하고

C:\> wsl –list –online

사용 가능한 버전 중에 원하는 버전을 선택하여 설치할 수 도 있다.

C:\> wsl –install -d Ubuntu-24.04

 

WSL 실행

WSL 은 설치한 후, Command Line 에서 직접 wsl 명령을 사용하여 접근하거나, Windows 11의 경우, “Windows 터미널”에서, 탭 확장을 이용하여 원하는 쉘을 실행하여 접근할 수 있다.

Windows 10에서는 Windows Store를 통해, “Windows 터미널”을 설치하여 사용할 수 있다.

 

WSL 자동 실행 설정

시작 프로그램을 통한 실행

WSL은 기본적으로 Windows 가 시작될 때 같이 시작되지 않는다. 또한, WSL이 유휴 상태일 때, Windows 는 WSL 시스템을 종료 시켜 시스템 자원을 확보하려 한다. 따라서, 아래와 같은 방법으로, 윈도우 시작과 동시에 WSL이 활성화 되고, 지속적으로 활성화된 상태를 유지 시켜 줘야 한다.

  1. WSL 시작을 위한 PowerShell Script 작성
    적당한 위치에 “WSL Startup.ps1” 파일을 생성하고, 아래와 같은 내용으로 스크립트를 작성한다.
    Start-Process “C:\Windows\System32\wsl.exe” -WindowStyle Hidden
  2. Startup 위치에 해당 스크립트를 실행하는 바로가기를 생성한다.
    WinKey + R & shell:startup
    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File “D:\DevTools\WSL Startup.ps1”

주의 사항은 이렇게 하더라도, wsl –shutdown 등의 명령으로, WSL시스템을 강제로 종료해 버리면, 백그라운드에서 돌아가는 해당 스크립트도 같이 종료 되기 때문에 시스템 상태 유지가 동작하지 않을 수 있다.

 

WSL Settings

WSL을 설치하면 WSL의 설정을 GUI환경에서 관리할 수 있는 도구가 같이 설치된다. 다만, 상황에 따라 해당 프로그램이 설치되지 않을 수도 있다. WSL Settings 를 찾아보고, 설치되어 있지 않다면, 아래 링크를 참고하여 설치하면 된다.

https://github.com/microsoft/WSL/releases

 

*.docker.internal 관련 설정

Docker Desktop에서는, *.docker.internal 주소를 자동으로 생성해서 제공해 준다. 하지만, docker-engine을 통해 설치할 경우는, 해당 기능을 제공해 주지 않으며, 이는 간단하게 Host PC의 hosts 파일에 아래 내용을 추가하여 기능을 제공해 줄 수 있다.

# Added by Docker Desktop
192.168.0.61 host.docker.internal
192.168.0.61 gateway.docker.internal
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section

 

Container의 Host IP를 통한 Container 접속

2개의 독립적인 Container가 존재하고, 다른 컨테이너로 접속하기 위하여 host IP를 통해 접근하게 되면, 정상적으로 접근이 되지 않는 경우가 발생할 수 있다.

이는 다중 NAT 설정의 포트 포워딩 설정으로 인해 발생하는 문제로, 뒤쪽에서 설명하는 포트 포워딩 등의 동작 방식이, 외부에서 접근하는 것과, 내부에서 접근하는 것에서 발생하는 차이로 인한 문제이다.

현재로써는, 해당 문제가 포트 포워딩으로 인해 발생하는 것 까지만 확인된 상태이며, 구체적으로 어떻게 해결해야 하는 것 까지는 확인하지 못했다. 또한, 해당 문제는 단순히, 내부 아이피 나, 컨테이너 HostName으로 호출하면 되는 문제이기에, 추후 다시 한번 확인할 필요가 있을 때 확인해 보기로 한다.

 

주요 설정

WSL Settings를 통해 Docker를 위한 설정을 몇가지 해주어야 한다.

  1. 메모리 및 프로세스
    1. 스왑 크기: 스왑 메모리가 사용되면, 유휴 상태의 Container가 스왑 영역으로 스왑 아웃될 수 있다. 이런 경우, 컨테이너가 느려지거나 비정상 적으로 동작할 수 있다. 간혹 스왑 인/아웃이 일어나면서, CPU가 100% 점유하는 현상도 발생할 수 있으니, 해당 스왑 크기는 0으로 설정하여 스왑 기능을 비활성화 한다.

 

Docker Engine 설치

기존 설치 버전 삭제

Docker Engine은 containerd에 의존한다. 따라서, 기존에 설치되어 있는 containerd.io나, 다른 종속성이 있는지 확인하여, Docker Engine과의 충돌을 피하기 위하여 아래 명령으로 삭제를 진행한다.

# for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done

Docker 저장소를 apt에 등록

설치를 진행하기 위해서 Docker 저장소를 apt에 먼저 등록해야 한다.

  1. 일단 저장소 패키지 정보들을 업데이트 하고,
    # sudo apt-get update
  2. 설치에 필요한 패키지들을 설치한다.
    # sudo apt-get install ca-certificates curl
  3. 폴더를 생성하고, 권한을 부여함
    # sudo install -m 0755 -d /etc/apt/keyrings
  4. 키 정보를 받아와 등록한다.
    # sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
  5. 읽기 권한 부여
    # sudo chmod a+r /etc/apt/keyrings/docker.asc
  6. 저장소 정보를 가져와 등록
    # echo “deb [arch=$(dpkg –print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo “$VERSION_CODENAME”) stable” | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  7. 등록된 저장소에서 정보를 가져올 수 있는지 확인하기 위하여 패키지 정보 업데이트 실행
    # sudo apt-get update

Docker Engine 설치

최신버전을 설치하려면 다음과 같이 진행한다.

# sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Docker Engine 설치 확인

Docker Engine이 정상적으로 설치되었는지 확인하기 위하여, 다음과 같이 명령을 실행하여 확인한다.

# sudo docker run hello-world

다음과 비슷한 문장이 보이면, 정상적으로 설치가 완료된 것이다.

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the “hello-world” image from the Docker Hub. (amd64)
3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

Docker Engine 제거

만약에, 설치된 Docker Engine을 제거하려면, 다음 명령으로 제거할 수 있다.

# sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras

호스트의 이미지, 컨테이너, 볼륨 또는 사용자 지정 구성 파일은 자동으로 제거되지 않기에, 다음 명령을 통해 제거를 진행해야 한다.

# sudo rm -rf /var/lib/docker

# sudo rm -rf /var/lib/containerd

 

Host PC 의 드라이브 마운트

wsl상에 Docker를 설치하게 되면, 독립적인 공간을 생성하여 관리되기에, 설정파일은 외부의 Host PC의 저장공간에 관리해야 할 필요성이 있다. 따라서, Host PC의 저장 공간에 접근하는 방법을 알아 두거나, 적당한 위치에 Link를 생성해 두면, Docker Container를 관리하는데 좀 더 편리할 수 있다.

WSL은 기본적으로 /mnt의 하위에 자동으로 드라이브 명으로 마운트 된다.

C: à /mnt/c

D: à /mnt/d

마운트 디렉토리를 이용하여 적당한 위치에 Symbolic Link를 생성한다.

예를 들어, D:\Docker 폴더를 만들고, 해당 폴더 하위에 Volume 파일을 관리한다면, 해당 폴더를 WSL시스템에 /var/lib/docker-config 이름으로 Symbolic Link를 만들어 둔다면 좀더 쉽고 직관적으로 이미지 저장 폴더를 관리할 수 있다.

# ln -s /mnt/d/docker /var/lib/docker-volumes

이에 따른 권한 설정 문제는 아래 “Host File System 에 대한 권한 설정 활성화”에서 다룬다.

 

Host File System (/mnt/c)에 대한 권한 설정 활성화 (WSL 2)

기본적으로 WSL은 자동 혹은 수동으로 마운트 된, Host – File System에 대한 권한 설정을 할 수 없다. 이는 Windows File System (NTFS)와 Linux File System (Ext4)의 권한 관리의 차이로 발생하는 문제이며, 마운트 된 HOST 시스템의 파일이나 폴더를 WSL 시스템이나, 이를 Volume으로 가져온 컨테이너 레벨에서 권한이나 사용자를 변경하더라도, 정상적으로 변경이 되지 않는 문제가 발생한다.

이로 인하여, Container의 Volume 관리에 어려운 점이 발생한다. 이를 테면, GitLab과 같이, 파일이나, 경로의 권한을 확인하여, 원하는 상태가 아닐 경우, (Mode 700 등) 시스템을 동작 시키지 않는 시스템의 경우는 아예 실행조차 되지 않는 문제가 발생할 수 있다.

이를 해결하기 위해서는, WSL 설정에 automout 부분에 아래와 같이 옵션을 추가하여 권한을 설정할 수 있게 설정해 줘야 한다. (WSL 내부 파일 임에 주의)

대상 파일: /etc/wsl.conf

[automount]
options=metadata

위와 같이 설정하게 되면, 마운트 된 Host PC의 File System에 대한 권한을 설정할 수 있다.

MetaData 방식은 이런 윈도우와 Linux간의 파일 권한 관리 차이점을 해결하기 위한 기술로, WSL2에서 사용하는 권한 정보를 Windows 파일시스템에 MetaData형태로 기록하고, 이를 WSL에서 읽어오거나 가져와서 사용할 수 있도록 해주는 기능이다.

 

TCP를 통한 원격 접속 설정

daemon.json 설정

Docker를 TCP를 이용하여 외부로 노출 시키려면 먼저 Docker Daemon 설정을 수정해야 한다.

  1. daemon.json 파일 수정
    /etc/docker 디렉토리에 daemon.json 파일을 생성하여, 아래 문장을 기록한다.
    {“hosts”: [“tcp://0.0.0.0:2375”, “unix:///var/run/docker.sock”]}
  2. /lib/system/system/docker.service 파일에서, 실행 구문 중 fd:// 문장을 제거한다.
    ExecStart=/usr/bin/dockerd -H fd:// –containerd=/run/containerd/containerd.sock
    è
    ExecStart=/usr/bin/dockerd –containerd=/run/containerd/containerd.sock
  3. 서비스를 재시작 한다.
    # systemctl daemon-reload
    # systemctl restart docker.service

위와 같은 과정을 통해, 외부에서 접속할 수 있도록 설정할 수 있다. 다만, 이렇게 설정 하더라도, localhost나, 127.0.0.1로 접속은 되지 않도, WSL에 지정된 내부 아이피를 통해 접속을 해야 정상 접속이 가능하다.

Web 기반 Docker 시각화 도구 설치

Docker Desktop 과 유사한 웹 기반 Docker 시각화 도구를 이용하면, 좀 더 편리하게 Docker 환경을 관리할 수 있다.

Portainer는 시각화를 통해 원격 혹은 로컬 Container들의 상태를 확인할 수 있는 UI를 제공한다.

아래 명령을 통해 설치한 후, 9000 번 포트를 이용하여 웹 브라우저를 통해 콘솔에 접근하면 된다.

# docker run -d –name portainer -p 8000:8000 -p 9000:9000 -p 9443:9443 –restart always portainer/portainer-ce:latest

비밀번호는 설치 초기에는 12자리로 고정되어 있지만, 최초 비밀번호 설정 후, 접근하여 비밀번호 길이를 조절할 수 있다.

 

WSL의 외부 공개 설정

WSL 상에 Docker를 설치하게 되면, WSL또한 NAT 상의 네트워크 상에서 동작하기 때문에, 외부 IP나, host PC에서 localhost를 통해 접속을 시도하게 되면, 접속이 되지 않는 현상이 발생한다. 이는 호스트 PC에서 WSL의 포트로 포트 포워딩이 되어 있지 않아, 정상적인 접속이 이루어지지 않아서 발생하는 현상이다.

아래 명령을 통해 host PC의 포트를 WSL 내부로 매핑해주면 외부 IP를 통해서도 정상적인 서비스가 가능하다.

포트 포워딩 설정

관리자 모드로 PowerShell을 띄운 후, 아래 명령을 참고하여 포트 포워딩 설정을 진행한다.

C:\> netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=[대상포트] connectaddress=[WSL내부 아이피] connectport=[내부포트]

 

포트 포워딩 리스트

참고로, 현재 설정된 리스트는 아래 명령으로 확인 가능하다.

C:\> netsh interface portproxy show all

 

포트 포워딩 삭제

C:\> netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=[대상 포트]

 

Host에서 Docker 명령 사용하기

WSL명령을 통한 실행

실행 방법

WSL에 설치된 docker 명령을 실행하여, docker에 접근하려면, 명령 앞에 wsl을 입력하면 가능하다.

C:\> wsl docker container ls

C:\> wsl docker compose up/down

편의 기능 설정

Path가 설정된 디렉토리에 docker.bat를 만들어 명령어를 단축 시키는 것도 좋은 방법이 될 수 있다.

아래와 같은 간단한 명령 구문으로 docker.bat를 만들어 주고, Path 설정을 통해 실행 가능 상태로 만들어 주면 실행 할 때 마다 wsl docker … 와 같은 형태로 실행하지 않고, Docker Desktop 과 동일한 형태로 docker … 명령을 수행하여 Docker를 제어할 수 있다.

@echo off
wsl docker %*

 

Docker CLI를 통한 실행

wsl을 입력하는 것이 싫다면, Docker CLI를 host에 설치한 후, 접속 경로를 설정하여 실행 환경을 생성할 수 있다.

  1. 바이너리 파일 설치
    1. Docker-CLI: WSL에 설치된 버전과 동일한 Windows Docker 바이너리를 다운로드 한다. (현재 기준으로 독립된 CLI파일만 다운로드 하거나 설치파일을 제공하지 않기 때문에, 아래 링크를 통해 Docker 전체 바이너리 파일을 다운로드 한다.)
      https://download.docker.com/win/static/stable/x86_64/
    2. Docker-Compose: Docker-CLI가 설치된 동일한 위치에 아래 링크에서 시스템 플랫폼에 맞는 파일을 다운로드 한다. (파일명을 필히 docker-compose.exe 로 변경한다. 아니면, 명령 수행 때마다 플랫폼 명까지 다 쳐도 무방하다.)
      https://github.com/docker/compose/releases
  2. 해당 파일을 적절한 위치에 압축해제 하고, PATH설정을 통해 실행 가능한 상태로 설정한다.
  3. 위 “TCP를 통한 원격 접속 설정”을 통해, WSL에서 원격 접속 설정을 수행한다.
  4. Windows의 “고급 시스템 설정”을 통해 Docker Host 경로를 설정한다.

    DOCKER_HOST: tcp://localhost:2375

     

위 과정을 통해, 설정이 완료되었다면, 명령이 정상적으로 수행 가능한지 확인한다.

C:\> docker container ls

C:\> docker compose up

문제점

위와 같이 Docker CLI와 Docker-Compose 바이너리 파일을 직접 다운로드 받아 설치하여 실행할 경우, Volume 설정 등에서, 경로 매칭 오류가 날 수 있다. 이는, Docker 명령을 실행한 위치와, Docker Daemon이 실행되는 위치의 차이 때문에 발생하는 것으로, 현재 경로(예를 들면, C:\Projects\example)를 WSL에서는 인식하지 못하는(/mnt/c/Projects/example) 문제로 인해 발생한 것이다.

WSL을 통해 설치된 환경에서는 Host에서는 되도록 “WSL명령을 통한 실행” 방법을 사용하는 것을 추천한다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다