다른 리전 OCI Generative AI를 프라이빗하게 호출하기
배경설명
OCI Generative AI가 OCI 일부 리전(Generative AI Regions)에서만 서비스되고 있습니다. 국내에서는 아직 Generative AI 서비스를 제공하고 있지 않아, 가까운 일본 오사카에 있는 OCI Generative AI 서비스를 사용한다고 할 경우, 국내 리전에 있는 서버에서 인터넷을 거치지 않고, 사용할 수 있는 지를 확인해 보고자 합니다.
OCI Service Gateway
Service Gateway는 같은 리전내 오라클 서비스들을 접근할 수 있게 해주며, OCI Generative AI도 Service Gateway를 지원에서 지원합니다. 즉, 같은 리전내 Private 서브넷에 있는 VM에서는 Service Gateway를 통해 인터넷을 거치지 않고, 리전내 OCI Generative AI 서비스를 호출할 수 있습니다. VM에서 Service Gateway를 통해 타 리전의 오라클 서비스에 대한 접근은 기본적으로는 지원하지 않습니다.
-
Access to Oracle Services: Service Gateway
- The service gateway is regional and enables access only to supported Oracle services in the same region as the VCN.
-
Service Gateway: Supported Cloud Services in Oracle Services Network.
Generative AI 서비스의 Cross Region Call
Services that Call into the Generative AI Service에 아래와 같은 설명이 있습니다.
정리하면, Generative AI 서비스가 현재 일부 리전에서만 서비스되고 있지만, 일부 OCI 관리형 클라우드 서비스에서 Generative AI가 필요한 경우가 있어, 일부 관리형 OCI 서비스에서 Generative AI를 호출할 수 있게 cross-region 호출을 지원한다고 합니다. 이중 가까운 일본 리전으로 예를 들면, 도쿄리전에 있는 일부 OCI 관리형 클라우드 서비스가 오사카 OCI Generative AI 서비스를 호출하면, OCI Generative AI 단에서 자동으로 다른 리전인 오사카 리전의 OCI Generative AI로 돌려준다는 의미로 추측됩니다.
일부 OCI 관리형 클라우드 서비스만 쓰는 건지, 그러면 도쿄 ADB에서 오사카 Generative AI를 호출할 수 있게 해주는 지 확인하려 했지만, 개인적으로 원하는 결과를 얻지는 못했습니다.
- Currently, the Oracle Cloud Infrastructure (OCI) Generative AI Service is not offered in every OCI commercial region. See the column below titled “Destination Region:” for a list of OCI commercial regions offering the OCI Generative AI Service.
- There are OCI services which document (in the “Oracle PaaS and IaaS Universal Credits Service Descriptions”) that they make calls into the OCI Generative AI Service. For a given call into the OCI Generative AI Service, if the Calling Region and Destination Region are not the same, then a cross-region call will be made.
Area Calling Regions Destination Region:OCI region offering OCI Generative AI Service Japan KIX,NRTKIX
Private Service Access Endpoints
일부 오라클 서비스는 개별 서비스에서 사용자의 서브넷에 Private IP로 노출시키는 것을 지원하였지만, 지난 1월에 Private Service Access Endpoints Now Available 릴리즈 노트와 함께 PSA 엔드포인트 출시되어, 더 많은 서비스를 지원하기 시작했습니다. OCI Generative AI도 기존에는 Dedicated Cluster만 Private Endpoint를 지원했지만, PSA 출시 직후인 1월 말부터 On-Demand 모드의 Generative AI 또한 Private Endpoint를 지원하기 시작했습니다.
테스트 환경구성
-
VCN Wizard로 Create VCN with Internet Connectivity 형식으로 VCN을 테스트할 각 리전에 생성합니다.
Region VCN CIDR Block Public Subnet Private Subnet ap-osaka-1 10.0.0.0/16 10.0.0.0/24 10.0.1.0/24 ap-tokyo-1 10.1.0.0/16 10.1.0.0/24 10.1.1.0/24 ap-seoul-1 10.2.0.0/16 10.2.0.0/24 10.1.1.0/24 -
모든 Private Subnet Route Rules에서는 Service Gateway만 남깁니다.
- Service Gateway: 유지
- NAT Gateway: 삭제
Case #1. 같은 리전내 OCI Generative AI 서비스 호출 테스트
ComputeVM@PrivateSubnet@ap-osaka-1 -> OCI GenAI@ap-osaka-1
Service Gateway만을 사용
-
Python 코드를 작성합니다.
import oci # Instance Principal Signer signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner() # Service endpoint (unchanged) endpoint = "https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com" # Create client using signer generative_ai_inference_client = oci.generative_ai_inference.GenerativeAiInferenceClient( config={}, # Still required but can be an empty dict signer=signer, service_endpoint=endpoint, retry_strategy=oci.retry.NoneRetryStrategy(), timeout=(10, 240) ) inputs = ["hello"] embed_text_detail = oci.generative_ai_inference.models.EmbedTextDetails() embed_text_detail.serving_mode = oci.generative_ai_inference.models.OnDemandServingMode( model_id="cohere.embed-v4.0" ) embed_text_detail.inputs = inputs embed_text_detail.truncate = "NONE" embed_text_detail.compartment_id = "ocid1.compartment.oc1..aaaaa..." embed_text_response = generative_ai_inference_client.embed_text(embed_text_detail) # Print result print("**************************Embed Texts Result**************************") print(f"{str(embed_text_response.data.embeddings[0])[:100]}...]") -
호출 테스트
$ python call-genai.py **************************Embed Texts Result************************** [0.015515471, 0.0130208265, 0.0023121093, -0.010769562, 0.008396608, 0.010769562, -0.037723888, 0.01...]=> 같은 리전내 OCI Generative AI 서비스는 Service Gateway를 통해 잘 호출됩니다.
Case #2. Service Gateway로 리전 간 OCI Generative AI 호출 테스트
ComputeVM@PrivateSubnet@ap-tokyo-1 -> OCI GenAI@ap-osaka-1
Service Gateway만을 사용
일부 OCI 서비스의 경우 cross-region call이 된다고 하여, ap-tokyo-1에서 ap-osaka-1로 호출
-
ap-tokyo-1 리전에서 ap-osaka-1에 있는 GenAI를 호출 테스트합니다.
$ python call-genai.py ... Traceback (most recent call last): File "/home/opc/call-genai.py", line 28, in <module> embed_text_response = generative_ai_inference_client.embed_text(embed_text_detail) ... File "/usr/lib/python3.9/site-packages/oci/base_client.py", line 754, in request raise exceptions.RequestException(e) oci.exceptions.RequestException: (MaxRetryError("OCIConnectionPool(host='inference.generativeai.ap-osaka-1.oci.oraclecloud.com', port=443): Max retries exceeded with url: /20231130/actions/embedText (Caused by NewConnectionError('<oci.base_client.OCIConnection object at 0x7f9c55e76610>: Failed to establish a new connection: [Errno -2] Name or service not known'))"), 'Request Endpoint: POST https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com/20231130/actions/embedText See https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdk_troubleshooting.htm for help troubleshooting this error, or contact support and provide this full error message.') $ curl https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com/20231130/actions/embedText curl: (6) Could not resolve host: inference.generativeai.ap-osaka-1.oci.oraclecloud.com=> 호출 실패
=> Service Gateway는 같은 리전내 오라클 서비스에 대한 접근을 지원한다고 했으니, 도쿄리전에서 오사카의 서비스가 Service Gateway를 통해 호출되지 않는 것은 당연해 보입니다.
Case #3. Service Gateway로 리전 간 OCI Generative AI 호출 테스트, OCI 서비스 중 하나인 ADB에서 호출
ADB@PrivateSubnet@ap-tokyo-1 -> OCI GenAI@ap-osaka-1
ADB: ADB 26ai 버전, Private endpoint access only 옵션으로 Private Subnet에 생성
PaaS 서비스내에서 호출이 되는지 확인하기 위해 SQL상에서 호출
-
Tokyo 리전에 ADB 26ai 버전을 Private endpoint access only 타입으로 Private Subnet에 생성합니다.
-
유저 생성 및 권한 설정
CREATE USER vector IDENTIFIED BY <YOUR_PASSWORD> DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users; GRANT CONNECT, RESOURCE TO vector; -- OCI 서비스 접속을 위한 Credential 생성 권한 부여 GRANT DB_DEVELOPER_ROLE TO vector; GRANT EXECUTE ON DBMS_CLOUD TO vector; GRANT execute on DBMS_CLOUD_AI to vector; -
DB내에서 외부 Embedding 모델을 호출하기 위해서는 네트워크 접근 허용을 설정해야 합니다. 사용할 DB 유저(예, vector 유저)에게 허용합니다.
BEGIN DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE( host => '*', ace => xs$ace_type( privilege_list => xs$name_list('http'), principal_name => 'VECTOR', principal_type => xs_acl.ptype_db)); END; / -
vector 유저로 접속후 각 URL에 접근이 되는 지 테스트합니다.
-
외부 인터넷 접근 테스트
SQL> SELECT UTL_HTTP.REQUEST(url => 'https://www.naver.com/') FROM dual; <!doctype html> <html lang="ko" class="fzoom"> <head> <meta charset="utf-8"> ... ...=> Routing Table에서 NAT를 제외하고, Service Gateway만 남겼는데도 외부 인터넷이 접근됩니다.
=> Enhanced Security for Outbound Connections with Private Endpoints 문서를 보면, ADB는 자체 service VCN의 NAT를 기본 사용한다고 합니다. 그래서 ADB 인스턴스가 위치한 Private Subnet의 Routing Table이 아닌, ADB의 Service VCN의 NAT를 통해 외부 인터넷에 접근이 된 것입니다.
Note If the ROUTE_OUTBOUND_CONNECTIONS property is not set, all outgoing connections to the public internet are routed through the Network Address Translation (NAT) Gateway of the service VCN. In this case, if the target host is a public endpoint, these outgoing connections are not subject to the egress rules defined for the Autonomous AI Database instance's private endpoint VCN or Network Security Group (NSG).
-
-
ROUTE_OUTBOUND_CONNECTIONS는ENFORCE_PRIVATE_ENDPOINT,PRIVATE_ENDPOINT두 가지 설정이 있으며, DB내 AI 호출시 사용되는DBMS_CLOUD 패키지를 포함한 모든 아웃바운드 연결을 DB가 속한 VCN 또는 NSG의 설정을 따르도록 하려면,ENFORCE_PRIVATE_ENDPOINT로 설정해야 합니다. -
ADB ADMIN 유저로
ROUTE_OUTBOUND_CONNECTIONS을ENFORCE_PRIVATE_ENDPOINT로 설정합니다.ALTER DATABASE PROPERTY SET ROUTE_OUTBOUND_CONNECTIONS = 'ENFORCE_PRIVATE_ENDPOINT';SQL> SELECT * FROM DATABASE_PROPERTIES WHERE PROPERTY_NAME = 'ROUTE_OUTBOUND_CONNECTIONS'; PROPERTY_NAME PROPERTY_VALUE DESCRIPTION _____________________________ ___________________________ _____________________________________________________________________ ROUTE_OUTBOUND_CONNECTIONS ENFORCE_PRIVATE_ENDPOINT Force all outbound connections to be routed via Private Endpoint (PE) -
vector 유저로 접속후 각 URL에 접근이 되는 지 다시 테스트합니다.
-
외부 인터넷 접근 테스트
SQL> SELECT UTL_HTTP.REQUEST(url => 'https://www.naver.com/') FROM dual; Error starting at line : 1 in command - SELECT UTL_HTTP.REQUEST(url => 'https://www.naver.com/') FROM dual Error at Command Line : 1 Column : 8 Error report - SQL Error: ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1594 ORA-30699: network connection failed: connection timed out ...=> 이제 외부 인터넷이 접근이 안됩니다.
=> ADB가 속한 Private Subnet의 Routing Table에 NAT를 추가해 보면 다시 접근이 됩니다. 확인후 다시 NAT를 제거합니다.
-
OCI Gen AI 오사카 리전 접근 테스트
SQL> SELECT UTL_HTTP.REQUEST(url => 'https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com/20231130/actions/embedText') FROM dual; Error starting at line : 1 in command - SELECT UTL_HTTP.REQUEST(url => 'https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com/20231130/actions/embedText') FROM dual Error at Command Line : 1 Column : 8 Error report - SQL Error: ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1594 ORA-12545: Connect failed because target host or object does not exist ...=> UTL_HTTP.REQUEST로는 도쿄리전에서 오사카의 서비스가 Service Gateway를 통해 호출되지 않습니다.
-
-
DBMS_VECTOR 패키지를 이용해 호출해 봅니다.
-
Credential을 먼저 생성합니다.
-
private_key(예,~/.oci/oci_api_key.pem)를 한줄 텍스트로 변경합니다.awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' ~/.oci/oci_api_key.pem -
API Key 정보를 사용하여 OCI_CRED 이름으로 Credential을 생성합니다.
declare jo json_object_t; begin jo := json_object_t(); jo.put('user_ocid', 'ocid1.user.oc1..aaaaa.....'); jo.put('tenancy_ocid', 'ocid1.tenancy.oc1..aaaaa.....'); jo.put('compartment_ocid', 'ocid1.compartment.oc1..aaaaa.....'); jo.put('fingerprint', '31:8c:.....'); jo.put('private_key', '-----BEGIN RSA PRIVATE KEY-----\nMII...84M=\n-----END RSA PRIVATE KEY-----\nOCI_API_KEY\n'); dbms_vector.create_credential( credential_name => 'OCI_CRED', params => json(jo.to_string) ); end; /
-
-
오사카 리전 서비스를 호출해 봅니다.
var params clob; BEGIN :params := '{ "provider" : "ocigenai", "credential_name" : "OCI_CRED", "url" : "https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com/20231130/actions/chat", "model" : "meta.llama-3.3-70b-instruct" }'; END; / SELECT DBMS_VECTOR.UTL_TO_GENERATE_TEXT('who are you?', json(:params));Error at Line: 1, Column: 6 SQL Error: ORA-20000: ORA-30699: network connection failed: connection timed out ORA-06512: at "SYS.DBMS_VECTOR", line 8026 ORA-06512: at "C##CLOUD$SERVICE.DBMS_CLOUD$PDBCS_260111_0", line 2265 ORA-06512: at "C##CLOUD$SERVICE.DBMS_CLOUD$PDBCS_260111_0", line 15079 ORA-06512: at line 5=> OCI 서비스인 ADB임에도 DBMS_VECTOR로 도쿄리전에서 오사카 리전의 Generative AI가 호출되지 않는 것을 알 수 있습니다.
-
Case #4. OCI Generative AI의 Private Endpoint를 생성하고, Remote Peering을 통해 두 리전을 연결하는 방법
ADB@PrivateSubnet@ap-tokyo-1 -> OCI GenAI@ap-osaka-1
ADB: ADB 26ai 버전, Private endpoint access only 옵션으로 PrivateSubnet에 생성
OCI GenAI@ap-osaka-1를 Private Endpoint를 생성
OCI Generative AI의 Private Endpoint를 생성
-
OCI Console에서 GenAI 서비스가 있는 오사카리전에서 Generative AI > Private endpoints 로 이동합니다.
-
사용할 서브넷과 DNS Prefix를 입력하고,
Allow Usage In On-Demand Mode를 반드시 체크하여, Private endpoint를 생성합니다.
-
Case #1에서 사용한 ComputeVM@PrivateSubnet@ap-osaka-1에 다시 접속합니다.
-
VM과 OCI Generative AI의 Private Endpoint가 같은 서브넷이지만, Security Rule에 Generative AI를 접속하기 위한 Ingress Rule에서 443 포트를 개방합니다.
- Source CIDR: 10.0.0.0/16
- Destination Port Range: 443
-
코드가 호출하는 Endpoint를 Private Endpoint의 DNS FQDN으로 변경합니다.
# Service endpoint (unchanged) #endpoint = "https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com" endpoint = "https://genai.pe.inference.generativeai.ap-osaka-1.oci.oraclecloud.com" -
다시 호출해 보면 Private Endpoint로 잘 호출되는 것을 알 수 있습니다.
$ python call-genai.py **************************Embed Texts Result************************** [0.015515471, 0.0130208265, 0.0023121093, -0.010769562, 0.008396608, 0.010769562, -0.037723888, 0.01...]
Remote Peering 생성
-
Tokyo 리전과 Osaka 리전을 Remote Peering합니다.
- tokyo-drg를 생성
- tokyo-rpc 생성
- osaka-drg를 생성
- osaka-rpc 생성
- tokyo-rpc에서 osaka-rpc랑 연결
- tokyo-drg에 tokyo-vcn을, osaka-drg에 osaka-vcn을 attach 합니다.
-
Tokyo 리전
- Private Subnet의 라우팅에 다음을 추가
- Target Type: Dynamic Routing Gateways
- Destination CIDR Block: 10.0.0.0/16
- Target DRG: tokyo-drg
- Private Subnet의 라우팅에 다음을 추가
-
Osaka 리전
- Private Subnet의 라우팅에 다음을 추가
- Target Type: Dynamic Routing Gateways
- Destination CIDR Block: 10.1.0.0/16
- Target DRG: osaka-drg
- Security Rule에 Tokyo 리전에서 Generative AI를 접속하기 위한 Ingress Rule 추가
- Source CIDR: 10.1.0.0/16
- Destination Port Range: 443
- Private Subnet의 라우팅에 다음을 추가
DNS 설정
Private Endpoint의 FQDN이 Tokyo리전에 조회될 수 있도록 DNS 설정이 필요합니다. DNS Forwarding을 설정해도 되지만, 여기서 한 건이므로, 직접 입력합니다.
-
Tokyo 리전에서 DNS Management > Private Zone 에 새로운 Zone과 Record를 추가합니다.
- Zone Name:
pe.inference.generativeai.ap-osaka-1.oci.oraclecloud.com - Record
- Name:
genai - Type:
A - IP: 생성한 Private Endpoint의 IP
- Name:
- Zone Name:
-
약간이 시간이 지나고 Tokyo 리전의 VM에서 조회가 되는 지 확인합니다.
$ nslookup genai.pe.inference.generativeai.ap-osaka-1.oci.oraclecloud.com Server: 169.254.xxx.xxx Address: 169.254.xxx.xxx#53 Non-authoritative answer: Name: genai.pe.inference.generativeai.ap-osaka-1.oci.oraclecloud.com Address: 10.0.1.50
호출 테스트
-
Tokyo 리전의 VM에서 코드가 호출하는 Endpoint를 Private Endpoint의 DNS FQDN으로 변경합니다.
# Service endpoint (unchanged) #endpoint = "https://inference.generativeai.ap-osaka-1.oci.oraclecloud.com" endpoint = "https://genai.pe.inference.generativeai.ap-osaka-1.oci.oraclecloud.com" -
다시 호출해 보면 Private Endpoint로 잘 호출되는 것을 알 수 있습니다.
$ python call-genai.py **************************Embed Texts Result************************** [0.015515471, 0.0130208265, 0.0023121093, -0.010769562, 0.008396608, 0.010769562, -0.037723888, 0.01...] -
Case #3에서 실패한, Tykyo 리전에 있는 ADB에서 DBMS_VECTOR를 사용해 다시 오사카 리전 서비스를 호출해 봅니다. 이번에는 url을 Private Endpoint FQDN으로 변경하여 호출합니다.
var params clob; BEGIN :params := '{ "provider" : "ocigenai", "credential_name" : "OCI_CRED", "url" : "https://genai.pe.inference.generativeai.ap-osaka-1.oci.oraclecloud.com/20231130/actions/chat", "model" : "meta.llama-3.3-70b-instruct" }'; END; / SELECT DBMS_VECTOR.UTL_TO_GENERATE_TEXT('who are you?', json(:params));DBMS_VECTOR.UTL_TO_GENERATE_TEXT('WHOAREYOU?',JSON(:PARAMS)) ___________________________________________________________________________________ I'm an artificial intelligence model known as Llama. Llama stands for "Large Lan=> ADB임에도 DBMS_VECTOR로 도쿄리전에서 리모트 피어링되어 있는 오사카 리전의 Generative AI의 Private Endpoint의 FQDN으로 호출되는 것을 알 수 있습니다.
정리된 내용으로 Seoul 리전에서 Osaka 리전 GenAI를 프라이빗하게 호출하다면…
- Osaka 리전:
Allow Usage In On-Demand Mode를 반드시 체크하여 Generative AI의 Private Endpoint 생성 - Osaka 리전 VCN과 Seoul 리전 VCN간 Remote Peering 생성
- Seoul 리전: Generative AI의 Private Endpoint의 FQDN를 DNS 등록
- Seoul 리전: ADB를 Private endpoint access only 타입으로 생성
- Seoul 리전: ADB가 Private Subnet의 Routing Table 사용하도록 설정
- ROUTE_OUTBOUND_CONNECTIONS:
ENFORCE_PRIVATE_ENDPOINT
- ROUTE_OUTBOUND_CONNECTIONS:
- 위 설정으로 Seoul 리전 ADB에서 Osaka Generative AI를 호출하는 것을 확인하였습니다.
이 글은 개인으로서, 개인의 시간을 할애하여 작성된 글입니다. 글의 내용에 오류가 있을 수 있으며, 글 속의 의견은 개인적인 의견입니다.