Run a Single-Instance Stateful Application

    • Create a PersistentVolume referencing a disk in your environment.
    • Create a MySQL Deployment.
    • Expose MySQL to other pods in the cluster at a known DNS name.

    Before you begin

    • You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. It is recommended to run this tutorial on a cluster with at least two nodes that are not acting as control plane hosts. If you do not already have a cluster, you can create one by using minikube or you can use one of these Kubernetes playgrounds:

      To check the version, enter .

    • You need to either have a with a default StorageClass, or yourself to satisfy the PersistentVolumeClaims used here.

    You can run a stateful application by creating a Kubernetes Deployment and connecting it to an existing PersistentVolume using a PersistentVolumeClaim. For example, this YAML file describes a Deployment that runs MySQL and references the PersistentVolumeClaim. The file defines a volume mount for /var/lib/mysql, and then creates a PersistentVolumeClaim that looks for a 20G volume. This claim is satisfied by any existing volume that meets the requirements, or by a dynamic provisioner.

    Note: The password is defined in the config yaml, and this is insecure. See Kubernetes Secrets for a secure solution.

    application/mysql/mysql-pv.yaml Run a Single-Instance Stateful Application - 图2

    1. apiVersion: v1
    2. kind: PersistentVolume
    3. metadata:
    4. name: mysql-pv-volume
    5. labels:
    6. type: local
    7. spec:
    8. storageClassName: manual
    9. capacity:
    10. storage: 20Gi
    11. accessModes:
    12. - ReadWriteOnce
    13. hostPath:
    14. path: "/mnt/data"
    15. ---
    16. apiVersion: v1
    17. kind: PersistentVolumeClaim
    18. metadata:
    19. name: mysql-pv-claim
    20. spec:
    21. storageClassName: manual
    22. - ReadWriteOnce
    23. resources:
    24. requests:
    25. storage: 20Gi
      1. kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml
    1. Deploy the contents of the YAML file:

      1. kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml
    2. Display information about the Deployment:

      The output is similar to this:

      1. Namespace: default
      2. CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700
      3. Labels: app=mysql
      4. Annotations: deployment.kubernetes.io/revision=1
      5. Selector: app=mysql
      6. Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable
      7. StrategyType: Recreate
      8. MinReadySeconds: 0
      9. Pod Template:
      10. Labels: app=mysql
      11. Containers:
      12. mysql:
      13. Image: mysql:5.6
      14. Port: 3306/TCP
      15. Environment:
      16. MYSQL_ROOT_PASSWORD: password
      17. Mounts:
      18. /var/lib/mysql from mysql-persistent-storage (rw)
      19. Volumes:
      20. mysql-persistent-storage:
      21. Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
      22. ClaimName: mysql-pv-claim
      23. ReadOnly: false
      24. Conditions:
      25. Type Status Reason
      26. Available False MinimumReplicasUnavailable
      27. Progressing True ReplicaSetUpdated
      28. NewReplicaSet: mysql-63082529 (1/1 replicas created)
      29. Events:
      30. FirstSeen LastSeen Count From SubobjectPath Type Reason Message
      31. --------- -------- ----- ---- ------------- -------- ------ -------
      32. 33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
    3. List the pods created by the Deployment:

      1. kubectl get pods -l app=mysql

      The output is similar to this:

      1. NAME READY STATUS RESTARTS AGE
      2. mysql-63082529-2z3ki 1/1 Running 0 3m
    4. Inspect the PersistentVolumeClaim:

      The output is similar to this:

      1. Name: mysql-pv-claim
      2. Namespace: default
      3. StorageClass:
      4. Status: Bound
      5. Volume: mysql-pv-volume
      6. Labels: <none>
      7. Annotations: pv.kubernetes.io/bind-completed=yes
      8. pv.kubernetes.io/bound-by-controller=yes
      9. Capacity: 20Gi
      10. Access Modes: RWO
      11. Events: <none>

    Accessing the MySQL instance

    Run a MySQL client to connect to the server:

    1. kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword

    This command creates a new Pod in the cluster running a MySQL client and connects it to the server through the Service. If it connects, you know your stateful MySQL database is up and running.

    1. Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
    2. If you don't see a command prompt, try pressing enter.
    3. mysql>

    The image or any other part of the Deployment can be updated as usual with the kubectl apply command. Here are some precautions that are specific to stateful apps:

    • Don’t scale the app. This setup is for single-instance apps only. The underlying PersistentVolume can only be mounted to one Pod. For clustered stateful apps, see the .
    • Use strategy: type: Recreate in the Deployment configuration YAML file. This instructs Kubernetes to not use rolling updates. Rolling updates will not work, as you cannot have more than one Pod running at a time. The strategy will stop the first pod before creating a new one with the updated configuration.

    Deleting a deployment

    Delete the deployed objects by name:

    If you manually provisioned a PersistentVolume, you also need to manually delete it, as well as release the underlying resource. If you used a dynamic provisioner, it automatically deletes the PersistentVolume when it sees that you deleted the PersistentVolumeClaim. Some dynamic provisioners (such as those for EBS and PD) also release the underlying resource upon deleting the PersistentVolume.