Summary

K3s 환경에서 PostgreSQL을 설치하는 과정을 정리했습니다.

애플리케이션 별로 PostgreSQL을 요구하는 경우가 있기 때문에 공동으로 사용할 수 있는 데이터베이스를 생성합니다.

yaml

PersistentVolumeClaim

PostgreSQL의 데이터를 저장하는 공간을 요청합니다.

postgres.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc           
  namespace: core-infra           
spec:
  accessModes:
    - ReadWriteOnce                # 하나의 노드에서 읽기/쓰기 가능
  storageClassName: local-path     # local-path 스토리지 클래스 사용
  resources:
    requests:
      storage: 50Gi

Service

파드의 네트워크와 관련한 설정입니다.

postgres.yaml
apiVersion: v1
kind: Service
metadata:
  name: postgres-svc
  namespace: core-infra
spec:
  type: ClusterIP                   # 클러스터 내부에서만 접근 가능한 서비스
  selector:
    app: postgresql
  ports:
    - protocol: TCP
      name: postgres
      port: 5432
      targetPort: 5432

StatefulSet

데이터베이스는 안정적인 파드의 운영이 중요하므로 StatefulSet으로 생성합니다.

postgres.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql
  namespace: core-infra
  labels:
    app: postgresql
spec:
  serviceName: "postgres-svc"
  replicas: 1
  selector:
    matchLabels:
      app: postgresql
  template:
    metadata:
      labels:
        app: postgresql
        dev.quenary.tugtainer.protected: "true"  # tugtainer 보호 라벨
    spec:
      containers:
        - name: postgresql
          image: postgres:17
          args:                    # PostgreSQL 성능 최적화 및 안정성 향상을 위한 커스텀 설정
            - "postgres"
            - "-c"
            - "shared_buffers=256MB"
            - "-c"
            - "effective_cache_size=1GB"
            - "-c"
            - "maintenance_work_mem=128MB"
            - "-c"
            - "checkpoint_completion_target=0.9"
            - "-c"
            - "wal_buffers=16MB"
            - "-c"
            - "default_statistics_target=100"
            - "-c"
            - "random_page_cost=1.1"
            - "-c"
            - "effective_io_concurrency=200"
            - "-c"
            - "work_mem=4MB"
            - "-c"
            - "min_wal_size=1GB"
            - "-c"
            - "max_wal_size=4GB"
            - "-c"
            - "max_worker_processes=4"
            - "-c"
            - "max_parallel_workers_per_gather=2"
            - "-c"
            - "max_parallel_workers=4"
            - "-c"
            - "max_parallel_maintenance_workers=2"
 
          env:    # 환경 변수 설정
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-secret
                  key: POSTGRES_PASSWORD
            - name: TZ
              value: "Asia/Seoul"
            - name: LANG
              value: "en_US.utf8"
            - name: PGDATA
              value: "/var/lib/postgresql/data/pgdata"
 
          ports:
            - containerPort: 5432
 
          readinessProbe:
            exec:
              command: ["pg_isready", "-U", "postgres", "-d", "postgres"]
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 10
            failureThreshold: 5
          livenessProbe:
            exec:
              command: ["pg_isready", "-U", "postgres", "-d", "postgres"]
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 10
            failureThreshold: 5
 
          resources:
            limits:
              cpu: "2.0"
              memory: "2Gi"
            requests:
              cpu: "1.0"
              memory: "1Gi"
 
          securityContext:
            allowPrivilegeEscalation: false
 
          volumeMounts:
            - name: postgres-data
              mountPath: /var/lib/postgresql/data
            - name: dshm
              mountPath: /dev/shm
 
      volumes:
        - name: postgres-data         # PVC 볼륨 마운트
          persistentVolumeClaim:
            claimName: postgres-pvc
        - name: dshm                  # PostgreSQL의 shared memory를 위한 emptyDir 볼륨
          emptyDir:
            medium: Memory
            sizeLimit: 256Mi
 

Tip

각 yaml은 하나의 파일 postgres.yaml로 관리합니다.

Installation

Secret 생성

Secret.env 파일과 같은 역할입니다. 비밀번호, API 키와 같이 보이면 안되는 값을 미리 지정해서 생성합니다.

kubectl create secret generic postgres-secret --from-literal=POSTGRES_PASSWORD=<postgres-password> -n <name-space>

Tip

PostgreSQL은 다른 서비스에서 DB를 사용해야할 수 있으므로 core-infra Namespace로 지정합니다.

postgres 생성

미리 만들어둔 postgres.yaml을 배포하여 DB를 구동합니다.

# postgres.yaml 배포
kubectl apply -f postgres.yaml
 
# Pod 실행 상태 확인
kubectl get pods -n core-infra -w

Success

PostgreSQL의 설치가 완료되었습니다.