using netapp with docker and kubernetes - hol. · pdf filefile storage from the netapp...

58
Using NetApp with Docker and Kubernetes May 2018 | SL10236 Version 1.0.2

Upload: dangnhan

Post on 15-Mar-2018

214 views

Category:

Documents


1 download

TRANSCRIPT

Using NetApp with Docker andKubernetes

May 2018 | SL10236 Version 1.0.2

Using NetApp with Docker and Kubernetes2 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

TABLE OF CONTENTS

1 Introduction...................................................................................................................................... 3

2 Lab Environment............................................................................................................................. 4

3 Docker...............................................................................................................................................6

3.1 Explore The Docker CLI........................................................................................................... 6

3.2 Explore Container Volumes....................................................................................................19

3.3 Explore Container Volumes Hosted on ONTAP Storage..................................................... 26

3.4 Create Containers using the NetApp Docker Volume Plugin (nDVP)................................. 32

3.5 Creating a Custom Container Image.....................................................................................38

4 Kubernetes..................................................................................................................................... 43

4.1 Explore Kubernetes.................................................................................................................43

4.2 Deploy a POD to the Kubernetes Cluster............................................................................. 49

4.3 Create a Persistent Volume on ONTAP using Trident......................................................... 51

5 References......................................................................................................................................56

6 Version History.............................................................................................................................. 57

Using NetApp with Docker and Kubernetes3 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

1 IntroductionDocker enables application portability by decoupling the application from the OS and facilitating applicationdistribution using images. This makes it a valuable tool for the rapid development, deployment, and scaling of anapplication.

Kubernetes is an orchestrator for deploying containers across a cluster of hosts, allowing you to centrally deployand manage complex application container environments.

This lab provides an introduction to both Docker and Kubernetes, and demonstrates how you can utilizeNetApp storage systems to provide persistent storage for your container environments using native Dockerand Kubernetes Command Line Interface (CLI) commands. This information can help you to leverage NetApp’sexisting enterprise storage capabilities to provision, manage, and protect the data in your container environmentswithout requiring your application developers to become storage experts.

1 Lab ObjectivesThis lab offers information on how to run Docker containers on Linux in the following topics:

• Explore basic container usage - instantiating, starting, stopping, and deleting containers.• Explore container volumes.• Host persistent container volumes on ONTAP.• Create customized containers.• Explore a Kubernetes environment.• Deploy a pod with Kubernetes.• Create persistent volumes for Kubernetes on ONTAP.

1 PrerequisitesDocker and Kubernetes are most closely associated with Linux, and are managed using the Linux Command LineInterface (CLI). A working knowledge of the Linux CLI is helpful for this lab, but not required as this lab guide fullyspecifies the required Linux commands at each step.

A basic working knowledge of clustered Data ONTAP is also helpful.

Using NetApp with Docker and Kubernetes4 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

2 Lab EnvironmentThe following diagram illustrates the environment for this lab.

All of the servers and storage controllers presented in this lab are virtual devices, and the networks thatinterconnect them are exclusive to your lab session. While we encourage you to follow the demonstrationsteps outlined in this lab guide, you are free to deviate from this guide and experiment with other Data ONTAPfeatures that interest you. While the virtual storage controllers (vsims) used in this lab offer nearly all of thesame functionality as physical storage controllers, they are not capable of providing the same performance as aphysical controller, which so they are not suitable for performance testing.

The Lab Host Credentials table provides a list of the servers and storage controller nodes in the lab, along withtheir IP address.

Figure 2-1:

Table 1: Lab Host Credentials

Hostname Description IP Address(es) Username Password

JUMPHOSTWindows 20012R2 RemoteAccess host

192.168.0.5 Demo\Administrator Netapp1!

RHEL1 Red Hat 7.3 x64 Linux host 192.168.0.61 root Netapp1!

RHEL2 Red Hat 7.3 x64 Linux host 192.168.0.62 root Netapp1!

RHEL3Red Hat 7.3 x64 Linux Host,Snap Creator Server

192.168.0.63 root Netapp1!

RHEL4Red Hat 7.3 x64 Linux Host,Docker Repository Server

192.168.0.64 root Netapp1!

DC1 Active Directory Server 192.168.0.253 Demo\Administrator Netapp1!

cluster1 Data ONTAP cluster 192.168.0.101 admin Netapp1!

The Preinstalled NetApp Software table lists the NetApp software that is pre-installed on the various hosts in thislab.

Using NetApp with Docker and Kubernetes5 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

Table 2: Preinstalled NetApp Software

Hostname Description

RHEL2 NetApp Docker Volume Plugin v17.07

RHEL3 NetApp Trident

Using NetApp with Docker and Kubernetes6 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

3 DockerContainers decouple an application from the host operating system by isolating the application process(es), andother resource requirements, from the rest of the system. Container images, which package the application’scode/binary, dependencies, and other tools into an easy to consume unit, provide a simple way to distributeand reuse applications and application components. This makes containers a powerful tool for application andoperations teams who want to create and deploy applications which are portable across any environment.

Containers are often thought of as being ephemeral, where they are created and destroyed with no need topersist any changes to what’s inside. However, this is not always true. Many applications, such as databases,have a persistence requirement, where data needs to exist beyond the lifespan of a container. To meet this needDocker created the concept of a Docker Volume. A Docker Volume is simply a bit of storage which is decoupledfrom the container. It is managed independently and, importantly, when the container it’s attached to is destroyed,the volume is unaffected.

Standard Docker volumes are created on the filesystem of the host that is executing the container. This isextremely convenient, but not an enterprise solution when you consider real-world challenges like:

• If a container needs to be relocated to a different host, how do you migrate the standard docker volumedata?

• How do you recover the standard docker volume data in the event of a host hardware failure?• How do you scale your aplication beyond the capabilities of a single host?

To fill this gap, and capitalize on the features, reliability, and capabilities of enterprise storage systems, Dockercreated the Docker Volume Plugin paradigm. This is what enables Docker, through the NetApp Docker VolumePlugin (nDVP), to seamlessly, and with extreme simplicity, consume and manage storage from the NetAppportfolio.

With nDVP, Docker users utilize the same command line they are already familiar with to provision block andfile storage from the NetApp portfolio, without having any knowledge of the underlying infrastructure. From theirperspective, storage is as simple as “docker volume create”, in exactly the same manner as they would consumestorage if it were local. This frictionless integration removes the infrastructure team as a barrier to applicationagility, while they are still able to retain control using the configuration mechanisms of nDVP.

3.1 Explore The Docker CLIDocker is a tool for creating and managing containers. A container is, at its core, a standard process which hasbeen isolated at the kernel level using two features: control groups (cgroups) and namespaces. Cgroups is aLinux kernel feature that limits, accounts for, and isolates the resource usage (CPU, memory, disk I/O, network,etc.) of a collection of processes. Namespaces provide the ability to not only isolate the process, but also to dothings like modify where the root of the file system is, attach a new network stack, and even isolate the usernamespace so that root in the container is not the same root as outside the container.

Containers are useful as a mechanism for deploying applications in a repeatable and predictable manner. Dockeradds the ability to quickly and easily create container images, which have the application, along with all of itsdependent libraries, tools, and executables, bundled together. Leveraging Docker, and the Docker Registry, itis very easy to redistribute the images and have them executed on any host with the Docker Engine installed,all while having confidence that the container will execute the same regardless of whether it was started ona developer laptop, the test/dev environment in the on-premises datacenter, or the production hyperscalarenvironment.

In this exercise you will explore some basic features and functionality of Docker.

1. On the taskbar of Jumphost, launch PuTTY.

Using NetApp with Docker and Kubernetes7 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

1

Figure 3-1:

The PuTTY Configuration window opens.2. If the right pane does not contain the header “Basic options for your PuTTY session”, then in the left

pane select the Session category.3. In the right pane, in the “Saved Sessions” list, double-click rhel1.

2

3

Figure 3-2:

A PuTTY teminal session window opens.4. Log in using the username root and the password Netapp1!.

login as: [email protected]'s password: Last login: Sat Jul 12 17:59:20 2017[root@rhel1 ~]#

Using NetApp with Docker and Kubernetes8 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

5. Issue the docker command, which is the base CLI command used to manage a docker environment.

[root@rhel1 ~]# docker

Usage:docker COMMAND

A self-sufficient runtime for containers

Options: --config string Location of client config files (default "/root/.docker") -D, --debug Enable debug mode --help Print usage -H, --host list Daemon socket(s) to connect to (default []) -l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info") --tls Use TLS; implied by --tlsverify --tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem") --tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem") --tlskey string Path to TLS key file (default "/root/.docker/key.pem") --tlsverify Use TLS and verify the remote -v, --version Print version information and quit

Management Commands: container Manage containers image Manage images network Manage networks node Manage Swarm nodes plugin Manage plugins secret Manage Docker secrets service Manage services stack Manage Docker stacks swarm Manage Swarm system Manage Docker volume Manage volumes

Commands: attach Attach to a running container build Build an image from a Dockerfile commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container diff Inspect changes to files or directories on a container's filesystem events Get real time events from the server exec Run a command in a running container export Export a container's filesystem as a tar archive history Show the history of an image images List images import Import the contents from a tarball to create a filesystem image info Display system-wide information inspect Return low-level information on Docker objects kill Kill one or more running containers load Load an image from a tar archive or STDIN login Log in to a Docker registry logout Log out from a Docker registry logs Fetch the logs of a container pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container ps List containers pull Pull an image or a repository from a registry push Push an image or a repository to a registry rename Rename a container restart Restart one or more containers rm Remove one or more containers rmi Remove one or more images run Run a command in a new container save Save one or more images to a tar archive (streamed to STDOUT by default) search Search the Docker Hub for images start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers

Using NetApp with Docker and Kubernetes9 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

version Show the Docker version information wait Block until one or more containers stop, then print their exit codes

Run 'docker COMMAND --help' for more information on a command.[root@rhel1 ~]#

Notice that the docker command has many sub-commands. These sub-commands are used to managedifferent aspects of the containers. You will explore some of these commands in this exercise.

6. Display details about the version of Docker you are using on the client and the server.

[root@rhel1 ~]# docker versionClient: Version: 17.04.0-ce API version: 1.28 Go version: go1.7.5 Git commit: 4845c56 Built: Mon Apr 3 18:01:50 2017 OS/Arch: linux/amd64

Server: Version: 17.04.0-ce API version: 1.28 (minimum version 1.12) Go version: go1.7.5 Git commit: 4845c56 Built: Mon Apr 3 18:01:50 2017 OS/Arch: linux/amd64 Experimental: false[root@rhel1 ~]#

7. Display system-wide information about the Docker installation.

[root@rhel1 ~]# docker infoContainers: 0 Running: 0 Paused: 0 Stopped: 0Images: 0Server Version: 17.04.0-ceStorage Driver: devicemapper Pool Name: docker-253:1-998953-pool Pool Blocksize: 65.54kB Base Device Size: 107.4GB Backing Filesystem: xfs Data file: /dev/loop0 Metadata file: /dev/loop1 Data Space Used: 53.74MB Data Space Total: 107.4GB Data Space Available: 37.16GB Metadata Space Used: 606.2kB Metadata Space Total: 2.147GB Metadata Space Available: 2.147GB Thin Pool Minimum Free Space: 10.74GB Udev Sync Supported: true Deferred Removal Enabled: false Deferred Deletion Enabled: false Deferred Deleted Device Count: 0 Data loop file: /var/lib/docker/devicemapper/devicemapper/data Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata Library Version: 1.02.135-RHEL7 (2016-09-28)Logging Driver: json-fileCgroup Driver: cgroupfsPlugins: Volume: local Network: bridge host macvlan null overlaySwarm: inactiveRuntimes: runcDefault Runtime: runcInit Binary: containerd version: 422e31ce907fd9c3833a38d7b8fdd023e5a76e73runc version: 9c2d8d184e5da67c95d601382adf14862e4f2228init version: 949e6faSecurity Options: seccomp Profile: defaultKernel Version: 3.10.0-514.el7.x86_64Operating System: Red Hat Enterprise Linux Server 7.3 (Maipo)OSType: linux

