Block Storage VS File Storage VS Object Storage

Block Storage

  • 데이터를 고정된 크기의 블록 단위(예: 16KB)로 쪼개어 저장
  • 블록들은 반드시 한곳에 모이지 않아도 되며, 소프트웨어가 자동으로 배치 최적화
  • 메타데이터 처리 제한적 (파일명 등 최소 수준)
  • 강력한 일관성과 구조화 보장 → DB 같은 워크로드에 적합
  • 블록 단위로 iSCSI, Fibre Channel, SATA, SAS 등 전문 프로토콜을 통해 접근
  • 추가 고려사항: "Raw" 스토리지를 사용할 경우 파일시스템(NTFS, XFS, ext4 등)을 얹어야 함

주요 장점: 높은 IOPS, 일관성 보장 → 데이터베이스, 트랜잭션 처리 시스템
단점: 메타데이터 부족, 직접 검색/관리 불편


File Storage

  • 데이터를 전체 파일 단위로 저장 및 액세스
  • 디렉토리/경로 기반 구조 (예: /HR/secret/report.pdf)
  • 제한적 메타데이터 (생성일, 수정일, 크기 등만 저장)
  • 파일 잠금(Lock)을 통해 동시 수정 충돌 방지 가능
  • 일반적으로 Block Storage 위에 파일시스템 형태로 구축됨
  • SMB, NFS 같은 파일 전용 프로토콜로 접근

주요 장점: 친숙한 구조(폴더 방식), 공유 디렉토리 활용 용이 (사내 업무 파일 서버)
단점: 대용량·비정형 데이터 검색 성능 낮음, 스케일링 제한적


Object Storage

  • 데이터를 객체(Object) 단위로 저장 (실제 파일 + 메타데이터 + ID)
  • 무제한 메타데이터 사용 가능 → 강력한 검색/분류 지원
  • 파일 Lock 불가, 대신 버전 관리를 통해 규제·무결성 충족
  • 이론적으로 무제한 확장 가능 (하드웨어 계속 추가)
  • HTTP 기반 REST API를 통해 접근 (S3, MinIO 등)
  • 네트워크 및 디스크 속도에 주로 종속, CPU/MEM 영향 적음

주요 장점: 무제한 확장, 메타데이터 기반 검색, API 접근으로 클라우드/앱 최적화
단점: 실시간 동기 업데이트(DB 등)에는 부적합, 실시간 동기 업데이트를 지원하려면 파일 잠금 기능이 있어야 하는데, 파일잠금기능이 없음.

  • 오브젝트 스토리지에는 파일잠금기능이 없는 이유
    • 오브젝트 스토리지는 거대한 분산 창고에서 물건(데이터)을 통째로 넣고 빼는 방식이라,
    • 부분적으로 물건을 잠그고 여러 사람이 동시에 쓸 수 있는 세밀한 제어(파일 잠금)를 할 수 없습니다.
    • 그래서 "파일 잠금" 기능이 없고, 동시 수정 충돌 방지는 ‘버전 관리’로 해결하려 합니다.
       
구분 Block Storage File Storage Object Storage
저장 단위 블록 (고정 크기, ex: 16KB) 파일 단위 객체 (데이터 + 메타데이터 + ID)
메타데이터 최소 (파일명, 일부 속성) 제한적 (생성/수정일, 크기 등) 무제한 (검색·분류 가능)
접근 방식 전용 프로토콜 (iSCSI, Fibre, SAS 등) SMB, NFS REST API (HTTP/S3 호환)
일관성/잠금 강력한 일관성 파일 Lock 지원 파일 Lock 불가, 대신 버전 관리
확장성 제한적 (디스크 추가 필요) 제한적 (파일시스템 규모 한계) 무제한 확장 (분산 스토리지)
주요 활용 DB, 고성능 트랜잭션 사내 공유파일 서버 클라우드, 데이터 레이크, 백업, 미디어 저장
성능 제약 디스크 속도, 파일시스템 필요 프로토콜 오버헤드 (SMB/NFS) 네트워크 및 디스크 I/O 의존

 

 

오브젝트 스토리지 vs. SAN/NAS/Block Storage: 핵심 요약

1. 불변성 (Immutability)

  • 객체는 본질적으로 변경 불가능: 한 번만 쓰고 여러 번 읽기 가능. e-디스커버리, 규정 준수(예: 보존기간 지정) 및 최신 데이터 무결성 요구에 적합.
  • 만료 이전까지는 변경 불가, 만료 후에만 삭제 허용.

2. 보안 및 암호화

  • SAN/NAS는 대부분 드라이브나 볼륨 수준에서 암호화 가능.
  • 객체 스토리지는 버킷 수준뿐 아니라, 객체마다 개별 키로 암호화 가능 → 같은 버킷 안의 서로 다른 객체를 별도의 키로 보호.

3. 클라우드 네이티브 / 접근 방식

  • SAN/iSCSI: 볼륨 ID와 블록 오프셋으로 접근.
  • NAS: NFS/SMB 마운트, 디렉토리 경로 방식.
  • 객체 스토리지는 RESTful API와 URL/객체ID로 접근; 클라우드-네이티브 환경에서 기본 스토리지로 인정받음.
  • 거의 모든 데이터베이스가 S3 API를 기본 지원하는 시대.

4. 메타데이터 및 검색성

  • SAN/NAS: 볼륨, 파일에 한정된 "표준" 메타데이터(생성일, 수정일, 용량 등)만 보유, 커스텀 메타데이터로 직접 검색 불가.
  • 객체 스토리지는 각 객체에 자유로운 커스텀 태그, 데이터 속성 추가 가능, 태그로 빠르고 유연한 검색 지원.

5. 확장성과 성능

  • SAN/NAS: PB 수준의 확장에 한계, 고가 장비 중심.
  • 객체 스토리지는 엑사스케일(EB)까지 수평 확장 가능, 하드웨어 한계는 드라이브 추가로 극복.
  • 최신 객체 스토리지는 NVMe, 100GbE 및 하드웨어만큼 빠르며, 실제로 대규모 AI/빅데이터 워크로드에서도 SAN/NAS 대비 뛰어난 throughput 보장

6. 데이터 보호: RAID vs. Erasure Coding

  • RAID: 블록 단위 복제 또는 패리티, 복구시 전체 드라이브를 rebuild해야 함. 디스크 용량 커질수록 복구 시간/리스크 증가, 대규모 환경에 비효율적.
  • Erasure Coding (MinIO): 객체 단위로 데이터/패리티 블록을 나누어 여러 노드, 드라이브에 분산 저장. 실패 시, 객체 단위로 빠르게 복구 가능. Bitrot(사일런트 데이터 손상)까지 검출/치유 지원하여, SAN/NAS snapshotting 접근 방식보다 훨씬 효율적.

주요 비교표 (SAN/NAS/Block vs Object Storage)

항목Block/SAN/NASObject Storage (MinIO)
구조 블록/파일 기반 객체(파일+메타데이터+글로벌 ID)
확장성 수 TB ~ 수 PB 제한 EB/엑사스케일까지 수평 확장 가능
API iSCSI/SMB/NFS 등 S3 REST API (웹 기반)
복구 RAID로 전체 드라이브 Erasure Coding으로 객체 단위 복구
메타데이터 제한적/표준세트 커스텀 태그/속성, 고급 검색 가능
불변성 제한적 객체/버킷 단위 불변 정책, 버저닝 지원
보안 볼륨/파일 암호화 버킷/객체 단위 독립 키 암호화
성능 HW/구조적 한계 하드웨어 및 네트워크 한계까지 최대 활용
활용 DB, 파일서버 AI/ML, 빅데이터, 분석, DB, 미디어, 백업
가격 $$$ (고가, 복잡) $ (소프트웨어 정의, commodity HW 활용)
 

 


MinIO란?

MinIO는 고성능, 확장 가능하며 AWS S3 API와 완벽하게 호환되는 분산 객체 스토리지 솔루션입니다. 온프레미스, 프라이빗 클라우드, 퍼블릭 클라우드, 그리고 하이브리드 환경에 모두 배포 가능하며, 대규모 데이터 저장, 백업, AI/ML, 빅데이터 분석 등 클라우드 네이티브 워크로드에 최적화되어 있습니다.

MinIO는 Erasure Coding을 통한 데이터 보호와 Bitrot 방지 기능으로 높은 내구성과 가용성을 제공하며, Kubernetes와의 네이티브 통합으로 현대 인프라 환경에 쉽게 적용할 수 있습니다. 또한, CLI와 웹 UI를 제공해 운영 편의성을 높였고, TLS 암호화 및 IAM 역할 기반 권한 관리 등 강력한 보안 기능도 포함합니다.

즉, MinIO는 빠르고 안정적인 대용량 객체 데이터 저장을 위한 오픈소스 기반의 기업급 스토리지 솔루션입니다

MinIO 배포 방식

  • MinIO는 세 가지 토폴로지로 배포됩니다: 단일 노드 단일 드라이브(SNSD), 단일 노드 다중 드라이브(SNMD), 다중 노드 다중 드라이브(MNMD)
  • SNSD는 개발 및 평가용으로 제한된 신뢰성을 가지며, SNMD는 저성능・저용량 워크로드에 적합합니다
  • MNMD는 분산 클러스터 환경으로, 다중 노드와 드라이브에서 최대 절반 장애까지 견디는 고가용성・고성능을 제공합니다
  • MNMD는 AI/ML, 분산 쿼리, 데이터 분석, 데이터 레이크 등 페타바이트급 대규모 워크로드를 지원합니다
  • 배포는 가상머신, 베어메탈, 쿠버네티스 등 다양한 인프라 환경에서 가능하며, 클러스터 노드들이 하나의 객체 저장소로 함께 작동합니다

MinIO 서버 관리 방식

  • 프로덕션 환경에서는 고가용성 확보를 위해 여러 노드와 스토리지 장치를 서버 풀(Server Pool)로 묶어 자원을 풀링합니다.
  • 하나 이상의 서버 풀이 모여 단일 MinIO 클러스터를 구성하며, 각 객체는 동일한 서버 풀 내 동일한 삭제 세트(Erasure Set)에 데이터를 씁니다.
  • 서버 풀이 하나라도 다운되면 클러스터 전체 I/O가 중단되고, 복구 후 정상 작동 시 다시 I/O가 재개됩니다.
  • 실제 시작 명령어에서 노드와 드라이브 수를 지정하며, 예를 들어 4노드에 노드당 4드라이브로 총 16드라이브 서버 풀 생성이 가능합니다.
  • 복수 서버 풀로 구성 시, 각 서버 풀은 최소 4개 이상의 노드로 구성하는 것이 권장됩니다.
  • 클러스터 전체는 해당 여러 서버 풀이 연결된 형태이며, 사용자는 CLI(mcli)나 웹 콘솔을 통해 클러스터 및 객체 상태를 관리할 수 있습니다.

MinIO의 가용성, 중복성, 안정성 제공 방법

  • Erasure Coding을 사용해 데이터를 데이터/패리티 블록으로 나누어 저장, 일부 드라이브 실패에도 데이터 복구가 가능합니다.
  • Bit rot(무형의 데이터 손상)을 해시 검증 및 자동 복구 기능으로 방어합니다.
  • Quorum 메커니즘으로 읽기·쓰기 가능한 최소 노드 수를 보장합니다.
  • 서버 풀 단위로 클러스터를 구성하며, 각 객체는 동일 서버 풀 내 삭제 세트에 저장됩니다.
  • 드라이브에 대한 독점적인 접근을 요구해 복구 능력을 보호합니다.

 

 

