๐Ÿ’พ ํŒŒ๋“œ๊ฐ€ ์ฃฝ์–ด๋„ ๋ฐ์ดํ„ฐ๋Š” ์‚ด์•„๋‚จ๋Š”๋‹ค – PV/PVC์™€ MySQL StatefulSet

Deployment๋กœ ๋งŒ๋“  ํŒŒ๋“œ๋Š” ์ฃฝ์œผ๋ฉด ์ƒˆ๋กœ ํƒœ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ๊ทธ ์•ˆ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋„ ๊ฐ™์ด ์‚ฌ๋ผ์ง„๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค. MySQL ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ Deployment๋กœ ์˜ฌ๋ฆฌ๋ฉด ํŒŒ๋“œ๊ฐ€ ์žฌ์‹œ์ž‘๋  ๋•Œ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด PersistentVolume(PV) ๊ณผ PersistentVolumeClaim(PVC), ๊ทธ๋ฆฌ๊ณ  StatefulSet์ž…๋‹ˆ๋‹ค.


๐Ÿงฉ ๊ฐœ๋… ์ •๋ฆฌ โ€” ์„ธ ๊ฐ€์ง€ ์šฉ์–ด ํ•œ ๋ฒˆ์—

๊ฐœ๋…์„ค๋ช…๋น„์œ 
PV์‹ค์ œ ์Šคํ† ๋ฆฌ์ง€ ๊ณต๊ฐ„์ฐฝ๊ณ  ์ž์ฒด
PVCPV๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” ์š”์ฒญ์„œ์ฐฝ๊ณ  ์ž„๋Œ€ ๊ณ„์•ฝ์„œ
StorageClassPVC ์š”์ฒญ ์‹œ PV๋ฅผ ์ž๋™ ์ƒ์„ฑํ•˜๋Š” ๊ด€๋ฆฌ์ž์ฐฝ๊ณ  ํšŒ์‚ฌ
StatefulSetํŒŒ๋“œ์— ๊ณ ์œ  ์ด๋ฆ„๊ณผ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ๋ถ€์—ฌ๊ณ ์ • ์ž๋ฆฌ๊ฐ€ ์žˆ๋Š” ์ง์›

๐Ÿ› ๏ธ ๊ตฌ์„ฑ ๊ณผ์ •

Step 1: StorageClass ์„ค์น˜

ํด๋ผ์šฐ๋“œ๊ฐ€ ์•„๋‹Œ ๋กœ์ปฌ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ๋Š” ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์ž๋™์œผ๋กœ ํ”„๋กœ๋น„์ €๋‹ํ•ด์ฃผ๋Š” ๊ด€๋ฆฌ์ž๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. local-path-provisioner๋ฅผ ์„ค์น˜ํ•˜๋ฉด PVC ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ ํ˜ธ์ŠคํŠธ ๊ฒฝ๋กœ์—์„œ ์ž๋™์œผ๋กœ PV๋ฅผ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.26/deploy/local-path-storage.yaml

# ์„ค์น˜ ํ™•์ธ
kubectl get sc
# local-path (default)  rancher.io/local-path  โ† ์ด๊ฒŒ ๋ณด์ด๋ฉด ์„ฑ๊ณต

Step 2: MySQL StatefulSet ๋ฐฐํฌ

# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password123"
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  # ํ•ต์‹ฌ! ํŒŒ๋“œ๋งˆ๋‹ค ๊ฐœ๋ณ„ PVC๋ฅผ ์ž๋™ ์ƒ์„ฑ
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: local-path
      resources:
        requests:
          storage: 5Gi

volumeClaimTemplates ๋•๋ถ„์— ์ˆ˜๋™์œผ๋กœ PV/PVC๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„๋„, ํŒŒ๋“œ ์ƒ์„ฑ ์‹œ ์ž๋™์œผ๋กœ 5Gi ์Šคํ† ๋ฆฌ์ง€๊ฐ€ ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค.

kubectl apply -f mysql-statefulset.yaml

# ํŒŒ๋“œ ์ด๋ฆ„์ด mysql-0 ์œผ๋กœ ๊ณ ์ •๋จ (Deployment์™€ ๋‹ค๋ฆ„)
kubectl get pods
kubectl get pvc  # PVC๊ฐ€ ์ž๋™ ์ƒ์„ฑ๋๋Š”์ง€ ํ™•์ธ

Step 3: ๋ฐ์ดํ„ฐ ๋„ฃ๊ธฐ

# MySQL ํŒŒ๋“œ ๋‚ด๋ถ€ ์ ‘์†
kubectl exec -it mysql-0 -- mysql -u root -ppassword123

# ๋ฐ์ดํ„ฐ ์ƒ์„ฑ
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');
SELECT * FROM users;

๐Ÿ”ฅ ํ•ต์‹ฌ ์‹คํ—˜ โ€” ํŒŒ๋“œ๋ฅผ ๊ฐ•์ œ๋กœ ์ฃฝ์—ฌ๋ดค๋‹ค

# mysql-0 ํŒŒ๋“œ ๊ฐ•์ œ ์‚ญ์ œ
kubectl delete pod mysql-0

StatefulSet ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ฆ‰์‹œ ๊ฐ™์€ ์ด๋ฆ„์˜ mysql-0 ํŒŒ๋“œ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์žฌ์ƒ์„ฑ๋œ ํŒŒ๋“œ์— ์ ‘์†ํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

MySQL [testdb]> SELECT * FROM users;
+------+-------+
| id   | name  |
+------+-------+
|    1 | Alice |
|    2 | Bob   |
+------+-------+

ํŒŒ๋“œ๊ฐ€ ๊ต์ฒด๋๋Š”๋ฐ๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์™„๋ฒฝํ•˜๊ฒŒ ๋ณด์กด๋ฉ๋‹ˆ๋‹ค! ๐ŸŽ‰


๐Ÿ” ์™œ ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ๋ผ์ง€์ง€ ์•Š์„๊นŒ? โ€” ๋‚ด๋ถ€ ๋™์ž‘ ์›๋ฆฌ

โ‘  ํŒŒ๋“œ๋Š” ๋ฐ”๋€Œ์–ด๋„ ์ด๋ฆ„์ด ๊ณ ์ •

Deployment๋Š” ํŒŒ๋“œ๊ฐ€ ์ฃฝ๊ณ  ์‚ด์•„๋‚˜๋ฉด ์ด๋ฆ„์ด ๋ฐ”๋€๋‹ˆ๋‹ค (nginx-xh52a โ†’ nginx-q91kz). StatefulSet์€ **ํ•ญ์ƒ mysql-0**์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋‹ค์‹œ ํƒœ์–ด๋‚ฉ๋‹ˆ๋‹ค.

โ‘ก PVC๋Š” ํŒŒ๋“œ์™€ ์ˆ˜๋ช…์ด ๋‹ค๋ฅด๋‹ค

ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•ด๋„ PVC(์Šคํ† ๋ฆฌ์ง€ ์ž„๋Œ€ ๊ณ„์•ฝ)๋Š” ์‚ญ์ œ๋˜์ง€ ์•Š๊ณ  ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค.

ํŒŒ๋“œ ์‚ญ์ œ ์ „: mysql-0 โ†” pvc-mysql-0 (๊ณ„์•ฝ ์œ ์ง€)
ํŒŒ๋“œ ์žฌ์ƒ์„ฑ:  mysql-0 (์ƒˆ ํŒŒ๋“œ) โ†’ ์ž๊ธฐ ์ด๋ฆ„ํ‘œ ํ™•์ธ โ†’ pvc-mysql-0 ์— ์žฌ์—ฐ๊ฒฐ

“๊ฑด๋ฌผ(Pod)์€ ๋ฌด๋„ˆ์ ธ์„œ ์ƒˆ๋กœ ์ง€์—ˆ์ง€๋งŒ, ์ฃผ์†Œ(PVC)๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๊ตฌ(Data)๋Š” ๊ทธ ์ž๋ฆฌ์— ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ์—ˆ๋‹ค.”


๐Ÿ’ก Deployment vs StatefulSet โ€” ์–ธ์ œ ๋ญ˜ ์“ฐ๋‚˜?

ํ•ญ๋ชฉDeploymentStatefulSet
ํŒŒ๋“œ ์ด๋ฆ„๋žœ๋ค (nginx-xh52a)์ˆœ์„œ ๊ณ ์ • (mysql-0, mysql-1)
์Šคํ† ๋ฆฌ์ง€๊ณต์œ  ๋ณผ๋ฅจ ๋˜๋Š” ์—†์ŒํŒŒ๋“œ๋งˆ๋‹ค ๋…๋ฆฝ PVC
์Šค์ผ€์ผ๋ง ์ˆœ์„œ๋žœ๋ค์ˆœ์„œ๋Œ€๋กœ (0โ†’1โ†’2)
์‚ฌ์šฉ ์ผ€์ด์Šค๋ฌด์ƒํƒœ ์›น ์•ฑDB, Kafka, Elasticsearch ๋“ฑ

โœ… ์ •๋ฆฌ

PV/PVC์™€ StatefulSet์€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ “์ƒํƒœ๊ฐ€ ์žˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(Stateful Application)” ์„ ๋‹ค๋ฃจ๋Š” ํ•ต์‹ฌ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ์šด์˜ํ•˜๋ ค๋ฉด ๋ฐ˜๋“œ์‹œ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ๊ธ€์—์„œ๋Š” ํด๋Ÿฌ์Šคํ„ฐ ๋ณด์•ˆ์˜ ํ•ต์‹ฌ์ธ RBAC(์—ญํ•  ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด) ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.