Tasks

Step-by-step instructions for performing operations with Kubernetes.

Documentation for Kubernetes v1.7 is no longer actively maintained. The version you are currently viewing is a static snapshot. For up-to-date documentation, see the latest version.

Edit This Page

Run a Single-Instance Stateful Application

This page shows you how to run a single-instance stateful application in Kubernetes using a PersistentVolume and a Deployment. The application is MySQL.

Objectives

Before you begin

Set up a disk in your environment

You can use any type of persistent volume for your stateful app. See Types of Persistent Volumes for a list of supported environment disks. For Google Compute Engine, run:

gcloud compute disks create --size=20GB mysql-disk

Next create a PersistentVolume that points to the mysql-disk disk just created. Here is a configuration file for a PersistentVolume that points to the Compute Engine disk above:

gce-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  gcePersistentDisk:
    pdName: mysql-disk
    fsType: ext4

Notice that the pdName: mysql-disk line matches the name of the disk in the Compute Engine environment. See the Persistent Volumes for details on writing a PersistentVolume configuration file for other environments.

Create the persistent volume:

kubectl create -f https://k8s.io/docs/tasks/run-application/gce-volume.yaml

Deploy MySQL

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 volume that meets the requirements, in this case, the volume created above.

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

mysql-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ""
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: mysql
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
          # Use secret in real usage
        - name: MYSQL_ROOT_PASSWORD
          value: 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
  1. Deploy the contents of the YAML file:

    kubectl create -f https://k8s.io/docs/tasks/run-application/mysql-deployment.yaml
    
  2. Display information about the Deployment:

    kubectl describe deployment mysql
    
     Name:                 mysql
     Namespace:            default
     CreationTimestamp:    Tue, 01 Nov 2016 11:18:45 -0700
     Labels:               app=mysql
     Annotations:          deployment.kubernetes.io/revision=1
     Selector:             app=mysql
     Replicas:             1 desired | 1 updated | 1 total | 0 available | 1 unavailable
     StrategyType:         Recreate
     MinReadySeconds:      0
     Pod Template:
       Labels:       app=mysql
       Containers:
        mysql:
         Image:      mysql:5.6
         Port:       3306/TCP
         Environment:
           MYSQL_ROOT_PASSWORD:      password
         Mounts:
           /var/lib/mysql from mysql-persistent-storage (rw)
       Volumes:
        mysql-persistent-storage:
         Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
         ClaimName:  mysql-pv-claim
         ReadOnly:   false
     Conditions:
       Type          Status  Reason
       ----          ------  ------
       Available     False   MinimumReplicasUnavailable
       Progressing   True    ReplicaSetUpdated
     OldReplicaSets:       <none>
     NewReplicaSet:        mysql-63082529 (1/1 replicas created)
     Events:
       FirstSeen    LastSeen    Count    From                SubobjectPath    Type        Reason            Message
       ---------    --------    -----    ----                -------------    --------    ------            -------
       33s          33s         1        {deployment-controller }             Normal      ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
    
  3. List the pods created by the Deployment:

    kubectl get pods -l app=mysql
    
     NAME                   READY     STATUS    RESTARTS   AGE
     mysql-63082529-2z3ki   1/1       Running   0          3m
    
  4. Inspect the Persistent Volume:

    kubectl describe pv mysql-pv
    
     Name:            mysql-pv
     Labels:          <none>
     Annotations:    pv.kubernetes.io/bound-by-controller=yes
     StorageClass:
     Status:          Bound
     Claim:           default/mysql-pv-claim
     Reclaim Policy:  Retain
     Access Modes:    RWO
     Capacity:        20Gi
     Message:
     Source:
         Type:        GCEPersistentDisk (a Persistent Disk resource in Google Compute Engine)
         PDName:      mysql-disk
         FSType:      ext4
         Partition:   0
         ReadOnly:    false
     Events:          <none>
    
  5. Inspect the PersistentVolumeClaim:

    kubectl describe pvc mysql-pv-claim
    
     Name:         mysql-pv-claim
     Namespace:    default
     StorageClass:
     Status:       Bound
     Volume:       mysql-pv
     Labels:       <none>
     Annotations:    pv.kubernetes.io/bind-completed=yes
                     pv.kubernetes.io/bound-by-controller=yes
     Capacity:     20Gi
     Access Modes: RWO
     Events:       <none>
    

Accessing the MySQL instance

The preceding YAML file creates a service that allows other Pods in the cluster to access the database. The Service option clusterIP: None lets the Service DNS name resolve directly to the Pod’s IP address. This is optimal when you have only one Pod behind a Service and you don’t intend to increase the number of Pods.

Run a MySQL client to connect to the server:

kubectl run -it --rm --image=mysql:5.6 mysql-client -- mysql -h <pod-ip> -p <password>

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.

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

mysql>

Updating

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:

Deleting a deployment

Delete the deployed objects by name:

kubectl delete deployment,svc mysql
kubectl delete pvc mysql-pv-claim
kubectl delete pv mysql-pv

Also, if you are using Compute Engine disks:

gcloud compute disks delete mysql-disk

What’s next

Analytics

Create an Issue Edit this Page