OpenAPI에서 Kubernetes API Delphi 클라이언트

모든 Kubernetes 클러스터는 자신의 API를 스스로 설명하고, sgcOpenAPI는 그 설명을 Delphi에서 호출하는 Pascal 유닛으로 바꿔요. 이 페이지들에서 다루는 공개 사양 가운데 가장 크고, 소스 문서 선택이 실제로 결과를 바꾸는 유일한 사례이기도 해요. 그래서 이 페이지는 어느 엔드포인트에서 생성해야 하는지, 알려진 두 가지 한계가 무엇인지를 짚어요.

Kubernetes + sgcOpenAPI

아래 내용은 모두 Kubernetes 사양에 생성기를 실행하고 결과를 컴파일해서 측정한 값이에요. 추정치가 아니에요.

여기서 생성하세요

/openapi/v3 아래에 있는 그룹별 OpenAPI 3 문서를 하나씩 쓰세요. 올바른 클라이언트가 나오는 경로예요.

여기서는 하지 마세요

통합된 /openapi/v2 문서예요. Swagger 2.0이고 변환과 생성이 되기는 하지만 두 가지가 잘못 나와요. 둘 다 아래에 설명해 뒀어요.

인증

-a 2로 생성하고 Authentication.Token.BearerToken을 설정하면 ServiceAccount 토큰이 Authorization: Bearer로 전송돼요.

기본 URL

Kubernetes는 서버 호스트를 선언하지 않아요. 생성 시점에 -u https://cluster:6443을 넘기거나 런타임에 SetBaseURL을 호출하세요.

/openapi/v3는 문서가 아니라 인덱스예요

가장 먼저 짚어야 할 부분이에요. 클러스터는 OpenAPI 3 파일 하나를 제공하지 않아요. /openapi/v3는 그룹 경로 목록을 반환하고, 각 그룹과 버전은 저마다의 URL에 있는 별개의 문서예요.

# API 그룹과 버전마다 문서 하나, 기본 클러스터에 65개
> sgcOpenAPI.exe -i "https://10.0.0.1:6443/openapi/v3/api/v1" \
      -o "k8s_core_v1.pas" -a 2 -u "https://10.0.0.1:6443"

File successfully created k8s_core_v1.pas

> sgcOpenAPI.exe -i "https://10.0.0.1:6443/openapi/v3/apis/apps/v1" \
      -o "k8s_apps_v1.pas" -a 2 -u "https://10.0.0.1:6443"

File successfully created k8s_apps_v1.pas

그렇게 생성하면 core 그룹은 경로 113개, 메서드 248개, 모델 클래스 293개로 42,705줄짜리 유닛이 되고, apps 그룹은 경로 38개, 메서드 77개, 모델 클래스 180개로 17,061줄이 돼요. 둘 다 RAD Studio 12의 Win32에서 라이브러리 경로에 sgcOpenAPI Source 폴더 말고는 아무것도 없이 깨끗하게 컴파일돼요. 그룹마다 유닛 하나를 두는 편이 거대한 유닛 하나보다 다루기 쉽고, 실제로 호출하는 그룹만 생성하면 돼요.

같은 문서들은 Kubernetes 저장소의 api/openapi-spec/v3/ 아래에도 게시되어 있어요. 그래서 실행 중인 클러스터 대신 체크인된 파일에서 생성해 결과를 버전 관리에 둘 수 있어요.

네임스페이스의 파드 나열하기

Kubernetes는 오퍼레이션 id를 이미 유효한 식별자로 쓰기 때문에, 생성된 메서드는 사양의 이름을 그대로 유지해요.

uses
  k8s_core_v1;   // 방금 생성한 유닛

procedure TfrmK8s.btnPodsClick(Sender: TObject);
var
  oResponse: TsgcOpenAPI_listCoreV1NamespacedPod_Response;
  oPod: TsgcOpenAPI_io_k8s_api_core_v1_Pod_Class;
