Commit ea39025a authored by insun park's avatar insun park
Browse files

docker-window-vm에 대한 READMD.md 수정

parent 38d93380
### Docker-KVM 기반 Windows VM 동작 원리 및 설정 과정 분석
# Docker-KVM 기반 Windows VM 서버 구축 가이드
#### 1. 개요
## 📋 목차
1. [시스템 개요](#시스템-개요)
2. [아키텍처 상세 분석](#아키텍처-상세-분석)
3. [기술 스택 및 구성 요소](#기술-스택-및-구성-요소)
4. [설치 및 배포 과정](#설치-및-배포-과정)
5. [네트워크 구성 및 포트 포워딩](#네트워크-구성-및-포트-포워딩)
6. [보안 설정 및 방화벽 구성](#보안-설정-및-방화벽-구성)
7. [문제 해결 및 트러블슈팅](#문제-해결-및-트러블슈팅)
8. [성능 최적화](#성능-최적화)
9. [모니터링 및 유지보수](#모니터링-및-유지보수)
이 시스템은 Docker 컨테이너 내부에 KVM(Kernel-based Virtual Machine) 하이퍼바이저를 설치하고, 그 위에 Vagrant를 사용하여 Windows 10 가상 머신을 구동하는 복합적인 가상화 구조입니다. 사용자는 최종적으로 RDP(원격 데스크톱 프로토콜)를 통해 Docker 외부에서 이 Windows VM에 접속할 수 있습니다.
## 🎯 시스템 개요
문서의 목표는 `docker-compose up` 명령부터 최종 RDP 접속까지의 전 과정을 단계별로 설명하고, 우리가 겪었던 네트워크 문제의 원인과 해결책을 명확히 이해하는 것입니다.
시스템은 **Docker 컨테이너 내부에 KVM(Kernel-based Virtual Machine) 하이퍼바이저를 설치**하고, **Vagrant를 사용하여 Windows 10 가상 머신을 구동**하는 복합적인 가상화 구조입니다.
#### 2. 전체 아키텍처
### 주요 특징
- **3단계 가상화**: Docker → KVM → Windows VM
- **원격 접속**: RDP(Remote Desktop Protocol)를 통한 외부 접속 지원
- **자동화된 배포**: Docker Compose를 통한 원클릭 배포
- **네트워크 격리**: 컨테이너 레벨의 네트워크 격리 및 포트 포워딩
### 사용 사례
- 개발 환경 격리
- Windows 애플리케이션 테스트
- 교육용 가상 머신 제공
- 크로스 플랫폼 개발 환경
## 🏗️ 아키텍처 상세 분석
### 전체 시스템 아키텍처
```mermaid
graph TD;
subgraph 사용자 PC
A[RDP 클라이언트]
graph TB
subgraph "외부 네트워크"
A[RDP 클라이언트<br/>192.168.1.100]
B[HTTP 클라이언트<br/>192.168.1.101]
end
subgraph 외부 네트워크
B(Host IP:33890)
subgraph "호스트 서버 (Ubuntu 20.04)"
C[iptables FORWARD Chain<br/>기본 정책: DROP]
D[Docker 데몬<br/>포트 매핑: 33890→3389]
E[호스트 네트워크<br/>eth0: 192.168.1.10]
end
subgraph "Docker 호스트 (Server)"
C{Host iptables<br/>FORWARD Chain}
D[Docker 데몬]
subgraph "Docker 컨테이너 (Ubuntu)"
E[libvirtd 데몬]
F[Vagrant]
G[Container iptables]
subgraph "Docker 컨테이너 (Ubuntu 20.04)"
F[libvirtd 데몬<br/>가상화 관리]
G[Vagrant<br/>VM 오케스트레이션]
H[컨테이너 iptables<br/>NAT 규칙]
I[가상 네트워크<br/>virbr0: 192.168.121.0/24]
end
subgraph "KVM 가상 머신"
H[Windows 10 VM<br/>Internal IP: 192.168.121.x<br/>RDP Port: 3389]
end
J[Windows 10 Enterprise<br/>IP: 192.168.121.251<br/>RDP: 3389<br/>HTTP: 8090]
K[Chocolatey 패키지 매니저]
L[Java 17 Runtime]
end
A -->|RDP:33890| C
B -->|HTTP:8081| C
C -->|FORWARD 규칙| D
D -->|포트 포워딩| H
H -->|NAT 변환| J
F -->|VM 관리| J
G -->|VM 생성/관리| J
```
### 네트워크 플로우 상세
```mermaid
sequenceDiagram
participant Client as RDP 클라이언트
participant Host as 호스트 서버
participant Docker as Docker 데몬
participant Container as 컨테이너
participant VM as Windows VM
Client->>Host: RDP 연결 요청 (33890)
Host->>Host: iptables PREROUTING 체인
Host->>Docker: DNAT: 33890 → 3389
Docker->>Container: 포트 포워딩
Container->>Container: iptables NAT 규칙
Container->>VM: 최종 전달 (192.168.121.251:3389)
VM->>Container: RDP 응답
Container->>Docker: 응답 전달
Docker->>Host: 응답 전달
Host->>Client: RDP 세션 수립
```
## 🔧 기술 스택 및 구성 요소
### 1. 컨테이너 기술
- **Docker**: 애플리케이션 컨테이너화
- **Docker Compose**: 멀티 컨테이너 오케스트레이션
- **Ubuntu 20.04**: 베이스 운영체제
### 2. 가상화 기술
- **KVM (Kernel-based Virtual Machine)**: 하이퍼바이저
- **QEMU**: 하드웨어 에뮬레이션
- **libvirt**: 가상화 관리 라이브러리
- **Vagrant**: VM 오케스트레이션 도구
### 3. 네트워크 기술
- **iptables**: 방화벽 및 NAT
- **bridge-utils**: 네트워크 브리지 관리
- **virbr0**: libvirt 기본 브리지 네트워크
### 4. 원격 접속 기술
- **RDP (Remote Desktop Protocol)**: Windows 원격 데스크톱
- **SSH**: 컨테이너 관리 접속
## 📦 설치 및 배포 과정
### 1. 사전 요구사항
```bash
# 호스트 서버 요구사항
- Ubuntu 20.04 LTS 이상
- Docker 및 Docker Compose 설치
- KVM 하드웨어 가상화 지원 (Intel VT-x/AMD-V)
- 최소 16GB RAM (VM용 8GB + 시스템용 8GB)
- 최소 50GB 디스크 공간
```
### 2. Docker 이미지 빌드 과정
```dockerfile
# Dockerfile 주요 단계별 분석
# 1단계: 베이스 이미지 설정
FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
# 2단계: 가상화 패키지 설치
RUN apt-get install -y qemu-kvm libvirt-daemon-system libvirt-clients \
bridge-utils virt-manager wget unzip gnupg kmod openssh-client net-tools
# 3단계: Vagrant 설치
RUN wget https://releases.hashicorp.com/vagrant/2.4.6/vagrant_2.4.6-1_amd64.deb && \
apt-get install -y ./vagrant_2.4.6-1_amd64.deb
# 4단계: vagrant-libvirt 플러그인 설치
RUN vagrant plugin install vagrant-libvirt
# 5단계: Windows 10 Vagrant Box 다운로드
RUN vagrant box add peru/windows-10-enterprise-x64-eval --provider libvirt
```
### 3. 컨테이너 실행 설정
```yaml
# docker-compose.yml 주요 설정 분석
services:
win10-kvm:
build: .
privileged: true # KVM 접근 권한
security_opt:
- "apparmor:unconfined" # 보안 제한 해제
cap_add:
- NET_ADMIN # 네트워크 관리 권한
devices:
- /dev/kvm # KVM 디바이스 접근
- /dev/net/tun # TUN 디바이스 접근
ports:
- "33890:3389" # RDP 포트 포워딩
- "8081:8090" # HTTP 포트 포워딩
volumes:
- /lib/modules:/lib/modules:ro # 커널 모듈 공유
```
### 4. VM 구성 설정
```ruby
# Vagrantfile 주요 설정 분석
Vagrant.configure("2") do |config|
config.vm.box = "peru/windows-10-enterprise-x64-eval"
config.vm.provider "libvirt" do |libvirt|
libvirt.memory = 8192 # 8GB 메모리 할당
libvirt.cpus = 4 # 4개 CPU 코어 할당
end
A --"1. RDP 접속 시도"--> B;
B --"2. 호스트 도착"--> C;
C --"3. 방화벽 통과"--> D;
D --"4. 포트 포워딩<br/>(33890 -> 3389)"--> G;
G --"5. 내부 포워딩<br/>(Container:3389 -> VM:3389)"--> H;
# Windows VM 초기 설정 스크립트
config.vm.provision "shell", inline: <<-SHELL
# Chocolatey 패키지 매니저 설치
# Java 17 런타임 설치
# 기타 필요한 소프트웨어 설치
SHELL
end
```
#### 3. 단계별 동작 과정
#### Vagrant 역할 및 동작 방식
1. **`docker-compose up` - 컨테이너 생성**
* `Dockerfile`에 정의된 대로 Ubuntu 20.04 이미지를 기반으로 새로운 컨테이너가 생성됩니다.
* 컨테이너 내부에 `apt-get`을 통해 `qemu-kvm`, `libvirt`, `vagrant` 등 VM을 구동하는 데 필요한 모든 소프트웨어가 설치됩니다. 이 시점에서 컨테이너는 그 자체로 하나의 작은 "가상화 서버"가 됩니다.
* `docker-compose.yml``ports: - "33890:3389"` 설정에 따라 Docker는 호스트의 `33890`번 포트로 들어오는 모든 요청을 컨테이너의 `3389`번 포트로 전달하도록 **호스트의 `iptables`에 `DNAT` 규칙을 자동으로 추가**합니다.
**Vagrant**는 이 프로젝트에서 Windows 10 VM의 생성, 구성, 관리를 자동화하는 핵심적인 **오케스트레이션 도구**입니다. 개발자가 코드로 가상 환경을 정의하고, 명령어 하나로 일관된 개발 환경을 구축할 수 있게 해줍니다.
2. **`startup.sh` - VM 부팅 및 내부 설정**
* 컨테이너가 시작되면 `startup.sh` 스크립트가 실행됩니다.
* **libvirt 데몬 실행:** KVM 가상 머신을 관리하는 `libvirtd` 서비스를 활성화합니다.
* **`vagrant up` 실행:** Vagrant가 `Vagrantfile`의 내용을 읽어 Windows 10 VM을 생성하고 부팅합니다.
* `vagrant-libvirt` 플러그인을 사용하여 KVM 위에서 VM을 동작시킵니다.
* 부팅이 완료되면 VM은 `libvirt`가 만든 내부 가상 네트워크(예: `192.168.121.0/24`)로부터 IP 주소(예: `192.168.121.251`)를 할당받습니다.
* **컨테이너 내부 RDP 포워딩 설정:** 스크립트는 VM의 IP를 알아낸 뒤, **컨테이너의 `iptables`**를 사용하여 컨테이너의 3389 포트로 들어온 요청을 Windows VM의 IP와 3389 포트로 전달하는 `DNAT` 규칙을 추가합니다.
- **`Vagrantfile`**:
- `Vagrantfile`은 VM을 어떻게 설정할지를 정의하는 **설계도**와 같습니다. 루비(Ruby) 구문으로 작성됩니다.
- **`config.vm.box`**: VM을 생성할 때 기반이 되는 "Box" 이미지를 지정합니다. 여기서는 `peru/windows-10-enterprise-x64-eval`를 사용하여 사전 설치된 Windows 10 이미지를 다운로드합니다.
- **`config.vm.provider`**: VM을 실행할 가상화 기술(Provider)을 지정합니다. `libvirt`를 명시하여 KVM을 사용하도록 설정합니다.
- **자원 할당**: VM에 할당할 메모리(`libvirt.memory`)와 CPU 코어 수(`libvirt.cpus`)를 정의합니다.
#### 4. 우리가 마주했던 문제와 해결 과정
- **`vagrant-libvirt` 플러그인**:
- Vagrant는 플러그인 아키텍처를 통해 VirtualBox, VMware, Hyper-V 등 다양한 가상화 기술을 지원합니다.
- 이 프로젝트에서는 `vagrant-libvirt` 플러그인을 사용하여 Vagrant가 `libvirt` API를 통해 KVM/QEMU를 제어할 수 있도록 합니다. 이 플러그인은 `Dockerfile`에서 `vagrant plugin install` 명령어로 설치됩니다.
모든 설정이 자동화된 것 같았지만, 우리는 RDP 접속에 실패했습니다. `nmap` 스캔 결과 포트가 `closed` 또는 `filtered` 상태로 나타났습니다.
- **프로비저닝 (Provisioning)**:
- `config.vm.provision "shell"` 블록은 VM이 처음 생성되고 부팅될 때 **자동으로 실행되는 스크립트**입니다.
- 여기서는 PowerShell 스크립트를 인라인으로 전달하여, Windows VM 내부에 **Chocolatey 패키지 매니저****Java 17**을 자동으로 설치합니다. 이를 통해 수동 개입 없이 필요한 소프트웨어가 설치된 환경을 구성할 수 있습니다.
**핵심 원인: 호스트 방화벽의 `FORWARD` 체인 정책**
- **워크플로우 (`vagrant up`)**:
- `startup.sh` 스크립트 내에서 `vagrant up` 명령어가 실행되면, Vagrant는 현재 디렉터리의 `Vagrantfile`을 읽어 다음 작업을 순차적으로 수행합니다.
1. `peru/windows-10-enterprise-x64-eval` Box가 로컬에 없으면 다운로드합니다.
2. `libvirt` 프로바이더를 통해 KVM 상에 새로운 VM을 생성합니다.
3. `Vagrantfile`에 정의된 메모리와 CPU를 할당합니다.
4. VM을 부팅합니다.
5. 부팅이 완료되면 프로비저닝 스크립트를 실행하여 소프트웨어를 설치합니다.
- `iptables`에는 여러 '체인(chain)'이 있으며, 패킷은 정해진 순서대로 체인을 통과하며 검사를 받습니다.
- **`INPUT` 체인:** 호스트 자신에게 들어오는 패킷을 처리합니다.
- **`FORWARD` 체인:** 호스트를 거쳐 다른 곳(우리의 경우, Docker 컨테이너)으로 **전달되는** 패킷을 처리합니다.
- 보안이 강화된 서버는 외부에서 들어온 패킷이 내부망으로 전달되는 것을 막기 위해 **`FORWARD` 체인의 기본 정책을 `DROP`(모두 차단)으로 설정**하는 경우가 많습니다. 저희 서버가 바로 이 경우였습니다.
## 🌐 네트워크 구성 및 포트 포워딩
Docker는 `FORWARD` 정책이 `DROP`일 것을 대비하여 자동으로 예외 규칙을 추가해주지 않습니다. 따라서 `33890` 포트로 들어온 패킷이 `DNAT`되어 컨테이너로 전달되려 할 때, `FORWARD` 체인의 `DROP` 정책에 의해 그냥 버려지고 있었던 것입니다.
### 1. 네트워크 주소 변환 (NAT) 구조
**잘못된 시도와 그 이유**
```bash
# 1차 NAT (호스트 레벨)
외부 IP:33890 → 컨테이너 IP:3389
외부 IP:8081 → 컨테이너 IP:8090
# 2차 NAT (컨테이너 레벨)
컨테이너 IP:3389 → VM IP:192.168.121.251:3389
컨테이너 IP:8090 → VM IP:192.168.121.251:8090
```
1. **`startup.sh`에서 호스트 방화벽 수정 시도:** `startup.sh`는 컨테이너 안에서 실행되므로, 보안상 격리된 컨테이너가 호스트의 방화벽 규칙을 수정할 수 없어 실패했습니다.
2. **`--dport 33890` 규칙 추가:** `FORWARD` 체인에서 `--dport 33890` 규칙으로 패킷을 잡으려 했지만, 패킷이 `FORWARD` 체인에 도달하기 전에 `PREROUTING` 체인에서 이미 목적지 포트가 컨테이너의 포트인 `3389``DNAT`된 후였습니다. 따라서 조건이 맞지 않아 규칙이 동작하지 않았습니다.
### 2. iptables 규칙 상세 분석
```bash
# 컨테이너 내부 NAT 규칙 (startup.sh)
iptables -t nat -A PREROUTING -p tcp --dport 3389 -j DNAT --to-destination "$VM_IP":3389
iptables -t nat -A POSTROUTING -j MASQUERADE
# FORWARD 체인 규칙
iptables -I FORWARD -d "$VM_IP" -p tcp --dport 3389 -j ACCEPT
iptables -I FORWARD -s "$VM_IP" -j ACCEPT
```
### 3. 네트워크 인터페이스 구성
```bash
# 호스트 네트워크 인터페이스
eth0: 192.168.1.10/24 (외부 네트워크)
# 컨테이너 네트워크 인터페이스
docker0: 172.17.0.1/16 (Docker 브리지)
eth0: 172.17.0.2/16 (컨테이너 내부)
# VM 네트워크 인터페이스
virbr0: 192.168.121.1/24 (libvirt 브리지)
vnet1: 192.168.121.251/24 (VM 내부)
```
## 🔒 보안 설정 및 방화벽 구성
### 1. 컨테이너 보안 설정
```yaml
# Docker 보안 옵션
security_opt:
- "apparmor:unconfined" # AppArmor 프로파일 비활성화
cap_add:
- NET_ADMIN # 네트워크 관리 권한
- SYS_ADMIN # 시스템 관리 권한 (필요시)
```
### 2. 호스트 방화벽 구성
```bash
# 호스트 iptables 규칙 (문제 해결용)
iptables -I DOCKER-USER -d 172.17.0.2 -p tcp --dport 3389 -j ACCEPT
iptables -I DOCKER-USER -d 172.17.0.2 -p tcp --dport 8090 -j ACCEPT
# 규칙 영구 저장
apt-get install iptables-persistent
netfilter-persistent save
```
**최종 해결책**
### 3. 네트워크 격리 및 보안
```bash
# libvirt 네트워크 격리
virsh net-list --all
virsh net-info default
# VM 네트워크 설정
virsh domifaddr win10_default
```
## 🛠️ 문제 해결 및 트러블슈팅
### 1. 일반적인 문제 및 해결책
#### RDP 연결 실패
```bash
# 문제 진단
nmap -p 33890 192.168.1.10
telnet 192.168.1.10 33890
# 해결책: 호스트 방화벽 규칙 추가
iptables -I DOCKER-USER -d 172.17.0.2 -p tcp --dport 3389 -j ACCEPT
```
#### VM 부팅 실패
```bash
# libvirt 로그 확인
virsh list --all
virsh domstate win10_default
journalctl -u libvirtd
# 해결책: KVM 모듈 로드
modprobe kvm
modprobe kvm_intel # Intel CPU
modprobe kvm_amd # AMD CPU
```
#### 네트워크 연결 문제
```bash
# VM IP 확인
virsh domifaddr win10_default
# 네트워크 브리지 확인
brctl show
ip addr show virbr0
# 해결책: 네트워크 재시작
virsh net-destroy default
virsh net-start default
```
### 2. 성능 문제 해결
```bash
# CPU 사용률 모니터링
top -p $(pgrep qemu)
# 메모리 사용률 확인
free -h
virsh dominfo win10_default
# 디스크 I/O 모니터링
iostat -x 1
```
### 3. 로그 분석
```bash
# Docker 로그
docker logs win10-container
# libvirt 로그
tail -f /var/log/libvirt/libvirtd.log
# VM 콘솔 접속
virsh console win10_default
```
## ⚡ 성능 최적화
### 1. VM 성능 최적화
```ruby
# Vagrantfile 성능 설정
config.vm.provider "libvirt" do |libvirt|
libvirt.memory = 8192
libvirt.cpus = 4
libvirt.cpu_mode = "host-passthrough" # CPU 패스스루
libvirt.disk_bus = "virtio" # VirtIO 디스크
libvirt.nic_model_type = "virtio" # VirtIO 네트워크
end
```
### 2. 호스트 시스템 최적화
```bash
# CPU 성능 모드 설정
cpupower frequency-set -g performance
# 메모리 스왑 비활성화
swapoff -a
# I/O 스케줄러 최적화
echo 'ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="none"' > /etc/udev/rules.d/60-ioschedulers.rules
```
### 3. 네트워크 성능 최적화
```bash
# 네트워크 버퍼 크기 증가
echo 'net.core.rmem_max = 16777216' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 16777216' >> /etc/sysctl.conf
sysctl -p
```
## 📊 모니터링 및 유지보수
### 1. 시스템 모니터링
```bash
# 리소스 사용률 모니터링 스크립트
#!/bin/bash
echo "=== System Resources ==="
echo "CPU Usage: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')"
echo "Memory Usage: $(free -h | grep Mem | awk '{print $3"/"$2}')"
echo "Disk Usage: $(df -h / | tail -1 | awk '{print $5}')"
echo "=== VM Status ==="
virsh list --all
virsh dominfo win10_default
```
### 2. 백업 및 복구
```bash
# VM 스냅샷 생성
virsh snapshot-create-as win10_default backup-$(date +%Y%m%d)
# VM 스냅샷 복원
virsh snapshot-revert win10_default backup-20231201
# 전체 VM 백업
virsh dumpxml win10_default > win10_backup.xml
```
### 3. 정기 유지보수
```bash
# 주간 유지보수 스크립트
#!/bin/bash
# 1. 시스템 업데이트
apt-get update && apt-get upgrade -y
# 2. Docker 이미지 정리
docker system prune -f
# 3. VM 상태 확인
virsh list --all
# 4. 로그 파일 정리
find /var/log -name "*.log" -mtime +7 -delete
```
1. **올바른 규칙 추가:** `FORWARD` 체인에서는 이미 `DNAT`가 끝난 상태이므로, 변환된 후의 **최종 목적지(컨테이너 IP와 포트)**를 기준으로 규칙을 만들어야 했습니다.
```bash
iptables -I DOCKER-USER -d 172.29.0.2 -p tcp --dport 3389 -j ACCEPT
```
이 규칙은 "최종 목적지가 `172.29.0.2``3389` 포트인 TCP 패킷은 `DOCKER-USER` 체인을 통과시켜라" 라는 의미입니다. `DOCKER-USER` 체인은 `FORWARD` 체인의 맨 앞에서 호출되므로, 기본 `DROP` 정책보다 먼저 이 규칙이 적용되어 패킷이 통과될 수 있었습니다.
## 📝 결론
2. **규칙 영구 저장:** 이 규칙은 호스트에 설정되어야 하는 "사전 환경 조건"이므로, `docker-compose`와는 별개로 호스트에 직접 추가해야 했습니다. `iptables-persistent` 패키지를 설치하고 `netfilter-persistent save` 명령어로 규칙을 영구 저장하여, 서버가 재부팅되어도 설정이 유지되도록 만들었습니다.
이 Docker-KVM 기반 Windows VM 시스템은 **복잡한 가상화 계층**을 통해 격리된 Windows 환경을 제공합니다.
#### 5. 결론
### 주요 성과
-**완전한 격리**: Docker 컨테이너 내부에서 Windows VM 실행
-**자동화된 배포**: Docker Compose를 통한 원클릭 배포
-**원격 접속**: RDP를 통한 외부 접속 지원
-**네트워크 격리**: 다단계 NAT를 통한 보안 강화
이 시스템은 **두 단계의 네트워크 주소 변환(NAT)****두 개의 방화벽(호스트, 컨테이너)**이 중첩된 복잡한 구조입니다.
### 기술적 도전과 해결
- 🔧 **복합 가상화**: Docker + KVM + Windows VM의 3단계 구조
- 🔧 **네트워크 복잡성**: 다단계 NAT 및 방화벽 규칙 관리
- 🔧 **성능 최적화**: 가상화 오버헤드 최소화
- **1차 NAT (호스트):** 외부 IP:33890 -> 컨테이너 IP:3389
- **2차 NAT (컨테이너):** 컨테이너 IP:3389 -> VM IP:3389
### 향후 개선 방향
- 🚀 **GPU 패스스루**: CUDA/OpenCL 지원
- 🚀 **스냅샷 관리**: 자동화된 백업 및 복구
- 🚀 **모니터링 대시보드**: 실시간 리소스 모니터링
- 🚀 **멀티 VM 지원**: 여러 Windows VM 동시 실행
문제 해결의 핵심은 패킷의 흐름을 정확히 이해하고, 각 단계에서 어떤 방화벽(체인)이 패킷을 검사하는지, 그리고 그 시점에 패킷의 목적지 주소가 무엇인지를 파악하는 것이었습니다. 최종적으로 호스트의 `FORWARD` 정책이라는 근본 원인을 찾아내고, 그에 맞는 정확한 `iptables` 규칙을 **올바른 위치(호스트)에** 추가함으로써 문제를 해결할 수 있었습니다.
\ No newline at end of file
이 시스템은 **현대적인 가상화 기술의 집약체**로서, 개발 환경 격리부터 교육용 플랫폼까지 다양한 용도로 활용할 수 있는 강력한 솔루션입니다.
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment