※ Label vs Selector 핵심 비교

구분 Label (이름표) Selector (검색기)
정의 리소스를 식별하기 위한 Key-Value 특정 Label을 가진 리소스를 선택하는 필터
위치 metadata.labels 항목에 작성 spec.selector 항목에 작성
사용 주체 Pod, Node (관리 대상) Service, Deployment, HPA (관리 주체)
비유 상품에 붙어 있는 바코드/태그 바코드를 찍어 물건을 분류하는 스캐너
역할 "나는 'A'라는 그룹 소속이다"라고 표시 "나는 'A' 그룹인 애들만 관리하겠다"라고 연결

 


 

1. k8s 환경 세팅

# k8s 에서 directory 생성
[root@k8s-master ~]#
mkdir -p /root/k8s-local-volume/1231

# k8s 대시보드에서 objec들 생성

dashboard 접속 > Namespace [모든 네임스페이스] > [+] 버튼 > [입력을 통해 생성] > yaml 파일 붙여넣기 > 업로드

- 아래는 yml.

더보기

apiVersion: v1
kind: Namespace
metadata:
  name: anotherclass-123
  labels:
    part-of: k8s-anotherclass
    managed-by: dashboard
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: api-tester-1231-files
  labels:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231-files
    version: 1.0.0
    managed-by: dashboard
spec:
  capacity:
    storage: 2G
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  local:
    path: "/root/k8s-local-volume/1231"
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - {key: kubernetes.io/hostname, operator: In, values: [k8s-master]}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: anotherclass-123
  name: api-tester-1231-files
  labels:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231
    version: 1.0.0
    managed-by: kubectl
spec:
  resources:
    requests:
      storage: 2G
  accessModes:
    - ReadWriteMany
  selector:
    matchLabels:
      part-of: k8s-anotherclass
      component: backend-server
      name: api-tester
      instance: api-tester-1231-files
---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: anotherclass-123
  name: api-tester-1231-properties
  labels:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231
    version: 1.0.0
    managed-by: dashboard
data:
  spring_profiles_active: "dev"
  application_role: "ALL"
  postgresql_filepath: "/usr/src/myapp/datasource/postgresql-info.yaml"
---
apiVersion: v1
kind: Secret
metadata:
  namespace: anotherclass-123
  name: api-tester-1231-postgresql
  labels:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231
    version: 1.0.0
    managed-by: dashboard
stringData:
  postgresql-info.yaml: |
    driver-class-name: "org.postgresql.Driver"
    url: "jdbc:postgresql://postgresql:5431"
    username: "dev"
    password: "dev123"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: anotherclass-123
  name: api-tester-1231
  labels:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231
    version: 1.0.0
    managed-by: dashboard
spec:
  selector:
    matchLabels:
      part-of: k8s-anotherclass
      component: backend-server
      name: api-tester
      instance: api-tester-1231
  replicas: 2
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        part-of: k8s-anotherclass
        component: backend-server
        name: api-tester
        instance: api-tester-1231
        version: 1.0.0
    spec:
      nodeSelector:
        kubernetes.io/hostname: k8s-master
      containers:
        - name: api-tester-1231
          image: 1pro/api-tester:v1.0.0
          ports:
          - name: http
            containerPort: 8080
          envFrom:
            - configMapRef:
                name: api-tester-1231-properties
          startupProbe:
            httpGet:
              path: "/startup"
              port: 8080
            periodSeconds: 5
            failureThreshold: 36
          readinessProbe:
            httpGet:
              path: "/readiness"
              port: 8080
            periodSeconds: 10
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: "/liveness"
              port: 8080
            periodSeconds: 10
            failureThreshold: 3
          resources:
            requests:
              memory: "100Mi"
              cpu: "100m"
            limits:
              memory: "200Mi"
              cpu: "200m"
          volumeMounts:
            - name: files
              mountPath: /usr/src/myapp/files/dev
            - name: secret-datasource
              mountPath: /usr/src/myapp/datasource
      volumes:
        - name: files
          persistentVolumeClaim:
            claimName: api-tester-1231-files
        - name: secret-datasource
          secret:
            secretName: api-tester-1231-postgresql
---
apiVersion: v1
kind: Service
metadata:
  namespace: anotherclass-123
  name: api-tester-1231
  labels:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231
    version: 1.0.0
    managed-by: dashboard
spec:
  selector:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231
  ports:
    - port: 80
      targetPort: http
      nodePort: 31231
  type: NodePort
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  namespace: anotherclass-123
  name: api-tester-1231-default
  labels:
    part-of: k8s-anotherclass
    component: backend-server
    name: api-tester
    instance: api-tester-1231
    version: 1.0.0
    managed-by: dashboard
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-tester-1231
  minReplicas: 2
  maxReplicas: 4
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 120

object 삭제 script

[root@k8s-master ~]# kubectl delete ns anotherclass-123

[root@k8s-master ~]# kubectl delete pv api-tester-1231-files

 

 

2. Obejct

 

3. Label / Selector / Naming (1)

 

3. Label / Selector / Naming (2)

 

 

 

 

k8s Web Application 배포 시 세팅해야 하는 기본(주요) 리소스

- 웹 서비스를 완성하는 4대 핵심 리소스 : 앱 관리(Deployment), 내부 연결(Service), 부하 대응(HPA), 도메인 접속(Ingress)

  > k8s 설정 yml에서 kind에 들어가는 속성

  • Deployment : 컨테이너를 몇 개 띄울지 결정하고, 앱이 죽으면 다시 살리며, 업데이트 시 중단 없이 교체해주는 컨트롤러
  • Service : 파드는 IP가 수시로 변하므로, 서비스라는 고정된 이름을 통해 파드들이 서로 통신하거나 외부에서 접속할 수 있게 연결
  • HPA (Horizontal Pod Autoscaler) : CPU나 메모리 사용량이 설정치를 넘어가면 Deployment의 replicas를 자동으로 늘려 서버 다운을 방지
  • Ingress: 여러 서비스를 하나의 공인 IP로 묶고, 도메인(예: api.test.com)이나 주소 경로(예: /login)에 따라 트래픽을 분산하며 SSL 보안 인증서를 적용

리소스 구분

리소스명 (kind) 핵심 역할 실무 비유
Deployment 앱 생성 및 버전 관리 본체 (Server)
Service 고정 주소(IP/Port) 제공 내부 입구 (Gateway)
HPA 부하에 따른 자동 확장 보험 (Autoscaling)
Ingress 도메인 연결 및 경로 설정 간판/문지기 (Domain/L7)

 


 

1. App 배포 환경 구성 및 배포
- k8s dashboard 접속 > Namespace [default] > [+] 버튼 > [입력을 통해 생성] > yaml 파일 붙여넣기 > 업로드

- 아래는 테스트용으로 썼던 yml. (나중엔 내가 개발한 APP으로 image 빌드 후 배포해보자)

더보기

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-1-2-2-1
spec:
  selector:
    matchLabels:
      app: '1.2.2.1'
  replicas: 2
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: '1.2.2.1'
    spec:
      containers:
        - name: app-1-2-2-1
          image: 1pro/app
          imagePullPolicy: Always
          ports:
            - name: http
              containerPort: 8080
          startupProbe:
            httpGet:
              path: "/ready"
              port: http
            failureThreshold: 20
          livenessProbe:
            httpGet:
              path: "/ready"
              port: http
          readinessProbe:
            httpGet:
              path: "/ready"
              port: http
          resources:
            requests:
              memory: "100Mi"
              cpu: "100m"
            limits:
              memory: "200Mi"
              cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
  name: app-1-2-2-1
spec:
  selector:
    app: '1.2.2.1'
  ports:
    - port: 8080
      targetPort: 8080
      nodePort: 31221
  type: NodePort
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: app-1-2-2-1
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: app-1-2-2-1
  minReplicas: 2
  maxReplicas: 4
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 40

 

 

 

2. App에 지속적으로 트래픽 보내기 (Traffic Routing 테스트)

# k8s-master에서 2초마다 트래픽 요청

[root@k8s-master ~]# while true; do curl http://192.168.56.30:31221/hostname; sleep 2; echo '';  done;

 

3. AppMemory Leak 나게 하기 (Self-Healing 테스트)

# k8s-master에서 실행

[root@k8s-master ~]# curl 192.168.56.30:31221/memory-leak

* 결과 : pod 1개가 restart

 

4. App에 부하주기 (AutoScaling 테스트)

# k8s-master에서 요청

[root@k8s-master ~]# curl 192.168.56.30:31221/cpu-load

* pod2개 더 생성되어 총 4개가 됨

>> YAML에 설정한 HPA(Horizontal Pod Autoscaler)CPU 부하를 감지하고, 서비스 안정성을 위해 파드 개수를 자동으로 늘린 것.
>> [
상세 원인 분석]

  • 부하 발생: /cpu-load 경로로 접속하면 해당 파드의 CPU 사용량이 강제로 급증
  • 임계치 초과: 앞서 작성한 YAML에서 CPU 사용량이 40%를 넘으면 확장하도록 설정함
  • 자동 확장: 쿠버네티스가 "현재 2개로는 부하를 감당하기 어렵다"고 판단하여, 설정된 최대치인 4개(maxReplicas: 4)까지 파드를 2개 더 생성한 것

5. App 이미지 업데이트 (RollingUpdate 테스트)

- Namespace: default > 디플로이먼트 > ... > 편집

spec:

      containers:

        - name: app-1-2-2-1

          image: 1pro/app-update  # 수정

- Script 실행 시

[root@k8s-master ~]# kubectl set image -n default deployment/app-1-2-2-1 app-1-2-2-1=1pro/app-update

* 결과 : 업데이트 된 이미지가 적용된 pod가 올라올 동안, 이전 pod도 유지됨

 

update 중지 script

[root@k8s-master ~]# kubectl rollout undo -n default deployment/app-1-2-2-1

 

object 삭제 script

[root@k8s-master ~]# kubectl delete -n default deploy app-1-2-2-1

[root@k8s-master ~]# kubectl delete -n default svc app-1-2-2-1

[root@k8s-master ~]# kubectl delete -n default hpa app-1-2-2-1

이번엔 이어서 모니터링 도구들을 설치해보자. 

 

프로젝트 환경에서 Prometheus와 Grafana는 VM 모니터링과 DB 모니터링에 사용했었는데 Loki는 이번에 처음 사용해봤다.

 

 

1. 프로메테우스 vs 로키 : 데이터의 차이

구분 프로메테우스 (Prometheus) 로키 (Loki-Stack)
수집 데이터 숫자 (Metrics) 문자 (Logs)
핵심 질문 "현재 CPU 사용량이 몇 %인가?" "에러 발생 시점에 기록된 내용은 무엇인가?"
저장 방식 시계열 데이터베이스 (TSDB) 레이블 기반 인덱싱 및 압축 저장
주요 용도 시스템 부하 감시 및 실시간 알람 구체적인 장애 원인 분석 및 디버깅
관계 독립적 엔진 (별도 구축 필요) 독립적 엔진 (별도 구축 필요)
통합 환경 Grafana (두 데이터를 한 화면에 표시) Grafana (두 데이터를 한 화면에 표시)

 

 

2. 로키 스택, 프로메테우스, 그라파나 설치

- 하기 설치 시 스토리지 연동은 하지 않았으므로 VM 재기동시마다 로그 초기화됨


** 본 설치는 kube-prometheus git 프로젝트의 매니페스트(YAML) 방식을 활용해 메트릭(Prometheus)과 로그(Loki)를 통합 구축하는 과정임

 

Q. Helm과 Yaml 설치 방식의 차이는?

구분 YAML 방식 (Manifest) Helm 방식 (Package Manager)
개념 모든 설정을 직접 작성한 문서 설정을 템플릿화한 패키지 (Chart)
설치 도구 kubectl helm
설정 변경 수십 개의 파일 내부를 일일이 수정 values.yaml 파일 하나만 수정
버전 관리 수동 (파일을 직접 백업/관리) 자동 (Revision 관리로 원클릭 롤백)
학습 효과 매우 높음 (내부 구조를 다 알게 됨) 낮음 (내부가 감춰져 있음)

 

- yaml 방식이 설정파일들을 뜯어볼 수 있어서 공부할 때는 좋지만, 실무에서는 버전 관리, 롤백, 환경별 설정 분리가 가능한 helm 방식이 표준

 

1) Github(k8s-1pro)에서 Prometheus(with Grafana), Loki-Stack yaml 다운로드

- [k8s-master] Console 접속 후 아래 명령 실행

# git 설치

[root@k8s-master ~]# yum -y install git

 

# 로컬 저장소 생성

git init monitoring

git config --global init.defaultBranch main

cd monitoring

 

# remote 추가 ([root@k8s-master monitoring]#)

git remote add -f origin https://github.com/k8s-1pro/install.git

 

# sparse checkout 설정

git config core.sparseCheckout true

echo "ground/k8s-1.27/prometheus-2.44.0" >> .git/info/sparse-checkout

echo "ground/k8s-1.27/loki-stack-2.6.1" >> .git/info/sparse-checkout

 

# 다운로드

git pull origin main

 

2) Prometheus(with Grafana) 설치

- Github : https://github.com/prometheus-operator/kube-prometheus/tree/release-0.14

 

# 설치 – monitoring directory에서 진행 ([root@k8s-master monitoring]#)

kubectl apply --server-side -f ground/k8s-1.27/prometheus-2.44.0/manifests/setup

kubectl wait --for condition=Established --all CustomResourceDefinition --namespace=monitoring

kubectl apply -f ground/k8s-1.27/prometheus-2.44.0/manifests

 

# 설치 확인 ([root@k8s-master]#)

kubectl get pods -n monitoring

 

3) Loki-Stack 설치

# 설치 – monitoring director에서 진행 ([root@k8s-master monitoring]#)

kubectl apply -f ground/k8s-1.27/loki-stack-2.6.1

 

# 설치 확인

kubectl get pods -n loki-stack

 

4) Grafana 접속

▶ 접속 URL : http://192.168.56.30:30001

로그인 :​ id: admin, pw: admin

 

5) Grafana에서 Loki-Stack 연결

Connect data : Home > Connections > Connect data

검색에 [loki] 입력 후 항목 클릭

 

6) Grafana 대시보드 생성

- 메뉴 이동: Grafana 좌측 메뉴에서 Dashboards > New > Import를 클릭

- ID 입력: 아래의 공식 ID를 입력하고 Load

 > Prometheus (K8S 상태): 315 (Kubernetes Cluster 모니터링 표준)

 > Loki (로그 확인): 15141 (Loki용 공식 로그 대시보드)

 

 

 

모니터링 설치 삭제 시

- Prometheus(with Grafana), Loki-stack 삭제

[k8s-master] Console 접속 후 아래 명령 실행

 

# 모니터링 설치 폴더로 이동

[root@k8s-master ~]# cd monitoring

 

# Prometheus 삭제

kubectl delete --ignore-not-found=true -f ground/k8s-1.27/prometheus-2.44.0/manifests -f ground/k8s-1.27/prometheus-2.44.0/manifests/setup

 

# Loki-stack 삭제

kubectl delete -f ground/k8s-1.27/loki-stack-2.6.1


 

- TODO : 1. 설치 yml 별도로 생성하여 진행하기 / 2. VM 재기동시 이력이 초기화 되지 않도록 스토리지 설정하기

앞서 K8S 를 구축하면 아래와 같은 K8S 컴포넌트들을 확인할 수 있다. 

 

1. K8S 컴포넌트 

Pod 명칭 (핵심 키워드) 설명
calico-apiserver Calico 네트워크 정책 전용 API 확장 서비스
calico-kube-controllers 네트워크 리소스 상태 감시 및 정책 관리 컨트롤러
calico-node 노드 간 통신 및 실제 라우팅을 수행하는 네트워크 엔진
calico-typha 노드 확장 시 DB 부하를 줄여주는 네트워크 최적화 도구
csi-node-driver 컨테이너와 가상 머신 저장소(디스크)를 연결하는 드라이버
coredns 클러스터 내 서비스 이름을 IP로 변환하는 DNS 서비스
etcd 모든 클러스터 상태 데이터가 저장되는 핵심 데이터베이스
kube-apiserver 모든 명령이 통과하는 쿠버네티스의 중앙 제어 관문
kube-controller-manager 노드 상태 및 복제본 수 등을 관리하는 클러스터 감시자
kube-proxy 트래픽을 컨테이너로 전달하기 위한 네트워크 규칙 관리
kube-scheduler 자원 상태에 따라 컨테이너를 최적의 노드에 배치
metrics-server CPU 및 메모리 사용량을 실시간 수집하는 성능 분석 도구
dashboard-metrics-scraper 웹 대시보드 표시용 통계 데이터를 수집하는 도구
kubernetes-dashboard 웹 브라우저에서 클러스터를 관리하게 해주는 GUI UI
tigera-operator Calico 네트워크 엔진의 설치와 관리를 자동화하는 관리자

 

 

2. K8S 인터페이스 규격

- K8S 인터페이스 규격이란 : 쿠버네티스가 다양한 외부 기술(컨테이너 실행, 네트워크, 저장소)을 마치 '레고 블록'처럼 자유롭게 갈아 끼울 수 있도록 만든 표준 연결 고리

 

- CRI : 컨테이너 실행(런타임) 인터페이스
- CNI : 네트워크 연결(통신) 인터페이스
- CSI : '외부 저장소 연결(스토리지)'을 위한 표준 규격

* CRI & CNI : Kubelet이 CRI를 통해 컨테이너를 생성하면, 이어서 CNI가 해당 컨테이너의 네트워크 환경(IP 등)을 설정함. 1.24 버전 이후부터는 Kubelet이 직접 CNI를 부르는 대신 CRI가 CNI를 호출하는 구조로 최적화 됨

* CSI :
> 독립성: 쿠버네티스 코드를 수정하지 않고도 새로운 스토리지 드라이버를 추가할 수 있음
> 자동화: 사용자가 PVC(Persistent Volume Claim)를 요청하면, CSI가 자동으로 실제 스토리지를 생성하고 파드에 연결(Mount)해 줌
> 다양성: 클라우드 디스크뿐만 아니라 온프레미스의 하드웨어 스토리지도 플러그인 형태로 연결 가능

 

# CRI / CNI / CSI 핵심 비교 

구분 CRI (Runtime) CNI (Network) CSI (Storage)
역할 컨테이너 실행/관리 IP 할당 및 통신 볼륨 연결 및 데이터 저장
비유 컴퓨터 본체 (연산) 랜선 (통신) 외장 하드 (저장)
실무 질문 "컨테이너를 띄워라" "통신이 되게 하라" "데이터를 저장하라"
대표 예시 Containerd, CRI-O Calico, Cilium AWS EBS, NFS, Rook/Ceph

 

일프로님 강의로 K8S를 구축해보며 로컬에서 정리하고 있었지만, 블로그에 기록하면 좋을 것 같아서 차례대로 옮기려고 한다.

 

먼저 로컬에 K8S 환경 구축하기 부터!


 

** 설치 권고 환경 : Windows10/11, Cpu 4core 이상, Memory 12GB 이상, 인터넷 사용 가능 환경 ** 

 

 

1. Virtualbox 설치 (7.1.6 버전)  # 25.3.03 Version Update

- Download : https://download.virtualbox.org/virtualbox/7.1.6/VirtualBox-7.1.6-167084-Win.exe

- Site : https://www.virtualbox.org/wiki/Downloads

 

2. Vagrant 설치 (2.4.3 버전) # 25.3.03 Version Update

- Download : https://releases.hashicorp.com/vagrant/2.4.3/vagrant_2.4.3_windows_amd64.msi

- Site : https://developer.hashicorp.com/vagrant/downloads?product_intent=vagrant

* Vagrant
: 가상 머신(VM) 환경을 설정 파일 하나로 자동 생성하고 관리하게 해주는 도구

* 핵심 구성요소 :

Provider 가상 머신을 실제로 띄우는 엔진 (: VirtualBox, VMware)
Box 가상 머신의 템플릿(이미지). OS와 기본 설정이 이미 들어있는 압축 파일
Vagrantfile 어떤 Box를 쓸지, 네트워크는 어떻게 할지 적어둔 설계도

 

3. Vagrant 스크립트 실행

- 윈도우 > 실행 > cmd > 확인

 

# Vagrant 폴더 생성

C:\dev> mkdir k8s && cd k8s

 

# Vagrant 스크립트 다운로드

curl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/k8s-1.27/vagrant-2.4.3/Vagrantfile

- 이 파일을 쓰자니, up.down 할 때마다 모니터링을 별도로 추가해야 해서 불편했다. 그래서 내 버전으로 설정 수정함.

  아래는 기존 vagrant 파일에서 모니터링 설치 및 대시보드 외부노출까지 script 추가한 버전!

더보기


Vagrant.configure("2") do |config|
    
  config.vm.box = "rockylinux/8"
  # Disk 확장설정 추가
  config.disksize.size = "50GB"

  # https://cafe.naver.com/kubeops/26
  config.vbguest.auto_update = false
  config.vm.synced_folder "./", "/vagrant", disabled: true
  config.vm.network :forwarded_port, guest: 22, host: 2222, id: "ssh", auto_correct: true
  config.vm.provision :shell, privileged: true, inline: $install_default
  config.vm.define "master-node" do |master|
    master.vm.hostname = "k8s-master"
    master.vm.network "private_network", ip: "192.168.56.30"
master.vm.provider :virtualbox do |vb|
      #vb.memory = 6144
      vb.memory = 8192 # 소영 추가 : Prometheus/Loki 가동을 위한 최소 메모리 확보
      vb.cpus = 4
  vb.customize ["modifyvm", :id, "--firmware", "efi"]
  vb.customize ["modifyvm", :id, "--nested-hw-virt", "on"]
end
    master.vm.provision :shell, privileged: true, inline: $install_master
  end

end

$install_default = <<-SHELL

echo '======== [4] Rocky Linux 기본 설정 ========'
echo '======== [4-1] 패키지 업데이트 ========'
# 강의와 동일한 실습 환경을 유지하기 위해 Linux Update 주석 처리
# yum -y update

# 초기 root 비밀번호 변경을 원하시면 아래 주석을 풀고 [새로운비밀번호]에 비번을 입력해주세요
# echo "root:새로운비밀번호" | chpasswd


echo '======== [4-2] 타임존 설정 및 동기화========'
timedatectl set-timezone Asia/Seoul
timedatectl set-ntp true
chronyc makestep

echo '======== [4-3] Disk 확장 / Bug: soft lockup 설정 추가========'
https://cafe.naver.com/kubeops/25
yum install -y cloud-utils-growpart
growpart /dev/sda 4
xfs_growfs /dev/sda4

echo '======== [4-4] [WARNING FileExisting-tc]: tc not found in system path 로그 관련 업데이트 ========'
yum install -y yum-utils iproute-tc

echo '======= [4-4] hosts 설정 =========='
cat << EOF >> /etc/hosts
192.168.56.30 k8s-master
EOF

echo '======== [5] kubeadm 설치 전 사전작업 ========'
echo '======== [5] 방화벽 해제 ========'
systemctl stop firewalld && systemctl disable firewalld

echo '======== [5] Swap 비활성화 ========'
swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab


echo '======== [6] 컨테이너 런타임 설치 ========'
echo '======== [6-1] 컨테이너 런타임 설치 전 사전작업 ========'
echo '======== [6-1] iptable 세팅 ========'
cat <<EOF |tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

modprobe overlay
modprobe br_netfilter

cat <<EOF |tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sysctl --system

echo '======== [6-2] 컨테이너 런타임 (containerd 설치) ========'
echo '======== [6-2-1] containerd 패키지 설치 (option2) ========'
echo '======== [6-2-1-1] docker engine 설치 ========'
echo '======== [6-2-1-1] repo 설정 ========'
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

