Author

Author


Rajesh Kumar

Rajesh Kumar

DevOps@RajeshKumar.xyz

DevOps@RajeshKumar.xyz

Support my work @Patron! Support my work @Patron!

Contents


Installation and Configuration

Exercise 3.1: Install Kubernetes

Overview

There are several Kubernetes installation tools provided by various vendors. In this lab we will learn to use kubeadm. As a community-supported independent tool, it is planned to become the primary manner to build a Kubernetes cluster.

The labs were written using Ubuntu instances running on Google Cloud Platform (GCP). They have been written to be vendor-agnostic so could run on AWS, local hardware, or inside of virtualization to give you the most flexibility and options. Each platform will have different access methods and considerations. As of v1.12.1 the minimum (as in barely works) size for VirtualBox is 3vCPU/1G memory/5G minimal OS for master and 1vCPU/1G memory/5G minimal OS for worker node.

If using your own equipment you will have to disable swap on every node. There may be other requirements which will be shown as warnings or errors when using the kubeadm command. While most commands are run as a regular user, there are some which require root privilege. Please configure sudo access as shown in a previous lab. You If you are accessing the nodes remotely, such as with GCP or AWS, you will need to use an SSH client such as a local terminal or PuTTY if not using Linux or a Mac. You can download PuTTY from www.putty.org. You would also require a .pem or .ppk file to access the nodes. Each cloud provider will have a process to download or create this file. If attending in-person instructor led training the file will be made available during class.

In the following exercise we will install Kubernetes on a single node then grow the cluster, adding more compute resources. Both nodes used are the same size, providing 2 vCPUs and 7.5G of memory. Smaller nodes could be used, but would run slower

Various exercises will use YAML files, which are included in the text. You are encouraged to write the files when possible, as the syntax of YAML has white space indentation requirements that are important to learn. An important note, do not use tabs in your YAML files, white space only. Indentation matters.

If using a PDF the use of copy and paste often does not paste the single quote correctly. It pastes as a back-quote instead. You will need to modify it by hand. The files have also been made available as a compressed tar file. You can view the resources by navigating to this URL:

https://training.linuxfoundation.org/cm/LFS258

To login use user: LFtraining and a password of: Penguin2014

Once you find the name and link of the current file, which will change as the course updates, use wget to download the file into your node from the command line then expand it like this:


$ wget https://training.linuxfoundation.org/cm/LFS258/LFS258 V2018-11-13 SOLUTIONS.tar.bz2 \
--user=LFtraining --password=Penguin2014
$ tar -xvf LFS258 V2018-11-13 SOLUTIONS.tar.bz2

(Note: depending on your software, if you are cutting and pasting the above instructions, the underscores may disappear and be replaced by spaces, so you may have to edit the command line by hand!)

While Ubuntu 18 bionic has become the typical version to deploy the Kubernetes repository does not yet have compatible binaries at the time of this writing. While xenial binaries can be used there are many additional steps necessary to complete the labs. Ubuntu 18 is expected to be available by the time Kubernetes v.1.13 is released.

Install Kubernetes

