다음을 통해 공유


StatefulSets를 사용하여 Kubernetes에 SQL Server Linux 컨테이너 배포

적용 대상: SQL Server - Linux

이 문서에는 StatefulSets를 사용하여 Kubernetes에서 SQL Server 컨테이너를 실행하기 위한 모범 사례와 지침이 포함됩니다. Kubernetes에서 Pod당 하나의 SQL Server 컨테이너(인스턴스)를 배포하는 것이 좋습니다. 따라서 Kubernetes 클러스터에 Pod당 하나의 SQL Server 인스턴스가 배포됩니다.

마찬가지로 배포 스크립트 권장 사항은 replicas 값을 1로 설정하여 하나의 SQL Server 인스턴스를 배포하는 것입니다. replicas 값으로 1보다 큰 숫자를 입력하면 많은 SQL Server 인스턴스 및 상호 관련된 이름이 표시됩니다. 예를 들어 아래 스크립트에서 replicas 값으로 숫자 2를 할당한 경우 각각 이름 mssql-0mssql-1을 사용하여 두 개의 SQL Server Pod를 배포합니다.

배포 스크립트당 하나의 SQL Server를 권장하는 또 다른 이유는 배포된 각 SQL Server 인스턴스에 대해 구성 값, 버전, 추적 플래그 및 기타 설정을 독립적으로 변경할 수 있도록 하기 위한 것입니다.

다음 예제에서 StatefulSet 워크로드 이름은 .spec.template.metadata.labels 값과 일치해야 합니다. 이 경우 mssql입니다. 자세한 내용은 StatefulSets를 참조하세요.

Important

SA_PASSWORD 환경 변수는 사용되지 않습니다. 대신 MSSQL_SA_PASSWORD를 사용하세요.

apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: mssql # name of the StatefulSet workload, the SQL Server instance name is derived from this. We suggest to keep this name same as the .spec.template.metadata.labels, .spec.selector.matchLabels and .spec.serviceName to avoid confusion.
spec:
 serviceName: "mssql" # serviceName is the name of the service that governs this StatefulSet. This service must exist before the StatefulSet, and is responsible for the network identity of the set.
 replicas: 1 # only one pod, with one SQL Server instance deployed.
 selector:
  matchLabels:
   app: mssql  # this has to be the same as .spec.template.metadata.labels
 template:
  metadata:
   labels:
    app: mssql # this has to be the same as .spec.selector.matchLabels, as documented [here](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/):
  spec:
   securityContext:
     fsGroup: 10001
   containers:
   - name: mssql # container name within the pod.
     image: mcr.microsoft.com/mssql/server:2019-latest
     ports:
     - containerPort: 1433
       name: tcpsql
     env:
     - name: ACCEPT_EULA
       value: "Y"
     - name: MSSQL_ENABLE_HADR
       value: "1"
     - name: MSSQL_AGENT_ENABLED
       value: "1"
     - name: MSSQL_SA_PASSWORD
       valueFrom:
         secretKeyRef:
          name: mssql
          key: MSSQL_SA_PASSWORD
     volumeMounts:
     - name: mssql
       mountPath: "/var/opt/mssql"
 volumeClaimTemplates:
   - metadata:
      name: mssql
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi

동일한 배포를 사용하여 SQL Server 인스턴스의 복제본을 둘 이상 배포하도록 선택하는 경우 해당 시나리오는 다음 섹션에서 설명합니다. 그러나 이 인스턴스는 별도의 독립 SQL Server 인스턴스이며 복제본이 아닙니다(SQL Server의 가용성 그룹 복제본과 다름).

워크로드 유형 선택

올바른 워크로드 배포 유형을 선택하는 것은 성능에 영향을 주지 않지만 StatefulSet은 ID 고정 요구 사항을 제공합니다.

StatefulSet 워크로드

SQL Server는 데이터베이스 애플리케이션이므로 대부분 StatefulSet 워크로드 유형으로 배포해야 합니다. StatefulSet로 워크로드를 배포하면 고유한 네트워크 식별, 영구 및 안정적인 스토리지 등의 기능을 제공하는 데 도움이 됩니다. 이 유형의 워크로드에 대한 내용은 Kubernetes 설명서를 참조하세요.

StatefulSet 워크로드와 동일한 배포 YAML 스크립트를 사용하여 두 개 이상의 SQL Server 컨테이너 복제본을 배포하는 경우 고려해야 할 중요한 매개 변수는 Pod 관리 정책(.spec.podManagementPolicy)입니다.

이 설정에는 다음 두 가지 값이 가능합니다.

  • OrderedReady: 기본값이며 배포 및 스케일링 보장에 설명된 대로 동작합니다.

  • 병렬: 다른 Pod가 생성될 때까지 기다리지 않고 Pod(이 경우 SQL Server Pod)를 만들고 시작할 대체 정책입니다. 마찬가지로 종료 중에 모든 Pod가 병렬로 삭제됩니다. 서로 독립적인 SQL Server 인스턴스를 배포하는 경우와 SQL Server 인스턴스를 시작하거나 삭제하는 순서를 따르지 않으려는 경우 이 옵션을 사용할 수 있습니다.

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mssql
    spec:
      serviceName: "mssql"
      replicas: 2 # two independent SQL Server instances to be deployed
      podManagementPolicy: Parallel
      selector:
        matchLabels:
          app: mssql
      template:
        metadata:
          labels:
            app: mssql
        spec:
          securityContext:
            fsGroup: 10001
          containers:
            - name: mssql
              image: mcr.microsoft.com/mssql/server:2019-latest
              ports:
                - containerPort: 1433
                  name: tcpsql
              env:
                - name: ACCEPT_EULA
                  value: "Y"
                - name: MSSQL_ENABLE_HADR
                  value: "1"
                - name: MSSQL_AGENT_ENABLED
                  value: "1"
                - name: MSSQL_SA_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      name: mssql
                      key: MSSQL_SA_PASSWORD
              volumeMounts:
                - name: mssql
                  mountPath: "/var/opt/mssql"
      volumeClaimTemplates:
        - metadata:
            name: mssql
          spec:
            accessModes:
              - ReadWriteOnce
            resources:
              requests:
                storage: 8Gi
    

Kubernetes에 배포된 SQL Server Pod는 서로 독립적이므로 Parallel은 일반적으로 podManagementPolicy에 사용되는 값입니다.

다음 샘플은 병렬 정책을 사용하여 Pod를 만든 직후의 kubectl get all에 대한 예제 출력입니다.

NAME          READY   STATUS              RESTARTS   AGE
pod/mssql-0   0/1     ContainerCreating   0          4s
pod/mssql-1   0/1     ContainerCreating   0          4s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   201.0.0.1    <none>        443/TCP   61d

NAME                     READY   AGE
statefulset.apps/mssql   1/1     4s

배포 워크로드

데이터 지속성이 중요하지 않은 경우와 같이 SQL Server 컨테이너를 상태 비저장 데이터베이스 애플리케이션으로 배포하려는 시나리오에서는 SQL Server에 배포 유형을 사용할 수 있습니다. 이와 같은 몇 가지 예제는 테스트/QA 또는 CI/CD에 해당합니다.

네임스페이스를 통한 격리

네임스페이스는 단일 Kubernetes 클러스터 내에서 리소스 그룹을 격리하는 메커니즘을 제공합니다. 네임스페이스 및 사용 시기에 대한 내용은 네임스페이스를 참조하세요.

SQL Server 관점에서 다른 리소스를 호스트하고 있는 Kubernetes 클러스터에서 SQL Server Pod를 실행하려는 경우 간편한 관리를 위해 자체 네임스페이스에서 SQL Server Pod를 실행해야 합니다. 예를 들어 동일한 Kubernetes 클러스터를 공유하는 부서가 여러 개 있고 영업 팀에 대한 SQL Server 인스턴스와 마케팅 팀에 대한 또 다른 인스턴스를 배포하려는 경우를 고려합니다. 다음 예제와 같이 salesmarketing이라는 두 개의 네임스페이스를 만듭니다.

kubectl create namespace sales
kubectl create namespace marketing

네임스페이스가 생성되었는지 확인하려면 kubectl get namespaces를 실행합니다. 그러면 다음 출력과 유사한 목록이 표시됩니다.

NAME              STATUS   AGE
default           Active   39d
kube-node-lease   Active   39d
kube-public       Active   39d
kube-system       Active   39d
marketing         Active   7s
sales             Active   26m

이제 다음 예제에 표시된 샘플 YAML을 사용하여 이러한 각 네임스페이스에 SQL Server 컨테이너를 배포할 수 있습니다. 배포 YAML에 추가된 namespace 메타데이터를 확인할 수 있습니다. 이 배포의 모든 컨테이너와 서비스가 sales 네임스페이스에 배포됩니다.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: azure-disk
provisioner: kubernetes.io/azure-disk
parameters:
  storageAccountType: Standard_LRS
  kind: Managed
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mssql-sales
  namespace: sales
  labels:
    app: mssql-sales
spec:
  serviceName: "mssql-sales"
  replicas: 1
  selector:
    matchLabels:
      app: mssql-sales
  template:
    metadata:
      labels:
        app: mssql-sales
    spec:
      securityContext:
        fsGroup: 10001
      containers:
        - name: mssql-sales
          image: mcr.microsoft.com/mssql/server:2019-latest
          ports:
            - containerPort: 1433
              name: tcpsql
          env:
            - name: ACCEPT_EULA
              value: "Y"
            - name: MSSQL_ENABLE_HADR
              value: "1"
            - name: MSSQL_AGENT_ENABLED
              value: "1"
            - name: MSSQL_SA_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mssql
                  key: MSSQL_SA_PASSWORD
          volumeMounts:
            - name: mssql
              mountPath: "/var/opt/mssql"
  volumeClaimTemplates:
    - metadata:
        name: mssql
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 8Gi
---
apiVersion: v1
kind: Service
metadata:
  name: mssql-sales-0
  namespace: sales
spec:
  type: LoadBalancer
  selector:
    statefulset.kubernetes.io/pod-name: mssql-sales-0
  ports:
    - protocol: TCP
      port: 1433
      targetPort: 1433
      name: tcpsql

리소스를 보기 위해 네임스페이스가 지정된 kubectl get all 명령을 실행하여 다음 리소스를 볼 수 있습니다.

kubectl get all -n sales
NAME                READY   STATUS    RESTARTS   AGE
pod/mssql-sales-0   1/1     Running   0          17m

NAME                    TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/mssql-sales-0   LoadBalancer   10.0.251.120   20.23.79.52   1433:32052/TCP   17m

NAME                           READY   AGE
statefulset.apps/mssql-sales   1/1     17m

네임스페이스는 네임스페이스 내에서 전체 리소스 만들기를 관리하기 위해 제한 범위 및/또는 리소스 할당량 정책을 사용하여 네임스페이스 내에서 만든 리소스 및 Pod를 제한하는 데 사용할 수도 있습니다.

Pod 서비스 품질 구성

단일 Kubernetes 클러스터에 여러 Pod를 배포할 때 Kubernetes 클러스터의 효율적인 실행을 보장하기 위해 리소스를 적절하게 공유해야 합니다. 특정 QoS(서비스 품질)가 할당되도록 Pod를 구성할 수 있습니다.

Kubernetes는 QoS 클래스를 사용하여 Pod 예약 및 제거에 대한 결정을 내립니다. 다양한 QoS 클래스에 대한 자세한 내용은 Pod에 대한 서비스 품질 구성을 참조하세요.

SQL Server 관점에서 프로덕션 기반 워크로드에 대해 QoS를 Guaranteed로 사용하여 SQL Server Pod를 배포하는 것이 좋습니다. SQL Server Pod에는 해당 Pod에 대해 보장된 QoS를 달성하기 위해 실행되는 SQL Server 컨테이너 인스턴스가 하나만 있다는 점을 고려하면 메모리 및 CPU 한도와 동일해야 하는 컨테이너에 대한 CPU 및 메모리 요청을 지정해야 합니다. 이렇게 하면 노드가 배포 중에 지정된 필수 리소스를 제공하고 커밋하며 SQL Server Pod에 대한 예측 가능한 성능을 제공합니다.

다음은 기본 네임스페이스에 하나의 SQL Server 컨테이너를 배포하는 샘플 배포 YAML이며, 리소스 요청이 지정되지 않았지만 보장된 서비스 품질 예제의 지침에 따라 한도가 지정되었기 때문에 다음 예제에 생성된 Pod에서 QoS가 Guaranteed로 설정된 것을 볼 수 있습니다. 리소스 요청을 지정하지 않으면 Kubernetes는 리소스 제한이 리소스 요청과 동일한 것으로 간주합니다.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
     name: azure-disk
provisioner: kubernetes.io/azure-disk
parameters:
  storageaccounttype: Standard_LRS
  kind: Managed
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: mssql
 labels:
  app: mssql
spec:
 serviceName: "mssql"
 replicas: 1
 selector:
  matchLabels:
   app: mssql
 template:
  metadata:
   labels:
    app: mssql
  spec:
   securityContext:
     fsGroup: 10001
   containers:
   - name: mssql
     command:
       - /bin/bash
       - -c
       - cp /var/opt/config/mssql.conf /var/opt/mssql/mssql.conf && /opt/mssql/bin/sqlservr
     image: mcr.microsoft.com/mssql/server:2019-latest
     resources:
      limits:
       memory: 2Gi
       cpu: '2'
     ports:
     - containerPort: 1433
     env:
     - name: ACCEPT_EULA
       value: "Y"
     - name: MSSQL_ENABLE_HADR
       value: "1"
     - name: MSSQL_SA_PASSWORD
       valueFrom:
         secretKeyRef:
          name: mssql
          key: MSSQL_SA_PASSWORD
     volumeMounts:
     - name: mssql
       mountPath: "/var/opt/mssql"
     - name: userdata
       mountPath: "/var/opt/mssql/userdata"
     - name: userlog
       mountPath: "/var/opt/mssql/userlog"
     - name: tempdb
       mountPath: "/var/opt/mssql/tempdb"
     - name: mssql-config-volume
       mountPath: "/var/opt/config"
   volumes:
     - name: mssql-config-volume
       configMap:
        name: mssql
 volumeClaimTemplates:
   - metadata:
      name: mssql
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi
   - metadata:
      name: userdata
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi
   - metadata:
      name: userlog
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi
   - metadata:
      name: tempdb
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi

kubectl describe pod mssql-0 명령을 실행하여 다음 코드 조각과 유사한 출력을 통해 QoS를 Guaranteed로 볼 수 있습니다.

...
QoS Class:                 Guaranteed
Node-Selectors:            <none>
Tolerations:               node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                           node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                           node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
...

성능 및 가용성이 높은 우선 순위가 아닌 비프로덕션 워크로드의 경우 QoS를 Burstable 또는 BestEffort로 설정하는 것이 좋을 수 있습니다.

버스트 가능 QoS 샘플

Burstable YAML 예제를 정의하려면 리소스 제한이 아닌 리소스 요청을 지정하거나 요청보다 높은 제한을 지정합니다. 다음 코드는 버스트 가능 워크로드를 정의하기 위해 이전 예제와는 다른 점만 표시합니다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: mssql
 labels:
  app: mssql
spec:
 serviceName: "mssql"
 replicas: 1
 selector:
  matchLabels:
   app: mssql
 template:
  metadata:
   labels:
    app: mssql
  spec:
   securityContext:
     fsGroup: 10001
   containers:
   - name: mssql
     command:
       - /bin/bash
       - -c
       - cp /var/opt/config/mssql.conf /var/opt/mssql/mssql.conf && /opt/mssql/bin/sqlservr
     image: mcr.microsoft.com/mssql/server:2019-latest
     resources:
      requests:
       memory: 2Gi
       cpu: '2'

kubectl describe pod mssql-0 명령을 실행하여 다음 코드 조각과 유사한 출력을 통해 QoS를 Burstable로 볼 수 있습니다.

...
QoS Class:                 Burstable
Node-Selectors:            <none>
Tolerations:               node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                           node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                           node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
...

최상의 작업 QoS 샘플

BestEffort YAML 예제를 정의하려면 리소스 요청 및 리소스 제한을 제거합니다. BestEffort의 QoS 클래스가 할당되는 Pod 만들기에 정의된 대로 최상의 작업 QoS로 마무리합니다. 이전과 같이 다음 코드는 최상의 작업 워크로드를 정의하기 위해 Guaranteed 예제와 다른 점만 표시합니다. 리소스 경합의 경우 가장 먼저 종료될 수 있으므로 이 옵션은 SQL Server Pod에 가장 권장되지 않는 옵션입니다. 테스트 및 QA 시나리오의 경우에도 SQL Server에 대한 버스트 가능 옵션을 사용하는 것이 좋습니다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mssql
  labels:
    app: mssql
spec:
  serviceName: "mssql"
  replicas: 1
  selector:
    matchLabels:
      app: mssql
  template:
    metadata:
      labels:
        app: mssql
    spec:
      securityContext:
        fsGroup: 10001
      containers:
        - name: mssql
          command:
            - /bin/bash
            - -c
            - cp /var/opt/config/mssql.conf /var/opt/mssql/mssql.conf && /opt/mssql/bin/sqlservr
          image: mcr.microsoft.com/mssql/server:2019-latest
          ports:
            - containerPort: 1433

kubectl describe pod mssql-0 명령을 실행하여 다음 코드 조각과 유사한 출력을 통해 QoS를 BestEffort로 볼 수 있습니다.

...
QoS Class:                 BestEffort
Node-Selectors:            <none>
Tolerations:               node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                           node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                           node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
...