echo '======== [6-2-1-1] containerd 설치 ========'
yum install -y containerd.io-1.6.21-3.1.el8
systemctl daemon-reload
systemctl enable --now containerd

echo '======== [6-3] 컨테이너 런타임 : cri 활성화 ========'
# defualt cgroupfs에서 systemd로 변경 (kubernetes default는 systemd)
containerd config default > /etc/containerd/config.toml
sed -i 's/ SystemdCgroup = false/ SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd



echo '======== [7] kubeadm 설치 ========'
echo '======== [7] repo 설정 ========'
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.27/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.27/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF


echo '======== [7] SELinux 설정 ========'
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

echo '======== [7] kubelet, kubeadm, kubectl 패키지 설치 ========'
yum install -y kubelet-1.27.2-150500.1.1.x86_64 kubeadm-1.27.2-150500.1.1.x86_64 kubectl-1.27.2-150500.1.1.x86_64 --disableexcludes=kubernetes
systemctl enable --now kubelet

SHELL



$install_master = <<-SHELL

echo '======== [8] kubeadm으로 클러스터 생성  ========'
echo '======== [8-1] 클러스터 초기화 (Pod Network 세팅) ========'
kubeadm init --pod-network-cidr=20.96.0.0/12 --apiserver-advertise-address 192.168.56.30

echo '======== [8-2] kubectl 사용 설정 ========'
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

echo '======== [8-3] Pod Network 설치 (calico) ========'
kubectl create -f https://raw.githubusercontent.com/k8s-1pro/install/main/ground/k8s-1.27/calico-3.26.4/calico.yaml
kubectl create -f https://raw.githubusercontent.com/k8s-1pro/install/main/ground/k8s-1.27/calico-3.26.4/calico-custom.yaml

echo '======== [8-4] Master에 Pod를 생성 할수 있도록 설정 ========'
kubectl taint nodes k8s-master node-role.kubernetes.io/control-plane-


echo '======== [9] 쿠버네티스 편의기능 설치 ========'
echo '======== [9-1] kubectl 자동완성 기능 ========'
echo "source <(kubectl completion bash)" >> ~/.bashrc
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -o default -F __start_kubectl k' >>~/.bashrc

echo '======== [9-2] Dashboard 설치 ========'
kubectl create -f https://raw.githubusercontent.com/k8s-1pro/install/main/ground/k8s-1.27/dashboard-2.7.0/dashboard.yaml

echo '======== ***** 대시보드 외부 오픈 (custom) ***** ========'
sleep 10  # <--- [중요] 대시보드 API가 준비될 시간을 줍니다.
# [설정 1] NodePort 30000번으로 고정
kubectl patch svc kubernetes-dashboard -n kubernetes-dashboard -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "nodePort": 30000, "targetPort": 8443}]}}'

# [설정 2] 로그인 화면에서 Skip 버튼 활성화
kubectl patch deployment kubernetes-dashboard -n kubernetes-dashboard --type 'json' -p '[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--enable-skip-login"}]'

# [설정 3] Skip 버튼 클릭 시 관리자 권한 부여
kubectl create clusterrolebinding dashboard-skip-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:kubernetes-dashboard

echo '======== ***** 대시보드 외부 오픈 (custom) 끝 ***** ========'

echo '======== [9-3] Metrics Server 설치 ========'
kubectl create -f https://raw.githubusercontent.com/k8s-1pro/install/main/ground/k8s-1.27/metrics-server-0.6.3/metrics-server.yaml

echo '======== [10] custom : 모니터링 (Prometheus & Loki) 설치 시작 ========'
# [10-1] Git 설치 및 레포지토리 구성
yum -y install git
cd $HOME
git init monitoring
cd monitoring
git remote add -f origin https://github.com/k8s-1pro/install.git
git config core.sparseCheckout true
echo "ground/k8s-1.27/prometheus-2.44.0" >> .git/info/sparse-checkout
echo "ground/k8s-1.27/loki-stack-2.6.1" >> .git/info/sparse-checkout
git pull origin main

# [10-2] Prometheus & Grafana 설치
kubectl apply --server-side -f ground/k8s-1.27/prometheus-2.44.0/manifests/setup
kubectl wait --for condition=Established --all CustomResourceDefinition --namespace=monitoring --timeout=300s
kubectl apply -f ground/k8s-1.27/prometheus-2.44.0/manifests

# [10-3] Loki-Stack 설치 (로컬 노트북 CPU 부족으로 주석처리)
# kubectl apply -f ground/k8s-1.27/loki-stack-2.6.1

echo '======== [10-4] 모니터링 외부 오픈 설정 (Grafana NodePort 30001) ========'
sleep 20
# Grafana 서비스를 NodePort 30001로 오픈하여 외부 접속 허용
kubectl patch svc grafana -n monitoring -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "nodePort": 30001, "targetPort": 3000}]}}'

echo '========  custom : 모니터링 설치 완료 (Grafana: http://192.168.56.30:30001) ========'

SHELL

 

# Rocky Linux Repo setting (Rocky Linux boxvagrant에 등록)

방법 1) 저장소 연결 후 다운로드 및 vagarnt에 등록

curl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/k8s-1.27/vagrant-2.4.3/rockylinux-repo.json

vagrant box add rockylinux-repo.json

 

방법 2) 방법 1 실행 중, rocky box 파일의 용량이 커서 다운로드가 너무 느림.
=> FDM
(Free Download Manager) 설치 후 병렬 스레드로 로컬에 다운로드를 완료한 후,
      로컬 image box 파일을 vagrant 등록함.

vagrant box add rockylinux/8 Rocky-8-Vagrant-Vbox-8.8-20230518.0.x86_64.box

 

# Vagrant Disk 설정 Plugin 설치

vagrant plugin install vagrant-vbguest vagrant-disksize

 

# Vagrant 실행 (VM생성)

vagrant up

※ Vagrant 명령어
vagrant init : 프로비저닝을 위한 기초 파일 생성
vagrant up : Vagrantfile을 읽어 프로비저닝 진행 (최초 VM생성 할때만 사용. 생성 이후 부터 컴퓨터를 껐다 켜거나 했을 때, VM기동/중지는 Virtualbox UI를 사용하는 걸 권장)
vagrant halt : 베이그런트에서 다루는 가상머신 종료
vagrant destroy : 베이그런트에서 관리하는 가상머신 삭제  (vagrant up으로 VM 생성 중 에러가 났을 때 이 명령으로 삭제)
vagrant ssh : 베이그런트에서 관리하는 가상머신에 ssh 접속 (multi vm 환경은 ssh 뒤에 vm name 기재)
vagrant provision : 베이그런트에서 관리하는 가상머신에 변경된 설정 적용
vagrant box list : 등록된 box (image) 파일 확인

 

4. MobaXterm 설치 (23.1 버전)

- Download : https://download.mobatek.net/2312023031823706/MobaXterm_Portable_v23.1.zip

- Site : https://mobaxterm.mobatek.net/download-home-edition.html

* MobaXterm : SSH, RDP, FTP, SFTP 등 다양한 네트워크 프로토콜을 단 하나의 프로그램에서 실행할 수 있는 통합 터미널 솔루션

5. MobaXterm 으로 Master Node 원격 접속 (Windows)

- Sessions > New session > SSH 을 선택해서 접속 세션 생성

- 최초 idroot, passwordvagrant

- 참고 이미지 

 


 

# TODO : master node 와 worker node를 모두 생성하고 클러스터 등록하도록 yml 을 수정하고 VM 생성

마지막 Transit Gateway 시작!


 

Scenario 3. AWS Transit Gateway 구현 (중앙 허브 라우팅)

 

# Scenario 3을 수행하기 전 check

* 검증 한계: AWS TGW 서비스 자체를 활용한 로컬 DB 직접 연결은 하드웨어 제약으로 인해 불가함.

* 불가 사유: TGW는 엔터프라이즈 전용 서비스로, 일반 PC 환경에서는 BGP 피어링 및 물리적 터널 종단이 불가함.

* 대체 검증: 실제 TGW 서비스 대신 EC2(Hub) + Tailscale 조합으로 대체하여 '중앙 집중형 라우팅' 로직을 검증함.

* 실무 포인트: TGW의 핵심인 'Hub-and-Spoke' 설계 원리와 VPC 라우팅 테이블 제어 방식은 EC2 기반 라우터를 통해 100% 동일하게 재현 및 실무 검증 가능함.

 

- 목적 : 다수의 서브넷/VPC 트래픽을 특정 HubEC2(Tailscale Subnet Router) 로 모아, 온프레미스(Local DB)와 통신하는 중앙 집중형 확장 구조를 검증함.

 

- 검증 가설 : "개별 노드에 VPN을 설치하지 않아도, Private 서브넷의 Route Table을 수정하여 트래픽을 Hub 노드로 리다이렉션하면 외부 네트워크와 통합 통신이 가능하다."


- 검증 항목 :

  • EC2의 서브넷 라우터(Subnet Router) 설정 및 트래픽 중계 여부 확인
  • 중앙 집중형 라우팅 테이블 설정을 통한 다수 네트워크 간의 통신 통합성 확인

- 방법 :

  • AWS Console 작업
    1. Hub 인스턴스 생성: 퍼블릭 서브넷 내에 가상 라우터 역할을 수행할 중계용 EC2를 배치함.
                                       보안그룹 설정 시 백엔드 API 인스턴스에서 오는 요청을 받도록 인바운드 규칙 추가.
    보안그룹 인바운드 규칙 설정
    2. 소스/대상 확인(Source/Dest. Check) 중지: 인스턴스 네트워킹 설정에서 이 옵션을 반드시 '중지'해야 본인이 최종 목적지가 아닌 외부 패킷(백엔드→로컬DB)을 드랍하지 않고 전달할 수 있음.
    중계용 EC2 인스턴스는 소스/대상 확인 설정을 "중지"함
    3. VPC 라우팅 테이블(Route Table) 업데이트: 백엔드 API 서버가 속한 서브넷의 이정표를 수정함. 로컬 DB 사설 대역(192.168.x.x)으로 가는 Target을 '중계용 Hub EC2의 인스턴스 ID'로 지정하여 트래픽을 강제로 허브로 밀어넣음.
    Backend 서버용 라우팅 테이블 (DB 요청은 중계 EC2로)
    중계용 라우팅 테이블은 기존 public 테이블과 동일
    4. 백엔드 API 서버 DB connection 변경 : 백엔드 API 서버가 속한 서브넷의 talescale 을 정지 / DB 커넥션을 시나리오 1의 talescale 10.x IP가 아닌 로컬 사설 IP 192.x 로 .env 파일 변경

  • Local(Tailscale) 연동 구현
    1. 중계 서버(Hub EC2) IP Forwarding 활성화 : 리눅스 커널이 패킷을 가로채서 로컬로 넘겨주도록 허용함.
      ** 단순히 ip_forward만 켜면 보안 그룹 설정이 완벽해도 패킷이 증발할 수 있음. 리눅스 커널은 들어온 경로와 나가는 경로가 다른 패킷을 비정상으로 보고 차단하기 때문인데, rp_filter 설정을 0으로 바꿔줘야만 중계 서버(Hub EC2)가 패킷을 버리지 않고 정상적으로 로컬 DB까지 전달함 ** 
    echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
    echo 'net.ipv4.conf.all.rp_filter = 0' | sudo tee -a /etc/sysctl.conf
    echo 'net.ipv4.conf.default.rp_filter = 0' | sudo tee -a /etc/sysctl.conf
    sudo sysctl -p

    2. Subnet Router 선언: Hub EC2에서 taliscale 설치 후 "tailscale up --advertise-routes=10.0.0.0/16 --accept-routes" 명령을 실행함.
    3. 로컬 PC 사설 대역 광고: 로컬 PC(온프레미스)에서도 자신의 대역을 등록함.
        "tailscale up --advertise-routes=192.168.0.0/24"
    4. Tailscale 관리자 페이지에서 승인 : Admin Console에서 중계용 EC2(10.0.0.0/16)와 로컬 PC(192.168.0.0/24)의 경로를 각각 'Approve' 처리함.
    5. 온프레미스 보안 설정: 로컬 PC 방화벽에서 AWS VPC 대역(10.0.0.0/16)에 대한 인바운드(TCP 3306, ICMP)를 허용함.
    6. 기술 매핑: 실제 TGW 서비스 대신 Tailscale이 깔린 EC2를 '가상 라우터'로 변신시켜 트래픽을 중계하는 기능을 동일하게 구현함.
    ** 설정 미반영 시 해결법: tailscale up 옵션을 변경했는데도 ip route나 관리자 콘솔에 즉시 반영되지 않는다면, tailscale down 후 다시 tailscale up 명령어를 실행하여 세션을 초기화함. ** 

