이 글은 인프런의 지식 공유자 박재성님의 강의를 듣고 개인적으로 정리하는 글임을 알립니다.
기존 파드를 새로운 파드로 교체하면, 기존 파드 내부에 있던 데이터도 같이 삭제된다. 만약 이 파드가 MySQL을 실행시키는 파드였다면 MySQL에 저장된 데이터도 같이 삭제 돼버린다.
따라서 파드 내부에 저장된 데이터가 삭제되면 안 되는 경우에는 볼륨(Volume)이라는 개념을 활용해야 한다.
Volume
볼륨(Volume)이란 데이터를 영속적으로 저장하기 위한 방법이다. 쿠버네티스에서 볼륨은 크게 2가지 종류로 나뉜다.
로컬 볼륨(Local Volume)
퍼시스턴트 볼륨(Persistent Volume, PV)
로컬 볼륨
파드 내부의 공간 일부를 볼륨(Volume)으로 활용하는 방식이다.
이 방식은 파드가 삭제되는 즉시 데이터도 함께 삭제된다. 이런 불편함 때문에 실제로 사용되는 일이 잘 없다.
퍼시스턴트 볼륨
파드 외부의 공간 일부를 볼륨(Volume)으로 활용하는 방식이다.
이 방식은 파드가 삭제되는 것과 상관없이 데이터를 영구적으로 사용할 수 있다는 장점이 있다. 현업에서는 주로 이 방식을 많이 활용한다.
퍼시스턴트 볼륨은 쿠버네티스 내부에 이 공간을 할당할 수도 있고, 쿠버네티스 외부에 이 공간을 할당할 수 있다.
위 그림의 왼쪽과 같은 경우, 쿠버네티스 공간 일부를 사용하는 경우이고, 오른쪽과 같은 경우는 쿠버네티스 외부 저장소(AWS EBS 등)를 사용하는 경우를 나타낸다.
파드(Pod)가 퍼시스턴트 볼륨(PV)에 직접 연결할 수 없다. 따라서 퍼시스턴트 볼륨 클레임(PVC)이라는 중개자가 있어야 한다.
그렇기 때문에 아래와 같은 구조로 파드는 PV와 연결된다.
볼륨을 활용해 MySql 실행
포트
쿠버네티스 내부 : 3306
쿠버네티스 외부 : 30002
데이터베이스
사용자 이름 : root
사용자 비밀번호 : password123
데이터베이스 : kub-practice
아래는 위의 조건을 만족하는 설정이다.
mysql-deployment.yaml
apiVersion: apps/v1 kind: Deployment
# Deployment 기본 정보 metadata: name: mysql-deployment # Deployment 이름
# Deployment 세부 정보 spec: replicas: 1 # 생성할 파드의 복제본 개수 selector: matchLabels: app: mysql-db # 아래에서 정의한 Pod 중 'app: backend-app'이라는 값을 가진 파드를 선택
# 배포할 Pod 정의 template: metadata: labels: # 레이블 (= 카테고리) app: mysql-db spec: containers: - name: mysql-container # 컨테이너 이름 image: mysql # 컨테이너를 생성할 때 사용할 이미지 ports: - containerPort: 3306 # 컨테이너에서 사용하는 포트를 명시적으로 표현 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: mysql-root-password - name: MYSQL_DATABASE valueFrom: configMapKeyRef: name: mysql-config key: mysql-database # 컨테이너 내에서 어떤 경로를 볼륨으로 사용할 지 지정 volumeMounts: - name: mysql-persistent-storage # 밑에서 설정할 volumes.name과 값이 같아야 함 mountPath: /var/lib/mysql # mysql 컨테이너 내부에 있는 경로 # 파드가 사용할 볼륨을 지정 volumes: - name: mysql-persistent-storage # 위에서 설정할 volumeMounts.name과 일치해야 함 persistentVolumeClaim: claimName: mysql-pvc # 연결시킬 PVC의 name과 동일해야 함
mysql-secret.yaml
apiVersion: v1 kind: Secret
# Secret 기본 정보 metadata: name: mysql-secret # Secret 이름
# Key, Value 형식으로 값 저장 stringData: mysql-root-password: password123
mysql-config.yaml
apiVersion: v1 kind: ConfigMap
# ConfigMap 기본 정보 metadata: name: mysql-config # ConfigMap 이름
# Key, Value 형식으로 설정값 저장 data: mysql-database: kub-practice
mysql-service.yaml
apiVersion: v1 kind: Service
# Service 기본 정보 metadata: name: mysql-service # Service 이름
# Service 세부 정보 spec: type: NodePort # Service의 종류 selector: app: mysql-db # 실행되고 있는 파드 중 'app: mysql-db'이라는 값을 가진 파드와 서비스를 연결 ports: - protocol: TCP # 서비스에 접속하기 위한 프로토콜 port: 3306 # 쿠버네티스 내부에서 Service에 접속하기 위한 포트 번호 targetPort: 3306 # 매핑하기 위한 파드의 포트 번호 nodePort: 30002 # 외부에서 사용자들이 접근하게 될 포트 번호
mysql-pv.yaml
apiVersion: v1 kind: PersistentVolume
# PersistentVolume 기본 정보 metadata: name: mysql-pv # PersistentVolume 이름
# PersistentVolume 세부 정보 spec: storageClassName: my-storage # PV와 PVC의 storageClassName이 같다면 볼륨이 연결된다. capacity: storage: 1Gi # 볼륨이 사용할 용량을 설정 accessModes: - ReadWriteOnce # 아래 hostPath 타입 활용 시 이 옵션만 사용 가능 hostPath: # hostPath 타입을 활용 (hostPath : 쿠버네티스 내부 공간을 활용) path: "/mnt/data" # 쿠버네티스 내부의 공간에서 /mnt/data의 경로를 볼륨으로 사용
mysql-pvc.yaml
apiVersion: v1 kind: PersistentVolumeClaim
# PersistentVolumeClaim 기본 정보 metadata: name: mysql-pvc # PersistentVolumeClaim 이름
# PersistentVolumeClaim 세부 정보 spec: storageClassName: my-storage # PV와 PVC의 storageClassName이 같다면 볼륨이 연결된다. accessModes: - ReadWriteOnce # 볼륨에 접근할 때의 권한 resources: # PVC가 PV에 요청하는 리소스의 양을 정의 requests: # 필요한 최소 리소스 storage: 1Gi # PVC가 PV에 요청하는 스토리지 양 (PV가 최소 1Gi 이상은 되어야 한다.)
# ConfigMap 기본 정보 metadata: name: spring-config # ConfigMap 이름
# Key, Value 형식으로 설정값 저장 data: db-host: mysql-service db-port: "3306" db-name: kub-practice
spring-deployment.yaml
apiVersion: apps/v1 kind: Deployment
# Deployment 기본 정보 metadata: name: spring-deployment # Deployment 이름
# Deployment 세부 정보 spec: replicas: 3 # 생성할 파드의 복제본 개수 selector: matchLabels: app: backend-app # 아래에서 정의한 Pod 중 'app: backend-app'이라는 값을 가진 파드를 선택
# 배포할 Pod 정의 template: metadata: labels: # 레이블 (= 카테고리) app: backend-app spec: containers: - name: spring-container # 컨테이너 이름 image: spring-server # 컨테이너를 생성할 때 사용할 이미지 imagePullPolicy: IfNotPresent # 로컬에서 이미지를 먼저 가져온다. 없으면 레지스트리에서 가져온다. ports: - containerPort: 8080 # 컨테이너에서 사용하는 포트를 명시적으로 표현 env: - name: DB_HOST valueFrom: configMapKeyRef: name: spring-config key: db-host - name: DB_PORT valueFrom: configMapKeyRef: name: spring-config key: db-port - name: DB_NAME valueFrom: configMapKeyRef: name: spring-config key: db-name - name: DB_USERNAME valueFrom: secretKeyRef: name: spring-secret key: db-username - name: DB_PASSWORD valueFrom: secretKeyRef: name: spring-secret key: db-password
spring-secret.yaml
apiVersion: v1 kind: Secret
# Secret 기본 정보 metadata: name: spring-secret # Secret 이름
# Key, Value 형식으로 값 저장 stringData: db-username: root db-password: password123
spring-service.yaml
apiVersion: v1 kind: Service
# Service 기본 정보 metadata: name: spring-service
# Service 세부 정보 spec: type: NodePort # Service의 종류 selector: app: backend-app # 실행되고 있는 파드 중 'app: backend-app'이라는 값을 가진 파드와 서비스를 연결 ports: - protocol: TCP # 서비스에 접속하기 위한 프로토콜 port: 8080 # 쿠버네티스 내부에서 Service에 접속하기 위한 포트 번호 (Service targetPort: 8080 # 매핑하기 위한 파드의 포트 번호 nodePort: 30000 # 외부에서 사용자들이 접근하게 될 포트 번호
30002번 포트로 MySQL에 직접적으로 접근할 수 있게끔 보안이 설정되어 있다는 점이다.
Service의 NodePort를 활용해 30002번 포트를 외부로 오픈해서 MySQL에 아무나 접근할 수 있게 만들었다.
보안적인 문제점 해결을 위해 Service의 종류 중 NodePort를 사용하지 않고 ClusterIP를 활용해야 한다. ClusterIP를 활용함으로써 외부에서 아무나 MySQL에 접근하지 못하게 막아야 한다.
Service 종류 - NodePort : 쿠버네티스 내부에서 해당 서비스에 접속하기 위한 포트를 열고 외부에서 접속 가능하도록 한다. - ClusterIP : 쿠버네티스 내부에서만 통신할 수 있는 IP 주소를 부여. 외부에서는 요청할 수 없다. - LoadBalancer : 외부의 로드밸런서(AWS의 로드밸런서 등)를 활용해 외부에서 접속할 수 있도록 연결한다.
mysql-service.yaml
apiVersion: v1 kind: Service
# Service 기본 정보 metadata: name: mysql-service # Service 이름
# Service 세부 정보 spec: type: ClusterIP # Service의 종류 selector: app: mysql-db # 실행되고 있는 파드 중 'app: mysql-db'이라는 값을 가진 파드와 서비스를 연결 ports: - protocol: TCP # 서비스에 접속하기 위한 프로토콜 port: 3306 # 쿠버네티스 내부에서 Service에 접속하기 위한 포트 번호 targetPort: 3306 # 매핑하기 위한 파드의 포트 번호 nodePort: 30002 # 외부에서 사용자들이 접근하게 될 포트 번호 -> 이 부분을 지운다.
서비스 오브젝트 변경사항 반영
kubectl apply -f mysql-service.yaml
이렇게 설정했다면 아래와 같은 아키텍쳐가 된 것이다.
DB를 관리하기 위해 접속해야 할 때는 쿠버네티스의 포트 포워딩을 활용해서 접속하면 된다.
아래 포트 포워딩 명령어를 사용하면 내 로컬 컴퓨터에서만 해당 파드와 연결을 허용시킬 수 있게 된다.
kubectl port-forward pod/[MySQL 파드명] 3306:3306
포트 설정 주의
이미 로컬에서 3306번 포트로 실행중이라면 접속에 실패할 수 있다. 따라서 아래와 같이 로컬에서는 13306번 포트로 접속해야한다.