Relations (Integration)
본 문서는 Juju 4.0 코드베이스 분석을 기반으로 AI가 정리했습니다.
Overview
Relation(Integration)은 애플리케이션 간의 연결을 선언적으로 정의하는 Juju의 핵심 메커니즘이다. charm 메타데이터에 선언된 인터페이스를 기반으로, 서로 호환되는 엔드포인트를 자동으로 매칭하고 연결한다.
flowchart LR
subgraph AppA["MySQL"]
PA["provides: db\n(interface: mysql)"]
end
subgraph AppB["WordPress"]
RB["requires: db\n(interface: mysql)"]
end
PA <-->|"relation"| RB
관계 유형
charm 메타데이터에서 3가지 유형의 관계를 선언한다:
Provider / Requirer
가장 일반적인 유형. 한 앱이 서비스를 제공(provides)하고, 다른 앱이 요구(requires)한다.
# MySQL charm의 metadata.yaml
provides:
db:
interface: mysql
# WordPress charm의 metadata.yaml
requires:
db:
interface: mysql
매칭 조건:
- 인터페이스가 정확히 일치해야 함 (예:
mysql↔mysql) - 역할이 상보적이어야 함 (Provider ↔ Requirer)
- 서로 다른 애플리케이션이어야 함
Peer
같은 애플리케이션의 유닛들 간 통신. 클러스터링이나 레플리카 구성에 사용된다.
# etcd charm
peers:
cluster:
interface: etcd-cluster
Peer 관계는 애플리케이션 배포 시 자동으로 생성되며, 유닛이 추가/제거될 때마다 이벤트가 발생한다.
스코프
| 스코프 | 설명 | 용도 |
|---|---|---|
| Global 기본 스코프. 관계의 모든 유닛이 서로를 볼 수 있다. 한 유닛이 여러 관계에 참여할 수 있다. | 모든 유닛이 서로 볼 수 있음 (기본) | 일반 서비스 연결 |
| Container subordinate charm 전용 스코프. 주 유닛과 1:1로 매핑되어, subordinate 유닛이 주 유닛과 같은 머신에 자동 배치된다. | 주 유닛과 1:1 매핑 | Subordinate charm |
CLI: juju integrate
파일: cmd/juju/application/integrate.go
juju integrate mysql wordpress
juju integrate mysql:db wordpress:database
내부 흐름
integrateCommand.Run()
→ validateEndpoints() // 엔드포인트 문자열 파싱
→ crossmodel.ParseOfferURL() // cross-model offer 감지
→ maybeConsumeOffer() // 원격이면 offer 소비
→ client.AddRelation(endpoints, viaCIDRs) // 관계 생성 API
엔드포인트 이름을 생략하면 Juju가 자동 추론 양쪽 앱의 모든 엔드포인트를 조회하여 인터페이스가 일치하는 유일한 쌍을 자동으로 찾는다. 매칭되는 쌍이 2개 이상이면 AmbiguousRelation 에러를 반환한다. 한다. 매칭 가능한 엔드포인트가 여러 개면 에러가 발생하므로 명시적으로 지정해야 한다.
관계 생성 과정
파일: domain/relation/state/relation.go
flowchart TB
A["엔드포인트 추론\n(인터페이스 매칭)"] --> B["앱 생존 확인\n(둘 다 Alive)"]
B --> C["베이스 호환성 확인\n(container 스코프 시)"]
C --> D["엔드포인트 용량 확인\n(limit 초과 여부)"]
D --> E["스코프 결정\n(container/global)"]
E --> F["DB 레코드 생성"]
F --> G["relation 테이블"]
F --> H["relation_endpoint 테이블"]
F --> I["relation_status = joining"]
dqlite 테이블 구조:
| 테이블 | 용도 |
|---|---|
relation | UUID, relation_id(순차), life, scope, suspended 상태 |
relation_endpoint | 관계의 양쪽 엔드포인트 (앱 + 역할 + 인터페이스) |
relation_status | 관계 상태 (joining → joined → broken) |
relation_unit_setting | 유닛별 관계 데이터 (key-value) |
relation_application_setting | 앱별 관계 데이터 (리더만 설정 가능) |
Relation Hook 이벤트
파일: internal/worker/uniter/relation/resolver.go
관계의 생명주기에 따라 hook이 순서대로 발생한다:
flowchart LR
RC["relation-created"] --> RJ["relation-joined"]
RJ --> RCH["relation-changed"]
RCH -->|"설정 변경 시"| RCH
RCH --> RD["relation-departed"]
RD --> RB["relation-broken"]
| Hook | 발생 시점 | 설명 |
|---|---|---|
| relation-created 관계가 최초 생성될 때 한 번 발생. 아직 상대 유닛이 없는 상태에서 관계 수준의 초기화를 수행한다. | 관계 최초 생성 | 관계 수준 초기화 |
| relation-joined | 상대 유닛이 스코프에 진입 | 유닛별 초기 설정 |
| relation-changed | 상대의 설정이 변경될 때 | 설정 반영 (가장 빈번) |
| relation-departed | 상대 유닛이 스코프에서 이탈 | 정리 작업 |
| relation-broken 전체 관계가 제거될 때 발생. 모든 유닛이 departed한 후에만 발생하며, peer 관계에서는 발생하지 않는다. | 관계 전체 제거 | 관계 수준 정리 |
관계 데이터 교환
유닛은 hook 내에서 relation-get/relation-set으로 데이터를 교환한다:
# 유닛 설정 (자신의 데이터를 상대에게 공개)
relation-set hostname=db-master.local port=3306
# 상대 유닛 설정 읽기
relation-get -r db:0 hostname mysql/0
# 앱 수준 설정 (리더만 가능)
relation-set --app connection-string=mysql://...
두 수준의 데이터가 존재한다:
| 수준 | 설정 주체 | 가시성 |
|---|---|---|
| Unit Settings | 각 유닛 | 상대 모든 유닛이 읽기 가능 |
| Application Settings | 리더 유닛만 애플리케이션의 리더 유닛만 앱 수준 설정을 변경할 수 있다. 리더십은 Leadership Management 문서의 lease 기반 시스템으로 결정된다. | 상대 모든 유닛이 읽기 가능 |
설정이 변경되면 SHA256 해시로 변경 감지 → 버전 번호 증가 → relation-changed hook 트리거.
Subordinate Charm
파일: domain/relation/state/subordinateunit.go
Subordinate charm 독립적으로 배포할 수 없고, 다른 charm(principal)에 관계를 통해 붙어서 실행되는 charm. 로깅 에이전트, 모니터링 사이드카 등에 사용된다. principal 유닛과 같은 머신에서 실행된다. 은 container 스코프 관계가 성립하면 자동으로 유닛이 생성된다.
flowchart TB
subgraph Machine["Machine 0"]
P["mysql/0\n(principal)"]
S["nrpe/0\n(subordinate)"]
end
subgraph Machine2["Machine 1"]
P2["mysql/1\n(principal)"]
S2["nrpe/1\n(subordinate)"]
end
P --- S
P2 --- S2
자동 생성 흐름
유닛이 container 스코프 관계에서 EnterScope()를 호출하면:
- 관계 스코프가 Container인지 확인
- 상대 엔드포인트에서 subordinate 앱을 찾음
- 해당 principal 유닛에 이미 subordinate가 있는지 확인
- 없으면 같은 머신에 subordinate 유닛 생성
unit_principal테이블에 principal-subordinate 매핑 기록
핵심: principal 유닛 하나당 subordinate 유닛 하나가 1:1로 생성된다. principal이 3개면 subordinate도 3개.
Cross-Model Relations (CMR)
서로 다른 controller나 모델에 있는 앱을 연결하는 기능이다.
Offer 생성 (제공 측)
juju offer mysql:db
# → admin/default.mysql 형태의 offer URL 생성
Consume & Integrate (소비 측)
juju integrate wordpress admin/default.mysql
# 또는 다른 controller의 offer:
juju integrate wordpress othercontroller:admin/default.mysql --via 10.0.0.0/24
CMR 내부 흐름
flowchart LR
subgraph Source["Source Controller"]
App["MySQL"]
Offer["Application Offer"]
App --> Offer
end
subgraph Target["Target Controller"]
SAAS["SAAS App\n(synthetic)"]
WP["WordPress"]
WP -->|"relation"| SAAS
end
SAAS <-.->|"cross-controller\nWebSocket"| Offer
소비 측에서는 SAAS 앱 Software As A Service의 약자. 원격 offer를 로컬에서 표현하는 가상 애플리케이션. 실제 유닛은 없고, 원격 controller와의 프록시 역할을 한다. 이 생성되어 원격 offer의 로컬 프록시 역할을 한다.
dqlite 테이블:
| 테이블 | 용도 |
|---|---|
offer | offer UUID, 이름, 소유자 |
offer_endpoint | offer에 노출된 엔드포인트 |
offer_connection | 관계 UUID, 사용자, ingress 서브넷 |
relation_network_egress | --via 플래그로 지정한 CIDR |
Suspension
CMR 관계는 일시 중단(suspend) 가능하다. 소스 controller에서 방화벽 협상이 필요하거나 오류 발생 시 관계를 중단했다가 재개할 수 있다.
Watcher
관계 변경은 Change Stream을 통해 워커에 전파된다:
| Watcher | 추적 대상 |
|---|---|
| RelationUnitsWatcher | 유닛 멤버십 변경 (joined/departed/changed) |
| RelationLifeSuspendedStatus | 관계 생존 상태 및 suspend 상태 변화 |
| RelationUnitChange (CMR) | 원격 유닛의 전체 설정 스냅샷 |
핵심 포인트
- 인터페이스 기반 매칭: 엔드포인트의 인터페이스 이름이 일치하고 역할이 상보적이면 연결 가능
- 자동 추론: 엔드포인트 이름을 생략하면 유일한 매칭을 자동 탐색, 모호하면 에러
- Hook 순서 보장: created → joined → changed → departed → broken 순서 엄격 관리
- 두 수준의 데이터: 유닛 설정(각 유닛)과 앱 설정(리더만)이 별도로 관리
- Subordinate 자동 생성: container 스코프 관계 시 principal과 같은 머신에 1:1로 유닛 생성
- Cross-Model: SAAS 프록시 앱으로 다른 controller의 앱과 연결,
--via로 네트워크 경로 지정 - 변경 감지: SHA256 해시로 설정 변경 감지, 버전 번호로 relation-changed hook 트리거
관련 문서
- Juju Status —
juju status에서 Relations 섹션이 표시되는 원리 - Leadership Management — 앱 수준 relation 설정은 리더 유닛만 변경 가능
- Change Stream — relation 변경 이벤트가 워커에 전파되는 인프라
- Model Migration — 마이그레이션 시 cross-model relation의 controller 참조 업데이트