Log into your nodes. If attending in-person instructor led training the node IP addresses will be provided by the instructor. You will need to use a .pem or .ppk key for access, depending on if you are using ssh from a terminal or PuTTY. The instructor will provide this to you.

  1. . Open a terminal session on your first node. For example, connect via PuTTY or SSH session to the first GCP node. The user name may be different than the one shown, student. The IP used in the example will be different than the one youwill use.
    
    	[student@laptop ~]$ ssh -i LFS458.pem student@35.226.100.87
    	The authenticity of host ’54.214.214.156 (35.226.100.87)’ can’t be established.
    	ECDSA key fingerprint is SHA256:IPvznbkx93/Wc+ACwXrCcDDgvBwmvEXC9vmYhk2Wo1E.
    	ECDSA key fingerprint is MD5:d8:c9:4b:b0:b0:82:d3:95:08:08:4a:74:1b:f6:e1:9f.
    	Are you sure you want to continue connecting (yes/no)? yes
    	Warning: Permanently added ’35.226.100.87’ (ECDSA) to the list of known hosts.
    	<output_omitted>
    			
    
    		
  2. Become root and update and upgrade the system. Answer any questions to use the defaults.
    
    	student@lfs458-node-1a0a:~$ sudo -i
    	root@lfs458-node-1a0a:~# apt-get update && apt-get upgrade -y
    	<output_omitted>
    
    			
    
    		
  3. The main choices for a container environment are Docker and cri-o. We will user Docker for class, as cri-o requires afair amount of extra work to enable for Kubernetes. As cri-o is open source the community seems to be heading towards its use.
    
    	root@lfs458-node-1a0a:~# apt-get install -y docker.io
    	
    			
    
    			
  4. . Add new repo for kubernetes. You could also get a tar file or use code from GitHub. Create the file and add an entry forthe main repo for your distribution. As we are still using Ubuntu 16.04 add the kubernetes-xenial with the key word main. Note there are four sections to the entry.
    
    	root@lfs458-node-1a0a:~# vim /etc/apt/sources.list.d/kubernetes.list
    	deb http://apt.kubernetes.io/ kubernetes-xenial main
    			
    
    		
  5. Add a GPG key for the packages. The command spans three lines. You can omit the backslash when you type. The OK is the expected output, not part of the command.
    
    	root@lfs458-node-1a0a:~# curl -s \
    	https://packages.cloud.google.com/apt/doc/apt-key.gpg \
    	| apt-key add -
    	OK
    
    			
    
    		
  6. Update with new repo, which will download new repo information.
    
    	root@lfs458-node-1a0a:~# apt-get update
    	
    			
    
    		
  7. Install the software. There are regular releases the newest of which can be used by omitting the equal sign and version information on the command line. Historically new version have lots of changes and a good chance of a bug or five.
    
    	root@lfs458-node-1a0a:~# apt-get install -y \
    	kubeadm=1.12.1-00 kubelet=1.12.1-00 kubectl=1.12.1-00
    	
    
    		
  8. Deciding which pod network to use for Container Networking Interface (CNI) should take into account the expected demands on the cluster. There can be only one pod network per cluster, although the CNI-Genie project is trying to change this
    The network must allow container-to-container, pod-to-pod, pod-to-service, and external-to-service communications. As Docker uses host-private networking, using the docker0 virtual bridge and veth interfaces would require being on that host to communicate.
    We will use Calico as a network plugin which will allow us to use Network Policies later in the course. Currently Calico does not deploy using CNI by default. The 3.3 version of Calico has more than one configuration file for flexibility with RBAC. Download the configuration files for. Once downloaded look for the expected IPV4 range for containers to use
    A short url for each file is shown, the longer URLs can be found here https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml and: https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
    
    	root@lfs458-node-1a0a:~# wget https://tinyurl.com/yb4xturm \
    			-O rbac-kdd.yaml
    	root@lfs459-node-1a0a:~# wget https://tinyurl.com/y8lvqc9g \
    			-O calico.yaml}
    
    			
    
    		
  9. Use less to page through the file. Look for the IPV4 pool expected by the containers. There are many different configuration settings in this file. Take a moment to view the entire file. The CALICO_IPV4POOL_CIDR must match the value given to kubeadm init in the following step, whatever the value may be.
    
    	root@lfs458-node-1a0a:~# less calico.yaml
    	....
    			# Configure the IP Pool from which Pod IPs will be chosen.
    			- name: CALICO_IPV4POOL_CIDR
    			value: "192.168.0.0/16"
    	....
    
    			
    
    		
  10. Initialize the master. Read through the output line by line. Expect the output to change as the software matures. At the end are configuration directions to run as a non-root user. The token is mentioned as well. This information can be found later with the kubeadm token list command. The output also directs you to create a pod network to the cluster, which will be our next step. Pass the network settings Calico has in its configuration file, found in the previous step. Please note: the output lists several commands which following commands will complete. Read the next step before further typing.
    
    	root@lfs458-node-1a0a:~# kubeadm init --pod-network-cidr 192.168.0.0/16
    	[init] using Kubernetes version: v1.12.1
    	[preflight] running pre-flight checks
    	[preflight/images] Pulling images required for setting up a
    	Kubernetes cluster
    	[preflight/images] This might take a minute or two, depending
    	on the speed of your internet connection
    	
    	Your Kubernetes master has initialized successfully!
    	To start using your cluster, you need to run the following as
    	a regular user:
    	mkdir -p $HOME/.kube
    	sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    	sudo chown $(id -u):$(id -g) $HOME/.kube/config
    	You should now deploy a pod network to the cluster.
    	Run "kubectl apply -f [podnetwork].yaml" with one of the options
    	listed at:
    	https://kubernetes.io/docs/concepts/cluster-administration/addons/
    	You can now join any number of machines by running the following
    	on each node as root:
    	kubeadm join 10.128.0.4:6443 --token rdnhok.g8mb6lfgesunanvh
    	--discovery-token-ca-cert-hash
    	sha256:66350d154fc0169b5bb5fd50c04b72468195e356d78d95f137ed55e995402f77
    			
    
    		
  11. . As suggested in the directions at the end of the previous output we will allow a non-root user admin level access to the cluster. Take a quick look at the configuration file once it has been copied and the permissions fixed.
    
    	root@lfs458-node-1a0a:~# exit
    	logout
    	student@lfs458-node-1a0a:~$ mkdir -p $HOME/.kube
    	student@lfs458-node-1a0a:~$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    	student@lfs458-node-1a0a:~$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
    	student@lfs458-node-1a0a:~$ less .kube/config
    	apiVersion: v1
    	clusters:
    	- cluster:
    	<output_omitted>
    
    		
  12. Apply the network plugin configuration to your cluster. Remember to copy the file to the current, non-root user directory first.
    
    	student@lfs458-node-1a0a:~$ sudo cp /root/rbac-kdd.yaml .
    	student@lfs458-node-1a0a:~$ kubectl apply -f rbac-kdd.yaml
    	clusterrole.rbac.authorization.k8s.io/calico-node created
    	clusterrolebinding.rbac.authorization.k8s.io/calico-node created
    	student@lfs458-node-1a0a:~$ sudo cp /root/calico.yaml .
    	student@lfs458-node-1a0a:~$ kubectl apply -f calico.yaml
    	configmap/calico-config created
    	service/calico-typha created
    	deployment.apps/calico-typha created
    	poddisruptionbudget.policy/calico-typha created
    	<output_omitted>
    
    		
  13. While many objects have short names, a kubectl command can be a lot to type. We will enable bash auto-completion. Begin by adding the settings to the current shell. Then update the ~/.bashrc file to make it persistent
    
    	student@lfs458-node-1a0a:~$ source <(kubectl completion bash)
    	student@lfs458-node-1a0a:~$ echo "source <(kubectl completion bash)" >> ~/.bashrc
    
    
    		
  14. Test by describing the node again. Type the first three letters of the sub-command then type the Tab key. Auto-completion assumes the default namespace. Pass the namespace first to use auto-completion with a different namespace. By pressing Tab multiple times you will see a list of possible values. Continue typing until a unique name is used.
    
    	student@lfs458-node-1a0a:~$ kubectl des n lfs458-
    	student@lfs458-node-1a0a:~$ kubectl -n kube-s g po e
    
    		