- AWS 아키텍처 : 

 

 - 검증 결과:

  • 통합 라우팅 확인: 복잡한 개별 Peering 없이, 중앙 허브(TGW 역할을 하는 EC2) 설정을 통해 다수의 가상 네트워크 대역에서 단일 로컬 DB에 접근 가능한 통합 라우팅 체계를 확인함.

backend public IP로 db 연결 시 중계서버를 거쳐 응답이 옴

 


 

[총평]


이번 기술 검증을 통해, 물리적인 VPN 장비가 없는 로컬 환경에서도 Tailscale과 같은 Mesh VPN을 활용하면 실제 기업의 Site-to-Site VPN이나 Direct Connect 환경을 충분히 시뮬레이션할 수 있음을 확인함.

이어서 Direct Connect(DX) 도 검증!
아키텍처와 공통설정은 앞선 "Site-to-Stie VPN" 과 동일함.

 


 

Scenario 2. Direct Connect(DX) 구현 (P2P 경로 최적화 검증)

 

# Scenario 2을 수행하기 전 check

Direct Connect 방식은 물리적 전용 회선 인입이 필요한 설계 구조이므로, 본 시나리오에서는 AWS 콘솔 절차를 숙지한 후 Tailscale 기반 성능 비교로 기술 검증만 수행함.

 

- 목적 : 인터넷 중계 서버(Relay)를 배제하고 온프레미스와 AWS 간 1:1 P2P(Direct) 경로를 수립하여, 물리적 전용선(Direct Connect) 수준의 고성능/저지연 통신 환경을 재현함.

 

- 검증 가설 : "의도적으로 UDP 통신을 제한한 Relay 모드와 최단 경로인 Direct 모드의 레이턴시(ms) 차이를 비교함으로써, DX가 하이브리드 아키텍처에서 제공하는 '직결성'과 '저지연'의 기술적 타당성을 입증할 수 있을 것이다."


- 검증 항목 :

  • Relay 환경: tailscale의 relay-only 설정을 통해 중계 서버(DERP)를 경유하는 통신의 지연 시간 측정.
  • Direct 환경: P2P 수립 후 중계 서버를 거치지 않는 최단 경로의 성능 수치 측정.
  • 성능 격차: 두 모드 간의 지연 시간 차이 및 패킷 안정성 비교.

- 방법 :

  • AWS Console 작업
    ** 본 시나리오에서는 AWS 서비스 신규 생성 작업은  없음 ** 
    1. Direct Connect Connection: 전용선 신청 메뉴(Create Connection)를 통해 물리적 포트 할당 및 LOA-CFA 발급 절차를 분석하고, 이를 Tailscale 가상 인터페이스 설정과 논리적으로 매핑할 수 있도록 숙지함.
    2. Private VIF 생성: Virtual Interfaces 메뉴에서 사설 통신용 VIF 생성 절차(BGP ASN, VLAN ID 설정 등)를 숙지함.
  • Local(Tailscale) 연동 구현
    1. Direct 상태 확인 : tailscale status 명령어로 EC2와 로컬 PC 간 P2P 직결 여부 확인 (default가 direct mode)

    2. Relay 모드 설정 : UDP 41641 차단
    sudo iptables -A OUTPUT -p udp --dport 41641 -j DROP
    sudo iptables -A INPUT -p udp --sport 41641 -j DROP
    # -> Relay 전환 후 ping 측정 (평균 80~100ms)

    3. Direct 복구 : 차단 규칙 제거 후 Tailscale 재기동
    sudo iptables -D OUTPUT -p udp --dport 41641 -j DROP
    sudo iptables -D INPUT -p udp --sport 41641 -j DROP
    sudo tailscale down && sudo tailscale up
    # → Direct 재수립 후 ping 측정 (평균 15~20ms)

    4. 결과 정리 : Relay는 중계 경유로 지연 증가, Direct는 P2P 직결로 저지연 유지 → 직결 경로 성능 우위 확인

- AWS 아키텍처 : 시나리오 1과 동일


- 검증 결과
:

  • Relay 모드 : 평균 80~100ms, 중계 서버 경유로 지연 증가 및 응답 편차 발생
    relay 모드 결과
  • Direct 모드 : 평균 15~20ms, P2P 직결로 저지연 및 안정적 응답 유지
    direct 모드
  • 결론 : Direct 전환 시 약 4~6배 레이턴시 개선 확인 → 직결 경로 확보가 성능에 결정적 영향 미침을 실험적으로 검증

"1. 이론/설계"편에서 찾아본 AWS 하이브리드 네트워킹의 3가지 표준 모델을 내 로컬 PC(온프레미스)와 AWS VPC 간에 Tailscale을 활용하여 직접 구현하고 기술적 타당성을 검증해보자.

 

먼저 Site-to-Site VPN 부터!


[공통]

 

1.기술 스택 (Tech Stack)

  • Language: Java 17
  • Framework: Spring Boot 3.5.9
  • Database: MariaDB 11.4.9 (Local On-premises)
  • ORM: MyBatis (with mybatis-spring-boot-starter 3.0.5)
  • Connectivity: Tailscale (Mesh VPN 기반 가상 사설망)
  • Build Tool: Maven

