이 글은 https://tech.kakaoenterprise.com/150 https://www.youtube.com/watch?v=mSD88FuST80 를 보고 공부한 내용을 바탕으로 기록한 글입니다.
도커 없이 컨테이너 만들기?
도커를 이용하면 컨테이너 환경을 손쉽게 구축할 수 있지만, 예전에 어떤 기업의 CTO님께 조언 받은 것이 있었다. 그분은 "윈도우 프로그램을 개발하려면 윈도우 내부를 잘 알고, 모바일 프로그램을 개발하려면 모바일 시스템을 잘 알아야 한다"며, 컨테이너 환경에서 작업하려면 그 내부 구조를 확실히 이해하는 것이 중요하다고 하셨다. 강의에서도 컨테이너 내의 애플리케이션에서 문제가 발생하면 애플리케이션 자체만 볼 것이 아니라, 실행되고 있는 환경을 살펴보아야 한다고 하셨다. 그래서 도커 없이 직접 컨테이너를 만들어 보면서 원리를 파악해 보기로 했다.
컨테이너란?
컨테이너는 애플리케이션을 격리된 환경에서 실행할 수 있도록 해주는 기술이다. 격리된 환경을 통해 애플리케이션이 독립적으로 동작하며, 각 컨테이너는 독립적인 파일 시스템, 네트워크, PID 등 시스템 리소스를 사용한다. 격리된 환경은 네임스페이스(name space)와 Cgroups(Control Groups)를 통해 구현된다.
리눅스 네임스페이스
네임스페이스는 프로그램에서 사용되는 이름의 논리적 그룹으로, 쿠버네티스에서는 단일 클러스터 내에서 리소스 그룹을 격리하는 메커니즘을 제공한다. 네임스페이스를 통해 프로세스와 리소스를 독립적으로 관리할 수 있다.
컨테이너의 파일 시스템
컨테이너의 파일 시스템은 루트 파일 시스템과 다르다. 루트 파일 시스템은 컨테이너 내부에서 독립적으로 존재하며, 이를 통해 호스트 파일 시스템과의 충돌을 방지한다. 컨테이너는 1979년 chroot에서시작되었고, chroot를 통해 프로세스를 격리할 수 있었다. 하지만 chroot의 fake root을 탈출(탈옥) 할 수 있는 문제가 있어, 컨테이너 환경에서 Host의 root에 접근이 가능해진다. 이렇기 때문에 실무에서는 사용할 수 없다.
이를 해결하기 위해 pivot_root라는 시스템 호출이 등장했고, pivot_root는 루트 파일 시스템을 전환하여 호스트 시스템과의 격리를 강화하는 기술이다. 이후 마운트 네임스페이스가 개발되면서, 컨테이너의 파일 시스템과 호스트 파일 시스템을 완벽하게 분리할 수 있게 되었다.
이미지 중복 문제 해결 - 오버레이 파일 시스템
컨테이너 이미지가 중복되면서 발생하는 문제를 해결하기 위해 오버레이 파일 시스템이 개발되었다. (e.g. nginx, nginx+mysql, nginx+mysql+tomcat 등 여러개의 이미지를 만들 때 ubuntu 중복 문제)
오버레이 파일 시스템은 여러 개의 이미지 레이어를 하나의 파일 시스템으로 병합하는 방식으로, 각 컨테이너가 필요한 이미지만 효율적으로 사용할 수 있게 한다. 이를 통해 컨테이너는 CoW(copy-on-write) 방식을 사용하여 원본 이미지를 유지하면서도, 필요한 부분만 수정하여 사용할 수 있다.
네임스페이스를 통한 격리
리눅스 네임스페이스는 컨테이너가 시스템 리소스를 독립적으로 사용할 수 있도록 한다. 네임스페이스에는 여러 종류가 있고, 담당하는 역할이 있다.
- 마운트 네임스페이스(2002): 파일 시스템을 격리하여 컨테이너마다 독립적인 파일 시스템을 제공한다.
- UTS 네임스페이스(2006): 호스트 이름과 도메인 이름을 격리하여 컨테이너마다 독립된 호스트 정보를 제공한다.
- IPC 네임스페이스(2006): 프로세스 간 통신(Shared Memory, Pipe 등)을 격리한다.
- PID 네임스페이스(2008): 프로세스 ID를 격리하여 컨테이너 내부에서 별도의 PID 공간을 제공한다.
- PID = 1 -> init 프로세스 (커널이 생성), 시그널 처리, 좀비-고아 프로세스 처리, 죽으면 시스템 패닉 (reboot)
- unshare 할 때 fork 하여 자식 PID 네임스페이스의 pid = 1로 실행된다. -> 죽으면(Kill 되면) 컨테이너 종료
- PID = 1 -> init 프로세스 (커널이 생성), 시그널 처리, 좀비-고아 프로세스 처리, 죽으면 시스템 패닉 (reboot)
- 네트워크 네임스페이스(2009): 네트워크 스택을 격리하여 컨테이너마다 독립적인 네트워크 환경을 제공한다.
- 네트워크 가상화, 가상 인터페이스(장치) 사용
- 여러 네트워크 네임스페이스에 걸쳐 있을 수 없고, 다른 네트워크 네임스페이스로 이동할 수 있다.
- 네트워크 네임스페이스가 삭제된다면, 가상 인터페이스는 삭제되고 물리 인터페이스는 기존 네임스페이스로 복원된다.
- USER 네임스페이스(2012): UID와 GID를 격리하여 컨테이너 내부에서만 루트 권한을 사용할 수 있도록 한다.
- UID/GID 넘버스페이스 격리: 컨테이너 내부에서는 루트 권한을 가진 사용자처럼 보이지만 실제로는 호스트에서는 일반 사용자로 동작한다. 이를 통해 컨테이너 내부에서만 root 권한을 사용할 수 있도록 격리하여 보안을 강화할 수 있다. 호스트에 영향을 미치지 않고 컨테이너 내에서만 권한을 제한할 수 있어, 보안성 향상과 관리의 유연성을 제공한다.
- USER 네임스페이스는 UID/GID Remap을 통해 각 네임스페이스가 독립적인 사용자 ID/그룹 ID를 사용할 수 있다.
- 이러한 구조는 부모-자식 네임스페이스로 중첩되며, 상위 네임스페이스에서는 하위 네임스페이스의 사용자 권한을 제어할 수 있다.
- UID/GID 넘버스페이스 격리: 컨테이너 내부에서는 루트 권한을 가진 사용자처럼 보이지만 실제로는 호스트에서는 일반 사용자로 동작한다. 이를 통해 컨테이너 내부에서만 root 권한을 사용할 수 있도록 격리하여 보안을 강화할 수 있다. 호스트에 영향을 미치지 않고 컨테이너 내에서만 권한을 제한할 수 있어, 보안성 향상과 관리의 유연성을 제공한다.
Cgroups를 통한 자원 관리
Cgroups는 컨테이너(프로세스)가 사용하는 CPU, 메모리, I/O 등의 자원을 제한하거나 할당할 수 있다. 이를 통해 여러 컨테이너가 동시에 실행될 때, 특정 컨테이너가 과도한 자원을 사용하지 않도록 조정할 수 있도록 한다.
Cgroups로 자원을 제한하는 실험에서는 CPU 사용률을 30%로 제한하는 설정을 적용한 후, top 명령어로 CPU 사용률을 확인해보았다. 제한된 설정에 따라 실제로 CPU 사용률이 30%를 넘지 않음을 확인할 수 있었고, 컨테이너가 시스템 자원을 효율적으로 관리할 수 있음을 알 수 있었다.
도커 없이 컨테이너 만들기 관련 실습 코드 링크 : https://github.com/sam0kim/container-internal/blob/main/ifkakao-handson/4-make-container.txt
컨테이너 기술의 발전 순서
- chroot (1979): 프로세스를 격리하는 초기 기술.
- Mount (2002): 파일 시스템 격리.
- UTS, IPC (2006): 호스트 이름 및 프로세스 간 통신 격리.
- PID, Cgroups (2008): 프로세스 ID 및 자원 격리.
- Net (2009): 네트워크 스택 격리.
- User (2012): 사용자 ID 격리.
- Docker (2013): 컨테이너 기술을 대중화한 도구.
- Kubernetes (2015): 컨테이너 오케스트레이션을 위한 도구.
앞으로 더 공부해야 할 것
- 컨테이너 네트워크 → 가상네트워크 통신
- 컨테이너 표준화 → 인터페이스
- 컨테이너 오케스트레이션 → 쿠버네티스
결론 및 느낀점
이번 강의를 통해 공부하며, 컨테이너의 내부 구조를 이해하는 데 큰 도움이 되었다.
도커가 편리한 도구라는 것은 아무도 의심하지 않는 사실이지만, 그 이면에는 리눅스 네임스페이스와 Cgroups 같은 중요한 기술들이 복잡하게 얽혀 있었다. 이를 직접 다뤄보면서, 각 컨테이너가 독립적인 파일 시스템, 네트워크, 프로세스 ID 공간을 가지게 되는 원리를 얕게나마 알 수 있어서 뜻깊었다.
특히, Cgroups를 이용해 CPU와 메모리 자원을 제한하고, 네임스페이스로 프로세스를 격리하는 과정은 컨테이너 기술의 본질을 체감할 수 있었다. 또한, 오버레이 파일 시스템을 통해 중복을 줄이고 효율적으로 자원을 관리하는 방식도 인상 깊었다.
컨테이너 기술이 발전해온 흐름을 따라가며, 단순히 도구에 의존하기보다는 그 기반 기술을 이해하는 것이 얼마나 중요한지 깨달았고, 앞으로 원리를 깨우치며 커리어를 나아가야겠다는 다짐을 갖을 수 있었다.
'Cloud > Container & Docker & K8S' 카테고리의 다른 글
DevOps 기초 2 - 컨테이너와 이미지 (2) | 2024.09.06 |
---|---|
DevOps 기초 1 - 컨테이너와 VM 비교 (0) | 2024.09.06 |