본문 바로가기
WIKI 기술 지식 베이스

이미지 볼륨 확장

원문 보기 위키 갱신

이미지 볼륨 확장 (Image Volume Extensions)

CloudNativePG는 Kubernetes ImageVolume 기능과 함께, CloudNativePG 프로젝트가 기여한 PostgreSQL 18에 도입된 extension_control_path GUC를 사용해 Pod 시작 시 Cluster에 PostgreSQL 확장을 동적으로 로드하는 것을 지원해요.

이 기능은 PostgreSQL 확장을 OCI 호환 컨테이너 이미지로 패키징해, 실행 중인 pod 안의 지정된 파일 시스템 경로에 읽기 전용·불변 볼륨으로 마운트할 수 있게 해줘요.

CREATE EXTENSION 명령으로 데이터베이스 레벨 설치가 필요한 확장에 대해서는, Database 리소스의 선언적 확장 관리를 사용해 모든 PostgreSQL 데이터베이스에서 일관되고 자동화된 설정을 보장할 수 있어요.

출처: 문서

본문

공식 확장 이미지와 카탈로그 (Official Extension Images and Catalogs)

CloudNativePG 커뮤니티는 postgres-extensions-containers 프로젝트)의 일부로 pgvector와 PostGIS를 포함한 확장 컨테이너 이미지 세트를 유지 관리해요. 이 이미지들은 공식 PostgreSQL minimal 이미지 위에 구축돼요.

:::info 이 문서는 제3자가 자체 이미지와 카탈로그를 빌드하는 데 필요한 기술 사양을 제공하지만, 아래 지침은 우리 공식 확장 이미지와 카탈로그의 배포와 사용에 특화되어 있어요. :::

이점 (Benefits)

확장 배포를 PostgreSQL operand 이미지에서 분리함으로써, 이 기능은 컨테이너에서 PostgreSQL을 실행하는 데 대한 중요한 장벽을 제거해요. 빌드 시점에 확장을 임베딩할 필요를 없애고, 공식 minimal operand 이미지를 사용하면서 Cluster 정의에 필요한 확장만 동적으로 추가할 수 있게 해줘요—직접 또는 이미지 카탈로그를 통해.

이 접근 방식은 핵심 데이터베이스 컨테이너에 운영에 필요한 필수 바이너리만 포함되도록 보장해 데이터베이스 클러스터의 공격 표면을 크게 줄여요. 불필요한 확장, 라이브러리, 빌드 시 의존성을 제외하면 잠재적 공격 진입점을 최소화하고 취약점 관리를 단순화해요. 이 아키텍처는 데이터 워크로드에 불변·최소 기본 이미지를 유지해 공급망 보안을 강화하고 운영 오버헤드를 줄여요.

:::important 확장 이미지는 문서화된 사양에 따라 빌드되어야 해요. :::

요구사항 (Requirements)

CloudNativePG에서 이미지 볼륨 확장을 사용하려면 다음이 필요해요:

  • PostgreSQL 18 이상: extension_control_path 지원에 필요
  • Kubernetes 1.35 이상: ImageVolume 기능이 기본으로 활성화됨. Kubernetes 1.33과 1.34 사용자는 ImageVolume 기능 게이트를 수동으로 활성화해야 해요.
  • ImageVolume 지원이 있는 컨테이너 런타임:
    • containerd v2.1.0 이상, 또는
    • CRI-O v1.31 이상
  • CloudNativePG 호환 확장 컨테이너 이미지, 다음을 보장해야 함:
    • Cluster 리소스의 PostgreSQL 메이저 버전과 일치
    • Cluster 리소스의 호환 운영체제 배포판
    • Cluster 리소스의 CPU 아키텍처와 일치

어떻게 동작하나요 (How it works)

확장 이미지는 .spec.postgresql.extensions 스탠자를 통해 새 Cluster 또는 기존 Cluster 리소스에 추가할 수 있어요.

:::important 실행 중인 Cluster에 새 확장을 추가하면, CloudNativePG가 자동으로 롤링 업데이트를 트리거해 각 pod에 새 이미지 볼륨을 연결해요. 프로덕션에 새 확장을 추가하기 전에, PostgreSQL 클러스터를 비정상 상태로 만들 수 있는 구성 문제를 방지하기 위해 스테이징 환경에서 철저히 테스트했는지 확인하세요. :::

:::info 필드 레벨 세부 사항은 ExtensionConfiguration에 대한 API 레퍼런스를 참조하세요. :::

구성 소스와 우선순위 (Configuration Source and Precedence)

extensions 스탠자는 각각 클러스터 내에서 고유해야 하는 name이 필요한 항목 목록을 받아들여요.

:::important name은 소문자 영숫자 문자, 밑줄(_) 또는 하이픈(-)으로 구성되어야 하고 영숫자 문자로 시작·끝나야 해요. 길이는 59자로 제한되며, 이는 CloudNativePG가 확장의 Kubernetes 볼륨 이름을 파생할 때 추가하는 프리픽스를 위한 공간을 남겨요(RFC 1123의 63자 한도에 맞춤). :::

각 항목은 컨테이너 이미지의 구성을 정의하고 PostgreSQL이 확장을 찾아 로드하는 데 필요한 옵션을 지정해요:

  • 이미지 카탈로그 경유: 클러스터가 현재 PostgreSQL 메이저 버전에 대한 확장을 정의하는 ImageCatalog를 참조하면, 그 정의들이 기본 구성으로 작동해요. 이렇게 하면 카탈로그가 image.reference를 중앙에서 관리하고, 클러스터는 이름으로 확장을 활성화하기만 하면 돼요.

  • 직접 정의: 클러스터가 이미지 카탈로그를 사용하지 않으면, image.reference 필드가 필수이며 확장 이미지에 대한 유효한 컨테이너 레지스트리 경로를 명시적으로 가리켜야 해요. image 스탠자는 Kubernetes ImageVolume API를 따라요.

"convention over configuration" 패러다임을 따라, CloudNativePG는 완전한 유연성을 제공해요: 카탈로그에서 상속된 image.reference를 포함한 어떤 값이든 Cluster 정의에서 선택적으로 오버라이드해 특정 로컬 요구사항을 충족할 수 있어요.

마운트와 PostgreSQL 구성 (Mounting and PostgreSQL Configuration)

각 확장은 pod 안의 /extensions/<EXTENSION_NAME>에 읽기 전용 볼륨으로 마운트돼요.

기본적으로 CloudNativePG는 다음을 설정해 관련 GUC를 자동으로 관리해요:

  • extension_control_path를 /extensions/<EXTENSION_NAME>/share로 설정해, PostgreSQL이 /extensions/<EXTENSION_NAME>/share/extension 안의 어떤 확장 제어 파일이든 찾을 수 있게 함
  • dynamic_library_path를 /extensions/<EXTENSION_NAME>/lib로 설정

:::note 밑줄이 포함된 확장 이름(예: pg_ivm)은 RFC 1123 DNS 레이블 요구사항을 준수하기 위해 Kubernetes 볼륨 이름에서 하이픈(예: pg-ivm)을 사용하도록 변환돼요. 세탁(sanitization) 후 동일해지는 확장 이름(예: pg_ivm과 pg-ivm은 둘 다 pg-ivm으로 세탁됨)은 사용하지 마세요. webhook 검증이 이러한 충돌을 방지해요. :::

이 값들은 extensions 목록에 정의된 순서대로 추가되어, PostgreSQL 안에서 결정적인 경로 해석을 보장해요. 이렇게 하면 pod 안에서 수동 구성을 요구하지 않고 PostgreSQL이 확장을 발견·로드할 수 있어요.

커스텀 이미지 레이아웃에 맞게 이 경로를 수동으로 조정할 수 있지만, 공식 CloudNativePG 카탈로그는 각 확장에 대해 올바른 값으로 이 옵션들을 미리 구성해 기본으로 바로 동작하도록 보장해요.

:::important 확장 이미지에 공유 라이브러리가 포함된 경우, operand 이미지와 동일한 PostgreSQL 메이저 버전, 운영체제 배포판, CPU 아키텍처로 컴파일되어야 해요. 공식 CloudNativePG 카탈로그를 사용하면 이 호환성이 자동으로 보장돼요: 카탈로그는 클러스터의 특정 환경과 일치하도록 설계되어, 라이브러리나 아키텍처 불일치로 인한 런타임 문제를 방지해요. :::

데이터베이스에 설치 (Installation in a Database)

선언적 데이터베이스 관리를 활용해 표준 PostgreSQL CREATE EXTENSION 메커니즘을 지원하는 확장의 최종 활성화를 자동화할 수 있어요.

확장 이미지가 마운트되고 GUC가 구성되면, 확장은 PostgreSQL 인스턴스에 사용 가능하지만 특정 데이터베이스 안에서는 아직 활성화되지 않아요. 설치하려면 Database 리소스를 정의하세요. 아래 예시는 공식 postgres-extensions-containers 프로젝트의 구현 표준을 따르는 pgvector를 사용해요:

apiVersion: postgresql.cnpg.io/v1
kind: Database
metadata:
  name: cluster-example-app
spec:
  name: app
  owner: app
  cluster:
    name: cluster-example
  extensions:
    - name: vector
      version: "<VERSION>"

CloudNativePG는 대상 데이터베이스 안에서 CREATE EXTENSION IF NOT EXISTS vector를 실행해 이 리소스를 자동으로 리컨실해요. 이렇게 하면 원하는 상태가 유지되고 모든 인스턴스에 일관되게 적용되도록 보장해요.

:::note 때로 모듈이라고 불리는 일부 PostgreSQL 컴포넌트는 CREATE EXTENSION 메커니즘을 사용하지 않아요. 이들은 보통 서버 시작 시 shared_preload_libraries로 로드해야 하는 공유 라이브러리로 구성돼요. 이미지 카탈로그를 사용해 이러한 바이너리 배포를 단순화하더라도, 메모리에 로드되도록 Cluster 정의의 shared_preload_libraries 옵션에 라이브러리 이름을 수동으로 추가해야 해요. :::

Postgres 클러스터에 확장 추가 (Adding an Extension to a Postgres Cluster)

앞서 예고했듯이, CloudNativePG는 확장 이미지를 정의하는 두 가지 방법을 제공해요. 둘 다 Pod 레벨에서 같은 결과를 얻지만, 일관되고 프로덕션 준비된 공급망을 유지하려면 이미지 카탈로그 사용이 권장되는 접근 방식이에요.

이미지 카탈로그 경유 (Via an Image Catalog, 권장)

:::info 이미지 카탈로그의 확장 컨테이너 이미지 지원은 CloudNativePG 1.29에서 도입됐어요. :::

커뮤니티가 제공하는 공식 카탈로그 같은 확장을 다루는 이미지 카탈로그를 사용하면, 특정 컨테이너 이미지 reference와 필수 파일 시스템 경로 같은 복잡한 구성 세부 사항이 중앙에서 관리돼요.

Cluster 정의는 이름으로 확장에 "옵트인"하기만 하면 되므로 깔끔하고 선언적으로 유지돼요. 연산자는 카탈로그 정의에 기반해 이미지와 필수 PostgreSQL 설정의 해석을 자동으로 처리해요.

카탈로그에서 pgvector 같은 확장을 활성화하려면 다음 발췌처럼 클러스터의 extensions 목록에 추가하세요:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  # ... <snip>
  imageCatalogRef:
    apiGroup: postgresql.cnpg.io
    kind: ClusterImageCatalog
    name: postgresql-minimal-trixie
    major: 18

  postgresql:
    extensions:
      - name: pgvector # Resolves all details, including the image reference, from the catalog
      # ... <snip>

이 방법은 확장 이미지가 같은 카탈로그 항목에 정의된 PostgreSQL operand 이미지와 항상 호환되도록 보장해요.

클러스터에서 직접 (Directly in the Cluster)

:::info Cluster 리소스에서 확장을 직접 정의하는 것은 원래 방식이며, CloudNativePG 1.29 이전 버전에서는 유일한 옵션이에요. 또한 현재 카탈로그에 없는 확장을 사용해야 하거나 커스텀 이미지를 테스트할 때 유용해요. :::

카탈로그 없이 Cluster 리소스 안에서 직접 확장을 정의할 수 있어요. 이 경우 이미지 reference를 명시적으로 제공해야 해요.

다음 예시는 공식 컨테이너 이미지를 명시적으로 가리켜 pgvector를 추가하는 방법을 보여줘요:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  # ... <snip>
  postgresql:
    extensions:
      - name: pgvector
        image:
          reference: ghcr.io/cloudnative-pg/pgvector:<TAG>

:::tip Cluster에서 직접 제공한 구성이 우선한다는 점을 기억하세요. 카탈로그를 참조하면서도 Cluster 스탠자에 같은 확장 이름을 정의하면, Cluster의 설정이 카탈로그의 설정을 덮어써요. ExtensionConfiguration의 모든 필드는 완전한 유연성을 위해 Cluster 레벨에서 오버라이드할 수 있지만, name 필드는 예외예요. :::

:::warning name은 고유 식별자 역할을 해요. 이를 변경하면 카탈로그의 기존 항목을 오버라이드하는 것이 아니라 새 확장 항목을 정의하게 돼요. :::

확장 상태 확인 (Verifying Extension Status)

확장은 이미지 카탈로그와 직접 클러스터 정의 모두에서 소싱될 수 있으므로, CloudNativePG는 Cluster 상태에 구성의 "해석된(resolved)" 뷰를 제공해요. 이는 연산자가 pod를 프로비저닝하는 데 사용하는 최종·실효 상태예요.

status.pgDataImageInfo.extensions 필드를 검사해 상속이나 오버라이드 결과를 볼 수 있어요:

# ... <snip>
status:
  # ... <snip>
  pgDataImageInfo:
    image: # registry path for your PostgreSQL image
    majorVersion: 18
    extensions:
    - name: foo
      image:
        reference: # registry path for your `foo` extension image
    - name: bar
      image:
        reference: # registry path for your `bar` extension image
    # ... <snip>

이 섹션은 특히 다음에 유용해요:

  • 해석 검증: Cluster에서 이름으로 요청된 확장이 관련 카탈로그에서 image.reference를 올바르게 가져왔는지 확인
  • 오버라이드 확인: 특정 이미지 버전 같은 클러스터 레벨 오버라이드가 카탈로그의 기본값을 성공적으로 대체했는지 검증
  • 트러블슈팅: pod가 롤링 업데이트를 거치기 전에 모든 원하는 확장이 연산자에 의해 인식되는지 보장

PostgreSQL 클러스터에서 확장 제거 (Removing an Extension from a PostgreSQL Cluster)

확장 제거는 인프라와 데이터베이스 메타데이터를 모두 정리하는 두 단계 과정을 포함해요.

"library not found" 오류를 피하려면 먼저 데이터베이스에서 확장을 제거해야 해요. 선언적 관리를 사용한다면 확장에 ensure: absent를 설정해 Database 리소스를 갱신하세요:

spec:
  # ... <snip>
  extensions:
    - name: pgvector
      ensure: absent
    # ... <snip>

이는 CloudNativePG가 데이터베이스 안에서 DROP EXTENSION을 실행하도록 트리거해요.

확장이 shared_preload_libraries에 추가되었다면 Cluster 구성에서도 제거해야 해요.

그런 다음 Cluster 리소스의 .spec.postgresql.extensions 목록에서 확장 항목을 제거하세요. 연산자는 ImageVolume을 분리하고 관련 GUC 경로를 갱신하는 롤링 업데이트를 수행해요.

고급 주제 (Advanced Topics)

어떤 경우에는 기본 예상 구조가 확장 이미지에 충분하지 않을 수 있어요, 특히:

  • 확장이 추가 시스템 라이브러리를 요구할 때
  • 여러 확장이 같은 이미지에 번들될 때
  • 이미지가 커스텀 디렉터리 구조를 사용할 때
  • 확장이 제대로 동작하기 위해 외부 바이너리를 요구할 때
  • 확장이 특정 환경 변수 설정을 요구할 때

"convention over configuration" 패러다임을 따라, CloudNativePG는 다음 필드를 통해 각 확장 이미지의 구성을 세밀하게 제어할 수 있게 해줘요:

  • extension_control_path: PostgreSQL의 extension_control_path에 추가할 컨테이너 이미지 내 상대 경로 목록, 확장 제어 파일을 찾을 수 있게 함
  • dynamic_library_path: PostgreSQL의 dynamic_library_path에 추가할 컨테이너 이미지 내 상대 경로 목록, 확장의 공유 라이브러리 파일을 찾을 수 있게 함
  • ld_library_path: Postgres 프로세스의 LD_LIBRARY_PATH 환경 변수에 추가할 컨테이너 이미지 내 상대 경로 목록, 런타임에 필수 시스템 라이브러리를 찾을 수 있게 함
  • bin_path: Postgres 프로세스의 PATH 환경 변수에 추가할 컨테이너 이미지 내 상대 경로 목록, 런타임에 바이너리를 찾을 수 있게 함
  • env: Postgres 프로세스 안의 환경 변수로 설정할 name과 value 쌍 목록

이 유연성은 명확성과 예측 가능성을 유지하면서 복잡하거나 비표준적인 확장 이미지를 지원할 수 있게 해줘요.

커스텀 경로 설정 (Setting Custom Paths)

확장 이미지가 라이브러리와 제어 파일에 기본 lib·share 디렉터리를 사용하지 않으면, extension_control_path와 dynamic_library_path를 명시적으로 설정해 기본값을 오버라이드할 수 있어요.

예를 들어:

spec:
  # ... <snip>
  postgresql:
    extensions:
      - name: my-extension
        extension_control_path:
          - my/share/path
        dynamic_library_path:
          - my/lib/path
        image:
          reference: # registry path for your extension image
      # ... <snip>
    # ... <snip>
  # ... <snip>

CloudNativePG는 PostgreSQL을 다음과 같이 구성해요:

  • /extensions/my-extension/my/share/path를 extension_control_path에 추가
  • /extensions/my-extension/my/lib/path를 dynamic_library_path에 추가

이렇게 하면 비표준 레이아웃에서도 PostgreSQL이 확장의 제어 파일과 공유 라이브러리를 올바르게 발견할 수 있어요.

다중 확장 이미지 (Multi-extension Images)

같은 컨테이너 이미지에 여러 확장을 포함하고, 각 확장의 파일이 고유의 하위 디렉터리에 있는 구조를 채택해야 할 수도 있어요.

예를 들어 PostGIS와 pgRouting을 각각 고유 하위 디렉터리에 두고 단일 이미지에 패키징하려면:

# ...
spec:
  # ... <snip>
  postgresql:
    extensions:
      - name: geospatial
        extension_control_path:
          - postgis/share
          - pgrouting/share
        dynamic_library_path:
          - postgis/lib
          - pgrouting/lib
        # ... <snip>
        image:
          reference: # registry path for your geospatial image
      # ... <snip>
    # ... <snip>
  # ... <snip>

시스템 라이브러리 포함 (Including System Libraries)

PostGIS 같은 일부 확장은 기본 PostgreSQL 이미지에 없을 수 있는 시스템 라이브러리를 요구해요. 이러한 요구를 지원하려면 필수 라이브러리를 확장 컨테이너 이미지 안에 패키징하고 ld_library_path 필드를 사용해 PostgreSQL에 제공할 수 있어요.

예를 들어 확장 이미지에 필수 라이브러리가 있는 system 디렉터리가 포함된 경우:

# ...
spec:
  # ... <snip>
  postgresql:
    extensions:
      - name: postgis
        # ... <snip>
        ld_library_path:
          - system
        image:
          reference: # registry path for your PostGIS image
      # ... <snip>
    # ... <snip>
  # ... <snip>

CloudNativePG는 LD_LIBRARY_PATH 환경 변수에 /extensions/postgis/system을 포함하도록 설정해, PostgreSQL이 런타임에 이러한 시스템 라이브러리를 찾아 로드할 수 있게 해줘요.

