Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ryanj
Last active November 11, 2019 15:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryanj/e11eb7e507600651e85de383cf35a1fd to your computer and use it in GitHub Desktop.
Save ryanj/e11eb7e507600651e85de383cf35a1fd to your computer and use it in GitHub Desktop.
Hands-On Intro to Kubernetes (and OpenShift) for JS Developers at NodeConfEU http://bit.ly/rhnodeconfeu
<section data-background-transition="none-in zoom-out" data-transition="zoom" id="HANDS-ON" data-background-color="white">
<h3 style="padding-top:26%;">Hands-on Intro to</h3>
<h1 style="font-size:113px;">Kubernetes & OpenShift</h1>
<h3>{ for JS Developers }</h3>
<p class='fragment grow'><a style="font-weight:bold;" href="http://bit.ly/rhnodeconfeu">bit.ly/rhnodeconfeu</a></p>
<p><a href="https://www.nodeconf.eu/nc-agenda/">Monday, November 11 16:00 - 17:30</a></p>
</section>
<section>
<section style="color:white;" data-transition='concave' data-background-transition='fade' data-background='#000000' data-background-color="black" id='presented-by'>
<p style="color:white;">presented by&hellip;</p>
<div class='fragment fade-right' style='width:45%; float:left;'>
<p><a href="http://twitter.com/ryanj/"><img alt="ryanj" src="http://ryanjarvinen.com/images/ryanj-mestrefungo-com.gif" style="width:70%" /></p>
<p><a href="http://twitter.com/ryanj/">Ryan Jarvinen @ryanj</a></p>
</div>
<div class='fragment fade-up' style='width:10%;float:left;margin-top: 13%;font-size: 250%;font-weight: bold;color:white;'>&amp;</div>
<div class='fragment fade-left' style='width:45%; float:left;'>
<p><a href="http://twitter.com/jankleinert"><img alt="Jan Kleinert" src="https://pbs.twimg.com/profile_images/1087055426267402240/BTeh6LLK_400x400.jpg" style="width:70%"/></p>
<p><a href="http://twitter.com/jankleinert">Jan Kleinert @jankleinert</a></p>
</div>
<br/>
<!-- <p style="color:white;">presented by <a href="http://twitter.com/ryanj/">@ryanj</a>, Developer Advocate at Red Hat</p>
<p style="color:white;" class='fragment fade-up'><a href="http://twitter.com/ryanj/"><img alt="ryanj" src="http://ryanjarvinen.com/images/ryanj-mestrefungo-com.gif" style="width:50%"/><br/>@ryanj</p> -->
</section>
<section id='brought-to-you-by' data-background='black' data-background-color="black">
<p style="color:white;">brought to you by</p>
<p style="color:white;"><a href="https://redhat.com"><img alt="Red Hat logo" src="https://www.underconsideration.com/brandnew/archives/red_hat_logo_inverse.png" /></a></p>
</section>
</section>
<section data-transition='convex'>
<section id='introduction'>
<h1>Introduction</h1>
</section>
<section id='survey'>
<h3>Intro Survey / Who are you?</h3>
<ol>
<li class='fragment'>do you have any experience using containers?</li>
<li class='fragment'>do you have any experience using Kubernetes?</li>
<li class='fragment'>do you consider yourself to be proficient with the <code>oc</code> or <code>kubectl</code> cli tools?</li>
<li class='fragment'>can you name five basic Kubernetes primitives or resource types?</li>
<li class='fragment'>do you have a plan for iterative web development using containers?</li>
</ol>
</section>
</section>
<section>
<section data-transition='convex' id='agenda'>
<h2>Workshop Agenda</h2>
<ul style='list-style: none;'>
<li class='fragment'><a href="#/introduction">Introduction</a>
<ul style='list-style: none;'>
<li class='fragment'><a href="#/agenda">Agenda</a></li>
<li class='fragment'><a href="#/kubernetes">Overview</a></li>
<li class='fragment'><a href="#/laptop-setup">Environment Setup</a></li>
</ul>
</li>
<li class='fragment'><a href="#/kubernetes-basics">Kubernetes Basics</a>
<ul style='list-style: none;'>
<li class='fragment'>Learn five basic resource types</li>
</ul>
</li>
<li class='fragment'><a href="#/hands-on-with-openshift">Hands-On with OpenShift</a>
<ul style='list-style: none;'>
<li class='fragment'>Build, Deploy, Iterate, Collaborate</li>
</ul>
</li>
<li class='fragment'><a href="#/wrap-up">Wrap Up / Q&amp;A</a></li>
</ul>
</section>
<section id='kubernetes' data-markdown>
# Kubernetes
* [is](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/): an ops tool; a collection of APIs for managing container-based workloads
* [is not](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#what-kubernetes-is-not): a PaaS
</section>
<section id='openshift' data-markdown>
# OpenShift
* a CNCF certified distribution of Kubernetes
* adds: Multi-tenant security, PaaS-style workflows, Service Catalog and Brokers, a container registry, distributed metrics and logs ...
</section>
<section id='more-info'>
<h3>More Information</h3>
<ul>
<li>Kubernetes Sources and Official Releases:<br/>
<a href="http://github.com/kubernetes/kubernetes">http://github.com/kubernetes/kubernetes</a></li>
<li>Kubernetes Docs: <a href="http://kubernetes.io/docs/home/">http://kubernetes.io/docs/home/</a></li>
<li>OpenShift Sources and Official Releases:<br/>
<a href="http://github.com/openshift/origin/">http://github.com/openshift/origin/</a></li>
<li>OpenShift Docs: <a href="https://docs.openshift.com/">https://docs.openshift.com/</a></li>
</ul>
</section>
</section>
<section>
<section id='laptop-setup' data-markdown>
## Workshop Requirements
Minimal requirements:
* *a web browser with JS enabled*
</section>
</section>
<section id='laptop-setup-2' data-markdown>
## Lab Requirements
To follow along, sign in with your username and a password of "openshift" at the following url:
left: https://lab-k8s-for-js-default.apps.cluster-nodeconf-57e5.nodeconf-57e5.example.opentlc.com
right: https://lab-k8s-for-js-workshops.apps.cluster-nodeconf-180f.nodeconf-180f.example.opentlc.com
</section>
<section>
<section data-transition='zoom-in convex-out' id='ready'>
<h1><i>Ready?</i></h1>
<br/>
<div class='fragment fade-up'>
<p>Before we get started, you'll need to configure your <code>~/.kube/config</code> file. We will do this by running:</p>
<pre><code contenteditable>export GUID=180f
export API_SERVER=https://api.cluster-nodeconf-$GUID.nodeconf-$GUID.example.opentlc.com:6443
export NAMESPACE=$(oc project --short)
export HOST_PORT=http://apps.cluster-nodeconf-$GUID.nodeconf-$GUID.example.opentlc.com</code></pre>
<pre><code contenteditable>curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.16.2/bin/linux/amd64/kubectl && chmod +x kubectl</code></pre>
</div>
<div class='fragment fade-up'>
<p>Confirm that you've been authenticated by running:</p>
<pre><code contenteditable>oc whoami</code></pre>
</div>
</section>
<section data-background-transition="zoom">
<h1>Set?</h1>
<div class='fragment fade-up'>
<p>Verify that your cli tools are configured to connect to your Kubernetes environment:<br/>
<pre><code contenteditable>kubectl version</code></pre>
<p>The output should include your <code>kubectl</code> version info, and the release version of the kubernetes API server (when available)</p>
</div>
</section>
<section data-background-transition="zoom">
<h1><i>Let's Go!</i></h1>
</section>
</section>
<section>
<section id='kubernetes-basics'>
<h1>Kubernetes Basics</h1>
<p>↓</p>
</section>
<section data-markdown>
## etcd
![etcd logo](https://raw.githubusercontent.com/coreos/etcd/master/logos/etcd-glyph-color.png)
* distributed key-value store
* implements the [RAFT](https://raft.github.io/raft.pdf) consensus protocol
* CAP theorum: [CAP twelve years later](https://www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed)
</section>
<section id='an-api' data-markdown>
Kubernetes provides&hellip;
# An API
API object primitives include the following attributes:
```
kind
apiVersion
metadata
spec
status
```
*mostly true
Extended Kubernetes API Reference:
http://k8s.io/docs/reference/generated/kubernetes-api/v1.14/
</section>
<section data-transition="linear" id='terminology' data-markdown>
### Basic K8s Terminology
1. [node](#/node)
2. [pod](#/po)
3. [service](#/svc)
4. [deployment](#/deployment)
5. [replicaSet](#/rs)
Introduction borrowed from: [bit.ly/k8s-kubectl](http://bit.ly/k8s-kubectl)
</section>
</section>
<section>
<section data-transition="linear" id='node' data-markdown>
### Nodes
A node is a host machine (physical or virtual) where containerized processes run.
Node activity is managed via one or more Master instances.
</section>
<section>
<p>Try using <code>kubectl</code> to list resources by type:</p>
<pre><code contenteditable>kubectl get nodes</code></pre>
<p>Try using <code>curl</code> to list nodes:</p>
<pre><code contenteditable>curl -k -H"Authorization: Bearer $(oc whoami -t)" $API_SERVER/api/v1/nodes</code></pre>
</section>
<section data-markdown>
### Observations:
* Designed to exist on multiple machines (distributed system)
* built for high availability
* platform scale out
* Your JS runs on nodes!
</section>
</section>
<section>
<section data-transition="linear" id='po' data-markdown>
### Pods
A group of one or more co-located containers. Pods represent your minimum increment of scale.
&gt; "Pods Scale together, and they Fail together" @theSteve0
</section>
<section>
<p>Try using <code>kubectl</code> to list resources by type:</p>
<pre><code contenteditable>kubectl get pods</code></pre>
<p>Create a new resource based on a json object specification:</p>
<pre><code contenteditable>kubectl create -f https://raw.githubusercontent.com/jankleinert/hello-workshop/master/pod.json
#curl -O https://raw.githubusercontent.com/ryanj/hello-k8s/master/pod.json && curl -k -H"Authorization: Bearer $(oc whoami -t)" -H'Content-Type: application/json' $API_SERVER/api/v1/namespaces/$NAMESPACE/pods -X POST --data-binary @pod.json</code></pre>
<p>List pods by type using <code>curl</code>:</p>
<pre><code contenteditable>curl -k -H"Authorization: Bearer $(oc whoami -t)" $API_SERVER/api/v1/namespaces/$NAMESPACE/pods</code></pre>
<p>Fetch an individual resource by <code>type/id</code>; output as <code>json</code>:</p>
<pre><code contenteditable>kubectl get pod hello-k8s -o json
curl -k -H"Authorization: Bearer $(oc whoami -t)" $API_SERVER/api/v1/namespaces/$NAMESPACE/pods/hello-k8s</code></pre>
<p class='fragment'>Notice any changes between the json spec and the API response?</p>
</section>
<section>
<!--
<p>Request the same info using <code>curl</code>:</p>
<pre><code contenteditable>curl -k -H'Authorization: Bearer $(oc whoami -t)' $API_SERVER/api/v1/namespaces/$NAMESPACE/pods/hello-world</code></pre>
-->
<p>Request the same info, but output the results as structured yaml:</p>
<pre><code contenteditable>kubectl get pod hello-k8s -o yaml</code></pre>
<p>Print human-readable API output:</p>
<pre><code contenteditable>kubectl describe pod/hello-k8s</code></pre>
</section>
<section data-markdown>
### Observations:
* API resources provide declarative specifications with asyncronous fulfilment of requests
* see `spec` vs `status`
* automated health checking for PID1 in each container
* Pods are scheduled to be run on nodes
* The API ambidextriously supports both json and yaml
</section>
<!--
<section data-markdown>
</section>
-->
</section>
<section>
<section data-transition="linear" id='svc' data-markdown>
### Services
Services (svc) establish a single endpoint for a collection of replicated pods, distributing traffic based on label selectors
In our K8s modeling language they represent a load balancer. Their implementation may vary per cloud provider
</section>
<section id='connections'>
<h3>Contacting your App</h3>
<p>Expose the pod by creating a new <code>service</code> (or "loadbalancer"):</p>
<pre><code contenteditable>kubectl expose pod/hello-k8s --port 8080 --type=NodePort</code></pre>
<p>Take a look at the resulting <code>{.spec.selector}</code> attribute:</p>
<pre><code contenteditable>kubectl get svc/hello-k8s -o json</code></pre>
<p>Try using a <a href="https://kubernetes.io/docs/reference/kubectl/jsonpath/">JSONpath</a> selector to find the assigned port number:</p>
<pre><code contenteditable>kubectl get svc/hello-k8s -o jsonpath={.spec.ports[0].nodePort}</code></pre>
<p>Contact your newly-exposed pod via the assigned port number:</p>
<pre><code contenteditable>echo www.apps.nodejsint.openshiftworkshop.com:$(kubectl get svc/hello-k8s -o jsonpath={.spec.ports[0].nodePort})</code></pre>
<pre><code contenteditable>curl www.apps.nodejsint.openshiftworkshop.com:$(kubectl get svc/hello-k8s -o jsonpath={.spec.ports[0].nodePort})</code></pre>
</section>
<section>
<p>Schedule the deletion of all pods that are labeled with:</p>
<pre><code contenteditable>kubectl get pods -l run=hello-k8s</code></pre>
<pre><code contenteditable>kubectl delete pods -l run=hello-k8s</code></pre>
<p>Contact the related service. What happens?:</p>
<pre><code contenteditable>curl www.apps.nodejsint.openshiftworkshop.com:$(kubectl get svc/hello-k8s -o jsonpath={.spec.ports[0].nodePort})</code></pre>
<p>Delete the service:</p>
<pre><code contenteditable>kubectl delete service hello-k8s</code></pre>
</section>
<section data-markdown>
### Observations:
* *"service"* basically means *"loadbalancer"*
* Label selectors can be used to organize workloads and manage groups of related resouces
* The Service resource uses label selectors to discover where traffic should be directed
* Pods and Services exist independently, have disjoint lifecycles
</section>
</section>
<section>
<section data-transition="linear" id='deployment' data-markdown>
### Deployments
A `deployment` helps you specify container runtime requirements (in terms of pods)
</section>
<section>
<p>Create a specification for your <code>deployment</code>:</p>
<pre><code contenteditable>kubectl run hello-k8s --image=jkleinert/nodejsint-workshop \
--dry-run -o json &gt; deployment.json</code></pre>
<p>View the generated deployment spec file:</p>
<pre><code contenteditable>cat deployment.json</code></pre>
</section>
<section>
<p>Create new resources based on your spec files:</p>
<pre><code contenteditable>kubectl create -f deployment.json</code></pre>
</section>
<section>
<p>Create a <code>Service</code> spec to direct traffic:</p>
<pre><code contenteditable>kubectl expose deploy/hello-k8s --type=NodePort --port=8080 --dry-run -o json &gt; service.json</code></pre>
<p>View the resulting spec file:</p>
<pre><code contenteditable>cat service.json</code></pre>
</section>
<section>
<p>Create a new service based on your spec file:</p>
<pre><code contenteditable>kubectl create -f service.json</code></pre>
<p>List multiple resources by type:</p>
<pre><code contenteditable>kubectl get po,svc,deploy</code></pre>
<p>Connect to your new deployment via the associated service id:</p>
<pre><code contenteditable>curl www.apps.nodejsint.openshiftworkshop.com:$(kubectl get svc/hello-k8s -o jsonpath={.spec.ports[0].nodePort})</code></pre>
</section>
<section id='replication'>
<h2>Replication</h2>
<p>Scale up the <code>hello-k8s</code> deployment to 3 replicas:</p>
<pre><code contenteditable>kubectl scale deploy/hello-k8s --replicas=3</code></pre>
<p>List pods:</p>
<pre><code contenteditable>kubectl get po</code></pre>
</section>
<section>
<p>Edit <code>deploy/hello-k8s</code>, setting <code>spec.replicas</code> to <code>5</code>:</p>
<pre><code contenteditable>kubectl edit deploy/hello-k8s -o json</code></pre>
<p>Save and quit. What happens?</p>
<pre><code contenteditable>kubectl get pods</code></pre>
</section>
<section id='autorecovery'>
<h2>AutoRecovery</h2>
<p>Watch for changes to <code>pod</code> resources:</p>
<pre><code contenteditable>kubectl get pods --watch &</code></pre>
<p>In another terminal, delete several pods by id:</p>
<pre><code contenteditable>kubectl delete pod $(kubectl get pods | grep ^hello-k8s | cut -f1 -s -d' ' | head -n 3 | tr '\n' ' ')</code></pre>
<p class='fragment'>What happened? How many pods remain?</p>
<pre class='fragment'><code contenteditable>kubectl get pods</code></pre>
</section>
<section data-markdown>
### Observations:
* Use the `--dry-run` flag to generate new resource specifications
* A deployment spec contains a pod spec in it's "template" element
* The API provides `edit` and `watch` operations (in addition to `get`, `set`, and `list`)
</section>
</section>
<section>
<section data-transition="linear" id='rs' data-markdown>
### ReplicaSets
A `replicaset` provides replication and lifecycle management for a specific image release
</section>
<section>
<p>View the current state of your deployment:</p>
<pre><code contenteditable>curl www.apps.nodejsint.openshiftworkshop.com:$(kubectl get svc/hello-k8s -o jsonpath={.spec.ports[0].nodePort})</code></pre>
<p>Watch deployments:</p>
<pre><code contenteditable>kubectl get deploy -w &amp;</code></pre>
</section>
<section>
<h3>Rollouts</h3>
<p>Update your deployment's image spec to rollout a new release:</p>
<pre><code contenteditable>kubectl set image deploy/hello-k8s hello-k8s=quay.io/ryanj/metrics-k8s:v1</code></pre>
<p>Reload your browser to view the state of your deployment</p>
<pre><code contenteditable>kubectl get rs</code></pre>
</section>
<section>
<h3>Rollbacks</h3>
<p>View the list of previous rollouts:</p>
<pre><code contenteditable>kubectl rollout history deploy/hello-k8s</code></pre>
<p>Rollback to the previous state:</p>
<pre><code contenteditable>kubectl rollout undo deployment hello-k8s</code></pre>
<p>Reload your browser to view the state of your deployment</p>
</section>
<section>
<h3>Cleanup</h3>
<p>Cleanup all resources:</p>
<pre><code contenteditable>kubectl delete service,deployment hello-k8s</code></pre>
<p>Close your remaining <code>--watch</code> listeners by running `fg` and sending a break signal (CTRL-c)</p>
<br/>
<p>Verify that your namespace is clean:</p>
<pre><code contenteditable>kubectl get all</code></pre>
</section>
<section data-markdown>
### Observations:
* ReplicaSets provide lifecycle management for pod resources
* Deployments create ReplicaSets to manage pod replication per rollout (per change in podspec: image:tag, environment vars)
* Deployments &gt; ReplicaSets &gt; Pods
</section>
</section>
<section data-transition="convex" id='hands-on-with-openshift'>
<h1>Hands-On with OpenShift</h1>
<p class='fragment'>For the rest of the workshop, go back to the interactive lab environment </p>
</section>
<section>
<section id='wrap-up'>
<h1>Wrap Up</h1>
</section>
<section id='exit-survey'>
<h3>Exit Survey</h3>
<ol>
<li class='fragment'>have experience using containers?</li>
<li class='fragment'>have experience using Kubernetes?</li>
<li class='fragment'>Do you consider yourself to be basically proficient with the <code>oc</code> or <code>kubectl</code> command-line tools?</li>
<li class='fragment'>Can you name five basic Kubernetes primitives or resource types?</li>
<li class='fragment'>Ready to start standardizing your web development processes with containers?</li>
</ol>
</section>
</section>
<section>
<section data-markdown>
## Resources
</section>
<section data-markdown>
### Free O'Reilly Ebook
<!--TODO: add image-->
[Deploying to OpenShift](https://www.openshift.com/deploying-to-openshift/) *NEW!*
</section>
<!--
<section data-markdown>
### Kubernetes SIGs
[Kubernetes Special Interest Groups (SIGs)](https://github.com/kubernetes/community/blob/master/sig-list.md)
</section>
-->
<section data-transition="linear" id='kubernetes-terminology' data-markdown>
## K8s Terminology
1. [node](https://kubernetes.io/docs/concepts/architecture/nodes/)
2. [pod](https://kubernetes.io/docs/concepts/workloads/pods/pod/)
3. [deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
4. [service](https://kubernetes.io/docs/concepts/services-networking/service/)
5. [replicaSet (rs)](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/)
</section>
<section data-transition="linear" id='openshift-terminology' data-markdown>
## OpenShift Terminology
1. [buildConfig (bc)](https://docs.openshift.org/latest/rest_api/apis-build.openshift.io/v1.BuildConfig.html)
2. [imageStream (is)](https://docs.openshift.org/latest/rest_api/apis-image.openshift.io/v1.ImageStream.html)
3. [deploymentConfig (dc)](https://docs.openshift.org/latest/rest_api/apis-apps.openshift.io/v1.DeploymentConfig.html)
4. [route](https://docs.openshift.org/latest/rest_api/apis-route.openshift.io/v1.Route.html)
5. [template](https://docs.openshift.org/latest/rest_api/oapi/v1.Template.html)
</section>
</section>
<section id='try-openshift' data-markdown>
### More Ways to Try OpenShift
* [OpenShift Learning Portal](http://learn.openshift.com)
* [try.openshift.com](https://try.openshift.com)
</section>
<section data-markdown>
## Top Tools for K8s JS Hackers
* https://github.com/nodeshift
* https://www.npmjs.com/package/openshift-rest-client
* https://www.npmjs.com/package/nodeshift
</section>
<section data-background-color='black' id='q-and-a'>
<h1 style='color:white;'>Q&amp;A</h1>
</section>
<section data-markdown>
# More follow-up Questions?
## Find us in the Red Hat booth!
</section>
<section id='thank-you'>
<h1>Thank You!</h1>
<p><img style="width:33%;" alt="RyanJ" src="https://tek.phparch.com/wp-content/uploads/sites/7/2018/05/ryan-jarvinen-headshot-e1525184794614-531x424.jpg" /></p>
<p><a href="https://twitter.com/ryanj">@RyanJ</a></p>
<br/>
<h3 class="fragment grow" style='text-transform:none;'><a href="http://bit.ly/rhnodeconfeu">bit.ly/rhnodeconfeu</a></h3>
</section>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment