Cloud Tech

RayCluster on EKS and Serving LLM Model

Hanhorang31 2025. 2. 9. 03:04

 

 
 

Amazon EKS(Elastic Kubernetes Service)는 AI/ML 워크로드를 운영하기에 적합한 환경을 제공합니다.

이번 글에서는 DoEKS(Data on Amazon EKS) 프로젝트를 참고하여 EKS에서 AI/ML 모델을 운영하는 과정을 실습하였습니다.

DoEKS는 EKS에서 확장 가능한 데이터 플랫폼을 구축하기 위한 도구 모음으로, Terraform 블루프린트 및 AWS CDK를 활용한 IaC(Infrastructure as Code) 템플릿, AI/ML 워크로드 실행을 위한 모범 사례, 성능 벤치마크 및 다양한 실습 예제를 제공합니다.

본 실습의 목표는 다음과 같습니다.

 

  1. AI/ML 생태계 이해 – Amazon EKS에서 실행되는 AI/ML 도구 및 워크로드의 흐름을 이해합니다.
  2. EKS 기반 AI 모델 운영의 장점 분석 – Kubernetes 기반의 AI/ML 운영이 가지는 장점과 AWS 네이티브 서비스와의 연계를 확인합니다.
  3. Terraform 블루프린트를 활용한 EKS Add-on 구성 확인 – AI/ML 모델 운영 인프라의 모범 사례를 테라폼 코드를 통해 확인합니다.

 

Amazon EKS를 활용한 AI/ML 플랫폼의 주요 장점

Amazon EKS는 AI/ML 모델을 실행하기 위한 확장 가능하고 유연한 기반을 제공하여 머신 러닝의 잠재력을 최대한 활용하려는 조직에 이상적인 선택입니다. (DoEKS)
  1. 확장성과 유연성
    • 대규모 언어 모델 학습과 예측이 어려운 트래픽에 대응하는 추론 파이프라인까지 효율적으로 확장 가능
    • 리소스 사용과 비용을 최적화하며 유연한 확장/축소 지원
  2. 고성능 컴퓨팅 지원
  3. AI/ML 도구 통합
    • TensorFlow, PyTorch, Ray 등 인기 있는 AI/ML 도구 및 프레임워크와 원활한 통합
    • 기존 도구를 활용하면서 쿠버네티스의 확장성과 관리 기능 활용 가능
  4. 자동화된 운영 관리
    • 쿠버네티스 기능(자동 스케일링, 롤링 업데이트, 자동 복구 등)을 활용하여 운영 작업 자동화
    • 수동 개입을 최소화하여 애플리케이션의 고가용성과 복원력 보장
  5. 보안 및 규정 준수
    • AWS IAM 역할, 암호화, 네트워크 정책을 통한 강력한 보안 기능 제공

 

 

RayCluster

https://awslabs.github.io/data-on-eks/docs/blueprints/ai-ml/jark

Ray는 AI 및 Python 애플리케이션을 확장하기 위한 통합 프레임워크입니다. Ray는 핵심 분산 런타임과 ML 컴퓨팅을 단순화하기 위한 일련의 AI 라이브러리로 구성됩니다.

KubeRay는 Kubernetes에서 Ray 클러스터를 배포하고 관리하기 위한 오퍼레이터입니다. Kubernetes 환경에서 Ray 클러스터를 쉽게 생성하여 분산 머신러닝 워크로드를 실행하고 Ray의 강력한 기능을 활용할 수 있습니다.

  • KubeRay Operator: Ray 클러스터 관리 및 생명주기 제어
  • Ray Autoscaler: 작업 부하에 따라 Worker Pod의 개수를 동적으로 조정
  • Ray Head Node Pod: 클러스터의 중앙 컨트롤러 역할, 작업 스케줄링 및 노드 간 통신 조율
  • Ray Worker Pods: 실제 작업(데이터 처리, 계산)을 수행하는 노드

 

RayCluster on EKS

https://awslabs.github.io/data-on-eks/docs/blueprints/ai-ml/jark

EKS에서는 RayCluster를 노드 그룹 단위로 구별합니다.

Core Managed Node group 은 기본 노드 그룹으로 GPU Managed Node group 은 카펜터로 구성하였습니다.

Core Managed Node group 에 RayCLuster Operator만 존재하며 Ray모델을 배포할 시 해드 노드와 워커 노드를 GPU 노드(카펜터) 로 구성합니다.

