Compare commits

...

10 Commits

Author SHA1 Message Date
013140f02c REFACTOR(repo): simplify project structure
Some checks failed
Build Docker Image / build-and-push (push) Has been cancelled
- Move services/backend to langgraph/
- Move deploy/docker/Dockerfile to Dockerfile
- Remove deploy/, services/ folders
- Update GitHub Actions workflow paths
- Remove kustomization update logic (managed by K3S-HOME/applications)
2026-01-05 16:50:49 +09:00
49083910c6 REFACTOR(api): remove Groq API dependency
- Remove Groq API integration
- Use only Anthropic Claude API
2026-01-02 00:05:14 +09:00
d3dd1da442 CHORE(k8s): switch to Traefik with Authelia SSO
- Change ingressClassName to traefik
- Add Authelia middleware for SSO
2026-01-01 23:28:54 +09:00
0e9940f0a3 REVERT(ci): revert to GITHUB_TOKEN for ghcr.io
- Revert authentication to GITHUB_TOKEN
- Fix container registry push
2026-01-01 19:37:44 +09:00
8719e1723c REFACTOR(build): use native ARM64 runner
- Switch from ubuntu-latest to ubuntu-24.04-arm
- Remove QEMU emulation (not needed with native ARM)
- Use CR_PAT instead of GITHUB_TOKEN for ghcr.io access
2026-01-01 19:36:21 +09:00
742d24ab55 FEAT(ci): add GitHub Actions workflow
- Add GitHub Actions CI/CD workflow
- Configure ghcr.io image registry
2026-01-01 18:32:41 +09:00
fa75dcc2ca FIX(app): update image registry to ghcr.io
- Change container image registry to ghcr.io
- Update image references
2026-01-01 18:31:30 +09:00
171cf347f4 REFACTOR(k8s): remove hostPath and nodeSelector
- Remove hostPath volume configuration
- Remove nodeSelector for flexible scheduling
2026-01-01 18:29:42 +09:00
075ce3f35c CHORE(api): update ExternalSecrets API version
- Update ExternalSecret API from v1beta1 to v1
- Migrate to stable API version
2025-12-29 21:11:06 +09:00
a50720e84d CHORE(k8s): update PostgreSQL namespace reference
- Update PostgreSQL service namespace reference
- Fix database connection configuration
2025-12-29 20:51:33 +09:00
30 changed files with 67 additions and 1043 deletions

View File

@@ -1,190 +0,0 @@
name: Build Docker Image
on:
push:
branches: [main]
tags:
- 'v*'
workflow_dispatch:
env:
REGISTRY: gitea0213.kro.kr
IMAGE_NAME: ${{ github.repository }}
DOCKER_HOST: tcp://172.17.0.1:2375
jobs:
build-and-push:
runs-on: ubuntu-24.04-arm
permissions:
contents: write
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to Gitea Container Registry
run: |
echo "${{ secrets.GITEAREGISTRY }}" | docker login ${{ env.REGISTRY }} --username bluemayne --password-stdin
- name: Lowercase repository name
id: lowercase
run: |
echo "repo=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ steps.lowercase.outputs.repo }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-sha-,format=long
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
id: build
run: |
TAGS="${{ steps.meta.outputs.tags }}"
# Build the image
docker build \
-t $(echo "$TAGS" | head -n 1) \
-f ./deploy/docker/Dockerfile \
./services/backend
# Tag all versions
FIRST_TAG=$(echo "$TAGS" | head -n 1)
echo "$TAGS" | while read tag; do
if [ "$tag" != "$FIRST_TAG" ]; then
docker tag "$FIRST_TAG" "$tag"
fi
done
# Push all tags
echo "$TAGS" | while read tag; do
docker push "$tag"
done
# Get digest
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$FIRST_TAG" | cut -d'@' -f2)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Extract SHA tag
id: extract-tag
run: |
# Extract the SHA-based tag from the tags list
TAGS="${{ steps.meta.outputs.tags }}"
echo "All tags:"
echo "$TAGS"
echo "---"
# Get commit SHA (full 40 characters)
COMMIT_SHA="${{ github.sha }}"
# Get current branch name
BRANCH_NAME="${{ github.ref_name }}"
echo "Branch: $BRANCH_NAME"
# Method 1: Extract the full SHA tag from docker/metadata-action output
# docker/metadata-action creates: <branch>-sha-<full-40-char-sha>
SHA_TAG=$(echo "$TAGS" | grep -oE "${BRANCH_NAME}-sha-[a-f0-9]{40}" | head -n 1)
# Method 2: If not found, try to extract any branch-sha- tag (fallback)
if [ -z "$SHA_TAG" ]; then
SHA_TAG=$(echo "$TAGS" | grep -oE "${BRANCH_NAME}-sha-[a-f0-9]+" | head -n 1)
if [ -n "$SHA_TAG" ]; then
echo "⚠️ Found SHA tag (may not be full 40 chars): $SHA_TAG"
fi
fi
# Method 3: Fallback to commit SHA directly (construct the tag)
if [ -z "$SHA_TAG" ]; then
SHA_TAG="${BRANCH_NAME}-sha-$COMMIT_SHA"
echo "⚠️ Could not extract from tags, using commit SHA: $SHA_TAG"
fi
if [ -z "$SHA_TAG" ]; then
echo "❌ ERROR: Failed to extract SHA tag"
exit 1
fi
echo "sha-tag=$SHA_TAG" >> $GITHUB_OUTPUT
echo "✅ Extracted SHA tag: $SHA_TAG"
- name: Update kustomization with new image tag
env:
GITEA_TOKEN: ${{ secrets.GITEAREGISTRYTOKEN }}
run: |
git config --global user.name "gitea-actions[bot]"
git config --global user.email "gitea-actions[bot]@users.noreply.gitea.com"
# Validate that SHA_TAG is not empty
SHA_TAG="${{ steps.extract-tag.outputs.sha-tag }}"
if [ -z "$SHA_TAG" ]; then
echo "❌ ERROR: SHA_TAG is empty, cannot update kustomization"
exit 1
fi
# For mas, we only have prod overlay (main branch)
BRANCH_NAME="${{ github.ref_name }}"
if [ "$BRANCH_NAME" = "main" ]; then
OVERLAY="prod"
else
echo "⚠️ Unknown branch: $BRANCH_NAME, skipping kustomization update"
exit 0
fi
KUSTOMIZATION_FILE="deploy/k8s/overlays/$OVERLAY/kustomization.yaml"
# Check if kustomization file has images section
if grep -q "images:" "$KUSTOMIZATION_FILE"; then
echo "📝 Updating $KUSTOMIZATION_FILE with tag: $SHA_TAG"
# Update kustomization.yaml with new image tag
# Handle both cases: newTag: (with value) and newTag: (empty)
sed -i.bak "s|newTag:.*|newTag: $SHA_TAG|" "$KUSTOMIZATION_FILE"
# Verify the update was successful
if grep -q "newTag: $SHA_TAG" "$KUSTOMIZATION_FILE"; then
echo "✅ Successfully updated kustomization.yaml"
rm -f "$KUSTOMIZATION_FILE.bak"
else
echo "❌ ERROR: Failed to update kustomization.yaml"
cat "$KUSTOMIZATION_FILE"
exit 1
fi
# Commit and push if there are changes
if git diff --quiet; then
echo "No changes to commit"
else
git add "$KUSTOMIZATION_FILE"
git commit -m "Update $OVERLAY image to $SHA_TAG"
git push
echo "✅ Kustomization updated with new image tag: $SHA_TAG"
fi
else
echo " $OVERLAY overlay uses base image (latest tag), skipping kustomization update"
echo " Image built with tag: $SHA_TAG"
fi
- name: Display image information
run: |
echo "✅ Image built and pushed successfully!"
echo "📦 Image tags:"
echo "${{ steps.meta.outputs.tags }}"
echo "🔖 SHA tag: ${{ steps.extract-tag.outputs.sha-tag }}"
echo "🔖 Digest: ${{ steps.build.outputs.digest }}"
echo ""
echo "🚀 Kustomization updated with new image tag"
echo " ArgoCD will automatically detect and deploy this new image"
echo " Monitor deployment at your ArgoCD dashboard"

