Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Car Pay-in — Private Cloud Infra

현대오토에버 모빌리티 SW스쿨 클라우드 3기 팀 프로젝트 CarPayIn의 일부입니다. CarPayIn은 차량에서 QR 인증만으로 로그인하고, 입차부터 요금 결제까지 사람의 개입 없이 자동으로 처리되는 차량 기반 주차 결제 시스템입니다. AWS(퍼블릭 클라우드)와 OpenStack(프라이빗 클라우드)로 구성된 하이브리드 클라우드 구조이며, 이 레포는 그중 Private Cloud 인프라 파트를 담당합니다. AWS 쪽 인프라(ECS, Lambda, ALB 등)는 별도 레포/팀원이 담당한 영역이라 이 레포에는 포함되어 있지 않습니다.

이 레포에서 내가 담당한 것

팀 프로젝트이며, 아래는 본인(June, 김준태)이 Private Cloud 인프라 / DevOps / Monitoring 담당자로서 직접 작업한 범위입니다. 서비스 코드(services/*)는 팀 공동 작업물이고, 아래 인프라·운영 영역이 본인 담당입니다.

  • Private Cloud 구축: Kolla-Ansible로 OpenStack(2024.2) 설치, Wi-Fi 단일 NIC 제약 환경에서 dummy0 가상 인터페이스로 External Network 우회 구성
  • 네트워크 설계: 외부 트래픽(public-net) / DB(private-net) / Vault(secure-net)로 3계층 분리, k3s 노드는 멀티홈 구조로 3개 네트워크에 모두 연결
  • k3s 멀티노드 & 로드밸런싱: Octavia(L4, VIP 단일 진입점)와 Traefik(L7)을 이중화해 노드 장애 시에도 트래픽이 우회되도록 구성, HPA로 파드를 6~9개 사이로 자동 확장
  • 하이브리드 클라우드 연결: WireGuard로 AWS ↔ OpenStack 간 VPN 터널 구성, PersistentKeepalive와 iptables DNAT로 NAT 환경에서도 안정적인 연결 유지. VPN 터널로 들어온 트래픽은 Octavia LB VIP (10.0.1.110)로 DNAT되어 mock-card Pod까지 전달
  • Self-hosted GitLab + IaC: OpenStack 내부에 GitLab을 직접 구축해 SCM/CI·CD/Registry/Terraform State를 단일 플랫폼으로 통합. Terraform(프로비저닝)과 Ansible(설정/스케일링)로 역할을 분리하고, terraform apply는 수동 승인 게이트로 사고를 방지
  • 모니터링 & 오토스케일링: Prometheus + AlertManager가 CPU 80% 초과 상태를 감지하면(최초 5분 지속 → 이후 1분으로 단축) FastAPI 기반 webhook-adapter를 거쳐 GitLab CI 파이프라인을 트리거하고, Ansible이 VM을 자동으로 추가/제거해 k3s 클러스터에 join/drain. scale-out/in에는 각각 10분/5분 쿨다운을 둬 중복 트리거를 방지

팀 구성

이름 역할
조성윤 PL
김희라 OpenStack 인프라
이예은 AWS 인프라
조형동 Mock Card 서비스 / DB
June (본인) Private Cloud 인프라 / DevOps / Monitoring

아키텍처 개요

flowchart LR
    subgraph AWS["AWS · 퍼블릭 클라우드 (팀원 담당, 이 레포 범위 아님)"]
        AAOS["AAOS 시뮬레이터"] --> GW["API Gateway / ALB"]
    end

    GW -- "WireGuard VPN\nPersistentKeepalive" --> VPNSRV

    subgraph OS["OpenStack 2024.2 · 프라이빗 클라우드 (본인 담당)"]
        VPNSRV["vpn-server\npublic-net"] -- "iptables DNAT" --> OCT["Octavia LB\nVIP · L4 ROUND_ROBIN"]
        OCT --> TRAEFIK["Traefik Ingress\nk3s · L7 라우팅"]
        TRAEFIK --> MC["mock-card Pod × 6~9\n(HPA, CPU 70%)"]
        MC --> PG[("PostgreSQL\nprivate-net")]
        MC -. "AppRole 인증" .-> VAULT[["Vault\nsecure-net"]]
    end
Loading

범위: Private Cloud(OpenStack/k3s/Octavia)에서 실제로 운영되는 서비스는 mock-card 하나입니다. carpayin-backend / mock-pg / pms는 AWS 쪽에 배포됩니다. docs/deployment/gitlab-registry.md가 4개 서비스 이미지를 모두 언급하는 것은 SaaS GitLab에서 Self-hosted GitLab으로 분리하기 이전 구성의 잔재이며, 현재 기준으로는 유효하지 않습니다.

  • Terraform: OpenStack VM, 네트워크 포트, Octavia 로드밸런서 프로비저닝 (infra/terraform)
  • Ansible: k3s 설치/조인, WireGuard 설정, 모니터링 에이전트 배포, 오토스케일링 시 노드 추가/제거 (infra/ansible)
  • webhook-adapter: AlertManager → GitLab CI 트리거 사이의 변환/쿨다운 레이어 (infra/webhook-adapter)

기술 스택

영역 기술
Private Cloud OpenStack 2024.2 (Kolla-Ansible), Neutron(OVS), Cinder, Octavia
Orchestration k3s (멀티노드), Traefik Ingress, HPA
IaC Terraform, Ansible
CI/CD Self-hosted GitLab (SCM/CI·CD/Registry/Terraform State)
보안 HashiCorp Vault (AppRole), WireGuard, 3계층 네트워크 분리
모니터링 Prometheus, Grafana, AlertManager
백엔드 Python (FastAPI), SQLAlchemy, PostgreSQL, Redis
클라이언트 Android (Kotlin)

트러블슈팅 하이라이트

  • 단일 NIC 환경에서 OpenStack Neutron 구성: Wi-Fi 단일 NIC만 있는 환경에서 물리 NIC은 내부 통신용으로 유지하고, 가상 인터페이스 dummy0을 만들어 OVS가 관리하는 external network로 사용해 문제를 우회했습니다. 배포 후에도 br-ex IP 미할당·Flow Table 오염·bridge-nf-call-iptables 간섭이 겹친 SSH 장애를 하나씩 추적해 해결했습니다. 자세히 보기 →
  • Octavia LB가 계속 OFFLINE에 머무는 문제: Amphora 이미지가 잘못된 프로젝트에 올라가 있던 문제, Redis 미배포로 octavia_worker가 크래시 루프를 돌던 문제, LB가 PENDING_CREATE에 멈춰 MariaDB에서 provisioning_status를 직접 ERROR로 바꿔 정리해야 했던 문제를 하나씩 해결한 뒤에도 LB가 OFFLINE에서 벗어나지 않았습니다. 원인은 octavia_network_interface가 기본값(Wi-Fi NIC)으로 잡혀 있어 Health Manager가 amphora와 heartbeat(포트 5555)를 주고받는 전용 인터페이스 o-hm0(lb-mgmt-net, 10.1.0.242)를 못 찾고 있던 것 — /etc/kolla/globals.yml에 octavia_network_interface: "o-hm0"을 지정하고 kolla-ansible reconfigure --tags octavia, openstack loadbalancer failover로 amphora를 교체해 멤버 3대(10.0.1.81/82/83)가 ONLINE으로 올라오고 VIP(10.0.1.110) 헬스체크(/health)가 정상 응답하는 것까지 확인했습니다. 자세히 보기 →
  • Terraform이 유발한 VM 삭제 사고: 네트워크 블록을 수정하면 Terraform이 이를 replace로 판단해 VM을 삭제 후 재생성한다는 점을 모른 채 plan 확인 없이 apply를 실행해 GitLab VM이 삭제될 뻔했습니다 (마침 그 VM 위에서 Runner가 돌고 있어 작업이 중단되며 부팅 볼륨 삭제까지는 가지 않았습니다). 이후 부팅 볼륨 delete_on_termination = false 고정, 주요 변경 전 스냅샷/state pull 백업, apply 수동 승인 게이트를 표준 절차로 만들었습니다. 자세히 보기 →
  • Vault AppRole 기반 배포 시크릿 발급: 애플리케이션이 요청마다 Vault를 호출하지 않도록, GitLab CI가 배포 시점에만 AppRole로 로그인해 일회용 secret_id를 조회하고 환경변수로 주입하는 방식을 채택했습니다. 자세히 보기 →

벨로그 시리즈: CarPayIn 프라이빗 클라우드 구축기

  1. 1편 — 프로젝트 개요 & 아키텍처 설계
  2. 2편 — Kolla-Ansible로 OpenStack 구축
  3. 3편 — OpenStack 단일 NIC 문제 해결
  4. 4편 — 3계층 네트워크 설계 & k3s 멀티노드 구축
  5. 5편 — Octavia 설정
  6. 6편 — HashiCorp Vault & PostgreSQL 보안 설계
  7. 7편 — Terraform & GitLab CI IaC 파이프라인
  8. 8편 — Prometheus/AlertManager 오토스케일링 자동화
  9. 외전 — 컨벤션 기반 팀 AI 협업 & TDD 자동 디버깅

레포 구조

services/
  android-app/        차량 내/로컬 테스트용 Android 클라이언트
  carpayin-backend/    인증/차량/카드/주차/결제 메인 API
  mock-card/           카드사 모방 API (k3s/Octavia 배포 대상)
  mock-pg/             PG사 모방 API + 카드 등록 WebView
  pms/                 주차 관제 시스템(PMS) 모방 API

infra/                             (아래 전체 본인 담당)
  terraform/           OpenStack VM / 네트워크 / Octavia LB 프로비저닝
    main.tf, variables.tf, outputs.tf, README.md(state import 가이드)
  ansible/             k3s, WireGuard, 모니터링 에이전트, 오토스케일링
    site.yml, inventory/hosts.yml
    roles/{k3s_agent, k3s_monitoring, node_exporter, wireguard}
    playbooks/{scale-in, scale-out}.yml
  webhook-adapter/     AlertManager → GitLab CI 트리거 어댑터 (FastAPI)

docs/
  api/                 OpenAPI 명세
  DB 스키마/           DB, Redis 키 설계 문서
  deployment/          레지스트리/CI-CD/배포 문서
  diagrams/            시퀀스 다이어그램 (Mermaid)
  use-cases/           유스케이스 명세
  시나리오/            시나리오 흐름 문서

scripts/
  build-push-images.ps1      로컬 GitLab Registry 이미지 빌드/푸시
  deploy-from-registry.ps1   레지스트리 이미지 pull 후 Docker Compose 실행
  start-local-e2e.ps1        로컬 E2E 의존 서비스 기동
  stop-local-e2e.ps1         로컬 E2E 의존 서비스 종료

로컬 실행

.env.example을 .env로 복사하고 실제 Hyundai OAuth 값을 채워 넣습니다.

PUBLIC_BASE_URL
HYUNDAI_CLIENT_ID
HYUNDAI_CLIENT_SECRET
PG_PUBLIC_BASE_URL

.env나 실제 시크릿은 커밋하지 않습니다.

docker compose up -d --build
포트 서비스
8000 carpayin-backend
8001 pms
8002 mock-pg
8003 mock-card
5432–5435 서비스별 PostgreSQL
6379 redis

테스트

cd services/carpayin-backend
python -m pytest tests/unit tests/api -q --import-mode=importlib
cd services/android-app
.\gradlew.bat :app:compileDebugKotlin

CI/CD

Self-hosted GitLab(OpenStack 내부, .gitlab-ci.yml)에서 변경된 경로에 따라 파이프라인이 갈라집니다.

변경 경로 자동 실행 수동 승인 필요
infra/terraform/** validate, plan (MR / main) apply (main)
infra/ansible/** – ansible:deploy (main)
infra/webhook-adapter/** – deploy:webhook-adapter (main, SCP + Docker Compose)
services/mock-card/** test (MR / main), build (main) deploy:mock-card (main, kubectl apply + 이미지 롤링)
  • Terraform state는 GitLab HTTP backend로 관리하며(-backend-config), lock 충돌 재발 방지를 위해 apply는 파이프라인 전용 + 수동 승인만 허용합니다.
  • 오토스케일링은 GitLab Pipeline Trigger token으로 별도 파이프라인(CI_PIPELINE_SOURCE == "trigger")을 실행해 scale:out / scale:in job이 Ansible로 노드를 추가/제거합니다.

docs/deployment/gitlab-registry.md와 scripts/build-push-images.ps1은 SaaS GitLab (registry.gitlab.com) 레지스트리로 4개 서비스 이미지를 로컬/수동으로 빌드-푸시하던 절차입니다. Self-hosted GitLab으로 옮기기 전에 쓰던 방식으로, 현재는 위 표의 self-hosted .gitlab-ci.yml 파이프라인(10.0.1.162:5050 레지스트리)이 기준이며 해당 문서/스크립트는 기록용으로만 남아 있습니다.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages