# Breakout session 1 - Kubectl, Pods and Namespaces ## Objectives - Learn common kubectl commands - Create a namespace - Deploy a pod to the created namespace - Learn basic interactions with the pod - view logs - upload/download files - execute commands - Edit and recreate pod ### Kubectl commands Get the status of the current nodes ```kubectl get nodes``` View the currently running pods ```kubectl get pods``` There shouldn't be any pods currently running. Let's create one. ```kubectl run nginx --image nginx``` Now when we run `kubectl get pods` we should see our running nginx pod ``` NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 55m ``` Great! We've got a running pod. Let's check out the logs to make sure it's running: ```kubectl logs nginx``` ``` /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration ...output truncated... 2022/10/06 19:47:14 [notice] 1#1: nginx/1.23.1 2022/10/06 19:47:14 [notice] 1#1: start worker process 34 2022/10/06 19:47:14 [notice] 1#1: start worker process 35 ``` Yep, that's an nginx server. Right now it's not too useful, as it isn't serving any content, and isn't actually connected to any networking. Let's run a command on the container. Let's say we want to check that we actaully have a running webserver. Unfortunately the pod isn't reachable from the outside, but we can try using curl from the inside. ```kubectl exec nginx -- curl localhost``` ``` % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 615 100 615 0 0 200k 0 --:--:-- --:--:-- --:--:-- 200k <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> ``` Ok, we've verified we have a working webserver. Let's look at that command again and break it down. * ```kubectl``` - the kubernetes client tool * ```exec``` - execute a command on the container * ```nginx``` - the name of the pod we want to execute a command on * ```-- curl localhost``` - the command being run There are two things of note with the command. First, the '-\-' is required. It's what tells kubectl you are starting your command to be executed. Second, the command must exist on the container. If the 'curl' binary is not present, you will get an error. There is another way we could have run this step: an interactive exec command. This looks like so: ```kubectl exec -it <pod> -- <command>``` Note the addition of the '-it' flag. These two flags redirect the input from the command line to container, and the output from the container to your terminal. This is useful if you want to run an interactive command, such as a shell ```kubectl exec -it nginx -- bash``` If you run this command, you'll need to type 'exit' or ctrl+c to drop back to your shell. This capability is very powerful for troubleshooting purposes, but generally shouldn't be used as part of your "real" workflow. If there is a command that needs to be run to set up your application, it should be baked into the Dockerfile that created the container image. (This is also a good use case for an init container, but that's beyond the scope of this session). What if we want to update our web page? We could copy in a new html in place of the default nginx one. ```kubectl cp index.html nginx:/usr/share/nginx/html/index.html``` If you've used a utility like scp or rsync, this syntax should look familiar. This command is copying the index.html file from your local folder to the /usr/share/nginx/html folder on the pod's default container. Downloading a file would be the same, with the arguments swapped. If you hit the pod with the exec command from earlier, you should see the new html file. ```kubectl exec nginx -- curl localhost``` ``` % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 24 100 24 0 0 24000 0 --:--:-- --:--:-- --:- <h1> Hello world! </h1> ``` While this is a handy dev tool, you don't really want to build production capability around this functionality. If we restart our pod, our changes are all lost. Later sessions will go into the right way to do this. --- ### Pod manifest file Using the CLI to create a pod is handy for quick tests, but isn't very useful at scale. We want to use the Kubernetes manifest files to really do this. One easy way to quickly generate the file is to use the --dry-run and --output flags together. ```kubectl run nginx --image nginx --dry-run=client -o yaml > pod.yaml``` This command will create the resource on the client, but not actaully send it to the server for creation. The use of the -o (output) flag, allows us to redirect this to a local file to be edited. ``` apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: nginx name: nginx spec: containers: - image: nginx name: nginx resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {} ``` Let's delete the existing pod and recreate it using the manifest file. ```kubectl delete pod nginx``` ```kubectl apply -f pod.yaml``` You can go through the steps we did previously to verify the pod is running. Now let's delete our pod then edit the manifest. By specifying the image without a tag, Kubernetes grabbed the "latest" tag for our nginx container. Let's use a different version. Using your text editor of choice, change line 10 of `pod.yaml` from ```image: nginx``` to ```image: nginx:1.22.0``` Change the "name" entry on line 7 to something fun too. Now recreate the pod (make sure you deleted the old one before you change the name otherwise Kubernetes will complain). ```kubectl delete -f pod.yaml && kubectl apply -f pod.yaml``` When you do a get pods now, you should see it named whatever you decided to call it. Note a Pod can not be edited once created, hence why we had to delete it. Most other objects do allow editing after creation, which we will see later. One last thing. Let's get Kubernetes to give us the details on our pod, to make sure it is what we think it is. ```kubectl describe pod nginx``` This will give a pretty detailed description of your pod. The output of the describe command changes based on what you are describing. In our case, scroll down to the "Containers" section of the output, which should look something similar to this: ``` Containers: nginx: Container ID: containerd://bdcea4a0a9b82e325458958712f148a47ceb5a3d5126d4d0b54f38dea7bc5d47 Image: nginx:1.22.0 Image ID: docker.io/library/nginx@sha256:f0d28f2047853cbc10732d6eaa1b57f1f4db9b017679b9fd7966b6a2f9ccc2d1 Port: <none> Host Port: <none> State: Running Started: Fri, 07 Oct 2022 17:47:27 +0000 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-nbnqx (ro) ``` We can see that the pod is using the 1.22.0 container image, and if we wanted to, we could take the `Image ID` and compare it to the value on Docker Hub to verify our image. We also notice that we've got no value for Port or Host Port, which makes our webserver not very useful. We'll get to that in a later lesson (along with `Environment` and `Mounts`). --- ## Namespaces Let's take a quick look at namespaces. Most resources in Kubernetes belong to a namespace. Out of the box there will be a "default" namespace, a "kube-system" namespace, and a few others depending on distribution. Default is where any resources will get created that don't have namespace specified. Kube-system is where most of the resources that make up the Kubernetes systems reside. Do not touch anything in this namespace unless you really know what you are doing. In a production environment, controls should be set up to limit access to resources in kube-system. List namespaces ```kubectl get namespace``` List pods in kube-system namespace ```kubectl get pods -n kube-system``` List pods in all namespaces ```kubectl get pods -A``` Create a namespace ```kubectl create namespace training-namespace ``` or ```kubectl apply -f namespace.yaml``` Now let's create our pod in the training-namespace namespace. ```kubectl apply -f pod.yaml -n training-namespace``` ```kubectl get pods -n training-namespace``` That's all we'll touch on namespaces for now. They'll come up again throughout other topics. One key takeaway is this - if you don't see the resources you're expecting, make sure you're in the right namespace.