67
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: Build Docker Image
on:
push:
branches: [main]
tags:
- 'v*'
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Lowercase repository name
id: lowercase
run: |
echo "repo=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ steps.lowercase.outputs.repo }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: ./langgraph
file: ./Dockerfile
push: true
platforms: linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Display image information
run: |
echo "Image built and pushed successfully!"
echo "Image tags:"
echo "${{ steps.meta.outputs.tags }}"

337
README.md
View File

@@ -1,337 +0,0 @@
# MAS (Multi-Agent System)
**K8s 인프라 분석 & 의사결정 시스템** - 클러스터를 분석하고 도구 도입 여부를 결정해주는 AI 시스템
## 🎯 What is this?
MAS는 Kubernetes 클러스터 상태를 분석하고, **도구 도입 추천/비추천을 결정**해주는 AI 에이전트 시스템입니다.
**사용 시나리오:**
1. "Tekton 도입 여부를 결정해줘" → 클러스터 분석 → **도입 추천/비추천 결정**
2. 한국어로 이유, 대안, 구현 가이드 제공
3. 기술적 세부사항 없이 **명확한 결론** 제시
## 🤖 Agents
### Planning Agent (Claude 4.5)
- 도구 요구사항 분석
- 필요한 K8s 리소스 파악
- 확인이 필요한 클러스터 정보 정의
### Research Agent (Groq Llama 3.3)
- kubectl 명령어로 클러스터 상태 분석
- 기존 도구 확인 (ArgoCD, Gitea, Prometheus 등)
- 리소스 사용률 및 버전 확인
### Decision Agent (Claude 4.5)
- **도입 추천/비추천 결정** (한국어)
- 명확한 이유 제시
- 대안 제시 (비추천인 경우)
- 간단한 구현 가이드 (추천인 경우)
### Tech stack
- **Backend**: LangGraph + LangChain + FastAPI
- **UI**: Chainlit (chat-style UI)
- **Database**: PostgreSQL (CNPG)
- **Cache**: Redis
- **LLMs**: Claude API (Orchestrator, Planning, Prompt Gen) + Groq Llama 3.3 (Research)
- **Deploy**: Kubernetes + ArgoCD
---
## 🚀 Local development
### 1. Run with Docker Compose
```bash
cd deploy/docker
# Copy or create .env and fill in your API keys
# (ANTHROPIC_API_KEY, GROQ_API_KEY, etc.)
# Start the full stack
docker compose up -d
# Tail logs
docker compose logs -f mas
```
Open: `http://localhost:8000`
### 2. Run backend directly (Python)
```bash
cd services/backend
# Create venv
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Environment variables
cp .env.example .env
# Edit .env and set your API keys
# Run Chainlit app
chainlit run chainlit_app.py
```
---
## ☸️ Kubernetes deployment
### 1. Create namespace and secrets
```bash
kubectl create namespace mas
kubectl create secret generic mas-api-keys \
--from-literal=anthropic-api-key=YOUR_CLAUDE_KEY \
--from-literal=openai-api-key=YOUR_OPENAI_KEY \
--from-literal=google-api-key=YOUR_GEMINI_KEY \
-n mas
```
### 2. Deploy via ArgoCD
```bash
# Create ArgoCD Application
kubectl apply -f deploy/argocd/mas.yaml
# Sync and check status
argocd app sync mas
argocd app get mas
```
### 3. Deploy from your server (example)
```bash
# SSH into your k3s master
ssh oracle-master
# Apply ArgoCD Application
sudo kubectl apply -f /path/to/deploy/argocd/mas.yaml
# Check status
sudo kubectl get pods -n mas
sudo kubectl logs -f deployment/mas -n mas
```
Ingress example (if configured): `https://mas.mayne.vcn`
---
## 🎨 UI customization
### Chainlit theme & behavior
You can customize the UI via `services/backend/.chainlit`:
```toml
[UI]
name = "MAS"
show_readme_as_default = true
default_collapse_content = true
```
### Agent prompts
System prompts for each agent live in `services/backend/agents.py`.
You can tune:
- how the **Orchestrator** routes tasks
- coding style of backend/frontend agents
- SRE troubleshooting behavior
---
## 📊 Observability
### Prometheus ServiceMonitor (example)
```yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: mas
namespace: mas
spec:
selector:
matchLabels:
app: mas
endpoints:
- port: http
path: /metrics
```
### Grafana dashboards
Recommended panels:
- LangGraph workflow metrics
- Per-agent latency & error rate
- Token usage and cost estimates
- Backend API latency & 5xx rate
---
## 🔧 Advanced features
### 1. MCP (Model Context Protocol) with Claude
Using Claude Code as Orchestrator, MAS can access:
- Filesystem (read/write project files)
- Git (status, commit, push, PR)
- SSH (run remote commands on your servers)
- PostgreSQL (schema inspection, migrations, queries)
- Kubernetes (kubectl via MCP tool)
This allows fully automated workflows like:
- “Create a new service, add deployment manifests, and deploy to k3s.”
- “Debug failing pods and propose a fix, then open a PR.”
### 2. Multi-agent collaboration (LangGraph)
Typical workflow:
```text
User request
Claude Orchestrator
↓ decides which agent(s) to call
Backend Dev → Frontend Dev → SRE
Claude Orchestrator (review & summary)
Final answer to user
```
Examples:
- Fullstack feature (API + UI + monitoring)
- Infra rollout (Harbor, Tekton, CNPG, MetalLB) with validation
---
## 📝 Usage examples
### Example 1: Tekton 도입 여부 결정
```text
User: "Tekton 도입 여부를 결정해줘"
🎼 Orchestrator → 조율
📋 Planning Agent:
→ Tekton 요구사항: Namespace, CRDs, Controllers
→ 필요 리소스: 2 CPU, 4GB RAM
→ 확인 필요: 기존 CI/CD 도구, K8s 버전
🔍 Research Agent:
→ kubectl get nodes: v1.33.6, 3 nodes ✓
→ kubectl get pods -A: ArgoCD 운영 중 발견
→ Gitea Actions 사용 가능 확인
💡 Decision Agent:
❌ Tekton 도입 비추천
이유:
- ArgoCD + Gitea Actions로 충분
- 추가 리소스 소비 불필요
- 학습 곡선 및 유지보수 부담
대안:
- Gitea Actions 활용 (이미 설치됨)
- ArgoCD로 배포 자동화 유지
✨ Output: 명확한 한국어 보고서
```
### Example 2: Harbor 필요성 분석
```text
User: "Harbor가 필요한지 분석해줘"
→ Planning: Harbor 요구사항 분석
→ Research: 기존 registry 확인 (Gitea Container Registry 발견)
→ Decision:
❌ Harbor 도입 비추천
이유: Gitea Container Registry로 충분
✨ 사용자 친화적 한국어 결론
```
### Example 3: Prometheus 설치 여부
```text
User: "Prometheus를 설치해야 할까?"
→ Planning: Monitoring stack 요구사항
→ Research: 이미 Prometheus 운영 중 발견!
→ Decision:
✅ 이미 설치되어 있음
현재 상태: monitoring namespace에서 정상 작동 중
✨ 중복 설치 방지
```
---
## 🔧 Workflow
```
User Input: "X 도입 여부를 결정해줘"
Orchestrator (조율)
Planning Agent (도구 요구사항 분석)
Research Agent (클러스터 상태 분석)
Decision Agent (한국어 의사결정 보고서)
Output: ✅ 추천 또는 ❌ 비추천 (이유 포함)
```
## 📊 출력 예시
```markdown
# Tekton 도입 분석 결과
## 📊 현재 클러스터 상태
- Kubernetes 버전: v1.33.6
- 노드: 3개 (1 control-plane, 2 workers)
- 기존 CI/CD: ArgoCD, Gitea Actions
- 운영 애플리케이션: 15개
## 💡 권장사항: Tekton 도입 비추천
### ❌ 비추천 이유
1. ArgoCD + Gitea Actions 조합으로 충분
2. 추가 리소스 소비 (2 CPU, 4GB RAM)
3. 학습 곡선 및 운영 부담 증가
### 🔄 권장 대안
- Gitea Actions로 빌드 파이프라인 구성
- ArgoCD로 GitOps 배포 유지
- 필요시 GitHub Actions 연동
## 🎯 결론
현재 인프라로 충분하며, Tekton 도입은 불필요합니다.
```
## 🤝 Contributing
Contributions are welcome:
- Improve Planning Agent prompts for better folder structures
- Enhance Research Agent kubectl commands
- Add more infrastructure tools (Harbor, Tekton, CNPG, MetalLB, etc.)
- Better Markdown template for Prompt Generator
Feel free to open issues or PRs in your Git repository.
---
## 📄 License
MIT