git clone https://github.com/awslabs/data-on-eks.git
cd data-on-eks/ai-ml/jark-stack/terraform && chmod +x install.sh
vi install.sh

 

 

배포 코드 이해

아키텍처 구성에서 핵심은 GPU 노드 그룹을 카펜터로 구성하고, RayCluster를 카펜터 노드에 배포하는 것입니다.

테라폼 코드에서 연동 부분을 확인하겠습니다.

 

# addon.tf 
  #---------------------------------------------------------------
  # Karpenter Resources Add-on
  #---------------------------------------------------------------
  enable_karpenter_resources = true
  karpenter_resources_helm_config = {

    g5-gpu-karpenter = {
      values = [
        <<-EOT
      name: g5-gpu-karpenter
      clusterName: ${module.eks.cluster_name}
      ec2NodeClass:
        amiFamily: Bottlerocket
..
      nodePool:
        labels:
          - type: karpenter
          - NodeGroupType: g5-gpu-karpenter
        taints:
          - key: nvidia.com/gpu
            value: "Exists"
            effect: "NoSchedule"
        requirements:
          - key: "karpenter.k8s.aws/instance-family"
            operator: In
            values: ["g5"]
          - key: "karpenter.k8s.aws/instance-size"
            operator: In
            values: [ "2xlarge", "4xlarge", "8xlarge" ]
          - key: "kubernetes.io/arch"
            operator: In
            values: ["amd64"]
          - key: "karpenter.sh/capacity-type"
            operator: In
            values: ["spot", "on-demand"]
        limits:
          cpu: 1000
        disruption:
          consolidationPolicy: WhenEmpty
          consolidateAfter: 300s
          expireAfter: 720h
        weight: 100
      EOT
      ]
    }
    x86-cpu-karpenter = {
      values = [
        <<-EOT
      name: x86-cpu-karpenter
      clusterName: ${module.eks.cluster_name}
      ec2NodeClass:
        amiFamily: Bottlerocket
        karpenterRole: ${split("/", module.eks_blueprints_addons.karpenter.node_iam_role_arn)[1]}
..
      nodePool:
        labels:
          - type: karpenter
          - NodeGroupType: x86-cpu-karpenter
        requirements:
          - key: "karpenter.k8s.aws/instance-family"
            operator: In
            values: ["m5"]
          - key: "karpenter.k8s.aws/instance-size"
            operator: In
            values: [ "xlarge", "2xlarge", "4xlarge", "8xlarge"]
          - key: "kubernetes.io/arch"
            operator: In
            values: ["amd64"]
          - key: "karpenter.sh/capacity-type"
            operator: In
            values: ["spot", "on-demand"]
        limits:
          cpu: 1000
        disruption:
          consolidationPolicy: WhenEmpty
          consolidateAfter: 300s
          expireAfter: 720h
        weight: 100
      EOT
      ]
    }
  }
..
}
  • consolidationPolicy: WhenEmpty 를 통해 노드에 파드가 비어 있으면 축소하도록 설정되어 있습니다.
  • taint 설정을 통해 key: nvidia.com/gpu 이 있는 파드들만 배치하도록 설정되어 있습니다.
  • RayCluster를 배포할 때 head node 는 x86 노드 풀에, worker Node는 GPU 파드로 배포하도록 설정합니다. (하단 내용 참고)

 

인프라 구성 지역을 서울로 설정합니다.

...
# NOTE: Trainium and Inferentia are only available in us-west-2 and us-east-1 regions
variable "region" {
  description = "region"
  default     = "ap-northeast-2" # 서울로 지정
  type        = string
}
..