Exercise 3.2: Grow the Cluster

Open another terminal and connect into a your second node. Install Docker and Kubernetes software. These are the many, but not all, of the steps we did on the master node.

The book will use the lfs458-worker prompt for the node being added to help keep track of the proper node for each command. Note that the prompt indicates both the user and system upon which run the command.

  1. Using the same process as before connect to a second node. If attending ILT use the same .pem key and a new IP provided by the instructor to access the new node. Giving a title or color to the new terminal window is probably a good idea to keep track of the two systems. The prompts can look very similar.
    
    	student@lfs458-worker:~$ sudo -i
    	root@lfs458-worker:~# apt-get update && apt-get upgrade -y
    	root@lfs458-worker:~# apt-get install -y docker.io
    	root@lfs458-worker:~# vim /etc/apt/sources.list.d/kubernetes.list
    	deb http://apt.kubernetes.io/ kubernetes-xenial main
    	root@lfs458-worker:~# curl -s \
    	https://packages.cloud.google.com/apt/doc/apt-key.gpg \
    	| apt-key add -
    	root@lfs458-worker:~# apt-get update
    	root@lfs458-worker:~# apt-get install -y \
    	kubeadm=1.12.1-00 kubelet=1.12.1-00 kubectl=1.12.1-00
    
    		
  2. Find the IP address of your master server. The interface name will be different depending on where the node is running. Currently inside of GCE the primary interface for this node type is ens4. Your interfaces names may be different. From the output we know our master node IP is 10.128.0.3.
    
    	student@lfs458-node-1a0a:~$ ip addr show ens4 | grep inet
    	inet 10.128.0.3/32 brd 10.128.0.3 scope global ens4
    	inet6 fe80::4001:aff:fe8e:2/64 scope link
    
    		
  3. Find the token on the master node. The token lasts 24 hours by default. If it has been longer, and no token is present you can generate a new one with the sudo kubeadm token create command, seen in the following command.
    
    	student@lfs458-node-1a0a:~$ ip addr show ens4 | grep inet
    	inet 10.128.0.3/32 brd 10.128.0.3 scope global ens4
    	inet6 fe80::4001:aff:fe8e:2/64 scope link
    
    		
  4. Only if the token has expired, you can create a new token, to use as part of the join command.
    
    	student@lfs458-node-1a0a:~$ sudo kubeadm token create
    	27eee4.6e66ff60318da929
    
    		
  5. Starting in v1.9 you should create and use a Discovery Token CA Cert Hash created from the master to ensure the node joins the cluster in a secure manner. Run this on the master node or wherever you have a copy of the CA file. You will get a long string as output.
    
    	student@lfs458-node-1a0a:~$ openssl x509 -pubkey \
    	-in /etc/kubernetes/pki/ca.crt | openssl rsa \
    	-pubin -outform der 2>/dev/null | openssl dgst \
    	-sha256 -hex | sed ’s/^.* //’
    	6d541678b05652e1fa5d43908e75e67376e994c3483d6683f2a18673e5d2a1b0
    		
  6. Use the token and hash, in this case as sha256: to join the cluster from the second node. Use the private IP address of the master server and port 6443. The output of the kubeadm init on the master also has an example to use, should it still be available.
    
    	root@lfs458-worker:~# kubeadm join \
    	--token 27eee4.6e66ff60318da929 \
    	10.128.0.3:6443 \
    	--discovery-token-ca-cert-hash \
    	sha256:6d541678b05652e1fa5d43908e75e67376e994c3483d6683f2a18673e5d2a1b0
    	[preflight] Running pre-flight checks.
    	[WARNING FileExisting-crictl]: crictl not found in system path
    	[discovery] Trying to connect to API Server "10.142.0.2:6443"
    	[discovery] Created cluster-info discovery client, requesting info from
    	"https://10.142.0.2:6443"
    	[discovery] Requesting info from "https://10.142.0.2:6443" again to
    	validate TLS against the pinned public key
    	[discovery] Cluster info signature and contents are valid and TLS
    	certificate validates against pinned roots, will
    	use API Server "10.142.0.2:6443"
    	[discovery] Successfully established connection with API Server
    	"10.142.0.2:6443"
    	This node has joined the cluster:
    	* Certificate signing request was sent to master and a response
    	was received.
    	* The Kubelet was informed of the new secure connection details.
    	Run ’kubectl get nodes’ on the master to see this node join the cluster.
    			   
  7. Try to run the kubectl command on the secondary system. It should fail. You do not have the cluster or authentication keys in your local .kube/config file.
    
    	root@lfs458-worker:~# exit
    	student@lfs458-worker:~$ kubectl get nodes
    	The connection to the server localhost:8080 was refused
    	- did you specify the right host or port?
    	student@lfs458-worker:~$ ls -l .kube
    	ls: cannot access ’.kube’: No such file or directory
    			

Exercise 3.3: Finish Cluster Setup

  1. View the available nodes of the cluster. It can take a minute or two for the status to change from NotReady to Ready. The NAME field can be used to look at the details. Your node name will be different. Note the master node says NotReady, which is due to a taint.
    
    	student@lfs458-node-1a0a:~$ kubectl get node
    	NAME STATUS ROLES AGE VERSION
    	lfs458-node-1a0a NotReady master 18m v1.12.1
    	lfs458-worker Ready <none> 3m25s v1.12.1
    			
  2. Look at the details of the node. Work line by line to view the resources and their current status. Notice the status of Taints. The master wont allow non-internal pods by default for security reasons. Take a moment to read each line of output, some appear to be an error until you notice the status shows False.
    
    	student@lfs458-node-1a0a:~$ kubectl describe node lfs458-node-1a0a
    	Name: lfs458-node-1a0a
    	Roles: master
    	Labels: beta.kubernetes.io/arch=amd64
    	beta.kubernetes.io/os=linux
    	kubernetes.io/hostname=lfs458-node-1a0a
    	node-role.kubernetes.io/master=
    	Annotations: kubeadm.alpha.kubernetes.io/cri-socket=/var/run/dockershim.sock
    	node.alpha.kubernetes.io/ttl=0
    	volumes.kubernetes.io/controller-managed-attach-detach=true
    	CreationTimestamp: Sun, 29 Jul 2018 21:29:32 +0000
    	Taints: node-role.kubernetes.io/master:NoSchedule
    	<output_omitted>
    
    			
  3. Allow the master server to run non-infrastructure pods. The master node begins tainted for security and performance reasons. Will will allow usage of the node in the training environment, but this step may be skipped in a production environment. Note the minus sign (-) at the end, which is the syntax to remove a taint. As the second node does not have the taint you will get a not found error.
    
    	student@lfs458-node-1a0a:~$ kubectl describe node | grep -i taint
    	Taints: node-role.kubernetes.io/master:NoSchedule
    	Taints: <none>
    	student@lfs458-node-1a0a:~$ kubectl taint nodes \
    	--all node-role.kubernetes.io/masternode/lfs458-node-1a0a
    	untainted
    	error: taint "node-role.kubernetes.io/master:" not found
    			
  4. Now that the master node is able to execute any pod we may find there is a new taint. This behavior began with v1.12.0,requiring a newly added node to be enabled. View then remove the taint if present. It can take a minute or two for the scheduler to deploy the remaining pods.
    
    	student@lfs458-node-1a0a:~$ kubectl describe node | grep -i taint
    	Taints: node.kubernetes.io/not-ready:NoSchedule
    	Taints: <none>
    	student@lfs458-node-1a0a:~$ kubectl taint nodes \
    	--all node.kubernetes.io/not-readynode/lfs58-node-1a0a
    	untainted
    	error: taint "node.kubernetes.io/not-ready:" not found
    
    			
  5. Another ”undocumented feature” in v1.12.1 is that the taint removal does not always work the first time. Check to see if the taint has been removed. You may have to remove the taint two or three times before it is actually gone. Wait 60 seconds before trying again to remove the taint.
    
    	student@lfs458-node-1a0a:~$ kubectl describe node | grep -i taint
    	Taints: node.kubernetes.io/not-ready:NoSchedule
    	Taints: <none>
    	student@lfs458-node-1a0a:~$ kubectl taint nodes \
    	--all node.kubernetes.io/not-readynode/lfs58-node-1a0a
    	untainted
    	error: taint "node.kubernetes.io/not-ready:" not found
    	student@lfs458-node-1a0a:~$ sleep 60 ; kubectl describe node | grep -i taint
    	Taints: <none>
    	Taints: <none>
    
    			
  6. Determine if the DNS and Calico pods are ready for use. They should all show a status of Running. It may take a minute or two to transition from Pending.
    
    	student@lfs458-node-1a0a:~$ kubectl get pods --all-namespaces
    	NAMESPACE NAME READY STATUS RESTARTS AGE
    	kube-system calico-etcd-jlgwr 1/1 Running 0 6m
    	kube-system calico-kube-controllers-74b888b647-wlqf5 1/1 Running 0 6m
    	kube-system calico-node-tpvnr 2/2 Running 0 6m
    	kube-system coredns-78fcdf6894-nc5cn 1/1 Running 0 17m
    	kube-system coredns-78fcdf6894-xs96m 1/1 Running 0 17m
    	<output_omitted>
    
    			
  7. . If you notice the coredns- pods are stuck in ContainerCreating status you may have to delete them, causing new ones to be generated. Delete both pods and check to see they show a Running state. Your pod names will be different.
    
    	student@lfs458-node-1a0a:~$ kubectl get pods --all-namespaces
    	NAMESPACE NAME READY STATUS
    	RESTARTS AGE
    	kube-system calico-node-qkvzh 2/2 Running
    	0 59m
    	kube-system calico-node-vndn7 2/2 Running
    	0 12m
    	kube-system coredns-576cbf47c7-rn6v4 0/1 ContainerCreating
    	0 3s
    	kube-system coredns-576cbf47c7-vq5dz 0/1 ContainerCreating
    	0 94m
    	<output_omitted>
    	student@lfs458-node-1a0a:~$ kubectl -n kube-system delete \
    	pod coredns-576cbf47c7-vq5dz coredns-576cbf47c7-rn6v4
    	pod "coredns-576cbf47c7-vq5dz" deleted
    	pod "coredns-576cbf47c7-rn6v4" deleted
    			
  8. When it finished you should see a new tunnel, tunl0, and a cali interface. It may take up to a minute to be created. As you create objects more interfaces will be created.
    
    	student@lfs458-node-1a0a:~$ ip a
    	<output_omitted>
    	4: tunl0@NONE:  mtu 1440 qdisc noqueue state
    	UNKNOWN group default qlen 1000
    	link/ipip 0.0.0.0 brd 0.0.0.0
    	inet 192.168.0.1/32 brd 192.168.0.1 scope global tunl0
    	valid_lft forever preferred_lft forever
    	6: calib0b93ed4661@if4:  mtu
    	1440 qdisc noqueue state UP group default
    	link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 1
    	inet6 fe80::ecee:eeff:feee:eeee/64 scope link
    	valid_lft forever preferred_lft forever
    
    			