View File

@@ -1,31 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: mas-prod
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/Mayne0213/mas.git
targetRevision: main
path: deploy/k8s/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: mas
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
revisionHistoryLimit: 10

View File

@@ -1,37 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: mas
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/Mayne0213/mas.git
targetRevision: main
path: deploy/argocd
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
revisionHistoryLimit: 10

View File

@@ -1,10 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
# App of Apps Application (self-managing)
- application.yaml
# Application deployments
- application-prod.yaml

View File

@@ -1,84 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mas
namespace: mas
labels:
app: mas
spec:
replicas: 1
selector:
matchLabels:
app: mas
template:
metadata:
labels:
app: mas
spec:
hostPID: true # 호스트 프로세스 네임스페이스 접근
serviceAccountName: mas
containers:
- name: mas
image: github.com/Mayne0213/mas:latest
imagePullPolicy: Always
securityContext:
privileged: true # nsenter 사용을 위한 권한
ports:
- containerPort: 8000
name: http
env:
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: mas-api-keys
key: anthropic-api-key
- name: GROQ_API_KEY
valueFrom:
secretKeyRef:
name: mas-api-keys
key: groq-api-key
- name: GROQ_API_BASE
value: "https://api.groq.com/openai/v1"
# Chainlit uses asyncpg directly (not SQLAlchemy)
- name: CHAINLIT_DATABASE_URL
value: "postgresql://bluemayne:$(POSTGRES_PASSWORD)@postgresql-cnpg-rw.postgresql-cnpg.svc.cluster.local:5432/mas"
# SQLAlchemy format (if needed)
- name: DATABASE_URL
value: "postgresql://bluemayne:$(POSTGRES_PASSWORD)@postgresql-cnpg-rw.postgresql-cnpg.svc.cluster.local:5432/mas"
- name: POSTGRES_HOST
value: "postgresql-cnpg-rw.postgresql-cnpg.svc.cluster.local"
- name: POSTGRES_PORT
value: "5432"
- name: POSTGRES_USER
value: "bluemayne"
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgresql-password
key: password
- name: GITEA_TOKEN
valueFrom:
secretKeyRef:
name: mas-api-keys
key: gitea-token
optional: true
- name: REDIS_URL
value: "redis://redis:6379/0"
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
# cpu: removed to prevent throttling
volumeMounts:
- name: projects
mountPath: /mnt/projects
nodeSelector:
kubernetes.io/hostname: mayne-vcn # Only run on master node where Projects directory exists
volumes:
- name: projects
hostPath:
path: /home/ubuntu/Projects
type: Directory

View File

@@ -1,16 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- serviceaccount.yaml
commonLabels:
app.kubernetes.io/name: mas
app.kubernetes.io/component: platform
images:
- name: github.com/Mayne0213/mas
newTag: latest

View File

@@ -1,17 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: mas
namespace: mas
labels:
app: mas
spec:
type: ClusterIP
ports:
- port: 8000
targetPort: 8000
protocol: TCP
name: http
selector:
app: mas

View File

@@ -1,50 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: mas
namespace: mas
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: mas-viewer
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: mas-writer
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: mas-viewer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mas-viewer
subjects:
- kind: ServiceAccount
name: mas
namespace: mas
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: mas-writer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mas-writer
subjects:
- kind: ServiceAccount
name: mas
namespace: mas

View File

@@ -1,62 +0,0 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: mas-api-keys
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: mas-api-keys
creationPolicy: Owner
data:
- secretKey: anthropic-api-key
remoteRef:
key: mas/api-keys
property: ANTHROPIC_API_KEY
- secretKey: groq-api-key
remoteRef:
key: mas/api-keys
property: GROQ_API_KEY
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: postgresql-password
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: postgresql-password
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: databases/postgresql-cnpg
property: PASSWORD
- secretKey: postgres-password
remoteRef:
key: databases/postgresql-cnpg
property: POSTGRES_PASSWORD
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: postgresql-root-password
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: postgresql-root-password
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: databases/postgresql-cnpg
property: POSTGRES_PASSWORD

