|
1 | | -# Lab 1. Container storage and Kubernetes |
| 1 | +# Lab 1: Non-persistent storage with Kubernetes |
2 | 2 |
|
3 | | -Expolore how local storage works on the pods. |
4 | | -Mount it on Docker. |
| 3 | +Storing data in containers or worker nodes are considered as the [non-persistent](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage) forms of data storage. |
| 4 | +In this lab, we will explore storage options on the IBM Kubernetes worker nodes. Follow this [lab](https://github.com/remkohdev/docker101/tree/master/workshop/lab-3) is you are interested in learning more about container-based storage. |
5 | 5 |
|
6 | | -The application is the [Guestbook App](https://github.com/IBM/guestbook), which is a sample multi-tier web application. |
| 6 | +The lab covers the following topics: |
| 7 | +- Create and claim IBM Kubernetes [non-persistent](https://cloud.ibm.com/docs/containers?topic=containers-storage_planning#non_persistent_overview) storage based on the primary and secondary storage available on the worker nodes. |
| 8 | +- Make the volumes available in the `Guestbook` application. |
| 9 | +- Use the volumes to store application cache and debug information. |
| 10 | +- Access the data from the guestbook container using the Kubernetes CLI. |
| 11 | +- Assess the impact of losing a pod on data retention. |
| 12 | +- Claim back the storage resources and clean up. |
7 | 13 |
|
8 | | -## Scenario 1: Deploy the application using `kubectl` |
| 14 | + |
| 15 | +The primary storage maps to the volume type `hostPath` and the secondary storage maps to `emptyDir`. Learn more about Kubernetes volume types [here](https://Kubernetes.io/docs/concepts/storage/volumes/). |
| 16 | + |
| 17 | +## Reserve Persistent Volumes |
| 18 | + |
| 19 | +From the cloud shell prompt, run the following commands to get the guestbook application and the kubernetes configuration needed for the storage labs. |
9 | 20 |
|
10 | 21 | ```bash |
11 | | -git clone https://github.com/IBM/workshop-template |
12 | | -cd workshop-template |
| 22 | +cd $HOME |
| 23 | +git clone --branch fs https://github.com/IBM/guestbook-nodejs.git |
| 24 | +git clone --branch storage https://github.com/rojanjose/guestbook-config.git |
| 25 | +cd $HOME/guestbook-config/storage |
| 26 | +``` |
| 27 | + |
| 28 | +Let's start with reserving the Persistent volume from the primary storage. |
| 29 | +Review the yaml file `pv-hostpath.yaml`. Note the values set for `type`, `storageClassName` and `hostPath`. |
| 30 | + |
| 31 | +```console |
| 32 | +apiVersion: v1 |
| 33 | +kind: PersistentVolume |
| 34 | +metadata: |
| 35 | + name: guestbook-primary-pv |
| 36 | + labels: |
| 37 | + type: local |
| 38 | +spec: |
| 39 | + storageClassName: manual |
| 40 | + capacity: |
| 41 | + storage: 10Gi |
| 42 | + accessModes: |
| 43 | + - ReadWriteOnce |
| 44 | + hostPath: |
| 45 | + path: "/mnt/data" |
| 46 | +``` |
| 47 | + |
| 48 | +Create the persistent volume as shown in the command below: |
| 49 | +``` |
| 50 | +kubectl create -f pv-hostpath.yaml |
| 51 | +persistentvolume/guestbook-primary-pv created |
| 52 | +
|
| 53 | +kubectl get pv |
| 54 | +NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE |
| 55 | +guestbook-primary-pv 10Gi RWO Retain Available manual 13s |
| 56 | +``` |
| 57 | + |
| 58 | +Next |
| 59 | +PVC yaml: |
| 60 | +``` |
| 61 | +apiVersion: v1 |
| 62 | +kind: PersistentVolumeClaim |
| 63 | +metadata: |
| 64 | + name: guestbook-local-pvc |
| 65 | +spec: |
| 66 | + storageClassName: manual |
| 67 | + accessModes: |
| 68 | + - ReadWriteMany |
| 69 | + resources: |
| 70 | + requests: |
| 71 | + storage: 3Gi |
| 72 | +``` |
| 73 | + |
| 74 | +Create PVC: |
| 75 | + |
| 76 | +``` |
| 77 | +kubectl create -f guestbook-local-pvc.yaml |
| 78 | +persistentvolumeclaim/guestbook-local-pvc created |
| 79 | +❯ kubectl get pvc |
| 80 | +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE |
| 81 | +guestbook-local-pvc Bound guestbook-local-pv 10Gi RWX manual 6s |
| 82 | +``` |
| 83 | + |
| 84 | + |
| 85 | +## Guestbook application using storage |
| 86 | + |
| 87 | +The application is the [Guestbook App](https://github.com/IBM/guestbook-nodejs), which is a simple multi-tier web application built using the loopback framework. |
| 88 | + |
| 89 | +Change to the guestbook application source directory: |
| 90 | + |
| 91 | +``` |
| 92 | +cd $HOME/guestbook-nodejs/src |
| 93 | +``` |
| 94 | +Review the source `common/models/entry.js`. The application uses storage allocated using `hostPath` to store data cache in the file `data/cache.txt`. The file `logs/debug.txt` records debug messages provisioned using the `emptyDir` storage type. |
| 95 | + |
| 96 | +```source |
| 97 | +module.exports = function(Entry) { |
| 98 | +
|
| 99 | + Entry.greet = function(msg, cb) { |
| 100 | +
|
| 101 | + // console.log("testing " + msg); |
| 102 | + fs.appendFile('logs/debug.txt', "Received message: "+ msg +"\n", function (err) { |
| 103 | + if (err) throw err; |
| 104 | + console.log('Debug stagement printed'); |
| 105 | + }); |
| 106 | +
|
| 107 | + fs.appendFile('data/cache.txt', msg+"\n", function (err) { |
| 108 | + if (err) throw err; |
| 109 | + console.log('Saved in cache!'); |
| 110 | + }); |
| 111 | +
|
| 112 | +... |
| 113 | +``` |
| 114 | + |
| 115 | +Run the commands listed below to build the guestbook image and copy into the docker hub registry: |
| 116 | + |
| 117 | +``` |
| 118 | +cd $HOME/guestbook-nodejs/src |
| 119 | +docker build -t $DOCKERUSER/guestbook-nodejs:storage . |
| 120 | +docker login -u $DOCKERUSER |
| 121 | +docker push $DOCKERUSER/guestbook-nodejs:storage |
| 122 | +``` |
| 123 | + |
| 124 | +Review the deployment yaml file `guestbook-deplopyment.yaml` prior to deploying the application into the cluster. |
| 125 | + |
| 126 | +``` |
| 127 | +cd $HOME/guestbook-config/storage/lab1 |
| 128 | +cat guestbook-deployment.yaml |
| 129 | +``` |
| 130 | + |
| 131 | +Replace the first part of `image` name with your docker hub user id. |
| 132 | +The section `spec.volumes` lists `hostPath` and `emptyDir` volumes. The section `spec.containers.volumeMounts` lists the mount paths that the application uses to write in the volumes. |
| 133 | + |
| 134 | +``` |
| 135 | +apiVersion: apps/v1 |
| 136 | +kind: Deployment |
| 137 | +metadata: |
| 138 | + name: guestbook-v1 |
| 139 | + labels: |
| 140 | + app: guestbook |
| 141 | + ... |
| 142 | + spec: |
| 143 | + containers: |
| 144 | + - name: guestbook |
| 145 | + image: rojanjose/guestbook-nodejs:storage |
| 146 | + imagePullPolicy: Always |
| 147 | + ports: |
| 148 | + - name: http-server |
| 149 | + containerPort: 3000 |
| 150 | + volumeMounts: |
| 151 | + - name: guestbook-primary-volume |
| 152 | + mountPath: /home/node/app/data |
| 153 | + - name: guestbook-secondary-volume |
| 154 | + mountPath: /home/node/app/logs |
| 155 | + volumes: |
| 156 | + - name: guestbook-primary-volume |
| 157 | + persistentVolumeClaim: |
| 158 | + claimName: guestbook-primary-pvc |
| 159 | + - name: guestbook-secondary-volume |
| 160 | + emptyDir: {} |
| 161 | + |
| 162 | +
|
| 163 | +... |
| 164 | +``` |
| 165 | + |
| 166 | +Deploy the Guestbook application: |
| 167 | + |
| 168 | +``` |
| 169 | +kubectl create -f guestbook-deployment.yaml |
| 170 | +deployment.apps/guestbook-v1 created |
| 171 | +
|
| 172 | +kubectl get pods |
| 173 | +NAME READY STATUS RESTARTS AGE |
| 174 | +guestbook-v1-6f55cb54c5-jb89d 1/1 Running 0 14s |
| 175 | +
|
| 176 | +kubectl create -f guestbook-service.yaml |
| 177 | +service/guestbook created |
| 178 | +``` |
| 179 | + |
| 180 | +Find the URL for the guestbook application by joining the worker node external IP and service node port. |
| 181 | + |
| 182 | +``` |
| 183 | +HOSTNAME=`ibmcloud ks workers --cluster $CLUSTERNAME | grep Ready | head -n 1 | awk '{print $2}'` |
| 184 | +SERVICEPORT=`kubectl get svc guestbook -o=jsonpath='{.spec.ports[0].nodePort}'` |
| 185 | +echo "http://$HOSTNAME:$SERVICEPORT" |
| 186 | +``` |
| 187 | + |
| 188 | +Open the URL in a browser and create guest book entries. |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | +Log into the pod: |
| 193 | + |
| 194 | +``` |
| 195 | +kubectl exec -it guestbook-v1-6f55cb54c5-jb89d bash |
| 196 | +
|
| 197 | +kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead. |
| 198 | +
|
| 199 | +root@guestbook-v1-6f55cb54c5-jb89d:/home/node/app# ls -al |
| 200 | +total 256 |
| 201 | +drwxr-xr-x 1 root root 4096 Nov 11 23:40 . |
| 202 | +drwxr-xr-x 1 node node 4096 Nov 11 23:20 .. |
| 203 | +-rw-r--r-- 1 root root 12 Oct 29 21:00 .dockerignore |
| 204 | +-rw-r--r-- 1 root root 288 Oct 29 21:00 .editorconfig |
| 205 | +-rw-r--r-- 1 root root 8 Oct 29 21:00 .eslintignore |
| 206 | +-rw-r--r-- 1 root root 27 Oct 29 21:00 .eslintrc |
| 207 | +-rw-r--r-- 1 root root 151 Oct 29 21:00 .gitignore |
| 208 | +-rw-r--r-- 1 root root 30 Oct 29 21:00 .yo-rc.json |
| 209 | +-rw-r--r-- 1 root root 105 Oct 29 21:00 Dockerfile |
| 210 | +drwxr-xr-x 2 root root 4096 Nov 11 03:40 client |
| 211 | +drwxr-xr-x 3 root root 4096 Nov 10 23:04 common |
| 212 | +drwxr-xr-x 2 root root 4096 Nov 11 23:16 data |
| 213 | +drwxrwxrwx 2 root root 4096 Nov 11 23:44 logs |
| 214 | +drwxr-xr-x 439 root root 16384 Nov 11 23:20 node_modules |
| 215 | +-rw-r--r-- 1 root root 176643 Nov 11 23:20 package-lock.json |
| 216 | +-rw-r--r-- 1 root root 830 Nov 11 23:20 package.json |
| 217 | +drwxr-xr-x 3 root root 4096 Nov 10 23:04 server |
| 218 | +
|
| 219 | +root@guestbook-v1-6f55cb54c5-jb89d:/home/node/app# cat data/cache.txt |
| 220 | +Hello Kubernetes! |
| 221 | +Hola Kubernetes! |
| 222 | +Zdravstvuyte Kubernetes! |
| 223 | +Nǐn hǎo Kubernetes! |
| 224 | +Goedendag Kubernetes! |
| 225 | +
|
| 226 | +root@guestbook-v1-6f55cb54c5-jb89d:/home/node/app# cat logs/debug.txt |
| 227 | +Received message: Hello Kubernetes! |
| 228 | +Received message: Hola Kubernetes! |
| 229 | +Received message: Zdravstvuyte Kubernetes! |
| 230 | +Received message: Nǐn hǎo Kubernetes! |
| 231 | +Received message: Goedendag Kubernetes! |
| 232 | +
|
| 233 | +
|
| 234 | +root@guestbook-v1-6f55cb54c5-jb89d:/home/node/app# df -h |
| 235 | +Filesystem Size Used Avail Use% Mounted on |
| 236 | +overlay 98G 3.5G 90G 4% / |
| 237 | +tmpfs 64M 0 64M 0% /dev |
| 238 | +tmpfs 7.9G 0 7.9G 0% /sys/fs/cgroup |
| 239 | +/dev/mapper/docker_data 98G 3.5G 90G 4% /etc/hosts |
| 240 | +shm 64M 0 64M 0% /dev/shm |
| 241 | +/dev/xvda2 25G 3.6G 20G 16% /home/node/app/data |
| 242 | +tmpfs 7.9G 16K 7.9G 1% /run/secrets/kubernetes.io/serviceaccount |
| 243 | +tmpfs 7.9G 0 7.9G 0% /proc/acpi |
| 244 | +tmpfs 7.9G 0 7.9G 0% /proc/scsi |
| 245 | +tmpfs 7.9G 0 7.9G 0% /sys/firmware |
| 246 | +
|
| 247 | +``` |
| 248 | + |
| 249 | +Kill the pod to see the impact of deleting the pod on data. |
| 250 | + |
| 251 | +``` |
| 252 | +kubectl get pods |
| 253 | +NAME READY STATUS RESTARTS AGE |
| 254 | +guestbook-v1-6f55cb54c5-jb89d 1/1 Running 0 12m |
| 255 | +
|
| 256 | +kubectl delete pod guestbook-v1-6f55cb54c5-jb89d |
| 257 | +pod "guestbook-v1-6f55cb54c5-jb89d" deleted |
| 258 | +
|
| 259 | +kubectl get pods |
| 260 | +NAME READY STATUS RESTARTS AGE |
| 261 | +guestbook-v1-5cbc445dc9-sx58j 1/1 Running 0 86s |
| 262 | +``` |
| 263 | + |
| 264 | + |
| 265 | + |
| 266 | +Enter new data: |
| 267 | + |
| 268 | + |
| 269 | +Log into the pod to view the state of the data. |
| 270 | + |
| 271 | +``` |
| 272 | +kubectl get pods |
| 273 | +NAME READY STATUS RESTARTS AGE |
| 274 | +guestbook-v1-5cbc445dc9-sx58j 1/1 Running 0 86s |
| 275 | +
|
| 276 | +kubectl exec -it guestbook-v1-5cbc445dc9-sx58j bash |
| 277 | +kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead. |
| 278 | +
|
| 279 | +root@guestbook-v1-5cbc445dc9-sx58j:/home/node/app# cat data/cache.txt |
| 280 | +Hello Kubernetes! |
| 281 | +Hola Kubernetes! |
| 282 | +Zdravstvuyte Kubernetes! |
| 283 | +Nǐn hǎo Kubernetes! |
| 284 | +Goedendag Kubernetes! |
| 285 | +Bye Kubernetes! |
| 286 | +Aloha Kubernetes! |
| 287 | +Ciao Kubernetes! |
| 288 | +Sayonara Kubernetes! |
| 289 | +
|
| 290 | +root@guestbook-v1-5cbc445dc9-sx58j:/home/node/app# cat logs/debug.txt |
| 291 | +Received message: Bye Kubernetes! |
| 292 | +Received message: Aloha Kubernetes! |
| 293 | +Received message: Ciao Kubernetes! |
| 294 | +Received message: Sayonara Kubernetes! |
| 295 | +root@guestbook-v1-5cbc445dc9-sx58j:/home/node/app# |
| 296 | +``` |
| 297 | + |
| 298 | +This shows that the storage type `emptyDir` loose data on a pod restart whereas `hostPath` data lives until the worker node or cluster is deleted. |
| 299 | + |
| 300 | + |
| 301 | +## Clean up |
| 302 | + |
13 | 303 | ``` |
| 304 | +cd $HOME/guestbook-config/storage/lab1 |
| 305 | +kubectl delete -f . |
| 306 | +``` |
0 commit comments