Exercise 3.4: Deploy A Simple Application

We will test to see if we can deploy a simple application, in this case the nginx web server

  1. Create a new deployment, which is an Kubernetes object while will deploy and monitor an application in a container. Verify it is running and the desired number of container matches the available.
    
    	student@lfs458-node-1a0a:~$ kubectl create deployment nginx --image=nginx
    	deployment.apps/nginx created
    	student@lfs458-node-1a0a:~$ kubectl get deployments
    	
    	NAME    DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
    	nginx    1        1       1            1     6s
    
    
    			
  2. View the details of the deployment. Remember auto-completion will work for sub-commands and resources as well.
    
    	student@lfs458-node-1a0a:~$ kubectl describe deployment nginx
    	Name: nginx
    	Namespace: default
    	CreationTimestamp: Thu, 08 Nov 2018 19:23:00 +0000
    	Labels: app=nginx
    	Annotations: deployment.kubernetes.io/revision: 1
    	Selector: app=nginx
    	Replicas: 1 desired | 1 updated | 1 total | 1 ava....
    	StrategyType: RollingUpdate
    	MinReadySeconds: 0
    	RollingUpdateStrategy: 25% max unavailable, 25% max surge
    	<output_omitted>
    
    			
  3. . View the basic steps the cluster took in order to pull and deploy the new application. You should see several lines of output with newer events at the top.
    
    	student@lfs458-node-1a0a:~$ kubectl get events
    	<output_omitted>
    
    
    			
  4. You can also view the output in yaml format, which could be used to create this deployment again or new deployments. Get the information but change the output to yaml. Note that halfway down there is status information of the current deployment.
    
    	student@lfs458-node-1a0a:~$ kubectl get deployment nginx -o yaml
    	apiVersion: extensions/v1beta1
    	kind: Deployment
    	metadata:
    	annotations:
    	deployment.kubernetes.io/revision: "1"
    	creationTimestamp: 2017-09-27T18:21:25Z
    	<output_omitted>
    
    			
  5. Run the command again and redirect the output to a file. Then edit the file. Remove the creationTimestamp, resourceVersion, selfLink, and uid lines. Also remove all the lines including and after status:, which should be somewhere around line 40, if others have already been removed.
    
    	student@lfs458-node-1a0a:~$ kubectl get deployment nginx -o yaml > first.yaml
    	student@lfs458-node-1a0a:~$ vim first.yaml
    	
    
    			
  6. Delete the existing deployment.
    
    	student@lfs458-node-1a0a:~$ kubectl delete deployment nginx
    	deployment.extensions "nginx" deleted
    
    			
  7. Create the deployment again this time using the file.
    
    	student@lfs458-node-1a0a:~$ kubectl create -f first.yaml
    	deployment.extension/nginx created
    
    
    			
  8. Look at the yaml output of this iteration and compare it against the first. The time stamp, resource version and uid we had deleted are in the new file. These are generated for each resource we create, so we need to delete them from yaml files to avoid conflicts or false information. The status should not be hard-coded either.
    
    	student@lfs458-node-1a0a:~$ kubectl get deployment nginx -o yaml > second.yaml
    	student@lfs458-node-1a0a:~$ diff first.yaml second.yaml
    	<output_omitted>
    
    
    			
  9. Now that we have worked with the raw output we will explore two other ways of generating useful YAML or JSON. Use the --dry-run option and verify no object was created. Only the prior nginx deployment should be found. The output lacks the unique information we removed before.
    
    	student@lfs458-node-1a0a:~$ kubectl create deployment two --image=nginx --dry-run -o yaml
    	apiVersion: apps/v1beta1
    	kind: Deployment
    	metadata:
    	creationTimestamp: null
    	labels:
    	run: two
    	name: two
    	spec:
    	<output_omitted>
    	student@lfs458-node-1a0a:~$ kubectl get deployment
    	NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
    	nginx 1 1 1 1 7m
    
    			
  10. Existing objects can be viewed in a ready to use YAML output. Take a look at the existing nginx deployment. Note there is more detail to the –export option.
    
    	student@lfs458-node-1a0a:~$ kubectl get deployments nginx --export -o yaml
    	apiVersion: extensions/v1beta1
    	kind: Deployment
    	metadata:
    	annotations:
    	deployment.kubernetes.io/revision: "1"
    	creationTimestamp: null
    	generation: 1
    	labels:
    	run: nginx
    	<output_omitted>
    
    			
  11. The output can also be viewed in JSON output.
    
    	student@lfs458-node-1a0a:~$ kubectl get deployment nginx --export -o json
    	{
    	"apiVersion": "extensions/v1beta1",
    	"kind": "Deployment",
    	"metadata": {
    	"annotations": {
    	"deployment.kubernetes.io/revision": "1"
    	},
    <output_omitted>
    
    			
  12. . The newly deployed nginx container is a light weight web server. We will need to create a service to view the default welcome page. Begin by looking at the help output. Note that there are several examples given, about halfway through the output.
    
    	student@lfs458-node-1a0a:~$ kubectl expose -h
    	<output_omitted>
    
    
    			
  13. Now try to gain access to the web server. As we have not declared a port to use you will receive an error.
    
    	student@lfs458-node-1a0a:~$ kubectl expose deployment/nginx
    	error: couldn’t find port via --port flag or introspection
    	See ’kubectl expose -h’ for help and examples.
    
    			
  14. To change an existing configuration in a cluster can be done with subcommands apply, edit or patch for non-disruptive updates. The apply command does a three-way diff of previous, current, and supplied input to determine modifications to make. Fields not mentioned are unaffected. The edit function performs a get, opens an editor, then an apply. You can update API objects in place with JSON patch and merge patch or strategic merge patch functionality.
    If the configuration has resource fields which cannot be updated once initialized then a disruptive update could be done using the replace --force option. This deletes first then re-creates a resource.
    Edit the file. Find the container name, somewhere around line 31 and add the port information as shown below.
    
    	student@lfs458-node-1a0a:~$ vim first.yaml
    	....
    			spec:
    			containers:
    			- image: nginx
    			imagePullPolicy: Always
    			name: nginx
    			ports: # Add these
    			- containerPort: 80 # three
    			protocol: TCP # lines
    			resources: {}
    	....
    
    
    			
  15. Due to how the object was created we will need to use replace to terminate and create a new deployment
    
    	student@lfs458-node-1a0a:~$ kubectl replace -f first.yaml
    	deployment.extensions/nginx replaced
    
    
    			
  16. View the Pod and Deployment. Note the AGE shows the Pod was re-created.
    
    	student@lfs458-node-1a0a:~$ kubectl get deploy,pod
    	NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
    	deployment.extensions/nginx 1 1 1 1 2m4s
    	NAME READY STATUS RESTARTS AGE
    	pod/nginx-7cbc4b4d9c-l8cgl 1/1 Running 0 8s
    
    			
  17. Try to expose the resource again. This time it should work
    
    	student@lfs458-node-1a0a:~$ kubectl expose deployment/nginx
    	service/nginx exposed
    
    
    			
  18. Verify the service configuration. First look at the service information, then at the endpoint information. Note the Cluster IP is not the current endpoint. Take note of the current endpoint IP. In the example below it is 10.244.1.99:80. We will use this information in a few steps.
    
    	student@lfs458-node-1a0a:~$ kubectl get svc nginx
    	NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    	nginx ClusterIP 10.100.61.122 <none> 80/TCP 3m
    	student@lfs458-node-1a0a:~$ kubectl get ep nginx
    	NAME ENDPOINTS AGE
    	nginx 10.244.1.99:80 4m
    
    			
  19. Determine which node the container is running on. Log into that node and use tcpdump to view traffic on the tunl0, as in tunnel zero, interface. The second node in this example. You may also see traffic on an interface which starts with cali and some string. Leave that command running while you run curl in the following step. You should see several messages go back and forth, including a HTTP: HTTP/1.1 200 OK and a ack response to the same sequence.
    
    	student@lfs458-node-1a0a:~$ kubectl describe pod nginx-7cbc4b4d9c-d27xw \
    	| grep Node:
    	Node: lfs458-worker/10.128.0.5
    	student@lfs458-worker:~$ sudo tcpdump -i tunl0
    	tcpdump: verbose output suppressed, use -v or -vv for full protocol...
    	listening on tunl0, link-type EN10MB (Ethernet), capture size...
    	<output_omitted>
    
    			
  20. Test access to the Cluster IP, port 80. You should see the generic nginx installed and working page. The output should be the same when you look at the ENDPOINTS IP address. If the curl command times out the pod may be running on the other node. Run the same command on that node and it should work.
    
    	student@lfs458-node-1a0a:~$ curl 10.100.61.122:80
    	<DOCTYPE html>
    	<html>
    	<head>
    	<title>Welcome to nginx!<title>
    	<style>
    	<output_omitted>
    
    			
  21. Now scale up the deployment from one to three web servers.
    
    	student@lfs458-node-1a0a:~$ kubectl get deployment nginx
    	NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
    	nginx 1 1 1 1 12m
    	student@lfs458-node-1a0a:~$ kubectl scale deployment nginx --replicas=3
    	deployment.extensions/nginx scaled
    	student@lfs458-node-1a0a:~$ kubectl get deployment nginx
    	NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
    	nginx 3 3 3 3 12m
    
    			
  22. View the current endpoints. There now should be three. If the DESIRED above said three, but AVAILABLE said two wait a few seconds and try again, it could be slow to fully deploy.
    
    	student@lfs458-node-1a0a:~$ kubectl get ep nginx
    	NAME ENDPOINTS AGE
    	nginx 10.244.0.66:80,10.244.1.100:80,10.244.1.99:80 10m
    
    			
  23. . Find the oldest pod of the nginx deployment and delete it. The Tab key can be helpful for the long names. Use the AGE field to determine which was running the longest. You will notice activity in the other terminal where tcpdump is running, when you delete the pod.
    
    	student@lfs458-node-1a0a:~$ kubectl get po -o wide
    	NAME READY STATUS RESTARTS AGE IP
    	nginx-1423793266-7f1qw 1/1 Running 0 14m 10.244.0.66
    	nginx-1423793266-8w2nk 1/1 Running 0 1m 10.244.1.100
    	nginx-1423793266-fbt4b 1/1 Running 0 1m 10.244.1.101
    	student@lfs458-node-1a0a:~$ kubectl delete po nginx-1423793266-7f1qw
    	pod "nginx-1423793266-7f1qw" deleted
    
    			
  24. Wait a minute or two then view the pods again. One should be newer than the others. In the following example two minutes instead of four. If your tcpdump was using the veth interface of that container it will error out.
    
    	student@lfs458-node-1a0a:~$ kubectl get po
    	NAME READY STATUS RESTARTS AGE
    	nginx-1423793266-13p69 1/1 Running 0 2m
    	nginx-1423793266-8w2nk 1/1 Running 0 4m
    	nginx-1423793266-fbt4b 1/1 Running 0 4m
    
    			
  25. View the endpoints again. The original endpoint IP is no longer in use. You can delete any of the pods and the service will forward traffic to the existing backend pods.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl get ep nginx
    	NAME   ENDPOINTS                                       AGE
    	nginx  10.244.0.66:80,10.244.1.100:80,10.244.1.101:80  15m
    
    			
  26. Test access to the web server again, using the ClusterIP address, then any of the endpoint IP addresses. Even though the endpoints have changed you still have access to the web server. This access is only from within the cluster
    
    	
    	student@lfs458-node-1a0a:~$ curl 10.100.61.122:80
    	<DOCTYPE html>
    	<html>
    	<head>
    	<title>Welcome to nginx!<title>
    	<style>
    	body {
    	<output_omitted>
    
    
    	

Exercise 3.5: Access from Outside the Cluster

You can access a Service from outside the cluster using a DNS add-on or vi environment variables. We will use environment variables to gain access to a Pod.

  1. Begin by getting a list of the pods.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl get po
    	NAME                    READY   STATUS   RESTARTS    AGE
    	nginx-1423793266-13p69 	 1/1 	Running 	0 		 8m
    	nginx-1423793266-8w2nk 	 1/1 	Running 	0 		 10m
    	nginx-1423793266-fbt4b 	 1/1 	Running 	0 		 10m
    
    
    
    	
  2. Choose one of the pods and use the exec command to run printenv inside the pod. The following example uses the first pod listed above.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl exec nginx-1423793266-13p69 \
    	-- printenv |grep KUBERNETES
    	KUBERNETES_SERVICE_PORT_HTTPS=443
    	KUBERNETES_SERVICE_HOST=10.96.0.1
    	KUBERNETES_SERVICE_PORT=443
    	NGINX_SERVICE_HOST=10.100.61.122
    	NGINX_SERVICE_PORT=80
    	<output_omitted>
    
    
    
    	
  3. Find and then delete the existing service for nginx.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl get svc
    	NAME         	TYPE    	CLUSTER-IP 		EXTERNAL-IP 	PORT(S)     AGE
    	kubernetes 	 ClusterIP      10.96.0.1	     <none> 		443/TCP		 2d
    	nginx        ClusterIP      10.100.61.122 	 <none> 		80/TCP 		40m
    
    
    	
  4. Delete the service.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl delete svc nginx
    	service "nginx" deleted
    
    
    
    	
  5. Create the service again, but this time pass the LoadBalancer type. Check to see the status and note the external ports mentioned. The output will show the External-IP as pending. Unless a provider responds with a load balancer it will continue to show as pending.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl expose deployment nginx --type=LoadBalancer
    	service/nginx exposed
    	student@lfs458-node-1a0a:~$ kubectl get svc
    	NAME           TYPE      CLUSTER-IP      EXTERNAL-IP         PORT(S)      AGE
    	kubernetes   ClusterIP   10.96.0.1        <none>            443/TCP       2d
    	nginx       LoadBalancer 10.104.249.102          80:32753/TCP    2s
    
    
    
    	
  6. Open a browser on your local system, not the GCE node, and use the public IP of your node and port 32753, shown in the output above. If running the labs on a remote system like AWS or GCE the CLUSTER-IPs are internal. Use the public IP you used with SSH to gain access.
  7. Scale the deployment to zero replicas. Then test the web page again. It should fail.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl scale deployment nginx --replicas=0
    	deployment.extensions/nginx scaled
    	student@lfs458-node-1a0a:~$ kubectl get po
    	No resources found.
    
    
    
    	
  8. Scale the deployment up to two replicas. The web page should work again
    
    	
    	student@lfs458-node-1a0a:~$ kubectl scale deployment nginx --replicas=2
    	deployment.extensions/nginx scaled
    	student@lfs458-node-1a0a:~$ kubectl get po
    	.NAME                 READY STATUS RESTARTS AGE
    	nginx-1423793266-7x181 1/1 Running 0        1m
    	nginx-1423793266-s6vcz 1/1 Running 0        1m
    
    
    	
  9. Delete the deployment to recover system resources. Note that deleting a deployment does not delete the endpoints or services.
    
    	
    	student@lfs458-node-1a0a:~$ kubectl delete deployments nginx
    	deployment.extensions "nginx" deleted
    	
    	student@lfs458-node-1a0a:~$ kubectl delete ep nginx
    	endpoints "nginx" deleted
    	
    	student@lfs458-node-1a0a:~$ kubectl delete svc nginx
    	service "nginx" deleted
    
    
    	

Avail Rajesh Kumar as trainer at 50% Discount
Puppet Online Training
Puppet Classroom TrainingEnroll Now