View File

@@ -1,43 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mas-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
# WebSocket 지원 (Chainlit UI에 필요)
nginx.ingress.kubernetes.io/websocket-services: "mas"
# 프록시 타임아웃 설정 (장시간 스트리밍 응답)
nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
# 프록시 버퍼링 비활성화 (스트리밍 응답)
nginx.ingress.kubernetes.io/proxy-buffering: "off"
spec:
ingressClassName: haproxy
tls:
- hosts:
- mas0213.kro.kr
- www.mas0213.kro.kr
secretName: mas-tls
rules:
- host: mas0213.kro.kr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mas
port:
number: 8000
- host: www.mas0213.kro.kr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mas
port:
number: 8000

View File

@@ -1,19 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mas
resources:
- ../../base
- resourcequota.yaml
- externalsecret.yaml
- ingress.yaml
commonLabels:
environment: production
# 이미지 태그 설정 (ArgoCD Image Updater가 자동으로 업데이트)
images:
- name: github.com/Mayne0213/mas
newTag: main-sha-004c30bfa872c37dd3da5ad8501589c415807da8

View File

@@ -1,8 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: mas
labels:
name: mas
environment: production

View File

@@ -1,12 +0,0 @@
apiVersion: v1
kind: ResourceQuota
metadata:
name: mas-quota
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
# limits.cpu: "8" # Removed to prevent quota enforcement (we removed CPU limits cluster-wide)
limits.memory: 16Gi
persistentvolumeclaims: "5"

View File

@@ -1,127 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: mas
namespace: mas
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: mas-viewer
rules:
# Read-only access to most resources
- apiGroups: [""]
resources:
- pods
- pods/log
- services
- endpoints
- namespaces
- nodes
- persistentvolumeclaims
- configmaps
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources:
- deployments
- statefulsets
- daemonsets
- replicasets
verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
resources:
- jobs
- cronjobs
verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
resources:
- ingresses
verbs: ["get", "list", "watch"]
- apiGroups: ["argoproj.io"]
resources:
- applications
verbs: ["get", "list", "watch"]
# Describe resources
- apiGroups: [""]
resources:
- pods/status
- services/status
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: mas-viewer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mas-viewer
subjects:
- kind: ServiceAccount
name: mas
namespace: mas
---
# YAML Manager용 write 권한 (Groq 에이전트)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: mas-writer
rules:
# Write access for YAML Manager
- apiGroups: [""]
resources:
- pods
- services
- configmaps
- secrets
verbs: ["create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources:
- deployments
- statefulsets
- daemonsets
- replicasets
verbs: ["create", "update", "patch", "delete"]
- apiGroups: ["networking.k8s.io"]
resources:
- ingresses
verbs: ["create", "update", "patch", "delete"]
- apiGroups: ["batch"]
resources:
- jobs
- cronjobs
verbs: ["create", "update", "patch", "delete"]
# Namespace management
- apiGroups: [""]
resources:
- namespaces
verbs: ["create", "update", "patch"]
# ArgoCD Application management
- apiGroups: ["argoproj.io"]
resources:
- applications
verbs: ["create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: mas-writer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mas-writer
subjects:
- kind: ServiceAccount
name: mas
namespace: mas