연재 시리즈

쿠버네티스 네트워크 스터디 1주차 1편: 컨테이너 격리

악분 2022. 1. 9. 23:12
반응형

스터디 목차

 

안녕하세요. 이 글은 facebook 쿠버네티스 그룹에서 올라온 "쿠버네티스 네트워크 스터디" 1주차 내용을 정리했습니다.

스터디 모집글: https://www.facebook.com/groups/k8skr/posts/3202691746679143

 

1. 1주차 첫번째 주제

1주차 첫번째 주제는 컨테이너 격리를 이해하는 시간을 가졌습니다. 스터디 진행 목차는 아래 그림과 같습니다.

스터디 1주차 진행 목차

 

2. 컨테이너는 독립된 환경을 가지고 있는 프로세스

컨테이너는 커널이 제공하는 격리기능을 사용하여 프로세스를 독립된 환경에서 동작할 수 있게 있게합니다. 아직까지는 리눅스 격리기능을 이용한 컨테이너가 많아 컨테이너라고 하면 리눅스 컨테이너라고 부를 수 있습니다. 구글링을 하면 윈도우 컨테이너[1]도 존재하지만 아직까지는 보편화되지 않은 것 같습니다.

컨테이너의 격리는 프로세스, 파일 시스템 등을 커널 리소스를 격리시키는 기능과 CPU, 메모리 등 하드웨어 자원을 격리시키는 2가지 관점이 있습니다. 이 글에서는 하드웨어 자원 격리는 생략하고 커널 리소스 격리를 살펴봅니다.

출처:O'REILLY - Networking and Kubernetes 책

 

3. 컨테이너와 하이퍼바이저 차이

컨테이너는 약한격리, 하이퍼바이저는 강한격리라고 표현합니다. 컨테이너의 격리수준은 하이퍼바이저보다 약합니다.

컨테이너로 격리된 프로세스는 host 커널을 공유하므로 syscall 등 프로세스 작업을 host 커널 직접 처리합니다. 반대로, 하이퍼바이저는 하드웨어레벨 가상화하므로 게스트 OS가 존재합니다. 하이퍼바이저로 실행된 프로세스는 게스트 OS 커널이 작업을 처리하게 됩니다.

하이퍼바이저는 독립된 OS를 보장하기 때문에 격리수준이 높지만 그만큼 처리속도에 오버헤드가 있어서 컨테이너보다 무겁다고 표현합니다. 반면, 컨테이너는 격리수준이 낮아 처리속도는 하이퍼바이저보다 높지만 host에서 직접 컨테이너를 조작할 수 있어 보안문제가 생길 수 있습니다.

출처: https://netpple.github.io/docs/make-container-without-docker/

 

4. 약한 결합의 특징

컨테이너는 host 커널을 공유하기 때문에 host에서 직접 컨테이너를 제어할 수 있습니다. 예를 들어 도커 컨테이너를 리눅스 kill명령어로 강제로 종료할 수 있습니다. 또한, 컨테이너의 환경변수, 파일 등의 정보를 접근할 수 있습니다.

 

sleep을 실행하는 도커 컨테이너를 실행합니다. 그리고 host에서 sleep프로세스를 실행하는 도커 컨테이너가 리눅스 프로세스로 보입니다.

host에서 도커 컨테이너 프로세스 확인

 

host에서 kill명령어로 sleep프로세스를 죽입니다. 죽이는 동시에 docker 컨테이너가 종료된 것을 알 수 있습니다. 도커 컨테이너가 종료된 이유는 init프로세스가 sleep프로세스이기 때문입니다. init프로세스가 종료되어 도커 컨테이너는 자동으로 종료되었습니다.

도커 프로세스 강제종료

 

도커 컨테이너의 환경변수는 /proc/<도커 컨테이너 PID>/environ파일에서 확인할 수 있습니다. 

도커 컨테이너의 환경변수 확인

 

파일 접근은 컨테이너 파일 시스템으로 접근하면 됩니다. 제 블로그 이전 글(https://malwareanalysis.tistory.com/213)에 자세히 설명했습니다.

 

5. 리눅스 환경 격리: 네임스페이스

5.1 네임스페이스란

리눅스 커널이 제공하는 커널 리소스 격리기능은 네임스페이스(namespace)입니다. 리눅스 프로세스는 네임스페이스라는 공간에 커널 리소스를 격리합니다. 사용하고 있는 네임스페이스는 /proc/$$/ns에서 볼 수 있습니다.

$$는 현재 프로세스ID 값을 가지고 있는 예약어입니다. 로그인한 사용자는 쉘(sh 또는 bash 등)을 실행하고 있으므로 쉘의 프로세스ID를 보여줍니다.
  • cgroup: 하드웨어 자원 관리
  • ipc: 프로세스 통신 네임스페이스
  • mnt: 마운트 네임스페이스
  • net: 네트워크 네임스페이스
  • pid: 프로세스 네임스페이스
  • user: 사용자 네임스페이스
  • uts: hostname 네임스페이스


네임스페이스는 각각 ID를 가지고 있습니다. 기본설정으로 리눅스 프로세스는 최초 프로세스인 init프로세스 네임스페이스를 사용합니다. 새로운 프로세스를 실행하고 이전 프로세스 네임스페이스와 비교하면 네임스페이스ID가 같습니다.

init프로세스와 다른 프로세스 네임스페이스 비교

 

5.2 컨테이너가 네임스페이스를 이용하는 방법

컨테이너는 init프로세스 네임스페이스를 사용하지 않고 새로 네임스페이스를 생성하여 사용합니다. init프로세스의 네임스페이스를 사용하지 않기 때문에 다른 환경에서 실행되는 것처럼 커널 리소스가 논리적으로 격리됩니다.

 

5.3 네임스페이스를 설정하여 프로세스 실행하는 방법

리눅스는 프로세스를 실행할 때 디폴트로 부모 프로세스 네임스페이스를 사용합니다. 그래서 자동으로 init 프로세스의 네임스페이스를 사용했던 것입니다.

 

리눅스는 프로세스를 실행할 때 네임스페이스를 설정할 수 있는 명령어를 제공합니다. 명령어 중 한개가 unshare명령어입니다.

man unshare

 

unshare을 이용하여 /bin/sh을 실행하면  sh쉘이 실행됩니다. 

unshare /bin/sh

 

네임스페이스를 확인하면 init프로세스 네임스페이스와 동일하는 것을 확인할 수 있습니다.

unshare로 /bin/sh쉘 실행과 네임스페이스 비교

 

5.4 네임스페이스 설정 예제

수동으로 네임스페이스 원리와 실습은 https://netpple.github.io/docs/make-container-without-dockerhttps://www.44bits.io/ko/post/is-docker-container-a-virtual-machine-or-a-process에 자세히 설명되어 있습니다. 아직 제가 이해할 수준이 안되어서 링크를 남기면서 살포시 넘겨봅니다.

 

그 대신 도커를 이용하여 도커가 자동으로 설정한 네임스페이스 목록을 확인해봅시다. 도커 컨테이너를 실행하기 전에 host init프로세스의 네임스페이스를 확인합니다.

ls -l /proc/1/ns

호스트 init프로세스의 네임스페이스

 

도커 컨테이너를 실행합니다. 그리고 namespace를 확인해봅시다. user 네임스페이스를 제외한 네임스페이스가 모두 다릅니다.

docker run --rm -it busybox /bin/sh

도커 컨테이너와 host init 네임스페이스 비교

 

6. 마치며

컨테이너 격리에 대해 자세히 알아보는 유익한 시간이었습니다. 네트워크 네임스페이스의 원리만 보기만 했었는데 이 시간을 통해서 처음 직접 만들어보고 원리를 살펴볼수 있었습니다.


토론시간도 뜻깊었습니다. 컨테이너의 보안을 호스트관점에서 어떻게 보완해야할 것인가에 대한 짧은 토론이 있었습니다. 아직은 컨테이너 보안에 대해 많은 자료가 없기 때문에 논의 단계로 보였습니다. 하이퍼커넥트는 Bottlerocket OS를 이용해서 selinux를 사용하는 것 같은데.. 나중에 한번 깊게 봐야겠습니다.

 

vagrant insert_key옵션을 새로 알게되었습니다. 실습은 vagrant로 진행이됩니다. 이때까지 vagrant ssh명령어가 잘 안되어서 insert_key옵션 비활성화 했었는데, 실습환경 vagrantfile을 보고 어떻게 사용하는지 이해하게 되었습니다.

 

7. 참고자료

1. [공식문서] 윈도우 컨테이너 공식문서: https://docs.microsoft.com/ko-kr/virtualization/windowscontainers/about/
2. [기업블로그] 하이퍼커넥트 컨테이너 보안: https://hyperconnect.github.io/2021/03/08/bottlerocket-on-kubernetes.html
3. [유투브] go lang으로 컨테이너 직접 만드는 과정: https://youtu.be/8fi7uSYlOdc
4. [유투브] 리눅스 프로세스: https://wiseworld.tistory.com/53
5. [유투브] 리눅스 컨테이너 생성과정: https://youtu.be/1wVpX2GyyPg

6. [블로그] 44bits-도커 컨테이너는 가상머신인가요? 프로세스인가요?: https://www.44bits.io/ko/post/is-docker-container-a-virtual-machine-or-a-process

7. [블로그] 44bits-chroot를 사용한 프로세스의 루트 디렉터리 격리: https://www.44bits.io/ko/post/change-root-directory-by-using-chroot

반응형