또한, 노드 그룹의 접속을 위해 개인 키를 노드 그룹에 등록합니다.

 ## eks.tf
  eks_managed_node_groups = {
    #  It's recommended to have a Managed Node group for hosting critical add-ons
    #  It's recommended to use Karpenter to place your workloads instead of using Managed Node groups
    #  You can leverage nodeSelector and Taints/tolerations to distribute workloads across Managed Node group or Karpenter nodes.
    core_node_group = {
      name        = "core-node-group"
      description = "EKS Core node group for hosting system add-ons"
      # Filtering only Secondary CIDR private subnets starting with "100.".
      # Subnet IDs where the nodes/node groups will be provisioned
      subnet_ids = compact([for subnet_id, cidr_block in zipmap(module.vpc.private_subnets, module.vpc.private_subnets_cidr_blocks) :
        substr(cidr_block, 0, 4) == "100." ? subnet_id : null]
      )

      # aws ssm get-parameters --names /aws/service/eks/optimized-ami/1.27/amazon-linux-2/recommended/image_id --region us-west-2
      ami_type     = "AL2_x86_64" # Use this for Graviton AL2_ARM_64
      min_size     = 2
      max_size     = 8
      desired_size = 2

      instance_types = ["m5.xlarge"]
      key_name = "shhan" # 개인 키 등록

      labels = {
        WorkerType    = "ON_DEMAND"
        NodeGroupType = "core"
      }

      tags = merge(local.tags, {
        Name = "core-node-grp"
      })
    }
    
    ....

 

인프라 구성 스크립트 확인시 의존성을 위해 VPC > EKS > addon 순으로 배포하는 것을 확인할 수 있습니다.
#!/bin/bash

# List of Terraform modules to apply in sequence
targets=(
  "module.vpc"
  "module.eks"
)

# Initialize Terraform
terraform init -upgrade

# Apply modules in sequence
for target in "${targets[@]}"
do
  echo "Applying module $target..."
  apply_output=$(terraform apply -target="$target" -auto-approve 2>&1 | tee /dev/tty)
  if [[ ${PIPESTATUS[0]} -eq 0 && $apply_output == *"Apply complete"* ]]; then
    echo "SUCCESS: Terraform apply of $target completed successfully"
  else
    echo "FAILED: Terraform apply of $target failed"
    exit 1
  fi
done

# Final apply to catch any remaining resources
echo "Applying remaining resources..."
apply_output=$(terraform apply -auto-approve 2>&1 | tee /dev/tty)
if [[ ${PIPESTATUS[0]} -eq 0 && $apply_output == *"Apply complete"* ]]; then
  echo "SUCCESS: Terraform apply of all modules completed successfully"
else
  echo "FAILED: Terraform apply of all modules failed"
  exit 1
fi
./install.sh
  • 약 20분 정도 소요됩니다.

 

배포 후 클러스터 정보와 대시보드 접근 키를 확인할 수 있습니다.

이를 토대로 클러스터를 확인하겠습니다.

aws eks --region ap-northeast-2 update-kubeconfig --name jark-stack

kubectl get nodes -A 
kubectl get deploy -A 
kubectl get pods -A 
kubectl get nodepool -A 

 

 

CloudCraft 를 통해 테라폼으로 배포한 자원을 확인하겠습니다.

CloudCraft 은 아키텍처 Draw 툴입니다. Draw 뿐만 아니라 기존의 자원을 Import 하여 아키텍처와 비용을 분석해줍니다. AWS 계정 내 IAM Role 생성을 통해 쉽게 연동할 수 있습니다.
  • 태그 기반으로 필터시 월 비용과 구성한 아키텍처를 확인할 수 있습니다.

 

 

노드 정보 확인

# 노드 접속 
kubectl node-shell ip-100-64-44-50.ap-northeast-2.compute.internal

# 노드 부트스트랩 확인
cat /etc/eks/bootstrap.sh 
...
systemctl daemon-reload
systemctl enable kubelet
systemctl start kubelet

# 로그 확인 
cat /var/log/cloud-init-output.log 
..
2025-02-08T09:01:35+0000 [eks-bootstrap] INFO: --apiserver-endpoint='https://ACE613AE88076395F9F28126FEC42060.gr7.ap-northeast-2.eks.amazonaws.com'
2025-02-08T09:01:35+0000 [eks-bootstrap] INFO: --dns-cluster-ip='172.20.0.10'
2025-02-08T09:01:35+0000 [eks-bootstrap] INFO: --use-max-pods='false'
2025-02-08T09:01:36+0000 [eks-bootstrap] INFO: Using kubelet version 1.30.8
2025-02-08T09:01:36+0000 [eks-bootstrap] INFO: Using containerd as the container runtime


ps -ef | grep kubelet  # 1 

cat  /etc/kubernetes/kubelet/kubelet-config.json  # 2 
{
  "kind": "KubeletConfiguration",
  "apiVersion": "kubelet.config.k8s.io/v1beta1",
  "address": "0.0.0.0",
  "authentication": {
    "anonymous": {
      "enabled": false
    },
    "webhook": {
      "cacheTTL": "2m0s",
      "enabled": true
    },
    "x509": {
      "clientCAFile": "/etc/kubernetes/pki/ca.crt"
    }
  },
  "authorization": {
    "mode": "Webhook",
    "webhook": {
      "cacheAuthorizedTTL": "5m0s",
      "cacheUnauthorizedTTL": "30s"
    }
  },
  "clusterDomain": "cluster.local",
  "hairpinMode": "hairpin-veth",
  "readOnlyPort": 0,
  "cgroupDriver": "systemd",
  "cgroupRoot": "/",
  "featureGates": {
    "RotateKubeletServerCertificate": true
  },
  "protectKernelDefaults": true,
  "serializeImagePulls": false,
  "serverTLSBootstrap": true,
  "tlsCipherSuites": [
    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
    "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
    "TLS_RSA_WITH_AES_256_GCM_SHA384",
    "TLS_RSA_WITH_AES_128_GCM_SHA256"
  ],
  "clusterDNS": [
    "172.20.0.10"
  ],
  "evictionHard": { # 3
    "memory.available": "100Mi",
    "nodefs.available": "10%",
    "nodefs.inodesFree": "5%"
  },
  "kubeReserved": { # 4 
    "cpu": "80m",
    "ephemeral-storage": "1Gi",
    "memory": "893Mi"
  },
  "providerID": "aws:///ap-northeast-2a/i-0bde9df1dca33ffe3",
  "systemReservedCgroup": "/system",
  "kubeReservedCgroup": "/runtime"
}

# cgroup 확인
mount | grep cgroup # 5 
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
...
  • 매개 변수를 통해 노드별 max-pod 적용 확인이 가능합니다.
  • kubelet-config.json 에는 kubelet 관련 정보가 포함되어 있습니다.
  • evictionHard 를 통해 리소스 부족 시 Pod 종료 기준 정책(메모리 100Mi, 디스크 공간 10%, inode 5% 이하) 을 확인할 수 있습니다.
  • kubeReserved 에서 Kubelet, API 서버 등)에서 사용할 예약 리소스를 확인할 수 있습니다.
  • cgroup 을 통해 cgroup Version 확인이 가능합니다. 현재 AMI가 AL2 로 cgroup1 버전을 사용하고 있습니다.

 

 

 LLM 모델 서빙

