- 컨테이너는 호스트와 커널을 공유하므로 컨테이너의 격리는 네임스페이스, cgroups 및 시스템 강화에 따라 달라집니다.
- Podman은 중앙 루트 데몬을 사용하지 않고 루트 권한 없이 실행할 수 있도록 함으로써 기존 Docker에 비해 추가적인 보안을 제공합니다.
- Podman의 브리지, 호스트 및 루트리스 네트워크(slirp4netns, paste)를 사용하면 연결성과 격리 사이의 균형을 조정할 수 있습니다.
- KVM, 컨테이너 및 모범 사례(루트리스, MAC, 보안 컴퓨팅, 이미지 스캐닝)를 결합하여 프로덕션 환경에 적합한 강력한 플랫폼을 제공합니다.

리눅스에서 본격적인 컨테이너 환경을 구축하기 시작하면 곧바로 다음과 같은 질문이 떠오릅니다. 컨테이너에만 의존하는 것이 어느 정도까지 안전하며, 언제 KVM이나 마이크로 VM으로 업그레이드하는 것이 바람직할까요? Docker, Podman, LXC, KVM 가상 머신, 그리고 다양한 하이퍼바이저가 혼합되어 사용되는 기업 환경에서는 격리 모델에 대한 확실한 이해가 오류를 방지하는 데 핵심입니다.
또한, VirtualBox나 KVM에서 가상 머신 내에서 Docker Desktop이나 Podman을 사용하려는 경우 처럼 다소 복잡한 시나리오도 드물지 않습니다. 이러한 시나리오에서는 여러 단계의 가상화(중첩 여부와 관계없이)가 사용되며, "호스트에서 KVM이 활성화되어 있지 않습니다."와 같은 오류가 발생하기 쉽습니다. 컨테이너, 가상 머신, Podman, KVM, 네트워킹 및 보안과 같은 모든 구성 요소를 체계적으로 정리하고, 이러한 요소들을 결합하여 진정으로 안전하고 실용적인 가상화를 구현하는 방법을 살펴보겠습니다.
KVM과 가상 머신을 이용한 기존 가상화
이 전체 구성의 기반은 KVM, Xen 또는 ESXi와 같은 하이퍼바이저를 사용한 운영 체제의 완전한 가상화 입니다 . 여기서 물리적 하드웨어는 하이퍼바이저를 실행하여 머신을 여러 개의 독립적인 가상 머신으로 "분할"하는 역할을 합니다.
이 모델에서 각 가상 머신은 호스트와 완전히 분리되어 자체 커널과 게스트 운영 체제를 부팅합니다 . 하이퍼바이저(예: Linux 커널에 통합된 KVM)는 하드웨어와 가상 머신 사이의 게이트키퍼 역할을 하며, 둘 사이의 강력한 격리를 담당합니다.
일반적으로 하이퍼바이저는 두 가지 유형으로 나뉩니다. 하나는 하드웨어에서 직접 실행되는 베어메탈 하이퍼바이저(Type 1)이고, 다른 하나는 기존 운영 체제 위에 호스팅되는 하이퍼바이저(Type 2)입니다. VirtualBox나 VMware Workstation은 Type 2에 해당하며 , Linux 서버에서 libvirt로 관리되는 KVM은 호스트와 공간을 공유하더라도 Type 1에 더 가깝습니다.
이 접근 방식의 가장 큰 장점은 각 가상 머신이 커널, 사용자 공간, 서비스, 네트워크 및 스토리지 등 자체적인 완전한 스택을 갖는다는 것입니다 . 이는 상당한 유연성을 제공하며 동일한 물리적 머신에서 다양한 운영 체제와 커널 버전을 실행할 수 있게 해줍니다.
GNU/Linux에서 이러한 가상화 플랫폼을 관리하기 위해 거의 항상 libvirt가 오케스트레이션 API로 사용되며 , 이를 기반으로 그래픽 및 명령줄 도구가 지원됩니다. 또는 VM, 베어메탈 및 컨테이너를 결합하여 완전한 클라우드를 구축하는 OpenStack과 같은 대규모 프로젝트에도 사용됩니다.
KVM의 하드웨어 요구 사항 및 일반적인 문제점
KVM을 실행하거나 KVM에 의존하는 솔루션(예: 일부 Docker Desktop 또는 마이크로 VM 구성)을 사용하기 전에 프로세서가 하드웨어 가상화(Intel의 경우 VT-x, AMD의 경우 SVM/AMD-V)를 지원하고 BIOS/UEFI에서 활성화되어 있는지 확인해야 합니다.
Linux에서는 간단한 확인 절차가 있습니다. `grep -E 'svm|vmx' /proc/cpuinfo` 명령어가 아무것도 반환하지 않거나 펌웨어에서 해당 옵션이 비활성화되어 있으면 KVM이 작동하지 않습니다. 또한, 가상 머신 내부에 또 다른 가상 머신을 실행하는 중첩 가상화 환경에서는 최상위 하이퍼바이저가 게스트 OS에 해당 확장 기능을 명시적으로 노출해야 합니다.
문제가 발생하면, VirtualBox 내 RHEL 9에서 악명 높은 Docker Desktop 팝업 메시지처럼 "호스트에서 KVM이 활성화되어 있지 않습니다 ."와 같은 일반적인 메시지가 나타납니다. 이 문제의 원인은 Docker나 RHEL 자체에 있는 것이 아니라, VirtualBox VM이 KVM을 실행하는 데 필요한 가상화 확장 기능을 제대로 받지 못했기 때문입니다.
`modprobe kvm` 또는 `modprobe kvm_amd / kvm_intel` 과 같은 명령어를 실행하면 오류 메시지 없이 커널 모듈이 로드되어야 합니다. 만약 `dmesg`에 관련 내용이 없거나, `lsmod | grep kvm`을 실행했을 때 `kvm`과 `irqbypass`만 표시되고 CPU별 모듈이 누락된 경우, 하드웨어 가상화가 게스트 시스템에 노출되지 않았 거나 펌웨어에서 비활성화되었을 가능성이 매우 높습니다.
이러한 시나리오에서 게스트 운영 체제 내에서 가능한 모든 기능을 활성화했더라도 VirtualBox가 중첩 가상화를 지원하지 않거나 구성이 잘못된 경우 KVM은 제대로 작동하지 않습니다 . 해결 방법은 호스트 하이퍼바이저(VirtualBox, VMware 등)의 구성을 검토하고 중첩 가상화를 지원하는 경우 활성화하는 것입니다.
컨테이너: 운영체제 수준의 경량 가상화
기존 가상 머신과 달리 컨테이너는 다른 접근 방식을 제공합니다. 컨테이너 는 모든 하드웨어를 에뮬레이션하는 대신 호스트 커널을 재사용 하고 Linux 커널 기능을 사용하여 프로세스와 리소스를 격리합니다.
컨테이너는 기본적으로 네임스페이스와 cgroup을 사용하여 캡슐화된 프로세스 집합 입니다 . 이러한 "환경" 내에서 애플리케이션은 자체 파일 시스템, 네트워크 인터페이스 및 PID를 가진 자체 머신에서 실행되고 있다고 생각하지만, 실제로는 호스트와 커널을 공유합니다.
컨테이너는 별도의 커널이나 완전한 하드웨어 에뮬레이션이 필요 없기 때문에 네이티브에 가까운 성능을 제공합니다 . 오버헤드는 최소화되어 있으며, 네임스페이스 마운트, cgroups를 사용한 리소스 제한, 보안 정책(seccomp, AppArmor, SELinux 등) 적용에 필요한 최소한의 작업만 수행합니다.
하지만 이러한 설계에는 중대한 결과가 따릅니다. 모든 워크로드가 동일한 물리적 커널을 공유하게 되는데 , 해당 커널에 심각한 취약점이 발견될 경우 해당 노드에서 실행 중인 모든 컨테이너에 대한 잠재적인 공격 경로가 될 수 있습니다.
그렇기 때문에 컨테이너 격리는 가상 머신처럼 "절대적"이지 않다고 흔히 말합니다 . 누군가 치명적인 커널 버그를 악용하는 데 성공하면 네임스페이스는 더 이상 효과적인 장벽이 되지 못하고 컨테이너와 호스트 간의 경계가 무너질 수 있습니다.
네임스페이스와 cgroups: 컨테이너 격리의 기반
리눅스에서 컨테이너 격리는 시스템 뷰를 분리하는 네임스페이스 와 리소스를 제한하고 관리하는 cgroups라는 두 가지 주요 기둥을 기반으로 합니다.
네임스페이스는 PID, 네트워크, 마운트 지점, IPC, 호스트 이름(UTS), 사용자와 같은 요소들을 격리합니다 . 이를 통해 프로세스는 자신의 네임스페이스에 속한 프로세스, 네트워크 인터페이스, 파일 시스템, 호스트 이름만 "볼" 수 있으므로 마치 다른 시스템에 있는 것처럼 느껴집니다.
cgroups를 사용하면 컨테이너가 사용할 수 있는 CPU, 메모리, 디스크 I/O, 프로세스 수 등을 지정할 수 있습니다 . 이는 제어되지 않은 부하로 인해 호스트 전체가 과부하되는 것을 방지하며, 팀이나 프로젝트 간에 노드를 공유할 때 매우 중요합니다.
하지만 네임스페이스와 cgroup만으로는 완벽한 보안 시스템을 구축할 수 없다는 점을 이해하는 것이 중요합니다 . 네임스페이스와 cgroup만으로는 커널 취약점 악용을 막거나, 시스템 호출을 필터링하거나, 세부적인 접근 정책을 관리할 수 없습니다. 네임스페이스와 cgroup은 보안의 기반이 되지만, 추가적인 보강이 필요합니다.
환경을 강화하는 합리적인 방법은 시스템 호출 필터와 보안 보완(seccomp), MAC 정책(AppArmor 또는 SELinux)을 결합하고 프로세스 권한을 대폭 제한하는 것 입니다 . 이상적으로는 사용자 네임스페이스와 루트리스 모드를 함께 사용하여 누군가 컨테이너에서 탈출하더라도 피해를 최소화할 수 있습니다.
컨테이너 플랫폼의 보안 위협
실제 컨테이너 플랫폼에서 공격 표면은 커널 및 런타임(runc, containerd, CRI-O), 이미지 공급망, 컨테이너/오케스트레이터 구성, 그리고 기본 인프라 (클라우드, 스토리지, IAM, 네트워크) 등 여러 계층에 걸쳐 분포되어 있습니다.
일반적인 공격 벡터에는 커널 또는 컨테이너 런타임의 소프트웨어 취약점 , 안전하지 않거나 유지 관리되지 않는 이미지 사용, Kubernetes 또는 Docker 구성 오류(특권 컨테이너, 위험한 호스트 마운트, 과도하게 개방된 네트워크 모드), 레지스트리 또는 CI/CD 파이프라인의 보안 결함 등이 있습니다.
실제 사고의 경우, 단 하나의 "마법 같은 버그"가 아니라 알려진 취약점과 허술한 구성이 복합적으로 작용한 결과입니다 . 예를 들어, 컨테이너를 루트 권한으로 실행하거나, --privileged 플래그를 사용하거나, 컨테이너 내부에 호스트 파일 시스템을 마운트하거나, seccomp 또는 MAC이 없는 경우 등이 있습니다.
이 모든 것에 더해 공급망 문제도 있습니다. 공개된 기본 이미지에는 종종 CVE(보안 취약점), 오래된 패키지, 제대로 관리되지 않는 종속성이 포함되어 있습니다 . 악성코드가 침투하거나 손상된 라이브러리가 실행에 적합한 조건이 될 때까지 잠복 상태로 남아 있기가 비교적 쉽습니다.
따라서 실제 운영 환경에서는 선택 사항이 아닙니다. Trivy, Clair 또는 Grype와 같은 도구를 사용하여 이미지의 취약점을 검사하고 , 사용할 레지스트리(Harbor, Quay, GHCR 및 정책)를 제어하고, 클러스터에 배포하기 전에 이미지에 서명/검증해야 합니다.
Docker와 Podman 비교: 위협 모델에 미치는 영향
애플리케이션 컨테이너 분야에서 Docker와 Podman은 유사한 기능을 제공하지만 아키텍처가 상당히 다르며, 이로 인해 호스트에서 사용하는 보안 모델이 달라집니다 .
Docker는 기존의 루트 권한 모드에서 루트 권한으로 실행되는 중앙 데몬(dockerd) 에 의존합니다 . CLI는 /var/run/docker.sock 또는 TCP를 통해 이 데몬과 통신하며, 컨테이너를 생성 및 삭제하고, 이미지, 네트워크 및 볼륨을 관리하고, 레지스트리와 상호 작용하는 것도 바로 이 권한 있는 프로세스입니다.
이는 Docker 소켓에 접근할 수 있는 사람은 누구나 사실상 호스트에 대한 루트 권한을 갖게 된다는 것을 의미합니다 . 왜냐하면 권한이 있는 컨테이너를 실행하고, 임의의 파일 시스템을 마운트하고, 중요한 구성을 수정할 수 있기 때문입니다. 결과적으로 데몬은 단일 장애 지점이 됩니다.
반면 Podman은 데몬이 없는 컨테이너 엔진으로서, 가능한 한 리눅스에 "네이티브"한 환경을 지향 하는 아이디어에서 탄생했습니다 . 영구적인 중앙 프로세스가 없으며, 컨테이너는 사용자 또는 systemd에 의해 제어됩니다. systemd와의 통합을 통해 서비스 유닛을 통해서도 컨테이너를 제어할 수 있습니다.
이 접근 방식은 "각 프로세스는 해당 프로세스를 실행한 사용자에게 속한다"는 유닉스 모델과 더 잘 부합하며, 높은 권한을 요구하는 데몬에 의존하지 않습니다 . 또한 Podman은 Docker 명령어와의 호환성을 제공하여 마이그레이션을 간소화합니다(Docker CE를 설치하지 않으려는 환경에서는 `docker=podman`으로 별칭을 지정할 수도 있습니다).
루트리스 모드 및 사용자 네임스페이스
컨테이너 탈출 가능성의 영향을 줄이는 데 있어 주요한 실질적인 발전 중 하나는 루트리스 모드와 사용자 네임스페이스를 결합하는 것 입니다 . 이 글은 "컨테이너가 탈출하면 어떻게 될까?"라는 질문에 대한 답을 찾고자 합니다.
사용자 네임스페이스를 사용하면 컨테이너의 UID 0을 호스트의 권한이 없는 UID로 다시 매핑할 수 있습니다 . 즉, 컨테이너 내부에서 애플리케이션은 자신이 루트라고 생각하지만, 호스트 관점에서는 해당 프로세스는 실제로는 하위 UID/하위 GID 범위가 할당된 일반 사용자입니다.
이러한 방식으로 공격자가 컨테이너 내부에서 루트 권한을 획득하고 커널 또는 런타임 취약점을 이용한 공격을 성공시키더라도, 호스트로 복귀할 때는 권한이 없는 사용자 자격으로 접속하게 됩니다 . 따라서 루트 바이너리를 덮어쓰거나, 민감한 파일 시스템을 마운트하거나, 필요한 권한이 없는 장치를 조작할 수 없습니다.
Podman은 처음부터 이러한 모델을 염두에 두고 설계되었습니다. 가능한 한 기본적으로 루트 권한이 없는 컨테이너화 , 루트 권한이 없더라도 SELinux/AppArmor 및 cgroups 사용, 그리고 구조적 권한 최소화에 중점을 두었습니다.
Docker는 이제 dockerd와 컨테이너가 사용자 네임스페이스 내에 상주하는 진정한 루트리스 모드를 제공합니다 . 이는 데몬이 루트 권한을 유지했던 기존의 userns-remap 방식과는 대조적입니다. 보안 관점에서 볼 때, 이는 dockerd에 대한 취약점을 악용하여 호스트에 자동으로 루트 권한을 획득하는 것을 방지합니다.
Podman을 사용한 컨테이너 네트워크: 브리지, 호스트, macvlan 및 루트리스 인터페이스
보안 및 실제 운영에 있어 또 다른 중요한 요소는 컨테이너 네트워크 계층 입니다 . Podman은 특히 루트리스 시나리오에 중점을 두고 다양한 연결 메커니즘을 제공합니다.
Podman 4에서는 CNI 모델을 따르는 네트워크 드라이버인 netavark가 도입되어 브리지 네트워크, macvlan 등에서 컨테이너에 IP 주소를 제공합니다. netavark를 사용하면 루트 권한을 가진 컨테이너는 일반적으로 호스트의 Linux 브리지(podman0)와 연결된 "podman"이라는 네트워크에 기본적으로 연결되며, 주소 범위는 10.88.0.0/16입니다.
이 기본 브리지 네트워크는 SNAT 규칙을 통해 기본적인 인터넷 연결을 제공하며 , `-po --publish` 명령어를 사용하여 컨테이너 포트를 호스트에 노출할 수 있습니다. 이 명령어는 iptables/nftables에 DNAT 규칙을 생성합니다. Docker와의 호환성을 위해 이 네트워크는 내부 DNS 서버를 실행하지 않습니다.
또한 사용자가 정의한 브리지 네트워크를 생성 하여 컨테이너 그룹을 서로 격리하고 내부 DNS를 제공할 수 있습니다. 이를 통해 컨테이너는 자체 프라이빗 네트워크 내에서 이름으로 확인할 수 있고, 서로 접근할 수 없어야 하는 서비스를 쉽게 분리할 수 있으며, MTU, 방화벽 및 기타 기능을 더욱 세밀하게 제어할 수 있습니다.
고급 환경에서는 macvlan 또는 ipvlan 네트워크를 사용하여 컨테이너를 호스트의 물리적 네트워크에 직접 연결할 수 있습니다 . macvlan은 컨테이너 간 통신을 허용하는 반면, ipvlan은 컨테이너를 더욱 격리하는 경향이 있습니다. 이러한 옵션은 각 컨테이너가 네트워크의 다른 부분에서 실제 호스트로 인식되어야 하는 배포 환경에서 유용합니다.
루트리스 네트워크: slirp4netns 및 pasta
사용자가 루트 권한이 없는 경우 상황이 복잡해집니다. 권한이 없는 사용자는 전역 네트워크 네임스페이스를 자유롭게 수정 하거나 임의의 인터페이스를 생성할 수 없으므로 Podman은 연결을 제공하기 위해 사용자 공간 솔루션을 사용해야 합니다.
여기서 Podman rootless에서 사용하는 고전적인 메커니즘인 slirp4netns가 등장합니다 . 이 프로젝트는 컨테이너 내부에 격리된 네트워크 환경을 생성하고 커널의 slirp 모듈을 사용하여 주소 변환(NAT)을 수행함으로써 컨테이너가 호스트 네트워크를 통해 인터넷에 접근할 수 있도록 합니다.
실제로 slirp4netns는 컨테이너의 네트워크 네임스페이스 내에 TAP 인터페이스 (예: IP 10.0.2.100, 게이트웨이 10.0.2.2를 가진 tap0)를 생성하고 사용자 공간에 구현된 TCP/IP 스택을 통해 트래픽을 라우팅합니다. 이 방식은 작동하지만 약간의 오버헤드와 몇 가지 제약 사항이 있습니다.
이러한 제한 사항 중 하나는 권한이 없는 사용자는 1024 미만의 포트를 사용할 수 없다는 것입니다 . sysctl 매개변수 net.ipv4.ip_unprivileged_port_start는 권한이 없는 사용자가 사용할 수 있는 포트(기본값은 1024)를 지정하지만, 보안 모델에서 허용하는 경우 이 값을 신중하게 조정할 수 있습니다.
Podman 5에서는 기본 루트리스 메커니즘으로 slirp4netns 대신 pasta가 사용됩니다 . pasta 역시 사용자 공간에서 완전히 작동하지만, tap 인터페이스와 제로 카피 기술 덕분에 네이티브 네트워크 성능에 가까운 성능을 제공하여 slirp4netns에 비해 지연 시간과 처리량에 미치는 영향을 줄입니다.
루트리스 컨테이너에서 브리지 및 호스트 네트워크를 구현합니다.
루트 권한이 없는 모드에서도 `--network=podman` 옵션을 사용하여 루트 권한이 없는 컨테이너를 기본 "podman" 브리지 네트워크에 연결할 수 있습니다 . 이렇게 하면 루트 권한 모드에서와 마찬가지로 `-p` 옵션을 통해 netavark의 기능을 활용하여 포트를 호스트에 매핑할 수 있습니다.
루트 권한이 없는 환경에서도 사용자 정의 브리지 네트워크를 생성할 수 있습니다 . 이 경우 브리지와 연결된 장치는 호스트의 전역 네트워크 네임스페이스가 아닌 사용자 네임스페이스에 생성되므로, `sudo ip a` 명령으로는 호스트에서 이러한 인터페이스에 접근할 수 없습니다.
이러한 루트리스 브리지를 검사하기 위해 Podman은 `podman unshare --rootless-netns` 명령어를 제공합니다 . 이 명령어는 사용자의 네트워크 네임스페이스에 셸을 열어줍니다. 셸에서 내부 브리지를 관찰하고 컨테이너와의 직접 연결을 확인할 수 있습니다.
이러한 고립은 흥미로운 효과를 가져온다. 호스트에서 루트 권한이 없는 컨테이너의 IP 주소로 직접 연결되지 않을 수 있습니다.하지만 호스트 자체의 IP 주소에 매핑된 포트를 사용하면 제대로 작동하며, 이 포트가 서비스의 진입점 역할을 합니다.
컨테이너 간 통신을 위해 사용자 정의 브리지 네트워크에 통합된 DNS 서버를 통해 컨테이너들이 이름으로 통신할 수 있으므로 분산 애플리케이션 구성이 크게 간소화됩니다.
반대쪽 끝에는 호스트 네트워크(--network=host)가 있는데 , 이 경우 컨테이너는 자체 IP 주소 없이 호스트와 네트워크 스택을 공유합니다. 이 모드에서 루트가 없는 컨테이너가 8080/tcp 포트에서 서버를 시작하면 해당 서비스는 호스트의 8080 포트에서 직접 사용할 수 있으므로 포트 매핑은 필요 없지만 격리 수준은 떨어집니다.
Podman 데스크톱, 이미지 처리 도구 및 로컬 오케스트레이션
시각적인 환경을 선호하는 사용자를 위해 Podman Desktop은 개발 환경에서 컨테이너, 파드, 이미지 및 네트워크 구성을 관리할 수 있는 그래픽 환경을 제공하며, Docker Desktop의 직접적인 대안이 될 수 있지만 데몬이 필요 없는 엔진을 사용합니다.
이미지는 `podman pull` 명령어를 사용하여 가져오며 , 이 명령어는 `/etc/containers/registries.conf`에 정의된 레지스트리에서 다운로드합니다 . 레지스트리 이름을 지정하지 않고 이미지를 지정하면 Podman은 기본적으로 `latest` 태그를 사용하여 구성된 레지스트리 순서 내에서 이미지를 찾으려고 시도합니다.
Podman CLI 외에도 skopeo를 전용 도구로 사용하여 레지스트리와 로컬 저장소 간의 이미지 관리, 검사 및 복사를 수행할 수 있습니다. copy, delete, sync와 같은 명령어를 통해 저장소 간 동기화를 자동화하고, 가비지 컬렉션 대상 이미지를 표시하고, 환경 간에 아티팩트를 이동할 수 있습니다.
이미지 다운로드가 완료되면 `podman run` 명령어를 사용하여 전송 방식과 경로(기본값은 Docker 전송 방식이며 구성된 레지스트리에서 검색)를 지정하여 컨테이너를 시작할 수 있습니다 . 일반적인 옵션(-d, -p, --name, --pod 등)은 실습 환경과 실제 배포 환경 모두에 사용할 수 있습니다.
일상적인 관리는 `podman ps` 명령으로 컨테이너 목록을 확인하고, `podman stop/start` 명령으로 기존 인스턴스를 중지 또는 시작하며, `podman rm` 명령으로 중지된 컨테이너를 삭제하는 방식으로 완료됩니다 . 컨테이너를 수정하고 새 이미지로 변환하려면 `podman commit` 명령을 사용하여 변경 사항을 새 이름으로 저장합니다.
Podman을 사용한 Pod 및 고급 실행 모델
Kubernetes에서 영감을 받은 Podman은 동일한 네트워크 스택과 특정 리소스를 공유하는 컨테이너들을 Pod로 그룹화할 수 있도록 해줍니다 . 이는 데이터베이스와 클라이언트, 또는 낮은 지연 시간으로 통신해야 하는 여러 마이크로서비스와 같은 구성에 이상적인 패턴입니다.
`podman pod create` 명령은 새로운 파드를 생성 하고 해당 파드의 ID를 반환하지만, 기본적으로 파드는 연결된 컨테이너가 시작되거나 `podman pod start` 명령으로 명시적으로 시작될 때까지 중지된 상태로 유지됩니다.
시스템에 어떤 파드가 있는지 확인하려면 `podman pod ls` 명령어를 사용하세요 . 이 명령어는 각 파드와 연결된 INFRA 컨테이너도 함께 표시합니다. 이 특수 컨테이너는 파드의 네트워크 및 기타 공유 리소스를 계속 실행 상태로 유지하므로 컨테이너 수는 절대 0이 되지 않습니다.
Podman은 전체 Pod를 시작, 중지 또는 재시작하는 특정 명령(podman pod start/stop/restart)을 제공 하지만, 나머지 Pod를 수정하지 않고 Pod 내의 특정 컨테이너에만 작업을 수행하여 애플리케이션 수준에서 프로세스 격리를 유지할 수도 있습니다.
기존 파드에 컨테이너를 추가하려면 개별 컨테이너를 추가할 때와 동일한 구문을 사용하여 `podman run --pod POD_NAME` 명령을 실행하세요 . 파드 멤버십은 파드의 수명 주기와 연결되어 있으므로 파드를 삭제하지 않고는 파드에서 컨테이너를 제거할 수 없습니다.
모니터링은 `podman ps –pod` 명령이나 특정 명령어를 사용하여 모든 파드의 모든 컨테이너 프로세스를 모니터링함으로써 완료할 수 있으며 , 이를 통해 어떤 프로세스가 어떤 그룹에 속하는지, 서비스가 어떻게 분산되어 있는지를 신속하게 파악할 수 있습니다.
컨테이너, LXC 및 애플리케이션 가상화
Docker와 Podman이 컨테이너화에 대한 논의를 주도하고 있지만, GNU/Linux에서 사용할 수 있는 유일한 컨테이너화 옵션은 아닙니다 . LXC/LXD, systemd-nspawn, Kata Containers와 같은 솔루션들은 각기 다른 접근 방식으로 문제를 해결합니다.
LXC는 자체 호스트 이름, IP 주소, 파일 시스템 및 완벽한 초기화 시스템을 갖춘 매우 가벼운 시스템 컨테이너를 제공합니다 . 컨테이너 및 VM용 하이퍼바이저 역할을 하는 LXD와 결합하면 거의 베어메탈 수준의 성능을 가진 여러 대의 경량 머신을 사용하는 것과 매우 유사한 환경을 제공합니다.
Docker/Podman이 OCI 규격을 준수하는 애플리케이션 컨테이너 에 초점을 맞추는 반면 , LXC는 여러 서비스와 프로세스가 있는 영구적인 환경이 필요할 때 빛을 발합니다. LXC는 VM처럼 동작하지만 오버헤드가 적고 Linux 커널과 매우 자연스럽게 통합됩니다.
성능 측면에서 LXC는 데이터 집약적인 엔터프라이즈 애플리케이션을 거의 성능 저하 없이 실행할 수 있으므로 , 기존 VM처럼 강력한 격리가 필요하지 않은 지연 시간에 민감한 워크로드에 적합한 강력한 선택입니다.
이와 더불어, Kata Containers처럼 각 Pod를 자체 커널을 가진 소형 가상 머신 내에서 실행하는 기술이나, gVisor처럼 애플리케이션과 Linux 사이에 Go 언어로 작성된 "커널 샌드박스"를 삽입하는 기술 등 마이크로 VM 및 향상된 격리 기능을 지향하는 기술들도 주목받고 있습니다. 이 두 기술 모두 공유 커널에 대한 의존성을 줄이고 VM의 보안 모델에 더 가까워지면서도 컨테이너의 사용자 친화성을 유지합니다.
Docker 및 Podman 보안 강화를 위한 모범 사례
위에서 언급한 모든 내용을 고려할 때, 견고한 컨테이너 플랫폼을 구축하는 합리적인 접근 방식은 계층별로 작업하는 것입니다. 즉, 네임스페이스/cgroup을 사용한 세분화, seccomp 및 MAC을 사용한 필터링 정책, 그리고 루트리스 모드를 통한 구조적 권한 제한을 적용하는 것입니다.
실제로, 특히 멀티테넌트 환경이나 공유 클라우드 환경에서는 가능한 한 루트 권한이 없는 모드로 컨테이너를 실행 하는 것이 좋습니다 . Podman은 기본적으로 이를 지원하며, Docker rootless 또한 호환성이 필요한 경우 동일한 방식을 제공합니다.
호스트 커널은 보안 패치로 최신 상태를 유지 해야 합니다 . Dirty COW, Dirty Pipe 등의 취약점은 업데이트를 통해 해결되며, 컨테이너 외부 침투를 막으려면 이러한 업데이트를 비교적 신속하게 적용해야 합니다.
또 다른 매우 효과적인 방법은 openSUSE MicroOS나 Flatcar Linux와 같은 불변의 컨테이너 기반 배포판을 사용하는 것입니다 . 이러한 배포판은 읽기 전용 루트와 원자적 업데이트 시스템을 통해 공격 표면을 크게 줄이고 패치 후 문제가 발생할 경우 롤백을 용이하게 합니다.
구성과 관련하여: 극히 제한적인 경우를 제외하고는 프로덕션 환경에서 권한 있는 컨테이너를 사용하지 마십시오 . 컨테이너 내부에서 루트 권한으로 애플리케이션을 실행하지 마십시오. 가능한 한 읽기 전용 파일 시스템을 사용하고, 기능을 최소한으로 제한하십시오. 애플리케이션의 실제 호출에 맞춘 SELinux/AppArmor 및 seccomp 프로파일은 사실상 필수적입니다.
마지막으로 런타임 모니터링 측면을 간과해서는 안 됩니다 . Falco, Sysdig Secure 또는 Aqua와 같은 도구는 이상 징후, 탈출 시도(예: /proc 또는 /sys에 대한 비정상적인 접근), 비정상적인 네트워크 트래픽 또는 의심스러운 명령을 감지하여 공격이 발생하기 전에 대응할 시간을 제공합니다.
기존 가상화 방식에 KVM, Podman으로 관리되는 컨테이너(가급적 루트리스 모드), 잘 분할된 네트워크, 그리고 우수한 보안 강화 방식을 결합하면 매우 유연하고 안전한 가상화 플랫폼을 구축할 수 있습니다. 공유 커널이 가장 중요한 요소라는 점을 이해하고, 위험이나 규정 준수 요구 사항에 따라 가상 머신(VM) 또는 마이크로 VM을 활용하며, 이미지 공급망을 신중하게 관리하는 것이 연구실 환경과 실제 운영 환경에 적합한 인프라를 구분하는 핵심입니다.