이 페이지에서는 Google Distributed Cloud (GDC) 오프라인 어플라이언스 Kubernetes 클러스터 내에서 스테이트풀 워크로드를 만들고 관리하는 방법을 설명합니다. 스테이트풀(Stateful) 워크로드를 사용하면 영구 스토리지를 사용하여 애플리케이션 배포를 확장할 수 있습니다. 영구 스토리지는 워크로드의 예약 위치와 관계없이 애플리케이션에 일관된 ID와 안정적인 호스트 이름을 제공합니다.
이 페이지는 조직의 애플리케이션 워크로드를 만드는 애플리케이션 운영자 그룹 내 개발자를 위한 페이지입니다.
시작하기 전에
사전 구성된 베어메탈 Kubernetes 클러스터에 대해 명령어를 실행하려면 다음 리소스가 있어야 합니다.
Kubernetes 클러스터 이름을 찾거나 플랫폼 관리자에게 클러스터 이름을 문의합니다.
Kubernetes 클러스터의 kubeconfig 파일이 없는 경우 로그인 및 생성합니다.
Kubernetes 클러스터의 kubeconfig 경로를 사용하여 이 안내의 CLUSTER_KUBECONFIG를 바꿉니다.
스테이트풀 워크로드를 만드는 데 필요한 권한을 얻으려면 조직 IAM 관리자에게 프로젝트 네임스페이스의 네임스페이스 관리자 역할 (namespace-admin)을 부여해 달라고 요청하세요.
StatefulSet 리소스 만들기
StatefulSet 매니페스트를 작성하고 kubectl apply를 실행하여 리소스를 만들어 StatefulSet 객체를 만듭니다. 클라이언트가 StatefulSet 리소스의 포드로 요청을 보내는 안정적인 방법을 제공하려면 Service 객체도 만들어야 합니다.
kubectl apply 명령어는 매니페스트 파일을 사용하여 클러스터에서 리소스를 생성, 업데이트, 삭제합니다. 이는 객체 구성의 선언적 메서드입니다. 이 메서드는 변경사항을 객체 구성 파일에 다시 병합하지 않고 실시간 객체에 대한 쓰기를 보관합니다.
metadata: name 필드로 표시된 nginx이라는 Service 객체가 생성됩니다. Service 객체는 labels.app: nginx 및 selector.app: nginx로 표시된 nginx이라는 앱을 대상으로 합니다. Service 객체는 포트 80을 노출하고 이름을 web으로 지정합니다. 이 Service 객체는 네트워크 도메인을 제어하고 인터넷 트래픽을 StatefulSet 객체로 배포된 컨테이너화된 애플리케이션으로 라우팅합니다.
replicas: 3 필드에 설정된 대로 복제된 Pod 객체가 3개인 StatefulSet(이름: web)가 생성됩니다.
.spec.template 섹션에서 설정된 Pod 템플릿은 Pod 객체에 app: nginx 라벨이 지정되었음을 나타냅니다.
.template.spec 섹션에서 설정한 Pod 사양은 StatefulSet의 포드가 버전 1.23에서 nginx 이미지를 실행하는 nginx 컨테이너 한 개를 실행함을 나타냅니다.
StatefulSet는 프로비저닝된 스토리지가 각각 1GB인 web-www-0, web-www-1, web-www-2라는 세 개의 PersistentVolumeClaim 객체를 프로비저닝합니다.
생성된 후 StatefulSet는 선택된 수의 Pod 객체가 항상 실행되고 사용 가능한 상태로 유지되도록 합니다. StatefulSet은 오류가 발생했거나 해당 노드에서 축출된 Pod 객체를 자동으로 교체하고, 새 Pod 객체를 StatefulSet 객체의 Pod 사양에 정의된 스토리지 리소스, 리소스 요청 및 제한, 기타 구성과 연결합니다.
StatefulSet 리소스에서 영구 스토리지 요청
영구 스토리지는 필요 시 기본 볼륨이 생성되도록 동적으로 프로비저닝할 수 있습니다. 애플리케이션은 PersistentVolumeClaim 객체를 사용하여 영구 스토리지를 요청할 수 있습니다.
일반적으로 Pod 객체를 만드는 것 외에도 PersistentVolumeClaim 객체를 만들어야 합니다. 하지만 StatefulSet 객체에는 PersistentVolumeClaim 객체를 생성하는 volumeClaimTemplates 배열이 포함됩니다. 각 StatefulSet 복제본은 자체 PersistentVolumeClaim 객체를 가져옵니다.
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["이해하기 어려움","hardToUnderstand","thumb-down"],["잘못된 정보 또는 샘플 코드","incorrectInformationOrSampleCode","thumb-down"],["필요한 정보/샘플이 없음","missingTheInformationSamplesINeed","thumb-down"],["번역 문제","translationIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-09-04(UTC)"],[[["\u003cp\u003e\u003ccode\u003eStatefulSet\u003c/code\u003e objects are used to manage stateful applications that require persistent storage, ensuring each \u003ccode\u003ePod\u003c/code\u003e has a unique identity and stable hostname.\u003c/p\u003e\n"],["\u003cp\u003eCreating a \u003ccode\u003eStatefulSet\u003c/code\u003e involves defining a \u003ccode\u003ePod\u003c/code\u003e template, which specifies the containers, volumes, labels, and selectors for the \u003ccode\u003ePod\u003c/code\u003e objects within the \u003ccode\u003eStatefulSet\u003c/code\u003e.\u003c/p\u003e\n"],["\u003cp\u003eTo ensure clients can stably send requests to the \u003ccode\u003eStatefulSet\u003c/code\u003e pods, a corresponding \u003ccode\u003eService\u003c/code\u003e object must also be created and referenced within the \u003ccode\u003eStatefulSet\u003c/code\u003e definition.\u003c/p\u003e\n"],["\u003cp\u003e\u003ccode\u003eStatefulSet\u003c/code\u003e objects use \u003ccode\u003evolumeClaimTemplates\u003c/code\u003e to automatically create \u003ccode\u003ePersistentVolumeClaim\u003c/code\u003e objects, providing each replica with its own persistent storage volume, dynamically provisioned when needed.\u003c/p\u003e\n"],["\u003cp\u003eThe \u003ccode\u003eStatefulSet\u003c/code\u003e ensures the desired number of \u003ccode\u003ePod\u003c/code\u003e objects are running, replacing any that fail and maintaining their configurations.\u003c/p\u003e\n"]]],[],null,["# Create stateful workloads\n\nThis page explains how to create and manage stateful workloads within a\nGoogle Distributed Cloud (GDC) air-gapped appliance Kubernetes cluster. Stateful workloads let you\nscale your application deployment with persistent storage. Persistent storage\nprovides your application with consistent identities and stable hostnames,\nregardless of where its workloads are scheduled.\n\nThis page is for developers within the application operator group, who are\nresponsible for creating application workloads for their organization.\n\nBefore you begin\n----------------\n\nTo run commands against the pre-configured bare metal Kubernetes cluster, make sure you have the\nfollowing resources:\n\n1. Locate the Kubernetes cluster name, or ask your Platform\n Administrator what the cluster name is.\n\n2. [Sign in and generate](/distributed-cloud/hosted/docs/latest/appliance/application/ao-user/iam/sign-in#kubernetes-cluster-kubeconfig) the\n kubeconfig file for the Kubernetes cluster if you don't have one.\n\n3. Use the kubeconfig path of the Kubernetes cluster to replace\n \u003cvar translate=\"no\"\u003eCLUSTER_KUBECONFIG\u003c/var\u003e in these instructions.\n\nTo get the required permissions to create stateful workloads, ask your\nOrganization IAM Admin to grant you the Namespace Admin role (`namespace-admin`)\nin your project namespace.\n\nCreate a `StatefulSet` resource\n-------------------------------\n\nCreate a `StatefulSet` object by writing a `StatefulSet` manifest and\nrunning `kubectl apply` to create the resource. To provide a stable way for\nclients to send requests to the pods of your `StatefulSet` resource, you must\nalso create a `Service` object.\n\nThe `kubectl apply` command uses manifest files to create, update, and delete\nresources in your cluster. This is a declarative method of object\nconfiguration. This method retains writes made to live objects without merging\nthe changes back into the object configuration files.\n\nTo create a `StatefulSet` and `Service` resource, run: \n\n kubectl --kubeconfig \u003cvar translate=\"no\"\u003eCLUSTER_KUBECONFIG\u003c/var\u003e -n \u003cvar translate=\"no\"\u003eNAMESPACE\u003c/var\u003e \\\n apply -f - \u003c\u003cEOF\n apiVersion: v1\n kind: Service\n metadata:\n name: \u003cvar translate=\"no\"\u003eSERVICE_NAME\u003c/var\u003e\n labels:\n app: \u003cvar translate=\"no\"\u003eAPP_NAME\u003c/var\u003e\n spec:\n ports:\n - port: 80\n name: web\n clusterIP: None\n selector:\n app: \u003cvar translate=\"no\"\u003eAPP_NAME\u003c/var\u003e\n ---\n apiVersion: apps/v1\n kind: StatefulSet\n metadata:\n name: \u003cvar translate=\"no\"\u003eSTATEFULSET_NAME\u003c/var\u003e\n spec:\n selector:\n matchLabels:\n app: \u003cvar translate=\"no\"\u003eAPP_LABEL_NAME\u003c/var\u003e\n serviceName: \"\u003cvar translate=\"no\"\u003eSERVICE_NAME\u003c/var\u003e\"\n replicas: \u003cvar translate=\"no\"\u003eNUMBER_OF_REPLICAS\u003c/var\u003e\n template:\n metadata:\n labels:\n app: \u003cvar translate=\"no\"\u003eAPP_LABEL_NAME\u003c/var\u003e\n spec:\n terminationGracePeriodSeconds: 10\n containers:\n - name: \u003cvar translate=\"no\"\u003eCONTAINER_NAME\u003c/var\u003e\n image: \u003cvar translate=\"no\"\u003eCONTAINER_IMAGE\u003c/var\u003e\n resources:\n requests:\n nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1\n limits:\n nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1\n ports:\n - containerPort: 80\n name: web\n volumeMounts:\n - name: www\n mountPath: \u003cvar translate=\"no\"\u003eCONTAINER_STORAGE_VOLUME_PATH\u003c/var\u003e\n volumeClaimTemplates:\n - metadata:\n name: www\n spec:\n accessModes: [ \"ReadWriteOnce\" ]\n resources:\n requests:\n storage: 1Gi\n EOF\n\nReplace the following:\n\n- \u003cvar translate=\"no\"\u003eCLUSTER_KUBECONFIG\u003c/var\u003e: the kubeconfig file for\n the Kubernetes cluster to which you're deploying container workloads.\n\n- \u003cvar translate=\"no\"\u003eNAMESPACE\u003c/var\u003e: the project namespace in which to deploy the container workloads.\n\n- \u003cvar translate=\"no\"\u003eSERVICE_NAME\u003c/var\u003e: the name of the `Service` object.\n Ensure the `StatefulSet` object sets the `Service` object in its `serviceName`\n as well.\n\n- \u003cvar translate=\"no\"\u003eAPP_NAME\u003c/var\u003e: the name of the application to run within\n the deployment.\n\n- \u003cvar translate=\"no\"\u003eAPP_LABEL_NAME\u003c/var\u003e: the label selector that determines\n which pods belong to the `StatefulSet` object.\n\n- \u003cvar translate=\"no\"\u003eSTATEFULSET_NAME\u003c/var\u003e: the name of the `StatefulSet`\n object.\n\n- \u003cvar translate=\"no\"\u003eNUMBER_OF_REPLICAS\u003c/var\u003e: the number of replicated `Pod`\n objects that the deployment manages.\n\n- \u003cvar translate=\"no\"\u003eCONTAINER_NAME\u003c/var\u003e: the name of the container.\n\n- \u003cvar translate=\"no\"\u003eCONTAINER_IMAGE\u003c/var\u003e: the name of the container image. You\n must include the container registry path and version of the image, such as\n \u003cvar class=\"readonly\" translate=\"no\"\u003eREGISTRY_PATH\u003c/var\u003e`/nginx:1.23`.\n\n- \u003cvar translate=\"no\"\u003eCONTAINER_STORAGE_VOLUME_PATH\u003c/var\u003e: the path within the\n container at which a storage volume is mounted.\n\n| **Note:** You can also use `kubectl apply -f `\u003cvar translate=\"no\"\u003eDIRECTORY\u003c/var\u003e to create new objects defined by configuration files stored in a directory.\n\nAs an example, the following `StatefulSet` object and corresponding `Service`\nobject create stateful container workloads: \n\n apiVersion: v1\n kind: Service\n metadata:\n name: nginx\n labels:\n app: nginx\n spec:\n ports:\n - port: 80\n name: web\n clusterIP: None\n selector:\n app: nginx\n ---\n apiVersion: apps/v1\n kind: StatefulSet\n metadata:\n name: web\n spec:\n selector:\n matchLabels:\n app: nginx\n serviceName: \"nginx\"\n replicas: 3\n template:\n metadata:\n labels:\n app: nginx\n spec:\n terminationGracePeriodSeconds: 10\n containers:\n - name: nginx\n image: \u003cvar class=\"readonly\" translate=\"no\"\u003e\u003cspan class=\"devsite-syntax-l devsite-syntax-l-Scalar devsite-syntax-l-Scalar-Plain\"\u003eREGISTRY_PATH\u003c/span\u003e\u003c/var\u003e/nginx:1.23\n resources:\n requests:\n nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1\n limits:\n nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1\n ports:\n - containerPort: 80\n name: web\n volumeMounts:\n - name: www\n mountPath: /usr/share/nginx/html\n volumeClaimTemplates:\n - metadata:\n name: www\n spec:\n accessModes: [ \"ReadWriteOnce\" ]\n resources:\n requests:\n storage: 1Gi\n\n| **Important:** If you're deploying GPU workloads to your containers, see [Manage GPU container workloads](/distributed-cloud/hosted/docs/latest/appliance/application/ao-user/containers/deploy-gpu-container-workloads) for more information.\n\nIn this example:\n\n- A `Service` object named `nginx` is created, indicated by the `metadata: name` field. The `Service` object targets an app called `nginx`, indicated by `labels.app: nginx` and `selector.app: nginx`. The `Service` object exposes port 80 and names it `web`. This `Service` object controls the network domain and routes internet traffic to the containerized application deployed by the `StatefulSet` object.\n- A `StatefulSet` named `web` is created with three replicated `Pod` objects, as set by the field `replicas: 3`.\n- The `Pod` template, set by the section `.spec.template`, indicates that its `Pod` objects are labelled `app: nginx`.\n- The `Pod` specification, set by the section `.template.spec`, indicates that the pods of the `StatefulSet` run one container, `nginx`, which runs the `nginx` image at version `1.23`.\n- The `Pod` specification uses the web port opened by the `Service` object.\n- The `.template.spec.volumeMounts` section specifies a `mountPath` field, which is named `www`. The `mountPath` is the path in the container where a storage volume is mounted.\n- The `StatefulSet` provisions three `PersistentVolumeClaim` objects, named `web-www-0`, `web-www-1`, and `web-www-2`, with 1GB of provisioned storage each.\n\nAfter it's created, the `StatefulSet` ensures that the chosen number of `Pod`\nobjects are running and available at all times. The `StatefulSet` automatically\nreplaces `Pod` objects that fail or are evicted from their nodes, and associates\nnew `Pod` objects with the storage resources, resource requests and limits, and\nother configurations defined in the `Pod` specification of the `StatefulSet`\nobject.\n\nRequest persistent storage in a `StatefulSet` resource\n------------------------------------------------------\n\nPersistent storage can be dynamically provisioned so that the underlying volumes\nare created on demand. Applications can request persistent storage with a\n`PersistentVolumeClaim` object.\n\nTypically, you must create `PersistentVolumeClaim` objects in addition to\ncreating the `Pod` object. However, `StatefulSet` objects include a\n`volumeClaimTemplates` array which generates the `PersistentVolumeClaim`\nobjects. Each `StatefulSet` replica gets its own `PersistentVolumeClaim` object.\n\nFor more information, see\n[Configure container storage](/distributed-cloud/hosted/docs/latest/appliance/application/ao-user/containers/access-multi-writer-storage)."]]