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-0
및 mssql-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:2022-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:2022-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 인스턴스와 마케팅 팀에 대한 또 다른 인스턴스를 배포하려는 경우를 고려합니다. 다음 예제와 같이 sales
및 marketing
이라는 두 개의 네임스페이스를 만듭니다.
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:2022-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:2022-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:2022-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:2022-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
...