:::important ld_library_path는 PostgreSQL 프로세스가 시작될 때 설정되어야 하므로, 이 값을 변경하려면 새 값이 적용되도록 클러스터 재시작이 필요해요. CloudNativePG는 현재 이 재시작을 자동으로 트리거하지 않아요. ld_library_path를 수정한 후 클러스터를 수동으로 재시작(예: cnpg restart 사용)해야 해요. :::

외부 바이너리 포함 (Including external binaries)

일부 확장은 확장 자체와 상호작용하는 데 필요한 몇 가지 바이너리를 제공해야 할 수 있어요. 이러한 요구를 지원하려면 필수 바이너리를 확장 컨테이너 이미지 안에 패키징하고 bin_path 필드를 사용해 PostgreSQL에 제공할 수 있어요.

예를 들어 확장 이미지에 필수 바이너리가 있는 bin 디렉터리가 포함된 경우:

# ...
spec:
  # ... <snip>
  postgresql:
    extensions:
      - name: my-extension
        # ... <snip>
        bin_path:
          - bin
        image:
          reference: # registry path for your extension image
      # ... <snip>
    # ... <snip>
  # ... <snip>

CloudNativePG는 Postgres 프로세스의 PATH 환경 변수에 /extensions/my-extension/bin을 추가해, PostgreSQL이 런타임에 이러한 바이너리를 찾을 수 있게 해줘요.

:::warning bin_path는 PostgreSQL 프로세스가 시작될 때 설정되어야 하므로, 이 값을 변경하려면 새 값이 적용되도록 클러스터 재시작이 필요해요. CloudNativePG는 현재 이 재시작을 자동으로 트리거하지 않아요. bin_path를 수정한 후 클러스터를 수동으로 재시작(예: cnpg restart 사용)해야 해요. :::

확장용 환경 변수 (Environment variables for extensions)

특정 확장은 제대로 동작하기 위해 PostgreSQL 프로세스 안에 특정 환경 변수를 설정해야 해요. 확장 구성의 env 필드를 사용해 이러한 변수를 정의할 수 있어요.

다음 예시는 정적 변수(FOO)와 플레이스홀더를 사용하는 변수(BAR)를 설정하는 방법을 보여줘요:

# ...
spec:
  # ... <snip>
  postgresql:
    # ... <snip>
    extensions:
      - name: my-extension
        image:
          reference: "ghcr.io/org/my-extension:latest"
        env:
          - name: FOO
            value: "static_value"
          - name: BAR
            value: "${image_root}/lib"
      # ... <snip>
# ...
동적 플레이스홀더 확장 (Dynamic Placeholder Expansion)

value 필드는 확장 환경에 기반한 동적 구성을 가능하게 하는 플레이스홀더 확장을 지원해요. 현재 지원되는 플레이스홀더는 다음과 같아요:

플레이스홀더 설명
${image_root} 확장 볼륨의 절대 마운트 경로로 해석됨 (예: /extensions/my-extension)

${image_root} 플레이스홀더는 확장 이미지 안의 애플리케이션이나 공유 라이브러리가 자체 마운트 볼륨 안의 특정 하위 디렉터리나 파일을 가리키는 환경 변수를 필요로 할 때 특히 유용해요.

위 예시에서 확장이 /extensions/my-extension에 마운트되면 변수 BAR는 /extensions/my-extension/lib로 해석되어, 연산자가 선택한 특정 마운트 경로와 무관하게 라이브러리가 의존성을 찾을 수 있게 해줘요.

:::tip 인식되지 않는 플레이스홀더(예: ${typo})는 접수(admission) 시점에 거부돼요. 값에 리터럴 ${...}가 필요하면 달러 기호를 두 번 써서 이스케이프하세요: $${...}. 예를 들어 $${not_expanded} 값은 리터럴 문자열 ${not_expanded}를 생성해요. :::

우선순위와 충돌 해결 (Precedence and Conflict Resolution)