g5.12xlarge 1대를 사용하므로 시간당 5.672 USD 비용이 발생합니다. 비용이 상당하므로 주의가 필요합니다.

모델을 다운받기 위해 Hugging Face에 가입한 후 Access Token(read)를 발급받습니다.

또한, 테스트에서 사용할 모델의 Repo로 들어가 Access 권한을 확인합니다.

# 아래 토큰 주입
export HUGGING_FACE_HUB_TOKEN=$(echo -n "Your-Hugging-Face-Hub-Token-Value" | base64)

# 모델 배포 
cd data-on-eks/gen-ai/inference/vllm-rayserve-gpu
envsubst < ray-service-vllm.yaml| kubectl apply -f -
  • 약 10분정도 소요됩니다.

Ray-service-vllm.yaml 에는 Ray-head 와 Ray-worker 노드 그룹의 구성과 모델 정의를 확인할 수 있습니다.

headGroupSpec:
      headService:
        metadata:
          name: vllm
          namespace: rayserve-vllm
      rayStartParams:
        dashboard-host: '0.0.0.0'
        num-cpus: "0"
      # Pod template
      template:
        spec:
          containers:
          - name: ray-head
            image: public.ecr.aws/data-on-eks/ray2.24.0-py310-vllm-gpu:v1
            imagePullPolicy: IfNotPresent
            lifecycle:
              preStop:
                exec:
                  command: ["/bin/sh", "-c", "ray stop"]
            ports:
            - containerPort: 6379
              name: gcs
            - containerPort: 8265
              name: dashboard
            - containerPort: 10001
              name: client
            - containerPort: 8000
              name: serve
            volumeMounts:
            - mountPath: /tmp/ray
              name: ray-logs
            # resources for pulling the larger images
            resources:
              limits:
                cpu: 2
                memory: "12G"
              requests:
                cpu: 2
                memory: "12G"
            env:
            # Ensure to set VLLM_PORT to avoid conflict with Ray serve port 8000
            # We also noticed an error when trying to deploy multiple replicas in single g5 instance. "Error: torch.distributed.DistNetworkError: The server socket has failed to listen on any local network address. The server socket has failed to bind to [::]:8004 (errno: 98 - Address already in use)."
            - name: VLLM_PORT
              value: "8004"
            - name: LD_LIBRARY_PATH
              value: "/home/ray/anaconda3/lib:$LD_LIBRARY_PATH"
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-token
                  key: hf-token
            - name: RAY_GRAFANA_HOST
              value: http://kube-prometheus-stack-grafana.kube-prometheus-stack.svc:80
            - name: RAY_PROMETHEUS_HOST
              value: http://kube-prometheus-stack-prometheus.kube-prometheus-stack.svc:9090
          nodeSelector:
            NodeGroupType: x86-cpu-karpenter
            type: karpenter
          volumes:
          - name: ray-logs
            emptyDir: {}
    workerGroupSpecs:
    # The pod replicas in this group typed worker
    - replicas: 1
      minReplicas: 1
      maxReplicas: 4
      groupName: gpu-group
      rayStartParams: {}
      # Pod template
      template:
        spec:
          containers:
          - name: ray-worker
            image: public.ecr.aws/data-on-eks/ray2.24.0-py310-vllm-gpu:v1
            imagePullPolicy: IfNotPresent
            lifecycle:
              preStop:
                exec:
                  command: ["/bin/sh", "-c", "ray stop"]
            resources:
              limits:
                cpu: 10
                memory: "60G"
                nvidia.com/gpu: 1
              requests:
                cpu: 10
                memory: "60G"
                nvidia.com/gpu: 1
            env:
            # Ensure to set VLLM_PORT to avoid conflict with Ray serve port 8000
            - name: VLLM_PORT
              value: "8004"
            - name: LD_LIBRARY_PATH
              value: "/home/ray/anaconda3/lib:$LD_LIBRARY_PATH"
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-token
                  key: hf-token
          nodeSelector:
            NodeGroupType: g5-gpu-karpenter
            type: karpenter
          # Please add the following taints to the GPU node.
          tolerations:
          - key: "nvidia.com/gpu"
            operator: "Exists"
            effect: "NoSchedule"
  • Karpenter를 이용하여 Ray Head Node 는 x86-cpu-karpneter 노드 풀에, Ray worker는 g5-gpu-karpenter 노드 풀에 배포합니다.

yaml 에는 RayServicer라는 객체를 통해 ML 모델을 정의하여 배포할 수 있습니다.

눈 여겨볼점은 모델의 관리 옵션입니다.

apiVersion: ray.io/v1
kind: RayService
metadata:
  name: vllm
  namespace: rayserve-vllm
spec:
  serviceUnhealthySecondThreshold: 1800 # Config for the health check threshold for service. Default value is 60.
  deploymentUnhealthySecondThreshold: 1800 # Config for the health check threshold for deployments. Default value is 60.
  serveConfigV2: |
    applications:
      - name: mistral
        import_path: "vllm_serve:deployment"
        runtime_env:
          env_vars:
            LD_LIBRARY_PATH: "/home/ray/anaconda3/lib:$LD_LIBRARY_PATH"
            MODEL_ID: "mistralai/Mistral-7B-Instruct-v0.2"
            GPU_MEMORY_UTILIZATION: "0.9"
            MAX_MODEL_LEN: "8192"
            MAX_NUM_SEQ: "4"
            MAX_NUM_BATCHED_TOKENS: "32768"
        deployments:
          - name: mistral-deployment
            autoscaling_config:
              metrics_interval_s: 0.2
              min_replicas: 1
              max_replicas: 4
              look_back_period_s: 2
              downscale_delay_s: 600
              upscale_delay_s: 30
              target_num_ongoing_requests_per_replica: 20
            graceful_shutdown_timeout_s: 5
            max_concurrent_queries: 100
            ray_actor_options:
              num_cpus: 1
              num_gpus: 1
  • erviceUnhealthySecondThreshold : 정상적으로 동작할 경우의 임계값, 1800초(30분)동안 문제가 없으면 정상으로 간주
  • deployements.autoscaling_config : 모델 동적 스케일링을 정의하는 옵션입니다. 최대 4개 인스턴스까지 자동 확장하며, 요청이 적으면 최소 1개만 유지합니다. 각 replica에서(target_num_ongoing_requests_per_replica) 20의 요청을 유지할 경우 30초 후( upscale_delay_s) 에 모델을 증가합니다.

 

