Docker 컨테이너 작동 방식

완료됨

앞에서 컨테이너는 앱을 배포하는 데 사용할 단위가 되는 것을 확인했습니다. 또한 컨테이너는 개발자 및 운영 팀이 모두 사용하는 표준화된 컨테이너 형식임을 배웠습니다.

예제에서는 회사의 다양한 아울렛에서 사용하는 주문 추적 포털을 개발하고 있습니다. Docker 이미지가 빌드된 상태에서 이제 운영 팀은 주문 추적 포털의 배포, 업데이트 출시 및 관리를 담당합니다.

이전 단원에서는 Docker 이미지를 빌드하는 방법을 살펴보았습니다. 여기서는 Docker 컨테이너의 수명 주기 및 컨테이너 관리 방법을 간단하게 살펴보겠습니다. 컨테이너의 데이터 스토리지 및 네트워크 옵션 구성에 대해 고려할 항목도 살펴봅니다.

Docker 컨테이너 관리 방법

Docker 컨테이너에는 컨테이너의 상태를 관리하고 추적하는 데 사용할 수 있는 수명 주기가 있습니다.

Diagram that shows the lifecycle of a container and the transition between the lifecycle phases.

컨테이너를 실행 상태로 전환하려면 run 명령을 사용합니다. 이미 실행 중인 컨테이너를 다시 시작할 수도 있습니다. 컨테이너를 다시 시작하면 컨테이너는 컨테이너의 커널이 종료되기 전에 실행 중인 모든 프로세스가 정상적으로 종료될 수 있도록 종료 신호를 수신합니다.

컨테이너는 일시 중지되거나, 중지되거나, 종료될 때까지 실행 상태로 간주됩니다. 그러나 컨테이너는 단독으로 실행 상태에서 종료될 수 있습니다. 실행 중인 프로세스가 완료되거나 프로세스가 오류 상태로 전환될 경우 컨테이너가 자동으로 종료될 수 있습니다.

실행 중인 컨테이너를 일시 중지하려면 pause 명령을 사용합니다. 이 명령은 컨테이너의 모든 프로세스를 일시 중단합니다.

실행 중인 컨테이너를 중지하려면 stop 명령을 사용합니다. stop 명령을 사용하면 종료 신호를 전송하여 작업 프로세스를 정상적으로 종료할 수 있습니다. 프로세스가 종료되면 컨테이너의 커널이 종료됩니다.

컨테이너를 종료해야 하는 경우 kill 명령을 사용하여 종료 신호를 보냅니다. 컨테이너의 커널은 종료 신호를 캡처하지만 실행 중인 프로세스는 종료 신호를 캡처하지 않습니다. 이 명령은 컨테이너에서 작업 프로세스를 강제로 종료합니다.

마지막으로, 중지 상태의 컨테이너를 제거하려면 remove 명령을 사용합니다. 컨테이너를 제거하면 컨테이너에 저장된 모든 데이터가 제거됩니다.

사용 가능한 컨테이너를 보는 방법

실행 중인 컨테이너를 나열하려면 docker ps 명령을 실행합니다. 상태와 관계없이 모든 컨테이너를 보려면 -a 인수를 전달합니다.

예를 들면 다음과 같습니다.

docker ps -a

해당 명령의 출력은 다음과 같습니다.

CONTAINER ID    IMAGE        COMMAND         CREATED       STATUS           PORTS        NAMES
d93d40cc1ce9    tmp-ubuntu:latest  "dotnet website.dll …"  6 seconds ago    Up 5 seconds        8080/tcp      happy_wilbur
33a6cf71f7c1    tmp-ubuntu:latest  "dotnet website.dll …"  2 hours ago     Exited (0) 9 seconds ago            adoring_borg

이전 출력에서 다음 세 가지 항목을 검토해야 합니다.

  • IMAGE 열에 나열된 이미지 이름입니다. 이 예제에서는 tmp-ubuntu: latest입니다. 동일한 이미지에서 둘 이상의 컨테이너를 만드는 방법을 확인합니다. 이는 솔루션에서 스케일링을 사용하도록 설정하는 데 활용할 수 있는 강력한 관리 기능입니다.

  • STATUS 열에 나열된 컨테이너 상태입니다. 이 예제에서는 실행 중인 컨테이너 1개와 종료된 컨테이너 1개가 있습니다. 컨테이너 상태(status)는 일반적으로 컨테이너 상태(health)의 첫 번째 표시기입니다.

  • NAMES 열에 나열된 컨테이너 이름입니다. 첫 번째 열의 컨테이너 ID 외에도 컨테이너는 이름도 수신합니다. 이 예제에서는 각 컨테이너의 이름을 명시적으로 제공하지 않았으므로 Docker가 컨테이너에 임의 이름을 지정했습니다. --name 플래그를 사용하여 컨테이너에 명시적 이름을 지정하려면 run 명령을 사용합니다.

