├── .gitignore ├── Readme.md ├── demos ├── guestbook │ ├── frontend-controller.yaml │ └── namespace.yaml ├── hands-on-pods │ ├── influxdb-local-pv.yaml │ ├── influxdb-persistentdisk.yaml │ ├── influxdb-readiness.yaml │ ├── influxdb-resource-limits.yaml │ ├── influxdb-simple.yaml │ ├── local-persistent-volume.yaml │ ├── local-pvc.yaml │ └── namespace.yaml ├── quota │ └── quota.yaml ├── replication-controllers │ └── inspector-rc.yaml ├── secrets │ └── secrets.yaml ├── services │ └── inspector-svc.yaml └── termination │ └── termination.yaml └── slideshow ├── .DS_Store ├── conference-redhat.yaml ├── day1.adoc ├── day2.adoc ├── day3.adoc ├── day4.adoc ├── images ├── .DS_Store ├── TitleBackground.png ├── bottleneck.png ├── ceposta.png ├── clapping_hands_sign.svg ├── collaborate.jpeg ├── collaborate1.jpeg ├── day1 │ ├── cattle.jpg │ ├── docker-animated-1.gif │ ├── docker-animated-2.gif │ ├── docker-components.png │ ├── docker-host-ports.png │ ├── docker-layers.png │ ├── docker-network.png │ ├── docker-ports.png │ ├── docker-vol-datacontainer.png │ ├── docker-vol-host.png │ ├── docker-vol.png │ ├── docker.png │ ├── intro-cgroups.png │ ├── local-registry.png │ ├── port-forward.png │ ├── scope.png │ ├── tomcat.png │ ├── workflow1.png │ └── workflow2.png ├── day2 │ ├── all-containers.jpg │ ├── deep-pod.png │ ├── demo.jpg │ ├── etcd.png │ ├── kube-control-plane-nodes.png │ ├── kube-control-plane.png │ ├── kube-diagram.png │ ├── kube-pods.png │ ├── kubernetes-platform.png │ ├── label-pods.png │ ├── make-it-so.png │ ├── node-connectivity.png │ ├── pod-creation.png │ ├── pod-selectors.png │ ├── services-overview.png │ └── services.png ├── day3 │ ├── abtesting.png │ ├── bluedeployment.png │ ├── cadvisor.png │ ├── canarydeployment.png │ ├── docker-network.png │ ├── docker-networking-funny.png │ ├── fluentd-es-overview.png │ ├── greendeployment.png │ ├── ha.png │ ├── influx.png │ ├── monitoring-architecture.png │ ├── promo.png │ └── sky-dns-pod.png ├── dev_impact1.png ├── developer.jpg ├── devops1.jpeg ├── devops2.jpeg ├── docker-animated-2.gif ├── docker-logo.png ├── docker.jpeg ├── docker │ └── install │ │ ├── docker-arch-windows.png │ │ └── docker-linux-arch.png ├── docker_vm_diagram.jpg ├── dockerfile-to-image.jpeg ├── dockerfile.png ├── eai-esb.png ├── eai.jpg ├── eai2.jpg ├── elasticsearch.jpeg ├── expensive.jpeg ├── fabric-pod-volume.png ├── fabric8-apps.png ├── fabric8-cd-tools.png ├── fabric8-cdci.png ├── fabric8-diagram1.png ├── fabric8-green-button.png ├── fabric8-pod-port.png ├── fabric8-pod-volume.png ├── fabric8-pod.png ├── fabric8-port.png ├── fabric8-service-pod.png ├── fabric8-volume.png ├── fabric8_logo.png ├── fluentd.jpeg ├── fuse-fabric.png ├── git.png ├── github.jpeg ├── goal.jpeg ├── grafana.jpeg ├── hawtio.png ├── html5.jpeg ├── hubot-avatar@2x.png ├── idea.jpeg ├── influxdb.png ├── jenkins-300x300.png ├── kibana-2.jpeg ├── kibana.jpeg ├── kubernetes-logo.png ├── kubernetes.png ├── lack-of-management.jpg ├── languages.jpeg ├── linux.png ├── microservice.jpeg ├── microservice.jpg ├── microservice1.png ├── nexus.png ├── openshift-paas.png ├── openshift_logo.png ├── opts-it.jpg ├── oss.jpeg ├── oss1.jpeg ├── questions.png ├── redhat-background.jpeg ├── redhat-linux.png ├── redhat-logo-background-1024-768.png ├── redhat-logo-background-1280-800.png ├── redhat-logo.jpg ├── redhat-logo.png ├── redhat-master-nodes-pods.png ├── rest-api.png ├── rhel-atomic.jpeg ├── rhel-atomic.png ├── rhel-atomic1.png ├── rht-atomic-enterprise-openshift.png ├── sonarqube.png ├── swagger.jpeg ├── worked-fine-in-dev.png └── wtf-dev-ops.png └── intro.adoc /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.iml 3 | .idea 4 | generated 5 | dk-diagrams.graffle 6 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Setting up your local environment 2 | 3 | This workshop requires you to bring your own laptop and have the following prerequisites installed: 4 | 5 | ### Hardware requirements 6 | 7 | * Operating System: Mac OS X (10.8 or later), Windows 7 (SP1), Fedora (21 or later) 8 | * Memory: At least 4 GB+, preferred 8 GB 9 | 10 | ### Software requirements 11 | 12 | * Java JDK -- [download here](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 13 | * Web Browser (preferably Chrome or Firefox) 14 | * Git client -- [download here](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 15 | * Apache Maven -- [download here](https://maven.apache.org/download.cgi) 16 | * VirtualBox -- [download here](https://www.virtualbox.org/wiki/Download_Old_Builds_4_3) 17 | * Vagrant -- [download here](http://www.vagrantup.com/downloads.html) 18 | 19 | Github.com access 20 | 21 | The slides will walk you through setting up Docker and Kubernetes, etc 22 | 23 | [http://redhatworkshops.github.io/slides/docker/generated/intro.html](http://redhatworkshops.github.io/slides/docker/generated/intro.html) 24 | 25 | [http://redhatworkshops.github.io/slides/docker/generated/intro.html](http://redhatworkshops.github.io/slides/docker/generated/day1.html) 26 | 27 | [http://redhatworkshops.github.io/slides/docker/generated/intro.html](http://redhatworkshops.github.io/slides/docker/generated/day2.html) 28 | 29 | [http://redhatworkshops.github.io/slides/docker/generated/intro.html](http://redhatworkshops.github.io/slides/docker/generated/day3.html) 30 | 31 | See this blog [for more info on each of the days](http://blog.christianposta.com/kubernetes/3-day-docker-and-kubernetes-training/) 32 | 33 | ## Generate slides 34 | The sources for the slides are written in asciidoc and are prepared and packaged with revealjs using a wonderful tool named [hyla](https://github.com/cmoulliard/hyla). To generate the slides, [install hyla]() and then from the root of this directory (after cloning it), run this: 35 | 36 | > hyla generate -c slideshow/conference-redhat.yaml 37 | 38 | 39 | ## Credits 40 | 41 | Huge shout out to the work [Kelsey Hightower](https://github.com/kelseyhightower/) does in the kubernetes community, and providing his [intro to kubernetes](https://github.com/kelseyhightower/intro-to-kubernetes-workshop) workshop on github.com I've used some of the `inspector` app RC and service definitions to illustrate the respective concepts. 42 | 43 | For my slides, I used a lot of the [kubernetes.io documentation]() and some inspiration from Googler [ 44 | Satnam Singh's presentation tiled "Cluster management with Kubernetes"](http://www.slideshare.net/SatnamSingh67/2015-0605-cluster-management-with-kubernetes) and blog post [http://blog.raintown.org/2014/11/logging-kubernetes-pods-using-fluentd.html](http://blog.raintown.org/2014/11/logging-kubernetes-pods-using-fluentd.html) 45 | -------------------------------------------------------------------------------- /demos/guestbook/frontend-controller.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: frontend 5 | labels: 6 | name: frontend 7 | spec: 8 | replicas: 1 9 | selector: 10 | name: frontend 11 | template: 12 | metadata: 13 | labels: 14 | name: frontend 15 | spec: 16 | containers: 17 | - name: php-redis 18 | image: gcr.io/google_samples/gb-frontend:v3 19 | env: 20 | - name: GET_HOSTS_FROM 21 | value: env 22 | ports: 23 | - containerPort: 80 -------------------------------------------------------------------------------- /demos/guestbook/namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: "Namespace" 3 | apiVersion: "v1" 4 | metadata: 5 | name: "guestbook" 6 | labels: 7 | name: "guestbook" 8 | -------------------------------------------------------------------------------- /demos/hands-on-pods/influxdb-local-pv.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | name: influxdb 6 | name: influxdb 7 | spec: 8 | volumes: 9 | - name: mypd 10 | persistentVolumeClaim: 11 | claimName: myclaim-1 12 | containers: 13 | - image: docker.io/tutum/influxdb:latest 14 | name: influxdb 15 | volumeMounts: 16 | - mountPath: "/data" 17 | name: "mypd" 18 | resources: 19 | limits: 20 | cpu: "500m" 21 | memory: "128Mi" 22 | readinessProbe: 23 | httpGet: 24 | path: /ping 25 | port: 8086 26 | initialDelaySeconds: 5 27 | timeoutSeconds: 1 28 | livenessProbe: 29 | httpGet: 30 | path: /ping 31 | port: 8086 32 | initialDelaySeconds: 15 33 | timeoutSeconds: 1 34 | ports: 35 | - containerPort: 8083 36 | name: admin 37 | protocol: TCP 38 | - containerPort: 8086 39 | name: http 40 | protocol: TCP -------------------------------------------------------------------------------- /demos/hands-on-pods/influxdb-persistentdisk.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | name: influxdb 6 | name: influxdb 7 | spec: 8 | volumes: 9 | - name: "influxdb-data" 10 | gcePersistentDisk: 11 | pdName: influxdb 12 | fsType: ext4 13 | containers: 14 | - image: docker.io/tutum/influxdb:latest 15 | name: influxdb 16 | volumeMounts: 17 | - mountPath: "/data" 18 | name: "influxdb-data" 19 | resources: 20 | limits: 21 | cpu: "500m" 22 | memory: "128Mi" 23 | readinessProbe: 24 | httpGet: 25 | path: /ping 26 | port: 8086 27 | initialDelaySeconds: 5 28 | timeoutSeconds: 1 29 | livenessProbe: 30 | httpGet: 31 | path: /ping 32 | port: 8086 33 | initialDelaySeconds: 15 34 | timeoutSeconds: 1 35 | ports: 36 | - containerPort: 8083 37 | name: admin 38 | protocol: TCP 39 | - containerPort: 8086 40 | name: http 41 | protocol: TCP -------------------------------------------------------------------------------- /demos/hands-on-pods/influxdb-readiness.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | name: influxdb 6 | name: influxdb 7 | spec: 8 | containers: 9 | - image: docker.io/tutum/influxdb:latest 10 | name: influxdb 11 | readinessProbe: 12 | httpGet: 13 | path: /ping 14 | port: 8086 15 | initialDelaySeconds: 5 16 | timeoutSeconds: 1 17 | livenessProbe: 18 | httpGet: 19 | path: /ping 20 | port: 8086 21 | initialDelaySeconds: 15 22 | timeoutSeconds: 1 23 | ports: 24 | - containerPort: 8083 25 | name: admin 26 | protocol: TCP 27 | - containerPort: 8086 28 | name: http 29 | protocol: TCP -------------------------------------------------------------------------------- /demos/hands-on-pods/influxdb-resource-limits.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | name: influxdb 6 | name: influxdb 7 | spec: 8 | containers: 9 | - image: docker.io/tutum/influxdb:latest 10 | name: influxdb 11 | resources: 12 | limits: 13 | cpu: "500m" 14 | memory: "128Mi" 15 | readinessProbe: 16 | httpGet: 17 | path: /ping 18 | port: 8086 19 | initialDelaySeconds: 5 20 | timeoutSeconds: 1 21 | livenessProbe: 22 | httpGet: 23 | path: /ping 24 | port: 8086 25 | initialDelaySeconds: 15 26 | timeoutSeconds: 1 27 | ports: 28 | - containerPort: 8083 29 | name: admin 30 | protocol: TCP 31 | - containerPort: 8086 32 | name: http 33 | protocol: TCP -------------------------------------------------------------------------------- /demos/hands-on-pods/influxdb-simple.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | name: influxdb 6 | name: influxdb 7 | spec: 8 | containers: 9 | - image: docker.io/tutum/influxdb:latest 10 | name: influxdb 11 | ports: 12 | - containerPort: 8083 13 | name: admin 14 | protocol: TCP 15 | - containerPort: 8086 16 | name: http 17 | protocol: TCP -------------------------------------------------------------------------------- /demos/hands-on-pods/local-persistent-volume.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolume 2 | apiVersion: v1 3 | metadata: 4 | name: pv0001 5 | labels: 6 | type: local 7 | spec: 8 | capacity: 9 | storage: 1Gi 10 | accessModes: 11 | - ReadWriteOnce 12 | hostPath: 13 | path: "/tmp/data01" -------------------------------------------------------------------------------- /demos/hands-on-pods/local-pvc.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: myclaim-1 5 | spec: 6 | accessModes: 7 | - ReadWriteOnce 8 | resources: 9 | requests: 10 | storage: 1Gi -------------------------------------------------------------------------------- /demos/hands-on-pods/namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: "Namespace" 3 | apiVersion: "v1" 4 | metadata: 5 | name: "demo-pods" 6 | labels: 7 | name: "demo-pods" 8 | -------------------------------------------------------------------------------- /demos/quota/quota.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: "v1" 3 | kind: "ResourceQuota" 4 | metadata: 5 | name: "quota" 6 | spec: 7 | hard: 8 | memory: "1Gi" 9 | cpu: "20" 10 | pods: "10" 11 | services: "5" 12 | replicationcontrollers: "20" 13 | resourcequotas: "1" 14 | -------------------------------------------------------------------------------- /demos/replication-controllers/inspector-rc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | labels: 5 | app: inspector 6 | track: stable 7 | name: inspector 8 | spec: 9 | replicas: 1 10 | selector: 11 | app: inspector 12 | track: stable 13 | template: 14 | metadata: 15 | labels: 16 | app: inspector 17 | track: stable 18 | spec: 19 | containers: 20 | - image: b.gcr.io/kuar/inspector:1.0.0 21 | imagePullPolicy: IfNotPresent 22 | name: inspector 23 | resources: {} 24 | terminationMessagePath: /dev/termination-log 25 | dnsPolicy: ClusterFirst 26 | restartPolicy: Always 27 | status: 28 | observedGeneration: 1 29 | replicas: 1 -------------------------------------------------------------------------------- /demos/secrets/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: mysecret 5 | type: Opaque 6 | data: 7 | password: dmFsdWUtMg0K 8 | username: dmFsdWUtMQ0K -------------------------------------------------------------------------------- /demos/services/inspector-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: inspector 5 | labels: 6 | app: inspector 7 | spec: 8 | type: NodePort 9 | selector: 10 | app: inspector 11 | ports: 12 | - name: http 13 | port: 80 14 | protocol: TCP 15 | -------------------------------------------------------------------------------- /demos/termination/termination.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-w-message 5 | spec: 6 | restartPolicy: Always 7 | containers: 8 | - name: messager 9 | image: "centos:7" 10 | command: ["/bin/sh","-c"] 11 | args: ["sleep 60 && /bin/echo Sleep expired > /dev/termination-log"] 12 | terminationMessagePath: /dev/termination-log 13 | -------------------------------------------------------------------------------- /slideshow/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/.DS_Store -------------------------------------------------------------------------------- /slideshow/conference-redhat.yaml: -------------------------------------------------------------------------------- 1 | source: slideshow 2 | destination: slideshow/generated 3 | backend: revealjs-redhat 4 | rendering: adoc2html 5 | 6 | mode: 'development' # Default value = production. Available : 'production', 'development" 7 | tracer: 'false' 8 | level: 'INFO' # Values available : DEBUG, INFO, WARN, ERROR, FATAL. Default for production : 'WARN' and development 'DEBUG' 9 | logname: hyla.log # Name of the log file 10 | 11 | attributes: 12 | linkcss!: true 13 | data-uri: true 14 | allow-uri-read: 15 | idprefix: 16 | linkattrs: 17 | linkcss: 18 | # scripts: jquery-1.11.2.min.js,gpe.min.js 19 | # scriptsdir: revealjs-redhat/lib/js 20 | 21 | # Code source highlight 22 | source-highlighter: highlightjs # prettify, pygments, coderay, highlightjs 23 | highlightjs-theme: zenburn # highlightjs-theme: solarized_dark , github, foundation, zenburn, dark, solarized_light, zenburn, docco, atelier-heath.light, tomorrow-night-blue, tomorrow-night-eighties 24 | 25 | # Font Icons - http://fortawesome.github.io/Font-Awesome/icons/ 26 | icon-arrow-left: 27 | icon-arrow-right: 28 | icon-arrow-down: 29 | icon-arrow-downcenter: 30 | icon-arrow-up: 31 | icon-plus: 32 | icon-exclamation-mark: 33 | icon-exclamation-triangle: 34 | icon-question-mark: 35 | icon-cloud: 36 | icon-smile-o: 37 | icon-ambulance: 38 | icon-cogs: 39 | icon-wrench: 40 | icon-co-spin: 41 | icon-frown-o: 42 | icon-angle-double-right: 43 | blank-space: ' ' 44 | 45 | icons: font 46 | 47 | # Use Remote resources of Font Awesome Icons (css) 48 | # iconfont-remote: true # Uncomment this line 49 | # iconfont-cdn: http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css 50 | 51 | # Use Local resource of Font-Awesome 52 | # iconfont-remote: # Comment this line 53 | iconfont-name: font-awesome-4.3.0 54 | 55 | revealjsdir: "revealjs-redhat" 56 | revealjs_theme: conference # Revealjs RedHat css theme 57 | revealjs_transition: none # default/cube/page/concave/zoom/linear/fade/none 58 | revealjs_display_slidenumber: true 59 | revealjs_history: true 60 | revealjs_cover_image: redhat-logo.png 61 | revealjs_partners_logo: redhat_EMEA_partnerconf_logo_2015.png 62 | revealjs_scrollbar: true 63 | revealjs_footer_copyright: Copyright ©2015 Red Hat, Inc. 64 | revealjs_slideshow: false 65 | # 66 | -------------------------------------------------------------------------------- /slideshow/day1.adoc: -------------------------------------------------------------------------------- 1 | :footer_copyright: Copyright ©2015 Red Hat, Inc. 2 | :imagesdir: images/ 3 | :speaker: Christian Posta 4 | :speaker-title: Principal Middleware Architect 5 | :speaker-email: christian@redhat.com 6 | :speaker-blog: http://blog.christianposta.com 7 | :speaker-twitter: http://twitter.com/christianposta[@christianposta] 8 | :talk-speaker: {speaker} 9 | :talk-name: Intro: Docker and Kubernetes training - Day 1 10 | :talk-date: 10/19/2015 11 | 12 | [#cover,data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 13 | == {blank-space} 14 | 15 | [#block,width="200px",left="70px",top="0px"] 16 | image::{revealjs_cover_image}[] 17 | 18 | [#cover-h1,width="600px",left="0px",top="200px"] 19 | {talk-name} 20 | 21 | [#cover-h2,width="800px",left="0px",top="450px"] 22 | {speaker} + 23 | {talk-date} 24 | 25 | // ************** who - christian ******** 26 | [#who] 27 | == Who 28 | 29 | [.noredheader,cols="30,70"] 30 | |=== 31 | | image:ceposta.png[width="90%",height="100%"] 32 | | {speaker-title} 33 | 34 | Blog: {speaker-blog} 35 | 36 | Twitter: {speaker-twitter} 37 | 38 | Email: {speaker-email} | 39 | |=== 40 | 41 | * Committer on Apache ActiveMQ, Apache Camel, Fabric8 42 | * Technology evangelist, recovering consultant 43 | * Spent a lot of time working with one of the largest Microservices, web-scale, unicorn companies 44 | * Frequent blogger and speaker about open-source, cloud, microservices 45 | 46 | // ************** Agenda ******** 47 | [#agenda] 48 | == Agenda 49 | 50 | * Intro / Prep Environments 51 | * *Day 1: Docker Deep Dive* 52 | * Day 2: Kubernetes Deep Dive 53 | * Day 3: Advanced Kubernetes: Concepts, Management, Middleware 54 | * Day 4: Advanced Kubernetes: CI/CD, open discussions 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | // ************** transition page - docker deep dive******************************************************************* 66 | [#transition1-deep-dive, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 67 | == {blank-space} 68 | 69 | [#block,width="200px",left="70px",top="0px"] 70 | image::{revealjs_cover_image}[] 71 | 72 | [#cover-h1,width="600px",left="0px",top="400px"] 73 | *Docker Deep Dive* 74 | 75 | // ************** what is it******** 76 | [#whatisit1] 77 | == What is this Docker thing? 78 | 79 | * A company? 80 | * A format? 81 | * An API? 82 | 83 | [#block,width="100px",top="120px",left="300px"] 84 | image:docker-logo.png[role="right"] 85 | 86 | // ************** what is it******** 87 | [#linuxcontainers] 88 | == Linux containers? That's not new... 89 | 90 | * Linux-native functionality 91 | * Has been around ~ 10 years? 92 | * cgroups 93 | * kernel namespaces 94 | * chroot 95 | * Linux capabilities 96 | * Security (SELinux) 97 | 98 | [#block,width="100px",top="220px",left="400px"] 99 | image:linux.png[role="right"] 100 | 101 | // ************** what is it******** 102 | [#cgroups] 103 | == cgroups 104 | 105 | * Built into Kernel (RHEL7/Debian/etc) 106 | * Generically isolates resource usage (CPU, memory, disk, network) 107 | * Guarantee resources to app/set of apps 108 | * Can be adjusted on the fly 109 | * Can monitor the cgroup itself to see utilization 110 | 111 | 112 | [#block,width="100px",top="220px",left="470px"] 113 | image:day1/intro-cgroups.png[width="85%",height="85%"] 114 | 115 | // ************** what is it******** 116 | [#namespaces] 117 | == Kernel namespaces 118 | 119 | * Isolating views of the system 120 | * Can make a process think it's the only process 121 | * Built-in way to "virtualize" a process 122 | 123 | [#block,width="100px",top="220px",left="470px"] 124 | image:day1/scope.png[width="85%",height="85%"] 125 | 126 | // ************** what is it******** 127 | [#namespaceslist] 128 | == Kernel namespaces 129 | 130 | * *mnt* (mount points, filesystem) 131 | * *pid* (processes) 132 | * *net* (network stack) 133 | * *ipc* (inter-process comms) 134 | * *uts* (hostname) 135 | * *user* (UIDs) 136 | 137 | // ************** what is it******** 138 | [#linuxcaps] 139 | == Linux capabilities 140 | 141 | * *"root"* has *all* capabilities 142 | * a fine-grained division of "root"'s permissions for a process 143 | * *CAP_NET_ADMIN* - modify routing tables, firewalling, NAT, etc 144 | * *CAP_KILL* - bypass any checks for sending the kill signals 145 | * *CAP_SYS_ADMIN* - mount, set hostname, etc 146 | 147 | // ************** what is it******** 148 | [#docker-bring-together] 149 | == Docker brings together 150 | 151 | [#block,width="100px",top="100px",left="50px"] 152 | image:day1/docker.png[width="90%",height="90%"] 153 | 154 | // ************** what is it******** 155 | [#whyimportant1] 156 | == Why is this important? 157 | 158 | * Image format vs golden image 159 | * API 160 | * Packaging 161 | * Separation of concerns (Devs/Ops) 162 | * Density, infrastructure utilization 163 | 164 | // ************** what is it******** 165 | [#dockerformat] 166 | == Docker format 167 | 168 | [#block,width="100px",top="100px",left="50px"] 169 | image:day1/docker-layers.png[width="90%",height="90%"] 170 | 171 | // ************** what is it******** 172 | [#processvirtualization] 173 | == Process virtualization 174 | 175 | [#block,width="100px",top="100px",left="50px"] 176 | image:day1/docker-animated-1.gif[width="90%",height="90%"] 177 | 178 | // ************** what is it******** 179 | [#immutableinfra] 180 | == Immutable infrastructure 181 | 182 | * "We'll put it back in Ansible" 183 | * Cattle vs Pets 184 | * Don't change it; *replace it* 185 | * System created fully from automation; *avoid drift* 186 | * Manual intervention is error prone 187 | * How does Docker help? 188 | 189 | [#block,width="100px",top="300px",left="450px"] 190 | image:day1/cattle.jpg[width="90%",height="90%"] 191 | 192 | // ************** what is it******** 193 | [#docker-components] 194 | == Basic Docker components 195 | 196 | * Docker client 197 | * Docker daemon 198 | * Images 199 | * Registry 200 | * Containers 201 | 202 | 203 | // ************** what is it******** 204 | [#docker-components2] 205 | == Basic Docker components 206 | 207 | [#block,width="100px",top="100px",left="50px"] 208 | image:day1/docker-components.png[width="90%",height="90%"] 209 | 210 | 211 | // ************** what is it******** 212 | [#docker-images] 213 | == Docker images 214 | 215 | * *Templates* from which containers are created 216 | * *Layered* using union filesystems 217 | * Each change to the system is a layer 218 | * Typically created with Dockerfiles/instructions 219 | * Stored in a docker registry (public/private) 220 | 221 | // ************** what is it******** 222 | [#docker-containers] 223 | == Docker containers 224 | 225 | * *Runtime* instances of a Docker Image 226 | * Copy on write file system; changes localized 227 | * *"virtualized"* with namespaces, cgroups, selinux, etc 228 | * Has own IP address/networking/volumes 229 | * Intended to *run single process* (process virtualization) 230 | 231 | 232 | // ************** what is it******** 233 | [#dev-workflow] 234 | == Developer workflow 235 | 236 | * work from *vagrant image* 237 | * can trash and reboot it any time 238 | * *locally* running docker client 239 | * Source code in developer IDE 240 | * When ready, use tooling to *generate docker image* (or hand craft) 241 | * Run image locally (possibly with others) 242 | * Push code (or image?) 243 | * CI process kicks in 244 | 245 | // ************** what is it******** 246 | [#dev-workflow-2] 247 | == Developer works locally 248 | 249 | [#block,width="100px",top="100px",left="50px"] 250 | image:day1/workflow1.png[width="100%",height="100%"] 251 | 252 | // ************** what is it******** 253 | [#dev-workflow-3] 254 | == Developer pushes code 255 | 256 | [#block,width="100px",top="100px",left="50px"] 257 | image:day1/workflow2.png[width="100%",height="100%"] 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | // ************** transition page ************************************************************************************** 269 | [#your-first-docker, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 270 | == {blank-space} 271 | 272 | [#block,width="200px",left="70px",top="0px"] 273 | image::{revealjs_cover_image}[] 274 | 275 | [#cover-h1,left="0px",top="350px",width="2000px"] 276 | *Your First Docker!* 277 | 278 | // ************** Your first Docker ******** 279 | [#pull-docker-image] 280 | == Pull a docker image 281 | 282 | Pull Centos7 from DockerHub (http://docker.io) 283 | 284 | ``` 285 | docker pull centos:7 286 | ``` 287 | 288 | output: 289 | 290 | ceposta@postamac(~) $ docker pull centos:7 291 | 7: Pulling from library/centos 292 | 293 | fa5be2806d4c: Pull complete 294 | 0cd86ce0a197: Pull complete 295 | e9407f1d4b65: Pull complete 296 | c9853740aa05: Pull complete 297 | e9fa5d3a0d0e: Pull complete 298 | Digest: sha256:def5c79bc29849815dec7dddc8f75530a9115c94d5b17e0e6807f929902fab62 299 | Status: Downloaded newer image for centos:7 300 | 301 | 302 | // ************** Your first Docker ******** 303 | [#list-docker-images] 304 | == List docker images 305 | 306 | List locally, installed images 307 | 308 | ``` 309 | docker images 310 | ``` 311 | 312 | output: 313 | 314 | ceposta@postamac(~) $ docker images 315 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 316 | centos 7 e9fa5d3a0d0e 2 days ago 172.3 MB 317 | 318 | Show all images, including itermmediate 319 | 320 | ``` 321 | docker images -a 322 | ``` 323 | 324 | output: 325 | 326 | ceposta@postamac(~) $ docker images -a 327 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 328 | centos 7 e9fa5d3a0d0e 2 days ago 172.3 MB 329 | c9853740aa05 2 days ago 172.3 MB 330 | e9407f1d4b65 2 days ago 172.3 MB 331 | 0cd86ce0a197 2 days ago 172.3 MB 332 | fa5be2806d4c 5 weeks ago 0 B 333 | 334 | 335 | // ************** Your first Docker ******** 336 | [#run-docker-image] 337 | == Let's run a Docker container! 338 | 339 | Let's run a linux command inside a docker container: 340 | 341 | ``` 342 | docker run --rm centos:7 echo "hello world" 343 | ``` 344 | 345 | output: 346 | 347 | ceposta@postamac(~) $ docker run --rm centos:7 echo "hello world" 348 | hello world 349 | 350 | Woah, what happened? It just printed out "hello, world"? So what? 351 | 352 | 353 | // ************** Your first Docker ******** 354 | [#run-docker-image2] 355 | == Let's run a Docker container! 356 | 357 | Let's run a shell inside a docker container: 358 | 359 | ``` 360 | docker run -it --rm centos:7 bash 361 | ``` 362 | 363 | output: 364 | 365 | [root@d7dfcc490cbe /]# _ 366 | 367 | Cool! We have a bash shell, and a minimal distro of Centos 7! 368 | Did you see how fast that booted up? 369 | Typing `ls -l /etc/*-release` from the new bash prompt shows us we indeed have a Centos 7 distro: 370 | 371 | [root@c2c2b8a65afe /]# ll /etc/*-release 372 | -rw-r--r-- 1 root root 38 Mar 31 2015 /etc/centos-release 373 | -rw-r--r-- 1 root root 393 Mar 31 2015 /etc/os-release 374 | lrwxrwxrwx 1 root root 14 Aug 14 21:00 /etc/redhat-release -> centos-release 375 | lrwxrwxrwx 1 root root 14 Aug 14 21:00 /etc/system-release -> centos-release 376 | 377 | 378 | // ************** Your first Docker ******** 379 | [#run-docker-image3] 380 | == Let's run a Docker container! 381 | 382 | Run some other commands from within the container: 383 | 384 | ``` 385 | hostname -f 386 | cat /etc/hosts 387 | ps aux 388 | yum -y install vim 389 | ip a 390 | ``` 391 | 392 | A real linux distro right? Did you notice that *`ps aux`* didn't show too many processes? 393 | 394 | 395 | // ************** Your first Docker ******** 396 | [#run-docker-image4] 397 | == Let's run a Docker container! 398 | 399 | Let's do some destructive stuff: 400 | 401 | ``` 402 | rm -fr /usr/sbin 403 | ``` 404 | 405 | Wuh? you deleted all of the sacred system tools!? 406 | 407 | Let's delete some user tools too 408 | 409 | ``` 410 | rm -fr /usr/bin 411 | ``` 412 | 413 | output: 414 | 415 | [root@c2c2b8a65afe /]# ls 416 | bash: /usr/bin/ls: No such file or directory 417 | 418 | Whoops... cannot *`ls`* or do anything useful anymore. What have we done!? 419 | 420 | // ************** Your first Docker ******** 421 | [#run-docker-image5] 422 | == Let's run a Docker container! 423 | 424 | No worries! Just *`exit`* the container and fire up a new one: 425 | 426 | ``` 427 | docker run -it --rm centos:7 bash 428 | ``` 429 | 430 | Everything is back! Phew.... 431 | 432 | // ************** Your first Docker ******** 433 | [#run-docker-explore-tomcat] 434 | == Deploy Apache Tomcat 435 | 436 | Now let's run a JVM based application like Apache Tomcat: 437 | 438 | ``` 439 | docker run --rm -p 8888:8080 tomcat:8.0 440 | ``` 441 | 442 | Since the Tomcat 8.0 docker image doesn't exist, Docker will try to automatically pull it from the registry. Give it 443 | a moment, and you should see tomcat start successfully: 444 | 445 | 16-Oct-2015 18:30:51.541 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/manager has finished in 28 ms 446 | 16-Oct-2015 18:30:51.542 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /usr/local/tomcat/webapps/examples 447 | 16-Oct-2015 18:30:52.108 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/examples has finished in 566 ms 448 | 16-Oct-2015 18:30:52.117 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /usr/local/tomcat/webapps/ROOT 449 | 16-Oct-2015 18:30:52.161 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/ROOT has finished in 45 ms 450 | 16-Oct-2015 18:30:52.176 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 451 | 16-Oct-2015 18:30:52.206 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"] 452 | 16-Oct-2015 18:30:52.208 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1589 ms 453 | 454 | 455 | // ************** Your first Docker ******** 456 | [#run-docker-explore-tomcat2] 457 | == Deploy Apache Tomcat 458 | 459 | Let's explore that command for a quick sec: 460 | 461 | ``` 462 | docker run --rm -p 8888:8080 tomcat:8.0 463 | ``` 464 | 465 | * *`--rm`* tells us that we want to remove the container (delete) when it's done running 466 | * *`-p 8888:8080`* tells us we want to map the container's port *`8080`* to the host port of *`8888`* 467 | 468 | So if we try to connect to *`http://localhost:8888`* we should be able to reach our tomcat server! 469 | 470 | 471 | // ************** Your first Docker ******** 472 | [#run-docker-explore-tomcat3] 473 | == Deploy Apache Tomcat 474 | 475 | Well, not quite. Why not? 476 | 477 | [#block,width="200px",top="250px",left="150px"] 478 | image:day1/docker-ports.png[width="120%",height="120%"] 479 | 480 | Our Docker Host has been mapped properly, but we cannot reach it from our host (Windows/MacOSX) because the VM does 481 | not expose those ports. 482 | 483 | // ************** Your first Docker ******** 484 | [#map-ports-tomcat] 485 | == Map ports for tomcat 486 | 487 | Enable port forwarding between the VM Host (windows/Mac) and the VM Guest (Docker host): 488 | 489 | [#block,width="200px",top="175px",left="150px"] 490 | image:day1/port-forward.png[width="100%",height="100%"] 491 | 492 | // ************** Your first Docker ******** 493 | [#map-ports-tomcat-diagram] 494 | == Map ports for tomcat 495 | 496 | [#block,width="200px",top="250px",left="150px"] 497 | image:day1/docker-host-ports.png[width="120%",height="120%"] 498 | 499 | 500 | // ************** Your first Docker ******** 501 | [#run-docker-explore-tomcat6] 502 | == Deploy Apache Tomcat 503 | 504 | Now navigate in a browser to `http://localhost:8888` 505 | 506 | [#block,width="200px",top="125px",left="0px"] 507 | image:day1/tomcat.png[width="100%",height="100%"] 508 | 509 | 510 | // ************** Your first Docker ******** 511 | [#run-docker-explore-tomcat7] 512 | == Deploy Apache Tomcat 513 | 514 | We have a running container that has tomcat in it! WooHoo! Let's explore the tomcat container really quick. 515 | Fire up a new shell window (separate than the running tomcat docker container from previous) 516 | 517 | ``` 518 | docker ps 519 | ``` 520 | 521 | output: 522 | 523 | ceposta@postamac(~) $ docker ps 524 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 525 | c2c059a3baab tomcat:8.0 "catalina.sh run" 36 minutes ago Up 36 minutes 0.0.0.0:8888->8080/tcp dreamy_kowalevski 526 | 527 | Let's log into the container to explore: 528 | 529 | ``` 530 | docker exec -it bash 531 | ``` 532 | 533 | We should now be at the bash prompt for the tomcat container. Feel free to explore around a bit. 534 | 535 | // ************** Your first Docker ******** 536 | [#run-docker-explore-tomcat8] 537 | == Deploy Apache Tomcat 538 | 539 | Now exit out of the tomcat container 540 | 541 | exit 542 | 543 | And switch back to the other window where we ran tomcat. Let's *`CTR+C`* that window and exit the docker container. 544 | 545 | We should have no containers running: 546 | 547 | ``` 548 | docker ps 549 | ``` 550 | 551 | Nor should we have any stopped containers: 552 | 553 | ``` 554 | docker ps -a 555 | ``` 556 | 557 | This is because we used the *`--rm`* command when we started the tomcat container, so it will automatically remove 558 | the container. 559 | 560 | 561 | // ************** Your first Docker ******** 562 | [#useful-docker-run] 563 | == Deploy Apache Tomcat 564 | 565 | Here are some other useful `docker run` flags: 566 | 567 | * *`--name`* give your container a unique name 568 | * *`-d`* run your container in daemon mode (in the background) 569 | * *`--dns`* give your container a different nameserver from the host 570 | * *`-it`* interactive with tty (wouldn't use this with `-d`) 571 | * *`-e`* pass in environment variables to the container 572 | * *`--expose`* expose ports from the docker container 573 | * *`-P`* expose all published ports on the container 574 | * *`-p`* map a specific port from the container to the host `host:container` 575 | 576 | We will look at *`--link`* and *`--volume`* later today. 577 | 578 | // ************** Your first Docker ******** 579 | [#run-docker-tomcat-daemon] 580 | == Deploy Apache Tomcat as a Daemon 581 | 582 | Let's use some of those previous `run` command-line flags and start tomcat in the background: 583 | 584 | ``` 585 | docker run -d --name="tomcat8" -p 8888:8080 tomcat:8.0 586 | ``` 587 | 588 | Note, we also gave this container a name, so we can refer to it by name instead of container id: 589 | 590 | ``` 591 | docker logs tomcat8 592 | ``` 593 | 594 | output: 595 | 596 | examples 597 | 16-Oct-2015 19:19:20.441 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/examples has finished in 526 ms 598 | 16-Oct-2015 19:19:20.447 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /usr/local/tomcat/webapps/ROOT 599 | 16-Oct-2015 19:19:20.507 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/ROOT has finished in 60 ms 600 | 16-Oct-2015 19:19:20.515 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 601 | 16-Oct-2015 19:19:20.527 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"] 602 | 16-Oct-2015 19:19:20.547 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1497 ms 603 | 604 | // ************** Your first Docker ******** 605 | [#run-docker-tomcat-daemon-2] 606 | == Deploy Apache Tomcat as a Daemon 607 | 608 | Let's use a couple of interesting docker commands with our `tomcat8` container: 609 | 610 | ``` 611 | docker top tomcat8 612 | ``` 613 | 614 | I know, a little misnamed -- instead of the normal linux `top` container, it just displays the processes running in the 615 | container: 616 | 617 | PID USER COMMAND 618 | 5301 root /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start 619 | 620 | // ************** Your first Docker ******** 621 | [#run-docker-tomcat-daemon-3] 622 | == Deploy Apache Tomcat as a Daemon 623 | 624 | What about this one: 625 | 626 | ``` 627 | docker inspect tomcat8 628 | ``` 629 | 630 | Wow... that's a lot of information about the container! We can also use a `--format` template to pick out specific info 631 | from that output (see `https://docs.docker.com/reference/commandline/inspect/`) 632 | 633 | ``` 634 | docker inspect --format='{{.NetworkSettings.IPAddress}}' tomcat8 635 | ``` 636 | 637 | or 638 | 639 | ``` 640 | docker inspect --format='{{.Config.Env}}' tomcat8 641 | ``` 642 | 643 | output: 644 | 645 | 646 | ceposta@postamac(~) $ docker inspect --format='{{.Config.Env}}' tomcat8 647 | [PATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LANG=C.UTF-8 JAVA_VERSION=7u79 JAVA_DEBIAN_VERSION=7u79-2.5.6-1~deb8u1 CATALINA_HOME=/usr/local/tomcat TOMCAT_MAJOR=8 TOMCAT_VERSION=8.0.28 TOMCAT_TGZ_URL=https://www.apache.org/dist/tomcat/tomcat-8/v8.0.28/bin/apache-tomcat-8.0.28.tar.gz] 648 | 649 | 650 | // ************** Your first Docker ******** 651 | [#stop-and-remove] 652 | == Stop and Remove container 653 | 654 | Feel free to play around with the container a little bit more. When finished, stop the container: 655 | 656 | ``` 657 | docker stop tomcat8 658 | ``` 659 | 660 | If you run `docker ps` you shouldn't see the container running any more. However, `docker run -a` will show all containers 661 | even the stopped ones. We can remove a container with: 662 | 663 | ``` 664 | docker rm tomcat8 665 | ``` 666 | 667 | Then neither `docker ps` nor `docker ps -a` should show the container. 668 | 669 | 670 | // ************** transition page ************************************************************************************** 671 | [#docker-registry, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 672 | == {blank-space} 673 | 674 | [#block,width="200px",left="70px",top="0px"] 675 | image::{revealjs_cover_image}[] 676 | 677 | [#cover-h1,left="0px",top="350px",width="2000px"] 678 | *Docker registry* 679 | 680 | // ************** Docker registry ******** 681 | [#dockerformat-deep] 682 | == Docker Images 683 | 684 | [#block,width="100px",top="100px",left="50px"] 685 | image:day1/docker-layers.png[width="90%",height="90%"] 686 | 687 | // ************** Docker registry ******** 688 | [#dockerformat-deep] 689 | == Docker Images 690 | 691 | * Image tags 692 | * Points to a specific layer 693 | * Usually the last most layer gets changed 694 | * Can have multiple tags each pointing to diff layers; same base 695 | * don't use `latest` if you can help it 696 | 697 | // ************** Docker registry ******** 698 | [#images-on-disk] 699 | == Docker Images 700 | 701 | Let's start a container and check where the images/containers live on disk: 702 | 703 | ``` 704 | docker run -it --rm centos:7 bash 705 | ``` 706 | 707 | Now in another window, let's list the docker containers running: 708 | 709 | ``` 710 | docker ps 711 | ``` 712 | 713 | Take note of the container ID. Let'ss ssh into the VM and see where the images/containers are stored: 714 | 715 | ``` 716 | docker-machine ssh default 717 | ``` 718 | 719 | Now: 720 | 721 | ``` 722 | sudo su - 723 | cd /var/lib/docker 724 | find ./aufs/mnt -name * 725 | ``` 726 | 727 | This is the location where your container lives. If you inspect that folder, you'll see the running container's 728 | files right there. 729 | 730 | Each directory in that location is a layer in the image. If you matched `docker images -a` you should see all of those 731 | layers in the /var/lib/docker/aufs/mnt folder 732 | 733 | // ************** Docker registry ******** 734 | [#storage-backends] 735 | == Device backends 736 | 737 | * vfs 738 | ** Simple 739 | ** No copy-on-write support (deep copy) 740 | ** Each layer is a complete listing of the FS 741 | ** Robust/portable 742 | * devicemapper 743 | ** block-level copy on write 744 | * aufs 745 | ** original docker backend 746 | ** not supported upstream (Fedora) 747 | ** not supported RHEL 748 | ** regular files and aufs metadata 749 | ** works on files/not blocks 750 | 751 | // ************** Docker registry ******** 752 | [#docker-hub] 753 | == Public/private docker registry 754 | 755 | * Docker hub: `http://docker.io` 756 | * Can host public images 757 | ** ie, search for fedora, or jenkins, etc 758 | * Can also host private repos (like github) 759 | * Other registries: 760 | ** JFrog 761 | ** Quay.io 762 | ** Google Container Registry 763 | 764 | // ************** Docker registry ******** 765 | [#enterprise-registry] 766 | == Enterprise docker registry 767 | 768 | * Be careful with images on Docker hub 769 | ** vulnerabilities 770 | ** run as root 771 | ** http://www.infoq.com/news/2015/05/Docker-Image-Vulnerabilities 772 | * Use trusted registries 773 | * Red Hat Docker registry 774 | ** registry.access.redhat.com:5000 775 | 776 | Try pulling: 777 | 778 | ``` 779 | docker pull registry.access.redhat.com/rhel7 780 | ``` 781 | 782 | // ************** Docker registry ******** 783 | [#creating-images] 784 | == Creating Docker images 785 | 786 | Encouraged to build docker images from `Dockerfile` s 787 | 788 | ``` 789 | FROM fabric8/java-agent-bond 790 | 791 | MAINTAINER fabric8@googlegroups.com 792 | 793 | ENV CLASSPATH /maven/*:/maven 794 | 795 | RUN mkdir /maven 796 | 797 | EXPOSE 8778 9779 798 | 799 | ADD run.sh /fabric8/run.sh 800 | CMD [ "/fabric8/run.sh" ] 801 | ``` 802 | 803 | // ************** Docker registry ******** 804 | [#dockerfile] 805 | == Dockerfile 806 | 807 | Constructs such as the following: 808 | 809 | * *`FROM`* 810 | * *`ADD`* 811 | * *`COPY`* 812 | * *`USER`* 813 | * *`ENV`* 814 | * *`VOLUME`* 815 | * *`WORKDIR`* 816 | * *`CMD`* 817 | * *`ENTRYPOINT`* 818 | 819 | Each step in the docker file is a new image layer! Don't put passwords into the docker file! 820 | 821 | 822 | // ************** Docker registry ******** 823 | [#dockerfile2] 824 | == Advanced Dockerfile 825 | 826 | ``` 827 | FROM ubuntu:14.04 828 | 829 | MAINTAINER fabric8.io (http://fabric8.io/) 830 | 831 | ENV GERRIT_HOME /home/gerrit 832 | ENV GERRIT_TMP_DIR /home/tmp 833 | ENV GERRIT_USER gerrit 834 | ENV GERRIT_VERSION 2.11 835 | 836 | RUN \ 837 | sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list && \ 838 | apt-get update && \ 839 | DEBIAN_FRONTEND=noninteractive apt-get -y upgrade && \ 840 | DEBIAN_FRONTEND=noninteractive apt-get install -y sudo vim-tiny git && \ 841 | DEBIAN_FRONTEND=noninteractive apt-get install -y openjdk-7-jre-headless && \ 842 | DEBIAN_FRONTEND=noninteractive apt-get install -y curl 843 | 844 | # Add user gerrit & group like also gerrit to sudo to allow the gerrit user to issue a sudo cmd 845 | RUN groupadd $GERRIT_USER && \ 846 | useradd -r -u 1000 -g $GERRIT_USER $GERRIT_USER 847 | 848 | RUN mkdir ${GERRIT_HOME} 849 | 850 | # Download Gerrit 851 | ADD http://gerrit-releases.storage.googleapis.com/gerrit-${GERRIT_VERSION}.war ${GERRIT_HOME}/${GERRIT_WAR} 852 | 853 | # Copy the files to bin, config & job folders 854 | ADD ./configs ${GERRIT_HOME}/configs 855 | 856 | # Copy the plugins 857 | ADD ./plugins ${GERRIT_HOME}/plugins 858 | 859 | WORKDIR ${GERRIT_HOME} 860 | 861 | EXPOSE 8080 29418 862 | CMD ["/home/gerrit/bin/conf-and-run-gerrit.sh"] 863 | ``` 864 | 865 | // ************** Docker registry ******** 866 | [#diff-cmd-entrypoing] 867 | == Difference between CMD and ENTRYPOINT 868 | 869 | * *`CMD`* can be overridden at run time 870 | ** docker run -it centos:7 871 | * *`ENTRYPOINT`* fixed command, pass things in as parameters 872 | ** docker run -it centos:7 873 | 874 | // ************** Docker registry ******** 875 | [#demo-creating-images] 876 | == Demo creating Docker images 877 | 878 | * clone the following repository: 879 | 880 | git clone git@github.com:fabric8io/base-images.git 881 | 882 | * `cd` into ./base-images/java/images/centos/openjdk8/jdk 883 | 884 | 885 | 886 | Run the folowing command from the directory that has the `Dockerfile` 887 | 888 | ``` 889 | docker build -t local.io/docker-java:latest . 890 | ``` 891 | 892 | Don't forget the `.` character! 893 | 894 | Now list the docker images: 895 | 896 | ``` 897 | docker images 898 | ``` 899 | 900 | output: 901 | 902 | ceposta@postamac(jdk (master)) $ docker images 903 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 904 | local.io/docker-java latest 8d11c57aafa6 Less than a second ago 431 MB 905 | tomcat 8.0 1e41e2ebc383 2 days ago 347.7 MB 906 | centos 7 e9fa5d3a0d0e 3 days ago 172.3 MB 907 | registry.access.redhat.com/rhel7 latest 82ad5fa11820 5 weeks ago 158.3 MB 908 | registry.access.redhat.com/rhel latest 82ad5fa11820 5 weeks ago 158.3 MB 909 | 910 | 911 | // ************** Docker registry ******** 912 | [#local-docker-registry] 913 | == Running a local docker registry 914 | 915 | * The old "python" based docker registry (before Docker 1.6 has been deprecated 916 | * New docker registry exists in "Docker Distribution" tools 917 | * https://github.com/docker/distribution 918 | * Can run local / scaled out docker registries 919 | * Backed by storage 920 | * Getting started: https://docs.docker.com/registry/ 921 | 922 | // ************** Docker registry ******** 923 | [#local-registry-arch] 924 | == Registry architecture 925 | 926 | [#block,width="200px",top="150px",left="150px"] 927 | image:day1/local-registry.png[width="170%",height="170%"] 928 | 929 | // ************** Docker registry ******** 930 | [#local-registry-backends] 931 | == Registry architecture 932 | 933 | Storage backends: 934 | 935 | * Implemented with a Storage API that can be extended 936 | * https://docs.docker.com/registry/storagedrivers/ 937 | * *`inmemory`* local, in-memory; only expected for testing/reference 938 | * *`filesystem`* local-storage driver 939 | * *`s3`* Amazon S3 buckets 940 | * *`azure`* Microsoft blob storage 941 | * *`rados`* Ceph object storage 942 | * *`swift`* OpenStack object storage 943 | * *`oss`* Aliyun OSS 944 | 945 | // ************** Docker registry ******** 946 | [#deploy-registry] 947 | == Registry architecture 948 | 949 | Let's deploy a local registry and try it out 950 | 951 | ``` 952 | docker run -d -p 5000:5000 --name registry registry:2 953 | ``` 954 | 955 | Note, you'll need to link:#map-ports-tomcat[open ports 5000 on your VM to allow forwarding to work] 956 | 957 | output: 958 | 959 | ceposta@postamac(temp) $ docker run -d -p 5000:5000 --name registry registry:2 960 | Unable to find image 'registry:2' locally 961 | 2: Pulling from library/registry 962 | 963 | f9a9f253f610: Pull complete 964 | eeb7cb91b09d: Pull complete 965 | 3c9a9d7cc6a2: Pull complete 966 | 0a17decee413: Pull complete 967 | cc85b2c38995: Pull complete 968 | 24a16bad4623: Pull complete 969 | ec4c9e01c657: Pull complete 970 | e200ab995df6: Pull complete 971 | b3b2a507517e: Pull complete 972 | 34e7db8ae1dc: Pull complete 973 | 2eafecf5086b: Pull complete 974 | Digest: sha256:802127562bcb59ac617a1296d70023258f22fc3e401fa86c866447a8c36e4278 975 | Status: Downloaded newer image for registry:2 976 | d89a9c4719089af289e38bcc436dff0db37aa1e82ebbe5e19ce508d87dd9cd0a 977 | 978 | // ************** Docker registry ******** 979 | [#push-to-registry] 980 | == Push to registry 981 | 982 | Let's tag and push our previously created docker image to our new registry: 983 | 984 | ``` 985 | docker tag local.io/docker-java localhost:5000/local.io/docker-java 986 | ``` 987 | 988 | then push it: 989 | 990 | ``` 991 | docker push localhost:5000/local.io/docker-java 992 | ``` 993 | 994 | output: 995 | 996 | ceposta@postamac(jdk (master)) $ docker push localhost:5000/local.io/docker-java 997 | The push refers to a repository [localhost:5000/local.io/docker-java] (len: 1) 998 | 8d11c57aafa6: Image successfully pushed 999 | f17de9438beb: Image successfully pushed 1000 | b492cca03931: Image successfully pushed 1001 | 9e3ba2489e43: Image successfully pushed 1002 | e7c1009b53b0: Image successfully pushed 1003 | 0a4fb08c5519: Image successfully pushed 1004 | 78c95afc4258: Image successfully pushed 1005 | 85d17ebc1200: Image successfully pushed 1006 | 83af41871016: Image successfully pushed 1007 | 9dbce2cf69a6: Image successfully pushed 1008 | d33d90067fc7: Image successfully pushed 1009 | 0aa3329df0b4: Image successfully pushed 1010 | e9fa5d3a0d0e: Image already exists 1011 | c9853740aa05: Image already exists 1012 | e9407f1d4b65: Image already exists 1013 | 0cd86ce0a197: Image successfully pushed 1014 | fa5be2806d4c: Image already exists 1015 | latest: digest: sha256:0cebcc42cbc25848524eff2cf4aa9d5a47e5d360c5ebfb931e6d33cfd8a38b97 size: 29837 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | // ************** transition page ************************************************************************************* 1026 | [#deploy-javaee, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 1027 | == {blank-space} 1028 | 1029 | [#block,width="200px",left="70px",top="0px"] 1030 | image::{revealjs_cover_image}[] 1031 | 1032 | [#cover-h1,left="0px",top="350px",width="2000px"] 1033 | *Deploying Java EE applications* 1034 | 1035 | 1036 | // ************** Deploy Java EE ******** 1037 | [#deploy-javaee-server] 1038 | == Deploying a Java EE app server 1039 | 1040 | First map the ports `8080` and `9990` from the VM to your host link:#map-ports-tomcat[following the steps previusly]. 1041 | 1042 | We will follow the similar steps we used to deploy Tomcat and will re-use the port mappings we had earlier. 1043 | Verify your tomcat server is no longer running on `8888` and follow these steps: 1044 | 1045 | 1046 | ``` 1047 | docker pull arungupta/wildfly-management 1048 | docker run -d -p 9990:9990 -p 8080:8080 --name wildfly arungupta/wildfly-management 1049 | docker ps 1050 | 1051 | ``` 1052 | 1053 | Navigate to link:http://localhost:8080[http://localhost:8080] to see the main page. Click "Administration Console" and login to the management console with `admin/docker#admin` 1054 | 1055 | You can deploy applictions using the admin console... or do it the Docker way! 1056 | 1057 | // ************** Deploy Java EE ******** 1058 | [#deploy-javaee-application] 1059 | == Deploying a Java EE application 1060 | 1061 | As discussed earlier, the "Docker way" is to package up your app as a new layer on top of the app server Docker image: 1062 | Let's look at an example Dockerfile: 1063 | 1064 | ``` 1065 | # Use latest jboss/wildfly 1066 | FROM jboss/wildfly 1067 | 1068 | MAINTAINER "Rafael Benevides" 1069 | 1070 | #Create admin user 1071 | RUN /opt/jboss/wildfly/bin/add-user.sh -u admin -p docker#admin --silent 1072 | 1073 | # Add customization folder 1074 | COPY customization /opt/jboss/wildfly/customization/ 1075 | 1076 | USER root 1077 | 1078 | # Run customization scripts as root 1079 | RUN chmod +x /opt/jboss/wildfly/customization/execute.sh 1080 | RUN /opt/jboss/wildfly/customization/execute.sh standalone standalone-ha.xml 1081 | 1082 | ADD ticket-monster.war /opt/jboss/wildfly/standalone/deployments/ 1083 | 1084 | # Fix for Error: Could not rename /opt/jboss/wildfly/standalone/configuration/standalone_xml_history/current 1085 | RUN rm -rf /opt/jboss/wildfly/standalone/configuration/standalone_xml_history 1086 | 1087 | RUN chown -R jboss:jboss /opt/jboss/wildfly/ 1088 | 1089 | USER jboss 1090 | 1091 | # Expose the ports we're interested in 1092 | EXPOSE 8080 9990 1093 | 1094 | # Set the default command to run on boot 1095 | # This will boot WildFly in the standalone mode and bind to external interface and enable HA 1096 | CMD /opt/jboss/wildfly/bin/standalone.sh -b `hostname -i` -bmanagement `hostname -i` -c standalone-ha.xml 1097 | ``` 1098 | 1099 | // ************** Deploy Java EE ******** 1100 | [#deploy-javaee-application2] 1101 | == Deploying a Java EE application 1102 | 1103 | Deploy the application: 1104 | 1105 | First stop and remove the previous wildfly deployment 1106 | 1107 | ``` 1108 | docker stop wildfly 1109 | docker rm wildfly 1110 | ``` 1111 | Now run the new app: 1112 | 1113 | ``` 1114 | docker run -d -p 9990:9990 -p 8080:8080 --name wildfly arungupta/javaee7-hol 1115 | ``` 1116 | 1117 | Navigate to link:http://localhost:8080/movieplex7[http://localhost:8080/movieplex7] to see the Java EE application 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | // ************** transition page ************************************************************************************* 1127 | [#Communicating between containers, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 1128 | == {blank-space} 1129 | 1130 | [#block,width="200px",left="70px",top="0px"] 1131 | image::{revealjs_cover_image}[] 1132 | 1133 | [#cover-h1,left="0px",top="350px",width="2000px"] 1134 | *Communicating between docker containers* 1135 | 1136 | 1137 | // ************** Communicating between docker container ******** 1138 | [#understand-docker-bridge] 1139 | == Quickly understand default docker networking 1140 | 1141 | [#block,width="200px",top="150px",left="75px"] 1142 | image:day1/docker-network.png[width="170%",height="170%"] 1143 | 1144 | 1145 | // ************** Communicating between docker container ******** 1146 | [#understand-docker-links] 1147 | == Linking Containers 1148 | 1149 | * We want containers to communicate with each other 1150 | * Each container has an IP (veth/eth0) 1151 | * Containers can expose virtual ports 1152 | * Docker bridge networking can link containers without going over host network 1153 | * How do we discover IP addresses, etc? 1154 | 1155 | ``` 1156 | docker run --link :alias ..... 1157 | ``` 1158 | 1159 | 1160 | // ************** Communicating between docker container ******** 1161 | [#understand-docker-links2] 1162 | == Linking Containers 1163 | 1164 | ``` 1165 | docker run --link :alias ..... 1166 | ``` 1167 | 1168 | * Name your containers!!!!!!! 1169 | * links depend on this 1170 | * `alias` is what your containers will see as environment variables 1171 | 1172 | example: 1173 | 1174 | ``` 1175 | docker run --rm --name web2 --link db:db training/webapp env 1176 | ``` 1177 | 1178 | Will create these environment variables: 1179 | 1180 | DB_NAME=/web2/db 1181 | DB_PORT=tcp://172.17.0.5:5432 1182 | DB_PORT_5432_TCP=tcp://172.17.0.5:5432 1183 | DB_PORT_5432_TCP_PROTO=tcp 1184 | DB_PORT_5432_TCP_PORT=5432 1185 | DB_PORT_5432_TCP_ADDR=172.17.0.5 1186 | 1187 | Your applications can then use environment variables to discover the dependent containers/services 1188 | 1189 | 1190 | // ************** Communicating between docker container ******** 1191 | [#understand-docker-links-dns] 1192 | == Linking Containers with DNS 1193 | 1194 | ``` 1195 | docker run -t -i --rm --link db:webdb training/webapp /bin/bash 1196 | ``` 1197 | 1198 | Check out /etc/hosts inside the container: 1199 | 1200 | 172.17.0.7 aed84ee21bde 1201 | ... 1202 | 172.17.0.5 webdb 6e5cdeb2d300 db 1203 | 1204 | So we can just refer to containers by name: `http://webdb` 1205 | 1206 | // ************** Communicating between docker container ******** 1207 | [#understand-docker-links-notes] 1208 | == Notes about linking containers 1209 | 1210 | * Injecting environment variables is a very powerful concept 1211 | * Can link multiple containers together 1212 | * The linking happens between *one host only*!! 1213 | 1214 | 1215 | // ************** Communicating between docker container ******** 1216 | [#understand-docker-links-example] 1217 | == Examples of linking: 1218 | 1219 | Run a database service which will be used by a Java EE application: 1220 | 1221 | ``` 1222 | docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -p 3306:3306 -d mysql 1223 | ``` 1224 | 1225 | Note, you may need to forward the `mysql` port `3306` in your VM. 1226 | 1227 | Now let's link up a Java EE application 1228 | 1229 | ``` 1230 | docker run -d --name mywildfly --link mysqldb:db -p 8080:8080 arungupta/wildfly-mysql-javaee7 1231 | ``` 1232 | 1233 | // ************** Communicating between docker container ******** 1234 | [#understand-docker-links-example2] 1235 | == Examples of linking: 1236 | 1237 | Our app is new using the DB, but let's log into the container and verify the environment variables/DNS was set up: 1238 | 1239 | ``` 1240 | docker exec -it mywildfly bash 1241 | ``` 1242 | 1243 | then type the following to list environment variables: 1244 | 1245 | ``` 1246 | env 1247 | ``` 1248 | 1249 | You can also take a look at the `/etc/hosts` file 1250 | 1251 | ``` 1252 | cat /etc/hosts` 1253 | ``` 1254 | 1255 | 1256 | [jboss@c924917fe4ad ~]$ cat /etc/hosts 1257 | 172.17.0.30 c924917fe4ad 1258 | 127.0.0.1 localhost 1259 | ::1 localhost ip6-localhost ip6-loopback 1260 | fe00::0 ip6-localnet 1261 | ff00::0 ip6-mcastprefix 1262 | ff02::1 ip6-allnodes 1263 | ff02::2 ip6-allrouters 1264 | 172.17.0.28 db ef59a1b98326 mysqldb 1265 | 172.17.0.30 mywildfly.bridge 1266 | 172.17.0.18 registry 1267 | 172.17.0.18 registry.bridge 1268 | 172.17.0.28 mysqldb 1269 | 172.17.0.28 mysqldb.bridge 1270 | 172.17.0.30 mywildfly 1271 | 1272 | 1273 | // ************** transition page ************************************************************************************** 1274 | [#stateful-containers, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 1275 | == {blank-space} 1276 | 1277 | [#block,width="200px",left="70px",top="0px"] 1278 | image::{revealjs_cover_image}[] 1279 | 1280 | [#cover-h1,left="0px",top="350px",width="2000px"] 1281 | *Stateful containers* 1282 | 1283 | // ************** Volumes ******** 1284 | [#docker-no-state] 1285 | == Docker containers have no state! 1286 | 1287 | * Containers are ephemeral!!! 1288 | * Nothing is saved from a container if it goes away 1289 | * Containers get new IP addresses 1290 | * Don't treat containers as VMs: they are not!! 1291 | * But what about stateful applications? 1292 | 1293 | 1294 | // ************** Volumes ******** 1295 | [#docker-volumes] 1296 | == Docker volumes 1297 | 1298 | * Docker volumes to the rescue! 1299 | * Persist data outside of the container 1300 | * Can be mapped directly to Host locations 1301 | * Can also be deployed independently of hosts/indirectly 1302 | 1303 | Example: 1304 | 1305 | ``` 1306 | docker run -d -P --name web -v /webapp training/webapp python app.py 1307 | ``` 1308 | 1309 | 1310 | // ************** Volumes ******** 1311 | [#docker-volumes-example1] 1312 | == Example Docker volumes 1313 | 1314 | Example: 1315 | 1316 | ``` 1317 | docker run -d -P --name web -v /webapp training/webapp python app.py 1318 | ``` 1319 | 1320 | [#block,width="200px",top="250px",left="150px"] 1321 | image:day1/docker-vol.png[width="120%",height="120%"] 1322 | 1323 | // ************** Volumes ******** 1324 | [#docker-volumes-host] 1325 | == Docker host volumes 1326 | 1327 | We can also map volumes directly to Host storage locations: 1328 | 1329 | * Useful for known locations on Host 1330 | * Can use NFS mounts 1331 | * Files are visible outside of the container and are persisted 1332 | * Can restart new containers up with same location 1333 | 1334 | ``` 1335 | docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py 1336 | ``` 1337 | 1338 | 1339 | // ************** Volumes ******** 1340 | [#docker-volumes-example2] 1341 | == Example Docker host volumes 1342 | 1343 | Example: 1344 | 1345 | ``` 1346 | docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py 1347 | ``` 1348 | 1349 | [#block,width="200px",top="250px",left="150px"] 1350 | image:day1/docker-vol-host.png[width="120%",height="120%"] 1351 | 1352 | 1353 | // ************** Volumes ******** 1354 | [#docker-volumes-container-data] 1355 | == Containers as data volumes 1356 | 1357 | Start a container that will manage the volume 1358 | 1359 | ``` 1360 | docker create -v /dbdata --name dbdata training/postgres /bin/true 1361 | ``` 1362 | 1363 | Now other containers can use that container so they're not tied directly to the volumes (mounting them, etc): 1364 | 1365 | ``` 1366 | docker run -d --volumes-from dbdata --name db1 training/postgres 1367 | ``` 1368 | 1369 | [#block,width="200px",top="300px",left="75px"] 1370 | image:day1/docker-vol-datacontainer.png[width="120%",height="120%"] 1371 | 1372 | 1373 | // ************** Volumes ******** 1374 | [#docker-volumes-jenkins-example1] 1375 | == Jenkins example 1376 | 1377 | Let's take an example using Jenkins. We can fire up Jenkins containers, add build jobs, etc. 1378 | But if we delete the container, the jobs are lost. 1379 | 1380 | ``` 1381 | docker run -d --name jenkins -p 8080:8080 jenkins 1382 | ``` 1383 | 1384 | We can save the changes and jobs that jenkins creates by adding a host volume: 1385 | 1386 | ``` 1387 | docker run -d --name jenkins -p 8080:8080 -v /your/home:/var/jenkins_home jenkins 1388 | ``` 1389 | 1390 | Now when you run jenkins, you can stop, destroy, and re-run jenkins and your build jobs should be there. 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | // ************** transition page ************************************************************************************** 1400 | [#cool-docker, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 1401 | == {blank-space} 1402 | 1403 | [#block,width="200px",left="70px",top="0px"] 1404 | image::{revealjs_cover_image}[] 1405 | 1406 | [#cover-h1,left="0px",top="350px",width="2000px"] 1407 | *Other cool docker stuff* 1408 | 1409 | 1410 | 1411 | 1412 | // ************** Things to know ******** 1413 | [#things-to-know] 1414 | == Things to know 1415 | 1416 | * Docker runs on a single host! 1417 | * `/var/lib/docker` needs to be managed! 1418 | * Use only what you need in your images (avoid image bloat) 1419 | * Don't run as root 1420 | * Be careful with docker images on Docker Hub (use trusted images only) 1421 | * Container security... containers do not "contain" 1422 | ** http://opensource.com/business/14/7/docker-security-selinux 1423 | * always use image tags 1424 | * Use sanity scripts to boot your process from within container 1425 | * One task per container! 1426 | 1427 | 1428 | 1429 | 1430 | // ********************************* 1431 | [#questions] 1432 | == Questions 1433 | 1434 | [.noredheader,cols="65,.<45"] 1435 | |=== 1436 | 1437 | .2+|image:questions.png[width="95%",height="95%"] 1438 | a|* Twitter : *{speaker-twitter}* 1439 | |=== 1440 | -------------------------------------------------------------------------------- /slideshow/day2.adoc: -------------------------------------------------------------------------------- 1 | :footer_copyright: Copyright ©2015 Red Hat, Inc. 2 | :imagesdir: images/ 3 | :speaker: Christian Posta 4 | :speaker-title: Principal Middleware Architect 5 | :speaker-email: christian@redhat.com 6 | :speaker-blog: http://blog.christianposta.com 7 | :speaker-twitter: http://twitter.com/christianposta[@christianposta] 8 | :talk-speaker: {speaker} 9 | :talk-name: Intro: Docker and Kubernetes training - Day 2 10 | :talk-date: 10/20/2015 11 | 12 | [#cover,data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 13 | == {blank-space} 14 | 15 | [#block,width="200px",left="70px",top="0px"] 16 | image::{revealjs_cover_image}[] 17 | 18 | [#cover-h1,width="600px",left="0px",top="200px"] 19 | {talk-name} 20 | 21 | [#cover-h2,width="800px",left="0px",top="450px"] 22 | {speaker} + 23 | {talk-date} 24 | 25 | // ************** who - christian ******** 26 | [#who] 27 | == Who 28 | 29 | [.noredheader,cols="30,70"] 30 | |=== 31 | | image:ceposta.png[width="90%",height="100%"] 32 | | {speaker-title} 33 | 34 | Blog: {speaker-blog} 35 | 36 | Twitter: {speaker-twitter} 37 | 38 | Email: {speaker-email} | 39 | |=== 40 | 41 | * Committer on Apache ActiveMQ, Apache Camel, Fabric8 42 | * Technology evangelist, recovering consultant 43 | * Spent a lot of time working with one of the largest Microservices, web-scale, unicorn companies 44 | * Frequent blogger and speaker about open-source, cloud, microservices 45 | 46 | // ************** Agenda ******** 47 | [#agenda] 48 | == Agenda 49 | 50 | * Intro / Prep Environments 51 | * Day 1: Docker Deep Dive 52 | * *Day 2: Kubernetes Deep Dive* 53 | * Day 3: Advanced Kubernetes: Concepts, Management, Middleware 54 | * Day 4: Advanced Kubernetes: CI/CD, open discussions 55 | 56 | 57 | // ************** transition page ************************************************************************************** 58 | [#transition1, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 59 | == {blank-space} 60 | 61 | [#block,width="200px",left="70px",top="0px"] 62 | image::{revealjs_cover_image}[] 63 | 64 | [#cover-h1,width="600px",left="0px",top="400px"] 65 | *Quick Recap* 66 | 67 | // ************** Recap ******** 68 | [#recap1] 69 | == Recap Docker 70 | 71 | * *Linux* containers 72 | * Docker API 73 | * Images 74 | * Containers 75 | * Registry 76 | 77 | // ************** Recap ******** 78 | [#recap2] 79 | == Why Docker matters 80 | 81 | * Application distribution 82 | * Dependency management 83 | * Application density 84 | * Reduced management overhead in terms of VMs 85 | * On premise, hybrid, public cloud 86 | 87 | 88 | // ************** Recap ******** 89 | [#recap3] 90 | == Recap Docker 91 | 92 | * Containers run on *single* Docker host 93 | * Containers are *ephemeral* 94 | * Nothing watchdogs the containers 95 | * Containers can have external persistence 96 | * Containers do not contain 97 | * Operating system *matters* 98 | 99 | // ************** Recap ******** 100 | [#recap3] 101 | == Why you win with Docker-based solutions 102 | 103 | * Immutable infrastructure 104 | * DevOps 105 | * CI/CD 106 | * *Who cares:* give me a platform to move faster!!! 107 | 108 | 109 | // ************** transition page ************************************************************************************** 110 | [#transition2, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 111 | == {blank-space} 112 | 113 | [#block,width="200px",left="70px",top="0px"] 114 | image::{revealjs_cover_image}[] 115 | 116 | [#cover-h1,left="0px",top="350px",width="2000px"] 117 | *Local environment setup* 118 | 119 | 120 | // ************** Environment setup *********** 121 | [#prep] 122 | == Set up kubernetes 123 | 124 | * Lab prerequisites in place! 125 | * Verify you have Oracle VirtualBox 4.3.x 126 | * Install Kubernetes link:http://kubernetes.io/v1.0/docs/getting-started-guides/vagrant.html[http://kubernetes.io/v1.0/docs/getting-started-guides/vagrant.html] 127 | * Windows: need to have HVT 128 | * Understand the architecture 129 | * Smoke test 130 | 131 | 132 | 133 | // ************** Environment setup *********** 134 | [#prep-output] 135 | == Final output 136 | 137 | Waiting for each minion to be registered with cloud provider 138 | Validating we can run kubectl commands. 139 | NAME READY STATUS RESTARTS AGE 140 | Connection to 127.0.0.1 closed. 141 | 142 | Kubernetes cluster is running. The master is running at: 143 | 144 | https://10.245.1.2 145 | 146 | The user name and password to use is located in ~/.kubernetes_vagrant_auth. 147 | 148 | calling validate-cluster 149 | Found 1 nodes. 150 | NAME LABELS STATUS 151 | 1 10.245.1.3 kubernetes.io/hostname=10.245.1.3 Ready 152 | Validate output: 153 | NAME STATUS MESSAGE ERROR 154 | controller-manager Healthy ok nil 155 | scheduler Healthy ok nil 156 | etcd-0 Healthy {"health": "true"} nil 157 | Cluster validation succeeded 158 | Done, listing cluster services: 159 | 160 | Kubernetes master is running at https://10.245.1.2 161 | KubeDNS is running at https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/kube-dns 162 | KubeUI is running at https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/kube-ui 163 | 164 | 165 | // ************** Environment setup *********** 166 | [#simpelarch] 167 | == Simple kubernetes architecture 168 | 169 | [#block,width="200px",top="150px",left="75px"] 170 | image:day2/kube-diagram.png[width="170%",height="170%"] 171 | 172 | // ************** Environment setup *********** 173 | [#fullarch] 174 | == Overall Kubernetes 175 | 176 | [#block,width="200px",top="75px",left="50px"] 177 | image:day2/kubernetes-platform.png[width="100%",height="100%"] 178 | 179 | 180 | 181 | // ************** transition page ************************************************************************************** 182 | [#transition-kube, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 183 | == {blank-space} 184 | 185 | [#block,width="200px",left="70px",top="0px"] 186 | image::{revealjs_cover_image}[] 187 | 188 | [#cover-h1,left="0px",top="250px",width="2000px"] 189 | *Kubernetes* 190 | 191 | 192 | [#containterizeit] 193 | == Containerize all the things! 194 | 195 | *Everything* at Google runs in containers!! 196 | 197 | * Gmail, search, maps 198 | * 2 billion containers *a week* 199 | * GCE? VMs in containers... 200 | 201 | [#block,width="200px",left="25px",top="300px"] 202 | image:day2/all-containers.jpg[] 203 | 204 | // ************** Kubernetes intro *********** 205 | [#whatisit1] 206 | == Kube what? 207 | 208 | * "helmsman of a ship" 209 | * Containers @ Google 210 | * Borg link:http://www.infoq.com/news/2015/04/google-borg[http://www.infoq.com/news/2015/04/google-borg] 211 | * Open source 6/2014 212 | * GKE... 213 | * Red Hat a top contributor 214 | * 100% written in *golang* 215 | * Do we need this? 216 | 217 | [#block,width="200px",left="200px",top="300px"] 218 | image:kubernetes.png[] 219 | 220 | 221 | 222 | 223 | // ************** Kubernetes intro *********** 224 | [#whatisit2] 225 | == What is Kubernetes 226 | 227 | * Different way to look at managing instances: scale 228 | * Design for failure 229 | * Efficient / Lean/ Simple 230 | * Portability 231 | * Extensible 232 | 233 | 234 | // ************** Kubernetes intro *********** 235 | [#whatisit3] 236 | == What is Kubernetes 237 | 238 | * How to place containers on a cluster 239 | * Smart placement 240 | * How to interact with a system that does placement 241 | * Different than configuration management 242 | ** Immutable infrastructure principles 243 | * What to do when containers fail? 244 | * *Containers will fail* 245 | * Cluster security authZ/authN 246 | * Scaling 247 | * Grouping/Aggregates 248 | 249 | 250 | // ************** Kubernetes intro *********** 251 | [#whyisitimportant] 252 | == Why is it important 253 | 254 | * Managing containers by hand is harder than VMs: won't scale 255 | * Automate the boilerplate stuff 256 | * Runbooks -> Scripts -> Config management -> Scale 257 | * Decouple application from machine! 258 | * Applications run on "resources" 259 | * Kubernetes manages this interaction of applications and resources 260 | * *Manage applications, not machines!* 261 | * What about *legacy apps?* 262 | 263 | 264 | // ************** Kubernetes intro *********** 265 | [#coreconcets] 266 | == Kubernetes core concepts 267 | 268 | * Simplicity, Simplicity, Simplicity 269 | * *Pods* 270 | * *Labels* / *Selectors* 271 | * *Replication Controllers* 272 | * *Services* 273 | * API -- link:http://kubernetes.io/third_party/swagger-ui/[http://kubernetes.io/third_party/swagger-ui/] 274 | 275 | [#block,width="200px",left="250px",top="400px"] 276 | image:day2/kube-pods.png[] 277 | 278 | 279 | 280 | // ************** Kubernetes intro *********** 281 | [#controlplane] 282 | == Reconciliation of end state 283 | 284 | [#block,width="200px",left="50px",top="170px"] 285 | image:day2/make-it-so.png[height="200%",width="200%"] 286 | 287 | 288 | 289 | 290 | // ************** Kubernetes intro *********** 291 | [#controlplane] 292 | == Kubernetes control plane 293 | 294 | * etcd 295 | * API Server 296 | * Scheduler 297 | * Controller manager 298 | 299 | [#block,width="200px",left="50px",top="300px"] 300 | image:day2/kube-control-plane.png[height="150%",width="150%"] 301 | 302 | 303 | // ************** Kubernetes intro *********** 304 | [#etcd] 305 | == etcd 306 | 307 | * Open source project started at CoreOS 308 | * Distributed database 309 | * CAP Theorem? == CP 310 | * Raft algorithm/protocol 311 | * watchable 312 | * etcd provides HA datastore 313 | 314 | 315 | [#block,width="200px",left="250px",top="250px"] 316 | image:day2/etcd.png[height="75%",width="75%"] 317 | 318 | 319 | // ************** Kubernetes intro *********** 320 | [#nodes] 321 | == Kubernetes nodes 322 | 323 | * Nodes are VMs / physical hosts 324 | * Nodes need connectivity between them 325 | * Ideally same network/data center/availability zone 326 | 327 | 328 | [#block,width="200px",left="50px",top="250px"] 329 | image:day2/node-connectivity.png[height="150%",width="150%"] 330 | 331 | // ************** Kubernetes intro *********** 332 | [#nodes1-overall] 333 | == Kubernetes nodes 334 | 335 | [#block,width="200px",left="50px",top="150px"] 336 | image:day2/kube-control-plane-nodes.png[height="150%",width="150%"] 337 | 338 | 339 | // ************** Kubernetes intro *********** 340 | [#nodes1] 341 | == Kubernetes nodes 342 | 343 | * Kubelet 344 | ** Watches for pods to be assigned to node 345 | ** Mount volumes 346 | ** Install secrets 347 | ** Runs the pod (via Docker) 348 | ** Reports pod status / node status 349 | * kube-proxy 350 | ** Connection forwarding 351 | ** Kube services 352 | * Docker 353 | 354 | 355 | 356 | 357 | // ************** Kubernetes intro *********** 358 | [#cluster-addons] 359 | == Cluster add-ons 360 | 361 | * Monitoring 362 | * DNS 363 | * UI 364 | * Logging 365 | 366 | 367 | 368 | // ************** Kubernetes intro *********** 369 | [#quick-demo] 370 | == Quick Demo! 371 | 372 | 373 | link:https://github.com/kubernetes/kubernetes/blob/release-1.0/examples/guestbook/README.md[Guestbook demo] 374 | 375 | [#block,width="200px",left="50px",top="50px"] 376 | image:day2/demo.jpg[height="100%",width="100%"] 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | // ************** transition page ************************************************************************************** 389 | [#deepdive, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 390 | == {blank-space} 391 | 392 | [#block,width="200px",left="70px",top="0px"] 393 | image::{revealjs_cover_image}[] 394 | 395 | [#cover-h1,left="0px",top="350px",width="2000px"] 396 | *Kubernetes Deep Dive* 397 | 398 | 399 | 400 | // ************** Kubernetes deep dive *********** 401 | [#core-concepts] 402 | == Kubernetes core concepts 403 | 404 | * *Pods* 405 | * *Labels* / *Selectors* 406 | * *Replication Controllers* 407 | * *Services* 408 | 409 | 410 | // ************** Kubernetes deep dive *********** 411 | [#deep-pods] 412 | == Kubernetes Pods 413 | 414 | * A pod is one or more docker containers 415 | * Ensures collocation / shared fate 416 | * Pods are scheduled and do not move nodes 417 | * Docker containers share resources within the pod 418 | ** Volumes 419 | ** Network / IP 420 | ** Port space 421 | ** CPU / Mem allocations 422 | * Pod health probes 423 | ** Readiness 424 | ** Liveness 425 | 426 | 427 | // ************** Kubernetes deep dive *********** 428 | [#deep-pods-image] 429 | == Kubernetes Pods 430 | 431 | [#block,width="400px",left="50px",top="100px"] 432 | image:day2/deep-pod.png[height="175%",width="175%"] 433 | 434 | 435 | // ************** Kubernetes deep dive *********** 436 | [#pod-creation] 437 | == Kubernetes Pods 438 | 439 | [#block,width="400px",left="50px",top="100px"] 440 | image:day2/pod-creation.png[height="175%",width="175%"] 441 | 442 | // ************** Kubernetes deep dive *********** 443 | [#deep-pods-probes] 444 | == Pod probes 445 | 446 | * Out of the box 447 | ** Readiness 448 | ** Liveness 449 | * Probe types 450 | ** ExecAction 451 | ** TCPSocketAction 452 | ** HTTPGetAction 453 | * Results 454 | ** Success 455 | ** Failure 456 | ** Unknown 457 | 458 | 459 | // ************** Kubernetes deep dive *********** 460 | [#deep-pods-restart-policy] 461 | == Pod restart policies 462 | 463 | * Pods restarted on single node 464 | * Only replication controller reschedules 465 | * RestartPolicy 466 | ** Always (default) 467 | ** OnFailure 468 | ** Never 469 | * Applies to all containers in the pod 470 | * For replication controllers, only _Always_ applicable 471 | 472 | // ************** Kubernetes deep dive *********** 473 | [#deep-pods-restart-policy2] 474 | == Pod restart policies 475 | 476 | Some Examples: 477 | 478 | * Pod is Running, 1 container, container exits success 479 | ** Always: restart container, pod stays Running 480 | ** OnFailure: pod becomes Succeeded 481 | ** Never: pod becomes Succeeded 482 | * Pod is Running, 1 container, container exits failure 483 | ** Always: restart container, pod stays Running 484 | ** OnFailure: restart container, pod stays Running 485 | ** Never: pod becomes Failed 486 | * Pod is Running, 2 containers, container 1 exits failure 487 | ** Always: restart container, pod stays Running 488 | ** OnFailure: restart container, pod stays Running 489 | ** Never: pod stays Running 490 | 491 | When container 2 exits... 492 | 493 | ** Always: restart container, pod stays Running 494 | ** OnFailure: restart container, pod stays Running 495 | ** Never: pod becomes Failed 496 | 497 | // ************** Kubernetes deep dive *********** 498 | [#deep-pods-termination] 499 | == Termination messages 500 | 501 | * Help debug problems by putting messages into "termination log" 502 | * default location `/dev/termination-log` 503 | * Quick demo? 504 | 505 | 506 | // ************** Kubernetes deep dive *********** 507 | [#first-pod] 508 | == Your first pod 509 | 510 | Let's take a look at the Kubernetes resource file that we will use and evolve for the purposes of this first 511 | hands-on experience: 512 | 513 | ``` 514 | apiVersion: v1 515 | kind: Pod 516 | metadata: 517 | labels: 518 | name: influxdb 519 | name: influxdb 520 | spec: 521 | containers: 522 | - image: docker.io/tutum/influxdb:latest 523 | name: influxdb 524 | ports: 525 | - containerPort: 8083 526 | name: admin 527 | protocol: TCP 528 | - containerPort: 8086 529 | name: http 530 | protocol: TCP 531 | ``` 532 | 533 | 534 | 535 | // ************** Kubernetes deep dive *********** 536 | [#deploy-first-pod] 537 | == Deploy the influxdb pod 538 | 539 | You can either copy/paste that locally, or download the pod resource file like this: 540 | 541 | ``` 542 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/hands-on-pods/influxdb-simple.yaml -O influxdb-simple.yaml 543 | ``` 544 | 545 | Once you have the file locally downloaded, run the kubectl command (`./cluster/kubectl.sh`) like this: 546 | 547 | ``` 548 | kubectl create -f influxdb-simple.yaml 549 | ``` 550 | 551 | Wait for the Docker image to download and the pod to start. Can watch it like this: 552 | 553 | ``` 554 | kubectl get pod --watch 555 | ``` 556 | 557 | Can watch the docker events in another window like this (to keep track of what's happening on the docker side) -- note, you'll need to be logged into `minion-1` directly to see the docker events: 558 | 559 | ``` 560 | docker events 561 | ``` 562 | 563 | // ************** Kubernetes deep dive *********** 564 | [#inspect-first-pod] 565 | == Interact with your first Kubernetes pod 566 | 567 | Now that we have our first pod up, let's see where it's deployed: 568 | 569 | ``` 570 | kubectl describe pod/influxdb 571 | ``` 572 | 573 | Note where it's deployed (Node field). 574 | 575 | ceposta@postamac(kubernetes (master)) $ kubectl describe pod/influxdb 576 | Name: influxdb 577 | Namespace: demo-pods 578 | Image(s): docker.io/tutum/influxdb:latest 579 | Node: 10.245.1.3/10.245.1.3 580 | Labels: name=influxdb 581 | Status: Running 582 | Reason: 583 | Message: 584 | IP: 10.246.1.7 585 | Replication Controllers: 586 | Containers: 587 | influxdb: 588 | Image: docker.io/tutum/influxdb:latest 589 | State: Running 590 | Started: Sun, 18 Oct 2015 17:09:16 -0700 591 | Ready: True 592 | Restart Count: 0 593 | Conditions: 594 | Type Status 595 | Ready True 596 | Events: 597 | 598 | 599 | 600 | // ************** Kubernetes deep dive *********** 601 | [#query-our-first-pod] 602 | == Interact with your first Kubernetes pod 603 | 604 | Let's login to our minion-1 machine and interact with the pod. We found out which machine the pod was running on in the last slide. 605 | 606 | ``` 607 | vagrant ssh minion-1 608 | ``` 609 | 610 | Let's try ping the pod to see if we can reach it from the minion (we could have also logged into the `master` and run the same commands; the assumption kubernetes makes is a flat network reachable from anywhere in the cluster. More on the kubrentes network model in Day 3). 611 | 612 | ``` 613 | ping 10.246.1.7 614 | ``` 615 | 616 | Note, you should use the IP address of the pod from the above `kubectl describe` command. 617 | 618 | 619 | [vagrant@kubernetes-master ~]$ ping 10.246.1.7 620 | PING 10.246.1.7 (10.246.1.7) 56(84) bytes of data. 621 | 64 bytes from 10.246.1.7: icmp_seq=1 ttl=63 time=2.43 ms 622 | 64 bytes from 10.246.1.7: icmp_seq=2 ttl=63 time=8.41 ms 623 | 64 bytes from 10.246.1.7: icmp_seq=3 ttl=63 time=1.27 ms 624 | 64 bytes from 10.246.1.7: icmp_seq=4 ttl=63 time=2.23 ms 625 | ^C 626 | --- 10.246.1.7 ping statistics --- 627 | 4 packets transmitted, 4 received, 0% packet loss, time 3004ms 628 | rtt min/avg/max/mdev = 1.271/3.587/8.411/2.819 ms 629 | 630 | 631 | // ************** Kubernetes deep dive *********** 632 | [#query-our-first-pod2] 633 | == Interact with your first Kubernetes pod 634 | 635 | Now, let's issue a command to that IP address. Note, these commands must be run from either `master` or `minion-1` 636 | 637 | ``` 638 | export INFLUX_NODE=10.246.1.7 639 | curl -G "http://$INFLUX_NODE:8086/query" --data-urlencode "q=CREATE DATABASE kubernetes" 640 | curl -X POST "http://$INFLUX_NODE:8086/write?db=kubernetes" -d 'pod,host=node0 count=10' 641 | curl -G "http://$INFLUX_NODE:8086/query?pretty=true" --data-urlencode "db=kubernetes" --data-urlencode "q=SELECT SUM(count) FROM pod" 642 | ``` 643 | 644 | We add a new database to the influxdb index, then we add some data, and finally we query it. You should see '10' as the result. 645 | 646 | 647 | // ************** Kubernetes deep dive *********** 648 | [#is-pod-healthy] 649 | == Adding readiness and liveness checks 650 | 651 | At this point, we've deployed our first application on Kubernetes, but it doesn't do too much. Earlier we discussed the different probe options we have for determining whether a pod is healthy or ready for action. Let's add some of that to our pod. The pod YAML resource looks like this: 652 | 653 | ``` 654 | apiVersion: v1 655 | kind: Pod 656 | metadata: 657 | labels: 658 | name: influxdb 659 | name: influxdb 660 | spec: 661 | containers: 662 | - image: docker.io/tutum/influxdb:latest 663 | name: influxdb 664 | readinessProbe: 665 | httpGet: 666 | path: /ping 667 | port: 8086 668 | initialDelaySeconds: 5 669 | timeoutSeconds: 1 670 | livenessProbe: 671 | httpGet: 672 | path: /ping 673 | port: 8086 674 | initialDelaySeconds: 15 675 | timeoutSeconds: 1 676 | ports: 677 | - containerPort: 8083 678 | name: admin 679 | protocol: TCP 680 | - containerPort: 8086 681 | name: http 682 | protocol: TCP 683 | ``` 684 | 685 | // ************** Kubernetes deep dive *********** 686 | [#is-pod-healthy2] 687 | == Adding readiness and liveness checks 688 | 689 | First, let's stop and remove our previous `influxdb` pod since we'll be re-doing it this time with health-checking: 690 | 691 | ``` 692 | kubectl stop pod/influxdb 693 | ``` 694 | 695 | Curl the pod resource as we did before. 696 | 697 | ``` 698 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/hands-on-pods/influxdb-readiness.yaml -O influxdb-rediness.yaml 699 | ``` 700 | 701 | Use the `kubectl` command line again to create our pod: 702 | 703 | ``` 704 | kubectl create -f influxdb-readiness.yaml 705 | ``` 706 | 707 | // ************** Kubernetes deep dive *********** 708 | [#is-pod-healthy3] 709 | == Adding readiness and liveness checks 710 | 711 | Now that we've deployed our liveness and readiness checks, our Pod is not automatically monitored by kubernetes. If there is ever an issue with it, Kubernetes will kill the pod and depending on its *restartPolicy* will take action. 712 | 713 | 714 | // ************** Kubernetes deep dive *********** 715 | [#pod-resources] 716 | == Adding resource constraints to our pods 717 | 718 | We have readiness and liveness checks, but we may also want to constrain what the `influxdb` pod(s) do in terms of isolation and CPU/Memory usage. We don't want a single pod taking over all of the underlying resources and starving other processes. 719 | 720 | Let's alter our pod yaml resource descriptor to add in resource constraints: 721 | 722 | ``` 723 | apiVersion: v1 724 | kind: Pod 725 | metadata: 726 | labels: 727 | name: influxdb 728 | name: influxdb 729 | spec: 730 | containers: 731 | - image: docker.io/tutum/influxdb:latest 732 | name: influxdb 733 | resources: 734 | limits: 735 | cpu: "500m" 736 | memory: "128Mi" 737 | readinessProbe: 738 | httpGet: 739 | path: /ping 740 | port: 8086 741 | initialDelaySeconds: 5 742 | timeoutSeconds: 1 743 | livenessProbe: 744 | httpGet: 745 | path: /ping 746 | port: 8086 747 | initialDelaySeconds: 15 748 | timeoutSeconds: 1 749 | ports: 750 | - containerPort: 8083 751 | name: admin 752 | protocol: TCP 753 | - containerPort: 8086 754 | name: http 755 | protocol: TCP 756 | ``` 757 | 758 | // ************** Kubernetes deep dive *********** 759 | [#pod-resources] 760 | == Adding resource constraints to our pods 761 | 762 | Let's stop our previous pod, download the new manifest and run it: 763 | 764 | ``` 765 | kubectl stop pod/influxdb 766 | ``` 767 | 768 | Curl the pod resource as we did before. 769 | 770 | ``` 771 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/hands-on-pods/influxdb-resource-limits.yaml -O influxdb-resource-limits.yaml 772 | ``` 773 | 774 | 775 | Use the `kubectl` command line again to create our pod: 776 | 777 | ``` 778 | kubectl create -f influxdb-resource-limits.yaml 779 | ``` 780 | 781 | Now our pod is allocated specific limits so we can sleep at night knowing we have resource isolation. 782 | 783 | // ************** Kubernetes deep dive *********** 784 | [#pods-volumes] 785 | == Stateful containers 786 | 787 | Whenever we add new databases to our `influxdb` and then stop the pod, we find that the data in the `influxdb` is not persisted. Let's add a way to persist that information. 788 | 789 | 790 | Kubernetes offers a few persistence mechanisms out of the box: 791 | 792 | * emtpyDir 793 | * hostpath 794 | * gcePersistentDisk 795 | * awsElasticBlockStorage 796 | * nfs 797 | * glusterfs 798 | * gitRepo 799 | 800 | // ************** Kubernetes deep dive *********** 801 | [#pods-volumes-hostpath] 802 | == Stateful containers 803 | 804 | In tomorrow's demo, we'll show how to use a shared-storage mechanism in Google Compute Engine to create stateful pods. But for now, we'll just map to a location on the Node/host. Note this has implications about pod rescheduling etc that will discussed in the class. 805 | 806 | Let's create the Kubernetes Persistent Volume 807 | 808 | ``` 809 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/hands-on-pods/local-persistent-volume.yaml | kubectl create -f - 810 | ``` 811 | 812 | Now we're going to create a "claim" for persistent volume space (details explained in class): 813 | 814 | ``` 815 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/hands-on-pods/local-pvc.yaml | kubectl create -f - 816 | ``` 817 | 818 | Make sure our influxdb pod is stopped 819 | 820 | ``` 821 | kubectl stop pod influxdb 822 | ``` 823 | 824 | And now deploy our new pod that uses the PersistentVolume: 825 | 826 | ``` 827 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/hands-on-pods/influxdb-local-pv.yaml | kubectl create -f - 828 | ``` 829 | 830 | // ************** Kubernetes deep dive *********** 831 | [#pods-volumes-query-influx] 832 | == Stateful containers 833 | 834 | Now let's figure out what IP address the new influxd pod lives: 835 | 836 | ``` 837 | kubectl describe pod/influxdb 838 | ``` 839 | 840 | And now let's query/interact with influxdb 841 | 842 | ``` 843 | export INFLUX_NODE=10.246.1.7 844 | curl -G "http://$INFLUX_NODE:8086/query" --data-urlencode "q=CREATE DATABASE kubernetes" 845 | curl -X POST "http://$INFLUX_NODE:8086/write?db=kubernetes" -d 'pod,host=node0 count=10' 846 | curl -X POST "http://$INFLUX_NODE:8086/write?db=kubernetes" -d 'pod,host=node1 count=9' 847 | curl -X POST "http://$INFLUX_NODE:8086/write?db=kubernetes" -d 'pod,host=node2 count=12' 848 | curl -G "http://$INFLUX_NODE:8086/query?pretty=true" --data-urlencode "db=kubernetes" --data-urlencode "q=SELECT SUM(count) FROM pod" 849 | ``` 850 | 851 | 852 | // ************** Kubernetes deep dive *********** 853 | [#pods-volumes-query-influx-restart] 854 | == Stateful containers 855 | 856 | Now let's kill the pod and restart it. We should see the same databases and data in the influxbd even after we restart it: 857 | 858 | ``` 859 | kubectl stop pod/influxdb 860 | ``` 861 | 862 | Restart it: 863 | 864 | ``` 865 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/hands-on-pods/influxdb-local-pv.yaml | kubectl create -f - 866 | ``` 867 | 868 | Query it: 869 | 870 | ``` 871 | curl -G "http://$INFLUX_NODE:8086/query?pretty=true" --data-urlencode "db=kubernetes" --data-urlencode "q=SELECT SUM(count) FROM pod" 872 | ``` 873 | 874 | // ************** Kubernetes deep dive *********** 875 | [#pods-in-production] 876 | == Pods in production 877 | 878 | * Use PersistentVolumes for stateful pods/containers 879 | * Use Kubernetes *secrets* to distribute credentials 880 | * Leverage readiness and liveness probes 881 | * Consider resources (CPU/Mem) limites/quotas 882 | * Use termination messages 883 | 884 | 885 | // ************** transition page ************************************************************************************** 886 | [#grouping, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 887 | == {blank-space} 888 | 889 | [#block,width="200px",left="70px",top="0px"] 890 | image::{revealjs_cover_image}[] 891 | 892 | [#cover-h1,left="0px",top="350px",width="2000px"] 893 | *Grouping, organizing your cluster* 894 | 895 | 896 | // ************** Labels ******** 897 | [#grouping-concepts] 898 | == Grouping 899 | 900 | * Decouple application dimensions from infrastructure deployments 901 | ** Tiers 902 | ** Release Tracks 903 | ** Grouping of microservices 904 | * Kubernetes clusters are dynamic 905 | * Predicated on failure 906 | * Need a way to identify groups of services 907 | * Be able to add/remove from group on failures 908 | * Needs to be flexible 909 | * Queryable 910 | * Kubernetes Labels 911 | 912 | 913 | // ************** Labels ******** 914 | [#what-are-labels] 915 | == What are Kubernetes Labels? 916 | 917 | * Arbitrary metadata 918 | * Attach to any API objects 919 | ** eg, Pods, ReplicationControllers, Endpoints, etc 920 | * Simple *key=value* assignments 921 | * Can be queried with *selectors* 922 | 923 | 924 | // ************** Labels ******** 925 | [#label-examples] 926 | == Examples 927 | 928 | * release=stable, release=canary 929 | * environment=dev, environment=qa, environment=prod 930 | * tier=frontend, tier=backend, tier=middleware 931 | * partition=customerA, partition=customerB, etc 932 | * used to group “like” objects — no expectation of uniqueness 933 | 934 | 935 | // ************** Labels ******** 936 | [#key-values] 937 | == Keys and Values 938 | 939 | * The structure of a key: 940 | ** / 941 | ** example key *`org.apache.hadoop/partition`* 942 | * Prefix can be up to `253` chars 943 | * Name can be up to `63` chars 944 | * Values can be ([a-z0-9A-Z]) with dashes (-), underscores (_), dots (.) 945 | * Values can be up to `63` chars 946 | 947 | // ************** Labels *********** 948 | [#examplelabels] 949 | == Example labels 950 | 951 | [#block,width="200px",top="70px",left="25px"] 952 | image:day2/label-pods.png[width="150%",height="150%"] 953 | 954 | 955 | // ************** Labels ******** 956 | [#selecors] 957 | == Selectors for grouping 958 | 959 | Labels are queryable metadata; selectors can do the queries: 960 | 961 | * Equality based 962 | ** environment *=* production 963 | ** tier *!=* frontend 964 | ** combinations: "tier != frontend, version = 1.0.0" 965 | * Set based 966 | ** environment *in* (production, pre-production) 967 | ** tier *notin* (frontend, backend) 968 | ** partition 969 | 970 | 971 | // ************** Labels *********** 972 | [#exampleselectors] 973 | == Example Selectors 974 | 975 | [#block,width="200px",top="70px",left="25px"] 976 | image:day2/pod-selectors.png[width="150%",height="150%"] 977 | 978 | // ************** Labels ******** 979 | [#annotations] 980 | == Annotations 981 | 982 | * Attaching useful metadata to objects; not queryable 983 | * Data that you want to know to build context; easy to have it close 984 | ** Author information 985 | ** build date/timestamp 986 | ** links to SCM 987 | ** PR numbers/gerrit patchsets 988 | * Annotations are *not* queryable *use labels for that) 989 | * Can build up tooling around annotations 990 | * link:https://oss.sonatype.org/content/repositories/public/io/fabric8/quickstarts/quickstart-karaf-camel-log/2.2.49-SNAPSHOT/quickstart-karaf-camel-log-2.2.49-20151014.171515-12-kubernetes.json[Examples] 991 | 992 | 993 | // ************** Labels ******** 994 | [#what-should-you] 995 | == What should you label and annotate? 996 | 997 | Everything. 998 | 999 | 1000 | 1001 | // ************** transition page ************************************************************************************** 1002 | [#transition-repl, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 1003 | == {blank-space} 1004 | 1005 | [#block,width="200px",left="70px",top="0px"] 1006 | image::{revealjs_cover_image}[] 1007 | 1008 | [#cover-h1,left="0px",top="250px",width="2000px"] 1009 | *Scaling and ensuring cluster invariants* 1010 | 1011 | // ************** Scaling pods *********** 1012 | [#repl-makeitso] 1013 | == Replication controllers 1014 | 1015 | [#block,width="200px",left="50px",top="170px"] 1016 | image:day2/make-it-so.png[height="200%",width="200%"] 1017 | 1018 | // ************** Scaling pods *********** 1019 | [#replcontrollers-intro] 1020 | == Replication controllers 1021 | 1022 | * Can configure the number of *replicas* of a pod 1023 | * Will be scheduled across applicable nodes 1024 | * Replication controllers can change *replica* value to scale up/down 1025 | * Which pods are scaled depends on RC selector 1026 | * Labels and selectors are the backbone of grouping 1027 | 1028 | 1029 | // ************** Scaling pods *********** 1030 | [#replcontrollers-intro] 1031 | == Replication controllers 1032 | 1033 | * Can even do complicated things with labels/RCs 1034 | * Take a pod out of cluster by changing its label 1035 | * Can have multiple RCs so no SPOF 1036 | * If a pod is unhealth (health prob), RC can kill and restart 1037 | 1038 | // ************** Scaling pods *********** 1039 | [#replcontrollers-eg] 1040 | == Example Replication controller 1041 | 1042 | ``` 1043 | apiVersion: v1 1044 | kind: ReplicationController 1045 | metadata: 1046 | labels: 1047 | app: inspector 1048 | track: stable 1049 | name: inspector 1050 | spec: 1051 | replicas: 1 1052 | selector: 1053 | app: inspector 1054 | track: stable 1055 | template: 1056 | metadata: 1057 | labels: 1058 | app: inspector 1059 | track: stable 1060 | spec: 1061 | containers: 1062 | - image: b.gcr.io/kuar/inspector:1.0.0 1063 | imagePullPolicy: IfNotPresent 1064 | name: inspector 1065 | resources: {} 1066 | terminationMessagePath: /dev/termination-log 1067 | dnsPolicy: ClusterFirst 1068 | restartPolicy: Always 1069 | status: 1070 | observedGeneration: 1 1071 | replicas: 1 1072 | ``` 1073 | 1074 | // ************** Scaling pods *********** 1075 | [#replcontrollers-eg-locally] 1076 | == Example Replication controller 1077 | 1078 | On your cluster, run the following command: 1079 | 1080 | ``` 1081 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/replication-controllers/inspector-rc.yaml | kubectl create -f - 1082 | ``` 1083 | 1084 | Then do: 1085 | 1086 | ``` 1087 | kubectl get rc 1088 | ``` 1089 | 1090 | You should see: 1091 | 1092 | CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS 1093 | inspector inspector b.gcr.io/kuar/inspector:1.0.0 app=inspector,track=stable 1 1094 | 1095 | 1096 | // ************** Scaling pods *********** 1097 | [#replcontrollers-eg-scale] 1098 | == Example scale up 1099 | 1100 | We want to change the value of the *`replicas`* for our `inspector` replication controller to scale up: 1101 | 1102 | ``` 1103 | kubectl scale rc inspector --replicas=5 1104 | ``` 1105 | 1106 | If successful, you should see: 1107 | 1108 | scaled 1109 | 1110 | Now do a "get pods" to see 1111 | 1112 | ``` 1113 | kubectl get pod 1114 | ``` 1115 | 1116 | NAME READY STATUS RESTARTS AGE 1117 | inspector-3sh6q 1/1 Running 0 13m 1118 | inspector-5djgp 1/1 Running 0 13m 1119 | inspector-9b68m 1/1 Running 0 13m 1120 | inspector-ohaod 1/1 Running 0 13m 1121 | inspector-r5bqo 1/1 Running 0 19m 1122 | 1123 | // ************** Scaling pods *********** 1124 | [#replcontrollers-eg-scale-down] 1125 | == Example scale down 1126 | 1127 | Let's scale the inspector app down to two pods: 1128 | 1129 | ``` 1130 | kubectl scale rc inspector --replicas=2 1131 | ``` 1132 | 1133 | Now when you get the pods, there should just be two. Kubernetes decides which ones to kill: 1134 | 1135 | NAME READY STATUS RESTARTS AGE 1136 | inspector-ohaod 1/1 Running 0 15m 1137 | inspector-r5bqo 1/1 Running 0 20m 1138 | 1139 | 1140 | 1141 | // ************** Scaling pods *********** 1142 | [#replcontrollers-auto] 1143 | == Autoscaling 1144 | 1145 | * Ongoing work in the community 1146 | ** https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/autoscaling.md 1147 | * Use existing monitoring tools to provide scaling 1148 | 1149 | 1150 | // ************** transition page ************************************************************************************** 1151 | [#transition-services, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 1152 | == {blank-space} 1153 | 1154 | [#block,width="200px",left="70px",top="0px"] 1155 | image::{revealjs_cover_image}[] 1156 | 1157 | [#cover-h1,left="0px",top="250px",width="2000px"] 1158 | *Loadbalancing, service discovery* 1159 | 1160 | 1161 | // ************** Services *********** 1162 | [#intro-services] 1163 | == You have lots of pods 1164 | 1165 | * Pods have their own IP address 1166 | * Pods can come and go; they're fungible 1167 | * Replication controllers maintain replica invariants 1168 | * So you have lots of Pods and IPs, which do you use? 1169 | * Use labels for grouping 1170 | * Kubernetes services does the heavy lifting of finding Pods 1171 | 1172 | 1173 | // ************** Services *********** 1174 | [#services] 1175 | == Kubernetes Services 1176 | 1177 | * Decouple providers and accessors of services 1178 | * Don't depend on Pod IPs directly 1179 | * Need to find pods that match certain selection criteria 1180 | ** mmm... labels and selectors again :) 1181 | * Pods can live on any node 1182 | * Use a single IP that doesn't change 1183 | * Virtual IP load balancing and discovery 1184 | 1185 | 1186 | // ************** Services *********** 1187 | [#services-example-arch] 1188 | == Kubernetes Services example 1189 | 1190 | [#block,width="200px",top="70px",left="0px"] 1191 | image:day2/services.png[width="170%",height="170%"] 1192 | 1193 | 1194 | // ************** Services *********** 1195 | [#services-example-yaml] 1196 | == Kubernetes Services example 1197 | 1198 | ``` 1199 | apiVersion: v1 1200 | kind: Service 1201 | metadata: 1202 | name: inspector 1203 | labels: 1204 | app: inspector 1205 | spec: 1206 | type: NodePort 1207 | selector: 1208 | app: inspector 1209 | ports: 1210 | - name: http 1211 | nodePort: 36000 1212 | port: 80 1213 | protocol: TCP 1214 | ``` 1215 | 1216 | // ************** Services *********** 1217 | [#services-example-no-selector] 1218 | == Kubernetes Services -- no selectors 1219 | 1220 | * Use selectors to locate existing kubernetes pods 1221 | * Use a service w/out selectors to point to external services 1222 | ** DB running outside of Kubernetes 1223 | 1224 | ``` 1225 | --- 1226 | kind: "Service" 1227 | apiVersion: "v1" 1228 | metadata: 1229 | name: "my-service" 1230 | spec: 1231 | ports: 1232 | - 1233 | protocol: "TCP" 1234 | port: 80 1235 | targetPort: 9376 1236 | ``` 1237 | 1238 | 1239 | // ************** Services *********** 1240 | [#services-example-no-selector2] 1241 | == Kubernetes Services -- no selectors 1242 | 1243 | Endpoint objects will not be created; will need to make those and point them where you want: 1244 | 1245 | ``` 1246 | --- 1247 | kind: "Endpoints" 1248 | apiVersion: "v1" 1249 | metadata: 1250 | name: "my-service" 1251 | subsets: 1252 | - 1253 | addresses: 1254 | - 1255 | IP: "1.2.3.4" 1256 | ports: 1257 | - 1258 | port: 80 1259 | ``` 1260 | 1261 | // ************** Services *********** 1262 | [#how-it-works-services2] 1263 | == How it works 1264 | 1265 | * When a new service/endpoint object created in etcd 1266 | * kube-proxy opens a port on the node 1267 | * Connections to that port will be proxied to the pods 1268 | * kube-proxy maintains iptables routing from the clusterIP (VIP) to the node port 1269 | 1270 | // ************** Services *********** 1271 | [#how-it-works-services] 1272 | == How it works 1273 | 1274 | [#block,width="200px",top="70px",left="0px"] 1275 | image:day2/services-overview.png[width="170%",height="170%"] 1276 | 1277 | // ************** Services *********** 1278 | [#how-it-works-services] 1279 | == Discovering services from collaborators 1280 | 1281 | * Example, UI pods need to use DB pods 1282 | *Environment variables 1283 | ** {SVCNAME}_SERVICE_HOST 1284 | ** {SVCNAME}_SERVICE_PORT 1285 | ** implies an __ordering__ requirement: service must have been created first! 1286 | * DNS (as a cluster addon — recommended) 1287 | ** {SVCNAME}.{NSNAME} 1288 | ** eg: my-service.my-namespace would be how you find a service in the my-namespace namespace 1289 | 1290 | Example: 1291 | 1292 | ``` 1293 | REDIS_MASTER_SERVICE_HOST=10.0.0.11 1294 | REDIS_MASTER_SERVICE_PORT=6379 1295 | REDIS_MASTER_PORT=tcp://10.0.0.11:6379 1296 | REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379 1297 | REDIS_MASTER_PORT_6379_TCP_PROTO=tcp 1298 | REDIS_MASTER_PORT_6379_TCP_PORT=6379 1299 | REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11 1300 | ``` 1301 | 1302 | 1303 | 1304 | // ************** Services *********** 1305 | [#service-types] 1306 | == Service types 1307 | 1308 | * ClusterIP — default, create an internal IP that can be used within pods for service discovery 1309 | * NodePort — open a port on all of the nodes that the service listens on (can be accessed from outside the cluster) 1310 | ** set type == “NodePort” 1311 | ** Will allocate a port in the default range (can be configured): 30000-32767 1312 | ** will set spec.ports.nodePort for you 1313 | *** can set it manually and it will try to use this fixed port, or it will fail 1314 | ** can then use your own loadbalancers and point to this specific port (external access) 1315 | * LoadBalancer — useful for cloud providers that expose external loadbalancers 1316 | * http://kubernetes.io/v1.0/docs/user-guide/services.html#type-loadbalancer 1317 | 1318 | 1319 | // ************** Services *********** 1320 | [#combine-service-rc] 1321 | == Combine service and RC resources 1322 | 1323 | ``` 1324 | --- 1325 | kind: "List" 1326 | apiVersion: "v1" 1327 | items: 1328 | - kind: "Service" 1329 | apiVersion: "v1" 1330 | metadata: 1331 | name: "mock" 1332 | labels: 1333 | app: "mock" 1334 | status: "replaced" 1335 | spec: 1336 | ports: 1337 | - protocol: "TCP" 1338 | port: 99 1339 | targetPort: 9949 1340 | selector: 1341 | app: "mock" 1342 | - kind: "ReplicationController" 1343 | apiVersion: "v1" 1344 | metadata: 1345 | name: "mock" 1346 | labels: 1347 | app: "mock" 1348 | status: "replaced" 1349 | spec: 1350 | replicas: 1 1351 | selector: 1352 | app: "mock" 1353 | template: 1354 | metadata: 1355 | labels: 1356 | app: "mock" 1357 | spec: 1358 | containers: 1359 | - name: "mock-container" 1360 | image: "kubernetes/pause" 1361 | ports: 1362 | - containerPort: 9949 1363 | protocol: "TCP" 1364 | ``` 1365 | 1366 | // ************** Services *********** 1367 | [#service-live-examples] 1368 | == Create a service 1369 | 1370 | Assuming you still have the replication controller from the previous section, let's create a service that 1371 | exposes the `inspector` app (https://github.com/kelseyhightower/inspector/) directly on the Nodes. 1372 | 1373 | 1374 | ``` 1375 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/services/inspector-svc.yaml | kubectl create -f - 1376 | ``` 1377 | 1378 | This service exposes to a NodePort on the Node. To see which port exactly it is exposed: 1379 | 1380 | ``` 1381 | kubectl get svc/inspector -o template -t "{{.spec.ports}}" 1382 | ``` 1383 | 1384 | Then you can query the Node (by IP if using vagrant) and the port. If you do this from outside the VMs, make sure to map 1385 | your VM port to your host. 1386 | 1387 | 1388 | // ************** Services *********** 1389 | [#example-inspector-service] 1390 | == Example output from inspector service 1391 | 1392 | [vagrant@kubernetes-master ~]$ curl -G http://10.245.1.3:30727/ 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 |
1400 | 1401 |

Inspector

1402 |

1403 | Home | 1404 | Environment | 1405 | Mounts | 1406 | Network 1407 |

1408 |
1409 |

Version: Inspector 1.0.0

1410 | 1411 | 1412 |
1413 | 1414 | 1415 | // ************** Services *********** 1416 | [#example-inspector-service2] 1417 | == Example output from inspector service 1418 | 1419 | Try running the curl command pointing to the /net path. For each call we can inspect what network information gets 1420 | returned. And if you have more than 1 replica, you should see that network information change as we access different 1421 | pods behind the service (load balanced): 1422 | 1423 | [vagrant@kubernetes-master ~]$ curl -G http://10.245.1.3:30727/net 1424 | 1425 | 1426 | eth0 1427 | 02:42:0a:f6:01:0e 1428 |
    1429 |
  • 10.246.1.14/24
  • 1430 |
  • fe80::42:aff:fef6:10e/64
  • 1431 |
1432 | 1433 | 1434 |
1435 | 1436 | 1437 | 1438 | // ********************************* 1439 | [#questions] 1440 | == Questions 1441 | 1442 | [.noredheader,cols="65,.<45"] 1443 | |=== 1444 | 1445 | .2+|image:questions.png[width="95%",height="95%"] 1446 | a|* Twitter : *{speaker-twitter}* 1447 | |=== -------------------------------------------------------------------------------- /slideshow/day3.adoc: -------------------------------------------------------------------------------- 1 | :footer_copyright: Copyright ©2015 Red Hat, Inc. 2 | :imagesdir: images/ 3 | :speaker: Christian Posta 4 | :speaker-title: Principal Middleware Architect 5 | :speaker-email: christian@redhat.com 6 | :speaker-blog: http://blog.christianposta.com 7 | :speaker-twitter: http://twitter.com/christianposta[@christianposta] 8 | :talk-speaker: {speaker} 9 | :talk-name: Intro: Docker and Kubernetes training - Day 3 10 | :talk-date: 10/21/2015 11 | 12 | [#cover,data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 13 | == {blank-space} 14 | 15 | [#block,width="200px",left="70px",top="0px"] 16 | image::{revealjs_cover_image}[] 17 | 18 | [#cover-h1,width="600px",left="0px",top="200px"] 19 | {talk-name} 20 | 21 | [#cover-h2,width="800px",left="0px",top="450px"] 22 | {speaker} + 23 | {talk-date} 24 | 25 | // ************** who - christian ******** 26 | [#who] 27 | == Who 28 | 29 | [.noredheader,cols="30,70"] 30 | |=== 31 | | image:ceposta.png[width="90%",height="100%"] 32 | | {speaker-title} 33 | 34 | Blog: {speaker-blog} 35 | 36 | Twitter: {speaker-twitter} 37 | 38 | Email: {speaker-email} | 39 | |=== 40 | 41 | * Committer on Apache ActiveMQ, Apache Camel, Fabric8 42 | * Technology evangelist, recovering consultant 43 | * Spent a lot of time working with one of the largest Microservices, web-scale, unicorn companies 44 | * Frequent blogger and speaker about open-source, cloud, microservices 45 | 46 | // ************** Agenda ******** 47 | [#agenda] 48 | == Agenda 49 | 50 | * Intro / Prep Environments 51 | * Day 1: Docker Deep Dive 52 | * Day 2: Kubernetes Deep Dive 53 | * *Day 3: Advanced Kubernetes: Concepts, Management, Middleware* 54 | * Day 4: Advanced Kubernetes: CI/CD, open discussions 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | // ************** transition page ************************************************************************************** 65 | [#transition1, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 66 | == {blank-space} 67 | 68 | [#block,width="200px",left="70px",top="0px"] 69 | image::{revealjs_cover_image}[] 70 | 71 | [#cover-h1,width="600px",left="0px",top="400px"] 72 | *Quick Recap* 73 | 74 | 75 | 76 | // ************** Recap ******** 77 | [#recap2] 78 | == Recap Docker 79 | 80 | * Containers run on *single* Docker host 81 | * Containers are *ephemeral* 82 | * Nothing watchdogs the containers 83 | * Containers can have external persistence 84 | * Containers do not contain 85 | * Operating system *matters* 86 | 87 | 88 | // ************** Kubernetes intro *********** 89 | [#whatiskube] 90 | == What is Kubernetes 91 | 92 | * Smart placement 93 | * How to interact with a system that does placement 94 | * Different than configuration management 95 | * *Containers will fail* 96 | * Scaling 97 | 98 | 99 | // ************** Recap *********** 100 | [#whyisitimportant] 101 | == Why is it important 102 | 103 | * Managing containers by hand is harder that VMS: won't scale 104 | * Automate the boilerplate stuff 105 | * Runbooks -> Scripts -> Config management -> Scale 106 | * Decouple application from machine! 107 | * Applications run on "resources" 108 | * Kubernetes manages this interaction of applications and resources 109 | * *Manage applications, not machines!* 110 | * What about *legacy apps?* 111 | 112 | 113 | 114 | // ************** Recap *********** 115 | [#controlplane] 116 | == Reconciliation of end state 117 | 118 | [#block,width="200px",left="50px",top="170px"] 119 | image:day2/make-it-so.png[height="200%",width="200%"] 120 | 121 | // ************** Recap *********** 122 | [#coreconcets] 123 | == Kubernetes core concepts 124 | 125 | * Simplicity, Simplicity, Simplicity 126 | * *Pods* 127 | * *Labels* / *Selectors* 128 | * *Replication Controllers* 129 | * *Services* 130 | * API 131 | 132 | 133 | // ************** Recap ******** 134 | [#why-you-win] 135 | == Why you win with Docker and Kubernetes 136 | 137 | * Immutable infrastructure 138 | * DevOps 139 | * CI/CD 140 | * *Who cares:* give me a platform to move faster!!! 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | // ************** transition page ************************************************************************************** 150 | [#deepdive, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 151 | == {blank-space} 152 | 153 | [#block,width="200px",left="70px",top="0px"] 154 | image::{revealjs_cover_image}[] 155 | 156 | [#cover-h1,left="0px",top="350px",width="2000px"] 157 | *Kubernetes: Deeper Dive* 158 | 159 | // ************** Deeper ******** 160 | [#namespaces] 161 | == Kubernetes namespaces 162 | 163 | * *Divide cluster* across uses, tiers, and teams 164 | * Unique within a *namespace*; not across multiple namespaces 165 | * Very powerful when combined with Labels 166 | * Example: qa/dev/prod can be implemented with Namespaces 167 | 168 | 169 | // ************** Deeper ******** 170 | [#namespaces1] 171 | == Kubernetes namespaces 172 | 173 | List the namespaces available to the cluster 174 | 175 | ``` 176 | kubectl get namespaces 177 | ``` 178 | 179 | List all the pods across all the namespaces 180 | 181 | ``` 182 | kubectl get pods --all-namespaces 183 | ``` 184 | 185 | Let's create a new namespace for our `guestbook` application: 186 | 187 | ``` 188 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/guestbook/namespace.yaml | kubectl create -f - 189 | ``` 190 | 191 | Let's list the pods in the `guestbook` namespace, hint: there shouldn't be any at the moment: 192 | 193 | ``` 194 | kubectl get pods --namespace=guestbook 195 | ``` 196 | 197 | // ************** Deeper ******** 198 | [#[namespaces-contexts] 199 | == Kubernetes Contexts / Namespaces 200 | 201 | You can log into multiple kubernetes clusters with the same client and switch between clusters/contexts at the 202 | command line. You can also specify which namespaces to use when pointing to specific clusters. For example, to 203 | view the current cluster context: 204 | 205 | 206 | ``` 207 | kubectl config view 208 | ``` 209 | Sample output: 210 | 211 | ``` 212 | - context: 213 | cluster: master-fuse-osecloud-com:8443 214 | namespace: microservice 215 | user: admin/master-fuse-osecloud-com:8443 216 | name: microservice/master-fuse-osecloud-com:8443/admin 217 | - context: 218 | cluster: vagrant 219 | user: vagrant 220 | name: vagrant 221 | current-context: vagrant 222 | kind: Config 223 | preferences: {} 224 | users: 225 | - name: admin/master-fuse-osecloud-com:8443 226 | user: 227 | token: kZ_L5Oj5sJ8nJUVJD4quq813Q1pRv4yZWhOjuJEw79w 228 | - name: vagrant 229 | user: 230 | client-certificate-data: REDACTED 231 | client-key-data: REDACTED 232 | password: vagrant 233 | username: vagrant 234 | ``` 235 | 236 | // ************** Deeper ******** 237 | [#namespaces-using-contexts] 238 | == Setting and using context/namespaces 239 | 240 | We can create a new context that points to our vagrant cluster: 241 | 242 | ``` 243 | kubectl config set-context guestbook --namespace=guestbook --user=vagrant --cluster=vagrant 244 | ``` 245 | 246 | Now, let's switch to use that context so we can put any new pods/RCs into this new namespace: 247 | 248 | ``` 249 | kubectl config use-context guestbook 250 | ``` 251 | 252 | Now double check we're in the new context/namespace: 253 | 254 | ``` 255 | kubectl config view | grep current-context | awk '{print $2}' 256 | ``` 257 | 258 | Now let's deploy a replication controller 259 | 260 | ``` 261 | curl -s -L https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/master/demos/guestbook/frontend-controller.yaml | kubectl create -f - 262 | ``` 263 | 264 | Now let's see how many pods we have: 265 | 266 | ``` 267 | kubectl get pods 268 | ``` 269 | 270 | NAME READY STATUS RESTARTS AGE 271 | frontend-juz6j 0/1 Pending 0 5s 272 | 273 | 274 | 275 | // ************** Deeper ******** 276 | [#namespaces-using-contexts2] 277 | == Removing components 278 | 279 | We have two good ways to group components for development purposes and then clean them up when you want to start over. 280 | 281 | * Use Kubernetes labels 282 | * Use namespaces 283 | 284 | You can delete all resources in a namespace like this: 285 | 286 | ``` 287 | kubectl config use-context vagrant 288 | kubectl delete namespace guestbook 289 | ``` 290 | 291 | This approach works fine for local development and grouping. In shared environments the best approach is to properly lable your components (services, RCs, pods, etc) and delete them using labels: 292 | 293 | ``` 294 | kubectl delete all -l "label=value" 295 | ``` 296 | 297 | // ************** Deeper ******** 298 | [#not-all-objects-ns] 299 | == Not all objects in a namespace 300 | 301 | * Most objects *are* in a namespace 302 | ** pods 303 | ** replication controllers 304 | ** services 305 | * Namespaces themselves not in namespace 306 | * Nodes, PersistentVolumes 307 | 308 | // ************** Deeper ******** 309 | [#resource-quotas] 310 | == Resource Quotas 311 | 312 | If the API Server has `ResourceQuota` passed to the `kube-apiserver`'s `--admission_control` argument, then a 313 | namespace can set a *ResourceQuota* object to limit resources. 314 | 315 | Example from the vagrant/master: 316 | 317 | root 6055 0.0 0.0 3172 48 ? Ss 00:04 0:00 /bin/sh -c /usr/local/bin/kube-apiserver --address=127.0.0.1 --etcd_servers=http://127.0.0.1:4001 --cloud_provider=vagrant --runtime_config=api/v1 --admission_control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota --service-cluster-ip-range=10.247.0.0/16 --client_ca_file=/srv/kubernetes/ca.crt --basic_auth_file=/srv/kubernetes/basic_auth.csv --cluster_name=kubernetes --tls_cert_file=/srv/kubernetes/server.cert --tls_private_key_file=/srv/kubernetes/server.key --secure_port=443 --token_auth_file=/srv/kubernetes/known_tokens.csv --bind-address=10.245.1.2 --v=2 --allow_privileged=False 1>>/var/log/kube-apiserver.log 2>&1 318 | 319 | 320 | // ************** Deeper ******** 321 | [#resource-quotas2] 322 | == Resource Quotas 323 | 324 | * Pods must use Resource Limits or will fail to accept the Pod (can use a *LimitRange* to add default limits) 325 | * Admin creates a ResourceQuota for the namespace 326 | * If a Pod would cause the Resource Limits to breach, the pod is rejected 327 | * If the aggregate Resource Limits are set higher than actual available resources, first-come first-serve 328 | 329 | // ************** Deeper ******** 330 | [#label-your-nodes] 331 | == Use labels... for Nodes too! 332 | 333 | You can organize your Nodes based on classifications/tiers/resource types. For example, for some data-intensive applications you may wish to request that the scheduler put those pods on nodes that have SSD storage/PV support: 334 | 335 | ``` 336 | kubectl label nodes node-foo disktype=ssd 337 | ``` 338 | 339 | Now if you add a node selector section to your Pod, the pod will only end up on nodes with the *`disktype=ssd`* label 340 | 341 | ``` 342 | apiVersion: v1 343 | kind: Pod 344 | metadata: 345 | name: nginx 346 | labels: 347 | env: test 348 | spec: 349 | containers: 350 | - name: nginx 351 | image: nginx 352 | imagePullPolicy: IfNotPresent 353 | nodeSelector: 354 | disktype: ssd 355 | ``` 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | // ************** transition page ************************************************************************************** 367 | [#security-transition, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 368 | == {blank-space} 369 | 370 | [#block,width="200px",left="70px",top="0px"] 371 | image::{revealjs_cover_image}[] 372 | 373 | [#cover-h1,left="0px",top="350px",width="2000px"] 374 | *Kubernetes: Security* 375 | 376 | 377 | // ************** Security ******** 378 | [#security-overview] 379 | == Security Goals 380 | 381 | * Appropriate boundaries between cluster, pods, users who manage cluster/application developers 382 | * Appropriate boundaries enforced between containers and hosts (via docker/linux cap/selinux/apparmor/etc) 383 | * Ability to delegate administrative functions to users where it makes sense 384 | * Hide credentials/keys/passwords from others 385 | 386 | // ************** Security ******** 387 | [#security-roles] 388 | == Security Roles 389 | 390 | * Administration/Full authority 391 | * Project/namespace admin 392 | * Developer 393 | 394 | 395 | // ************** Security ******** 396 | [#secure-api-server] 397 | == Securing the API Server 398 | 399 | * `--client_ca_file` -- used to allow authentication via client certificates 400 | * `--token_auth_file` -- allow authentication via tokens; tokens are long-lived and cannot be refreshed (atm) 401 | * `--basic_auth_file` -- HTTP basic httpswd file 402 | 403 | // ************** Security ******** 404 | [#secure-api-server2] 405 | == Attribute based access control (ABAC) 406 | 407 | The four attributes that apply to authorization measures: 408 | 409 | * The user (as authenticated already) 410 | * Read only/Write -- GET commands are readonly 411 | * The resource in question (pod/RC/service,etc) 412 | * The namespace 413 | 414 | 415 | // ************** Security ******** 416 | [#specify-policies] 417 | == Specify policies 418 | Specifying policies: when starting the API server, pass a single-line JSON file to `--authorization_policy_file` 419 | 420 | * {"user":"ceposta"} 421 | * {"user":"ceposta", "resource": "pods", "readonly": true} 422 | * {"user":"ceposta", "resource": "events"} 423 | * {"user":"ceposta", "resource": "pods", "readonly": true, "ns": "projectBalvenie"} 424 | 425 | NOTE: This file is only reloaded when restarting API server 426 | 427 | 428 | // ************** Security ******** 429 | [#serviceaccounts-intro] 430 | == Service Accounts intro 431 | 432 | Service accounts vs User accounts 433 | 434 | * User accounts for humans; service accounts for services w/in Pods 435 | * Service accounts are "namespaced" 436 | * Service account creation is much simpler/lightweight vs User creation 437 | * Allow services to access the Kubernetes API 438 | 439 | 440 | // ************** Security ******** 441 | [#serviceaccounts-admission-controller] 442 | == Service Accounts Admission 443 | 444 | Acts as part of the API server, decorates pods with Service Account information: 445 | 446 | * Will assign `default` Service Account if one not specified 447 | * Will reject a Service Account if it specified and does not exist 448 | * Add ImagePullSecrets (for private repos) 449 | * Adds volume for token-based API access (secret) 450 | * Runs synchronously when pods are created 451 | 452 | 453 | // ************** Security ******** 454 | [#secrets] 455 | == Secrets 456 | 457 | * Image secrets 458 | * Secret Volumes 459 | * Service accounts actually use secrets to pass API tokens 460 | * Can pass sensitive data 461 | ** passwords 462 | ** keys 463 | ** certificates 464 | 465 | ``` 466 | apiVersion: v1 467 | kind: Secret 468 | metadata: 469 | name: mysecret 470 | type: Opaque 471 | data: 472 | password: dmFsdWUtMg0K 473 | username: dmFsdWUtMQ0K 474 | ``` 475 | 476 | NOTE: Secret "keys" in the map above, must link:http://kubernetes.io/v1.0/docs/design/identifiers.html[follow DNS subdomain naming convention]. The values are `base64` encoded 477 | 478 | 479 | 480 | // ************** Security ******** 481 | [#pod-using-secret-explicitly] 482 | == Pod using a secret 483 | 484 | ``` 485 | --- 486 | apiVersion: "v1" 487 | kind: "Pod" 488 | metadata: 489 | name: "mypod" 490 | namespace: "myns" 491 | spec: 492 | containers: 493 | - 494 | name: "mypod" 495 | image: "redis" 496 | volumeMounts: 497 | - 498 | name: "foo" 499 | mountPath: "/etc/foo" 500 | readOnly: true 501 | volumes: 502 | - 503 | name: "foo" 504 | secret: 505 | secretName: "mysecret" 506 | ``` 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | // ************** transition page ************************************************************************************** 518 | [#networking-transition, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 519 | == {blank-space} 520 | 521 | [#block,width="200px",left="70px",top="0px"] 522 | image::{revealjs_cover_image}[] 523 | 524 | [#cover-h1,left="0px",top="350px",width="2000px"] 525 | *Kubernetes Networking* 526 | 527 | 528 | // ************** Networking ******** 529 | [#docker-networking] 530 | == Docker networking 531 | 532 | 533 | * local, host-only bridge (docker0) 534 | * create new adapters to the bridge (veth) for each container that’s created 535 | * veth is mapped to eth0 on a container 536 | * eth0 is assigned an IP from the range dedicated to the virtual bridge 537 | * result: docker containers can talk to each other only on the same machine 538 | * containers on different hosts could have the exact same IP 539 | * in order for docker containers to communicate across hosts, they need to allocate ports on the host 540 | * this means containers must coordinate appropriately, etc or allocate dynamically (and know when not to run out of ports) 541 | * this is difficult to do, doesn’t scale very well 542 | * dynamic port allocation tricky — now each app MUST take a “port” parameter and configured at runtime 543 | 544 | // ************** Networking ******** 545 | [#understand-docker-bridge] 546 | == Quickly understand default docker networking 547 | 548 | [#block,width="200px",top="150px",left="75px"] 549 | image:day1/docker-network.png[width="170%",height="170%"] 550 | 551 | 552 | // ************** Networking ******** 553 | [#kube-networking] 554 | == Kubernetes networking 555 | 556 | 557 | * all pods can communicate with other pods w/out any NAT 558 | * all nodes can communicate with pods without NAT 559 | * the IP the pod sees is the same IP seen outside of the pod 560 | * cannot take docker hosts out of the box and expect kube to work 561 | * this is a simpler model 562 | ** reduces friction when coming from VM environments where this is more or less true 563 | 564 | 565 | // ************** Networking ******** 566 | [#kube-networking-pod-to-pod] 567 | == Pod to Pod, Pod to external 568 | 569 | * Flat networking space 570 | * So the transition is consistent VM->Pod 571 | * No additional container or application gymnastics /NAT/etc to have to go through each time you deploy 572 | * Pods have their own “port space” independent of other pods 573 | * Don’t need to explicitly create “docker links” between containers (would only work on a single node anyway) 574 | * Otherwise, dynamic allocation of ports on Host every time a pod needs a port gets very complicated for orchestration and scheduling 575 | ** exhaustion of ports 576 | ** reuse of ports 577 | ** tricky app config 578 | ** watching/cache invalidation 579 | ** redirection, etc 580 | ** conflicts 581 | ** NAT breaks self-registration mechanisms, etc 582 | 583 | 584 | // ************** Networking ******** 585 | [#kube-networking-container-to-container2] 586 | == Pods have single IP address for all containers 587 | 588 | * IP address visible inside and outside of the container 589 | * Self-registration works fine as you would expect as does DNS 590 | * Implemented as a “pod container” which holds the network namespace (net) and “app containers” which join with Docker’s —net=container: 591 | * In docker world, the IP inside the container is NOT what an entity outside of the container sees, even in another container 592 | 593 | 594 | 595 | // ************** Networking ******** 596 | [#kube-networking-container-to-container] 597 | == Container to Container w/ Pod 598 | 599 | * All containers behave as though they’re on a single host, i.e., they see the same ports and network. they can communicate with each other over localhost 600 | * Simplicity (well known ports, 80, 22, etc) 601 | * Security (ports bound on localhost are only visible within the pod/containers, never outside) 602 | * Performance (don’t have to take network stack penalties, marshaling, unmarhsaling, etc) 603 | * Very similar to running multiple processes in a VM host for example 604 | * Drawback: no container-local ports, could clash, etc. but these are minor inconveniences at the moment and workarounds are being implemented 605 | * However, pods come with the premise of shared resources (volumes, CPU, memory, etc) so a reduction in isolation is really expected. If you need isolation, use Pods not containers to achieve this. 606 | 607 | 608 | // ************** Networking ******** 609 | [#kube-networking-pod-toservice] 610 | == Pod to service 611 | 612 | * Service IPs are VIP 613 | * kube-proxy alters iptables on the node to trap service IPs and redirect them to the correct backends 614 | * Simple, hi-performance, HA solution 615 | 616 | // ************** Networking ******** 617 | [#kube-networking-external-to-pod] 618 | == External to Pod 619 | 620 | * This gets tricky 621 | * Need to set up external load balancer to fwd all service IPs and load balance against all nodes 622 | * The kube-proxy should trap that IP and send it to service? 623 | * Expose services directly to node hosts? —> suitable for poc type workloads, but not suitable for real prod workloads 624 | 625 | 626 | 627 | // ************** transition page ************************************************************************************** 628 | [#livedemo, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 629 | == {blank-space} 630 | 631 | [#block,width="200px",left="70px",top="0px"] 632 | image::{revealjs_cover_image}[] 633 | 634 | [#cover-h1,left="0px",top="350px",width="2000px"] 635 | *Live Demo* 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | // ************** transition page ************************************************************************************** 652 | [#cluster-addons, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 653 | == {blank-space} 654 | 655 | [#block,width="200px",left="70px",top="0px"] 656 | image::{revealjs_cover_image}[] 657 | 658 | [#cover-h1,left="0px",top="350px",width="2000px"] 659 | *Cluster AddOns* 660 | 661 | 662 | // ************** AddOns ******** 663 | [#dns] 664 | == Cluster DNS 665 | 666 | * AddOns implemented as Services and Repliction Controllers 667 | * Sky DNS used to implement DNS-addon 668 | * A pod that bridges between kubernetes services and DNS 669 | 670 | 671 | [#block,width="200px",top="250px",left="75px"] 672 | image:day3/sky-dns-pod.png[width="100%",height="100%"] 673 | 674 | 675 | // ************** AddOns ******** 676 | [#dns-lookup] 677 | == Cluster DNS 678 | 679 | * A kubernetes service that is the DNS provider (ie, has an vIP, etc) 680 | * Kublet configured to decorate the pods with correct DNS server 681 | ** Can configure the kubelet manually if not automatically set up: 682 | 683 | ``` 684 | --cluster_dns= 685 | --cluster_domain= 686 | ``` 687 | 688 | * A records are created for services in the form `svc-name.ns-name.svc.cluster.local` 689 | * Headless service (no clusterIP) are DNS round-robin 690 | * SRV records (discovering services and ports) `_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local` 691 | ** resolves to the hostname `my-svc.my-namespace.svc.cluster.local` and the port 692 | 693 | 694 | // ************** AddOns ******** 695 | [#cluster-logging] 696 | == Cluster logging with Elasticsearch and fluentd 697 | 698 | * Log collector on each node 699 | * Implemented with fluentd, as a pod 700 | * Watches all containers' logs on that node and pump them to Elastic search cluster 701 | * Elasticsearch can be queried via Kibana 702 | 703 | 704 | // ************** AddOns ******** 705 | [#cluster-logging-es-fluentd] 706 | == Elasticsearch and fluentd 707 | 708 | [#block,width="200px",top="50px",left="25px"] 709 | image:day3/fluentd-es-overview.png[width="75%",height="75%"] 710 | 711 | 712 | // ************** AddOns ******** 713 | [#cluster-logging-es-fluentd] 714 | == Elasticsearch and fluentd Demo 715 | 716 | Quick Demo? 717 | 718 | // ************** AddOns ******** 719 | [#container-monitoring] 720 | == Container level monitoring 721 | 722 | * Need visibility into the cluster as an aggregate and individually where appropriate 723 | * cAdvisor 724 | * Heapster 725 | * Influxdb/Prometheus/Graphite 726 | ** link:http://prometheus.io/docs/introduction/comparison/[Comparison -- http://prometheus.io/docs/introduction/comparison/] 727 | * Grafana 728 | 729 | // ************** AddOns ******** 730 | [#container-monitoring2] 731 | == Container level monitoring 732 | 733 | [#block,width="200px",top="150px",left="25px"] 734 | image:day3/monitoring-architecture.png[width="140%",height="140%"] 735 | 736 | // ************** AddOns ******** 737 | [#container-monitoring-cadvisor] 738 | == cAdvisor UI 739 | 740 | [#block,width="200px",top="50px",left="25px"] 741 | image:day3/cadvisor.png[width="140%",height="140%"] 742 | 743 | 744 | // ************** AddOns ******** 745 | [#container-monitoring-influxdb] 746 | == Influxdb 747 | 748 | [#block,width="200px",top="75px",left="0px"] 749 | image:day3/influx.png[width="100%",height="100%"] 750 | 751 | 752 | // ************** AddOns ******** 753 | [#container-monitoring-promo] 754 | == Prometheus 755 | 756 | [#block,width="200px",top="75px",left="0px"] 757 | image:day3/promo.png[width="100%",height="100%"] 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | // ************** transition page ************************************************************************************** 768 | [#cluster-ha, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 769 | == {blank-space} 770 | 771 | [#block,width="200px",left="70px",top="0px"] 772 | image::{revealjs_cover_image}[] 773 | 774 | [#cover-h1,left="0px",top="350px",width="2000px"] 775 | *Cluster High Availability* 776 | 777 | 778 | 779 | // ************** AddOns ******** 780 | [#high-availability-architecture] 781 | == High Availability 782 | 783 | [#block,width="200px",top="50px",left="0px"] 784 | image:day3/ha.png[width="100%",height="100%"] 785 | 786 | // ************** AddOns ******** 787 | [#high-availability-components] 788 | == High Availability components 789 | 790 | * HA master nodes 791 | * etcd datastore 792 | * Replicated, load-balanced, API server 793 | * Elected scheduler and controllers 794 | 795 | [#etcd] 796 | == etcd 797 | 798 | * Open source project started at CoreOS 799 | * Distributed database 800 | * CAP Theorem? == CP 801 | * Raft algorithm/protocol 802 | * watchable 803 | * etcd provides HA datastore 804 | 805 | 806 | [#block,width="200px",left="250px",top="250px"] 807 | image:day2/etcd.png[height="75%",width="75%"] 808 | 809 | // ************** AddOns ******** 810 | [#high-availability-components2] 811 | == High Availability components 812 | 813 | * Run kubelet on the masters to monitor that API server process and restart on failure 814 | ** systemctl enable kubelet and systemctl enable docker. 815 | * Replicated etcd 816 | * Run shared storage locations for each of the etcd nodes 817 | * Network loadbalancers over the API servers 818 | * Run `podmaster` which coordinates a lease-lock election using etcd 819 | 820 | 821 | 822 | 823 | 824 | // ************** transition page ************************************************************************************** 825 | [#releasees, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 826 | == {blank-space} 827 | 828 | [#block,width="200px",left="70px",top="0px"] 829 | image::{revealjs_cover_image}[] 830 | 831 | [#cover-h1,left="0px",top="350px",width="2000px"] 832 | *Updating applications - Releasing updates* 833 | 834 | // ************** Releases ******** 835 | [#release-types] 836 | == Release Types 837 | 838 | * Canary release 839 | * Blue/green deployment 840 | * A/B testing 841 | * Rolling upgrade/rollback 842 | 843 | 844 | 845 | // ************** Releases ******** 846 | [#canary-release] 847 | == Canary Release 848 | 849 | [#block,width="200px",top="75px",left="0px"] 850 | image:day3/canarydeployment.png[width="200%",height="200%"] 851 | 852 | 853 | // ************** Releases ******** 854 | [#canary-release-w-kube] 855 | == Canary Release with Kubernetes 856 | 857 | * https://github.com/kubernetes/kubernetes/issues/11505 858 | * Can do with labels (exclude certain labels) 859 | 860 | Example: 861 | 862 | App to deploy: 863 | 864 | labels: 865 | app: guestbook 866 | tier: frontend 867 | track: canary 868 | 869 | Existing set of apps: 870 | 871 | labels: 872 | app: guestbook 873 | tier: frontend 874 | track: stable 875 | 876 | Service selector 877 | 878 | selector: 879 | app: guestbook 880 | tier: frontend 881 | 882 | 883 | 884 | // ************** Releases ******** 885 | [#blue-green-green] 886 | == Blue/Green deployment 887 | 888 | [#block,width="200px",top="75px",left="0px"] 889 | image:day3/greendeployment.png[width="200%",height="200%"] 890 | 891 | 892 | // ************** Releases ******** 893 | [#blue-green-blue] 894 | == Blue/Green deployment 895 | 896 | [#block,width="200px",top="75px",left="0px"] 897 | image:day3/bluedeployment.png[width="200%",height="200%"] 898 | 899 | // ************** Releases ******** 900 | [#blue-green-green-w-kube] 901 | == Blue/Green deployment with Kubernetes 902 | 903 | * Have two separate replication controllers, one blue, one green 904 | * Have labels "color=green", "color=blue" 905 | * Service selector = "color=green" 906 | * Change selector to "color=blue" to switch 907 | * Can switch back 908 | 909 | // ************** Releases ******** 910 | [#ab-testing] 911 | == A/B Testing 912 | 913 | [#block,width="200px",top="75px",left="0px"] 914 | image:day3/abtesting.png[width="110%",height="110%"] 915 | 916 | // ************** Releases ******** 917 | [#rolling-upgrade] 918 | == Rolling update 919 | 920 | 921 | * Bring up a container with the new version, same fleet of containers 922 | * Bring down one of the old version 923 | * Bring up a second container with the new version 924 | * Repeat 925 | * To be aware: potentially scaling while doing Rolling Updates 926 | 927 | 928 | // ************** Releases ******** 929 | [#rolling-upgrade-how-to-do] 930 | == Rolling update: how to 931 | 932 | * Use replication controllers to control the number of replicas at a given step 933 | * Use `kubectl rolling-update 934 | * Replaces an old RC with a new RC 935 | * Must be in same namespace 936 | * Share at least one label name, different value 937 | 938 | Example: 939 | 940 | ``` 941 | kubectl rolling-update frontend-v1 -f frontend-v2.json 942 | ``` 943 | 944 | // ************** Releases ******** 945 | [#rolling-upgrade-how-to-do-recovery] 946 | == Rolling update: how to Recovery 947 | 948 | * What happens if a failure is introduced part-way through the Rolling update: 949 | * Kubernetes keeps track and annotates the RC with info: 950 | * *`kubernetes.io/desired-replicas`* 951 | ** the number that this replica controller needs to get to 952 | * *`kubernetes.io/update-partner`* 953 | ** Who's the other half of the replica-set 954 | * Recovery is achieved by running the same command again 955 | 956 | // ************** Releases ******** 957 | [#rolling-upgrade-how-to-do-algo] 958 | == Rolling update: how to Recovery 959 | 960 | * While size of foo-next < desired-replicas annotation on foo-next 961 | ** increase size of foo-next 962 | ** if size of foo > 0 decrease size of foo 963 | * Goto Rename 964 | 965 | 966 | // ************** Releases ******** 967 | [#rolling upgrade-how-to-do] 968 | == Rolling update: how to 969 | link:http://kubernetes.io/v1.0/docs/user-guide/update-demo/README.html[Demo] 970 | 971 | 972 | // ************** transition page ************************************************************************************** 973 | [#mvn-plugins, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 974 | == {blank-space} 975 | 976 | [#block,width="200px",left="70px",top="0px"] 977 | image::{revealjs_cover_image}[] 978 | 979 | [#cover-h1,left="0px",top="350px",width="2000px"] 980 | *Automating generation of kubernetes resources for Java* 981 | 982 | 983 | // ************** Fabric8 ******** 984 | [#docker-mvn-plugin] 985 | == Docker maven plugin 986 | 987 | * Set of maven goals for managing docker builds and containers 988 | * Can be run as part of a CI/build step in your existing build or CI pipelines 989 | * Requires access to a Docker Daemon for builds 990 | * Can build images, start/stop containers, etc 991 | * https://github.com/rhuss/docker-maven-plugin 992 | 993 | // ************** Fabric8 ******** 994 | [#docker-mvn-plugin2] 995 | == Docker maven plugin 996 | 997 | 998 | * docker:start Create and start containers 999 | * docker:stop Stop and destroy containers 1000 | * docker:build Build images 1001 | * docker:watch Watch for doing rebuilds and restarts 1002 | * docker:push Push images to a registry 1003 | * docker:remove Remove images from local docker host 1004 | * docker:logs Show container logs 1005 | 1006 | 1007 | // ************** Fabric8 ******** 1008 | [#docker-mvn-build] 1009 | == Docker maven plugin: build 1010 | 1011 | * *`mvn package docker:build`* 1012 | * Can build a docker image as part of `mvn lifecycle` 1013 | * Package files from project (build artifacts, configs, etc) into docker image 1014 | * Which files are selected using link:http://maven.apache.org/plugins/maven-assembly-plugin/[maven-assembly-plugin] 1015 | * Selected files are inserted into base image at specified location 1016 | * default `/maven` 1017 | * See the link:http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html[assembly descriptor file format] 1018 | * Once image is built, can use link:http://maven.apache.org/surefire/maven-failsafe-plugin/[maven-failsafe-plugin] to 1019 | run integration tests 1020 | 1021 | // ************** Fabric8 ******** 1022 | [#docker-mvn-build2] 1023 | == Docker maven plugin: build 1024 | 1025 | ``` 1026 | 1027 | 1028 | 1029 | service 1030 | jolokia/docker-demo:${project.version} 1031 | 1032 | 1033 | java:8 1034 | 1035 | docker-assembly.xml 1036 | 1037 | 1038 | 8080 1039 | 1040 | 1041 | java -jar /maven/service.jar 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | tomcat.port:8080 1048 | 1049 | 1050 | http://localhost:${tomcat.port}/access 1051 | 1052 | 1053 | 1054 | database:db 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | database 1061 | postgres:9 1062 | 1063 | 1064 | database system is ready to accept connections 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | ``` 1072 | 1073 | // ************** Fabric8 ******** 1074 | [#docker-mvn-watch] 1075 | == Docker maven plugin: watch 1076 | 1077 | * Can watch for changes in project and rebuild 1078 | * Rebuild docker image 1079 | * Re-start existing running container 1080 | * Fast development feedback/loop 1081 | * `mvn package docker:build docker:watch -Ddocker.watchMode=build` 1082 | * `mvn docker:start docker:watch -Ddocker.watchMode=run` 1083 | * 1084 | 1085 | 1086 | // ************** Fabric8 ******** 1087 | [#docker-mvn-watch2] 1088 | == Docker maven plugin: watch 1089 | 1090 | ``` 1091 | 1092 | 1093 | 10000 1094 | 1095 | both 1096 | 1097 | 1098 | 1099 | service 1100 | .... 1101 | 1102 | 5000 1103 | 1104 | 1105 | 1106 | 1107 | db 1108 | .... 1109 | 1110 | none 1111 | 1112 | 1113 | .... 1114 | 1115 | 1116 | ``` 1117 | 1118 | 1119 | 1120 | // ************** Fabric8 ******** 1121 | [#fabric8-maven-plugin] 1122 | == Fabric8 maven plugin 1123 | 1124 | * *`fabric8:json`* 1125 | * *`fabric8:apply`* 1126 | * *`fabric8:rolling`* 1127 | * *`fabric8:devops`* 1128 | * *`fabric8:create-routes`* 1129 | * *`fabric8:recreate`* 1130 | 1131 | 1132 | 1133 | 1134 | // ************** Fabric8 ******** 1135 | [#fabric8-maven-plugin-json] 1136 | == Fabric8 maven plugin: json 1137 | 1138 | * Generates `kubernetes.json` file based on Maven settings 1139 | ** Can generate ReplicationController/Services/Pods 1140 | * Attaches `kubernetes.json` and versions as part of the build 1141 | ** Will be included in the artifacts uploaded to artifact repo 1142 | 1143 | Options 1144 | 1145 | * Hand-generate your own file and let mvn coordinates be applied 1146 | * Use default mvn properties and let fabric8:json generate the json file 1147 | * Use annnotation processors and typesafe DSL builders directly 1148 | * Enrich the generated JSON with additional stuff 1149 | 1150 | 1151 | // ************** Fabric8 ******** 1152 | [#fabric8-maven-plugin-json-envs] 1153 | == Fabric8 maven plugin: json 1154 | 1155 | ``` 1156 | 1157 | ... 1158 | 1159 | bar 1160 | ... 1161 | 1162 | ... 1163 | 1164 | ``` 1165 | 1166 | 1167 | // ************** Fabric8 ******** 1168 | [#fabric8-maven-plugin-json-properties] 1169 | == Fabric8 maven plugin: json 1170 | 1171 | 1172 | * `docker.image` Used by the docker-maven-plugin to define the output docker image name. 1173 | * `fabric8.combineDependencies` If enabled then the maven dependencies will be scanned for any dependency of kubernetes and json which are then combined into the resulting generated JSON file. See Combining JSON files 1174 | * `fabric8.container.name` The docker container name of the application in the generated JSON. This defaults to ${project.artifactId}-container 1175 | * `fabric8.containerPrivileged` Whether the generated container should be run in priviledged mode (defaults to false) 1176 | * `fabric8.env.FOO` = BAR Defines the environment variable FOO and value BAR. 1177 | * `fabric8.extra.json` Allows an extra JSON file to be merged into the generated kubernetes json file. Defaults to using the file target/classes/kubernetes-extra.json. 1178 | * `fabric8.generateJson` If set to false then the generation of the JSON is disabled. 1179 | * `fabric8.iconRef` Provides the resource name of the icon to use; found using the current classpath (including the ones shipped inside the maven plugin). For example icons/myicon.svg to find the icon in the src/main/resources/icons directorty. You can refer to a common set of icons by setting this option to a value of: activemq, camel, java, jetty, karaf, mule, spring-boot, tomcat, tomee, weld, wildfly 1180 | * `fabric8.iconUrl` The URL to use to link to the icon in the generated Template. 1181 | * `fabric8.iconUrlPrefix` The URL prefix added to the relative path of the icon file 1182 | 1183 | 1184 | // ************** Fabric8 ******** 1185 | [#fabric8-maven-plugin-json-properties1] 1186 | == Fabric8 maven plugin: json 1187 | 1188 | * `fabric8.iconBranch` The SCM branch used when creating a URL to the icon file. The default value is master. 1189 | * `fabric8.imagePullPolicy` Specifies the image pull policy; one of Always, Never or IfNotPresent, . Defaults to Always if the project version ends with SNAPSHOT otherwise it is left blank. On newer OpenShift / Kubernetes versions a blank value implies IfNotPresent 1190 | * `fabric8.imagePullPolicySnapshot` Specifies the image pull policy used by default for SNAPSHOT maven versions. 1191 | * `fabric8.includeAllEnvironmentVariables` Should the environment variable JSON Schema files, generate by the **fabric-apt** API plugin be discovered and included in the generated kuberentes JSON file. Defaults to true. 1192 | * `fabric8.includeNamespaceEnvVar` Whether we should include the namespace in the containers' env vars. Defaults to true 1193 | * `fabric8.label.FOO` = BAR Defines the kubernetes label FOO and value BAR. 1194 | * `fabric8.livenessProbe.exec` Creates a exec action liveness probe with this command. 1195 | * `fabric8.livenessProbe.httpGet.path` Creates a HTTP GET action liveness probe on with this path. 1196 | * `fabric8.livenessProbe.httpGet.port` Creates a HTTP GET action liveness probe on this port. 1197 | * `fabric8.livenessProbe.httpGet.host` Creates a HTTP GET action liveness probe on this host. 1198 | * `fabric8.livenessProbe.port` Creates a TCP socket action liveness probe on specified port. 1199 | * `fabric8.namespaceEnvVar` The name of the env var to add that will contain the namespace at container runtime. Defaults to KUBERNETES_NAMESPACE. 1200 | 1201 | 1202 | 1203 | // ************** Fabric8 ******** 1204 | [#fabric8-maven-plugin-json-properties2] 1205 | == Fabric8 maven plugin: json 1206 | 1207 | * `fabric8.parameter.FOO.descriptio`n Defines the description of the OpenShift template parameter FOO. 1208 | * `fabric8.parameter.FOO.value` Defines the value of the OpenShift template parameter FOO. 1209 | * `fabric8.port.container.FOO` = 1234 Declares that the pod's container has a port named FOO with a container port 1234. 1210 | * `fabric8.port.host.FOO` = 4567 Declares that the pod's container has a port port named FOO which is mapped to host port 4567. 1211 | * `fabric8.provider` The provider name to include in resource labels (defaults to fabric8). 1212 | * `fabric8.readinessProbe.exec` Creates a exec action readiness probe with this command. 1213 | * `fabric8.readinessProbe.httpGet.path` Creates a HTTP GET action readiness probe on with this path. 1214 | * `fabric8.readinessProbe.httpGet.port` Creates a HTTP GET action readiness probe on this port. 1215 | * `fabric8.readinessProbe.httpGet.host` Creates a HTTP GET action readiness probe on this host. 1216 | * `fabric8.readinessProbe.port` Creates a TCP socket action readiness probe on specified port. 1217 | * `fabric8.replicas` The number of pods to create for the Replication Controller if the plugin is generating the App JSON file. 1218 | * `fabric8.replicationController.name` The name of the replication controller used in the generated JSON. This defaults to ${project.artifactId}-controller 1219 | 1220 | 1221 | // ************** Fabric8 ******** 1222 | [#fabric8-maven-plugin-json-properties3] 1223 | == Fabric8 maven plugin: json 1224 | 1225 | * `fabric8.serviceAccount` The name of the service account to use in this pod (defaults to none) 1226 | * `fabric8.service.name` The name of the Service to generate. Defaults to ${project.artifactId} (the artifact Id of the project) 1227 | * `fabric8.service.port` The port of the Service to generate (if a kubernetes service is required). 1228 | * `fabric8.service.type` The type of the service. Set to "LoadBalancer" if you wish an external load balancer to be created. 1229 | * `fabric8.service.containerPort` The container port of the Service to generate (if a kubernetes service is required). 1230 | * `fabric8.service.protocol` The protocol of the service. (If not specified then kubernetes will default it to TCP). 1231 | * `fabric8.service.port.` The service port to generate (if a kubernetes service is required with multiple ports). 1232 | * `fabric8.service.containerPort.` The container port to target to generate (if a kubernetes service is required with multiple ports). 1233 | * `fabric8.service.protocol.` The protocol of this service port to generate (if a kubernetes service is required with multiple ports). 1234 | * `fabric8.volume.FOO.emptyDir` = somemedium Defines the emtpy volume with name FOO and medium somemedium. 1235 | * `fabric8.volume.FOO.hostPath` = /some/path Defines the host dir volume with name FOO. 1236 | * `fabric8.volume.FOO.mountPath` = /some/path Defines the volume mount with name FOO. 1237 | * `fabric8.volume.FOO.readOnly` Specifies whether or not a volume is read only. 1238 | * `fabric8.volume.FOO.secret` = BAR Defines the secret name to be BAR for the FOO volume. 1239 | 1240 | 1241 | // ************** Fabric8 ******** 1242 | [#fabric8-maven-plugin-apply] 1243 | == Fabric8 maven plugin: apply 1244 | 1245 | * Takes the `kubernetes.json` from fabric8:json and "applies" it to kubernetes 1246 | * Synonymous with *`kubectl create -f 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /slideshow/images/collaborate.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/collaborate.jpeg -------------------------------------------------------------------------------- /slideshow/images/collaborate1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/collaborate1.jpeg -------------------------------------------------------------------------------- /slideshow/images/day1/cattle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/cattle.jpg -------------------------------------------------------------------------------- /slideshow/images/day1/docker-animated-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-animated-1.gif -------------------------------------------------------------------------------- /slideshow/images/day1/docker-animated-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-animated-2.gif -------------------------------------------------------------------------------- /slideshow/images/day1/docker-components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-components.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker-host-ports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-host-ports.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker-layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-layers.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-network.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker-ports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-ports.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker-vol-datacontainer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-vol-datacontainer.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker-vol-host.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-vol-host.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker-vol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker-vol.png -------------------------------------------------------------------------------- /slideshow/images/day1/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/docker.png -------------------------------------------------------------------------------- /slideshow/images/day1/intro-cgroups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/intro-cgroups.png -------------------------------------------------------------------------------- /slideshow/images/day1/local-registry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/local-registry.png -------------------------------------------------------------------------------- /slideshow/images/day1/port-forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/port-forward.png -------------------------------------------------------------------------------- /slideshow/images/day1/scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/scope.png -------------------------------------------------------------------------------- /slideshow/images/day1/tomcat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/tomcat.png -------------------------------------------------------------------------------- /slideshow/images/day1/workflow1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/workflow1.png -------------------------------------------------------------------------------- /slideshow/images/day1/workflow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day1/workflow2.png -------------------------------------------------------------------------------- /slideshow/images/day2/all-containers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/all-containers.jpg -------------------------------------------------------------------------------- /slideshow/images/day2/deep-pod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/deep-pod.png -------------------------------------------------------------------------------- /slideshow/images/day2/demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/demo.jpg -------------------------------------------------------------------------------- /slideshow/images/day2/etcd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/etcd.png -------------------------------------------------------------------------------- /slideshow/images/day2/kube-control-plane-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/kube-control-plane-nodes.png -------------------------------------------------------------------------------- /slideshow/images/day2/kube-control-plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/kube-control-plane.png -------------------------------------------------------------------------------- /slideshow/images/day2/kube-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/kube-diagram.png -------------------------------------------------------------------------------- /slideshow/images/day2/kube-pods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/kube-pods.png -------------------------------------------------------------------------------- /slideshow/images/day2/kubernetes-platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/kubernetes-platform.png -------------------------------------------------------------------------------- /slideshow/images/day2/label-pods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/label-pods.png -------------------------------------------------------------------------------- /slideshow/images/day2/make-it-so.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/make-it-so.png -------------------------------------------------------------------------------- /slideshow/images/day2/node-connectivity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/node-connectivity.png -------------------------------------------------------------------------------- /slideshow/images/day2/pod-creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/pod-creation.png -------------------------------------------------------------------------------- /slideshow/images/day2/pod-selectors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/pod-selectors.png -------------------------------------------------------------------------------- /slideshow/images/day2/services-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/services-overview.png -------------------------------------------------------------------------------- /slideshow/images/day2/services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day2/services.png -------------------------------------------------------------------------------- /slideshow/images/day3/abtesting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/abtesting.png -------------------------------------------------------------------------------- /slideshow/images/day3/bluedeployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/bluedeployment.png -------------------------------------------------------------------------------- /slideshow/images/day3/cadvisor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/cadvisor.png -------------------------------------------------------------------------------- /slideshow/images/day3/canarydeployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/canarydeployment.png -------------------------------------------------------------------------------- /slideshow/images/day3/docker-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/docker-network.png -------------------------------------------------------------------------------- /slideshow/images/day3/docker-networking-funny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/docker-networking-funny.png -------------------------------------------------------------------------------- /slideshow/images/day3/fluentd-es-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/fluentd-es-overview.png -------------------------------------------------------------------------------- /slideshow/images/day3/greendeployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/greendeployment.png -------------------------------------------------------------------------------- /slideshow/images/day3/ha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/ha.png -------------------------------------------------------------------------------- /slideshow/images/day3/influx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/influx.png -------------------------------------------------------------------------------- /slideshow/images/day3/monitoring-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/monitoring-architecture.png -------------------------------------------------------------------------------- /slideshow/images/day3/promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/promo.png -------------------------------------------------------------------------------- /slideshow/images/day3/sky-dns-pod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/day3/sky-dns-pod.png -------------------------------------------------------------------------------- /slideshow/images/dev_impact1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/dev_impact1.png -------------------------------------------------------------------------------- /slideshow/images/developer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/developer.jpg -------------------------------------------------------------------------------- /slideshow/images/devops1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/devops1.jpeg -------------------------------------------------------------------------------- /slideshow/images/devops2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/devops2.jpeg -------------------------------------------------------------------------------- /slideshow/images/docker-animated-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/docker-animated-2.gif -------------------------------------------------------------------------------- /slideshow/images/docker-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/docker-logo.png -------------------------------------------------------------------------------- /slideshow/images/docker.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/docker.jpeg -------------------------------------------------------------------------------- /slideshow/images/docker/install/docker-arch-windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/docker/install/docker-arch-windows.png -------------------------------------------------------------------------------- /slideshow/images/docker/install/docker-linux-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/docker/install/docker-linux-arch.png -------------------------------------------------------------------------------- /slideshow/images/docker_vm_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/docker_vm_diagram.jpg -------------------------------------------------------------------------------- /slideshow/images/dockerfile-to-image.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/dockerfile-to-image.jpeg -------------------------------------------------------------------------------- /slideshow/images/dockerfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/dockerfile.png -------------------------------------------------------------------------------- /slideshow/images/eai-esb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/eai-esb.png -------------------------------------------------------------------------------- /slideshow/images/eai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/eai.jpg -------------------------------------------------------------------------------- /slideshow/images/eai2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/eai2.jpg -------------------------------------------------------------------------------- /slideshow/images/elasticsearch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/elasticsearch.jpeg -------------------------------------------------------------------------------- /slideshow/images/expensive.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/expensive.jpeg -------------------------------------------------------------------------------- /slideshow/images/fabric-pod-volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric-pod-volume.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-apps.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-cd-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-cd-tools.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-cdci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-cdci.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-diagram1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-diagram1.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-green-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-green-button.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-pod-port.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-pod-port.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-pod-volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-pod-volume.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-pod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-pod.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-port.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-port.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-service-pod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-service-pod.png -------------------------------------------------------------------------------- /slideshow/images/fabric8-volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8-volume.png -------------------------------------------------------------------------------- /slideshow/images/fabric8_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fabric8_logo.png -------------------------------------------------------------------------------- /slideshow/images/fluentd.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fluentd.jpeg -------------------------------------------------------------------------------- /slideshow/images/fuse-fabric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/fuse-fabric.png -------------------------------------------------------------------------------- /slideshow/images/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/git.png -------------------------------------------------------------------------------- /slideshow/images/github.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/github.jpeg -------------------------------------------------------------------------------- /slideshow/images/goal.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/goal.jpeg -------------------------------------------------------------------------------- /slideshow/images/grafana.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/grafana.jpeg -------------------------------------------------------------------------------- /slideshow/images/hawtio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/hawtio.png -------------------------------------------------------------------------------- /slideshow/images/html5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/html5.jpeg -------------------------------------------------------------------------------- /slideshow/images/hubot-avatar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/hubot-avatar@2x.png -------------------------------------------------------------------------------- /slideshow/images/idea.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/idea.jpeg -------------------------------------------------------------------------------- /slideshow/images/influxdb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/influxdb.png -------------------------------------------------------------------------------- /slideshow/images/jenkins-300x300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/jenkins-300x300.png -------------------------------------------------------------------------------- /slideshow/images/kibana-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/kibana-2.jpeg -------------------------------------------------------------------------------- /slideshow/images/kibana.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/kibana.jpeg -------------------------------------------------------------------------------- /slideshow/images/kubernetes-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/kubernetes-logo.png -------------------------------------------------------------------------------- /slideshow/images/kubernetes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/kubernetes.png -------------------------------------------------------------------------------- /slideshow/images/lack-of-management.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/lack-of-management.jpg -------------------------------------------------------------------------------- /slideshow/images/languages.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/languages.jpeg -------------------------------------------------------------------------------- /slideshow/images/linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/linux.png -------------------------------------------------------------------------------- /slideshow/images/microservice.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/microservice.jpeg -------------------------------------------------------------------------------- /slideshow/images/microservice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/microservice.jpg -------------------------------------------------------------------------------- /slideshow/images/microservice1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/microservice1.png -------------------------------------------------------------------------------- /slideshow/images/nexus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/nexus.png -------------------------------------------------------------------------------- /slideshow/images/openshift-paas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/openshift-paas.png -------------------------------------------------------------------------------- /slideshow/images/openshift_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/openshift_logo.png -------------------------------------------------------------------------------- /slideshow/images/opts-it.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/opts-it.jpg -------------------------------------------------------------------------------- /slideshow/images/oss.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/oss.jpeg -------------------------------------------------------------------------------- /slideshow/images/oss1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/oss1.jpeg -------------------------------------------------------------------------------- /slideshow/images/questions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/questions.png -------------------------------------------------------------------------------- /slideshow/images/redhat-background.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/redhat-background.jpeg -------------------------------------------------------------------------------- /slideshow/images/redhat-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/redhat-linux.png -------------------------------------------------------------------------------- /slideshow/images/redhat-logo-background-1024-768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/redhat-logo-background-1024-768.png -------------------------------------------------------------------------------- /slideshow/images/redhat-logo-background-1280-800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/redhat-logo-background-1280-800.png -------------------------------------------------------------------------------- /slideshow/images/redhat-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/redhat-logo.jpg -------------------------------------------------------------------------------- /slideshow/images/redhat-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/redhat-logo.png -------------------------------------------------------------------------------- /slideshow/images/redhat-master-nodes-pods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/redhat-master-nodes-pods.png -------------------------------------------------------------------------------- /slideshow/images/rest-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/rest-api.png -------------------------------------------------------------------------------- /slideshow/images/rhel-atomic.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/rhel-atomic.jpeg -------------------------------------------------------------------------------- /slideshow/images/rhel-atomic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/rhel-atomic.png -------------------------------------------------------------------------------- /slideshow/images/rhel-atomic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/rhel-atomic1.png -------------------------------------------------------------------------------- /slideshow/images/rht-atomic-enterprise-openshift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/rht-atomic-enterprise-openshift.png -------------------------------------------------------------------------------- /slideshow/images/sonarqube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/sonarqube.png -------------------------------------------------------------------------------- /slideshow/images/swagger.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/swagger.jpeg -------------------------------------------------------------------------------- /slideshow/images/worked-fine-in-dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/worked-fine-in-dev.png -------------------------------------------------------------------------------- /slideshow/images/wtf-dev-ops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christian-posta/docker-kubernetes-workshop/8954249304a82853b745de3b3dcfd51d44acde17/slideshow/images/wtf-dev-ops.png -------------------------------------------------------------------------------- /slideshow/intro.adoc: -------------------------------------------------------------------------------- 1 | :footer_copyright: Copyright ©2015 Red Hat, Inc. 2 | :imagesdir: images/ 3 | :speaker: Christian Posta 4 | :speaker-title: Principal Middleware Architect 5 | :speaker-email: christian@redhat.com 6 | :speaker-blog: http://blog.christianposta.com 7 | :speaker-twitter: http://twitter.com/christianposta[@christianposta] 8 | :talk-speaker: {speaker} 9 | :talk-name: Intro: Docker and Kubernetes training 10 | :talk-date: 10/19/2015 11 | 12 | [#cover,data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 13 | == {blank-space} 14 | 15 | [#block,width="200px",left="70px",top="0px"] 16 | image::{revealjs_cover_image}[] 17 | 18 | [#cover-h1,width="600px",left="0px",top="200px"] 19 | {talk-name} 20 | 21 | [#cover-h2,width="800px",left="0px",top="450px"] 22 | {speaker} + 23 | {talk-date} 24 | 25 | // ************** who - christian ******** 26 | [#who] 27 | == Who 28 | 29 | [.noredheader,cols="30,70"] 30 | |=== 31 | | image:ceposta.png[width="90%",height="100%"] 32 | | {speaker-title} 33 | 34 | Blog: {speaker-blog} 35 | 36 | Twitter: {speaker-twitter} 37 | 38 | Email: {speaker-email} | 39 | |=== 40 | 41 | * Committer on Apache ActiveMQ, Apache Camel, Fabric8 42 | * Technology evangelist, recovering consultant 43 | * Spent a lot of time working with one of the largest Microservices, web-scale, unicorn companies 44 | * Frequent blogger and speaker about open-source, cloud, microservices 45 | 46 | // ************** Agenda ******** 47 | [#agenda] 48 | == Agenda 49 | 50 | * *Intro / Prep Environments* 51 | * Day 1: Docker Deep Dive 52 | * Day 2: Kubernetes Deep Dive 53 | * Day 3: Advanced Kubernetes: Concepts, Management, Middleware 54 | * Day 4: Advanced Kubernetes: CI/CD, open discussions 55 | 56 | 57 | // ************** transition page ************ 58 | [#transition1, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 59 | == {blank-space} 60 | 61 | [#block,width="200px",left="70px",top="0px"] 62 | image::{revealjs_cover_image}[] 63 | 64 | [#cover-h1,width="600px",left="0px",top="400px"] 65 | *Setting up Docker locally* 66 | 67 | // ************** prep ******** 68 | [#prep] 69 | == Prep Environments 70 | 71 | * Lab prerequisites in place! 72 | * Verify you have Oracle VirtualBox 4.3.x 73 | * Install Docker (https://docs.docker.com/installation/) 74 | ** NOTE: for OS X, you can use brew: `brew install docker-machine` 75 | * Windows: need to have HVT 76 | * Understand the architecture 77 | * Smoke test 78 | 79 | // ************** simple arch ******** 80 | [#simpelarch] 81 | == Simple docker architecture 82 | 83 | [#block,top="150px"] 84 | image:docker/install/docker-linux-arch.png[] 85 | image:docker/install/docker-arch-windows.png[] 86 | 87 | // ************** Smoke test ******** 88 | [#smoketest] 89 | == Smoke test environment 90 | 91 | Run the following commands from shell: 92 | 93 | docker info 94 | 95 | 96 | Output: 97 | .... 98 | Containers: 0 99 | Images: 0 100 | Storage Driver: aufs 101 | Root Dir: /mnt/sda1/var/lib/docker/aufs 102 | Backing Filesystem: tmpfs 103 | Dirs: 0 104 | Dirperm1 Supported: true 105 | Execution Driver: native-0.2 106 | Logging Driver: json-file 107 | Kernel Version: 4.1.10-boot2docker 108 | Operating System: Boot2Docker 1.8.3 (TCL 6.4); master : af8b089 - Mon Oct 12 18:56:54 UTC 2015 109 | CPUs: 1 110 | Total Memory: 1.956 GiB 111 | Name: default 112 | ID: 54V7:OQNP:A4GT:D2T5:USDN:QLUG:PDOC:4I7I:I3O4:XW62:RCUP:24A7 113 | Debug mode (server): true 114 | File Descriptors: 10 115 | Goroutines: 16 116 | System Time: 2015-10-15T23:34:17.354643925Z 117 | EventsListeners: 0 118 | Init SHA1: 119 | Init Path: /usr/local/bin/docker 120 | Docker Root Dir: /mnt/sda1/var/lib/docker 121 | Labels: 122 | provider=virtualbox 123 | .... 124 | 125 | // ************** Smoke test ******** 126 | [#smoketest2] 127 | == Smoke test environment 128 | 129 | Run the following commands from shell: 130 | 131 | docker ps 132 | 133 | 134 | Output: 135 | .... 136 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 137 | .... 138 | 139 | 140 | // ************** so special ******** 141 | [#sospecial] 142 | == So what's so special? 143 | 144 | [#block,width="800px",top="50px"] 145 | image:day1/docker-animated-1.gif[] 146 | 147 | 148 | // ************** so special ******** 149 | [#sospecial] 150 | == Installing Kubernetes... 151 | 152 | We will be installing kubernetes 1.0.6 later in the hands-on sections. To do that we'll need *vagrant*, so lets install 153 | that right now. 154 | 155 | * http://www.vagrantup.com/downloads.html 156 | 157 | Make sure you have Virtual Box 4.3.x installed: BTW, docker machine will install 5.x Virtual Box; this will not be 158 | sufficent. Go ahead and link:https://www.virtualbox.org/wiki/Download_Old_Builds_4_3[install the 4.3.x version of 159 | Virtual Box] 160 | 161 | // ************** transition page ************************************************************************************** 162 | [#transition2, data-background-image="revealjs-redhat/image/1156524-bg_redhat.png" data-background-color="#cc0000"] 163 | == {blank-space} 164 | 165 | [#block,width="200px",left="70px",top="0px"] 166 | image::{revealjs_cover_image}[] 167 | 168 | [#cover-h1,left="0px",top="350px",width="2000px"] 169 | *Continue on to Day 1 presentations!* 170 | 171 | 172 | 173 | 174 | 175 | --------------------------------------------------------------------------------