[MLOps] 컨테이너 관리 도구 도커(Docker) 소개 및 사용법
각 컨테이너는 독립적으로 작동하기 때문에 여러 컨테이너를 효과적으로 다룰 방법이 필요해졌다. Unix나 linux는 하나의 호스트 운영체제 안에서 자원을 분리해 할당하고 프로세스를 격리해서 관리하는 방법을 제공해왔지만, 이는 매우 복잡한 과정이다. 이런 과정을 쉽게 만들어주는 도구로 등장한 것이 도커(docker)이다.
1. Docker
도커는 컨테이너를 사용하여 애플리케이션을 만들고, 배포하고, 실행하는 데 사용되는 도구이다. 개발자는 컨테이너를 사용하여 필요한 모든 파트(라이브러리, 프레임워크, 종속성 등)와 함께 앱을 패키징하여 하나의 패키지로 제공할 수 있다. 컨테이너를 사용하면 앱을 실행하는 컴퓨터(코드를 작성하고 테스트하는 데 사용된 머신과 다를 수도 있음)의 사용자 지정된 설정 또는 이전에 설치한 라이브러리와 상관없이 앱이 동일하게 실행된다. 따라서 개발자는 코드가 실행될 시스템에 대해 신경 쓰지 않고 코드 작성에 집중할 수 있다. 도커는 이런 컨테이너를 사용하는 방법을 명령어로 정리한 것이라고 보면 된다. 도커를 사용하면 사용자가 따로 신경쓰지 않아도 컨테이너를 생성할 때 개별적인 실행 환경을 분리하고 자원을 할당한다.
도커는 2013년 Docker사에서 만든 컨테이너 관리 도구로, 컨테이너를 실행하는 데 필요한 이미지를 만들거나 공유하는 등 다양한 기능을 제공한다.
2. Docker Image
도커로 컨테이너를 다루기 위해서는 도커 이미지를 내려받아 컨테이너로 실행하는 단계가 필요하다.
도커 이미지(docker image)란 도커에서 서비스 운영에 필요한 서버 프로그램, 소스코드 및 라이브러리, 컴파일된 실행 파일을 묶은 형태이다. 도커 이미지 그대로는 사용할 수 없고 CRI로 불러들여야 컨테이너가 실제로 작동하게 된다. 쉽게 말하면 실행 파일-실행된 파일 관계로 볼 수 있을 것이다. 혹은 이미지를 어플리케이션과 각종 파일을 담고 있다는 점에서 zip 같은 압축 파일로도 볼 수 있다.
도커 이미지 안에는 레이어(layer)가 포함되어 있다.
압축 파일과 달리 도커 이미지는 내용이 같은 레이어1, 레이어2를 공유하기 때문에 전체 공간에서 봤을 때 상대적으로 용량을 적게 차지한다. 이 말인 즉슨 이미지는 같은 내용일 경우 여러 이미지에 동일한 레이어를 공유하므로 전체 용량이 감소한다는 것이다.
다시 도커 설명으로 돌아와서, 도커는 사용자가 명령어를 입력하는 명령어 도구(CLI)와 명령을 받아들이는 도커 데몬(docker daemon)으로 구성되어 있다. 도커 데몬은 클라이언트가 입력한 입력을 맏아 그것에 따라 이미지나 컨테이너를 실행하는 등의 작업을 한다. 도커 1.11 이전에는 도커가 직접 컨테이너를 제어했으나, 이후부터는 컨테이너를 제어하기 위해 별도의 컨데이너디(containerd)를 포함하고 있다. 도커와 쿠버네티스를 함께 설치할 경우 쿠버네티스는 컨테이너 오케스트레이션을 위해 도커에 포함된 컨테이너디를 활용한다.
3. Docker 사용법
나의 환경: Windows Pro 10에 설치되어 있는 WSL2 Ubuntu-18.04
※ 참고
WSL2 설치하기 - https://docs.microsoft.com/ko-kr/windows/wsl/install WSL에 Docker 설치하기 -https://docs.microsoft.com/ko-kr/windows/wsl/tutorials/wsl-containers
우선 컨테이너를 만들 이미지가 있어야 한다.
- 이미지 검색
docker search <검색어>
레지스트리에 특정한 이름(검색어)을 포함하는 이미지가 있는지 찾는다(별도로 지정하지 않으면 기본으로 도커 허브에서 검색). 이미지는 어플리케이션, 미들웨어 등 목적에 맞게 패키징 되어있다. 예를 들어 <검색어> 부분에 nginx를 넣어 현재 사용할 수 있는 nginx 이미지를 찾아보자.
- NAME: 검색된 이미지 이름
- DESCRIPTION: 이미지에 대한 설명
- STARS: 해당 이미지를 내려받은 사용자에게 받은 평가 횟수
- OFFICIAL: [OK] - 해당 이미지에 포함된 앱이나 미들웨어 등을 개발한 업체에서 공식적으로 제공한 이미지
- AUTOMATED: [OK] - 도커 허브에서 자체적으로 제공하는 이미지 빌드 자동화 기능을 활용해 생성된 이미지
- 이미지 내려받기
docker pull <이미지 이름>
docker search로 찾은 이미지를 내려받는 명령어이다. 앞에서 찾은 nginx 이미지를 내려받아보자.
- 태그(tag): 이미지 버전 확인 가능 / latest - 최신 이미지
- 레이어(layer): 분리되어 내려받아진 데이터
- 다이제스트(digest): 이미지 고유 식별자(동일한지 검증)
- 내려받은 이미지 조회
docker images <이미지 이름(option)>
docker images 명령어로 모든 top level 이미지들을 조회할 수 있다. 뒤에 <이미지 이름>을 명명하게 된다면 레포지토리 이름으로 필터링 할 수 있다. 아래는 docker images 명령어로 조회한 이미지들이다.
- IMAGE ID: 도커 파일을 빌드할 때 만들어지는 식별자
- SIZE: 이미지 용량
- 이미지 생성 과정과 용량 조회
docker history <이미지 이름>
argument로 이미지 이름을 특정해주면 IMAGE ID와 생성된 날짜, 용량 등을 통해 해당 이미지가 어떻게 빌드되었는지 확인할 수 있다. 아래는 docker history nginx로 조회한 history이다.
- 컨테이너 실행하기
docker run (options) <이미지 이름> (:태그 | @다이제스트)
말 그대로 컨테이너를 실행시키는 명령어이다. docker run -d nginx를 통해 nginx 이미지를 기반으로 새로운 컨테이너를 실행해보았다. 이때 리턴되는 16진수 문자열은 컨테이너를 식별할 수 있는 고유한 ID이다(도커가 임의로 부여한 값).
Options
- -d(--detached): 컨테이너를 백그라운드에서 구동. 옵션을 생략하면 컨테이너 내부에서 실행되는 앱의 상태가 화면에 계속 표시된다. 이때 ^C를 누그면 앱뿐만 아니라 컨테이너도 같이 중단된다. 따라서 계속 실행되어야 하는 프로그램은 -d 옵션을 붙여 백그라운드에서 작동하게 한다.
- -i 혹은 -t: 컨테이너를 종료하지 않은 상태로 터미널의 입력을 계속해서 컨테이너로 전달할 때 사용. -it 옵션의 형태로 붙여쓰는 경우가 많다. 컨테이너의 쉘이나 CLI 도구를 사용할 때 유용함.
- --name: 컨테이너에 붙여주는 이름. docker run으로 컨테이너를 생성하면 결괏값으로 컨테이너 ID가 리턴되는데, 너무 길어서 기억하기 어렵다. 이때 --name 옵션으로 컨테이너 이름을 부여해주면 해당 이름으로 컨테이너를 식별할 수 있음 (컨테이너 ID와 이미지 ID는 다르다!!)
- -p: 호스트와 컨테이너 간의 포트 배포/바인드를 위해 사용. 호스트 컴퓨터에서 컨테이너에서 리스닝하고 있는 포트로 접속할 수 있도록 설정해준다. gpu 서버 도커로 쓸 때 꼭 필요함...
- -w: Dockerfile의 작업 디렉토리 변경할 때 사용.
- --restart always: 프로그램 오류로 인해 컨테이너 작동이 중지되었을 때 즉시 재시작하거나, linux 시스템에서 도커 서비스가 중지되었다가 재작동시 컨테이너도 자동으로 다시 시작하도록 설정. --restart always 명령어를 사용하면 예상치 못한 상황으로 실행이 중지되었다가도 자동으로 기존 상태를 이어갈 수 있다.
- 컨테이너 리스트 반환
docker ps (options)
생성된 컨테이너들의 리스트와 상태를 확인할 수 있다.
Options
- -a(--all): 가동 중, 멈춘 컨테이너를 포함해 모두 다 표현.
- -f(--filter): 컨테이너를 지정해 검색. key(대상)=value(값) 형식으로 입력하며 필터링 키로 컨테이너 ID나 이름, 레이블 등을 사용할 수 있다.
- -l: 마지막으로 생성한 컨테이너 표시.
- -q: 컨테이너 ID만 리턴.
- -s(--size): 컨테이너 용량 표시.
- 컨테이너 중지하고 다시 시작하기
# 컨테이너 중지하기
docker stop <컨테이너 ID/이름>
# 컨테이너 시작하기
docker start <컨테이너 ID/이름>
실행되고 있는 컨테이너를 중지한다. 도커에서 컨테이너를 삭제하기 위해서는 일단 중지를 해야하기 때문에 삭제 전에 docker stop 명령어를 통해 실행을 멈춘다. 이때 인자로 컨테이너 ID 혹은 이름 둘 중 아무거나 사용해도 된다(ID값은 다 복붙 안해도 되고 앞에 몇글자만 해도 되는 듯).
반대로 중지한 컨테이너를 다시 시작하고 싶으면 docker start를 사용하면 된다.
- 컨테이너 삭제하기
docker rm <컨테이너 ID/이름>
위에도 말했지만 docker rm 명령어는 실행 중인 컨테이너에는 사용할 수 없다. 문제를 해결하려면 먼저 컨테이너를 중지하거나, 강제로 삭제를 해야한다. 삭제한 컨테이너는 복구할 수 없다!!
- -f: -f 옵션을 통해 실행 중인 컨테이너를 강제로 삭제할 수 있다.