PostgreSQL 프로세스의 환경 변수는 여러 곳에서 정의될 수 있어요. 같은 변수 이름이 둘 이상의 위치에 나타나면 다음 우선순위가 적용돼요(마지막이 가장 높은 우선순위):

  1. spec.env / spec.envFrom: 클러스터 레벨에서 정의된 변수는 Kubernetes가 컨테이너 환경에 주입하며 베이스 역할을 해요.
  2. 확장 env: 각 확장의 env 필드에 정의된 변수는 같은 이름의 클러스터 레벨 변수를 오버라이드해요.
  3. 확장 순서: 여러 확장이 같은 변수를 정의하면, extensions 배열에서 마지막에 나열된 확장이 우선해요.

CloudNativePG는 확장 환경 변수가 이전 확장이 이미 설정한 값을 덮어쓸 때 인스턴스 매니저 로그에 경고를 내보내, 잠재적 충돌 진단을 돕습니다.

:::important 예약 변수: 연산자 용도로 예약된 환경 변수(PG 또는 CNPG_로 시작하는 이름, 그리고 POD_NAME, NAMESPACE, CLUSTER_NAME)와 전용 필드로 관리되는 변수(bin_path를 통한 PATH, ld_library_path를 통한 LD_LIBRARY_PATH)는 env 필드로 설정할 수 없으며 접수 시점에 거부돼요. :::

:::warning 수동 재시작 필요: 환경 변수는 PostgreSQL 프로세스가 시작될 때 주입되므로, env 섹션의 어떤 변경에도 클러스터 재시작이 필요해요. CloudNativePG는 이러한 변경에 대한 롤아웃을 자동으로 트리거하지 않아요. 매니페스트에서 env 필드를 갱신한 후, 새 값이 적용되도록 클러스터를 수동으로 재시작(예: kubectl cnpg restart 사용)해야 해요. :::

이미지 사양 (Image Specifications)

CloudNativePG용 표준 확장 컨테이너 이미지에는 루트에 두 개의 필수 디렉터리가 포함돼요:

  • /share/: 확장 제어 파일(예: <EXTENSION>.control)과 해당 SQL 파일이 있는 extension 하위 디렉터리 포함
  • /lib/: 확장의 공유 라이브러리(예: <EXTENSION>.so)와 필수 기타 라이브러리 포함

이 구조를 따르면 확장이 CloudNativePG 안에서 PostgreSQL에 의해 수동 구성 없이 자동으로 발견되고 사용 가능하도록 보장돼요.

:::important PostgreSQL 확장 개발자와 제3자 제공자에게 이 레이아웃을 따르는 OCI 호환 확장 이미지를 게시할 것을 권장해요. 실용적인 구현 세부 사항은 공식 CloudNativePG 확장 이미지를 빌드하기 위한 레퍼런스 역할을 하는 postgres-extensions-containers 프로젝트를 검토할 것을 권장해요.

이상적으로 확장 이미지는:

  • 특정 운영체제 배포판과 CPU 아키텍처 집합을 대상으로 해야 함
  • 특정 PostgreSQL 메이저 버전에 묶여 있어야 함
  • 클러스터에서 사용되는 PostgreSQL operand 이미지와의 일관성, 보안, 호환성을 보장하기 위해 배포판의 네이티브 패키징 시스템(예: .deb 또는 .rpm 패키지)으로 빌드되어야 함 :::

주의사항 (Caveats)

현재 확장 이미지를 추가·제거·갱신하면 PostgreSQL pod가 재시작돼요. 이 동작은 Kubernetes에서 이미지 볼륨(image volumes)이 동작하는 방식에서 상속된 것이에요.

확장 업데이트를 수행하기 전에 다음을 확인했는지 보장하세요:

  • 스테이징 환경에서 업데이트 과정을 철저히 테스트
  • 확장 이미지가 현재 설치된 버전과 대상 버전 사이에 필요한 업그레이드 경로를 포함하는지 검증
  • 관련 Database 리소스 정의의 확장 version 필드를 이미지의 새 버전과 일치하도록 갱신

이 단계들은 확장 업데이트 중 PostgreSQL 클러스터의 다운타임이나 데이터 불일치를 방지하는 데 도움을 줘요.

더 알아보기 (Learn more)