카카오 테크 캠퍼스 3단계 과정에서 실제로 서비스를 만들고 배포해야 하는데, 배포 과정에서 도커랑 쿠버네티스에 대한 이해가 필요한 것 같아서 그림과 실습으로 배우는 도커 & 쿠버네티스라는 책으로 도커와 쿠버네티스에 대해 알아보았다.
도커를 한마디로 정의하면 데이터 또는 프로그램을 격리시키는 기능
을 제공하는 소프트웨어이다.
격리된 환경을 제공하는 게 중요한 이유는 같은 환경에서 여러 프로그램으로 구성되어 있는 경우 프로그램 간의 충돌이나 설정 충돌 등으로 문제가 발생할 수도 있기 때문이다.
또한 같은 프로그램을 다른 버전으로 다른 프로그램과 연동해서 사용할 때에도 유용하다.
docker run
는 docker container run
을 줄여서 사용하는 것으로 docker pull
, docker create
, docker start
를 한번에 수행하는 명령어이다.
이렇게 컨테이너를 생성 후 실행한 후 컨테이너를 삭제하고 싶다면 먼저 컨테이너의 실행을 멈춰야만 한다.
이때 실행 중인 컨테이너를 확인하고 싶다면 docker ps
를 통해 실행 중인 컨테이너들을 확인할 수 있다.
docker stop
으로 컨테이너의 실행을 멈추고 docker rm
으로 컨테이너를 삭제할 수 있다.
그리고 컨테이너를 삭제해도 이미지가 남아있기 때문에 이미지를 지우려면 docker image rm
으로 이미지까지 지워줄 수 있다.
아파치 서버를 도커를 통해 컨테이너로 생성해보자.
먼저 컨테이너 생성 및 실행을 위해 docker run --name apa000ex2 -d -p 8080:80 httpd
를 입력하자.
--name
은 컨테이너 이름을 지어주는 옵션이고, -d
백그라운드 실행, -p 8080:80
은 host의 8080 포트와 아파치 서버의 80 포트를 연결해주는 옵션이다. httpd
는 아파치의 이미지 이름을 의미한다.
그리고 docker ps
로 컨테이너가 실행 중인지 확인할 수 있다.
http://localhost:8080/
에 접근하면 아파치의 초기 화면을 확인할 수 있다.
이제 컨테이너를 삭제하려면 먼저 docker stop apa000ex2
로 컨테이너를 종료하고 docker rm apa000ex2
로 컨테이너를 삭제하면 된다.
볼륨을 간단하게 말하면 스토리지, 즉 저장 장소의 한 영역을 분할한 것을 말한다.
마운트는 연결한다라는 의미 그대로 대상을 연결해서 운영체제나 소프트웨어 간의 연결을 의미한다.
도커에서는 컨테이너의 성격상 '쓰고 버려야'하기 때문에 언젠가는 삭제되기 마련이다.
이런 상황에서 컨테이너 속에 데이터를 저장해둔다면 데이터도 함께 소멸된다.
따라서 컨테이너 외부에 둔 데이터에 접근해서 사용하는 것이 일반적이다.
이때 데이터를 두는 장소가 바로 마운트된 스토리지 영역이다.
스토리지는 두 가지 종류가 있다.
하나는 볼륨 마운트이고 다른 하나는 바인드 마운트이다.
볼륨 마운트의 큰 특징은 볼륨 마운트가 도커 엔전의 관리 하에 있다는 점이다.
따라서 컨테이너를 경유해서 볼륨에 접근해야 한다.
다만 바인드 마운트에 비해 직접 조작하기 어렵기 때문에 임시 목적으로 사용하거나 자주 쓰지 않는 파일을 두는 목적으로 사용한다.
바인드 마운트는 기존과 동일한 방식으로 파일을 사용할 수 있다는 점이 가장 큰 특징이다.
예를 들어서 윈도우에서 파일을 조작하면 바로 도커의 파일에 반영 되는 것이다.
이를테면 바탕화면의 단축 아이콘과 유사하다. 실제 실행되는 프로그램은 별도의 다른 장소에 있지만 마치 컨테이너 안에 있는 것처럼 설정되는 것이다.
먼저 바인드 마운트를 하는 예시를 살펴보자.
apa_folder라는 이름으로 마운트 원본이 될 폴더/디렉터리를 생성하자.
윈도우로 예를 들면 문서 폴더 아래에 apa_folder라는 이름으로 폴더를 생성하는 것이다.
그 후 도커에서 docker run --name apa000ex20 -d -p 8090:80 -v C:\Users\사용자명\Documents\apa_folder:/usr/local/apache2/htdocs httpd
를 입력한다.
--name
은 컨테이너의 이름을 지어주는 옵션이고, -d
옵션은 백그라운드 실행, -p
는 포트를 연결, -v
는 볼륨을 마운트해주는 옵션이다.
이후 apa_folder 폴더에 index.html같은 파일을 넣는다면 실제 아파치 서버에 반영된다는 것을 알 수 있다.
볼륨 마운트는 직접적인 확인이 어려워서 volume inspect
명령을 통해 간접적으로 확인한다.
먼저 docker volume create apa000vol1
을 통해 마운트할 볼륨을 생성해야 한다.
참고로 생성한 볼륨은 도커 엔진에서 관리하기 때문에 신경 쓰지 않아도 된다.
그 후 docker run --name apa000ex21 -d -p 8091:80 -v apa000vol1:/user/local/apache2/htdocs httpd
를 통해 생성한 볼륨을 마운트 시켜준다.
볼륨의 상세 정보를 확인하려면 docker volume inspect apa000vol1
을 통해 자세한 정보를 확인할 수 있다.
또 마운트가 잘됐는지 확인하려면 docker volume inspect apa000ex21
로 마운트 정보를 확인할 수 있다.
컨테이너를 개조하는 방법은 두 가지 방법이 있다.
첫번째 방법은 앞서 파일 복사와 마운트를 이용한 방법이다.
두번째 방법은 컨테이너에서 리눅스 명령어를 실행하는 방법이다.
리눅스 명령어를 실행하려면 리눅스에 명령을 전달해주는 프로그램인 shell이 필요하다. 일반적으로 bash가 많이 사용된다.
bash를 실행하기 위해서 이자로 /bin/bash
를 전달하면 된다.
예를 들어 docker exec -it apa000ex23 /bin/bash
를 입력하면 된다.
-i
는 표준 입력을 유지하고 컨테이너와 통신할 수 있게 해주고, -t
는 가상 터미널을 할당하고, 컨테이너 내부의 명령 프롬프트가 터미널처럼 동작해서 명령을 입력하고 결과를 볼 수 있게 해준다.
이때 주의할 점은 bash를 통해 컨테이너 내부를 조작하는 동안에는 도커 명령을 사용할 수 없다는 점이다. 도커 컨테이너는 도커 엔진과는 별개이기 때문이다.
도커 엔진을 통한 명령은 도커 엔진 자체의 시작, 종료, 네트워크, 디스크 설정 등 컨테이너 전체에 대한 관리 작업이다.
반면 컨테이너 내부에서 실행하는 명령은 컨테이너 새로운 소프트웨어를 추가하거나 소프트웨어의 실행, 종료, 설정 변경 등의 작업이다.
작업이 끝나면 exit
로 컨테이너를 빠져나가 다시 도커 엔진에게 명령할 수 있다.
도커 컴포즈는 시스템 구축과 관련된 명령어를 하나의 정의 파일에 기재해 명령어 한번으로 시스템 전체를 실행하고 종료와 폐기까지 한번에 할 수 있도록 도와주는 도구이다.
up 커맨드의 경우 정의 파일에 기재된 내용대로 이미지를 내려 받고 컨테이너를 생성 및 실행한다.
down 커맨드의 경우 컨테이너와 네트워크를 삭제한다. 이때 볼륨과 이미지는 삭제하지 않는다.
도커 컴포즈는 docker run
명령어를 여러 개 모아놓은 것과 같다. 컨테이너와 네트워크와 볼륨처럼 주변 환경을 함께 만들 수 있다.
반면에 Dockerfile은 이미지를 만들기 위한 것으로 네트워크나 볼륨은 만들 수 없다.
참고로 도커 컴포즈와 쿠버네티스 간의 차이점에 대해 궁금할 수 있는데, 쿠버네티스는 컨테이너를 관리하는 도구이지만 도커 컴포즈는 컨테이너를 생성하고 삭제하는 것뿐 관리하는 기능은 없다.
쿠버네티스는 여러 개의 컨테이너를 쉽고 빠르게 배포, 확장하고 관리를 자동화해주는 도구이다.
쿠버네티스는 컨트롤 플레인(Control Plane)과 워커 노드(Worker node) 구성되어 있다.
컨트롤 플레인에서는 컨테이너를 실행하지 않으며 설정 정보에 따라 워커 노드에서 실행되는 컨테이너를 관리하는 역할을 한다.
이렇게 컨트롤 플레인과 워커 노드로 구성된 쿠버네티스 시스템을 클러스터라고 한다.
컨트롤 플레인은 아래와 같은 요소들로 구성되어 있다.
kube-api-server는 외부와 통신하는 프로세스로 클라이언트와 etcd에 저장된 데이터 사이의 상호작용을 중개한다.
kube-controller는 api 서버를 통해 클러스터의 다양한 컴포넌트의 상태를 감시하고 원하는 상태를 만드는 역할을 한다.
kube-scheduler는 새로운 Pod를 감지하고 워커 노드에 할당하는 역할을 한다.
etcd라는 key-value로 이뤄진 데이터베이스로, 이곳에 컨테이너 등의 상태를 관리하기 위한 메타 데이터 정보를 저장한다.
워커노드는 아래와 같은 요소들로 구성되어 있다.
kube-let은 kube-scheduler와 연동하여 워커 노드에 Pod를 배치하고 실행한다. 또 실행 중인 Pod의 상태를 모니터링하며 kube-scheduler에게 통지한다.
kube-proxy는 모든 워커 노드마다 실행되는 네트워크 프록시로, 다른 Pod간의 네트워크 통신과 클러스터 바깥에서 Pod로 네트워크 통신을 할 수 있게 해준다.
Pod라는 용어가 자주 사용되었는데, Pod는 쿠버네티스에서 컨테이너를 관리하는 단위를 의미한다. 기본적으로 파드 하나가 컨테이너 하나이지만 컨테이너가 여러 개인 경우도 있다.
Pod를 여러 개 모은 것이 서비스이다. 구성이 다른 서비스는 별도의 서비스로 관리한다. 서비스는 여러 개의 파드를 관리하는 관리자라고 생각하면 된다.
서비스의 역할은 로드 밸런서(Load Balancer)로 각 서비스는 자동적으로 고정된 IP 주소를 부여 받고(Cluster IP), 이 주소로 들어오는 통신을 처리한다.
내부적으로는 여러 개의 Pod가 있어도 밖에서는 하나의 IP 주소(Cluster IP)만 볼 수 있으며, 이 주소로 접근하면 서비스가 적절히 트래픽을 분배해준다.
하지만 서비스가 분배하는 트래픽은 한 워커 노드 안으로 국한되며, 여러 워커 노드 간의 분배는 실제 로드 밸런서나 인그레스(Ingress)가 담당한다.
레플리카세트(ReplicaSet)는 Pod의 수를 관리하는 역할을 한다. 장애가 발생해서 Pod가 종료됐을 때, 모자라는 Pod를 보충하거나 설정이 변경되어 정의된 Pod의 수가 감소했을 때 실제로 Pod의 수를 감소시킨다.
레플리카세트는 단독으로 사용되는 경우는 드물다. 보통 디플로이먼트(Deployment)와 함께 쓰이는 경우가 많다. 디플로이먼트는 말 그대로 배포를 관리하는 요소로 Pod의 배포에 대한 정보를 관리한다.
쿠버네티스는 manifest 파일에 기재된 내용에 따라 상태를 유지한다. 보통 YAML이나 JSON 형식으로 기재한다.