Using NetApp with Docker and Kubernetes10 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

Architecture: x86_64CPUs: 2Total Memory: 1.797GiBName: rhel1ID: KLKY:4YCQ:3B25:FVJB:J2QX:O34Z:KTH5:QQIZ:5HBQ:WD7Z:ZW7F:UMWDDocker Root Dir: /var/lib/dockerDebug Mode (client): falseDebug Mode (server): falseRegistry: https://index.docker.io/v1/Experimental: falseInsecure Registries: 127.0.0.0/8Live Restore Enabled: false

WARNING: devicemapper: usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.WARNING: bridge-nf-call-iptables is disabledWARNING: bridge-nf-call-ip6tables is disabled[root@rhel1 ~]#

This command displays information about the Docker installation and configuration. The Storage Driverline refers to the driver that Docker is using when it instantiates the container images, or creates anew basic Docker volume. The Docker devicemapper storage driver leverages the thin provisioningand snapshotting capabilities of Linux Device Mapper, a kernel-based framework that underpins manyadvanced volume manegement technologies on Linux, for image and container management.

8. Display a list of the container images that are present on the system.

[root@rhel1 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE[root@rhel1 ~]#

The list is currently empty, as you have not yet installed any container images.9. Download the httpd 2.2 docker image.

[root@rhel1 ~]# docker pull httpd:2.22.2: Pulling from library/httpd9f0706ba7422: Pull complete9f21d14d4c65: Pull complete3771e13e1db2: Pull complete993be87f35a4: Pull completeb6e1946da58b: Pull completeDigest: sha256:972fbc4434624b1259838812750b3f620c4c26e2c17ff333db4362c2392d7704Status: Downloaded newer image for httpd:2.2[root@rhel1 ~]#

The Docker daemon retrieves the httpd version 2.2 container image from Docker Hub. During the pullprocess you will notice that it is pulling the image layers, which are stored as .tar.gz files, then extractingthem. The command updates each output line with current status as it works through this process, withstatus switching through the states of Pulling, Downloading, Verifying, Extracting, and Pull complete. TheDigest line near the end of the output displays the sha256 digest checksum for the image so that you canverify the image's integrity.

10. Display an updated list of the container images that are present on rhel1.

[root@rhel1 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEhttpd 2.2 60bc4ccd60d8 3 days ago 171MB[root@rhel1 ~]#

Notice that the image you just pulled is displayed along with its size and how long ago it was updated.The “Created” time comes from the Docker Hub / Registry and indicates when the image was createdthere, not how long ago the image was pulled to the local system.

11. Now that you have a copy of the httpd 2.2 container image on rhel1, the next step is to start a container.

[root@rhel1 ~]# docker run -d --name my_www httpd:2.29031b77d43caca4aeb1e9b63b5956608d9a5ffca57eb7f41334b53a607c2d658[root@rhel1 ~]#

Using NetApp with Docker and Kubernetes11 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

The -d option indicates that the container is to run in detached mode rather than in the foreground, sothat you will not tie up your command line session.

12. Display the status of your running containers.

[root@rhel1 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES9031b77d43ca httpd:2.2 "httpd-foreground" 9 seconds ago Up 9 seconds 80/tcp my_www[root@rhel1 ~]#

Note the container ID and container name (my_www), and that it's status is reported as “Up”, meaningit is running. Also note the ports value (80/tcp), which you will examine more closely over the next fewsteps.

13. View the logs for the container.

[root@rhel1 ~]# docker logs my_wwwhttpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2 for ServerName[Fri Jul 14 20:11:39 2017] [warn] Init: Session Cache is not configured [hint: SSLSessionCache]httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2 for ServerName[Fri Jul 14 20:11:39 2017] [notice] Digest: generating secret for digest authentication ...[Fri Jul 14 20:11:39 2017] [notice] Digest: done[Fri Jul 14 20:11:40 2017] [notice] Apache/2.2.34 (Unix) mod_ssl/2.2.34 OpenSSL/1.0.1t DAV/2 configured -- resuming normal operations[root@rhel1 ~]#

This docker sub-command is valuable for troubleshooting and monitoring containerized applications.14. On the desktop of Jumphost, open the Firefox web browser.

14

Figure 3-3:

15. Open a new tab in Firefox and browse to http://rhel1.demo.netapp.com. If you prefer Chrome, you canuse that instead, but the screenshots in this guide all utilize Firefox.

Using NetApp with Docker and Kubernetes12 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

15

Figure 3-4:

In this step of the lab the browser cannot open the requested page because by default Docker does notexpose the ports the container is using (80/tcp in this case) through the underlying host.

Containers do not have direct network identities of their own, their network services are all providedthrough the network identity of the underlying host. In other words, containers running on a hostshare the host's IP address, and distinguish themselves from one another (and from services runningnatively on the underlying host) through the use of port masquerading. As an example, imagine twoweb server containers running on a host with the IP address 192.168.1.10, with both containersinternally running HTTPD on port 80. Both containers will leverage the host's IP address for networkcommunication, but the host will use port translation to map different host ports to these container ports.So, web clients might access one web server by the URL http://192.168.1.10:8080, and the other bythe URL http://192.168.1.10:8081, with the host's port translation internally mapping these ports to eachcontainer's port 80. Network and application administrators typically deploy load balancers in front ofthis sort of deployment in order to hide awareness of this port mapping complexity from applicationusers.

A core tenet of Docker is that containers are ephemeral, in that they are designed to be easilydiscarded and re-instantiated with minimal configuration. So, in the next steps, rather than try to fix theexisting container, you will instead simply destroy the container and re-create it with the desired portmapping.

16. Stop the “my_www” container.

[root@rhel1 ~]# docker stop my_wwwmy_www[root@rhel1 ~]#

17. Destroy the “my_www” container.

[root@rhel1 ~]# docker rm my_www

my_www

Using NetApp with Docker and Kubernetes13 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

[root@rhel1 ~]#

18. Create a new httpd container, this time mapping the container’s TCP port 80 to the host’s TCP port 80.

[root@rhel1 ~]# docker run -d --name my_www -p 80:80 httpd:2.28ff217517f1be40701998313a89120569315baa56af6c13920d457ec0995b761[root@rhel1 ~]#

The newly added “-p 80:80” option specifies the port mapping.19. Display the status of your running containers again.

[root@rhel1 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES8ff217517f1b httpd:2.2 "httpd-foreground" 19 seconds ago Up 18 seconds 0.0.0.0:80->80/tcp my_www[root@rhel1 ~]#

Notice the port mapping information now displayed under the PORTS column.20. Switch back to the Firefox browser, and use the browser refresh button to reload the page. You will

now see the Apache server's default “It works!” web page.

20

Figure 3-5:

21. If you are setting up a web server then you probably want to display more interesting content than theweb server's default web page. To change the current content you will need to initiate an interactive CLIsession to the container.

[root@rhel1 ~]# docker exec -it my_www /bin/bashroot@8ff217517f1b:/usr/local/apache2#

The docker exec command runs a command inside a running container. In this example that commandis the bash shell, and the -it option for the exec sub-command indicates that Docker should maintain aninteractive tty connection to that bash shell.

Using NetApp with Docker and Kubernetes14 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

22. Navigate to the container's htdoc's directory.

root@8ff217517f1b:/usr/local/apache2# cd /usr/local/apache2/htdocsroot@8ff217517f1b:/usr/local/apache2/htdocs#

23. Display the directory's contents.

root@8ff217517f1b:/usr/local/apache2/htdocs# lsindex.htmlroot@8ff217517f1b:/usr/local/apache2/htdocs#

The directory contains the site's default page file, index.html.24. Display the file's contents so you can see the format.

root@8ff217517f1b:/usr/local/apache2/htdocs# cat index.html <html><body><h1>It works!</h1></body></html>root@8ff217517f1b:/usr/local/apache2/htdocs#

25. Replace the default index.html file with something more interesting.

root@8ff217517f1b:/usr/local/apache2/htdocs# echo '<h1>Connect Clouds with the NetApp Data Fabric!</h1>' > index.htmlroot@8ff217517f1b:/usr/local/apache2/htdocs#

26. Verify the file's contents.

root@8ff217517f1b:/usr/local/apache2/htdocs# cat index.html<h1>Connect Clouds with the NetApp Data Fabric!</h1>root@8ff217517f1b:/usr/local/apache2/htdocs#

Tip: You may notice that the html tags you entered are not as complete and complex as thefile's original tags. That is designed to save you some typing, the simplified html structure youentered is still valid.

27. In Firefox, refresh the browser page for http://rhel1.demo.netapp.com. The web page now updates todisplay your new web page.

Using NetApp with Docker and Kubernetes15 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

27

Figure 3-6:

28. Exit out of your CLI session to the my-www container.

root@8ff217517f1b:/usr/local/apache2/htdocs# exitexit[root@rhel1 ~]#

29. Stop the container.

[root@rhel1 ~]# docker stop my_wwwmy_www[root@rhel1 ~]#

30. Refresh the Firefox browser window.

Using NetApp with Docker and Kubernetes16 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

30

Figure 3-7:

As expected, there is no response from the web server.31. Restart the container using the docker start my_www command.

[root@rhel1 ~]# docker start my_wwwmy_www[root@rhel1 ~]#

32. Refresh the Firefox browser window again.

Using NetApp with Docker and Kubernetes17 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

32

Figure 3-8:

This time the page displays properly, demonstrating that the content was preserved across restarts ofthe hosting container.

33. Assume now that a new version of Apache has been released, resulting in a new httpd containerimage, and that you want to update to that newer version. Remember that a running container is notmeant to be updated in-place. Instead it is stopped, removed, and then re-created. You will now applythis procedure to your existing container installation.

Stop and remove your existing lod_www container.

[root@rhel1 ~]# docker stop my_www && docker rm my_wwwmy_wwwmy_www[root@rhel1 ~]#

Tip: The “&&” syntax in the above command allows you to logically link the execution of twoindependent commands together. In this example the “docker rm my_www” command willexecute only if the “docker stop my_www” first completes successfully.

34. Instantiate a container for the latest httpd.

[root@rhel1 ~]# docker run -d --name my_www -p 80:80 httpd:latestUnable to find image 'httpd:latest' locallylatest: Pulling from library/httpdf0706ba7422: Already exists47bacf36113f: Pull complete56798d8e5a30: Pull complete27db250fa75b: Pull completece9c5765af5f: Pull complete5b5660aa17c6: Pull complete772197068420: Pull completeStatus: Downloaded newer image for httpd:latestDigest: sha256:1989458ded44c5cfdb4e5b4e37ac435937564d52450db79c972b1b59dda0c7db13c38d7a6bbcdf7dbd4623a8a917953d08609db7cac19d61a58304c9e14ccf6e[root@rhel1 ~]#

Using NetApp with Docker and Kubernetes18 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

Since the latest httpd container image is not available locally, Docker initiates an image downloadoperation and once that finishes it then instantiates the container.

Attention: If you get an error message stating “...lookup index.docker.io: no such host” whilerunning this command, try issuing the command again. This image is getting pulled from a publicDocker server that has on occasion emitted this error, but the error resolves itself when you re-run the command.

35. Display a list of the local images.

[root@rhel1 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEhttpd latest e0ceae115daa 3 days ago 177MBhttpd 2.2 60bc4ccd60d8 3 days ago 171MB[root@rhel1 ~]#

These are the images you downloaded locally from the Docker repository.36. Display a list of the running containers.

[root@rhel1 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES13c38d7a6bbc httpd:latest "httpd-foreground" 32 seconds ago Up 31 seconds 0.0.0.0:80->80/tcp my_www[root@rhel1 ~]#

37. In Firefox, refresh the page for http://rhel1.demo.netapp.com.

37

Figure 3-9:

Notice that the page's contents have reverted back to the Apache default page! This is becausethe data inside the container is non-persistent; when the container image is removed, so is the dataassociated with it.

38. Stop and remove the my_www container.

[root@rhel1 ~]# docker stop my_www && docker rm my_wwwmy_www

Using NetApp with Docker and Kubernetes19 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

my_www[root@rhel1 ~]#

Leave your PuTTY session to rhel1 open, as you will be using it again in later exercises.

3.2 Explore Container VolumesA container volume is a dedicated file/directory created on the container host that stores data for the container.It is separate from any container image, which means you can delete an associated container without losingany data stored within the container volume. In other words, container volumes provide persistent storage, butremember that by default that storage still resides on the container host's local disks.

1. Create a new Docker local container volume named “myhttpd” using the local file system driver, whichwill create that volume on one of rhel1's local disks, outside of any given container's native directorytrees.

[root@rhel1 ~]# docker volume create --name=myhttpdmyhttpd[root@rhel1 ~]#

2. Display a list of the existing docker volumes on the host.

[root@rhel1 ~]# docker volume lsDRIVER VOLUME NAMElocal myhttpd[root@rhel1 ~]#

The only listed volume is the myhttpd volume that you just created.3. Inspect the “myhttpd” volume.

[root@rhel1 ~]# docker volume inspect myhttpd[ { "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/myhttpd/_data", "Name": "myhttpd", "Options": {}, "Scope": "local" }][root@rhel1 ~]#

Notice that the Mountpoint value indicates that this persistent volume maps to the /var/lib/docker/volumes/myhttpd/_data directory on the container host (i.e., on rhel1).

4. List the contents of the Mountpoint directory on rhel1.

[root@rhel1 ~]# ls /var/lib/docker/volumes/myhttpd/_data[root@rhel1 ~]#

Observe that the directory is empty, meaning the persistent volume does not currently contain any files.5. You have created a persistent volume, but as of yet that volume is not associated with any container.

Create a new “my_www” container that has the “myhttpd” volume attached as /usr/local/apache2/htdocs.

[root@rhel1 ~]# docker run -d --name my_www -v myhttpd:/usr/local/apache2/htdocs -p 80:80 httpd:2.28d5ecd4a87d2007d348a8dee163cd938aaa5e96de80f862ebf627ec86dbdda78[root@rhel1 ~]#

6. Inspect the “my_www” container you just created.

[root@rhel1 ~]# docker inspect my_www[ { "Id": "8d5ecd4a87d2007d348a8dee163cd938aaa5e96de80f862ebf627ec86dbdda78", "Created": "2017-07-17T17:55:02.959586227Z", "Path": "httpd-foreground",

Using NetApp with Docker and Kubernetes20 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

"Args": [], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 22617, "ExitCode": 0, "Error": "", "StartedAt": "2017-07-17T17:55:03.514390958Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:60bc4ccd60d8157c6220ff2171716622d1e7d87d7a2c7e4b890e7e7ed7712288", "ResolvConfPath": "/var/lib/docker/containers/8d5ecd4a87d2007d348a8dee163cd938aaa5e96de80f862ebf627ec86dbdda78/resolv.conf", "HostnamePath": "/var/lib/docker/containers/8d5ecd4a87d2007d348a8dee163cd938aaa5e96de80f862ebf627ec86dbdda78/hostname", "HostsPath": "/var/lib/docker/containers/8d5ecd4a87d2007d348a8dee163cd938aaa5e96de80f862ebf627ec86dbdda78/hosts", "LogPath": "/var/lib/docker/containers/8d5ecd4a87d2007d348a8dee163cd938aaa5e96de80f862ebf627ec86dbdda78/8d5ecd4a87d2007d348a8dee163cd938aaa5e96de80f862ebf627ec86dbdda78-json.log", "Name": "/my_www", "RestartCount": 0, "Driver": "devicemapper", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": [ "myhttpd:/usr/local/apache2/htdocs" ], "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": { "80/tcp": [ { "HostIp": "", "HostPort": "80" } ] }, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ],

Using NetApp with Docker and Kubernetes21 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

"Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": null, "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DiskQuota": 0, "KernelMemory": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": -1, "OomKillDisable": false, "PidsLimit": 0, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0 }, "GraphDriver": { "Data": { "DeviceId": "155", "DeviceName": "docker-253:1-998953-f1b867a4e9892a782c9eaa6ba5309114b1d7f7f01f36ec24ca01141de4529e11", "DeviceSize": "107374182400" }, "Name": "devicemapper" }, "Mounts": [ { "Type": "volume", "Name": "myhttpd", "Source": "/var/lib/docker/volumes/myhttpd/_data", "Destination": "/usr/local/apache2/htdocs", "Driver": "local", "Mode": "z", "RW": true, "Propagation": "" } ], "Config": { "Hostname": "8d5ecd4a87d2", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "80/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HTTPD_PREFIX=/usr/local/apache2", "HTTPD_VERSION=2.2.34", "HTTPD_SHA1=829206394e238af0b800fc78d19c74ee466ecb23", "HTTPD_BZ2_URL=https://www.apache.org/dyn/closer.cgi?action=download&filename=httpd/httpd-2.2.34.tar.bz2", "HTTPD_ASC_URL=https://www.apache.org/dist/httpd/httpd-2.2.34.tar.bz2.asc", "HTTPD_BZ2_FALLBACK_URL=https://archive.apache.org/dist/httpd/httpd-2.2.34.tar.bz2", "HTTPD_ASC_FALLBACK_URL=https://archive.apache.org/dist/httpd/httpd-2.2.34.tar.bz2.asc" ],

Using NetApp with Docker and Kubernetes22 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

"Cmd": [ "httpd-foreground" ], "ArgsEscaped": true, "Image": "httpd:2.2", "Volumes": null, "WorkingDir": "/usr/local/apache2", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "NetworkSettings": { "Bridge": "", "SandboxID": "c155f38da6c52ab901152b1f1538cac571c3bda9c60619e7eb8faa5edaa33c12", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "80/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "80" } ] }, "SandboxKey": "/var/run/docker/netns/c155f38da6c5", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "59d5fe198cea720f8f53cd004831f46112ce163199c55764955a4419c8df0c67", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "282b99e06a54f10067130c09cc046046a48c7aceb65c21f780bd80e4323d6111", "EndpointID": "59d5fe198cea720f8f53cd004831f46112ce163199c55764955a4419c8df0c67", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02" } } } }][root@rhel1 ~]#

The output is lengthy, as it provides a lot of detail about the container's configuration. Specifically lookfor the “Mounts” section, which describes any volumes which are associated with the container, includingtheir names, paths on the local host, and mount points. This information is useful if you have a containerthat is already running (perhaps started by someone else), and you want to know what resources thecontainer is using.

7. On Jumphost, refresh the Firefox browser to display http://rhel1.demo.netapp.com.

Using NetApp with Docker and Kubernetes23 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

7

Figure 3-10:

The browser will display the standard Apache “It works!” page.8. Create a new default web page for the container's web server. Start by initiating an interactive CLI

session to the “my_www” container.

[root@rhel1 ~]# docker exec -it my_www /bin/bashroot@8d5ecd4a87d2:/usr/local/apache2#

9. Your CLI session is now operating inside the container, with a current working directory of /usr/local/apache2. Change to the htdocs subdirectory so that you are working inside the web server's documentroot directory, and then list the directory's contents.

root@8d5ecd4a87d2:/usr/local/apache2# lsbin cgi-bin error icons logs manual srcbuild conf htdocs include man modulesroot@8d5ecd4a87d2:/usr/local/apache2# cd htdocsroot@8d5ecd4a87d2:/usr/local/apache2/htdocs# ls index.htmlroot@8d5ecd4a87d2:/usr/local/apache2/htdocs#

The directory now contains an index.html file that was automatically created as part of the container'sinstantiation.

10. Display the index.html file's contents.

root@8d5ecd4a87d2:/usr/local/apache2/htdocs# cat index.html<html><body><h1>It works!</h1></body></html>root@8d5ecd4a87d2:/usr/local/apache2/htdocs#

It contains Apache's default “It works!” page content.11. Overwrite the existing index.html file with a new customized one.

root@8d5ecd4a87d2:/usr/local/apache2/htdocs# echo '<h1>This is a persistent page!</h1>' > index.htmlroot@8d5ecd4a87d2:/usr/local/apache2/htdocs# lsroot@8d5ecd4a87d2:/usr/local/apache2/htdocs# cat index.html

Using NetApp with Docker and Kubernetes24 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

<h1>This is a persistent page!</h1>

If your index.html file content does match what is displayed in this example, fix it before you move on.12. Exit from the container shell.

root@8d5ecd4a87d2:/usr/local/apache2/htdocs# exitexit[root@rhel1 ~]#

13. On Jumphost, refresh the Firefox browser page for http://rhel1.demo.netap.com.

13

Figure 3-11:

Notice that the page now displays “This is a persistent page!”14. Imagine that an update to Apache has been released and you need to refresh your container. Begin by

stopping and deleting the existing “my_www”container.

[root@rhel1 ~]# docker stop my_www && docker rm my_wwwmy_wwwmy_www[root@rhel1 ~]#

15. Recall from step 3 that the persistent volume is stored at /var/lib/docker/volumes/myhttp/_data.Examine the contents of the this directory again from rhel1.

[root@rhel1 ~]# ls -l /var/lib/docker/volumes/myhttpd/_datatotal 4-rw-r--r-- 1 1001 1001 36 Jul 17 18:07 index.html[root@rhel1 ~]# cat /var/lib/docker/volumes/myhttpd/_data/index.html<h1>This is a persistent page!</h1>[root@rhel1 ~]#

Your updated index.html file is still there and intact!16. Create a new container that utilizes the updated Apache image.

[root@rhel1 ~]# docker run -d --name my_www -v myhttpd:/usr/local/apache2/htdocs -p 80:80 httpd:latest3feb39591500876e8df03f8a392ecd4f89994e64fef944435554915554d7842b

Using NetApp with Docker and Kubernetes25 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

[root@rhel1 ~]#

Observe that in this container instantiation command you are attaching the same “myhttpd” volume thatwas connected to the original container.

17. On Jumphost, refresh the Firefox browser page for http://rhel1.demo.netapp.com.

17

Figure 3-12:

Your browser displays your customized “This is a persistent page!” web page, meaning that yourupdated container is now serving out your web content.

Now clean up after this exercise in order to remove conflicts that will interfere with later exercises.18. Stop and remove the “my_www” container.

[root@rhel1 ~]# docker stop my_www && docker rm my_wwwmy_wwwmy_www[root@rhel1 ~]#

19. Verify that the container has been removed.

[root@rhel1 ~]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES[root@rhel1 ~]#

20. Delete the “myhttpd” volume.

[root@rhel1 ~]# docker volume rm myhttpdmyhttpd[root@rhel1 ~]#

21. Verify that the volume has been removed.

[root@rhel1 ~]# docker volume lsDRIVER VOLUME NAME[root@rhel1 ~]#

Using NetApp with Docker and Kubernetes26 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

Leave your PuTTY session to rhel1 open, as you will be using it again in later exercises.

3.3 Explore Container Volumes Hosted on ONTAP StorageUsing ONTAP to host persistent container data is much more valuable than using local storage on the containerhost, as it allows the container volumes to be easily moved from host to host by simply mounting the exportedvolume.

This activity makes use of a pre-created Storage Virtual Machine (SVM) named “svm1” that resides on the lab'sincluded ONTAP storage cluster. This SVM hosts a FlexVol named “www” that you will be accessing over NFSfrom several of the lab's Red Hat Enterprise Linux hosts. The “www” volume will serve as the document root forthe apache containers that you will be creating.

1. In your PuTTY session to rhel1, create a new directory under the root's home directory that will serve asan NFS mount point.

[root@rhel1 ~]# cd[root@rhel1 ~]# pwd/root[root@rhel1 ~]# lssc_412[root@rhel1 ~]# mkdir www[root@rhel1 ~]# lssc_412 www[root@rhel1 ~]#

2. NFS mount the svm1:/www volume on the newly created mountpoint.

[root@rhel1 ~]# mount svm1:/www /root/www[root@rhel1 ~]#

Tip: This mount request may take up to a minute to complete. In RHEL7, Red Hat adoptedsystemctl to start services, and under this system the nfs client services are started dynamicallyat first mount rather than at boot time. This approach introduces a rather lengthy delay the firsttime you mount an NFS volume after boot (while you wait for those services to start). Subsequentmount requests will be much faster, regardless of the server you are mounting from, so long asyou do not reboot the RHEL client.

3. Change directory into the newly-mounted NFS volume and list it's contents.

[root@rhel1 ~]# cd www[root@rhel1 www]# ls[root@rhel1 www]#

The underlying NFS volume is empty, so the directory list command does not report any files.4. Create a new default web page file in this folder. This web page will be leveraging dynamic content

through PHP, so the file will be named index.php.

[root@rhel1 www]# echo 'The hostname is <?php echo gethostname(); ?>' > index.php[root@rhel1 www]# ls -ltotal 4-rw-r--r-- 1 root root 45 Jul 17 18:56 index.php[root@rhel1 www]# cat index.phpThe hostname is <?php echo gethostbyname(); ?>[root@rhel1 www]#

5. Start a new php container using the mounted NetApp volume as a container volume.

[root@rhel1 www]# docker run -d --name my_php -v /root/www:/var/www/html -p 80:80 php:5.5-apacheUnable to find image 'php:5.5-apache' locally5.5-apache: Pulling from library/php357ea8c3d80b: Pull complete85537f80f73d: Pull complete3d821ad560e1: Pull completeb4ae91aad522: Pull complete66e1c1a53c95: Pull complete

Using NetApp with Docker and Kubernetes27 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

5d1f306a8912: Pull complete37733078a51e: Pull completec5351b4d6bee: Pull complete4f946c4dcbe2: Pull complete0c48c69d4b11: Pull completedbc71ed1796a: Pull complete9c6d026ad711: Pull complete3fced1e5eb8f: Pull completeDigest: sha256:be7f9332d3bea49084d74a0718a5400f7b5d128c1937575e76f72df3a41e8eacStatus: Downloaded newer image for php:5.5-apache12befac27a95c0270c519f0ebbe57876744b77247f23ab5c5349cc8e742ccc3e[root@rhel1 www]#

The -v option in the docker run command indicates that a volume path on the underlying host should bemounted in the container. In this example, the ~/www volume on rhel1 is to be mounted in the containeras /var/www/html.

6. Make note of the new container's ID.

[root@rhel1 www]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESf82fb60badcb php:5.5-apache "apache2-foreground" 12 seconds ago Up 11 seconds 0.0.0.0:80->80/tcp my_ph 0.0.0.0:80->80/tcp my_php[root@rhel1 www]#

In this example the new container's ID is 5bd4b3a934fb. The container ID shown in your lab will bedifferent.

7. On Jumphost, refresh the web page for http://rhel1.demo.netapp.com.

7

Figure 3-13:

The page displays the hostname of the container, which should match the container name you saw inthe “docker ps” output in your lab. Most significantly, the hostname shown in your browser is not “rhel1”,the name of the host executing the container, but rather the container ID!

8. On rhel1, append some additional static content to your index.php file.

[root@rhel1 www]# echo

Using NetApp with Docker and Kubernetes28 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

'<h2>This line is the same regardless of the serving container!</h2>' >> index.php[root@rhel1 www]# cat index.phpThe hostname is <?php echo gethostname(); ?><h2>This line is the same regardless of the serving container!</h2>[root@rhel1 www]#ls -ltotal 4-rw-r--r-- 1 root root 113 Jul 17 19:05 index.php[root@rhel1 www]#

Notice that in this step you are modifying the data in the mounted directory on the underlying containerhost (in this case from rhel1) rather than from inside the container instance.

9. On Jumphost, refresh the Firefox page for http://rhel1.demo.netapp.com.

9

Figure 3-14:

The browser display updates to show the new page content you added.10. On the taskbar on Jumphost, right click on the PuTTY icon.11. Select PuTTY from the context menu.

Using NetApp with Docker and Kubernetes29 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

11

10

Figure 3-15:

12. In the saved sessions list, double click on rhel2, and log in as the user root, with the passwordNetapp1!.

12

Figure 3-16:

Using NetApp with Docker and Kubernetes30 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

13. Create a new directory that you will use to mount the same NFS volume you mounted on rhel1, but putthat new directory in a different location than you used on rhel1.

[root@rhel2 ~]# ls /mnthgfs[root@rhel2 ~]# mkdir /mnt/www[root@rhel2 ~]#

14. NFS mount the svm1:/www volume on the newly created mountpoint.

[root@rhel2 ~]# mount svm1:/www /mnt/www[root@rhel2 ~]# ls -l /mnt/wwwtotal 4-rw-r--r-- 1 root root 113 Jul 17 19:05 index.php[root@rhel2 ~]#

Tip: Since this is your first NFS mount attempt on rhel2, this mount may take about a minute tocomplete, too.

Observe that this is a different NFS mount path for the www volume than you used on rhel1.15. Create a new container on rhel2 that utilizes the newly-mounted NFS volume.

[root@rhel2 ~]# docker run -d --name my_php -v /mnt/www:/var/www/html -p 80:80 php:5.5-apacheUnable to find image 'php:5.5-apache' locally5.5-apache: Pulling from library/php357ea8c3d80b: Pull complete85537f80f73d: Pull complete3d821ad560e1: Pull completeb4ae91aad522: Pull complete66e1c1a53c95: Pull complete5d1f306a8912: Pull complete37733078a51e: Pull completec5351b4d6bee: Pull complete4f946c4dcbe2: Pull complete0c48c69d4b11: Pull completedbc71ed1796a: Pull complete9c6d026ad711: Pull complete3fced1e5eb8f: Pull complete1BDigest: sha256:be7f9332d3bea49084d74a0718a5400f7b5d128c1937575e76f72df3a41e8eacStatus: Downloaded newer image for php:5.5-apachea513855a9464d122f0d22ff0f7489f59ee99224ab75dcd228739493456a3f917[root@rhel2 ~]#

Docker accounts for the different NFS mount path on this container through a corresponding change invalue supplied to the docker run command's -v option.

16. Display a list of the running containers.

[root@rhel2 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES9d24838e0411 php:5.5-apache "apache2-foreground" 57 seconds ago Up 55 seconds 0.0.0.0:80->80/tcp my_phpffe2054a9068 quay.io/coreos/flannel "/bin/sh -c 'set -..." 3 days ago Up 3 days k8s_install-cni_kube-flannel-ds-sl8n9_kube-system_f01b458b-2eaf-11e7-be31-0050560102bd_2663ed9a760f6 quay.io/coreos/flannel "/opt/bin/flanneld..." 3 days ago Up 3 days k8s_kube-flannel_kube-flannel-ds-sl8n9_kube-system_f01b458b-2eaf-11e7-be31-0050560102bd_338d6dba1c815 gcr.io/google_containers/kube-proxy-amd64 "/usr/local/bin/ku..." 3 days ago Up 3 days k8s_kube-proxy_kube-proxy-lddvh_kube-system_f01b2ff5-2eaf-11e7-be31-0050560102bd_2a7d1d7073a58 gcr.io/google_containers/pause-amd64:3.0 "/pause" 3 days ago Up 3 days k8s_POD_kube-flannel-ds-sl8n9_kube-system_f01b458b-2eaf-11e7-be31-0050560102bd_2d8a8e3c21e52 gcr.io/google_containers/pause-amd64:3.0 "/pause" 3 days ago Up 3 days k8s_POD_kube-proxy-lddvh_kube-system_f01b2ff5-2eaf-11e7-be31-0050560102bd_2[root@rhel2 ~]#

The output here is a bit hard to follow because there are a number of other containers running on thishost in addition to the one you just created. It would be nice if you could restrict the output to only thecontainer you just created...

Using NetApp with Docker and Kubernetes31 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

17. List only the most recently created container.

[root@rhel2 ~]# docker ps -lCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES9d24838e0411 php:5.5-apache "apache2-foreground" 5 minutes ago Up 5 minutes 0.0.0.0:80->80/tcp my_php]0;root@rhel2:~[root@rhel2 ~]#

You may have noticed that the “my_php” name you used for this container is the same value that youused for the container you created earlier in this exercise on rhel1. You can have containers that usethe same name as long as they are running on different hosts.

18. On Jumphost, open another new tab in Firefox.19. Browse to the URL http://rhel2.demo.netapp.com.

18

19

Figure 3-17:

If you compare this tab to the one you opened for rhel1, you will notice that the pages look mostly thesame, the key difference being that each displays a different container ID (as these two pages arebeing served out by different containers).

20. On rhel2, stop and remove the my_php container.

[root@rhel2 ~]# docker stop my_php && docker rm my_phpmy_phpmy_php[root@rhel2 ~]#

21. On rhel1, stop and remove the my_php container.

[root@rhel1 ~]# docker stop my_php && docker rm my_phpmy_phpmy_php[root@rhel1 ~]#

22. Leave your PuTTY sessions to rhel1 and rhel2 open, as you will need them again in the next exercise.

Using NetApp with Docker and Kubernetes32 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

3.4 Create Containers using the NetApp Docker Volume Plugin (nDVP)Docker volumes provide a convenient way to create and consume persistent storage that is decoupled from anindividual container instance. But Docker volumes are also limited to just a single host, so they do not providehigh availability or data protection, and offer limited performance. Using persistent storage from an enterprisestorage system, such as ONTAP, SolidFire, or E-Series, is a great way to improve all of these characteristicsof the persistent storage. However, manually provisioning and attaching storage resources to the host is stillcumbersome at best.

To make this process easier, NetApp has created a Docker Volume Plugin to integrate with Docker’s commandline volume interface. This greatly simplifies consuming storage from the NetApp portfolio, allowing the Dockeruser to create and connect to volumes using the same syntax and commands they use with local volumes. Thisactivity demonstrates how easy it is to consume storage from ONTAP, and includes how to seamlessly, andeffortlessly use the same volume from multiple hosts.

1. In your PuTTY session to rhel1, display a list of the installed docker plugins.

[root@rhel1 ~]# cd[root@rhel1 ~]# docker plugin lsID NAME DESCRIPTION ENABLED[root@rhel1 ~]#

Note that there are no plugins currently running.2. In order to create an instance of the nDVP managed plugin you need to have a suitable plugin

configuration file under the /etc/netappdvp directory. The default filename for this file is “config.json”, butyou could use a different filename instead. Rhel1 includes a preconfigured /etc/netappdvp/config.json filefor your convenience.

[root@rhel1 ~]# ls -l /etc/netappdvptotal 4-rw-r--r-- 1 root root 183 Jul 28 23:53 config.json[root@rhel1 ~]# cat /etc/netappdvp/config.json{ "version": 1, "storageDriverName": "ontap-nas", "managementLIF": "192.168.0.131", "svm": "svm1", "username": "vsadmin", "password": "Netapp1!", "aggregate": "aggr1"}[root@rhel1 ~]#

This file contains definitions for what storage driver the plugin instance should use (NAS vs SAN). It alsocontains the name of Storage Virtual Machine (SVM) and aggregate that should host any volumes themanaged plugin instance winds up provisioning, along with the management IP address and credentialsneeded to access the NetApp storage system during volume provisioning.

Observe that the username listed in this file is not the cluster administrator user account, but ratheran administrative user account for a specific Storage Virtual Machine (SVM). While you could use thecluster administration account with nDVP, we recommend against doing so. Likewise, the ManagementLIF address is the address of the svm1 SVM's management LIF, not the cluster management LIF.

3. Create an instance of the nDVP managed plugin, and name it “netapp”.

[root@rhel1 ~]# docker plugin install netapp/ndvp-plugin:17.07 --alias netapp --grant-all-permissions17.07: Pulling from netapp/ndvp-plugin

9d55698a43fb: Download completeDigest: sha256:561da74049eaaba092c3686111eda7afbd82c6f07a04f05e77c66d305c4d4132Status: Downloaded newer image for netapp/ndvp-plugin:17.07Installed plugin netapp/ndvp-plugin:17.07[root@rhel1 ~]#

This command will utilize the default /etc/netappdvp/config.json managed plugin configuration file.

Using NetApp with Docker and Kubernetes33 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

4. List the installed docker plugins again.

[root@rhel1 ~]# docker plugin lsID NAME DESCRIPTION ENABLED761bdd9a7fde netapp:latest nDVP - NetApp Docker Volume Plugin true[root@rhel1 ~]#

The output shows that a managed plugin instance named “netapp” is available.5. Display a list of the current Docker volumes.

[root@rhel1 ~]# docker volume lsDRIVER VOLUME NAME[root@rhel1 ~]#

There are no docker volumes currently defined.6. Create a new 10 GB persistent volume named “my_data” on the NetApp cluster using nDVP.

[root@rhel1 ~]# docker volume create -d netapp --name my_data -o size=10gmy_data[root@rhel1 ~]#

The “-d netapp” option tells Docker to use the managed plugin instance you created earlier. This valuemust match the alias assigned when instantiating the managed plugin instance.

7. Re-display the list of the current Docker volumes, that now shows the “my_data” volume you justcreated.

[root@rhel1 ~]# docker volume lsDRIVER VOLUME NAMEnetapp:latest my_data[root@rhel1 ~]#

8. Inspect the details for the my_data volume.

[root@rhel1 ~]# docker volume inspect my_data[ { "Driver": "netapp:latest", "Labels": {}, "Mountpoint": "/var/lib/docker/plugins/761bdd9a7fdee39599bddcede08a340913e698fd3b413ed18523b7bf14452568/rootfs", "Name": "my_data", "Options": { "size": "10g" }, "Scope": "global", "Status": { "Snapshots": null } }][root@rhel1 ~]#

Note the “Options” and “Status” fields. Options represents any creation time options that were passed tothe volume. Status will show any snapshots that have been created on the volume by the storage systemwhen using ONTAP or SolidFire.

You provisioned this volume from the NetApp storage without directly touching the NetApp storagesystem. In other words, your docker users can provision NetApp storage directly from the docker CLI,without the involvement of a storage administrator! Take a moment to examine how this volume wasprovisioned on the ONTAP cluster before moving on the utilize this volume from Docker.

9. On the taskbar of Jumphost, right-click on the PuTTY icon.10. Select PuTTY from the context menu.

Using NetApp with Docker and Kubernetes34 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

9

10

Figure 3-18:

11. Double-click the saved session for svm1 (you will need to scroll down in the Saved Sessions listto see it). This will launch an ssh session to the svm1 SVM's management CLI, which allows you toonly manage storage that belongs to the svm1 SVM. Log in as the user vsadmin, with the passwordNetapp1!.

Using NetApp with Docker and Kubernetes35 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

11

Figure 3-19:

12. List the volumes that are present in this SVM.

svm1::> volume showVserver Volume Aggregate State Type Size Available Used%--------- ------------ ------------ ---------- ---- ---------- ---------- -----svm1 netappdvp_my_data aggr1 online RW 10GB 9.50GB 5%svm1 registry aggr1 online RW 20GB 19.82GB 0%svm1 svm1_root aggr1 online RW 20MB 18.24MB 8%svm1 trident_trident aggr1 online RW 1.86GB 1.77GB 5%svm1 www aggr1 online RW 5GB 5.00GB 0%5 entries were displayed.

svm1::>

The netappdvp_my_data volume is the volume you just created using the managed plugin.13. Show the namespace junction points for these volumes.

svm1::> volume show -junction Junction JunctionVserver Volume Language Active Junction Path Path Source--------- ------------ -------- -------- ------------------------- -----------svm1 netappdvp_my_data C.UTF-8 true /netappdvp_my_data RW_volumesvm1 registry C.UTF-8 true /registry RW_volumesvm1 svm1_root C.UTF-8 true / -svm1 trident_trident C.UTF-8 true /trident_trident RW_volumesvm1 www C.UTF-8 true /www RW_volume5 entries were displayed.

svm1::>

Using NetApp with Docker and Kubernetes36 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

The my_data volume is junctioned as /netappdvp_my_data.14. Terminate the PuTTY session to svm1.

svm1::> exit

15. Return to your PuTTY session to rhel1 and list the containers on the host.

[root@rhel1 ~]# docker ps -a[root@rhel1 ~]#

16. Provision a new container using the busybox image. Name the container “mycont”, connect themy_data volume to it, and launch an interactive shell inside the container.

[root@rhel1 ~]# docker run -it --name mycont -v my_data:/data busybox /bin/shUnable to find image 'busybox:latest' locallylatest: Pulling from library/busybox9e87eff13613: Pull completeDigest: sha256:2605a2c4875ce5eb27a9f7403263190cd1af31e48a2044d400320548356251c4Status: Downloaded newer image for busybox:latest#

17. Verify that the my_data volume is mounted inside the container.

# mount | grep my_data192.168.0.132:/netappdvp_my_data on /data type nfs (rw,relatime,vers=3,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=192.168.0.132,mountvers=3,mountport=635,mountproto=udp,local_lock=none,addr=192.168.0.132)#

Notice that the my_data volume has been mounted at “/data”, and the output shows the NFS LIF andvolume junction from the ONTAP system.

18. Create a test file inside the volume.

# date > /data/test.txt# ls -l /data/test.txt-rw-r--r-- 1 root root 29 Jul 29 23:43 /data/test.txt# cat /data/test.txtSat Jul 29 23:44:30 UTC 2017#

The test file's contents are a timestamp from when you created the file.19. Exit the container.

# exit[root@rhel1 ~]#

20. List the containers on rhel1.

[root@rhel1 ~]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES732bca0f4d9c busybox "/bin/sh" 2 minutes ago Exited (0) 15 seconds ago mycont[root@rhel1 ~]#

Note the presence of the newly created “mycont” container.21. Remove the container and confirm its deletion.

[root@rhel1 ~]# docker rm mycontmycont[root@rhel1 ~]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES[root@rhel1 ~]#

Using NetApp with Docker and Kubernetes37 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

22. Switch to your PuTTY session for rhel2. If you previously closed it, open it again and log in as the userroot, with the password Netapp1!.

Figure 3-20:

23. List the docker plugins installed on rhel2.

[root@rhel2 ~]# docker plugin lsID NAME DESCRIPTION ENABLEDf331da35444f netapp:latest nDVP - NetApp Docker Volume Plugin true[root@rhel2 ~]#

The “netapp” managed plugin instance is pre-configured for you on rhel2.24. Display the list of Docker volumes.

[root@rhel2 ~]# docker volume lsDRIVER VOLUME NAMEnetapp:latest my_data[root@rhel2 ~]#

Notice that the volume you created on rhel1 is automatically available on rhel2.25. Create a new container named “mycont2”on rhel2 that uses the my_data volume. As before, the new

container will be based on the busybox image, and you will launch an interactive shell inside it,

[root@rhel2 ~]# docker run -it --name mycont2 -v my_data:/data busybox /bin/shUnable to find image 'busybox:latest' locallylatest: Pulling from library/busybox

9e87eff13613: Pull completeDigest: sha256:2605a2c4875ce5eb27a9f7403263190cd1af31e48a2044d400320548356251c4Status: Downloaded newer image for busybox:latest#

26. Verify the test.txt file you created from the old “mycont” container is intact from the mycont2 container.

# ls -l /datatotal 0-rw-r--r-- 1 root root 29 Jul 29 23:43 test.txt# cat /data/testSat Jul 29 23:44:30 UTC 2017#

Significantly, because this is an NFS volume, if both containers were still running they could bothaccess this volume simultaneously if desired.

27. Exit the container.

# exit[root@rhel2 ~]#

28. Remove the mycont2 container.

[root@rhel2 ~]# docker rm mycont2mycont2[root@rhel2 ~]#

29. Remove the my_data volume and verify it's deletion.

[root@rhel2 ~]# docker volume rm my_datamy_data[root@rhel2 ~]# docker volume lsDRIVER VOLUME NAME[root@rhel2 ~]#

Leave your PuTTY sessions for rhel1 and rhel2 open as you will need them again in the next exercise.

Using NetApp with Docker and Kubernetes38 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

3.5 Creating a Custom Container ImageThere are two ways to create a custom container image. The first is to take an existing image, modify it, and thenpush it into the registry. The second is to build an image using a Dockerfile, then push to the registry.

In this activity you explore both techniques.

1. Switch to your PuTTY session for rhel1.2. Instantiate the new httpd container instance that you will customize.

[root@rhel1 ~]# docker run -d --name my_custom_httpd httpd:latesta0b9d8c605af0f17fff469d1486f534384a37458dd87856142167922ad092b11[root@rhel1 ~]#

3. Establish an interactive CLI session into the container, create a new index.html file for the container'sweb server, and then end the CLI session.

[root@rhel1 ~]# docker exec -it my_custom_httpd /bin/bashroot@a0b9d8c605af:/usr/local/apache2# echo '<h1>My customized Apache page</h1>' > htdocs/index.htmlroot@a0b9d8c605af:/usr/local/apache2# cat htdocs/index.html<h1>My customized Apache page</h1>root@a0b9d8c605af:/usr/local/apache2# exitexit[root@rhel1 ~]#

4. Verify that the container is still running.

[root@rhel1 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa0b9d8c605af httpd:latest "httpd-foreground" About a minute ago Up About a minute 80/tcp my_custom_httpd[root@rhel1 ~]#

5. Stop the “my_custom_httpd” container.

[root@rhel1 ~]# docker stop my_custom_httpdmy_custom_httpd[root@rhel1 ~]#

6. Display a list of all the containers on the host, including those that are not running.

[root@rhel1 ~]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa0b9d8c605af httpd:latest "httpd-foreground" 2 minutes ago Exited (0) 5 seconds ago my_custom_httpd[root@rhel1 ~]#

7. Commit the changes you just made to the “my_custom_httpd” image.

[root@rhel1 ~]# docker commit my_custom_httpd registry.demo.netapp.com/my_custom_httpd:latestsha256:f31d8acde9d954081be51c5f42601f174fccf1494588ca364c70cce8e02fb570[root@rhel1 ~]#

When you commit the container you are preserving its state so that it can be re-used to instantiate othercontainers. On a commit operation, Docker creates a new local image, but only stores the differencesbetween the container's source image and the container's current state.

8. Generate a list of the local images.

[root@rhel1 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEregistry.demo.netapp.com/my_custom_httpd latest f31d8acde9d9 28 seconds ago 177MBbusybox latest efe10ee6727f 4 days ago 1.13MBhttpd latest e0ceae115daa 12 days ago 177MB

Using NetApp with Docker and Kubernetes39 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

httpd 2.2 60bc4ccd60d8 13 days ago 171MBphp 5.5-apache ea0a3d41ce6c 11 months ago 390MB[root@rhel1 docker]#

Note the repository name for the newly committed image, “registry.demo.netapp.com/my_custom_image”. By default the docker command assumes commits are supposed to go tothe main docker hub (hub.docker.com), but this lab exercise utilizes a local docker registry server(registry.demo.netapp.com, which is an alias for rhel4).

9. Push the new “my_custom_httpd” image to the registry server so that server can offer the image to otherusers and registry servers.

[root@rhel1 ~]# docker push registry.demo.netapp.com/my_custom_httpdThe push refers to a repository [registry.demo.netapp.com/my_custom_httpd]a7090b99c87f: Pushedde872627d7a1: Pushedcf8213cf12e6: Pushedca4b576930e7: Pushed27c884880e0f: Pushed4cea9efa0efd: Pushed88100ed9d5fc: Pushed0d960f1d4fba: Pushedlatest: digest: sha256:cab448f29c3af040dc69a7243f38690987c19875a68f48974a6a797d9e96547e size: 1987[root@rhel1 ~]#

10. Switch to your PuTTY session for rhel2.11. Pull a copy of the my_custom_httpd image from the registry server to the local host.

[root@rhel2 ~]# docker pull registry.demo.netapp.com/my_custom_httpdUsing default tag: latestlatest: Pulling from my_custom_httpd9f0706ba7422: Pull complete47bacf36113f: Pull complete56798d8e5a30: Pull complete27db250fa75b: Pull completece9c5765af5f: Pull complete5b5660aa17c6: Pull complete772197068420: Pull complete4a3d5e65398f: Pull completelatest: digest: sha256:cab448f29c3af040dc69a7243f38690987c19875a68f48974a6a797d9e96547eStatus: Downloaded newer image for registry.demo.netapp.com/my_custom_httpd:latest[root@rhel2 ~]#

12. Instantiate a new container from this image.

[root@rhel2 ~]# docker run -d -p 80:80 registry.demo.netapp.com/my_custom_httpd2403a6a9fb69f346294cf9e9272f3e3d6130dbcf42068557e4cac3c6e15e9950[root@rhel2 ~]#

Tip: You may have noticed that you did not use the --name option here to specify a name forthis container. In this situation docker assigns the container a name using a combination ofrandom words. Issue the docker ps command in your lab to see what name docker assigned toyour container instance.

13. On Jumphost, refresh the web page for http://rhel2.demo.netapp.com.

Using NetApp with Docker and Kubernetes40 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

13

Figure 3-21:

The web page published by rhel2 matches the customized web page you included in the customizedcontainer image you created from rhel1.

14. Exit your PuTTY session to rhel2, as you will no longer need it.

[root@rhel2 ~]# exit

Next you will build an image using a Dockerfile. A Dockerfile contains a set of instructions on how tobuild new images, and the docker build command executes those instructions. Dockerfiles offer a morerobust way to build images because they document and automate the build process, which makes iteasier to share image development processes among a team.

15. On rhel1, create a temporary working directory and cd into it.

[root@rhel1 ~]# mkdir /tmp/custom[root@rhel1 ~]# cd /tmp/custom[root@rhel1 custom]#

16. Create a new index.html file that you will add to the new image you are creating.

[root@rhel1 custom]# echo '<h1>Created by Dockerfile</h1>' > index.html[root@rhel1 custom]#

17. Create a Dockerfile that contains instructions for customizing your image.

[root@rhel1 custom]# echo 'FROM httpd:latest' > Dockerfile[root@rhel1 custom]# echo 'ADD index.html /usr/local/apache2/htdocs/index.html' >> Dockerfile[root@rhel1 custom]# cat DockerfileFROM httpd:latestADD index.html /usr/local/apache2/htdocs/index.html[root@rhel1 custom]#

These instructions indicate that Docker should use the “httpd:latest” image as a starting point, and theninstall the customized index.html file in the image as /usr/local/apache2/htdocs/index.html.

Using NetApp with Docker and Kubernetes41 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

18. Build the customized image.

[root@rhel1 custom]# docker build -t registry.demo.netapp.com/another_custom_httpd /tmp/customSending build context to Docker daemon 3.072kBStep 1/2 : FROM httpd:latest ---> e0ceae115daaStep 2/2 : ADD index.html /usr/local/apache2/htdocs/index.html ---> ccc4fc90c724Removing intermediate container 99a8bcd8ef1eSuccessfully built ccc4fc90c724[root@rhel1 custom]#

19. List the images on this host (rhell1).

[root@rhel1 custom]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEregistry.demo.netapp.com/another_custom_httpd latest ccc4fc90c724 11 seconds ago 177MBregistry.demo.netapp.com/my_custom_httpd latest f31d8acde9d9 About an hour ago 177MBbusybox latest efe10ee6727f 4 days ago 1.13MBhttpd latest e0ceae115daa 13 days ago 177MBhttpd 2.2 60bc4ccd60d8 13 days ago 171MBphp 5.5-apache ea0a3d41ce6c 11 months ago 390MB[root@rhel1 custom]#

Notice the presense of the “another_custom_httpd” image.20. Start a new container based on that image.

[root@rhel1 custom]# docker run -d -p 80:80 registry.demo.netapp.com/another_custom_httpddaf0e905e905dd19f275c2bd32d1db0f04158ff69a64e4597f75d760e46c3b46[root@rhel1 custom]#

21. In Firefox, select the browser tab for rhel1.22. Refresh the browser page, and verify that it displays the “Created by Dockerfile” message as expected.23. Close the browser when finished.

Using NetApp with Docker and Kubernetes42 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

21

22

23

Figure 3-22:

24. Terminate your PuTTY session to rhel1.

[root@rhel1 custom]# exit

Using NetApp with Docker and Kubernetes43 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

4 KubernetesScaling an application beyond the capabilities of a single host can be a complex task when trying to managecontainers solely with Docker. To make this process easier, several container orchestrators have become veryprominent, one of which is Kubernetes. When using Kubernetes, the application developer/admin defines therequirements for a set of containers that need to be interconnected to create the application. This includes notonly the quantity of each container image, but also how they should communicate over the network, and evenwhat storage they need.

Kubernetes' persistent storage paradigm relies on three concepts:

• Persistent Volume (PV): A unit of persistent storage, such as an iSCSI LUN or NFS export, which isintroduced to the Kubernetes cluster.

• Persistent Volume Claim (PVC): A request by an application/user for persistent storage.• Storage Class: A definition of a type of storage, such as “Gold” or “Silver”.

PVCs can be met in one of two ways by the Kubernetes cluster:

1. If an existing PV is waiting and available, it is allocated to the PVC and consumed by the application.2. Otherwise a provisioner, associated with a Storage Class, creates the PV on-demand.

When using NetApp’s portfolio of storage, this on-demand provisioning capability is provided using NetAppTrident, NetApp's open source, external storage provisioner for Kubernetes. Trident integrates with Kubernetesto dynamically create storage, such as NFS exports or iSCSI LUNs, that meets the capabilities outlined in theStorage Class specified by the application. The application team can seamlessly scale and deploy pods acrosshosts in the Kubernetes cluster without having to worry about the underlying storage infrastructure. They simplyuse storage when they need it, where they need it, and how they need it.

4.1 Explore KubernetesThis section of the lab explores the basic functionality of the Kubernetes cluster, including persistent storageusing NetApp Trident.

Kubernetes has several constructs that you will want to be familiar with before continuing with this exercise.

• Pod: A pod describes a unit of deployment for an application or application service (i.e. microservice). Apod consists of one or more containers which are expected to be executed together.

• Deployment: A pod with additional metadata and features, such as the number of replicas whichshould be running at any time. In other words, a deployment is one of the ways to describe anapplication to Kubernetes. For example, a deployment with one replica specified means thatKubernetes will ensure that one instance of the pod is always running somewhere in the cluster.

• Storage Class: Provides an abstract definition of storage. Each storage class has a provisioner andsome number of defined parameters. For NetApp the provisioner is Trident, an open source projectwhich manages the creation and destruction of volumes for ONTAP, SolidFire, and E-Series storagearrays.

• Persistent Volume (PV): A storage device which a container uses to store persistent data. It isdecoupled from the pod and has a lifecycle of its own.

• Persistent Volume Claim (PVC): A user/application creates a PVC to request access to persistentstorage. The PVC describes requirements like the size and type of the required volume, e.g. “I need20 GiB of storage”, which Kubernetes then evaluates against its inventory of available PVs, and itthen assigns one which meets those needs. The application can then utilize the PVC to ensure thatKubernetes mounts the assigned PV to the host which is executing the pod.

If the PVC specifies a storage class, then Kubernetes follows the same process to find a match in theexisting pool of PVs. However, if it can't find a matching PV then Kubernetes will rely on the provisionerspecified in the storage class to create a suitable match.

• Namespace: A namespace is an administrative division of resources in the cluster, providing isolationbetween users, their pods/deployments, and resource assignments.

Using NetApp with Docker and Kubernetes44 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

Trident, NetApp’s software for dynamically provisioning persistent volumes for Kubernetes applications, is itself anapplication deployed to Kubernetes. As you explore Kubernetes in the following exercises and look at its structureand unique nomenclature, you will see objects in the Kubernetes cluster that are part of the Trident applicationinstallation. Specifically, you can expect to see:

• A deployment named “trident”. In this instance, the Trident deployment states that the Kubernetescluster should keep one instance of the Pod “trident” running at all times.

• A pod named “trident”. The “trident” pod consists of two containers: trident-main, which is the Tridentapplication code, and etcd, a distributed key-value store that supports the Trident application and whichpersists its data using a persistent volume.

• A PVC named “trident”, which defines the storage requirements for the Trident application's etcdinstance.

• A persistent volume named “trident”. In this instance, the PV is provisioned from the ONTAP system inthe lab environment.

• Finally, the PV “trident” is associated with the pod “trident”, a component of the deployment “trident”,using a persistent volume claim…also creatively called “trident”.

If that last bit sounds a little tedious, that’s why Trident was created. Rather than manually provisioning a volume(for example, an NFS export, or iSCSI LUN), introducing it as a PV to Kubernetes where it sits waiting, and thenassociate it with an application using a PVC, the whole process is streamlined. The user simply creates a PVCwhich says “I need X amount of capacity using storage class Y”. If “Y” is provisioned by Trident, then Tridentcreates a volume according to the requirements outlined in the storage class definition, and hands it back toKubernetes to be used by the application.

Begin by looking at the Kubernetes cluster deployed in the lab environment.

1. On the taskbar of Jumphost, launch PuTTY.

1

Figure 4-1:

The PuTTY Configuration window opens.2. If the right pane does not contain the header “Basic options for your PuTTY session”, then in the left

pane select the Session category.3. In the right pane, in the “Saved Sessions” list, double-click rhel3.

Using NetApp with Docker and Kubernetes45 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

2

3

Figure 4-2:

A PuTTY teminal session window opens.4. Log in using the username root and the password Netapp1!.

login as: [email protected]'s password: Last login: Sat Jul 29 17:59:20 2017[root@rhel3 ~]#

5. Display a list of the nodes in the cluster.

[root@rhel3 ~]# kubectl get nodesNAME STATUS AGE VERSIONrhel2 Ready 85d v1.6.2rhel3 Ready 88d v1.6.2[root@rhel3 ~]#

As you can see, this is a two node cluster comprised of rhel2 and rhel3.6. Display a summary of the rhel3 node's configuration, resource availability and utilization, any assigned

tags, and more.

[root@rhel3 ~]# kubectl describe node rhel3Name: rhel3Role:Labels: beta.kubernetes.io/arch=amd64 beta.kubernetes.io/os=linux kubernetes.io/hostname=rhel3 node-role.kubernetes.io/master=Annotations: flannel.alpha.coreos.com/backend-data={"VtepMAC":"fe:83:15:e4:ac:ba"} flannel.alpha.coreos.com/backend-type=vxlan flannel.alpha.coreos.com/kube-subnet-manager=true flannel.alpha.coreos.com/public-ip=192.168.0.63

Using NetApp with Docker and Kubernetes46 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

node.alpha.kubernetes.io/ttl=0 volumes.kubernetes.io/controller-managed-attach-detach=trueTaints: <none>CreationTimestamp: Fri, 28 Apr 2017 20:12:14 +0000Phase:Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- OutOfDisk False Wed, 26 Jul 2017 16:30:10 +0000 Fri, 28 Apr 2017 20:12:14 +0000 KubeletHasSufficientDisk kubelet has sufficient disk space available MemoryPressure False Wed, 26 Jul 2017 16:30:10 +0000 Fri, 28 Apr 2017 20:12:14 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Wed, 26 Jul 2017 16:30:10 +0000 Fri, 28 Apr 2017 20:12:14 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure Ready True Wed, 26 Jul 2017 16:30:10 +0000 Fri, 28 Apr 2017 20:13:24 +0000 KubeletReady kubelet is posting ready statusAddresses: 192.168.0.63,192.168.0.63,rhel3Capacity: cpu: 2 memory: 1883996Ki pods: 110Allocatable: cpu: 2 memory: 1781596Ki pods: 110System Info: Machine ID: 447bc68ac2f3494fa211c573ab48e6c8 System UUID: 4218F920-1D51-98AF-8208-9B9DEA6D8D15 Boot ID: fe0a3ae4-7651-41f1-80c3-7842a3eaf845 Kernel Version: 3.10.0-514.el7.x86_64 OS Image: Red Hat Enterprise Linux Server 7.3 (Maipo) Operating System: linux Architecture: amd64 Container Runtime Version: docker://1.12.6 Kubelet Version: v1.6.2 Kube-Proxy Version: v1.6.2PodCIDR: 10.244.0.0/24ExternalID: rhel3Non-terminated Pods: (8 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits --------- ---- ------------ ---------- --------------- ------------- default trident-4219367752-jcckg 0 (0%) 0 (0%) 0 (0%) 0 (0%) kube-system etcd-rhel3 0 (0%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-apiserver-rhel3 250m (12%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-controller-manager-rhel3 200m (10%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-dns-3913472980-s21tz 260m (13%) 0 (0%) 110Mi (6%) 170Mi (9%) kube-system kube-flannel-ds-287nx 0 (0%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-proxy-q1l85 0 (0%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-scheduler-rhel3 100m (5%) 0 (0%) 0 (0%) 0 (0%)Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) CPU Requests CPU Limits Memory Requests Memory Limits ------------ ---------- --------------- ------------- 810m (40%) 0 (0%) 110Mi (6%) 170Mi (9%)Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 25m 25m 1 kubelet, rhel3 Normal Starting Starting kubelet. 25m 25m 1 kubelet, rhel3 Warning ImageGCFailed unable to find data for container / 25m 25m 43 kubelet, rhel3 Normal NodeHasSufficientDisk Node rhel3 status is now: NodeHasSufficientDisk 25m 25m 43 kubelet, rhel3 Normal NodeHasSufficientMemory Node rhel3 status is now: NodeHasSufficientMemory 25m 25m 43 kubelet, rhel3 Normal NodeHasNoDiskPressure Node rhel3 status is now: NodeHasNoDiskPressure

Using NetApp with Docker and Kubernetes47 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

25m 25m 1 kubelet, rhel3 Warning Rebooted Node rhel3 has been rebooted, boot id: fe0a3ae4-7651-41f1-80c3-7842a3eaf845 25m 25m 1 kube-proxy, rhel3 Normal Starting Starting kube-proxy.[root@rhel3 ~]#

7. Display a list of the cluster's namespace.

[root@rhel3 ~]# kubectl get namespaceNAME STATUS AGEdefault Active 88dkube-public Active 88dkube-system Active 88dtrident Active 88d[root@rhel3 ~]#

The Kubernetes services run in the kube-system namespace. The trident service runs in the tridentnamespace. Pods without a specified namespace deploy and run in the default namespace.

8. Display a list of the pods in this cluster running in the trident namespace.

[root@rhel3 ~]# kubectl get pods -n tridentNAME READY STATUS RESTARTS AGEtrident-4219367752-jcckg 2/2 Running 6 88d[root@rhel3 ~]#

At this time there is a single pod running in the trident namespace on this cluster. This pod happens tobe the Trident deployment.

9. List the namespaces for all the pods.

[root@rhel3 ~]# kubectl get pods --all-namespacesNAMESPACE NAME READY STATUS RESTARTS AGE kube-system etcd-rhel3 1/1 Running 3 88dkube-system kube-apiserver-rhel3 1/1 Running 3 88dkube-system kube-controller-manager-rhel3 1/1 Running 3 88dkube-system kube-dns-3913472980-s21tz 3/3 Running 9 88dkube-system kube-flannel-ds-287nx 2/2 Running 7 88dkube-system kube-flannel-ds-sl8n9 2/2 Running 7 85dkube-system kube-proxy-lddvh 1/1 Running 3 85dkube-system kube-proxy-q1l85 1/1 Running 3 88dkube-system kube-scheduler-rhel3 1/1 Running 3 88dtrident trident-4219367752-jcckg 2/2 Running 6 88d[root@rhel3 ~]#

There are many other pods providing services to the Kubernetes cluster.10. Display the deployments for this cluster.

[root@rhel3 ~]# kubectl get deployment -n tridentNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGEtrident 1 1 1 1 88d[root@rhel3 ~]#

There is a single deployment, Trident, running in this cluster. As mentioned earlier, this particulardeployment configuration will make sure that there is always one instance of the “trident” pod running.

11. Display deeper details for the Trident deployment.

[root@rhel3 ~]# kubectl describe deployment tridentName: tridentNamespace: tridentCreationTimestamp: Fri, 28 Apr 2017 20:16:50 +0000Labels: app=trident.netapp.io kubernetes.io/cluster-service=trueAnnotations: deployment.kubernetes.io/revision=1Selector: app=trident.netapp.ioReplicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailableStrategyType: RollingUpdateMinReadySeconds: 0RollingUpdateStrategy: 1 max unavailable, 1 max surgePod Template: Labels: app=trident.netapp.io Service Account: default

Using NetApp with Docker and Kubernetes48 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

Containers: trident-main: Image: netapp/trident:17.04.0 Port: 8000/TCP Command: /usr/local/bin/trident_orchestrator Args: -port 8000 -etcd_v2 http://127.0.0.1:8001 -k8s_pod Environment: <none> Mounts: <none> etcd: Image: quay.io/coreos/etcd:v3.1.3 Port: Command: /usr/local/bin/etcd Args: -name etcd1 -advertise-client-urls http://127.0.0.1:8001 -listen-client-urls http://127.0.0.1:8001 -initial-cluster default=http://127.0.0.1:8002 -initial-advertise-peer-urls http://127.0.0.1:8002 -listen-peer-urls http://127.0.0.1:8002 -data-dir /var/etcd/data -initial-cluster etcd1=http://127.0.0.1:8002 Environment: <none> Mounts: /var/etcd/data from etcd-vol (rw) Volumes: etcd-vol: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: trident ReadOnly: falseConditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailableOldReplicaSets: <none>NewReplicaSet: trident-4219367752 (1/1 replicas created)Events: <none>[root@rhel3 ~]#

The command returns a lot of information, including the pod template used by the deployment, volumesassociated with the pods, the number of replicas, and the name of the replica set.

12. Display a list of the persistent volume claims in the trident namespace.

[root@rhel3 ~]# kubectl get pvc -n tridentNAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGEtrident Bound trident 2Gi RWO 88d[root@rhel3 ~]#

Observe that a single Persistent Volume Claim (PVC) exists. This is the “trident” PVC that supports theTrident application installation. Note that this PVC is being serviced by the volume named “trident”.

13. Display the persistent volumes.

[root@rhel3 ~]# kubectl get pv -n tridentNAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGEtrident 2Gi RWO Retain Bound trident/trident 88d[root@rhel3 ~]#

Using NetApp with Docker and Kubernetes49 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

The “trident' PV is claimed by the PVC identifed as “trident/trident”. This means that the “trident” PVC isrunning in the “trident” namespace.

14. Display details of the persistent volume.

[root@rhel3 ~]# kubectl describe pv tridentName: tridentLabels: app=trident.netapp.ioAnnotations: <none>StorageClass: Status: BoundClaim: trident/tridentReclaim Policy: RetainAccess Modes: RWOCapacity: 2GiMessage: Source: Type: NFS (an NFS mount that lasts the lifetime of a pod) Server: 192.168.0.132 Path: /trident_trident ReadOnly: falseEvents: <none>[root@rhel3 ~]#

The details show, among other things, that the persistent volume is NFS storage, along with the serverand mount path for the export.

4.2 Deploy a POD to the Kubernetes ClusterThis activity demonstrates how to deploy a pre-configured pod within the Kubernetes cluster, and then how todelete it.

1. In your PuTTY session to rhel3, change to the root user's home directory and list the contents of the k8sdirectory.

[root@rhel3 ~]# cd[root@rhel3 ~]# lsk8s sc_412[root@rhel3 ~]# ls k8salpine2.yaml alpine.yaml trident[root@rhel3 ~]#

2. Display the contents of the k8s/apline.yaml file, which contains the configuration definition for the pod.

[root@rhel3 ~]# cat k8s/alpine.yamlapiVersion: v1kind: Podmetadata: name: alpine namespace: defaultspec: containers: - image: alpine:3.2 command: - /bin/sh - "-c" - "sleep 60m" imagePullPolicy: IfNotPresent name: alpine restartPolicy: Always[root@rhel3 ~]#

There are several interesting things in this file.

• The “namespace:” entry indicates that this configuration is for the pod's default namespace.• The file's single “container:” section specifies that this pod only runs a single container.• The “image:” entry indicates that container utilizes the alpine3:2 image.• The “command:” section indicates the command that is to be executed inside the container

when it is started, which in this case is to simply to sleep for 60 minutes.

Using NetApp with Docker and Kubernetes50 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

• The “restartPolicy:” entry is set to “Always”. This means Kubernetes should automaticallyrestart the container in the event something happens to it (for example, the process insidecrashes).

3. Tell Kubernetes to launch the pod.

[root@rhel3 ~]# kubectl create -f k8s/alpine.yamlpod "alpine" created[root@rhel3 ~]#

4. View the status of the pod.

[root@rhel3 ~]# kubectl get pod alpineNAME READY STATUS RESTARTS AGEalpine 1/1 Running 0 11s[root@rhel3 ~]#

5. View details about the pod.

[root@rhel3 ~]# kubectl describe pod alpineName: alpineNamespace: defaultNode: rhel2/192.168.0.62Start Time: Wed, 26 Jul 2017 17:56:46 +0000Labels: <none>Annotations: <none>Status: RunningIP: 10.244.1.2Controllers: <none>Containers: alpine: Container ID: docker://38cdf035c13e5f09fb90f5195105246bc6398ff2c3c7581fe35b25711c6bf50c Image: alpine:3.2 Image ID: docker-pullable://alpine@sha256:19826d59171c2eb7e90ce52bfd822993bef6a6fe3ae6bb4a49f8c1d0a01e99c7 Port: Command: /bin/sh -c sleep 60m State: Running Started: Wed, 26 Jul 2017 17:56:53 +0000 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-jjtqc (ro)Conditions: Type Status Initialized True Ready True PodScheduled True Volumes: default-token-jjtqc: Type: Secret (a volume populated by a Secret) SecretName: default-token-jjtqc Optional: falseQoS Class: BestEffortNode-Selectors: <none>Tolerations: node.alpha.kubernetes.io/notReady=:Exists:NoExecute for 300s node.alpha.kubernetes.io/unreachable=:Exists:NoExecute for 300sEvents: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 29s 29s 1 default-scheduler Normal Scheduled Successfully assigned alpine to rhel2 28s 28s 1 kubelet, rhel2 spec.containers{alpine} Normal Pulling pulling image "alpine:3.2" 22s 22s 1 kubelet, rhel2 spec.containers{alpine} Normal Pulled Successfully pulled image "alpine:3.2" 22s 22s 1 kubelet, rhel2 spec.containers{alpine} Normal Created Created container with id 38cdf035c13e5f09fb90f5195105246bc6398ff2c3c7581fe35b25711c6bf50c

Using NetApp with Docker and Kubernetes51 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

22s 22s 1 kubelet, rhel2 spec.containers{alpine} Normal Started Started container with id 38cdf035c13e5f09fb90f5195105246bc6398ff2c3c7581fe35b25711c6bf50c[root@rhel3 ~]#

The describe command returns back a substantial amount of information about the containers in thepod, including the internal IP address(es), the node(s) used for execution, and a log of events associatedwith the containers. If any errors occur during container instantiation, they will be listed in the “Events:”section of the output as well.

6. Destroy the pod.

[root@rhel3 ~]# kubectl delete pod alpinepod "alpine" deleted[root@rhel3 ~]#

4.3 Create a Persistent Volume on ONTAP using TridentWith Trident you request the creation of a Persistent Volume (PV) by submitting a Persistent Volume Claim(PVC). The details of the PVC identify the desired storage class. Of course, to construct a PVC you must knowwhat configured storage classes are available, so the first order of business is to query Kubernetes for thatinformation.

1. Still using your PuTTY session to rhel3 from the previous exercises, display the storage classesregistered in the namespace.

[root@rhel3 ~]# kubectl get scNAME TYPEnfs netapp.io/trident [root@rhel3 ~]#

The output indicates that there is only a single storage class named “nfs”, which is serviced by Trident.2. Get the details of the nfs storage class.

[root@rhel3 ~]# kubectl describe sc nfsName: nfsIsDefaultClass: NoAnnotations: <none>Provisioner: netapp.io/tridentParameters: backendType=ontap-nasEvents: <none>[root@rhel3 ~]#

This storage class has a single parameter defined, “backendType=ontap-nas”. This is used by Tridentto select a configured backend when provisioning storage for this storage class. (See the Tridentdocumentation for full details on the available selectors.) Based on the selector used here, Trident willsimply use any storage which can be mounted via NFS.

3. To submit a PVC you begin by creating a yaml file that contains the details of the request. For yourconvenience, this lab activity includes a pre-configured yaml request file on the rhel3 host. Examine thecontents of that file.

[root@rhel3 ~]# cat k8s/trident/pvc-nfs.yamlkind: PersistentVolumeClaimapiVersion: v1metadata: name: nfsvol annotations: volume.beta.kubernetes.io/storage-class: nfsspec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi[root@rhel3 ~]#

Using NetApp with Docker and Kubernetes52 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

This particular PVC specifies a request for a 1 Gigabyte volume named “nfsvol” from the nfs storageclass.

Tip: The “accessMode:” value specifies the protocol type the volume must use, with theReadWriteOnce value indicating that either block or file storage is acceptable. However, sincethe only storage class available is “nfs” in this environment, this request will only ever be satisfiedwith file storage. If you wanted to explicity limit the PVC to just request file storage the you wouldspecify an accessMode value of ReadWriteMany or ReadOnlyMany instead.

4. Submit the PVC to Kubernetes to request the volume.

[root@rhel3 ~]# kubectl create -f k8s/trident/pvc-nfs.yamlpersistentvolumeclaim "nfsvol" created[root@rhel3 ~]#

5. To verify that the volume was created, display the details of the PVC request.

[root@rhel3 ~]# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGEnfsvol Bound default-nfsvol-0bff5 1Gi RWO nfs 9strident Bound trident 2Gi RWO 88d[root@rhel3 ~]#

Tip: You will need the value from the “VOLUME” column for the PVC named “nfsvol” in the nextstep. This value in your lab will be different from the value shown here.

The output indicates the PVC named “nfsvol” exists and is bound to a PV named after the pattern“default-nfsvol-XXXXX”. The first part of the volume name is the namespace where the volume wascreated (default), the second part is the name of the PVC (nfsvol), and the last five characters arerandomly generated (and so will differ in your lab). The output also indicates that the PV storage for thisPVC comes from the “nfs” storage class.

6. Display the details of the PV that you created. For this command you will need to specify the actual PVname from your lab instance (as reported in the output from the preceding step).

[root@rhel3 ~]# kubectl describe pv default-nfsvol-0bff5Name: default-nfsvol-0bff5Labels: <none>Annotations: pv.kubernetes.io/provisioned-by=netapp.io/trident volume.beta.kubernetes.io/storage-class=nfsStorageClass: nfsStatus: BoundClaim: default/nfsvolReclaim Policy: DeleteAccess Modes: RWOCapacity: 1GiMessage: Source: Type: NFS (an NFS mount that lasts the lifetime of a pod) Server: 192.168.0.132 Path: /trident_default_nfsvol_0bff5 ReadOnly: falseEvents: <none>[root@rhel3 ~]#

Observe that the “Source:” section reports the NFS server address and export path for the PV.

You can also verify that the volume was created by examining the ONTAP cluster.7. From the taskbar of Jumphost, right click the PuTTY icon.8. Select PuTTY from the context menu.

Using NetApp with Docker and Kubernetes53 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

8

7

Figure 4-3:

9. In the saved session list, double-click the entry for cluster1, and log in as the user admin with thepassword Netapp1!.

9

Figure 4-4:

Using NetApp with Docker and Kubernetes54 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

10. Display a list of the volumes on the svm1 Storage Virtual Machine (SVM).

cluster1::> volume show -vserver svm1Vserver Volume Aggregate State Type Size Available Used%--------- ------------ ------------ ---------- ---- ---------- ---------- -----svm1 registry aggr1 online RW 20GB 19.75GB 1%svm1 svm1_root aggr1 online RW 20MB 18.15MB 9%svm1 trident_default_nfsvol_0bff5 aggr1 online RW 1GB 972.6MB 5%svm1 trident_trident aggr1 online RW 1.86GB 1.77GB 5%svm1 www aggr1 online RW 5GB 5.00GB 0%5 entries were displayed.

cluster1::>

The output shows that the volume you just created exists (”trident_default_nfsvol_0bff5” in thisexample, the volume name will will differ in your lab). This is the ONTAP volume that provides thebacking storage for the nfsvol PV.

11. Display the namespace juntcion paths for these volumes.

cluster1::> volume show -vserver svm1 -junction Junction JunctionVserver Volume Language Active Junction Path Path Source--------- ------------ -------- -------- ------------------------- -----------svm1 registry C.UTF-8 true /registry RW_volumesvm1 svm1_root C.UTF-8 true / -svm1 trident_default_nfsvol_0bff5 C.UTF-8 true /trident_default_nfsvol_ RW_volume 0bff5svm1 trident_trident C.UTF-8 true /trident_trident RW_volumesvm1 www C.UTF-8 true /www RW_volume5 entries were displayed.

cluster1::>

In this example the trident_default_nfsvol_0bff5 is junctioned as /trident_default_nfsvol_0bff5.12. Return to the PuTTY session for rhel3 and attach the new PV to a container. To perform this task you

must use a pod definition file (in yaml format) to create the desired container and to identify the PVCto attach. Once again, this exercise includes a pre-configured pod definition file on the rhel3 host.Examine the contents of that file.

[root@rhel3 ~]# cat k8s/trident/pv-alpine.yamlkind: PodapiVersion: v1metadata: name: pvpodspec: volumes: - name: pvpod-storage persistentVolumeClaim: claimName: nfsvol containers: - name: pv-alpine image: alpine:3.2 command: - /bin/sh - "-c" - "sleep 60m" volumeMounts: - mountPath: "/data" name: pvpod-storage[root@rhel3 ~]#

This request file calls for the creation of a pod named “pvpod” containing a single container named “pv-alpine”. The pod will utilize the PVC named “nfsvol” and mount it as “/data”.

13. Create the pod.

[root@rhel3 ~]# kubectl create -f k8s/trident/pv-alpine.yamlpod "pvpod" created

Using NetApp with Docker and Kubernetes55 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

[root@rhel3 ~]#

The output shows that you just created a new pod named “pvpod”.14. Display the status of this new pod.

[root@rhel3 ~]# kubectl get pod pvpodNAME READY STATUS RESTARTS AGEpvpod 1/1 Running 0 2m[root@rhel3 ~]#

The new pod “pvpod” is up and running.15. Launch a CLI session inside the pvpod container.

[root@rhel3 ~]# kubectl exec -it pvpod /bin/sh/ #

16. Display a list of the mounted volumes in the pod to verify that the PV is attached. In this example youare specifically looking for the volume mounted on “/data”.

/ # mount | grep /data192.168.0.132:/trident_default_nfsvol_0bff5 on /data type nfs (rw,relatime,vers=3,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=192.168.0.132,mountvers=3,mountport=635,mountproto=udp,local_lock=none,addr=192.168.0.132)/ #

In this example the volume is NFS mounted from 192.168.0.132:/trident_default_nfsvol_0bff5 onto /data.

Using NetApp with Docker and Kubernetes56 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

5 ReferencesThe following references were used in writing this lab guide.

• thePub – http://netapp.io/blog/• Slack at thePub – http://netapp.io/slack/• Docker Documentation – Getting Started with Docker: https://docs.docker.com/get-started/part2/• nDVP Documentation - http://netappdvp.readthedocs.io/en/latest/• Kubernetes Documentation – Creating a Deployment using Kubernetes: https://kubernetes.io/docs/

tutorials/kubernetes-basics/deploy-intro/• Trident Documentation – https://github.com/netapp/trident

Using NetApp with Docker and Kubernetes57 © 2018 NetApp, Inc. All rights reserved. NetApp Proprietary

6 Version History

Version Date Document Version History

1.0 August 2017 Initial Release

1.0.1 September 2017 Minor Errata

Refer to the Interoperability Matrix Tool (IMT) on the NetApp Support site to validate that the exactproduct and feature versions described in this document are supported for your specific environment.The NetApp IMT defines the product components and versions that can be used to constructconfigurations that are supported by NetApp. Specific results depend on each customer's installation inaccordance with published specifications.

NetApp provides no representations or warranties regarding the accuracy, reliability, or serviceability of anyinformation or recommendations provided in this publication, or with respect to any results that may be obtainedby the use of the information or observance of any recommendations provided herein. The information in thisdocument is distributed AS IS, and the use of this information or the implementation of any recommendations ortechniques herein is a customer’s responsibility and depends on the customer’s ability to evaluate and integratethem into the customer’s operational environment. This document and the information contained herein may beused solely in connection with the NetApp products discussed in this document.

Go further, faster®

© 2018NetApp, Inc. All rights reserved. No portions of this document may be reproduced without prior written consentof NetApp, Inc. Specifications are subject to change without notice. NetApp, the NetApp logo, Data ONTAP®,ONTAP®, OnCommand®, SANtricity®, FlexPod®, SnapCenter®, and SolidFire® are trademarks or registeredtrademarks of NetApp, Inc. in the United States and/or other countries. All other brands or products are trademarks orregistered trademarks of their respective holders and should be treated as such.