Kubernetes/Docker는 개인적인 공부를 위해서 정리하는 용도이다. 개인적으로 인터넷을 통해서 공부한 내용을 기반으로 정리할 것이다.
Docker는 간단하게 말해서 application을 packaging 할 수 있는 tool이다. Container라고 불리는 하나의 작은 software unit 안에 application과 그에 필요한 system tool들과 환경 설정, 모든 dependency를 하나로 묶어서 다른 server나 PC 등 어떠한 곳에도 쉽게 배포하고 안정적으로 구동할 수 있도록 도와주는 tool이다. 기술이 발전함에 따라서 application을 구동하는데 많은 것들이 필요해졌다. 보통 source file만을 배포하게 되면 문제점이 발생하게 된다. 외부 library 등을 사용하게 된다면 여러 dependency들과 환경 설정 등의 새로운 설정이 필요해지게 되고 server 혹은 개발하는 PC마다 이러한 모든 것들을 설치하고 설정하는 것은 꽤 번거로운 작업이다. 만약 내가 개발한 곳과 배포하려는 server에 동일한 framework가 존재하기 때문에 source file만을 배포하기만 해도 자동으로 동작할 것이라고 생각할 수 있다. 이러한 경우에 error가 발생할 수 있고 가령 같은 프로그램이라도 버전의 차이로 인해서 디버깅에 괜한 시간을 할애하는 경우도 종종 있다.
이러한 번거로운 문제점을 해결해주기 위해서 docker라는 것이 생겨나게 되었다. Docker container 안에는 우리가 개발한 application 뿐만 아니라 application을 동작하기 위한 프로그램, 환경 설정, 여러 library들의 dependency, 그리고 application을 위해서 필요한 여러 resource들이 포함될 수 있다. 요약하자면 우리의 application의 구동을 위해서 필요한 모든 것들을 docker container 안에 포함시켜 놓았다고 생각하면 된다. Docker container를 사용하면 우리의 application을 구동하기 위해서 run time 환경이 필요한 모든 것들을 어떠한 server나 PC에서도 언제든지 동일하게 구동할 수 있다. 그리고 여러가지 설정해야하는 번거로움을 해결해주는 유용한 packaging tool이다.
기존의 가상화 기술은 hypervisor를 이용해 여러 OS를 하나의 host에서 생성해서 사용하는 방식이었다. 이러한 여러 OS는 VM이라는 단위로 구별되고, 각 VM에는 Ubuntu, CentOS 등의 OS가 설치되어 사용된다. Hypervisor에 의해 생성되고 관리되는 OS는 Guest OS라고 하며, 각 Guest OS는 다른 Guest OS와는 완전히 독립된 공간과 system resource를 할당받아 사용된다. 이러한 가상화 방식을 사용할 수 있는 대표적인 tool이 바로 VirtuaBox와 VMware 등이 있는 것이다.
VM이라고 불리는 virtual machine의 경우에는 server와 같은 hardware infrastructure 위에 VMware나 VirtualBox와 같은 hypervisor software를 이용해서 각각의 virtual machine을 만들어낼 수 있다. 하나의 OS 위에서 동일한 application을 각각의 고립된 다른 환경에서 구동하기 위해서는 VM을 이용해서 application을 구동해야 한다. VM은 각각의 OS를 포함하고 있기 때문에 mac이라는 OS 위에서 이러한 VM을 이용하면 window와 linux를 동시에 구동할 수 있게 된다. 이렇게 고립된 환경에서 application을 구동하기 위해서 VM을 사용하게 되면 OS를 포함하고 있기 때문에 굉장히 무거워지고 시작하는데 오래 걸려서 컴퓨터의 infrastructure의 resource를 많이 잡아먹게 되는 문제점이 발생하게 된다.
이러한 VM에서 경량화 된 컨셉이 바로 container이다. Container는 hardware에 설치된 OS, 즉 host OS에서 container engine이라는 software를 설치하기만 하면 개별적인 container를 만들어서 각가의 application을 고립된 환경에서 구동할 수 있도록 해준다. VM과의 차이점이 확실해지면서 VM이 OS를 포함했다면 container는 OS를 포함하지 않고 container engine이 설치된 host OS를 공유하게 된다. 다만 container가 구동되기 위해서는 container engine이라는 것이 필요하고, container engine이 host OS에 접근해서 필요한 것들을 처리해주게 되는 구조이다. 여기서 container engine 중에서 가장 많이 사용하는 것이 바로 docker라는 것이다.
Container는 VM에 비해서 굉장히 가벼워져 기존이 문제점을 해결할 수 있다. Container는 가상화된 공간을 생성하기 위해서 linux 자체 기능인 chroot, namespac, cgroup을 사용해서 process 단위의 격리 환경을 만들기 때문에 성능 손실이 거의 없다. 더불어 container에 필요한 kernel은 host의 kernel을 공유해 사용하고 container 안에는 application을 구동하는데 필요한 library와 실행 file만 존재하기 떄문에 container를 image로 만들었을 때 용량 또한 크게 줄어들게 된다. 따라서 배포하는 시간이 VM에 비해 빠르며, 가상화된 공간을 사용할 때의 성능 손실이 거의 없어지게 된다.
- 가볍고 성능의 손실이 거의 없으며 빠르다.
- Application의 개발과 배포가 편해진다.
- 여러 application의 독립성과 확장성이 높아진다.
- Project 자체의 성숙도나 확장성, 편의성 등이 좋다.
Docker를 보면 container를 만들고 배포하고 구동하는 식의 방식으로 진행이 된다. 여기서 container를 만들기 위해서는 총 3가지가 필요하게 된다. Container를 만들어내기 위해서 먼저 docker file을 만들어야 하고 이를 이용하여 image를 만든 뒤에 container를 구동할 수 있다.
Docker file은 container를 어떻게 만들어야 하는지에 대한 설명서와 같은 역할을 한다. Application을 구동하기 위해서 꼭 필요한 file들은 무엇이 있는지 설명할 수 있고 어떠한 framework나 library를 설치해야 하는지에 대한 외부 dependency에 대해서 명시할 수 있으며 필요하 환경 변수에 대해서 설정할 수도 있다. 그리고 어떻게 구동해야 되는지 script도 포함할 수 있다.
이렇게 작성한 docker file을 이용해서 image를 만들 수 있는데, 이 image 안에는 application을 실행하는데 필요한 code, runtime 환경, system tool, system library 등의 모든 setting들이 포함되어져 있다. 간단하게 이야기하면 실행되고 있는 우리의 application을 카메라로 예를 들면 사진을 하나 찍어둬서 image로 만들어둔다고 생각하면 된다. 이렇게 만들어진 docker image는 변경이 불가능한 불변의 상태로 볼 수 있다.
마지막 단계인 container는 만들어둔 application의 image를 고립된 환경에서 개별적인 file system 안에서 실행할 수 있는 것을 말한다. 즉, container 안에서 우리가 만든 appliation이 동작한다고 보면 된다. Container는 미리 준배해 놓은 application의 image를 이용해서 application을 구동하게 되는 것이다.
객체지향 프로그래밍에 익숙해지게 되면 여기서 image를 class라고 생각하면 된다. Class는 여러 객체를 생성해낼 수 있는 일종의 틀같은 것이다. 동작하고 있는 application을 template 형태로 image를 만들어두고, image를 이용해서 실제로 application이 동작하는 각각의 container를 만들어낼 수 있게 된다. 그래서 image는 만들어지는 당시에 project의 상태를 바꿀 수 없는 상태로 가지고 있게 되며, container에서 각각 동작하는 application은 file도 만들 수 있고 수정도 할 수 있는 개별적으로 수정이 가능한 상태가 되는 것이다. 각각의 container에서 수정된 file들이 있다면 이는 image에는 전혀 영향을 끼치지 않게 된다. Image는 class이고 만들어진 각 container는 instance라고 볼 수 있는 것이다.
Container를 배포하는 과정, 즉 docker image를 공유하는 과정은 git과 github를 사용해봤다면 익숙할 정도로 비슷할 것이다. 개발한 local machine에서 image를 build해서 github와 같은 container registry에 우리가 만든 image를 push하고 필요한 server나 다른 개발자 PC에서 우리가 만들어둔 image를 가지고오는 pull을 통해서 그대로 실행하면 된다. 물론 image를 정상적으로 실행하기 위해서는 docker와 같은 container engine을 꼭 설치해둬야 한다.
이미지를 업로드하고 공유할 수 있는 container registry는 public과 private이 있다. Public에는 dockerhub나 Github Packages와 같은 것들이 있으며 보통 dockerhub가 더 많이 사용되곤 한다. 많은 개발자들은 이러한 public service를 이용하고 있지만, 회사에서는 대부분 private를 사용한다. 회사 project와는 관련이 없는 다른 사람들이 해당 project의 docker image를 쉽게 다운로드 받지 못하므로 보안적인 이유에서 회사에서는 private를 많이 사용한다. AWS, Google Cloud, Microsoft Azure 등 주요 3사에서 제공해주는 이러한 service들 덕분에 private을 사용하고 있는 것이다.
요약하자면 우리가 개발하고 있는 local machine과 server에 docker를 설치하기만 하면 된다. Application을 구동하는데 필요한 docker file을 작성한 다음에 이를 이용해서 application을 담을 수 있는 image를 만든 뒤에 이 image를 container registry에 올린 다음에 server에서 다운로드 받아서 container를 실행할 수 있다.