begin
  GetOpenAPIClient.Authentication.Token.BearerToken := vToken;
  GetOpenAPIClient.SetBaseURL('https://10.0.0.1:6443');

  // aNamespace, aPretty, 그다음 선언 순서대로 쿼리 매개변수
  oResponse := GetOpenAPIClient.listCoreV1NamespacedPod('production',
    '', oapiBoolNull, '', '', 'app=api,tier=backend');
  try
    if oResponse.IsSuccessful then
      for oPod in oResponse.Successful.Items do
        memoLog.Lines.Add(Format('%-30s %s %s',
          [oPod.Metadata.Name, oPod.Status.Phase, oPod.Status.HostIP]))
    else
      memoLog.Lines.Add(IntToStr(oResponse.ResponseCode) + ' ' +
        oResponse.ResponseError);
  finally
    oResponse.Free;
  end;
end;

모델 클래스는 Kubernetes 이름을 그대로 담고 있어요. 그래서 파드는 Metadata, Spec, Status를 가진 TsgcOpenAPI_io_k8s_api_core_v1_Pod_Class이고, 목록은 타입이 지정된 Items를 가진 TsgcOpenAPI_io_k8s_api_core_v1_PodList_Class예요. Kubernetes가 선택 항목으로 선언한 불리언 쿼리 매개변수는 TsgcOpenAPIBoolean이 되고, 그 oapiBoolNull 값은 매개변수를 false로 보내는 대신 URL에서 아예 빼라는 뜻이에요.

디플로이먼트 스케일링하기

Kubernetes가 요청 본문을 이름 있는 스키마로 설명한 경우, 그리고 대개 그렇게 하는데, 생성된 메서드는 문자열이 아니라 타입이 지정된 클래스를 받아요.

uses
  k8s_apps_v1;

var
  oRead: TsgcOpenAPI_readAppsV1NamespacedDeploymentScale_Response;
  oWrite: TsgcOpenAPI_replaceAppsV1NamespacedDeploymentScale_Response;
begin
  oRead := GetOpenAPIClient.readAppsV1NamespacedDeploymentScale(
    'api', 'production');
  try
    if not oRead.IsSuccessful then
      raise Exception.Create(oRead.ResponseError);

    oRead.Successful.Spec.Replicas := 5;

    oWrite := GetOpenAPIClient.replaceAppsV1NamespacedDeploymentScale(
      'api', 'production', oRead.Successful);
    try
      memoLog.Lines.Add(IntToStr(oWrite.ResponseCode));
    finally
      oWrite.Free;
    end;
  finally
    oRead.Free;
  end;
end;

Kubernetes 전체를 놓고 보면 비율이 거의 반반이에요. 요청 본문의 절반 정도는 TsgcOpenAPI_io_k8s_api_autoscaling_v1_Scale_Class 같은 타입이 지정된 클래스로 들어오고, 나머지 절반 정도는 문자열로 들어와요. 문서가 스키마에 이름을 붙였는지에 따라 갈려요.

생성된 유닛에 들어 있는 것

유닛은 가리킨 문서를 그대로 반영해요. 그래서 적용 범위는 생성한 그룹과 버전 그 자체예요.

워크로드

apis/apps/v1은 Deployment, StatefulSet, DaemonSet, ReplicaSet을 다뤄요. apis/batch/v1은 Job과 CronJob을, api/v1은 Pod와 ReplicationController를 다뤄요.

서비스와 네트워킹

api/v1은 Service, Endpoints, ConfigMap, Secret을 다뤄요. apis/networking.k8s.io/v1은 Ingress와 NetworkPolicy를, apis/discovery.k8s.io/v1은 EndpointSlice를 다뤄요.

스토리지, RBAC, 정책

apis/storage.k8s.io/v1, apis/rbac.authorization.k8s.io/v1, apis/policy/v1, apis/admissionregistration.k8s.io/v1이 각각 별개의 문서이고 각각 별개의 유닛이 돼요.

커스텀 리소스

CRD가 설치된 클러스터는 자체 그룹 경로에서 이를 제공해요. 그래서 /openapi/v3의 인덱스가 기본 제공 그룹과 나란히 이들을 나열하고, 생성 방식도 같아요.

모든 모델이 클래스로

ObjectMeta, PodSpec, PodStatus, Container, condition 타입들, list 타입들이 모두 들어 있어요. core 그룹 하나만으로 293개가 나와요.

사양에 담긴 문서

Kubernetes 필드 설명이 각 메서드와 속성 위에 Pascal 주석으로 들어와요. 유닛이 긴 이유의 상당 부분이 여기에 있어요.

실제로 돌려 보고 찾아낸 것

이 가운데 두 가지는 통합된 Swagger 2.0 문서에서만 나타나고, 이 페이지가 그룹별 생성을 권하는 이유예요.

v2 문서에서는 경로 수준 매개변수가 사라져요

Kubernetes는 namespacepretty를 path item에 한 번 선언하고 $ref로 참조해요. /openapi/v2에서 생성하면 이 둘이 메서드까지 오지 못해서, listCoreV1NamespacedPodaNamespace 인자 없이 나오고 URL에는 {namespace} 자리표시자가 그대로 남아요. 같은 그룹의 /openapi/v3 문서에서 생성하면 인자가 제대로 들어와요. v3 문서를 쓰세요.

CRD 그룹은 컴파일되지 않아요

apis/apiextensions.k8s.io/v1JSONSchemaProps.enum을 타입을 전혀 선언하지 않은 스키마의 배열로 설명해요. 그래서 생성기가 TArray<>를 내보내고 컴파일러가 이를 거부해요. 유닛에서 두 줄에 해당해요. 그 그룹을 건너뛰거나, 통합 문서를 생성하면서 그 14개 오퍼레이션을 -x-p에도 함께 넘기세요. 그러면 클래스가 제거되고 유닛 전체가 빌드돼요.

통합 문서는 어마어마해요

경로 602개, 메서드 1,202개에 약 197,000줄, 13 MB짜리 유닛이에요. 읽기와 생성은 1초도 걸리지 않지만 그 크기의 파일에서는 IDE 편집기가 느려져요. 그룹별 유닛은 그 일부에 지나지 않아요. core 그룹이 42,705줄, apps가 17,061줄이에요.

클러스터 CA는 직접 신뢰해야 해요

대부분의 클러스터는 자체 서명 CA를 쓰기 때문에, 무엇을 신뢰할지 알려 주기 전까지는 TLS 핸드셰이크가 실패해요. 생성된 클라이언트는 OnSSLVerifyPeer, OnSSLGetHandler, OnSSLAfterCreateHandler를 제공하고, kubeconfig의 클러스터 CA 번들을 여기에 설치하면 돼요.

watch는 열거 가능한 대상이 아니에요

watch=truefollow=true가 붙은 컨테이너 로그는 오래 유지되는 청크 응답이에요. 생성된 메서드는 응답이 끝나면 반환하는 평범한 요청이라서, 실시간 watch는 생성된 클라이언트가 스트리밍해 주는 것이 아니라 TsgcHTTP1Client 위에 직접 만드는 것이에요.

바인딩된 ServiceAccount 토큰은 만료돼요

Kubernetes 1.21부터 유효 기간이 정해져 있어요. 클러스터 안에서는 /var/run/secrets/kubernetes.io/serviceaccount/token을 다시 읽고, 밖에서는 TokenRequest API를 호출한 다음 Authentication.Token.BearerToken을 다시 할당하세요. 클라이언트는 마지막으로 준 값을 그대로 들고 있어요.

블로그에서

OpenAPI Delphi 파서

리더가 실제 사양을 다루는 방식, 그리고 처리할 수 없는 것을 Warnings에 어떻게 남기는지.

게시물 읽기 →

OpenAPI 클라이언트 + 파서

생성된 클라이언트와 그 바탕이 되는 리더를 소개하는 동반 게시물.

게시물 읽기 →

sgcOpenAPI 2026.6

현재 버전의 릴리스 노트예요. 생성기 옵션과 리더 변경 사항이 담겨 있어요.

게시물 읽기 →
최고의 가성비: All-Access모든 eSeGeCe 제품과 프리미엄 지원이 포함되어 연 €1,059부터 이용할 수 있어요.
All-Access 가격 보기

오늘 Delphi에서 Kubernetes를 구동하세요

sgcOpenAPI는 리더, 코드 생성기, OpenAPI 서버, 그리고 Amazon, Azure, Google, Microsoft용 미리 빌드된 SDK를 함께 제공해요. 하나의 제품, 세 가지 등급이고, 기능이 아니라 좌석 수로 가격이 매겨져요.