파드 정상 확인 후 Ray 에 대시보드에 접근합니다.

kubectl get pods -n rayserve-vllm

kubectl -n rayserve-vllm port-forward svc/vllm 8265:8265
  • cloudcraft는 Karpent를 인지하지 못하는 것 같습니다.
  • 카펜터로 구성된 노드들의 AMI는 Bottlerocket입니다.

 

모델 테스트

서빙하는 LLM 모델을 확인하겠습니다. 먼저 배포한 모델을 포트포워딩합니다.

kubectl -n rayserve-vllm port-forward svc/vllm-serve-svc 8000:8000

클라이언트를 통해 LLM을 확인합니다.

cd data-on-eks/gen-ai/inference/vllm-rayserve-gpu
python3 -m venv .venv
source .venv/bin/activate
pip install requests
pip install aiohttp
python3 client.py

Client.py 는 프롬포트 파일(prompts.txt)를 읽고 모델 API(localhost:8000)를 호출하여 결과 값을 result.txt 에 저장합니다. 결과 파일을 확인하면 정상적으로 AI 모델 결과를 확인할 수 있습니다.

 

 

Observability

Ray head 와 worker Node 에 대한 메트릭 대시보드 구성할 수 있습니다.

아래 경로를 통해 각 노드의 메트릭 수집 엔드포인트 노출합니다.

cd data-on-eks/ai-ml/jark-stack/terraform/monitoring

kubectl apply -f serviceMonitor.yaml
kubectl apply -f podMonitor.yaml

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: ray-head-monitor
  namespace: kube-prometheus-stack
  labels:
    # `release: $HELM_RELEASE`: Prometheus can only detect ServiceMonitor with this label.
    release: kube-prometheus-stack
spec:
  jobLabel: ray-head
  # Only select Kubernetes Services in the "default" namespace.
  namespaceSelector:
    matchNames:
      - rayserve-vllm
  # Only select Kubernetes Services with "matchLabels".
  selector:
    matchLabels:
      ray.io/node-type: head
  # A list of endpoints allowed as part of this ServiceMonitor.
  endpoints:
    - port: metrics
    - port: as-metrics # autoscaler metrics
    - port: dash-metrics # dashboard metrics
  targetLabels:
  - ray.io/cluster

또한, Ray Dashboard에서 Grafana 정보를 읽을 수 있습니다.

기본 설정으로 확인만 합니다.

env:
  - name: RAY_GRAFANA_HOST
    value: http://kube-prometheus-stack-grafana.kube-prometheus-stack.svc:80
  - name: RAY_PROMETHEUS_HOST
    value: http://kube-prometheus-stack-prometheus.kube-prometheus-stack.svc:9090

대시보드는 Git REPO json 을 Import 합니다.

Import 후 RayCluster 에 대한 대시보드를 정상적으로 확인할 수 있습니다.

kubectl port-forward deployment/kube-prometheus-stack-grafana -n kube-prometheus-stack 3000:3000

# Username : admin, Password는 아래 참고 

- Get secret name from Terraform output
terraform output grafana_secret_name

- Get admin user password
aws secretsmanager get-secret-value --secret-id <grafana_secret_name_output> --region $AWS_REGION --query "SecretString" --output text

 

 

자원 정리

# RayCluster & 모델 자원 정리 
cd data-on-eks/gen-ai/inference/vllm-rayserve-gpu
kubectl delete -f ray-service-vllm.yaml 


# 모니터링 자원 정리 
cd data-on-eks/ai-ml/jark-stack/terraform/monitoring

kubectl delete -f serviceMonitor.yaml
kubectl delete -f podMonitor.yaml

# 테라폼 자원 정리
cd data-on-eks/ai-ml/jark-stack/terraform/ && chmod +x cleanup.sh
./cleanup.sh 

 

 

참조

https://docs.ray.io/en/latest/serve/getting_started.html

https://awslabs.github.io/data-on-eks/docs/gen-ai/inference/GPUs/vLLM-rayserve

https://www.youtube.com/watch?v=DjhdPdU9JiY