MinIO 아키텍처 및 erasure coding 설명

  • https://www.youtube.com/watch?v=GNBWHjB7PP0 : 아키텍처
  • https://www.youtube.com/watch?v=sxcz6U0fUpo : erasure coding

동영상 짧으니 직접 보는게 이해가 가장 빠르다.

 

MinIO 드라이브 손실시 parity, quorom에 따른 처리 결과들

MinIO가 고가용성과 안정성을 위해 데이터를 여러 조각과 패리티로 나누어 여러 디스크에 분산하는 방식

  • MinIO는 객체를 데이터 샤드(Data Shard)와 패리티 샤드(Parity Shard)로 나누어 저장합니다.
    • 데이터 샤드는 실제 데이터를, 패리티 샤드는 데이터 복구용 중복 정보를 포함합니다.
    • 파란색 D는 데이터 샤드, 빨간색 P는 패리티 샤드를 의미하며, 총 16개의 드라이브에 12개의 데이터 샤드와 4개의 패리티 샤드가 분포되어 있습니다.
    • 패리티 샤드는 데이터의 일부 장애나 손실 시 데이터를 복구할 수 있도록 하는 중복 정보 역할을 합니다 (삭제 코딩 EC:4).
  • 1노드 내의 이런 삭제 세트 구성을 통해 MinIO는 드라이브 장애에도 데이터 가용성과 복원력을 제공합니다.
  • MinIO는 이 샤드들을 각 드라이브에 균등하게 분포시켜 장애 시 복구 및 가용성을 보장합니다.
  • 사용자는 minioClient.putObject() API를 통해 데이터를 MinIO 노드에 저장하고, 노드는 내부적으로 이 구조를 통해 데이터를 분산 저장합니다.

패리티 4개가 있는데, 2개 장애니까 정상동작

삭제 코딩(Erasure Coding) 개념

  • Erasure Coding은 데이터를 여러 조각(Data Shard)과 보호용 조각(Parity Shard)으로 나누어 저장하는 기술입니다.
  • 'Erasure'는 ‘지움’ 또는 ‘손실’을 의미하며, 일부 데이터 조각이 손실되어도 원래 데이터를 복구할 수 있도록 코딩하는 과정입니다.
  • MinIO는 모든 객체를 데이터와 패리티 샤드로 분할하고, 이를 삭제 세트(Erasure Set)라는 그룹의 여러 드라이브에 균등하게 분배합니다.
  • 예를 들어, 16 드라이브 삭제 세트에서 기본 패리티는 4개입니다(EC:4). 이는 최대 4개의 드라이브 장애에도 데이터를 복구할 수 있다는 뜻입니다.
  • 패리티 수는 가용성과 저장 효율 간 트레이드오프가 있습니다. 패리티가 많으면 장애 허용량이 커지지만 저장 공간 효율은 감소합니다.

Bitrot 보호

  • Bitrot은 저장장치에 저장된 데이터가 시간이 지나면서 내부적으로 무형식 손상되는 현상입니다.
  • MinIO는 고속 해시 알고리즘(HighwayHash)을 이용해 데이터를 읽을 때마다 무결성 검사를 수행하고, 데이터 손상이 감지되면 Erasure Coding으로 자동 복구합니다.
  • 이런 자동 검증과 복구 덕분에 사용자나 시스템이 알지 못하는 데이터 손상도 사전에 방지됩니다.

 

MinIO 배포(도커 컨테이너)

# 
mkdir /tmp/data
tree -h /tmp/data

#
docker ps -a
docker run -itd -p 9000:9000 -p 9090:9090 --name minio -v /tmp/data:/data \
  -e "MINIO_ROOT_USER=admin" -e "MINIO_ROOT_PASSWORD=minio123" \
  quay.io/minio/minio server /data --console-address ":9090"
  
docker ps

#
docker exec -it minio env
docker inspect minio | jq
...
      "Env": [
        "MINIO_ROOT_USER=admin",
        "MINIO_ROOT_PASSWORD=miniopasswd",
        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
        "MINIO_ACCESS_KEY_FILE=access_key",
        "MINIO_SECRET_KEY_FILE=secret_key",
        "MINIO_ROOT_USER_FILE=access_key",
        "MINIO_ROOT_PASSWORD_FILE=secret_key",
        "MINIO_KMS_SECRET_KEY_FILE=kms_master_key",
        "MINIO_UPDATE_MINISIGN_PUBKEY=RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav",
        "MINIO_CONFIG_ENV_FILE=config.env",
        "MC_CONFIG_DIR=/tmp/.mc"
      ],
...

#
docker logs minio
INFO: Formatting 1st pool, 1 set(s), 1 drives per set.
INFO: WARNING: Host local has more than 0 drives of set. A host failure will result in data becoming unavailable.
MinIO Object Storage Server
Copyright: 2015-2025 MinIO, Inc.
License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
Version: RELEASE.2025-07-23T15-54-02Z (go1.24.5 linux/arm64)

API: http://172.17.0.2:9000  http://127.0.0.1:9000 
   RootUser: admin 
   RootPass: miniopasswd 

WebUI: http://172.17.0.2:9090 http://127.0.0.1:9090  
   RootUser: admin 
   RootPass: miniopasswd 

CLI: https://min.io/docs/minio/linux/reference/minio-mc.html#quickstart
   $ mc alias set 'myminio' 'http://172.17.0.2:9000' 'admin' 'miniopasswd'

Docs: https://docs.min.io

 

MinIO 웹으로 접속해서 test 버킷 만들고 life.txt(1000줄짜리 소설) 업로드

 

life.txt라는 디렉토리가 생성되고 하위에 xl.meta 파일이 생성된것이 확인된다.

 

MinIO MC(MinIO Client) 설치

# https://docs.min.io/enterprise/aistor-object-store/reference/cli/ 각자 실습 환경 OS에 맞는 mc 설치 할 것!
brew install minio/stable/mc
mc --help

# mc alias
mc alias list
mc alias set 'myminio' 'http://127.0.0.1:9000' 'admin' 'minio123'
Added `myminio` successfully.

mc alias list
myminio
  URL       : http://127.0.0.1:9000
  AccessKey : admin
  SecretKey : miniopasswd
  API       : s3v4
  Path      : auto
  Src       : /Users/gasida/.mc/config.json

cat ~/.mc/config.json

# admin info
mc admin info play
mc admin info myminio
●  127.0.0.1:9000
   Uptime: 1 hour 
   Version: 2025-07-23T15:54:02Z
   Network: 1/1 OK 
   Drives: 1/1 OK 
   Pool: 1

┌──────┬────────────────────────┬─────────────────────┬──────────────┐
│ Pool │ Drives Usage           │ Erasure stripe size │ Erasure sets │
│ 1st  │ 44.0% (total: 460 GiB) │ 1                   │ 1            │
└──────┴────────────────────────┴─────────────────────┴──────────────┘

27 KiB Used, 1 Bucket, 1 Object
1 drive online, 0 drives offline, EC:0

# ls : lists buckets and objects on MinIO or another S3-compatible service
mc ls 
mc ls myminio/test
[2025-09-07 12:21:09 KST]  27KiB STANDARD life.txt

# tree
mc tree --files myminio/test       
myminio/test
└─ life.txt
 
# find
mc find myminio/test --name "*.txt"
myminio/test/life.txt

# stat
mc stat myminio/test           
Name      : test
Date      : 2025-09-07 12:48:49 KST 
Size      : N/A    
Type      : folder 

Properties:
  Versioning: Un-versioned
  Location: us-east-1
  Anonymous: Disabled
  ILM: Disabled

Usage:
      Total size: 27 KiB
   Objects count: 1
  Versions count: 0

Object sizes histogram:
   1 object(s) BETWEEN_1024B_AND_1_MB
   1 object(s) BETWEEN_1024_B_AND_64_KB
   0 object(s) BETWEEN_10_MB_AND_64_MB
   0 object(s) BETWEEN_128_MB_AND_512_MB
   0 object(s) BETWEEN_1_MB_AND_10_MB
   0 object(s) BETWEEN_256_KB_AND_512_KB
   0 object(s) BETWEEN_512_KB_AND_1_MB
   0 object(s) BETWEEN_64_KB_AND_256_KB
   0 object(s) BETWEEN_64_MB_AND_128_MB
   0 object(s) GREATER_THAN_512_MB
   0 object(s) LESS_THAN_1024_B
   
mc stat myminio/test/life.txt
Name      : life.txt
Date      : 2025-09-07 12:21:09 KST 
Size      : 27 KiB 
ETag      : f7593a23177b30a86197e83197d99acd 
Type      : file 
Metadata  :
  Content-Type: text/plain 

# 그외 mb/rb, mv, cp, rm, mirror 등은 직접 해볼 것!

 

MinIO Policy

# IAM 기본 정책 및 커스텀 정책 확인
mc admin policy list myminio        
consoleAdmin
diagnostics
readonly
readwrite
writeonly

# IAM 정책 세부 (대상 지정)
mc admin policy info myminio consoleAdmin | jq
{
  "PolicyName": "consoleAdmin",
  "Policy": {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": [
          "admin:*"
        ]
      },
      {
        "Effect": "Allow",
        "Action": [
          "kms:*"
        ]
      },
      {
        "Effect": "Allow",
        "Action": [
          "s3:*"
        ],
        "Resource": [
          "arn:aws:s3:::*"
        ]
      }
    ]
  }
}

 

# 버킷 외부 공개 정책 확인(private)
mc anonymous get myminio/test
Access permission for `myminio/test` is `private`

# 객체 접근 (외부 사용자)
curl http://127.0.0.1:9000/test/life.txt
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied.</Message><Key>life.txt</Key><BucketName>test</BucketName><Resource>/test/life.txt</Resource><RequestId>1862E3D962D137B2</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>


# 버킷 외부 공개 정책 수정(public) : GET, PUT, LIST
mc anonymous set public myminio/test
mc anonymous get myminio/test
Access permission for `myminio/test` is `public`

# 객체 접근 (외부 사용자)
curl http://127.0.0.1:9000/test/life.txt
...


# 버킷 외부 공개 정책 원복(private)
mc anonymous set private myminio/test
mc anonymous get myminio/test

 

1차 실습 끝. 실습 리소스 제거 :docker rm -f minio && rm -rf /tmp/data

싱글노드 멀티 디스크로 배포(SNMD)

# 4개의 로컬 디렉토리를 생성하여 각각을 MinIO 컨테이너의 별도의 디스크 볼륨으로 마운트 준비
mkdir -p /tmp/disk1 /tmp/disk2 /tmp/disk3 /tmp/disk4

# 생성된 디렉토리 구조 확인 (tree 명령어가 있으면 디렉토리 크기 정보 포함 출력)
tree -h /tmp

# 실행 중인 모든 도커 컨테이너 리스트 확인
docker ps -a

# MinIO 컨테이너 실행 (백그라운드, 9000포트 - S3 API, 9090포트 - 콘솔 UI 포트)
# 4개의 로컬 경로를 컨테이너 내부 /data1, /data2, /data3, /data4로 각각 마운트
# 환경변수 설정: 루트 계정(admin), 비밀번호(minio123), Erasure Coding 패리티 1 (EC:1) 기본 저장소 클래스
# 서버 시작 명령어 : /data{1...4} 경로를 데이터 저장소로 지정하고, 콘솔 UI는 9090 포트 오픈
docker run -itd -p 9000:9000 -p 9090:9090 --name minio \
  -v /tmp/disk1:/data1 \
  -v /tmp/disk2:/data2 \
  -v /tmp/disk3:/data3 \
  -v /tmp/disk4:/data4 \
  -e "MINIO_ROOT_USER=admin" -e "MINIO_ROOT_PASSWORD=minio123" -e "MINIO_STORAGE_CLASS_STANDARD=EC:1" \
  quay.io/minio/minio server /data{1...4} --console-address ":9090"

# 현재 실행 중인 컨테이너 상태 출력 (정상 실행 여부 확인)
docker ps

# 컨테이너 내 환경변수 확인 (MINIO_ROOT_USER, MINIO_ROOT_PASSWORD, 스토리지 클래스 등 환경 정보)
docker exec -it minio env

# 컨테이너 상세 정보 조회 후 jq로 JSON 포맷팅 출력 (볼륨 마운트 정보, 네트워크, 포트 등)
docker inspect minio | jq

# MinIO 컨테이너 로그 확인 (삭제 코딩 적용된 1개의 풀, 4드라이브 구성, 드라이브가 동일 호스트에 위치한다는 경고 포함)
docker logs minio
INFO: Formatting 1st pool, 1 set(s), 4 drives per set.
INFO: WARNING: Host local has more than 1 drives of set. A host failure will result in data becoming unavailable.
...

 

life.txt 파일 업로드

 

멀티디스크로 배포했기에 erasure coding이 동작하게된다.

위와같이 파일이 쪼개져서 들어간것을 볼 수 있고, 패리티는 3번 디스크에 반영된것을 알 수 있다.

 

 

 

 

#
mc admin info myminio
●  127.0.0.1:9000
   Uptime: 3 minutes 
   Version: 2025-07-23T15:54:02Z
   Network: 1/1 OK 
   Drives: 4/4 OK 
   Pool: 1

┌──────┬────────────────────────┬─────────────────────┬──────────────┐
│ Pool │ Drives Usage           │ Erasure stripe size │ Erasure sets │
│ 1st  │ 44.0% (total: 1.3 TiB) │ 4                   │ 1            │
└──────┴────────────────────────┴─────────────────────┴──────────────┘

65 KiB Used, 1 Bucket, 1 Object

mc stat myminio/test
mc stat myminio/test/life.txt

# 강제로 (패리티 아닌)디렉터리 1개 제거
rm -rf /tmp/disk1/test
tree -h /tmp

#
mc admin info myminio
mc stat myminio/test/life.txt

# 버킷 힐
mc admin heal myminio/test

# 약간의 시간 걸림
mc stat myminio/test/life.txt
tree -h /tmp
cat /tmp/disk1/test/life.txt/xl.meta

위 코드로 유실 재현 및 복구를 확인해보자.

 

위와같이 삭제된 상태에서,

heal 해서 다시 데이터가 살아난것을 볼 수 있다.

 

이번엔 2개를 날려보자(현재 패리티는 1개인 상황)

# 강제로 디렉터리 2개 제거
rm -rf cat /tmp/disk1/test
rm -rf cat /tmp/disk2/test
tree -h /tmp

#
mc admin info myminio
mc stat myminio/test/life.txt

# 버킷 힐 시도
mc admin heal myminio/test 
tree -h /tmp
...

실습 리소스 제거 :docker rm -f minio && rm -rf /tmp/disk{1..4}

MinIO on K8S

mkdir minio && cd minio

# kind 설치
kind create cluster --name myk8s --image kindest/node:v1.33.4 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000 
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
- role: worker
- role: worker
- role: worker
- role: worker
EOF

#
docker ps
kubectl get node

# kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30000 --set env.TZ="Asia/Seoul" --namespace kube-system
echo -e "KUBE-OPS-VIEW URL = http://localhost:30000/#scale=1.5"

MinIO 실습을 위한 쿠버네티스 배포 및 설정

 

MinIO on K8S - MinIO를 쿠버네티스에 설치(오퍼레이터 사용)

  • MinIO는 Kubernetes 네이티브 고성능 객체 저장소이며 S3 호환 API를 제공합니다.
  • MinIO Operator는 Kubernetes 클러스터 내에 MinIO Tenant(사용자별 독립 객체 저장소)를 배포, 관리하기 위한 Kubernetes Operator입니다.
  • Operator는 MinIO Tenant를 Kubernetes Custom Resource Definition(CRD) 객체로 취급하여 선언적 방식으로 배포 운용을 지원합니다.

주요 구성

  • MinIO Operator는 자체 네임스페이스에서 실행되며 두 개의 주요 파드(Pod)를 운용합니다.
    1. Operator Pod: Tenant 배포, 관리, 수정, 유지보수의 기본 기능 수행
    2. Console Pod: Operator의 GUI 기능을 제공하는 콘솔 UI (현재 6.0.0 버전에서 deprecated 예정)

TLS 인증서 관리

  • MinIO Operator는 Kubernetes의 certificates.k8s.io API를 활용하여 TLS 인증서 서명 요청(CSR)과 발급 프로세스를 관리합니다.
  • TLS 인증서 자동 발급은 아래 조건에서 활성화됩니다.
    • 자동 인증서(autoCert) 기능 활성화 시
    • 콘솔 TLS 환경변수(MINIO_CONSOLE_TLS_ENABLE=on) 설정 시
    • STS(Security Token Service) 환경변수(OPERATOR_STS_ENABLED=on) 설정 시
    • 클러스터 상태 확인용 인증서 관리 등
# Add the MinIO Operator Repo to Helm
helm repo add minio-operator https://operator.min.io
helm repo update
helm search repo minio-operator
NAME                            CHART VERSION   APP VERSION     DESCRIPTION                                       
minio-operator/minio-operator 4.3.7             v4.3.7          A Helm chart for MinIO Operator                   
minio-operator/operator       7.1.1             v7.1.1          A Helm chart for MinIO Operator                   
minio-operator/tenant         7.1.1             v7.1.1          A Helm chart for MinIO Operator  
 
# Install the Operator : Run the helm install command to install the Operator. 
# The following command specifies and creates a dedicated namespace minio-operator for installation. 
# MinIO strongly recommends using a dedicated namespace for the Operator.
helm install \
  --namespace minio-operator \
  --create-namespace \
  --set operator.replicaCount=1 \
  operator minio-operator/operator 

# 확인
kubectl get all -n minio-operator
kubectl get-all -n minio-operator
kubectl get crd
NAME                        CREATED AT
policybindings.sts.min.io   2025-09-07T08:36:29Z
tenants.minio.min.io        2025-09-07T08:36:29Z

#
kubectl explain tenants.minio.min.io
kubectl explain tenants.minio.min.io.spec

 

MinIO 테넌트 구성요소

  • MinIO 테넌트는 MinIO 오브젝트 스토리지 서비스를 지원하는 쿠버네티스 리소스를 특정 네임스페이스에 완전하게 배포한 세트입니다.
  • MinIO는 로컬에 직접 연결된 스토리지가 있는 쿠버네티스 워커 노드에 테넌트를 배포하는 것을 강력히 권장합니다. 워커 노드는 MinIO의 프로덕션용 하드웨어 체크리스트를 충족해야 합니다.
  • 영구 볼륨(Persistent Volume)은 주로 ReadWriteOnce 액세스 모드를 지원하는 볼륨을 사용하며, MinIO의 일관성 보장을 위해 독점적 접근이 필요합니다. 영구 볼륨 클레임(PVC)에 대해 Retain 회수 정책 설정을 권고하며, 볼륨 포맷은 XFS가 성능상 최적입니다.
  • 노드에 직접 연결된 스토리지가 있는 클러스터에서는 DirectPV CSI 드라이버 사용을 추천합니다. 이는 로컬 볼륨 수동 관리를 자동화합니다.
  • MinIO 테넌트는 반드시 자체 네임스페이스를 가져야 하고, 오퍼레이터가 이 네임스페이스 내에서 테넌트 운영에 필요한 파드(Pod)를 생성합니다.
  • 각 테넌트 파드는 3개의 컨테이너를 실행합니다:
    • MinIO 컨테이너: 객체 저장 및 검색 기능 수행 (베어메탈 MinIO와 동일 기능)
    • InitContainer: 파드 시작 시 설정 비밀 관리, 시작 후 종료됨
    • SideCar 컨테이너: 구성 비밀과 루트 자격 증명을 지속 감시하며 변경 시 업데이트, 루트 자격 증명 미발견 시 오류 발생
  • MinIO Operator 버전 5.0.6부터는 추가 Pod 초기화를 위한 사용자 정의 init 컨테이너도 지원합니다.
  • 테넌트는 영구 볼륨 클레임을 사용해 데이터를 저장하는 영구 볼륨과 통신합니다.

MinIO 배포 및 노드포트 설정

#
curl -sLo values.yaml https://raw.githubusercontent.com/minio/operator/master/helm/tenant/values.yaml

# VSCODE 수정 : 기본키(minio , minio123)
tenant:
  pools:
    - servers: 4
      name: pool-0
      volumesPerServer: 1 # The number of volumes attached per MinIO Tenant Pod / Server.
      size: 1Gi # The capacity per volume requested per MinIO Tenant Pod.

  env:
    - name: MINIO_STORAGE_CLASS_STANDARD
      value: "EC:1"

#
helm install \
--namespace tenant-0 \
--create-namespace \
--values values.yaml \
tenant-0 minio-operator/tenant

# 확인
kubectl get tenants -A -w
NAMESPACE   NAME      STATE                                   HEALTH   AGE
tenant-0    myminio   Waiting for MinIO TLS Certificate                24s
tenant-0    myminio   Provisioning MinIO Cluster IP Service            28s
tenant-0    myminio   Provisioning Console Service                     28s
tenant-0    myminio   Provisioning MinIO Headless Service              28s
tenant-0    myminio   Provisioning MinIO Statefulset                   29s
tenant-0    myminio   Waiting for Tenant to be healthy                 30s
tenant-0    myminio   Waiting for Tenant to be healthy        red      53s
tenant-0    myminio   Waiting for Tenant to be healthy        green    56s
tenant-0    myminio   Initialized                             green    58s

kubectl get tenants -n tenant-0
NAME      STATE         HEALTH   AGE
myminio   Initialized   green    3m13s

kubectl get tenants -n tenant-0 -owide -o yaml
...
 spec:
    configuration:
      name: myminio-env-configuration
    env:
    - name: MINIO_STORAGE_CLASS_STANDARD
      value: EC:1
    features:
      bucketDNS: false
      enableSFTP: false
    image: quay.io/minio/minio:RELEASE.2025-04-08T15-41-24Z
    imagePullPolicy: IfNotPresent
    mountPath: /export
    podManagementPolicy: Parallel
    pools:
    - containerSecurityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop:
          - ALL
        runAsGroup: 1000
        runAsNonRoot: true
        runAsUser: 1000
        seccompProfile:
          type: RuntimeDefault
      name: pool-0
      securityContext:
        fsGroup: 1000
        fsGroupChangePolicy: OnRootMismatch
        runAsGroup: 1000
        runAsNonRoot: true
        runAsUser: 1000
      servers: 4
      volumeClaimTemplate:
        metadata:
          name: data
        spec:
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
      volumesPerServer: 1
    poolsMetadata:
      annotations: {}
      labels: {}
    prometheusOperator: false
    requestAutoCert: true
    subPath: /data
  status:
    availableReplicas: 4
    certificates:
      autoCertEnabled: true
      customCertificates: {}
    currentState: Initialized
    drivesOnline: 4
    healthStatus: green
    pools:
    - legacySecurityContext: false
      ssName: myminio-pool-0
      state: PoolInitialized
    revision: 0
    syncVersion: v6.0.0
    usage:
      capacity: 2991747305472
      rawCapacity: 3988996407296
      rawUsage: 115434881024
      usage: 86576160768
    writeQuorum: 3

테넌트 배포 완료

 

 

NodePort 설정 및 접속 , mc alias 와 버킷 생성

#
kubectl get-all -n tenant-0
kubectl get sts,pod,svc,ep,pvc,secret -n tenant-0
NAME                              READY   AGE
statefulset.apps/myminio-pool-0   4/4     84s

NAME                   READY   STATUS    RESTARTS   AGE
pod/myminio-pool-0-0   2/2     Running   0          84s
pod/myminio-pool-0-1   2/2     Running   0          84s
pod/myminio-pool-0-2   2/2     Running   0          84s
pod/myminio-pool-0-3   2/2     Running   0          84s

NAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/minio             ClusterIP   10.96.17.142    <none>        443/TCP    85s
service/myminio-console   ClusterIP   10.96.252.107   <none>        9443/TCP   85s
service/myminio-hl        ClusterIP   None            <none>        9000/TCP   85s
...

#
kubectl get pod -n tenant-0 -l v1.min.io/pool=pool-0 -owide
kubectl describe pod -n tenant-0 -l v1.min.io/pool=pool-0
kubectl logs -n tenant-0 -l v1.min.io/pool=pool-0

#
kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- id
uid=1000 gid=1000 groups=1000

kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- env
...
MINIO_CONFIG_ENV_FILE=/tmp/minio/config.env
...

kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- cat /tmp/minio/config.env
export MINIO_ARGS="https://myminio-pool-0-{0...3}.myminio-hl.tenant-0.svc.cluster.local/export/data"
export MINIO_PROMETHEUS_JOB_ID="minio-job"
export MINIO_ROOT_PASSWORD="minio123"
export MINIO_ROOT_USER="minio"
export MINIO_SERVER_URL="https://minio.tenant-0.svc.cluster.local:443"
export MINIO_STORAGE_CLASS_STANDARD="EC:1"
export MINIO_UPDATE="on"
export MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav"

#
kubectl get secret -n tenant-0 myminio-env-configuration -o jsonpath='{.data.config\.env}' | base64 -d ; echo
export MINIO_ROOT_USER="minio"
export MINIO_ROOT_PASSWORD="minio123"

#
kubectl get secret -n tenant-0 myminio-tls -o jsonpath='{.data.public\.crt}' | base64 -d
kubectl get secret -n tenant-0 myminio-tls -o jsonpath='{.data.public\.crt}' | base64 -d | openssl x509 -noout -text
...
      Issuer: CN=kubernetes
        Validity
            Not Before: Sep 10 12:37:02 2025 GMT
            Not After : Sep 10 12:37:02 2026 GMT
        Subject: O=system:nodes, CN=system:node:*.myminio-hl.tenant-0.svc.cluster.local
      ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier: 
                23:2A:4E:1A:BF:D1:BB:14:D7:2B:E4:93:EF:CF:DF:98:D0:22:23:A3
            X509v3 Subject Alternative Name: 
                DNS:myminio-pool-0-{0...3}.myminio-hl.tenant-0.svc.cluster.local, DNS:minio.tenant-0.svc.cluster.local, DNS:minio.tenant-0, DNS:minio.tenant-0.svc, DNS:*.myminio-hl.tenant-0.svc.cluster.local, DNS:*.tenant-0.svc.cluster.local
...

kubectl get secret -n tenant-0 myminio-tls -o jsonpath='{.data.private\.key}' | base64 -d
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwWq28PCWou2keOFw
rJk4KPRn/Z8xFqob34bDq4dHFBehRANCAASWSrORD9HFR11Jq4z6/PgWMyl2xFbY
WCQeeX46Oadkm5YvEu3boOrt2ibEz/8MddvNtRTGhOO28rVw5kV3p3ME
-----END PRIVATE KEY-----

#
kubectl patch svc -n tenant-0 myminio-console -p '{"spec": {"type": "NodePort", "ports": [{"port": 9443, "targetPort": 9443, "nodePort": 30001}]}}'

# 기본키(minio , minio123)
open https://127.0.0.1:30001


#
kubectl patch svc -n tenant-0 minio -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 9000, "nodePort": 30002}]}}'


# mc alias
mc alias set k8sminio https://127.0.0.1:30002 minio minio123 --insecure
mc alias list
mc admin info k8sminio --insecure

# 버킷 생성
mc mb k8sminio/mybucket --insecure
mc ls k8sminio --insecure

파일 업로드까지 완료

 

# 노드에 기본 툴 설치
docker ps
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree -y'
for node in worker worker2 worker3 worker4; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node sh -c 'apt update && apt install tree -y'; echo; done

#
kubectl describe pv
for node in worker worker2 worker3 worker4; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node tree -h /var/local-path-provisioner; echo; done

#
docker exec -it myk8s-worker  sh -c 'cat /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta'
docker exec -it myk8s-worker2 sh -c 'cat /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta'
docker exec -it myk8s-worker3 sh -c 'cat /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta'
docker exec -it myk8s-worker4 sh -c 'cat /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta'

# 혹은 pool-0 파드 내에서 확인
kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- ls -l /export/data/mybucket/life.txt
total 24
-rw-r--r-- 1 1000 1000 22680 Sep  7 13:51 xl.meta

kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- cat /export/data/mybucket/life.txt/xl.meta
...

#
mc stat k8sminio/mybucket --insecure
mc stat k8sminio/mybucket/life.txt --insecure

파일 확인 : MNMD 경우 데이터가 Multi Drives 나 Server 로 분산 저장

 

 

 

 

 

MinIO의 인증 및 인가 개요

1. 인증 (Authentication)

  • 클라이언트가 MinIO에 연결할 때 본인임을 증명하는 과정입니다.
  • MinIO는 AWS Signature 버전 4 프로토콜을 사용해 액세스 키(access key)와 비밀 키(secret key)를 검증합니다.
  • 모든 S3 및 MinIO 관리 API 요청(PUT, GET, DELETE 등)은 유효한 키가 있어야만 접근할 수 있습니다.

2. 인가 (Authorization)

  • 인증된 사용자에게 어떤 작업과 리소스에 접근할 수 있는 권한을 제한하는 과정입니다.
  • MinIO는 정책 기반 액세스 제어(PBAC)를 사용하여, 각 사용자나 그룹이 수행 가능한 작업과 접근 가능한 리소스를 정책으로 정의합니다.
  • 명시적으로 허용되지 않은 작업이나 리소스는 기본적으로 거부합니다.

ID 관리 (Identity Management)

  • MinIO는 내부 ID 관리와 외부 ID 관리 모두 지원합니다.
  • 지원하는 ID 공급자(IDP)는 다음과 같습니다:
IDP 종류설명
MinIO 내부 IDP MinIO 내장 ID 관리 기능 제공
OpenID Connect (OIDC) OIDC 호환 서비스 통해 사용자 관리
MinIO Authentication Plugin 사용자 정의 외부 인증 플러그인 지원
Active Directory / LDAP AD 또는 LDAP 기반 사용자 관리 지원
MinIO Access Management Plugin 사용자 정의 외부 접근 관리 플러그인 지원
 
  • 인증이 완료되면, MinIO는 해당 사용자가 작업 수행 권한이 있는지 판단해 허용/거부합니다.

접근 관리 (Access Management)

  • 정책 기반으로 사용자 및 그룹 권한을 정의합니다.
  • 정책은 JSON 형식으로 AWS IAM 정책과 호환되도록 설계되어 있습니다.
  • 사용자는 직접 정책을 할당받거나, 소속된 그룹에서 상속받을 수 있습니다.
  • 명시적으로 허용하지 않은 요청은 거부되며, 정책이 없으면 작업 수행 불가합니다.

정책 평가 규칙

  • AWS IAM과 마찬가지로 Deny(명시적 거부) 규칙이 Allow(허용) 규칙보다 우선합니다.
  • 예: 사용자가 어떤 작업에 대해 허용되어 있어도, 그룹에 명시적으로 거부 정책이 있으면 거부됩니다.

MinIO Identity Management 요약

1. 내장 ID 공급자 (Internal IDP)

  • MinIO는 인증을 지원하기 위해 고유한 액세스 키(사용자 이름)와 비밀 키(비밀번호)를 갖는 다수의 장기 사용자생성을 지원합니다.
  • 각 사용자는 유효한 액세스 키와 비밀 키를 통해 자신을 인증해야 합니다.
  • 관리자는 mc admin user 명령어를 통해 사용자를 생성하고 관리할 수 있습니다.
  • 또한, 액세스 키는 부모 사용자의 권한을 상속하는 자식 ID(서비스 계정 등)도 만들 수 있습니다.
  • 기본적으로 명시적으로 할당되거나 상속된 정책에 따라 허용되지 않은 작업 및 리소스는 거부됩니다.
  • 정책을 직접 사용자에게 지정하거나 그룹에 할당해 권한을 관리합니다.

2. 외부 ID 공급자 (External IDP)

  • MinIO는 OpenID Connect(OIDC)와 Active Directory/LDAP IDP를 통한 외부 ID 관리를 지원합니다.
  • AD/LDAP와 OIDC는 상호 배타적이며, AD/LDAP 외부 ID 관리를 활성화하면 내장 IDP는 비활성화됩니다.
  • OIDC는 여러 공급자의 구성이 가능하며, OIDC 사용자에게는 별도로 정책을 할당해야 합니다.

3. 권한 및 정책 관리

  • MinIO의 권한 관리는 정책 기반 접근 제어(PBAC)로 이루어집니다.
  • 정책은 JSON 형식이며 AWS IAM 정책과 호환됩니다.
  • 사용자는 명시적 정책이나 그룹 정책을 할당받아 권한을 얻습니다.
  • MinIO는 권한 허용과 거절을 정책으로 엄격히 평가하며 기본적으로 거부 우선 정책을 따른다.

 

 

Web 콘솔에서 사용자 생성 : Identity → Users → Create User : viewuser , viewpasswd , readonly ⇒ 생성 후 admin 로그 아웃

upload failed: s1 to s3://s1 An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

 

권한설정을 잘 줘도 위와 같이 에러가 나는 경우

 

 

AWS CLI 및 SDK 특정 버전(예: AWS CLI v2.23.0, boto3 1.36) 이후 버전에서는 Object Storage에서 지원하지 않는 새로운 체크섬 알고리즘이 기본적으로 활성화되기 때문에 요청에 실패한다. 따라서 이전 버전을 사용하거나, 최신 버전에서 해당 체크섬 설정을 비활성화가 필요하다.

 

<예시>
$ cat ~/.aws/config
[default]
request_checksum_calculation = WHEN_REQUIRED
response_checksum_validation = WHEN_REQUIRED

Terraform 사용 시:
최신 버전을 사용하는 경우, skip_s3_checksum = true 

 

스프링부트 프레임워크에서 application.yml에 설정시

  cloud:
    aws:
      s3:
        endpoint: https://kr.object.private.fin-ncloudstorage.com
        region: kr-standard
        checksum-validation-enabled: false  ##이부분 추가
      region:
        static: kr-standard
      credentials:
        access-key: 123123123123
        secret-key: 123123123123123123

 

 

Istio Ambient Mesh는 사이드카 프록시 없이 인프라에 통합된 데이터플레인 방식을 제공한다. 기존 Istio는 각 파드마다 사이드카 프록시를 배치하여 트래픽을 제어했다.


Ambient Mesh에서는 노드 단위로 공유되는 ztunnel 파드를 통해 파드 간 안전한 통신을 보장한다. ztunnel은 L4(전송 계층) 보안, 인증, 원격 측정, L4 정책을 제공한다. L7(애플리케이션 계층) 트래픽 제어나 정책이 필요할 때는 Waypoint Proxy 파드를 통해 처리한다.

 

Waypoint Proxy는 특정 네임스페이스 또는 서비스 계정 단위로 배포할 수 있다.

HBONE(HTTP Based Overlay Network Encapsulation) 프로토콜을 활용해 HTTP CONNECT 방식으로 트래픽을 터널링한다. HTTP/2와 mTLS를 사용하여 암호화 및 상호 인증을 제공한다.

ztunnel은 Istiod에서 xDS Config를 받아 네트워크 구성을 동적으로 적용한다.

ztunnel과 Waypoint Proxy는 서로 역할이 분리되어 보안성과 확장성을 높인다.

Ambient Mesh는 파드 스펙 변경이나 재시작 없이 메시 기능을 적용할 수 있다. 리소스 오버헤드가 기존 사이드카 방식보다 적고, 클러스터 자원 활용 효율이 높아진다. 또한 보안 측면에서 ztunnel은 노드 단위 키만 접근하므로 공격 범위가 제한된다.

기존 사이드카 방식과 Ambient Mesh 방식을 혼용해 사용할 수 있다. Ambient Mesh는 운영 단순화, 비용 절감, 확장성 개선 등 다양한 이점을 제공한다.

 

Istio의 사이드카 방식은 애플리케이션 파드의 사양을 수정하고 트래픽을 리디렉션해야 하므로, 사이드카 설치나 업그레이드 시 파드를 재시작해야 하는 부담이 있다. 각 파드별로 프록시 리소스를 최악의 상황에 맞춰 할당해야 하므로 클러스터 전체의 리소스 활용도가 저하된다. 사이드카가 트래픽 캡처와 HTTP 처리를 담당하면서 일부 비표준 HTTP 구현 애플리케이션에서는 트래픽이 차단되는 문제가 발생한다. 이러한 제약으로 인해 덜 침입적이고 사용하기 쉬운 서비스 메시 옵션의 필요성이 대두된다.

 

 

실습 환경 구성

```bash
# 
kind create cluster --name **myk8s** --image kindest/node:**v1.32.2** --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: **control-plane**
  extraPortMappings:
  - containerPort: 30000 # Sample Application
    hostPort: 30000
  - containerPort: 30001 # Prometheus
    hostPort: 30001
  - containerPort: 30002 # Grafana
    hostPort: 30002
  - containerPort: 30003 # Kiali
    hostPort: 30003
  - containerPort: 30004 # Tracing
    hostPort: 30004
  - containerPort: 30005 # kube-ops-view
    hostPort: 30005
- role: **worker**
- role: **worker**
networking:
  podSubnet: 10.10.0.0/16
  serviceSubnet: 10.200.1.0/24
EOF

# 설치 확인
docker ps

# 노드에 기본 툴 설치
for node in control-plane worker worker2; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node sh -c 'apt update && apt install tree psmisc lsof ipset wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'; echo; done
~~for node in control-plane worker worker2; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node sh -c 'DEBIAN_FRONTEND=noninteractive **apt install termshark -y**'; echo; done~~

# (옵션) kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=**NodePort**,service.main.ports.http.nodePort=**30005** --set env.TZ="Asia/Seoul" --namespace kube-system
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view

## kube-ops-view 접속 URL 확인
open "http://127.0.0.1:**30005**/#scale=1.5"
open "http://127.0.0.1:30005/#scale=1.3"
```
# kind 설치 시 kind 이름의 도커 브리지가 생성된다 : 172.18.0.0/16 대역
docker network ls
docker inspect kind


# '테스트용 PC(mypc)' 컨테이너 기동 : kind 도커 브리지를 사용하고, 컨테이너 IP를 지정 혹은 지정 없이 배포
docker run -d --rm --name mypc --network kind --ip 172.18.0.100 nicolaka/netshoot sleep infinity # IP 지정 실행 시
혹은 IP 지정 실행 시 에러 발생 시 아래 처럼 IP 지정 없이 실행
docker run -d --rm --name mypc --network kind nicolaka/netshoot sleep infinity # IP 지정 없이 실행 시
docker ps


# '웹서버(myweb1, myweb2)' 컨테이너 기동 : kind 도커 브리지를 사용
# https://hub.docker.com/r/hashicorp/http-echo
docker run -d --rm --name myweb1 --network kind --ip 172.18.0.101 hashicorp/http-echo -listen=:80 -text="myweb1 server"
docker run -d --rm --name myweb2 --network kind --ip 172.18.0.102 hashicorp/http-echo -listen=:80 -text="myweb2 server"
혹은 IP 지정 실행 시 에러 발생 시 아래 처럼 IP 지정 없이 실행
docker run -d --rm --name myweb1 --network kind hashicorp/http-echo -listen=:80 -text="myweb1 server"
docker run -d --rm --name myweb2 --network kind hashicorp/http-echo -listen=:80 -text="myweb2 server"
docker ps


# kind network 중 컨테이너(노드) IP(대역) 확인
docker ps -q | xargs docker inspect --format '{{.Name}} {{.NetworkSettings.Networks.kind.IPAddress}}'
/myweb2 172.18.0.102
/myweb1 172.18.0.101
/mypc 172.18.0.100
/myk8s-control-plane 172.18.0.2

# 동일한 docker network(kind) 내부에서 컨테이너 이름 기반 도메인 통신 가능 확인!
docker exec -it mypc curl myweb1
docker exec -it mypc curl myweb2

docker exec -it mypc curl 172.18.0.101
docker exec -it mypc curl 172.18.0.102
# MetalLB 배포
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml


# 확인
kubectl get crd
kubectl get pod -n metallb-system


# IPAddressPool, L2Advertisement 설정
cat << EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
  - 172.18.255.201-172.18.255.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
  - default
EOF

# 확인
kubectl get IPAddressPool,L2Advertisement -A
# myk8s-control-plane 진입 후 설치 진행
docker exec -it myk8s-control-plane bash
-----------------------------------
# istioctl 설치
export ISTIOV=1.26.0
echo 'export ISTIOV=1.26.0' >> /root/.bashrc

curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
istioctl version --remote=false
client version: 1.26.0

# ambient 프로파일 컨트롤 플레인 배포
istioctl install --set profile=ambient --set meshConfig.accessLogFile=/dev/stdout --skip-confirmation
istioctl install --set profile=ambient --set meshConfig.enableTracing=true -y

# Install the Kubernetes Gateway API CRDs
kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml

# 보조 도구 설치
kubectl apply -f istio-$ISTIOV/samples/addons
kubectl apply -f istio-$ISTIOV/samples/addons # nodePort 충돌 시 한번 더 입력

# 빠져나오기
exit
-----------------------------------

# 설치 확인 : istiod, istio-ingressgateway, crd 등
kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
kubectl get crd | grep istio.io
kubectl get crd | grep -v istio | grep -v metallb
kubectl get crd  | grep gateways
gateways.gateway.networking.k8s.io          2025-06-01T04:54:23Z
gateways.networking.istio.io                2025-06-01T04:53:51Z

kubectl api-resources | grep Gateway
gatewayclasses                      gc           gateway.networking.k8s.io/v1        false        GatewayClass
gateways                            gtw          gateway.networking.k8s.io/v1        true         Gateway
gateways                            gw           networking.istio.io/v1              true         Gateway

kubectl describe cm -n istio-system istio
...
Data
====
mesh:
----
accessLogFile: /dev/stdout
defaultConfig:
  discoveryAddress: istiod.istio-system.svc:15012
defaultProviders:
  metrics:
  - prometheus
enablePrometheusMerge: true
...

docker exec -it myk8s-control-plane istioctl proxy-status
NAME                           CLUSTER        CDS         LDS         EDS         RDS         ECDS        ISTIOD                     VERSION
ztunnel-25hpt.istio-system     Kubernetes     IGNORED     IGNORED     IGNORED     IGNORED     IGNORED     istiod-86b6b7ff7-x4787     1.26.0
ztunnel-4r4d4.istio-system     Kubernetes     IGNORED     IGNORED     IGNORED     IGNORED     IGNORED     istiod-86b6b7ff7-x4787     1.26.0
ztunnel-9rzzt.istio-system     Kubernetes     IGNORED     IGNORED     IGNORED     IGNORED     IGNORED     istiod-86b6b7ff7-x4787     1.26.0

docker exec -it myk8s-control-plane istioctl ztunnel-config workload
docker exec -it myk8s-control-plane istioctl ztunnel-config service

# iptables 규칙 확인
for node in control-plane worker worker2; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node sh -c 'iptables-save'; echo; done


# NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), tracing(30004)
kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'

# Prometheus 접속 : envoy, istio 메트릭 확인
open http://127.0.0.1:30001

# Grafana 접속
open http://127.0.0.1:30002

# Kiali 접속 : NodePort
open http://127.0.0.1:30003

# tracing 접속 : 예거 트레이싱 대시보드
open http://127.0.0.1:30004
# ztunnel 파드 확인 : 파드 이름 변수 지정
kubectl get pod -n istio-system -l app=ztunnel -owide
kubectl get pod -n istio-system -l app=ztunnel
ZPOD1NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[0].metadata.name}")
ZPOD2NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[1].metadata.name}")
ZPOD3NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[2].metadata.name}")
echo $ZPOD1NAME $ZPOD2NAME $ZPOD3NAME

#
kubectl describe pod -n istio-system -l app=ztunnel
...
Containers:
  istio-proxy:
    Container ID:  containerd://d81ca867bfd0c505f062ea181a070a8ab313df3591e599a22706a7f4f537ffc5
    Image:         docker.io/istio/ztunnel:1.26.0-distroless
    Image ID:      docker.io/istio/ztunnel@sha256:d711b5891822f4061c0849b886b4786f96b1728055333cbe42a99d0aeff36dbe
    Port:          15020/TCP
    ...
    Requests:
      cpu:      200m
      memory:   512Mi
    Readiness:  http-get http://:15021/healthz/ready delay=0s timeout=1s period=10s #success=1 #failure=3
    Environment:
      CA_ADDRESS:                        istiod.istio-system.svc:15012
      XDS_ADDRESS:                       istiod.istio-system.svc:15012
      RUST_LOG:                          info
      RUST_BACKTRACE:                    1
      ISTIO_META_CLUSTER_ID:             Kubernetes
      INPOD_ENABLED:                     true
      TERMINATION_GRACE_PERIOD_SECONDS:  30
      POD_NAME:                          ztunnel-9rzzt (v1:metadata.name)
      POD_NAMESPACE:                     istio-system (v1:metadata.namespace)
      NODE_NAME:                          (v1:spec.nodeName)
      INSTANCE_IP:                        (v1:status.podIP)
      SERVICE_ACCOUNT:                    (v1:spec.serviceAccountName)
      ISTIO_META_ENABLE_HBONE:           true
    Mounts:
      /tmp from tmp (rw)
      /var/run/secrets/istio from istiod-ca-cert (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-42r88 (ro)
      /var/run/secrets/tokens from istio-token (rw)
      /var/run/ztunnel from cni-ztunnel-sock-dir (rw)
    ...
Volumes:
  istio-token:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  43200
  istiod-ca-cert:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      istio-ca-root-cert
    Optional:  false
  cni-ztunnel-sock-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/run/ztunnel
    HostPathType:  DirectoryOrCreate
...


#
kubectl krew install pexec
kubectl pexec $ZPOD1NAME -it -T -n istio-system -- bash
-------------------------------------------------------
whoami

ip -c addr
ifconfig

iptables -t mangle -S
iptables -t nat -S

ss -tnlp
ss -tnp

ss -xnp
Netid       State        Recv-Q        Send-Q                               Local Address:Port                Peer Address:Port        Process                                                                              
u_str       ESTAB        0             0                                                * 44981                          * 44982        users:(("ztunnel",pid=1,fd=13),("ztunnel",pid=1,fd=8),("ztunnel",pid=1,fd=6))       
u_seq       ESTAB        0             0                    /var/run/ztunnel/ztunnel.sock 47646                          * 46988                                                                                            
u_str       ESTAB        0             0                                                * 44982                          * 44981        users:(("ztunnel",pid=1,fd=7))                                                      
u_seq       ESTAB        0             0                                                * 46988                          * 47646        users:(("ztunnel",pid=1,fd=19)) 

ls -l  /var/run/ztunnel
total 0
srwxr-xr-x    1 root     root             0 Jun  1 04:54 ztunnel.sock

# 메트릭 정보 확인
curl -s http://localhost:15020/metrics

# Viewing Istiod state for ztunnel xDS resources
curl -s http://localhost:15000/config_dump

exit
-------------------------------------------------------

# 아래 ztunnel 파드도 확인해보자
kubectl pexec $ZPOD2NAME -it -T -n istio-system -- bash
kubectl pexec $ZPOD3NAME -it -T -n istio-system -- bash


# 노드에서 기본 정보 확인
for node in control-plane worker worker2; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node sh -c 'ls -l /var/run/ztunnel'; echo; done


# ztunnel 데몬셋 파드 로그 확인
kubectl logs -n istio-system -l app=ztunnel -f
...
# ztunnel 파드 확인 : 파드 이름 변수 지정
kubectl get pod -n istio-system -l app=ztunnel -owide
kubectl get pod -n istio-system -l app=ztunnel
ZPOD1NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[0].metadata.name}")
ZPOD2NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[1].metadata.name}")
ZPOD3NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[2].metadata.name}")
echo $ZPOD1NAME $ZPOD2NAME $ZPOD3NAME

#
kubectl describe pod -n istio-system -l app=ztunnel
...
Containers:
  istio-proxy:
    Container ID:  containerd://d81ca867bfd0c505f062ea181a070a8ab313df3591e599a22706a7f4f537ffc5
    Image:         docker.io/istio/ztunnel:1.26.0-distroless
    Image ID:      docker.io/istio/ztunnel@sha256:d711b5891822f4061c0849b886b4786f96b1728055333cbe42a99d0aeff36dbe
    Port:          15020/TCP
    ...
    Requests:
      cpu:      200m
      memory:   512Mi
    Readiness:  http-get http://:15021/healthz/ready delay=0s timeout=1s period=10s #success=1 #failure=3
    Environment:
      CA_ADDRESS:                        istiod.istio-system.svc:15012
      XDS_ADDRESS:                       istiod.istio-system.svc:15012
      RUST_LOG:                          info
      RUST_BACKTRACE:                    1
      ISTIO_META_CLUSTER_ID:             Kubernetes
      INPOD_ENABLED:                     true
      TERMINATION_GRACE_PERIOD_SECONDS:  30
      POD_NAME:                          ztunnel-9rzzt (v1:metadata.name)
      POD_NAMESPACE:                     istio-system (v1:metadata.namespace)
      NODE_NAME:                          (v1:spec.nodeName)
      INSTANCE_IP:                        (v1:status.podIP)
      SERVICE_ACCOUNT:                    (v1:spec.serviceAccountName)
      ISTIO_META_ENABLE_HBONE:           true
    Mounts:
      /tmp from tmp (rw)
      /var/run/secrets/istio from istiod-ca-cert (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-42r88 (ro)
      /var/run/secrets/tokens from istio-token (rw)
      /var/run/ztunnel from cni-ztunnel-sock-dir (rw)
    ...
Volumes:
  istio-token:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  43200
  istiod-ca-cert:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      istio-ca-root-cert
    Optional:  false
  cni-ztunnel-sock-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/run/ztunnel
    HostPathType:  DirectoryOrCreate
...


#
kubectl krew install pexec
kubectl pexec $ZPOD1NAME -it -T -n istio-system -- bash
-------------------------------------------------------
whoami

ip -c addr
ifconfig

iptables -t mangle -S
iptables -t nat -S

ss -tnlp
ss -tnp

ss -xnp
Netid       State        Recv-Q        Send-Q                               Local Address:Port                Peer Address:Port        Process                                                                              
u_str       ESTAB        0             0                                                * 44981                          * 44982        users:(("ztunnel",pid=1,fd=13),("ztunnel",pid=1,fd=8),("ztunnel",pid=1,fd=6))       
u_seq       ESTAB        0             0                    /var/run/ztunnel/ztunnel.sock 47646                          * 46988                                                                                            
u_str       ESTAB        0             0                                                * 44982                          * 44981        users:(("ztunnel",pid=1,fd=7))                                                      
u_seq       ESTAB        0             0                                                * 46988                          * 47646        users:(("ztunnel",pid=1,fd=19)) 

ls -l  /var/run/ztunnel
total 0
srwxr-xr-x    1 root     root             0 Jun  1 04:54 ztunnel.sock

# 메트릭 정보 확인
curl -s http://localhost:15020/metrics

# Viewing Istiod state for ztunnel xDS resources
curl -s http://localhost:15000/config_dump

exit
-------------------------------------------------------

# 아래 ztunnel 파드도 확인해보자
kubectl pexec $ZPOD2NAME -it -T -n istio-system -- bash
kubectl pexec $ZPOD3NAME -it -T -n istio-system -- bash


# 노드에서 기본 정보 확인
for node in control-plane worker worker2; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node sh -c 'ls -l /var/run/ztunnel'; echo; done


# ztunnel 데몬셋 파드 로그 확인
kubectl logs -n istio-system -l app=ztunnel -f
...

 

 

#
docker exec -it myk8s-control-plane ls -l istio-1.26.0
total 40
-rw-r--r--  1 root root 11357 May  7 11:05 LICENSE
-rw-r--r--  1 root root  6927 May  7 11:05 README.md
drwxr-x---  2 root root  4096 May  7 11:05 bin
-rw-r-----  1 root root   983 May  7 11:05 manifest.yaml
drwxr-xr-x  4 root root  4096 May  7 11:05 manifests
drwxr-xr-x 27 root root  4096 May  7 11:05 samples
drwxr-xr-x  3 root root  4096 May  7 11:05 tools

# Deploy the Bookinfo sample application:
docker exec -it myk8s-control-plane kubectl apply -f istio-1.26.0/samples/bookinfo/platform/kube/bookinfo.yaml

# 확인
kubectl get deploy,pod,svc,ep
docker exec -it myk8s-control-plane istioctl ztunnel-config service
docker exec -it myk8s-control-plane istioctl ztunnel-config workload
docker exec -it myk8s-control-plane istioctl proxy-status


# 통신 확인 : ratings 에서 productpage 페이지
kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"


# 요청 테스트용 파드 생성 : netshoot
kubectl create sa netshoot

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: netshoot
spec:
  serviceAccountName: netshoot
  nodeName: myk8s-control-plane
  containers:
  - name: netshoot
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

# 요청 확인
kubectl exec -it netshoot -- curl -sS productpage:9080/productpage | grep -i title

# 반복 요청
while true; do kubectl exec -it netshoot -- curl -sS productpage:9080/productpage | grep -i title ; date "+%Y-%m-%d %H:%M:%S"; sleep 1; done

 

#
docker exec -it myk8s-control-plane cat istio-1.26.0/samples/bookinfo/gateway-api/bookinfo-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  gatewayClassName: istio
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bookinfo
spec:
  parentRefs:
  - name: bookinfo-gateway
  rules:
  - matches:
    - path:
        type: Exact
        value: /productpage
    - path:
        type: PathPrefix
        value: /static
    - path:
        type: Exact
        value: /login
    - path:
        type: Exact
        value: /logout
    - path:
        type: PathPrefix
        value: /api/v1/products
    backendRefs:
    - name: productpage
      port: 9080

docker exec -it myk8s-control-plane kubectl apply -f istio-1.26.0/samples/bookinfo/gateway-api/bookinfo-gateway.yaml

# 확인
kubectl get gateway
NAME               CLASS   ADDRESS          PROGRAMMED   AGE
bookinfo-gateway   istio   172.18.255.201   True         75s

kubectl get HTTPRoute
NAME       HOSTNAMES   AGE
bookinfo               101s

kubectl get svc,ep bookinfo-gateway-istio
NAME                             TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                        AGE
service/bookinfo-gateway-istio   LoadBalancer   10.200.1.122   172.18.255.201   15021:30870/TCP,80:31570/TCP   2m37s

NAME                               ENDPOINTS                      AGE
endpoints/bookinfo-gateway-istio   10.10.1.6:15021,10.10.1.6:80   2m37s

kubectl get pod -l gateway.istio.io/managed=istio.io-gateway-controller -owide
NAME                                      READY   STATUS    RESTARTS   AGE     IP          NODE            NOMINATED NODE   READINESS GATES
bookinfo-gateway-istio-6cbd9bcd49-fwqqp   1/1     Running   0          3m45s   10.10.1.6   myk8s-worker2   <none>           <none>

# 접속 확인
docker ps

kubectl get svc bookinfo-gateway-istio -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
GWLB=$(kubectl get svc bookinfo-gateway-istio -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
docker exec -it mypc curl $GWLB/productpage -v
docker exec -it mypc curl $GWLB/productpage -I

# 반복 요청 : 아래 mypc 컨테이너에서 반복 요청 계속 해두기!
GWLB=$(kubectl get svc bookinfo-gateway-istio -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
while true; do docker exec -it mypc curl $GWLB/productpage | grep -i title ; date "+%Y-%m-%d %H:%M:%S"; sleep 1; done


# 자신의 로컬 PC에서 접속 시도
kubectl patch svc bookinfo-gateway-istio -p '{"spec": {"type": "LoadBalancer", "ports": [{"port": 80, "targetPort": 80, "nodePort": 30000}]}}'
kubectl get svc bookinfo-gateway-istio

open "http://127.0.0.1:30000/productpage"

# 반복 요청
while true; do curl -s http://127.0.0.1:30000/productpage | grep -i title ; date "+%Y-%m-%d %H:%M:%S"; sleep 1; done

 

Adding your application to ambient- Docs

  • The namespace or pod has the label istio.io/dataplane-mode=ambient
  • The pod does not have the opt-out label istio.io/dataplane-mode=none
# 디폴트 네임스페이서 모든 파드들에 ambient mesh 통신 적용 설정
# You can enable all pods in a given namespace to be part of the ambient mesh by simply labeling the namespace:
kubectl label namespace default istio.io/dataplane-mode=ambient

# 파드 정보 확인 : 사이트카가 없다! , 파드 수명 주기에 영향도 없다! -> mTLS 암호 통신 제공, L4 텔레메트리(메트릭) 제공
docker exec -it myk8s-control-plane istioctl proxy-status
kubectl get pod

#
docker exec -it myk8s-control-plane istioctl ztunnel-config workload
NAMESPACE          POD NAME                                    ADDRESS    NODE                WAYPOINT PROTOCOL
default            details-v1-766844796b-nfsh8                 10.10.2.16 myk8s-worker        None     HBONE
default            netshoot                                    10.10.0.7  myk8s-control-plane None     HBONE
default            productpage-v1-54bb874995-xkq54             10.10.2.20 myk8s-worker        None     HBONE
...

docker exec -it myk8s-control-plane istioctl ztunnel-config workload --address 10.10.2.20
NAMESPACE POD NAME                        ADDRESS    NODE         WAYPOINT PROTOCOL
default   productpage-v1-54bb874995-xkq54 10.10.2.20 myk8s-worker None     HBONE

docker exec -it myk8s-control-plane istioctl ztunnel-config workload --address 10.10.2.20 -o json
[
    {
        "uid": "Kubernetes//Pod/default/productpage-v1-54bb874995-xkq54",
        "workloadIps": [
            "10.10.2.20"
        ],
        "protocol": "HBONE",
        "name": "productpage-v1-54bb874995-xkq54",
        "namespace": "default",
        "serviceAccount": "bookinfo-productpage",
        "workloadName": "productpage-v1",
        "workloadType": "pod",
        "canonicalName": "productpage",
        "canonicalRevision": "v1",
        "clusterId": "Kubernetes",
        "trustDomain": "cluster.local",
        "locality": {},
        "node": "myk8s-worker",
        "status": "Healthy",
...


#
PPOD=$(kubectl get pod -l app=productpage -o jsonpath='{.items[0].metadata.name}')

kubectl pexec $PPOD -it -T -- bash
-------------------------------------------------------
iptables-save
iptables -t mangle -S
iptables -t nat -S
ss -tnlp
ss -tnp
ss -xnp
ls -l  /var/run/ztunnel

# 메트릭 정보 확인
curl -s http://localhost:15020/metrics | grep '^[^#]'
...

# Viewing Istiod state for ztunnel xDS resources
curl -s http://localhost:15000/config_dump

exit
-------------------------------------------------------


# 노드에서 ipset 확인 : 파드들의 ip를 멤버로 관리 확인
for node in control-plane worker worker2; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node ipset list; echo; done
...
Members:
10.10.2.15 comment "57009539-36bb-42e0-bdac-4c2356fabbd3"
10.10.2.19 comment "64f46320-b85d-4e10-ab97-718d4e282116"
10.10.2.17 comment "b5ff9b4c-722f-48ef-a789-a95485fe9fa8"
10.10.2.18 comment "c6b368f7-6b6f-4d1d-8dbe-4ee85d7c9c22"
10.10.2.16 comment "cd1b1016-5570-4492-ba3a-4299790029d9"
10.10.2.20 comment "2b97238b-3b37-4a13-87a2-70755cb225e6"

# istio-cni-node 로그 확인
kubectl -n istio-system logs -l k8s-app=istio-cni-node -f
...

# ztunnel 파드 로그 모니터링 : IN/OUT 트래픽 정보
kubectl -n istio-system logs -l app=ztunnel -f | egrep "inbound|outbound"
2025-06-01T06:37:49.162266Z     info    access  connection complete     src.addr=10.10.2.20:48392 src.workload="productpage-v1-54bb874995-xkq54" src.namespace="default" src.identity="spiffe://cluster.local/ns/default/sa/bookinfo-productpage" dst.addr=10.10.2.18:15008 dst.hbone_addr=10.10.2.18:9080 dst.service="reviews.default.svc.cluster.local" dst.workload="reviews-v2-556d6457d-4r8n8" dst.namespace="default" dst.identity="spiffe://cluster.local/ns/default/sa/bookinfo-reviews" direction="inbound" bytes_sent=602 bytes_recv=192 duration="31ms"
2025-06-01T06:37:49.162347Z     info    access  connection complete     src.addr=10.10.2.20:53412 src.workload="productpage-v1-54bb874995-xkq54" src.namespace="default" src.identity="spiffe://cluster.local/ns/default/sa/bookinfo-productpage" dst.addr=10.10.2.18:15008 dst.hbone_addr=10.10.2.18:9080 dst.service="reviews.default.svc.cluster.local" dst.workload="reviews-v2-556d6457d-4r8n8" dst.namespace="default" dst.identity="spiffe://cluster.local/ns/default/sa/bookinfo-reviews" direction="outbound" bytes_sent=192 bytes_recv=602 duration="31ms"


# ztunnel 파드 확인 : 파드 이름 변수 지정
kubectl get pod -n istio-system -l app=ztunnel -owide
kubectl get pod -n istio-system -l app=ztunnel
ZPOD1NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[0].metadata.name}")
ZPOD2NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[1].metadata.name}")
ZPOD3NAME=$(kubectl get pod -n istio-system -l app=ztunnel -o jsonpath="{.items[2].metadata.name}")
echo $ZPOD1NAME $ZPOD2NAME $ZPOD3NAME

#
kubectl pexec $ZPOD1NAME -it -T -n istio-system -- bash
-------------------------------------------------------
iptables -t mangle -S
iptables -t nat -S
ss -tnlp
ss -tnp
ss -xnp
ls -l  /var/run/ztunnel

# 메트릭 정보 확인
curl -s http://localhost:15020/metrics | grep '^[^#]'
...

# Viewing Istiod state for ztunnel xDS resources
curl -s http://localhost:15000/config_dump

exit
-------------------------------------------------------

# netshoot 파드만 ambient mode 에서 제외해보자
docker exec -it myk8s-control-plane istioctl ztunnel-config workload
kubectl label pod netshoot istio.io/dataplane-mode=none
docker exec -it myk8s-control-plane istioctl ztunnel-config workload
NAMESPACE          POD NAME                                    ADDRESS    NODE                WAYPOINT PROTOCOL
default            netshoot                                    10.10.0.7  myk8s-control-plane None     TCP

default NS는 HBONE으로 동작하는것을 알 수 있다.

 

PS.

기존 사이드카 구성에서 ambient mode로 변경하려면... 어떡해야할까..

https://ambientmesh.io/docs/setup/sidecar-migration/

 

Migrating to ambient mesh from Istio in sidecar mode

The Solo ambient mesh migration tool provides a prescriptive path for migrating from Istio’s sidecar mode to ambient mode. This migration is zero-downtime when used with the free Solo builds of Istio, but can also translate Kubernetes manifests for users

ambientmesh.io

 

 

ztunnel-config

# A group of commands used to update or retrieve Ztunnel configuration from a Ztunnel instance.
docker exec -it myk8s-control-plane istioctl ztunnel-config
  all         Retrieves all configuration for the specified Ztunnel pod.
  certificate Retrieves certificate for the specified Ztunnel pod.
  connections Retrieves connections for the specified Ztunnel pod.
  log         Retrieves logging levels of the Ztunnel instance in the specified pod.
  policy      Retrieves policies for the specified Ztunnel pod.
  service     Retrieves services for the specified Ztunnel pod.
  workload    Retrieves workload configuration for the specified Ztunnel pod.
...

docker exec -it myk8s-control-plane istioctl ztunnel-config service
NAMESPACE      SERVICE NAME            SERVICE VIP  WAYPOINT ENDPOINTS
default        bookinfo-gateway-istio  10.200.1.122 None     1/1
default        details                 10.200.1.202 None     1/1
default        kubernetes              10.200.1.1   None     1/1
default        productpage             10.200.1.207 None     1/1
default        ratings                 10.200.1.129 None     1/1
default        reviews                 10.200.1.251 None     3/3
...

docker exec -it myk8s-control-plane istioctl ztunnel-config service --service-namespace default --node myk8s-worker
docker exec -it myk8s-control-plane istioctl ztunnel-config service --service-namespace default --node myk8s-worker2
docker exec -it myk8s-control-plane istioctl ztunnel-config service --service-namespace default --node myk8s-worker2 -o json
...
    {
        "name": "productpage",
        "namespace": "default",
        "hostname": "productpage.default.svc.cluster.local",
        "vips": [
            "/10.200.1.207"
        ],
        "ports": {
            "9080": 9080
        },
        "endpoints": {
            "Kubernetes//Pod/default/productpage-v1-54bb874995-xkq54": {
                "workloadUid": "Kubernetes//Pod/default/productpage-v1-54bb874995-xkq54",
                "service": "",
                "port": {
                    "9080": 9080
                }
            }
        },
        "ipFamilies": "IPv4"
    },
...

docker exec -it myk8s-control-plane istioctl ztunnel-config workload
docker exec -it myk8s-control-plane istioctl ztunnel-config workload --workload-namespace default
docker exec -it myk8s-control-plane istioctl ztunnel-config workload --workload-namespace default --node myk8s-worker2
docker exec -it myk8s-control-plane istioctl ztunnel-config workload --workload-namespace default --node myk8s-worker -o json
...
    {
        "uid": "Kubernetes//Pod/default/productpage-v1-54bb874995-xkq54",
        "workloadIps": [
            "10.10.2.20"
        ],
        "protocol": "HBONE",
        "name": "productpage-v1-54bb874995-xkq54",
        "namespace": "default",
        "serviceAccount": "bookinfo-productpage",
        "workloadName": "productpage-v1",
        "workloadType": "pod",
        "canonicalName": "productpage",
        "canonicalRevision": "v1",
        "clusterId": "Kubernetes",
        "trustDomain": "cluster.local",
        "locality": {},
        "node": "myk8s-worker",
        "status": "Healthy",
        "hostname": "",
        "capacity": 1,
        "applicationTunnel": {
            "protocol": ""
        }
    },
...

docker exec -it myk8s-control-plane istioctl ztunnel-config certificate --node myk8s-worker
CERTIFICATE NAME                                              TYPE     STATUS        VALID CERT     SERIAL NUMBER                        NOT AFTER                NOT BEFORE
spiffe://cluster.local/ns/default/sa/bookinfo-details         Leaf     Available     true           6399f0ac1d1f508088c731791930a03a     2025-06-02T06:21:46Z     2025-06-01T06:19:46Z
spiffe://cluster.local/ns/default/sa/bookinfo-details         Root     Available     true           8a432683a288fb4b61d5775dcf47019d     2035-05-30T04:53:58Z     2025-06-01T04:53:58Z
spiffe://cluster.local/ns/default/sa/bookinfo-productpage     Leaf     Available     true           f727d33914e23029b3c889c67efe12e1     2025-06-02T06:21:46Z     2025-06-01T06:19:46Z
spiffe://cluster.local/ns/default/sa/bookinfo-productpage     Root     Available     true           8a432683a288fb4b61d5775dcf47019d     2035-05-30T04:53:58Z     2025-06-01T04:53:58Z
spiffe://cluster.local/ns/default/sa/bookinfo-ratings         Leaf     Available     true           d1af8176f5047f620d7795a4775869ad     2025-06-02T06:21:46Z     2025-06-01T06:19:46Z
spiffe://cluster.local/ns/default/sa/bookinfo-ratings         Root     Available     true           8a432683a288fb4b61d5775dcf47019d     2035-05-30T04:53:58Z     2025-06-01T04:53:58Z
spiffe://cluster.local/ns/default/sa/bookinfo-reviews         Leaf     Available     true           af013ce3f7dca5dc1bead36455155d65     2025-06-02T06:21:46Z     2025-06-01T06:19:46Z
spiffe://cluster.local/ns/default/sa/bookinfo-reviews         Root     Available     true           8a432683a288fb4b61d5775dcf47019d     2035-05-30T04:53:58Z     2025-06-01T04:53:58Z

docker exec -it myk8s-control-plane istioctl ztunnel-config certificate --node myk8s-worker -o json
...


docker exec -it myk8s-control-plane istioctl ztunnel-config connections --node myk8s-worker
WORKLOAD                                DIRECTION LOCAL                                        REMOTE                                                REMOTE TARGET                          PROTOCOL
productpage-v1-54bb874995-xkq54.default Inbound   productpage-v1-54bb874995-xkq54.default:9080 bookinfo-gateway-istio-6cbd9bcd49-fwqqp.default:33052                                        HBONE
ratings-v1-5dc79b6bcd-64kcm.default     Inbound   ratings-v1-5dc79b6bcd-64kcm.default:9080     reviews-v2-556d6457d-4r8n8.default:56440              ratings.default.svc.cluster.local      HBONE
reviews-v2-556d6457d-4r8n8.default      Outbound  reviews-v2-556d6457d-4r8n8.default:41722     ratings-v1-5dc79b6bcd-64kcm.default:15008             ratings.default.svc.cluster.local:9080 HBONE

docker exec -it myk8s-control-plane istioctl ztunnel-config connections --node myk8s-worker --raw 
WORKLOAD                                DIRECTION LOCAL            REMOTE           REMOTE TARGET                     PROTOCOL
productpage-v1-54bb874995-xkq54.default Inbound   10.10.2.20:9080  10.10.1.6:33064                                    HBONE
productpage-v1-54bb874995-xkq54.default Inbound   10.10.2.20:9080  10.10.1.6:33052                                    HBONE
ratings-v1-5dc79b6bcd-64kcm.default     Inbound   10.10.2.15:9080  10.10.2.18:56440 ratings.default.svc.cluster.local HBONE
ratings-v1-5dc79b6bcd-64kcm.default     Inbound   10.10.2.15:9080  10.10.2.19:56306 ratings.default.svc.cluster.local HBONE
reviews-v2-556d6457d-4r8n8.default      Outbound  10.10.2.18:45530 10.10.2.15:15008 10.200.1.129:9080                 HBONE
reviews-v3-564544b4d6-nmf92.default     Outbound  10.10.2.19:56168 10.10.2.15:15008 10.200.1.129:9080                 HBONE

docker exec -it myk8s-control-plane istioctl ztunnel-config connections --node myk8s-worker -o json
...
   {
        "state": "Up",
        "connections": {
            "inbound": [
                {
                    "src": "10.10.2.18:56440",
                    "originalDst": "ratings.default.svc.cluster.local",
                    "actualDst": "10.10.2.15:9080",
                    "protocol": "HBONE"
                },
                {
                    "src": "10.10.2.19:56306",
                    "originalDst": "ratings.default.svc.cluster.local",
                    "actualDst": "10.10.2.15:9080",
                    "protocol": "HBONE"
                }
            ],
            "outbound": []
        },
        "info": {
            "name": "ratings-v1-5dc79b6bcd-64kcm",
            "namespace": "default",
            "trustDomain": "",
            "serviceAccount": "bookinfo-ratings"
        }
    },
...

#
docker exec -it myk8s-control-plane istioctl ztunnel-config policy   
NAMESPACE POLICY NAME ACTION SCOPE

#
docker exec -it myk8s-control-plane istioctl ztunnel-config log   
ztunnel-25hpt.istio-system:
current log level is hickory_server::server::server_future=off,info
...

 

 

Secure Application Access : L4 Authorization Policy - Docs

Istio의 앰비언트 모드에서는 ztunnel을 통해 L4 보안 정책을 지원하며 호환 CNI 플러그인 기반 쿠버네티스 네트워크 정책과의 병행 사용이 가능하고, ztunnel과 웨이포인트 프록시의 계층화 구조를 통해 워크로드 단위로 L7 처리 여부를 선택적으로 적용할 수 있으며 정책 시행 지점이 다중화되는 특성이 있다.

# netshoot 파드만 ambient mode 다시 참여
docker exec -it myk8s-control-plane istioctl ztunnel-config workload
kubectl label pod netshoot istio.io/dataplane-mode=ambient --overwrite
docker exec -it myk8s-control-plane istioctl ztunnel-config workload


# L4 Authorization Policy 신규 생성
# Explicitly allow the netshoot and gateway service accounts to call the productpage service:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: productpage-viewer
  namespace: default
spec:
  selector:
    matchLabels:
      app: productpage
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/default/sa/netshoot
EOF

# L4 Authorization Policy 생성 확인
kubectl get authorizationpolicy
NAME                 AGE
productpage-viewer   8s

# ztunnel 파드 로그 모니터링
kubectl logs ds/ztunnel -n istio-system -f | grep -E RBAC

# L4 Authorization Policy 동작 확인
## 차단 확인!
GWLB=$(kubectl get svc bookinfo-gateway-istio -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
while true; do docker exec -it mypc curl $GWLB/productpage | grep -i title ; date "+%Y-%m-%d %H:%M:%S"; sleep 1; done

## 허용 확인!
kubectl exec -it netshoot -- curl -sS productpage:9080/productpage | grep -i title
while true; do kubectl exec -it netshoot -- curl -sS productpage:9080/productpage | grep -i title ; date "+%Y-%m-%d %H:%M:%S"; sleep 1; done


# L4 Authorization Policy 업데이트
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: productpage-viewer
  namespace: default
spec:
  selector:
    matchLabels:
      app: productpage
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/default/sa/netshoot
        - cluster.local/ns/default/sa/bookinfo-gateway-istio
EOF

kubectl logs ds/ztunnel -n istio-system -f | grep -E RBAC


# 허용 확인!
GWLB=$(kubectl get svc bookinfo-gateway-istio -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
while true; do docker exec -it mypc curl $GWLB/productpage | grep -i title ; date "+%Y-%m-%d %H:%M:%S"; sleep 1; done

 

netshoot POD에서 실행된 요청은 정상 접근되는것을 알 수 있다.

Configure waypoint proxies - Docs

Istio 앰비언트 모드는 **ztunnel(L4)**과 **웨이포인트 프록시(L7)**의 계층적 구조로 운영되며, ztunnel은 노드 단위 mTLS 암호화 및 L4 트래픽 관리를 담당하고 웨이포인트는 선택적 L7 기능(HTTP 라우팅/정책/메트릭)을 처리한다. 웨이포인트 프록시는 네임스페이스 단위로 배포되며 여러 워크로드에서 공유 가능해 사이드카 대비 90% 이상의 리소스 절감 효과를 제공한다. L7 기능 필요 시에만 웨이포인트를 활성화할 수 있어 점진적 도입이 가능하며, HTTP 기반 트래픽 관리/보안 정책/관측성이 필요한 경우에 한해 배포딘다. 정책 시행 지점이 목적지 측 웨이포인트로 이동해 중앙 집중식 정책 관리가 가능하며, HBONE 프로토콜을 통해 ztunnel-웨이포인트 간 트래픽을 안전하게 전달한다. 앰비언트 모드 전환 시 기존 사이드카 구성과의 혼용 운영이 가능하며, CNI 플러그인과의 호환성을 통해 쿠버네티스 네트워크 정책과의 병행 사용이 지원된다.

# istioctl can generate a Kubernetes Gateway resource for a waypoint proxy. 
# For example, to generate a waypoint proxy named waypoint for the default namespace that can process traffic for services in the namespace:
kubectl describe pod bookinfo-gateway-istio-6cbd9bcd49-6cphf | grep 'Service Account'
Service Account:  bookinfo-gateway-istio

# Generate a waypoint configuration as YAML
docker exec -it myk8s-control-plane istioctl waypoint generate -h

# --for string        Specify the traffic type [all none service workload] for the waypoint
istioctl waypoint generate --for service -n default
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  labels:
    istio.io/waypoint-for: service
  name: waypoint
  namespace: default
spec:
  gatewayClassName: istio-waypoint
  listeners:
  - name: mesh
    port: 15008
    protocol: HBONE

#
docker exec -it myk8s-control-plane istioctl waypoint apply -n default
✅ waypoint default/waypoint applied

kubectl get gateway 
kubectl get gateway waypoint -o yaml
...

#
kubectl get pod -l service.istio.io/canonical-name=waypoint -owide
NAME                      READY   STATUS    RESTARTS   AGE     IP           NODE           NOMINATED NODE   READINESS GATES
waypoint-66b59898-p7v5x   1/1     Running   0          2m15s   10.10.1.21   myk8s-worker   <none>           <none>

#
docker exec -it myk8s-control-plane istioctl waypoint list  
NAME         REVISION     PROGRAMMED
waypoint     default      True

docker exec -it myk8s-control-plane istioctl waypoint status
NAMESPACE     NAME         STATUS     TYPE           REASON         MESSAGE
default       waypoint     True       Programmed     Programmed     Resource programmed, assigned to service(s) waypoint.default.svc.cluster.local:15008

docker exec -it myk8s-control-plane istioctl proxy-status   
NAME                                                CLUSTER        CDS               LDS               EDS               RDS               ECDS        ISTIOD                     VERSION
bookinfo-gateway-istio-6cbd9bcd49-6cphf.default     Kubernetes     SYNCED (5m5s)     SYNCED (5m5s)     SYNCED (5m4s)     SYNCED (5m5s)     IGNORED     istiod-86b6b7ff7-gmtdw     1.26.0
waypoint-66b59898-p7v5x.default                     Kubernetes     SYNCED (5m4s)     SYNCED (5m4s)     IGNORED           IGNORED           IGNORED     istiod-86b6b7ff7-gmtdw     1.26.0
ztunnel-52d22.istio-system                          Kubernetes     IGNORED           IGNORED           IGNORED           IGNORED           IGNORED     istiod-86b6b7ff7-gmtdw     1.26.0
ztunnel-ltckp.istio-system                          Kubernetes     IGNORED           IGNORED           IGNORED           IGNORED           IGNORED     istiod-86b6b7ff7-gmtdw     1.26.0
ztunnel-mg4mn.istio-system                          Kubernetes     IGNORED           IGNORED           IGNORED           IGNORED           IGNORED     istiod-86b6b7ff7-gmtdw     1.26.0

docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/waypoint                              
RESOURCE NAME     TYPE           STATUS     VALID CERT     SERIAL NUMBER                        NOT AFTER                NOT BEFORE
default           Cert Chain     ACTIVE     true           4346296f183e559a876c0410cb154f50     2025-06-02T10:11:45Z     2025-06-01T10:09:45Z
ROOTCA            CA             ACTIVE     true           aa779aa04b241aedaa8579c0bc5c3b5f     2035-05-30T09:19:54Z     2025-06-01T09:19:54Z

#
kubectl pexec waypoint-66b59898-dlrj4 -it -T -- bash
----------------------------------------------
ip -c a

curl -s http://localhost:15020/stats/prometheus

ss -tnlp
State           Recv-Q          Send-Q                   Local Address:Port                    Peer Address:Port         Process                                 
LISTEN          0               4096                         127.0.0.1:15000                        0.0.0.0:*             users:(("envoy",pid=18,fd=18))         
LISTEN          0               4096                           0.0.0.0:15008                        0.0.0.0:*             users:(("envoy",pid=18,fd=35))         
LISTEN          0               4096                           0.0.0.0:15008                        0.0.0.0:*             users:(("envoy",pid=18,fd=34))         
LISTEN          0               4096                           0.0.0.0:15021                        0.0.0.0:*             users:(("envoy",pid=18,fd=23))         
LISTEN          0               4096                           0.0.0.0:15021                        0.0.0.0:*             users:(("envoy",pid=18,fd=22))         
LISTEN          0               4096                           0.0.0.0:15090                        0.0.0.0:*             users:(("envoy",pid=18,fd=21))         
LISTEN          0               4096                           0.0.0.0:15090                        0.0.0.0:*             users:(("envoy",pid=18,fd=20))         
LISTEN          0               4096                                 *:15020                              *:*             users:(("pilot-agent",pid=1,fd=11))  

ss -tnp

ss -xnlp
ss -xnp

exit
----------------------------------------------

 

 

 

 

이로써 9주간의 istio 스터디가 끝났다.

가시다 님 및 운영진님들 고생하셨고 좋은 스터디 제공해주셔서 감사합니다.

 

 

+ Recent posts