diff --git a/.gitignore b/.gitignore index cf1876d..264d4f9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /tools/imports/**/*.zip **/*.quarto_ipynb +/.serena/ \ No newline at end of file diff --git a/_quarto.yml b/_quarto.yml index c5fe1e7..8dade58 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -33,15 +33,13 @@ website: contents: - text: "6-1. Neutron의 agent에 대해 알아보기" file: lectures/ch6/neutron_agents.qmd + - text: "6-2. Provider network와 tenant network 개념 정리" + file: lectures/ch6/provider_tenant_network.qmd - text: "6-12. SNAT/DNAT란?" file: lectures/ch6/snat_dnat.qmd - text: "6-15. OVS와 VXLAN를 이용해 가상 네트워크 만들기" file: lectures/ch6/ovs_vxlan_vpn.qmd - - - - format: html: theme: @@ -49,4 +47,4 @@ format: - custom.scss toc: true lang: ko - include-after-body: _footer.html \ No newline at end of file + include-after-body: _footer.html diff --git a/lectures/ch6/images/provider_tenant_network/east_west.svg b/lectures/ch6/images/provider_tenant_network/east_west.svg new file mode 100644 index 0000000..ac386fb --- /dev/null +++ b/lectures/ch6/images/provider_tenant_network/east_west.svg @@ -0,0 +1,29 @@ + + + + + + + + + VM1 + 10.0.0.5 + + + Tenant Network + same subnet / same L2 domain + + + VM2 + 10.0.0.6 + + + + + + diff --git a/lectures/ch6/images/provider_tenant_network/egress_snat.svg b/lectures/ch6/images/provider_tenant_network/egress_snat.svg new file mode 100644 index 0000000..68e3790 --- /dev/null +++ b/lectures/ch6/images/provider_tenant_network/egress_snat.svg @@ -0,0 +1,37 @@ + + + + + + + + + VM + private IP + + + Tenant Network + isolated internal network + + + Virtual Router + SNAT + private -> public + + + Provider / External + uplink network + + + Outside + + + + + + diff --git a/lectures/ch6/images/provider_tenant_network/ingress_dnat.svg b/lectures/ch6/images/provider_tenant_network/ingress_dnat.svg new file mode 100644 index 0000000..03d92e6 --- /dev/null +++ b/lectures/ch6/images/provider_tenant_network/ingress_dnat.svg @@ -0,0 +1,37 @@ + + + + + + + + + Outside + + + Provider / External + public entry point + + + Virtual Router + DNAT / Floating IP + public -> private + + + Tenant Network + isolated internal network + + + VM + private IP + + + + + + diff --git a/lectures/ch6/images/provider_tenant_network/inter_tenant_router.svg b/lectures/ch6/images/provider_tenant_network/inter_tenant_router.svg new file mode 100644 index 0000000..21cdc01 --- /dev/null +++ b/lectures/ch6/images/provider_tenant_network/inter_tenant_router.svg @@ -0,0 +1,37 @@ + + + + + + + + + VM1 + 10.0.1.5 + + + TenantNet A + subnet A + + + Virtual Router + routes between subnets + + + TenantNet B + subnet B + + + VM2 + 10.0.2.6 + + + + + + diff --git a/lectures/ch6/images/provider_tenant_network/layer_overview.svg b/lectures/ch6/images/provider_tenant_network/layer_overview.svg new file mode 100644 index 0000000..623b00e --- /dev/null +++ b/lectures/ch6/images/provider_tenant_network/layer_overview.svg @@ -0,0 +1,35 @@ + + + + + + + + + Physical Network + + direct mapping + + + Provider Network + operator-managed + + routing / NAT gate + + + Virtual Router + + + + Tenant Network + tenant-managed + + + + VM Ports / VMs + diff --git a/lectures/ch6/provider_tenant_network.qmd b/lectures/ch6/provider_tenant_network.qmd new file mode 100644 index 0000000..3eba06e --- /dev/null +++ b/lectures/ch6/provider_tenant_network.qmd @@ -0,0 +1,166 @@ +--- +title: "6-2. Provider network와 tenant network 개념 정리" +description: "Provider network와 tenant network가 왜 분리되어 있는지, 각각 누가 만들고 어떤 역할을 맡는지 OpenStack Neutron 관점에서 정리합니다." +code: "6-2" +--- + +# [6-2-1] 해당 개념들이 생기게 된 이유 + +클라우드는 보통 **여러 사용자(테넌트)**가 **같은 물리 인프라(서버/스위치/회선)**를 공유합니다. 이때 네트워크에서 동시에 만족해야 하는 요구가 두 가지입니다. + +1. **운영자 관점(Provider)** + - 데이터센터 물리 네트워크(스위치/라우터/사내망/인터넷)와 안전하게 연결 + - 장애/보안/성능/정책을 중앙에서 통제 +2. **사용자 관점(Tenant)** + - 각 팀/프로젝트가 VM들을 위해 네트워크를 “스스로” 만들고 지울 수 있어야 함 + - 다른 팀/프로젝트와 트래픽이 섞이면 안 됨(격리) + +이 두 요구를 깔끔하게 분리한 결과가 보통: + +- **Provider network** = “운영자가 물리망과 연결해둔 기반 네트워크” +- **Tenant network** = “테넌트가 VM용으로 만드는 격리된 논리 네트워크” + +입니다. + +# [6-2-2] Provider Network란? + +### 정의(핵심) + +**Provider network**는 보통 “클라우드 네트워크가 물리 네트워크와 만나는 지점”에 있는 네트워크입니다. + +즉, **물리 스위치/라우터의 특정 네트워크(VLAN 등)와 직접 매핑**되거나, 최소한 강하게 연결됩니다. + +### 누가 만들고 관리하나 + +- 대부분 환경에서 **운영자(Admin)**가 생성/관리 +- 이유: 물리망 연결은 잘못 건드리면 전체 장애/보안 이슈로 직결 + +### 어떤 형태가 흔한가(대표) + +환경에 따라 다르지만, 전형적인 분류는 이런 느낌입니다. + +- **Flat(untagged)**: VLAN 태그 없이 특정 물리 네트워크에 바로 붙는 형태 +- **VLAN 기반**: 물리 스위치에서 VLAN으로 분리된 네트워크에 매핑 + +(※ OpenStack Neutron에선 provider network가 `flat` 또는 `vlan`로 많이 구성됩니다.) + +### 주 역할 + +- **외부망(External)** 제공: 인터넷/사내망 등 “클라우드 밖”으로 나가는 출구/입구 역할 +- 데이터센터 내부의 특정 물리망(예: 관리망, 스토리지망, DMZ망 등)과 연결되는 통로 역할 + +# [6-2-3] Tenant Network란? + +### 정의(핵심) + +**Tenant network**는 테넌트(프로젝트/사용자)가 VM들을 붙이기 위해 만드는 네트워크입니다. + +특징은 **다른 테넌트와 논리적으로 격리**된다는 점입니다. + +### 누가 만들고 관리하나 + +- 보통 **테넌트(프로젝트 사용자)**가 직접 생성(Self-service) +- 네트워크/서브넷/라우터를 UI/CLI로 만들고 VM을 붙이는 형태 + +### 격리는 어떻게 하냐(개념 수준) + +테넌트 네트워크는 물리 케이블을 새로 까는 게 아니라, **가상화 계층에서 분리**합니다. 대표적으로: + +- **오버레이(Overlay)**: VXLAN/Geneve/GRE 같은 캡슐화로 논리 네트워크를 분리 + + → 여러 테넌트가 같은 물리망을 공유해도 “논리적으로 서로 다른 L2”처럼 보이게 함 + + +### 주요 특징 + +- 테넌트 간 **트래픽 분리**가 기본값 +- 서로 다른 테넌트가 **같은 IP 대역**(예: 둘 다 10.0.0.0/24)을 써도 공존 가능(격리되어 있으니까) +- 외부 연결은 기본적으로 바로 열려 있지 않습니다 + + → 라우터/NAT/보안그룹 등을 통해 열어야 외부 통신이 됩니다 + + +# [6-2-4] 전체 레이어 + +![그림 6-2-4-1. Provider network와 tenant network의 전체 레이어](images/provider_tenant_network/layer_overview.svg) + +# [6-2-5] 트래픽 흐름 3가지로 이해하기 + +## 테넌트 내부 통신(East-West) + +같은 tenant network에 붙은 VM끼리는 그냥 L2/L3로 통신합니다. + +![그림 6-2-5-1. 같은 tenant network 내부의 East-West 통신](images/provider_tenant_network/east_west.svg) + +다른 tenant network라면(서브넷이 다르면) 라우터가 필요합니다. + +![그림 6-2-5-2. 서로 다른 tenant network 간 Virtual Router 통신](images/provider_tenant_network/inter_tenant_router.svg) + +--- + +## VM이 외부로 나감(Egress, 보통 SNAT) + +많은 클라우드에서 기본은: + +- VM은 사설 IP +- 외부로 나갈 때 라우터가 **SNAT**를 수행 + +![그림 6-2-5-3. VM이 외부로 나갈 때의 SNAT 흐름](images/provider_tenant_network/egress_snat.svg) + +--- + +## 외부에서 VM으로 들어옴(Ingress, 보통 DNAT/매핑 필요) + +기본적으로 tenant network는 외부에서 바로 접근이 안 됩니다. 들어오려면 보통: + +- **Floating IP(공인 IP를 VM에 매핑)** 또는 +- 포트포워딩 같은 DNAT 설정 +- 보안그룹/방화벽 허용 + +이런 “열어주는 작업”이 필요합니다. + +![그림 6-2-5-4. 외부에서 VM으로 들어올 때의 DNAT/Floating IP 흐름](images/provider_tenant_network/ingress_dnat.svg) + +--- + +# [6-2-6] Provider vs Tenant 차이 정리 + +| 구분 | Provider Network | Tenant Network | +| --- | --- | --- | +| 주 사용자 | 운영자(Admin) | 테넌트(프로젝트/사용자) | +| 목적 | 물리망/외부망과 연결되는 기반 제공 | VM용 내부망 제공, 테넌트 간 격리 | +| 물리망과 관계 | 직접 매핑/연결(Flat/VLAN 등) | 논리망(오버레이 등으로 분리)인 경우가 많음 | +| IP 성격 | 공인/사내 대역 등 “외부에 의미 있는” 대역일 수 있음 | 보통 사설 IP 대역(중복 가능) | +| 외부 접근성 | 외부망 역할이면 접근성 높음(정책에 따름) | 기본은 외부에서 직접 접근 어려움 | +| 성능/MTU 이슈 | 상대적으로 단순(캡슐화 없음) | 오버레이면 캡슐화 오버헤드/MTU 고려 필요 | +| 운영 리스크 | 잘못 설정하면 전체 장애/보안 영향 큼 | 특정 프로젝트 범위 영향이 대부분 | + +--- + +# [6-2-7] 흔한 오해 정리 + +- **“Provider network = 무조건 인터넷망”** + + → 외부망일 수도 있고, 데이터센터 내부의 특정 물리망(VLAN)일 수도 있습니다 + +- **“Tenant network = 무조건 완전 내부만”** + + → 기본은 내부로 쓰지만, 라우터/NAT/Floating IP 등으로 외부와 연결 가능합니다 + +- **“Tenant network는 물리적으로 따로 깔린 네트워크”** + + → 보통은 물리적으로 새로 까는 게 아니라, **논리적으로 분리**하는 방식(오버레이/VLAN 등) 입니다 + + +--- + +# [6-2-8] 결론 + +- **Provider network**: 운영자가 **물리망/외부망과 연결해 둔 기반 네트워크** +- **Tenant network**: 테넌트가 **VM을 붙이고 서비스 구성하려고 만드는 격리된 논리 네트워크** + +# 참조 + +[# OpenStack OVN provider network 아키텍처를 설명하는 공식 관리자 문서](https://docs.openstack.org/neutron/2024.2/admin/ovn/refarch/provider-networks.html) + +[# OpenStack self-service network와 라우터 연결 흐름을 설명하는 공식 설치 가이드](https://docs.openstack.org/install-guide/launch-instance-networks-selfservice.html) diff --git a/lectures/ch6_lec.qmd b/lectures/ch6_lec.qmd index 9ac3b48..f13326c 100644 --- a/lectures/ch6_lec.qmd +++ b/lectures/ch6_lec.qmd @@ -9,5 +9,6 @@ Neutron은 오픈스택의 네트워킹 서비스입니다. 이 장에서는 Neu ## 하위 목차 - [6-1 Neutron 에이전트 종류 정리](ch6/neutron_agents.qmd) +- [6-2 Provider network와 tenant network 개념 정리](ch6/provider_tenant_network.qmd) - [6-12 SNAT/DNAT 개념](ch6/snat_dnat.qmd) - [6-15 OVS/VXLAN 가상 네트워크 만들기](ch6/ovs_vxlan_vpn.qmd) diff --git a/lectures/index.qmd b/lectures/index.qmd index e0e9993..96bef0e 100644 --- a/lectures/index.qmd +++ b/lectures/index.qmd @@ -16,6 +16,7 @@ title: "오픈스택 강의 자료" - [4-1장. nova의 서비스 종류]() - [5장. Glance]() - [6장. Neutron](ch6_lec.qmd) - - [SNAT/DNAT 개념](ch6/snat_dnat.qmd) - [Neutron Agent 종류 정리](ch6/neutron_agents.qmd) - - [OVS/VXLAN 가상 네트워크 만들기](ch6/ovs_vxlan_vpn.qmd) \ No newline at end of file + - [6-2. Provider network와 tenant network 개념 정리](ch6/provider_tenant_network.qmd) + - [SNAT/DNAT 개념](ch6/snat_dnat.qmd) + - [OVS/VXLAN 가상 네트워크 만들기](ch6/ovs_vxlan_vpn.qmd) diff --git a/tools/scripts/README.md b/tools/scripts/README.md index 5ed68f3..404165f 100644 --- a/tools/scripts/README.md +++ b/tools/scripts/README.md @@ -93,17 +93,27 @@ python3 import_notion_zip.py "SNAT, DNAT 개념.zip" ch6 snat_dnat --title "SNAT - 예: `neutron_agents.qmd`에서는 `[Red Hat OpenStack Platform Neutron 설정 문서](https://docs.redhat.com/ko/documentation/red_hat_openstack_platform/16.2/html/configuration_reference/neutron_2)` 처럼, 공식 문서가 무엇을 다루는지 한글로 설명을 붙여 준다. - - 강의 본문 헤딩(`#`, `##`, `###`)에는 가능하면 **섹션 코드/번호**를 붙이되, ch6에서는 다음과 같이 정리한다. - - 기본 원칙: - - 섹션 코드는 **frontmatter의 `code:` 필드**와 **제목(title)** 에 우선 반영한다. - - 예: `code: "6-12"`, `title: "6-12 SNAT, DNAT 개념 정리"`. - - 본문 첫 `##` 헤딩에는 같은 번호를 **중복해서 다시 붙이지 않는다.** - - 즉, `## NAT가 왜 생겼는지`처럼 내용 위주의 헤딩만 둔다. + - 강의 본문 헤딩(`#`, `##`, `###`) 번호는 **변환 직후 반드시 확인**한다. 특히 ch6 문서는 다음 규칙을 기본값으로 삼는다. + - 섹션 코드는 **frontmatter의 `code:` 필드**와 **제목(title)** 에 우선 반영한다. + - 예: `code: "6-12"`, `title: "6-12. SNAT/DNAT란?"` + - ch6의 **주요 본문 섹션**은 plain heading으로 두지 말고, `# [6-12-1] ...`, `# [6-12-2] ...` 같은 **번호형 H1**으로 맞춘다. + - 예: `# [6-2-1] 해당 개념들이 생기게 된 이유` + - 예: `# [6-2-5] 트래픽 흐름 3가지로 이해하기` + - 번호형 H1 아래의 하위 설명은 필요에 따라 일반 `##`/`###` 헤딩으로 둘 수 있다. + - 예: `## 테넌트 내부 통신(East-West)` + - 예: `## VM이 외부로 나감(Egress, 보통 SNAT)` + - 변환 후에는 최소한 아래를 **무조건 점검**한다. + - `code:` 값과 제목의 장/절 번호가 서로 일치하는지 + - 본문 주요 섹션 번호가 `[6-2-1]`, `[6-2-2]`처럼 **순서대로 이어지는지** + - plain `# 제목`이 남아 있지 않은지 + - 새로 끼어든 섹션이 있으면 뒤 번호까지 함께 밀어서 renumber 되었는지 - 일반적인 장/절 구조(코드 필드가 없는 다른 장)에서는 기존처럼 `## 2.2.5 VM NIC 3개 구성 및 정적 IP 설정` 형태를 사용할 수 있다. - - 번호가 누락된 경우, 에이전트는 상위 헤딩 구조와 순서를 기준으로 번호를 **추론**만 하고, 실제 헤딩 텍스트 수정은 PR/리뷰에서 사람과 함께 확정하는 것을 권장한다. - - 그림/표 번호는 이 헤딩/코드(예: `6-12`)를 기준으로 `그림 6-12-1`, `표 6-12-1` 처럼 계산한다. - - 그림을 추가/정리할 때는 다음 형태를 기본으로 사용한다. - - `![그림 6-12-1. SNAT/DNAT 예시 흐름](images/ch6/snat_dnat_1.png){width="55%" fig-align="left"}` + - 그림/표 번호는 **가장 가까운 번호형 섹션 헤딩 전체**를 기준으로 계산한다. + - 예: `# [6-2-4] 전체 레이어` 아래 첫 그림이면 `그림 6-2-4-1` + - 예: `# [6-12-3] 두 가지 전통적인 NAT 방식` 아래 첫 그림이면 `그림 6-12-3-1` + - 섹션 번호가 바뀌면 그 아래 그림/표 번호도 **같이 renumber** 되었는지 반드시 확인한다. + - 그림을 추가/정리할 때는 다음 형태를 기본으로 사용한다. + - `![그림 6-12-3-1. NAPT 동작 원리](images/snat_dnat/image.png){width="55%" fig-align="left"}` → **번호 + 한 줄 설명 + 파일명 + 왼쪽 정렬**이 한 번에 정리되도록 돕는다. - 코드 블록(```` ``` ````) 언어 태그를 실제 내용과 맞춰 정리한다. - 사용자가 `@파일경로 (21-26)`처럼 특정 범위를 가리킬 때, 그 범위가 **명령어**인지 **설정 파일**인지 보고 언어를 결정한다. @@ -123,8 +133,10 @@ python3 import_notion_zip.py "SNAT, DNAT 개념.zip" ch6 snat_dnat --title "SNAT - 코드 블록인데 실제로는 **그림/다이어그램을 글로 그려 놓은 경우**도 올바르게 정리한다. - 예: 패킷 흐름, 토폴로지, 구성 요소 관계 등을 `|-`, `+`, `->` 같은 문자로 그려 놓은 ASCII 다이어그램. - 이런 블록은 실행 가능한 코드가 아니므로, 다음 중 하나로 정리한다. - - **설명 위주라면 일반 본문/리스트/표로 풀어서 재작성**하고, 가능하면 별도 그림 파일로 만드는 것을 권장한다. - - 그대로 둘 필요가 있을 때는 언어 태그를 `text` 또는 비워 두어, ` ```text` 처럼 “코드가 아닌 텍스트 블록”임을 드러낸다. + - **우선순위 1:** `lectures/{chapter}/images/{slug}/` 아래에 **실제 그림 파일(svg/png 등)** 로 만들고, 본문에서는 다른 문서와 동일하게 `![그림 6-2-5-1. ...](images/{slug}/diagram.svg)` 형태로 넣는다. + - **우선순위 2:** 설명 위주라면 일반 본문/리스트/표로 풀어서 재작성한다. + - **마지막 fallback:** 그대로 둘 필요가 있을 때만 언어 태그를 `text` 또는 비워 두어, ` ```text` 처럼 “코드가 아닌 텍스트 블록”임을 드러낸다. + - 즉, 기존 강의처럼 렌더 결과에 **정식 figcaption** 이 보이게 하려면, 가능한 한 텍스트 블록 대신 실제 이미지 파일로 바꿔 넣는 것을 기본값으로 삼는다. - 셸/프로그래밍 언어로 잘못 태그된 ASCII 다이어그램은, 반드시 `text`/무태그로 바꾸거나 일반 문단으로 풀어서 정리한다. --- diff --git a/tools/scripts/import_notion_zip.py b/tools/scripts/import_notion_zip.py index 30cd82c..fe7d986 100644 --- a/tools/scripts/import_notion_zip.py +++ b/tools/scripts/import_notion_zip.py @@ -233,7 +233,7 @@ def main(): zip_path = Path(zip_arg).resolve() if not zip_path.exists(): - imports_chapter = IMPORTS_DIR / chapter + imports_chapter = IMPORTS_DIR / chapter if '/' not in zip_arg and '\\' not in zip_arg and not imports_chapter.exists(): imports_chapter.mkdir(parents=True) print(f"tools/imports/{chapter}/ 폴더를 생성했습니다. ZIP 파일을 넣어주세요: {imports_chapter}")