2. 사전 환경설정

1) 가상 사설망(VPN) 구축: Tailscale 설정
- 실무의 AWS Site-to-Site VPN 역할을 대신할 가상 사설망 구축.
- 로컬 PC: Tailscale 설치 및 로그인 후 가상 사설 IP 확인.
- AWS EC2: 에이전트 설치 및 노드 등록 실행.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
- 연결 확인: EC2 터미널에서 로컬 PC IP로 통신(ping) 여부 확인.

2) 온프레미스 DB 보안 및 네트워크 개방
- 사설망 경로는 확보되었으나 DB 및 OS 차원의 접근 허용 설정 필요.
- MariaDB 설정: bind-address를 0.0.0.0으로 수정하여 외부 접속 허용.
# my.ini 설정
bind-address = 0.0.0.0
- OS 방화벽: Windows/Mac 인바운드 규칙에서 3306/TCP 포트 개방.
- DB 사용자 권한: Tailscale 사설 대역(100.x.x.x)에 대한 접속 권한 명시.
CREATE USER 'USERNAME'@'TailscaleIP' IDENTIFIED BY 'PASSWORD';
GRANT ALL PRIVILEGES ON awslab.* TO 'USERNAME'@'TailscaleIP';
FLUSH PRIVILEGES;

3) 백엔드 어플리케이션 환경 변수 설정
- EC2에 배포된 앱이 사설망 경로를 통해 DB를 인식하도록 엔드포인트 수정.
# application.yml
spring:
  datasource:
    url: jdbc:mariadb://[로컬_Tailscale_IP]:3306/awslab
    username: [USERNAME]
    password: [PASSWORD]
    hikari:
      connection-timeout: 5000 # 하이브리드망 지연 고려 최적화

4) AWS EC2 인스턴스에 Tailscale 설치
# tailscale 설치 
curl -fsSL https://tailscale.com/install.sh | sh

# 서비스 구동
# 로그인 승인: 터미널에 출력된 https://login.tailscale.com/a/xxxx 링크를 복사하여 브라우저에서 [Connect] 버튼 클릭.
sudo tailscale up

# 사설 IP 할당 여부 및 통신 확인
tailscale ip -4

# 상호 통신 검증: EC2에서 로컬 PC의 Tailscale IP로 핑을 날려 네트워크 터널링 완성 여부 체크.
ping [로컬_PC_Tailscale_IP]

5) AWS EC2 인스턴스에서 Backend API 서비스 기동


- 이후 3가지 하이브리드 시나리오(VPN, DX, TGW) 검증 진행

 

Scenario 1. Site-to-Site VPN 검증 (보안 터널 및 차단 검증)

 

# Scenario 1을 수행하기 전 check

* 검증 한계: AWS 콘솔 내 리소스 등록 및 구성 파일 추출까지는 가능하나, 실제 Tunnel: UP(통신 가능) 상태 구현은 불가함.

* 불가 사유: 실제 하이브리드 연결에는 고정 공인 IP와 IPSec 하드웨어 장비가 필수이나, 일반 로컬 환경(유동 IP/NAT)은 이를 충족하지 못함.

* 실무 포인트: 본 시나리오는 실제 장비 연결 전, 클라우드 측의 설정값 생성 및 구성도 설계 역량을 검증하는 데 목적이 있음.

 

- 목적 : 인터넷망을 경유하되 IPSec 암호화 터널과 동일한 보안 통로를 생성하여, 외부 접근은 차단하고 내부 통신만 허용하는지 검증함.

 

- 검증 가설 : "AWS 보안 그룹에서 외부(Anywhere) 접속을 허용하는 인바운드 규칙이 전혀 없더라도, 가상 터널(Tailscale)을 통한 사설 통신은 보안 그룹의 제어 범위를 우회하여 정상 동작할 것이다."


- 검증 항목 :

  • 인바운드 규칙 공백 상태에서 외부 공인 IP를 통한 접속 차단 여부 (Default Deny 확인).
  • 동일 상태에서 Tailscale 사설 대역(100.x.x.x)을 통한 DB 데이터 호출 성공 여부.

- 방법 :

  • AWS Console 작업
    1. Customer Gateway(CGW) 생성: [VPC] > [고객 게이트웨이]에서 내 로컬 PC의 공인 IP를 등록하여 온프레미스 접점을 정의함. (현업에선 기업의 VPN 서버 공인 IP를 등록)
    2. Virtual Private Gateway(VGW) 생성: [VPC] > [가상 프라이빗 게이트웨이] 생성 후, 현재 사용 중인 VPC에 'Attach' 하여 클라우드 측 종단점을 활성화함.
    3. VPN Connection 설정: 위 두 지점을 연결하고 '정적(Static) 라우팅'에 내 로컬 사설 대역을 입력함
    공인 IP 가 없는 한 사용은 불가함. 이번 시나리오에서는 작성만 해봄.
  • Local(Tailscale) 연동 구현
    1. 네트워크 통합: 로컬 PC와 EC2에 Tailscale을 설치하여 가상의 단일 사설망으로 묶음.
    2. 기술 매핑: 고가의 IPSec VPN 장비 대신, 테일스케일의 기반 기술인 WireGuard 프로토콜을 활용해 소프트웨어적으로 보안 터널을 생성함.

- 구축한 AWS 아키텍처 :

 

- 검증 결과:

  • 네트워크 격리: EC2 보안 그룹에 3306 포트 규칙이 부재함을 확인. 외부 스캐닝 및 공인 IP 접속 시 타임아웃(Timeout) 발생.
    인바운드 규칙 설정

    연결불가
  • 사설 경로 유효성: 가상 인터페이스(tailscale0)를 통해 유입되는 트래픽은 SG 필터링 레이어를 거치지 않고 OS 커널로 전달되어, 사설 IP 기반의 DB 연동이 성공함.

EC2 인스턴스에서 tailscale 기동 후 IP 확인 & 온프레미스 DB의 tailscale IP가 있는 설정파일
EC2 인스턴스에서 온프레미스 DB 통신 성공

 

+ Recent posts