컨테이너에 이름을 지정하는 이유는 무엇인가요?

이 기능을 사용하면 동일한 이미지의 여러 컨테이너 인스턴스를 실행할 수 있습니다. 컨테이너 이름은 고유합니다. 즉, 이름을 지정하면 해당 이름을 다시 사용하여 새 컨테이너를 만들 수 없습니다. 특정 이름을 다시 사용하는 유일한 방법은 이전 컨테이너를 제거하는 것입니다.

컨테이너를 실행하는 방법

컨테이너를 시작하려면 docker run 명령을 사용합니다. 이미지에서 컨테이너를 시작하려면 이름 또는 ID를 사용하여 실행할 이미지를 지정하면 됩니다. 이 방식으로 시작된 컨테이너는 대화형 환경을 제공합니다.

여기서 웹 사이트와 함께 컨테이너를 백그라운드에서 실행하려면 -d 플래그를 추가합니다.

docker run -d tmp-ubuntu

이 경우 명령은 새 컨테이너의 ID만 반환합니다.

실행할 이미지를 지정하고 나면 Docker는 이미지를 찾고, 이미지에서 컨테이너를 로드하고, 진입점으로 지정된 명령을 실행합니다. 이때 컨테이너를 관리할 수 있습니다.

컨테이너를 일시 중지하는 방법

컨테이너를 일시 중지하려면 docker pause 명령을 실행합니다. 예를 들면 다음과 같습니다.

docker pause happy_wilbur

컨테이너를 일시 중지하면 모든 프로세스가 일시 중단됩니다. 이 명령을 사용하면 컨테이너가 이후 단계에서 프로세스를 계속할 수 있습니다. docker unpause 명령은 지정된 컨테이너에서 모든 프로세스의 일시 중단을 해제합니다.

컨테이너를 다시 시작하는 방법

컨테이너를 다시 시작하려면 docker restart 명령을 실행합니다. 예를 들면 다음과 같습니다.

docker restart happy_wilbur

컨테이너는 stop 명령과 start 명령을 차례로 수신합니다. 컨테이너가 stop 명령에 응답하지 않으면 종료 신호가 전송됩니다.

컨테이너를 중지하는 방법

실행 중인 컨테이너를 중지하려면 docker stop 명령을 실행합니다. 예를 들면 다음과 같습니다.

docker stop happy_wilbur

stop 명령은 컨테이너와 컨테이너에서 실행 중인 프로세스에 종료 신호를 보냅니다.

컨테이너를 제거하는 방법

컨테이너를 제거하려면 docker rm 명령을 실행합니다. 예를 들면 다음과 같습니다.

docker rm happy_wilbur

컨테이너를 제거하면 컨테이너의 모든 데이터가 제거됩니다. 데이터 저장을 고려할 때 항상 컨테이너를 임시로 간주해야 합니다.

Docker 컨테이너 스토리지 구성

앞에서 설명한 대로 컨테이너의 앱이 데이터를 저장해야 하는 경우 항상 컨테이너를 임시로 간주합니다.

추적 포털이 앱 루트의 하위 폴더에(컨테이너의 파일 시스템에 직접) 로그 파일을 만든다고 가정해 봅시다. 앱이 로그 파일에 데이터를 쓰면 쓰기 가능한 컨테이너 계층에 데이터가 기록됩니다.

이 접근 방법을 사용할 수 있지만 아쉽게도 이 방법에는 몇 가지 단점이 있습니다.

  • 컨테이너 스토리지가 임시입니다.

    로그 파일은 컨테이너 인스턴스 간에 지속되지 않습니다. 예를 들어 컨테이너를 중지하고 제거한다고 가정해 봅시다. 새 컨테이너 인스턴스를 시작하면 새 인스턴스는 지정된 이미지를 기반으로 하며 이전 데이터가 모두 누락됩니다. 컨테이너를 제거하면 컨테이너의 모든 데이터가 컨테이너와 함께 제거됩니다.

  • 컨테이너 스토리지가 기본 호스트 머신에 연결됩니다.

    컨테이너가 기본 호스트 머신에 연결되므로 컨테이너에서 로그 파일에 액세스하거나 로그 파일을 이동하기 어렵습니다. 파일에 액세스하려면 컨테이너 인스턴스에 연결해야 합니다.

  • 컨테이너 스토리지 드라이브 성능이 저하됩니다.

    컨테이너는 앱이 데이터를 쓸 수 있도록 스토리지 드라이버를 구현합니다. 이 드라이버는 호스트 OS 커널과 통신하기 위해 추가 추상화를 도입하며 호스트 파일 시스템에 직접 쓰는 것보다 성능이 저하됩니다.

컨테이너는 데이터를 유지하는 두 가지 옵션을 사용할 수 있습니다. 첫 번째 옵션은 볼륨을 사용하는 것이고, 두 번째 옵션은 바인드 탑재입니다.

볼륨이란 무엇인가요?

볼륨은 호스트 파일 시스템의 특정 폴더 위치에 저장됩니다. 비Docker 프로세스에서 데이터를 수정하지 않는 것으로 알려진 폴더를 선택합니다.

Docker는 docker volume create 명령을 실행하여 새 볼륨을 만들고 관리합니다. 이 명령은 Dockerfile 정의의 일부를 구성할 수 있습니다. 즉, 컨테이너 생성 프로세스의 일부로 볼륨을 만들 수 있습니다. 볼륨을 처음으로 컨테이너에 탑재하려고 할 때 Docker는 볼륨을 만듭니다(없는 경우).

볼륨은 호스트 파일 시스템의 디렉터리 내에 저장됩니다. Docker는 컨테이너에서 볼륨을 탑재하고 관리합니다. 탑재된 볼륨은 호스트 머신에서 격리됩니다.

여러 컨테이너가 동시에 동일한 볼륨을 사용할 수 있습니다. 또한 컨테이너가 볼륨 사용을 중지하는 경우 볼륨이 자동으로 제거되지 않습니다.

이 예제에서는 컨테이너 호스트에 디렉터리를 만든 다음, 추적 포털 컨테이너를 만들 때 이 볼륨을 컨테이너에 탑재할 수 있습니다. 추적 포털에서 데이터를 기록하는 경우 컨테이너 호스트의 파일 시스템을 통해 이 정보에 액세스할 수 있습니다. 컨테이너가 제거된 경우에도 이 로그 파일에 액세스할 수 있습니다.

또한 Docker는 타사 회사가 볼륨으로 사용할 추가 기능을 빌드할 수 있는 방법을 제공합니다. 예를 들어 Azure Storage는 Docker 컨테이너에서 Azure Storage를 볼륨으로 탑재하는 플러그 인을 제공합니다.

바인드 탑재란 무엇인가요?

바인드 탑재는 개념적으로 볼륨과 동일하지만, 특정 폴더를 사용하는 대신 파일이나 폴더를 호스트에 탑재할 수 있습니다. 또한 호스트가 이 탑재의 콘텐츠를 변경할 수 있어야 합니다. 볼륨처럼 파일이나 폴더를 탑재하는데 아직 호스트에 없으면 바인드 탑재가 생성됩니다.

바인드 탑재는 볼륨보다 제한된 기능을 포함하며 성능이 더 높더라도 특정 폴더 구조가 배치된 호스트를 사용합니다.

볼륨은 컨테이너와 함께 사용할 기본 설정 데이터 스토리지 전략으로 간주됩니다.

Windows 컨테이너의 경우 SMB 경로를 볼륨으로 탑재하고 컨테이너에 표시할 수 있는 다른 옵션을 제공합니다. 이렇게 하면 다른 호스트의 컨테이너에서 동일한 영구 스토리지를 사용할 수 있습니다.

Docker 컨테이너 네트워크 구성

기본 Docker 네트워크 구성을 통해 Docker 호스트의 컨테이너를 격리할 수 있습니다. 이 기능을 사용하여 서로 안전하게 소통할 수 있는 앱을 빌드하고 구성할 수 있습니다.

Docker는 Linux 및 Windows에 대한 다양한 네트워크 설정을 제공합니다.

Linux의 경우 미리 구성된 6가지 네트워크 옵션이 있습니다.

  • 브리지
  • 호스트
  • 오버레이
  • IPvLan
  • MACvLan
  • 없음

Windows의 경우 미리 구성된 6가지 네트워크 옵션이 있습니다.

  • NAT(Network Address Translation)
  • 투명
  • 오버레이
  • L2Bridge
  • L2Tunnel
  • 없음

네트워크 요구 사항에 따라 컨테이너에 적용할 네트워크 구성 중에서 선택할 수 있습니다.

브리지 네트워크란 무엇인가요?

브리지 네트워크는 다른 네트워크 구성을 지정하지 않고 시작될 때 컨테이너에 적용되는 기본 구성입니다. 이 네트워크는 컨테이너에서 사용되는 내부 프라이빗 네트워크이며 Docker 호스트 네트워크에서 컨테이너 네트워크를 격리합니다.

