diff --git a/basics/README.md b/basics/README.md new file mode 100644 index 0000000..157af43 --- /dev/null +++ b/basics/README.md @@ -0,0 +1,16 @@ +# Goals +* Understand Basic Kubernetes (k8s) Concepts +* Familiarize with the different parts of a k8s manifest File +* Deploy an application in ~~local~~ k8s +* ~~Interact with Kubernetes locally~~ +* Access the deployed application from outside the Kubernetes cluster. + +# Prerequisite +* [Git CLI](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) + +# Exercises +* [Deploying your application to k8s](deployment/README.md) +* [Accessing your application in k8s](services/README.md) + + diff --git a/basics/deployment/README.md b/basics/deployment/README.md new file mode 100644 index 0000000..bde50e0 --- /dev/null +++ b/basics/deployment/README.md @@ -0,0 +1,56 @@ +# Deployment Exercise + +In this exercise, we are going to deploy the quintessential hello world application in k8s. + +*If you are not familiar with a Deployment manifest you can see the explanation for each section of the manifest file [here](manifest.md). (Or you can skip ahead to the instructions on how to deploy the application using the manifest file)* + +In the command line terminal (e.g., cmd, powershell, git bash, WSL terminal, etc.), execute the following command. +```console +kubectl apply -f hello/hello-deployment.yaml +``` +This creates a [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) resource that will in turn create the [Pods](https://kubernetes.io/docs/concepts/workloads/pods/pod/). *(All of these objects are created in the default namespace because we did not specify one. Use the -n option to specify a namespace on all the kubectl commands. In our private cloud, we require a namespace be provided in the manifest file metadata itself.)* + +To see the list of your deployments and its statuses: +```console +kubectl get deployments +``` +It should say `1/1` on the `READY` column for your deployment when all the pod is up and running. + +Alternatively, you can see the list of pods that are created by the deployment: +```console +kubectl get pod +``` +This should also have a `READY` column that will say `1/1` when all the containers in the pod are up and running (in our example there's only 1). The `readinessProbe` determines when a container is considered ready. + +If you want to watch the pods or deployments until it is up and running you can pass the -w or --watch ( CTRL+C to exit). For example: +```console +kubectl get pod -w +``` +This will block on that command, allowing you to see the status change without having to repeatedly execute the command. + +You can check the logs of your pod: +```console +kubectl logs +``` +Use the `` from when you listed the pods. + +To follow/tail the logs add the -f option ( CTRL+C to exit): +```console +kubectl logs -f +``` + +Next, we are going to try to delete the pod. + +First, get the list of pods +```console +kubectl get pods +``` +Take note of the name of one of the `hello-` pods. Use the pod name for the command below. +```console +kubectl delete pod +``` +List out the pods again. +```console +kubectl get pods +``` +See what happens. diff --git a/basics/deployment/manifest.md b/basics/deployment/manifest.md new file mode 100644 index 0000000..941743e --- /dev/null +++ b/basics/deployment/manifest.md @@ -0,0 +1,117 @@ +# Breaking down a deployment manifest + +## Kind +The `apiVersion` and `kind`, together, specifies the API and what kind of resource we are defining in the manifest file. We are creating a *Deployment* manifest file. + +```yaml +apiVersion: apps/v1 +kind: Deployment + +## Metadata +The `name` uniquely identifies this Deployment. `labels` are used for selectors on other resources and log queries. + +```yaml +metadata: + name: hello + labels: + app: hello +``` +*(Note: In our private cloud, we are required to specify a namespace in the metadata. However, for our exercise we are just using the default namespace.)* + +## Spec +The `spec` section of a manifest file contains configurations for that resource type, in this case they are configuration for a deployment. + +For example, the first thing we are going to configure is how many `replicas` (of pods) this deployment will have. + +```yaml +spec: + replicas: 1 +``` + +Next we need to specify the label `selector` that defines which pods are managed by this deployment, i.e., `spec.selector.matchLabels`. + +```yaml + selector: + matchLabels: + app: hello +``` + +## Pod Template +The next subsection is the `spec.template` which contains the template of the Pod that will be created. + +The `spec.template.metadata.labels` must match the selector.matchLabels because this determines which pods the are managed by the deployment. + +```yaml + template: + metadata: + labels: + app: hello +``` + +The pod template also has its own `spec` section which defines the configuration of the pod. This section is where you define the `containers` that will go into the pod. + +A container requires a name field. + +```yaml + spec: + containers: + - name: hello-app +``` + +In the container section you'll need to specify which `image` to use for the container. + +**TODO: Update image** +```yaml + image: "egineering-llc/hello-micronaut:0.0.1-26_3e59c44" +``` + +The `spec.template.spec.containers[].ports[]` contains the list `ports` in the container that will be [*exposed*](https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p---expose). These exposed ports can then be bound to service ports (will be covered later). + +```yaml + ports: + - name: http + containerPort: 8080 + protocol: TCP +``` + +## Probes + +The `spec.template.spec.containers[].readinessProbe` defines the check that helps kubernetes determine when a container is considered ready to receive requests (the service will start allowing traffic through). In this case, it is using an http `GET` to perform a check. It is considered a success when it returns a status code greater than or equal to `200` and less than `400`. + +```yaml + readinessProbe: + httpGet: + path: /hello + port: 8080 + initialDelaySeconds: 3 + periodSeconds: 10 +``` +The `spec.template.spec.containers[].livenessProbe` performs its checks in the same way that the `readinessProbe` is done. However, this probe check is used for self-healing instead of determining the readiness of the pod. If the liveness check fails (i.e., the container does not return a status code greater than or equal to 200 and less than 400) it will kill the container and be subjected to its restart policy, which default to `Always`, which means it will perform a restart if it fails the liveness probe. The `initialDelaySeconds` on the livenessProbe is set to a larger number than the `readinessProbe` to avoid a situation where the container is restarted before it is given a chance to fully startup. + +```yaml + livenessProbe: + httpGet: + path: /hello + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 30 +``` + +# Resource Management +The `spec.template.spec.containers[].resources` is the section in the manifest that defines the management of the computer resources. The `limits` is used to set policies for how much resources a container can use. The `requests` defines the minimum resource requirements of a container which is used for determining the required resources for a node to host this pod. + +The memory `requests` and `limits` are straightforward and can be taken as the minimum and maximum values of the memory resource, but the CPU values between `requests` and `limits` has some [nuance](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#how-pods-with-resource-limits-are-run) that you can check out if you are interested. In simple terms, these values can be treated as minimum and maximum boundaries. + +`Mi` on the memory values stands for *MebiByte* which differs from *MegaByte* in that a MegaByte is in the power of 10 whereas a MebiByte is in the power of 2. 1 MebiByte is equal to 1024 KibiByte whereas 1 MegaByte is 1000 KiloByte. MebiByte is a more accurate unit to represent memory than the MegaByte but either can be used (i.e., you can use the suffix M for MegaByte). + +The `m` unit for CPU stands for 1/1000 of a CPU core. + +```yaml + resources: + limits: + memory: 100Mi + cpu: 1 + requests: + memory: 10Mi + cpu: 10m +```