예시: WordPress와 MySQL을 퍼시스턴트 볼륨에 배포하기

이 튜토리얼은 WordPress 사이트와 MySQL 데이터베이스를 Minikube를 이용하여 어떻게 배포하는지 보여준다. 애플리케이션 둘 다 퍼시스턴트 볼륨과 퍼시스턴트볼륨클레임을 데이터를 저장하기 위해 사용한다.

퍼시스턴트볼륨(PV)는 관리자가 수동으로 프로비저닝한 클러스터나 쿠버네티스 스토리지클래스를 이용해 동적으로 프로비저닝된 저장소의 일부이다. 퍼시스턴트볼륨클레임(PVC)은 PV로 충족할 수 있는 사용자에 의한 스토리지 요청이다. 퍼시스턴트볼륨은 파드 라이프사이클과 독립적이며 재시작, 재스케줄링이나 파드를 삭제할 때에도 데이터를 보존한다.

경고: 이 배포는 프로덕션 사용 예로는 적절하지 않은데 이는 단일 인스턴스의 WordPress와 MySQL을 이용했기 때문이다. 프로덕션이라면 WordPress Helm Chart로 배포하기를 고려해보자.
참고: 이 튜토리얼에 제공된 파일들은 GA 디플로이먼트 API를 사용하며 쿠버네티스 버전 1.9 이상을 이용한다. 이 튜토리얼을 쿠버네티스 하위 버전에서 적용한다면 API 버전을 적절히 갱신하거나 이 튜토리얼의 이전 버전을 참고하자.

목적

  • 퍼시스턴트볼륨클레임과 퍼시스턴트볼륨 생성
  • 다음을 포함하는 kustomization.yaml 생성
    • 시크릿 생성자
    • MySQL 리소스 구성
    • WordPress 리소스 구성
  • kubectl apply -k ./로 생성한 kustomization 을 적용
  • 정리

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

버전 확인을 위해서, 다음 커맨드를 실행 kubectl version. 이 예시는 kubectl 1.14 이상 버전에서 동작한다.

다음 설정 파일을 다운로드한다.

  1. mysql-deployment.yaml

  2. wordpress-deployment.yaml

퍼시스턴트볼륨클레임과 퍼시스턴트볼륨 생성

MySQL과 Wordpress는 각각 데이터를 저장할 퍼시스턴트볼륨이 필요하다. 퍼시스턴트볼륨클레임은 배포 단계에 생성된다.

많은 클러스터 환경에서 설치된 기본 스토리지클래스(StorageClass)가 있다. 퍼시스턴트볼륨클레임에 스토리지클래스를 지정하지 않으면 클러스터의 기본 스토리지클래스를 사용한다.

퍼시스턴트볼륨클레임이 생성되면 퍼시스턴트볼륨이 스토리지클래스 설정을 기초로 동적으로 프로비저닝된다.

경고: 로컬 클러스터에서 기본 스토리지클래스는 hostPath 프로비저너를 사용한다. hostPath는 개발과 테스트 목적에만 적합하다. hostPath 볼륨인 경우 데이터는 스케쥴링된 파드의 노드에 /tmp 살아있고 노드 간에 이동하지 않는다. 파드가 죽어서 클러스터 내에 다른 노드로 스케줄링되거나 해당 노드가 재부팅되면 그 데이터는 잃어버린다.
참고: hostPath 프로비저너를 사용해야 하는 클러스터를 기동하는 경우라면 --enable-hostpath-provisioner 플래그를 controller-manager 컴포넌트에 꼭 설정해야 한다.
참고: 만약 구글 쿠버네티스 엔진으로 운영하는 쿠버네티스 클러스터를 가지고 있다면 가이드를 따르도록 한다.

kustomization.yaml 생성하기

시크릿 생성자 추가

시크릿은 암호나 키 같은 민감한 데이터들을 저장하는 오브젝트이다. 1.14 버전부터 kubectl은 kustomization 파일을 이용해서 쿠버네티스 오브젝트를 관리한다. kustomization.yaml의 제너레이터로 시크릿을 생성할 수 있다.

다음 명령어로 kustomization.yaml 내에 시크릿 제네레이터를 추가한다. YOUR_PASSWORD는 사용하기 원하는 암호로 변경해야 한다.

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
  literals:
  - password=YOUR_PASSWORD
EOF

MySQL과 WordPress에 필요한 리소스 구성 추가하기

다음 매니페스트는 MySQL 디플로이먼트 단일 인스턴스를 기술한다. MySQL 컨케이너는 퍼시스턴트볼륨을 /var/lib/mysql에 마운트한다. MYSQL_ROOT_PASSWORD 환경 변수는 시크릿에서 가져와 데이터베이스 암호로 설정한다.

apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

다음의 매니페스트는 단일-인스턴스 WordPress 디플로이먼트를 기술한다. WordPress 컨테이너는 웹사이트 데이터 파일을 위해 /var/www/html에 퍼시스턴트볼륨을 마운트한다. WORDPRESS_DB_HOST 환경 변수에는 위에서 정의한 MySQL 서비스의 이름이 설정되며, WordPress는 서비스를 통해 데이터베이스에 접근한다. WORDPRESS_DB_PASSWORD 환경 변수에는 kustomize가 생성한 데이터베이스 패스워드가 설정된다.

apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim
  1. MySQL 디플로이먼트 구성 파일을 다운로드한다.

    curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
    
  2. WordPress 구성 파일을 다운로드한다.

    curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
    
  3. 두 파일을 kustomization.yaml에 추가하자.

cat <<EOF >>./kustomization.yaml
resources:
  - mysql-deployment.yaml
  - wordpress-deployment.yaml
EOF

적용하고 확인하기

kustomization.yaml은 WordPress 사이트와 MySQL 데이터베이스를 배포하는 모든 리소스를 포함한다. 다음과 같이 디렉터리를 적용할 수 있다.

kubectl apply -k ./

이제 모든 오브젝트가 존재하는지 확인할 수 있다.

  1. 시크릿이 존재하는지 다음 명령어를 실행하여 확인한다.

    kubectl get secrets
    

    응답은 아래와 비슷해야 한다.

    NAME                    TYPE                                  DATA   AGE
    mysql-pass-c57bb4t7mf   Opaque                                1      9s
    
  2. 퍼시스턴트볼륨이 동적으로 프로비저닝되었는지 확인한다.

    kubectl get pvc
    
    참고: PV를 프로비저닝하고 정착(bound)시키는데 수 분이 걸릴 수 있다.

    응답은 아래와 비슷해야 한다.

    NAME             STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       AGE
    mysql-pv-claim   Bound     pvc-8cbd7b2e-4044-11e9-b2bb-42010a800002   20Gi       RWO            standard           77s
    wp-pv-claim      Bound     pvc-8cd0df54-4044-11e9-b2bb-42010a800002   20Gi       RWO            standard           77s
    
  3. 다음 명령어를 실행하여 파드가 실행 중인지 확인한다.

    kubectl get pods
    
    참고: 파드의 상태가 RUNNING가 되기까지 수 분이 걸릴 수 있다.

    응답은 아래와 비슷해야 한다.

    NAME                               READY     STATUS    RESTARTS   AGE
    wordpress-mysql-1894417608-x5dzt   1/1       Running   0          40s
    
  4. 다음 명령어를 실행하여 서비스가 실행 중인지 확인해보자.

    kubectl get services wordpress
    

    응답은 아래와 비슷해야 한다.

    NAME        TYPE            CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
    wordpress   LoadBalancer    10.0.0.89    <pending>     80:32406/TCP   4m
    
    참고: Minikube에서는 서비스를 NodePort으로만 노출할 수 있다. EXTERNAL-IP는 항상 Pending 상태이다.
  5. 다음 명령어를 실행하여 WordPress 서비스의 IP 주소를 얻어온다.

    minikube service wordpress --url
    

    응답은 아래와 비슷해야 한다.

    http://1.2.3.4:32406
    
  6. IP 주소를 복사해서 웹 브라우저에서 사이트를 열어 보자.

    아래 스크린샷과 유사한 WordPress 설정 페이지를 볼 수 있어야 한다.

    wordpress-init

경고: 이 페이지의 WordPress 설치를 내버려 두지 말자. 다른 사용자가 이 페이지를 발견하고 귀하의 인스턴스에 웹 사이트를 설정하고 악의적인 컨텐츠를 게시하는데 사용할 수 있다.

WordPress를 사용자명과 암호를 넣어 생성하거나 인스턴스를 삭제하자.

정리하기

  1. 다음 명령을 실행하여 시크릿, 디플로이먼트, 서비스와 퍼시스턴트볼륨클레임을 삭제하자.

    kubectl delete -k ./
    

다음 내용

최종 수정 April 02, 2021 at 12:18 AM PST : Resolve conflicts on dev-1.20-ko.7 branch (cf780b654)