브리지 네트워크의 각 컨테이너에는 IP 주소 및 서브넷 마스크가 할당되며 호스트 이름이 기본적으로 컨테이너 이름으로 지정됩니다. 기본 브리지 네트워크에 연결된 컨테이너는 IP 주소를 통해 다른 브리지 연결 컨테이너에 액세스할 수 있습니다. 브리지 네트워크에서는 호스트 이름을 사용한 컨테이너 간 통신을 허용하지 않습니다.

기본적으로 Docker는 컨테이너 포트를 게시하지 않습니다. 컨테이너 포트와 Docker 호스트 포트 간에 포트 매핑을 사용하려면 Docker 포트 --publish 플래그를 사용합니다.

publish 플래그는 포트를 매핑하는 방화벽 규칙을 효과적으로 구성합니다.

이 예제에서는 포트 80을 검색하는 클라이언트가 추적 포털에 액세스할 수 있습니다. 컨테이너의 포트 80을 호스트에서 사용 가능한 포트에 매핑해야 합니다. 호스트에 포트 8080이 열려 있으므로 다음과 같이 플래그를 설정할 수 있습니다.

--publish 8080:80

Docker 호스트 IP 및 포트 8080을 검색하는 모든 클라이언트가 추적 포털에 액세스할 수 있습니다.

Linux 관련 구성 외에도 Windows의 NAT 네트워크는 브리지 네트워크와 동일하게 작동합니다. 또한 NAT는 Windows의 기본 네트워크이며 달리 지정하지 않는 한 모든 컨테이너가 연결됩니다.

호스트 네트워크란 무엇인가요?

호스트 네트워크를 사용하면 호스트 네트워크에서 직접 컨테이너를 실행할 수 있습니다. 이 구성은 네트워크 수준에서 호스트와 컨테이너 간 격리를 효과적으로 제거합니다.

이 예제에서는 네트워킹 구성을 호스트 네트워크 옵션으로 변경한다고 가정해 봅시다. 호스트 IP를 사용하여 추적 포털에 계속 액세스할 수 있습니다. 이제 매핑된 포트 대신 잘 알려진 포트 80을 사용할 수 있습니다.

컨테이너는 호스트에서 사용되지 않는 포트만 사용할 수 있다는 점에 유의합니다.

Windows에서는 호스트 네트워크를 사용할 수 없습니다. Windows 호스트에서는 호스트와 컨테이너 간에 동일한 IP 주소(네트워킹 스택)를 공유하는 옵션이 없습니다. NAT 네트워크는 브리지 네트워크와 매우 유사하게 작동하며 오버레이 옵션은 호스트와 동일한 네트워크에서 컨테이너에 IP 주소를 제공하지만 동일한 IP 주소는 아닙니다.

오버레이 및 기타 네트워크 옵션

고급 시나리오의 경우 Linux와 Windows 모두 추가 네트워크 옵션을 제공합니다. 예를 들어 오버레이 옵션은 호스트 네트워크에서 가상 스위치를 만들어서 해당 네트워크의 컨테이너가 DHCP 서버에서 IP 주소를 얻거나 해당 네트워크 세그먼트의 IP 주소로 작동할 수 있도록 합니다. 또한 Docker를 사용하면 타사 공급업체가 네트워크 플러그 인을 만들 수 있습니다.

없음 네트워크란 무엇인가요?

컨테이너에 네트워킹을 사용하지 않으려면 없음 네트워크 옵션을 사용합니다. 네트워크를 사용하지 않는 애플리케이션이 있거나 컨테이너에서 애플리케이션이 예상대로 실행되는지 확인만 하려는 경우에 유용할 수 있습니다.

운영 체제 고려 사항

데스크톱 운영 체제 간에 Docker 네트워크 구성 옵션에 대한 차이가 있다는 점에 유의하세요. 예를 들어 브리지 네트워크를 사용하는 경우 Docker0 네트워크 인터페이스를 macOS에서 사용할 수 없으며, Windows 및 macOS 데스크톱에서는 모두 호스트 네트워크 구성이 지원되지 않습니다.

이와 같은 차이는 개발자가 컨테이너 개발을 관리하도록 워크플로를 구성하는 방법에 영향을 줄 수 있습니다. 또한 컨테이너 오케스트레이터는 Docker 설정에 더해 다른 네트워킹 구성을 제공할 수도 있습니다.

지식 점검

1.

컨테이너는 --publish 80:8080 플래그를 사용하여 시작됩니다. 컨테이너에 사용될 가능성이 가장 높은 네트워크 구성 옵션은 어느 것인가요?

2.

호스트 및 컨테이너가 파일을 공유하여 이름 서버 확인을 관리할 수 있는 가장 적합한 스토리지 옵션은 무엇인가요(예: Linux의 resolve.conf 파일)?