운영 모델¶
1. 목적¶
이 문서는 tirosh-infra 저장소의 역할과 책임 경계를 설명합니다. 처음 실행하는 절차는 시작하기를 보고, 이 문서는 왜 파일과 디렉터리가 이렇게 나뉘는지 판단할 때 봅니다.
1-1. 기본 원칙¶
- 실제 사용하는 자동화만 저장소에 둡니다.
- 아직 운영 방식이 정해지지 않은 영역은 미리 디렉터리로 만들지 않습니다.
- site별 차이는 안정적인
site_id, profile, inventory, domain desired state로 추적합니다. - 환자 정보, 운영망 접속 정보, 인증 정보는 문서나 manifest에 직접 기록하지 않습니다.
- Make는 사람이 호출하는 interface로 두고, 실제 변경 로직은 Ansible, OpenTofu, Python package에 둡니다.
1-2. 읽는 순서¶
저장소를 이해할 때는 아래 순서로 보면 흐름이 끊기지 않습니다.
sites/<site_id>/profile.toml에서 site의 기본 실행 context를 확인합니다.sites/<site_id>/inventory.toml에서 실제 접속 대상과 host 속성을 확인합니다.sites/<site_id>/<domain>/의*.vars.yml또는*.tfvars에서 원하는 상태를 확인합니다.make <domain>/<action>이 어떤 Ansible playbook이나 OpenTofu module로 위임되는지 확인합니다.
2. 전체 구조¶
tirosh-infra는 site 운영을 위한 control plane에 가깝습니다. Kubernetes manifest 저장소가 아니라, on-premise infra를 준비하고 운영 상태를 선언하는 저장소입니다.
tirosh-infra/
├─ Makefile
├─ make/
├─ packages/
│ ├─ infra-tools/
│ └─ object-store-cli/
├─ tools/
│ └─ nexus-backup/
├─ infra/
│ ├─ ansible/
│ │ └─ playbooks/
│ └─ opentofu/
├─ sites/
│ └─ tirosh-home/
│ ├─ manifest.yaml
│ ├─ profile.toml
│ ├─ inventory.toml
│ ├─ inventory.yml
│ ├─ vms.tfvars
│ ├─ proxmox/
│ ├─ host/
│ ├─ k3s/
│ ├─ rke2/
│ ├─ argocd/
│ ├─ nexus/
│ └─ github-runner/
├─ docs/
└─ mkdocs.yml
2-1. 계층별 책임¶
| 계층 | 위치 | 책임 |
|---|---|---|
| Entry / Interface | Makefile, make/*.mk |
사람이 호출하는 운영 명령과 얇은 위임 |
| Site Metadata | sites/<site_id>/manifest.yaml |
site 식별 정보와 문서화용 metadata |
| Site Profile | sites/<site_id>/profile.toml |
기본 target, vars 파일, inventory, kube context 선택 |
| Inventory Source | sites/<site_id>/inventory.toml |
실제 host 목록, SSH 접속 정보, host 속성 |
| Rendered Inventory | sites/<site_id>/inventory.yml |
Ansible이 읽는 렌더링 결과 |
| Ansible Desired State | sites/<site_id>/<domain>/*.vars.yml |
Ansible playbook에 넘기는 도메인별 원하는 상태 |
| OpenTofu Desired State | sites/<site_id>/**/*.tfvars |
OpenTofu module에 넘기는 provider, VM catalog, secrets 입력 |
| Automation Engine | infra/ansible/, infra/opentofu/ |
실제 변경 수행 |
| Helper Packages | packages/infra-tools, packages/object-store-cli |
repo helper 또는 재사용 가능한 package |
| Deployable Tools | tools/ |
특정 운영 목적의 tool/image |
| Documentation | docs/ |
운영 절차와 설계 원칙 |
2-2. packages와 tools¶
Python code는 목적에 따라 packages/와 tools/로 나눕니다.
packages/: 재사용 가능한 package 또는 publish 대상 CLItools/: 특정 운영 목적의 deployable tool 또는 image
packages/object-store-cli는 object storage를 다루는 재사용 가능한 package입니다. tools/nexus-backup은 Nexus backup이라는 운영 목적을 가진 deployable tool입니다.
3. Site 디렉터리¶
sites/<site_id>는 site별 상태를 읽는 출발점입니다. Make target은 여기서 선택된 profile, inventory, vars, tfvars를 각 실행기로 전달합니다.
3-1. site index¶
manifest.yaml: site 식별 정보와 문서화용 metadataprofile.toml: Make command default profile and explicit file path selectioninventory.toml: 사람이 관리하는 inventory sourceinventory.yml: Ansible이 읽는 렌더링된 inventoryvms.tfvars: OpenTofu가 관리할 site VM catalogproxmox/: Proxmox bootstrap, template, VM provisioning 변수host/: bare-metal host network 변수k3s/: k3s management cluster 변수rke2/: RKE2 workload cluster 변수argocd/: Argo CD 설치와 노출 변수nexus/: Nexus 내부 운영 상태 변수github-runner/: GitHub Actions runner 변수
manifest.yaml은 자동화 경로를 중복 선언하지 않습니다. 자동화 경로와 기본 실행 context는 profile.toml에 둡니다.
3-2. profile.toml¶
profile.toml은 값을 담는 파일이 아니라, site에서 어떤 파일과 context를 기본으로 사용할지 고르는 index입니다.
예를 들어 make rke2/server/install SITE=tirosh-home은 profile.toml에서 다음 값을 읽습니다.
- 사용할 inventory 경로
- RKE2 server target group
- RKE2 vars 파일
- kubeconfig 저장 경로
- kube context 이름
이 구조 덕분에 Make target은 site별 경로를 직접 추론하지 않고, profile이 명시한 값을 실행기에 넘깁니다.
3-3. inventory.toml과 inventory.yml¶
inventory.toml은 사람이 관리하는 source입니다. 실제 host, SSH 사용자, workload 참여 여부, RKE2 server/agent 역할 같은 host 속성을 여기에 둡니다.
inventory.yml은 Ansible이 읽는 렌더링 결과입니다. inventory.toml을 수정한 뒤에는 아래 명령으로 다시 생성합니다.
make site/inventory/render SITE=tirosh-home
inventory.yml은 사람이 직접 구조를 다듬는 파일이 아니라, Ansible 실행을 위한 산출물로 봅니다.
3-4. vars와 tfvars¶
*.vars.yml은 Ansible playbook 입력입니다. 파일 이름은 playbook 책임에 맞춰 정하고, 같은 도메인 안에서도 lifecycle이 다르면 분리합니다.
예를 들어 GitHub runner는 VM 내부 준비와 GitHub 등록의 변경 주기가 다르기 때문에 prepare.vars.yml과 register.vars.yml을 분리합니다.
*.tfvars는 OpenTofu module 입력입니다.
proxmox/vars.tfvars: Proxmox VM module의 provider/site 공통값vms.tfvars: site의 VM catalog*.secrets.tfvars: local secret 입력
profile.toml은 *.vars.yml이나 *.tfvars의 값을 중복 선언하지 않습니다. 어떤 vars 파일을 어떤 Make target의 기본 입력으로 사용할지만 명시합니다.
4. 실행 경계¶
이 저장소의 실행 경계는 interface와 engine을 분리하는 데 있습니다. Make는 사용자가 기억해야 할 명령 표면을 만들고, 실제 변경은 하위 실행기가 맡습니다.
4-1. Makefile¶
Makefile과 make/*.mk는 사람이 호출하는 entrypoint입니다.
profile.toml에서 기본값을 읽습니다.- 필요한 파일 존재 여부를 빠르게 확인합니다.
- Ansible, OpenTofu, Python helper로 실행을 위임합니다.
- 복잡한 상태 변경 로직을 직접 갖지 않습니다.
4-2. Ansible¶
infra/ansible/playbooks/는 host 내부 상태를 변경합니다.
- Proxmox node bootstrap
- Ubuntu cloud template 생성
- host network 설정
- k3s, RKE2, Argo CD 설치
- Nexus 내부 상태 provisioning
- GitHub Actions self-hosted runner 준비와 등록
Ansible의 site별 입력은 *.vars.yml로 관리합니다.
4-3. OpenTofu¶
infra/opentofu/는 declarative infra lifecycle을 담당합니다. 현재는 Proxmox VM provisioning을 다룹니다.
OpenTofu의 site별 입력은 *.tfvars로 관리합니다. local secret 값은 *.secrets.tfvars처럼 분리하고, repository에 실제 secret을 넣지 않습니다.
4-4. Python helpers¶
packages/infra-tools는 repository 내부 workflow를 돕는 helper package입니다. 예를 들어 site profile 조회, inventory 렌더링, 사용 가능한 port 탐색을 제공합니다.
packages/object-store-cli는 재사용 가능한 object storage package입니다. tools/nexus-backup은 이 package를 활용할 수 있는 운영 tool입니다.
5. 현재 운영 workflow¶
현재 구현된 자동화는 Proxmox VM provisioning, bare-metal host network bootstrap, k3s 기반 Argo CD, RKE2 workload cluster, Nexus package registry 운영, GitHub Actions self-hosted runner 운영입니다.
5-1. Proxmox와 VM¶
Ubuntu cloud template 생성은 Ansible이 담당합니다.
- Playbook:
infra/ansible/playbooks/proxmox/ubuntu-cloud-template.yml - 변수 예시:
infra/ansible/playbooks/proxmox/ubuntu-cloud-template.vars.example.yml - 사이트별 변수:
sites/<site_id>/proxmox/ubuntu-cloud-template.vars.yml - 실행 진입점:
make proxmox/template/apply
생성된 template을 clone해서 실제 VM을 만드는 작업은 OpenTofu가 담당합니다.
- Module:
infra/opentofu/proxmox/vms - 사이트별 Proxmox 변수:
sites/<site_id>/proxmox/vars.tfvars - 사이트별 VM 목록:
sites/<site_id>/vms.tfvars - 실행 진입점:
make proxmox/vms/plan,make proxmox/vms/apply
5-2. k3s, Argo CD, RKE2¶
Argo CD는 단일 VM 위의 k3s cluster에 배포하는 경량 bootstrap workflow로 시작합니다.
- k3s playbooks:
infra/ansible/playbooks/k3s - Argo CD playbooks:
infra/ansible/playbooks/argocd - 사이트별 k3s 변수:
sites/<site_id>/k3s/vars.yml - 실행 진입점:
make k3s/install,make argocd/install
GPU workload cluster는 RKE2로 구성합니다.
- RKE2 playbooks:
infra/ansible/playbooks/rke2 - 사이트별 RKE2 변수:
sites/<site_id>/rke2/vars.yml - 실행 진입점:
make rke2/server/install,make rke2/agent/install
5-3. Nexus¶
Nexus package registry 운영은 Nexus Kubernetes resource가 아니라 Nexus 내부 애플리케이션 상태를 관리합니다. Nexus에는 PyPI, npm, Maven, Helm, Cargo, Go, Conan처럼 package manager 생태계가 registry를 기대하는 대상과 embedded raw artifact repository만 둡니다.
- Playbook:
infra/ansible/playbooks/nexus/provision-repositories.yml - 사이트별 Nexus 변수:
sites/<site_id>/nexus/vars.yml - 실행 진입점:
make nexus/repositories/apply
5-4. GitHub Actions runner¶
GitHub Actions self-hosted runner는 host 준비와 GitHub 등록을 분리합니다.
- Prepare playbook:
infra/ansible/playbooks/github-runner/prepare.yml - Register playbook:
infra/ansible/playbooks/github-runner/register.yml - 사이트별 prepare/register 변수:
sites/<site_id>/github-runner/ - 실행 진입점:
make github-runner/prepare,make github-runner/register
6. 확장 기준¶
새 디렉터리나 새 계층은 책임이 생겼을 때 추가합니다. 이름을 먼저 만들고 나중에 의미를 채우는 방식은 피합니다.
6-1. 추가 기준¶
새 디렉터리는 아래 조건 중 하나가 충족될 때 추가합니다.
- 실제 코드나 설정 파일이 들어간다.
- 같은 패턴이 두 개 이상의 사이트에서 반복된다.
- 도구 책임이 명확해졌다.
6-2. 예상 확장¶
- OpenTofu backend: local state에서 S3-compatible backend로 이전할 수 있습니다.
- Cloud 또는 platform 경로: 실제 클라우드/Kubernetes 자산이 생길 때 추가합니다.
- Packer: 별도 image build workflow가 필요해질 때 추가합니다.
- 추가 site:
sites/<site_id>아래에 같은 profile/inventory/domain vars 구조를 반복합니다.
7. 이름 규칙¶
7-1. site_id¶
- 경로에는 병원명 대신 안정적인
site_id를 사용합니다. - 같은 site는 모든 도메인에서 같은
site_id를 사용합니다. - 병원명, 지역, 솔루션명은 경로가 아니라 manifest metadata로 관리합니다.
site_id는 가능하면 의미를 과하게 넣지 않은 고정 식별자로 유지합니다.
좋은 예:
tirosh-homehospital-001
피할 예:
Hospital A서울병원hospital-aseoul-hospital-mlflow-prod
7-2. 파일 이름¶
- Ansible 입력은
*.vars.yml을 사용합니다. - OpenTofu 입력은
*.tfvars를 사용합니다. - local secret 입력은
*.secrets.tfvars처럼 분리합니다. - lifecycle이 다르면 같은 도메인 안에서도 vars 파일을 나눕니다.
8. 리뷰 체크리스트¶
구조 관련 변경을 리뷰할 때는 아래를 확인합니다.
- 실제 파일 없이 디렉터리만 추가하지 않았는가
- Make target에 복잡한 상태 변경 로직이 들어가지 않았는가
- manifest에 자동화 경로가 중복 선언되어 있지 않은가
- profile이 참조하는 파일 경로가 실제 존재하는가
*.vars.yml과*.tfvars의 책임이 섞이지 않았는가- 사이트별 값이 공통 playbook에 직접 들어가지 않았는가
- 같은
site_id가 일관되게 쓰이는가 - 민감 정보가 문서나 manifest에 들어가지 않았는가