Compare commits

...

580 Commits

Author SHA1 Message Date
Jerome Petazzoni
bd28742333 fix-redirects.sh: adding forced redirect 2020-04-07 16:48:38 -05:00
Bridget Kromhout
1b38a1ff09 Merge pull request #297 from bridgetkromhout/version-up
Version update
2018-06-27 01:16:30 -05:00
Bridget Kromhout
65faa4507c Version bump 2018-06-27 08:12:40 +02:00
Bridget Kromhout
644f2b9c7a Merge pull request #295 from bridgetkromhout/add-slides-ams
Adding slides link for ams
2018-06-26 17:04:27 -05:00
Bridget Kromhout
dab9d9fb7e Adding slides link 2018-06-27 00:03:18 +02:00
Bridget Kromhout
a280c34a27 Merge pull request #294 from bridgetkromhout/devopsdaysams2018
Updates for ams 2018
2018-06-26 17:00:15 -05:00
Bridget Kromhout
47e1ced630 Updates for ams 2018 2018-06-26 23:58:18 +02:00
Diego Quintana
139757613b Update Container_Networking_Basics.md
Added needed single quotes. I've also moved `nginx` to the end of the line, to follow a more consistent syntax  (`options` before `name|id`).

```
Usage:	docker inspect [OPTIONS] NAME|ID [NAME|ID...]

Return low-level information on Docker objects

Options:
  -f, --format string   Format the output using the given Go template
  -s, --size            Display total file sizes if the type is container
      --type string     Return JSON for specified type
```
2018-06-22 10:58:26 -05:00
Bridget Kromhout
10eed2c1c7 Merge pull request #288 from ctas582/typos
Correct typos
2018-06-22 09:21:56 -05:00
ctas582
c4fa75a1da Correct typos 2018-06-21 15:00:36 +01:00
ctas582
847140560f Correct typo 2018-06-21 14:16:05 +01:00
ctas582
1dc07c33ab Correct typos 2018-06-20 11:19:28 +01:00
Bridget Kromhout
4fc73d95c0 Merge pull request #285 from bridgetkromhout/vupdate
Updating version
2018-06-12 10:14:21 -07:00
Bridget Kromhout
690ed55953 Updating version 2018-06-12 10:12:04 -07:00
Bridget Kromhout
16a5809518 Merge pull request #284 from bridgetkromhout/add-vel-2day
Adding Erik and Brian's two-day Velocity training to the front page
2018-06-12 09:01:32 -07:00
Bridget Kromhout
0fed34600b Adding Erik and Brian's two-day 2018-06-12 08:55:53 -07:00
Jerome Petazzoni
2d95f4177a Remove extraneous python invocation 2018-06-12 04:25:00 -05:00
Bridget Kromhout
e9d1db56fa Adding VelNY bootcamp (#283)
* Adding VelNY bootcamp

* Colon not good here
2018-06-12 04:09:54 -05:00
Bridget Kromhout
a076a766a9 Merge pull request #282 from bridgetkromhout/reorder
Reordering upcoming events
2018-06-11 09:47:57 -07:00
Bridget Kromhout
be3c78bf54 Reordering 2018-06-11 09:40:30 -07:00
Bridget Kromhout
5bb6b8e2ab Merge pull request #281 from bridgetkromhout/add-velocity-sj-2018
Adding Velocity SJ 2018
2018-06-11 09:08:35 -07:00
Bridget Kromhout
f79193681d Adding Velocity SJ 2018 2018-06-11 08:53:53 -07:00
Bridget Kromhout
379ae69db5 Merge pull request #277 from bridgetkromhout/rollout-failure
Clarifying rollout failure via dashboard
2018-06-11 08:34:36 -07:00
Jerome Petazzoni
cde89f50a2 Add mention to skip slide if dashboard isn't deployed 2018-06-10 17:07:56 -05:00
Bridget Kromhout
98563ba1ce Clarifying rollout failure via dashboard 2018-06-04 20:58:57 -05:00
Bridget Kromhout
99bf8cc39f Merge pull request #271 from jpetazzo/new-index-generator
Replace index.html with a generator
2018-06-05 02:13:27 +02:00
Bridget Kromhout
ea642cf90e Merge pull request #274 from bridgetkromhout/eng-v
bumping version
2018-06-04 23:28:48 +02:00
Bridget Kromhout
a7d89062cf Bumping engine version 2018-06-04 15:43:30 -05:00
Bridget Kromhout
564e4856b4 Merge branch 'master' of https://github.com/jpetazzo/container.training 2018-06-04 14:41:07 -05:00
Bridget Kromhout
011cd08af3 Merge pull request #269 from jpetazzo/kubectlproxy
Show how to access internal services with kubectl proxy
2018-06-04 21:40:40 +02:00
Jerome Petazzoni
e294a4726c Update version numbers 2018-06-04 08:47:30 -05:00
Jerome Petazzoni
a21e8b0849 Image and title size fixes 2018-06-04 06:11:00 -05:00
Jerome Petazzoni
cc6f36b50f Wording (non-native speakers probably don't know boo-boo) 2018-06-04 05:54:02 -05:00
Jerome Petazzoni
6e35162788 Remove 'kubernetes in action' demo 2018-06-04 05:50:21 -05:00
Jerome Petazzoni
30ca940eeb Opt-out a bunch of slides in the deep dive section 2018-06-04 05:49:24 -05:00
Jerome Petazzoni
14eb19a42b Typo fixes 2018-06-04 05:43:28 -05:00
Jerome Petazzoni
da053ecde2 Update fundamentals TOC 2018-06-03 15:27:27 -05:00
Jerome Petazzoni
c86ef7de45 Add 'past workshops' page and backfill 2016-2017 workshops 2018-06-03 09:55:43 -05:00
Jérôme Petazzoni
c5572020b9 Add a few slides about resource limits (#273)
The section about namespaces and cgroups is very thorough,
but we also need something showing how to practically
limit container resource usage without diving into a very
deep technical chapter.
2018-06-03 05:28:16 -05:00
Jerome Petazzoni
3d7ed3a3f7 Clarify how to stop kubectl proxy 2018-06-03 05:10:48 -05:00
Bridget Kromhout
138163056f Merge pull request #270 from jpetazzo/kubectl-create-namespace
Show an easier way to create namespaces
2018-06-02 17:12:38 +02:00
Alexis Daboville
5e78e00bc9 Small typos (#272)
* Small typo

* elastichsearch -> elasticsearch

* realeased -> released
2018-06-02 09:09:38 -05:00
Jerome Petazzoni
2cb06edc2d Replace index.html with a generator
The events are now listend in index.yaml, and generated
with index.py. The latter is called automatically by
build.sh.

The list of events has been slightly improved:
- we only show the last 5 past events
- video recordings now get a section of their own
2018-05-31 14:22:23 -05:00
Jerome Petazzoni
8915bfb443 Update README section indicating 'teacher for hire' 2018-05-31 12:55:09 -05:00
Jerome Petazzoni
24017ad83f Clarify usage of <<< 2018-05-29 11:06:31 -05:00
Jerome Petazzoni
3edebe3747 New script to count slides
count-slides.py will count the number of slides per section,
and compute size of each chapter as well. It is not perfect
(for instance, it assumes that excluded_classes=in_person)
but it should help to assess the size of the content before
delivering long workshops.
2018-05-29 10:03:11 -05:00
Jerome Petazzoni
636a2d5c87 Show an easier way to create namespaces
We were using 'kubectl apply' with a YAML snppet.
It's valid, but it's quite convoluted. Instead,
let's use 'kubectl create namespace'. We can still
mention the other method of course.
2018-05-29 05:53:12 -05:00
Jerome Petazzoni
4213aba76e Show how to access internal services with kubectl proxy 2018-05-29 05:47:27 -05:00
Jerome Petazzoni
3e822bad82 Add a slide about JSON file and log rotation 2018-05-28 10:28:52 -05:00
Jerome Petazzoni
cd5b06b9c7 Show how to connect/disconnect dynamically 2018-05-28 10:08:11 -05:00
Jerome Petazzoni
b0841562ea Add a bunch of Dockerfile examples 2018-05-25 09:31:50 -05:00
Jerome Petazzoni
06f70e8246 Add 'tree' in the VMs
This is a convenient tool to get an idea of what a
directory hierarchy looks like.
2018-05-24 07:06:21 -05:00
Jerome Petazzoni
9614f8761a Add link to Serge Hallyn blog post 2018-05-24 06:03:28 -05:00
Jerome Petazzoni
92f9ab9001 Add a section leading to multi-stage builds 2018-05-24 05:46:28 -05:00
Bridget Kromhout
ad554f89fc New events (and old event to past) 2018-05-23 15:31:07 -05:00
Jerome Petazzoni
5bb37dff49 Parametrize git repo and slides URLs
We have two extra variables in the slides:
@@GITREPO@@ (current value: github.com/jpetazzo/container.training)
@@SLIDES@@ (current value: http://container.training/)

These variables are set with gitrepo and slides in the YAML files.
(Just like the chat variable.)

Supercedes #256
2018-05-23 15:27:57 -05:00
Bridget Kromhout
0d52dc2290 Merge pull request #267 from jasonknudsen/patch-1
Update README.md - typo
2018-05-23 10:22:05 -05:00
Bridget Kromhout
c575cb9cd5 New events (and old event to past) 2018-05-23 10:18:02 -05:00
jasonknudsen
9cdccd40c7 Update README.md - typo
Typo in instructions - should be pull_images not pull-images
2018-05-23 08:17:46 -07:00
Bret Fisher
fdd10c5a98 fix docker-compose scale up change (#265) 2018-05-18 10:10:06 -05:00
mkrupczak3
8a617fdbc7 change "alpine telnet" to "busybox telnet"
Newer versions of alpine may not include telnet
2018-05-18 10:01:41 -05:00
Jerome Petazzoni
a058a74d8f Minor fix for hidden autopilot command 2018-05-18 09:16:34 -05:00
Bret Fisher
4896a3265e Update volume chapter 2018-05-18 08:08:33 -05:00
Bret Fisher
131947275c Improve explanation about images and layers 2018-05-18 08:08:27 -05:00
Bret Fisher
1b7e8cec5e Update info about Docker for Mac/Windows 2018-05-18 08:08:20 -05:00
Bret Fisher
c17c0ea9aa Remove obsolete MAINTAINER command 2018-05-18 08:08:08 -05:00
Bridget Kromhout
7b378d2425 Merge pull request #264 from bridgetkromhout/master
Moving NDC to past
2018-05-14 06:56:23 -05:00
Bridget Kromhout
47da7d8278 Moving NDC to past 2018-05-14 06:53:08 -05:00
Bridget Kromhout
3c69941fcd Merge pull request #262 from bridgetkromhout/craft-past
Craft to past
2018-05-10 07:38:44 -05:00
Bridget Kromhout
beb188facf Craft to past 2018-05-10 07:36:30 -05:00
Bridget Kromhout
dfea8f6535 Merge pull request #258 from bridgetkromhout/add-ndc
Adding NDC Minnesota
2018-05-08 21:37:43 -05:00
Bridget Kromhout
3b89149bf0 Adding NDC Minnesota 2018-05-08 21:34:53 -05:00
Bret Fisher
c8d73caacd move visualizer to service and stack (#237) 2018-05-08 10:51:40 -05:00
Jérôme Petazzoni
290185f16b Merge pull request #255 from eightlimbed/patch-1
fixed a typo
2018-05-07 13:52:40 -05:00
Jérôme Petazzoni
05e9d36eed Merge pull request #254 from mkrupczak3/master
Fix typo create network to network create
2018-05-07 13:51:12 -05:00
Jérôme Petazzoni
05815fcbf3 Merge pull request #240 from BretFisher/settings-update
updated versions, renamed files
2018-05-07 13:15:34 -05:00
Lee Gaines
bce900a4ca fixed a typo
changed "contain" to "contained" in the first bullet point
2018-05-06 21:49:43 -07:00
mkrupczak3
bf7ba49013 Fix typo create network to network create 2018-05-05 16:55:22 -04:00
Bret Fisher
323aa075b3 removing settings feature teaser 2018-05-05 12:54:20 -04:00
Jérôme Petazzoni
f526014dc8 Merge pull request #253 from BretFisher/ingress-graphics
swarm ingress images and updates
2018-05-05 06:39:13 -05:00
Jérôme Petazzoni
dec546fa65 Merge pull request #252 from BretFisher/patch-15
update docker-compose scale command
2018-05-05 06:36:53 -05:00
Jérôme Petazzoni
36390a7921 Merge pull request #251 from BretFisher/swarm-3-nodes
moving to 3 node swarms by default
2018-05-05 06:35:45 -05:00
Jérôme Petazzoni
313d705778 Merge pull request #248 from BretFisher/fundamentals-cnm-updates
more fundamentals CNM tweaks
2018-05-05 06:20:06 -05:00
Jérôme Petazzoni
ca34efa2d7 Merge pull request #247 from BretFisher/patch-13
adding more images to cache
2018-05-05 05:49:52 -05:00
Jérôme Petazzoni
25e92cfe39 Merge pull request #245 from BretFisher/patch-12
more new features for swarm
2018-05-05 05:46:07 -05:00
Jérôme Petazzoni
999359e81a Update versions.md 2018-05-05 05:45:40 -05:00
Jérôme Petazzoni
3a74248746 Merge pull request #244 from BretFisher/patch-11
a bit more detail on network drivers included
2018-05-05 05:41:10 -05:00
Jérôme Petazzoni
cb828ecbd3 Update Container_Network_Model.md 2018-05-05 05:41:01 -05:00
Jérôme Petazzoni
e1e984e02d Merge pull request #243 from BretFisher/patch-10
Updating some compose info for devs
2018-05-05 05:40:10 -05:00
Jérôme Petazzoni
d6e19fe350 Update Compose_For_Dev_Stacks.md 2018-05-05 05:39:25 -05:00
Jérôme Petazzoni
1f91c748b5 Merge pull request #242 from BretFisher/check-for-entr-in-build
Friendly error if entr isn't installed for build.sh
2018-05-05 05:30:05 -05:00
Bret Fisher
38356acb4e swarm ingress images and updates 2018-05-04 13:00:49 -04:00
Bret Fisher
7b2d598c38 fix my fat fingers.
ugg, sorry, editing via github and I need to go to bed :)
2018-05-04 00:20:31 -04:00
Bret Fisher
c276eb0cfa remove fat finger 2018-05-04 00:19:35 -04:00
Bret Fisher
571de591ca update docker-compose scale command
scale command is now legacy, use `--scale` option instead
2018-05-04 00:18:58 -04:00
Bret Fisher
e49a197fd5 moving to 3 node swarms by default 2018-05-03 23:52:51 -04:00
Bret Fisher
a30eabc23a more fundamentals CNM tweaks 2018-05-03 19:28:39 -04:00
Bret Fisher
73c4cddba5 forgot one image :/ 2018-05-03 16:32:12 -04:00
Bret Fisher
6e341f770a adding more images to cache
Based on images used in swarm and fundamentals workshops
2018-05-03 16:24:54 -04:00
Bridget Kromhout
527145ec81 Merge pull request #241 from BretFisher/patch-8
date updates for container.training
2018-05-03 18:19:36 +02:00
Bret Fisher
c93edceffe more new features for swarm 2018-05-02 23:25:12 -04:00
Bret Fisher
6f9eac7c8e a bit more detail on network drivers included 2018-05-02 23:21:45 -04:00
Bret Fisher
522420ef34 Updating some compose info for devs 2018-05-02 23:18:19 -04:00
Bret Fisher
927bf052b0 Friendly error if entr isn't installed for build.sh 2018-05-02 23:08:52 -04:00
Bret Fisher
1e44689b79 swarm versions 2018-05-02 23:00:55 -04:00
Bret Fisher
b967865faa date updates for container.training 2018-05-02 22:24:12 -04:00
Bret Fisher
054c0cafb2 updated versions, renamed files 2018-05-02 17:43:08 -04:00
Jérôme Petazzoni
29e37c8e2b Merge pull request #235 from KMASubhani/patch-1
Update Getting_Inside.md
2018-04-25 23:33:24 -05:00
Jérôme Petazzoni
44fc2afdc7 Merge pull request #239 from BretFisher/fix-stack-deploy-cmd
reordering stack deploy cmd format
2018-04-25 23:29:58 -05:00
Jérôme Petazzoni
7776c8ee38 Merge pull request #238 from BretFisher/fix-detach-false
remove more unneeded detach=false
2018-04-25 23:27:54 -05:00
Bret Fisher
9ee7e1873f reording stack deploy cmd format 2018-04-25 16:33:38 -05:00
Bret Fisher
e21fcbd1bd remove more unneeded detach=false 2018-04-25 16:26:28 -05:00
Khaja Mashood Ahmed Subhani
5852ab513d Update Getting_Inside.md
fixed spelling
2018-04-25 11:00:37 -05:00
Jérôme Petazzoni
3fe33e4e9e Merge pull request #234 from bridgetkromhout/adding-ndc
Adding NDC
2018-04-24 03:56:13 -05:00
Bridget Kromhout
c44b90b5a4 Adding NDC 2018-04-23 20:03:46 -05:00
Jérôme Petazzoni
f06dc6548c Merge pull request #232 from bridgetkromhout/rollout-params
Clarify rollout params
2018-04-23 11:32:25 -05:00
Jérôme Petazzoni
e13552c306 Merge pull request #224 from bridgetkromhout/re-order
Re-ordering "kubectl apply" discussion
2018-04-23 11:31:15 -05:00
Bridget Kromhout
0305c3783f Adding an overview; marking clarification as extra 2018-04-23 10:52:29 -05:00
Bridget Kromhout
5158ac3d98 Clarify rollout params 2018-04-22 15:49:32 -05:00
Jérôme Petazzoni
25c08b0885 Merge pull request #231 from bridgetkromhout/add-goto-kube101
Adding goto's kube101
2018-04-22 14:55:55 -05:00
Bridget Kromhout
f8131c97e9 Adding goto's kube101 2018-04-22 14:35:50 -05:00
Bridget Kromhout
3de1fab66a Clarifying failure mode 2018-04-22 14:04:57 -05:00
Jérôme Petazzoni
ab664128b7 Merge pull request #228 from bridgetkromhout/helm-completion
Correction for helm completion
2018-04-22 14:00:08 -05:00
Bridget Kromhout
91de693b80 Correction for helm completion 2018-04-22 13:33:54 -05:00
Jérôme Petazzoni
a64606fb32 Merge pull request #225 from bridgetkromhout/tail-log
Clarify log tailing
2018-04-22 13:14:11 -05:00
Jérôme Petazzoni
58d9103bd2 Merge pull request #223 from bridgetkromhout/1.10.1-updates
Updates for 1.10.1
2018-04-22 13:13:25 -05:00
Jérôme Petazzoni
61ab5be12d Merge pull request #222 from bridgetkromhout/weave-link
Link to Weave
2018-04-22 13:08:54 -05:00
Bridget Kromhout
030900b602 Clarify log tailing 2018-04-22 12:39:18 -05:00
Bridget Kromhout
476d689c7d Clarify naming 2018-04-22 12:32:11 -05:00
Bridget Kromhout
4aedbb69c2 Re-ordering 2018-04-22 12:14:16 -05:00
Bridget Kromhout
db2a68709c Updates for 1.10.1 2018-04-22 11:57:37 -05:00
Bridget Kromhout
f114a89136 Link to Weave 2018-04-22 11:08:17 -05:00
Jérôme Petazzoni
96eda76391 Merge pull request #220 from bridgetkromhout/rearrange-kube-halfday
Rearrange kube halfday
2018-04-21 10:48:21 -05:00
Bridget Kromhout
e7d9a8fa2d Correcting EFK 2018-04-21 10:43:39 -05:00
Bridget Kromhout
1cca8db828 Rearranging halfday for kube 2018-04-21 10:38:54 -05:00
Bridget Kromhout
2cde665d2f Merge pull request #219 from jpetazzo/re-add-kube-halfday
Re-add half day file
2018-04-21 10:17:45 -05:00
Jerome Petazzoni
d660c6342f Re-add half day file 2018-04-21 12:00:04 +02:00
Bridget Kromhout
7e8bb0e51f Merge pull request #218 from bridgetkromhout/cloud-typo
Typo fix
2018-04-20 16:49:31 -05:00
Bridget Kromhout
c87f4cc088 Typo fix 2018-04-20 16:47:13 -05:00
Jérôme Petazzoni
05c50349a8 Merge pull request #211 from BretFisher/patch-4
add popular swarm reverse proxy options
2018-04-20 02:38:00 -05:00
Jérôme Petazzoni
e985952816 Add colon and fix minor typo 2018-04-20 02:37:48 -05:00
Jérôme Petazzoni
19f0ef9c86 Merge pull request #216 from jpetazzo/googl
Replace goo.gl with 1.1.1.1
2018-04-20 02:36:15 -05:00
Bret Fisher
cc8e13a85f silly me, Traefik is golang 2018-04-20 03:07:40 -04:00
Bridget Kromhout
6475a05794 Update kubectlrun.md
Removing misleading term
2018-04-19 14:37:26 -05:00
Bridget Kromhout
cc9840afe5 Update kubectlrun.md 2018-04-19 07:36:37 -05:00
Bridget Kromhout
b7a2cde458 Merge pull request #215 from jpetazzo/more-options-to-setup-k8s
Mention Kubernetes the Hard Way and more options
2018-04-19 07:32:20 -05:00
Bridget Kromhout
453992b55d Update setup-k8s.md 2018-04-19 07:31:25 -05:00
Bridget Kromhout
0b1067f95e Merge pull request #217 from jpetazzo/tolerations
Add a line about tolerations
2018-04-19 07:28:57 -05:00
Jérôme Petazzoni
21777cd95b Merge pull request #214 from BretFisher/patch-7
we can now add/remove networks from services 🤗
2018-04-19 06:35:09 -05:00
Jérôme Petazzoni
827ad3bdf2 Merge pull request #213 from BretFisher/patch-6
product name change 🙄
2018-04-19 06:34:41 -05:00
Jérôme Petazzoni
7818157cd0 Merge pull request #212 from BretFisher/patch-5
adding 3rd party registry options
2018-04-19 06:34:22 -05:00
Jérôme Petazzoni
d547241714 Merge pull request #210 from BretFisher/patch-3
fix image size via pic css class
2018-04-19 06:31:46 -05:00
Jérôme Petazzoni
c41e0e9286 Merge pull request #209 from BretFisher/patch-2
removed older notes about detach and service logs
2018-04-19 06:31:17 -05:00
Jérôme Petazzoni
c2d4784895 Merge pull request #208 from BretFisher/patch-1
removed mention of compose upg 1.6 to 1.7
2018-04-19 06:30:47 -05:00
Jérôme Petazzoni
11163965cf Merge pull request #204 from bridgetkromhout/clarify-off-by-one
Clarify an off-by-one amount of pods
2018-04-19 06:30:19 -05:00
Jérôme Petazzoni
e9df065820 Merge pull request #197 from bridgetkromhout/patch-only-daemonset
Patch only daemonset pods
2018-04-19 06:27:52 -05:00
Jerome Petazzoni
101ab0c11a Add a line about tolerations 2018-04-19 06:25:41 -05:00
Jérôme Petazzoni
25f081c0b7 Merge pull request #190 from bridgetkromhout/daemonset
Clarifications around daemonsets
2018-04-19 06:21:58 -05:00
Jérôme Petazzoni
700baef094 Merge pull request #188 from bridgetkromhout/clarify-kinds
kubectl get all missing-type workaround
2018-04-19 06:19:00 -05:00
Jerome Petazzoni
3faa586b16 Remove NOC joke 2018-04-19 06:14:54 -05:00
Jerome Petazzoni
8ca77fe8a4 Merge branch 'googl' of git://github.com/bridgetkromhout/container.training into bridgetkromhout-googl 2018-04-19 05:59:12 -05:00
Jerome Petazzoni
019829cc4d Mention Kubernetes the Hard Way and more options 2018-04-19 05:55:58 -05:00
Bret Fisher
a7f6bb223a we can now add/remove networks from services 🤗 2018-04-18 19:11:51 -04:00
Bret Fisher
eb77a8f328 product name change 🙄 2018-04-18 17:50:19 -04:00
Bret Fisher
5a484b2667 adding 3rd party registry options 2018-04-18 17:47:55 -04:00
Bret Fisher
982c35f8e7 add popular swarm reverse proxy options 2018-04-18 17:28:46 -04:00
Bret Fisher
adffe5f47f fix image size via pic css class
make swarm internals bigger!
2018-04-18 17:07:33 -04:00
Bret Fisher
f90a194b86 removed older notes about detach and service logs
Since these options have been around nearly a year, I removed some unneeded verbosity and consolidated the detach stuff.
2018-04-18 15:34:04 -04:00
Bret Fisher
99e9356e5d removed mention of compose upg 1.6 to 1.7
I feel like compose 1.7 was so long ago (over 2 years) that mentioning logs change isn't necessary.
2018-04-18 15:18:17 -04:00
Bridget Kromhout
860840a4c1 Clarify off-by-one 2018-04-18 14:09:08 -05:00
Bridget Kromhout
ab63b76ae0 Clarify types bug 2018-04-18 13:59:26 -05:00
Bridget Kromhout
29bca726b3 Merge pull request #2 from jpetazzo/daemonset-proposal
Pod cleanup proposal
2018-04-18 12:21:34 -05:00
Bridget Kromhout
91297a68f8 Update daemonset.md 2018-04-18 12:20:53 -05:00
Jerome Petazzoni
2bea8ade63 Break down last kube chapter (it is too long) 2018-04-18 11:44:30 -05:00
Jerome Petazzoni
ec486cf78c Do not bind-mount localtime (fixes #207) 2018-04-18 03:33:07 -05:00
Jerome Petazzoni
63ac378866 Merge branch 'darkalia-add_helm_completion' 2018-04-17 16:13:58 -05:00
Jerome Petazzoni
35db387fc2 Add ':' for consistency 2018-04-17 16:13:44 -05:00
Jerome Petazzoni
a0f9baf5e7 Merge branch 'add_helm_completion' of git://github.com/darkalia/container.training into darkalia-add_helm_completion 2018-04-17 16:12:52 -05:00
Jerome Petazzoni
4e54a79abc Pod cleanup proposal 2018-04-17 16:07:24 -05:00
Jérôme Petazzoni
37bea7158f Merge pull request #181 from jpetazzo/more-info-on-labels-and-rollouts
Label use-cases and rollouts
2018-04-17 15:18:24 -05:00
Jerome Petazzoni
618fe4e959 Clarify the grace period when shutting down pods 2018-04-17 02:24:07 -05:00
Jerome Petazzoni
0c73144977 Merge branch 'jgarrouste-patch-1' 2018-04-16 08:03:34 -05:00
Jerome Petazzoni
ff8c3b1595 Remove -o name 2018-04-16 08:03:09 -05:00
Jerome Petazzoni
b756d0d0dc Merge branch 'patch-1' of git://github.com/jgarrouste/container.training into jgarrouste-patch-1 2018-04-16 08:02:41 -05:00
Jerome Petazzoni
23147fafd1 Paris -> past sessions 2018-04-15 15:57:46 -05:00
Jérémy GARROUSTE
b036b5f24b Delete pods with ''-l run-rng' and remove xargs
Delete pods with ''-l run-rng' and remove xargs
2018-04-15 16:37:10 +02:00
Benjamin Allot
3b9014f750 Add helm completion 2018-04-13 16:40:42 +02:00
Jérôme Petazzoni
6ad7a285e7 Merge pull request #201 from bridgetkromhout/chart-clarity
Clarify chart install
2018-04-13 01:08:13 -05:00
Jérôme Petazzoni
e529eaed2d Merge pull request #200 from bridgetkromhout/helm-example
Use prometheus as example
2018-04-13 01:07:18 -05:00
Jérôme Petazzoni
4697c6c6ad Merge pull request #189 from bridgetkromhout/elastic-patience
Clarify error message upon start & endpoints
2018-04-13 01:06:33 -05:00
Jérôme Petazzoni
56e47c3550 Update kubectlexpose.md
Add line break for readability
2018-04-13 08:06:23 +02:00
Jérôme Petazzoni
b3a9ba339c Merge pull request #199 from bridgetkromhout/helm-mkdir
Directory missing
2018-04-13 01:04:39 -05:00
Jérôme Petazzoni
8d0ce37a59 Merge pull request #196 from bridgetkromhout/or-azure
Azure directions are also included
2018-04-13 01:04:07 -05:00
Jérôme Petazzoni
a1bbbd6f7b Merge pull request #195 from bridgetkromhout/slide-clarity
Making slide easier to read
2018-04-13 01:03:39 -05:00
Bridget Kromhout
de87743c6a Clarify an off-by-one amount of pods 2018-04-12 16:10:38 -05:00
Bridget Kromhout
9d4a72a4ba Merge pull request #202 from bridgetkromhout/url-update-fix
Fixing typo
2018-04-12 15:30:11 -05:00
Bridget Kromhout
19e39aea49 Fixing typo 2018-04-12 15:27:51 -05:00
Bridget Kromhout
da064a6005 Clarify chart install 2018-04-12 10:24:01 -05:00
Bridget Kromhout
a12a38a7a9 Use prometheus as example 2018-04-12 09:50:12 -05:00
Bridget Kromhout
2c3a442a4c wording correction
The addresses aren't what show us the addresses - it seems clear from context that this should be "commands".
2018-04-12 08:11:43 -05:00
Bridget Kromhout
25d560cf46 Directory missing 2018-04-12 07:48:25 -05:00
Bridget Kromhout
c3324cf64c More general 2018-04-12 07:41:43 -05:00
Bridget Kromhout
053bbe7028 Bold instead of highlighting 2018-04-12 07:39:02 -05:00
Bridget Kromhout
74f980437f Clarify that clusters can be of arbitrary size 2018-04-12 07:31:49 -05:00
Jérôme Petazzoni
5ef96a29ac Update kubectlexpose.md 2018-04-12 00:37:18 -05:00
Jérôme Petazzoni
f261e7aa96 Merge pull request #194 from bridgetkromhout/fix-blue
removing extra leading spaces which break everything
2018-04-11 23:55:34 -05:00
Jérôme Petazzoni
8e44e911ca Merge pull request #193 from bridgetkromhout/stern
Missing word added
2018-04-11 23:52:17 -05:00
Bridget Kromhout
6711ba06d9 Patch only daemonset pods 2018-04-11 21:09:46 -05:00
Bridget Kromhout
fce69b6bb2 Azure directions are also included 2018-04-11 19:34:51 -05:00
Bridget Kromhout
1183e2e4bf Making slide easier to read 2018-04-11 18:55:23 -05:00
Bridget Kromhout
de3082e48f Extra spaces prevent this from working 2018-04-11 18:47:30 -05:00
Bridget Kromhout
3acac34e4b Missing word added 2018-04-11 18:11:07 -05:00
Bridget Kromhout
f97bd2b357 googl to cloudflare 2018-04-11 13:36:00 -05:00
Jérôme Petazzoni
3bac124921 Merge pull request #183 from bridgetkromhout/stalling-for-time
Stalling for time during download
2018-04-11 14:56:02 +02:00
Bridget Kromhout
ba44603d0f Correcting title and slide section division 2018-04-11 06:53:01 -05:00
Jerome Petazzoni
358f844c88 Typo fix 2018-04-11 02:40:38 -07:00
Jérôme Petazzoni
74bf2d742c Merge pull request #182 from bridgetkromhout/versions-validated
Clarify versions validated
2018-04-10 23:11:38 -07:00
Jérôme Petazzoni
acba3d5467 Merge pull request #192 from bridgetkromhout/add-links
Add links
2018-04-10 23:03:09 -07:00
Jérôme Petazzoni
cfc066c8ea Merge pull request #191 from jgarrouste/master
Reversed sentences
2018-04-10 15:03:09 -07:00
Jérôme Petazzoni
4f69f19866 Merge pull request #186 from bridgetkromhout/vm-readme
link to VM prep README
2018-04-10 14:56:19 -07:00
Jérôme Petazzoni
c508f88af2 Update setup-k8s.md 2018-04-10 16:56:07 -05:00
Jérôme Petazzoni
9757fdb42f Merge pull request #185 from bridgetkromhout/article
Adding an article
2018-04-10 14:52:49 -07:00
Bridget Kromhout
24d57f535b Add links 2018-04-10 16:52:07 -05:00
Jérôme Petazzoni
e42dfc0726 Merge pull request #184 from bridgetkromhout/url-update
URL update
2018-04-10 14:51:55 -07:00
Bridget Kromhout
3f54f23535 Clarifying cleanup 2018-04-10 16:45:50 -05:00
Jérémy GARROUSTE
c7198b3538 correction 2018-04-10 22:56:42 +02:00
Bridget Kromhout
827d10dd49 Clarifying ambiguous labels on pods 2018-04-10 15:48:54 -05:00
Bridget Kromhout
1b7a072f25 Bump version and add link 2018-04-10 15:29:14 -05:00
Bridget Kromhout
af1347ca17 Clarify endpoints 2018-04-10 15:07:42 -05:00
Bridget Kromhout
f741cf5b23 Clarify error message upon start 2018-04-10 14:33:49 -05:00
Bridget Kromhout
eb1b3c8729 Clarify types 2018-04-10 14:17:27 -05:00
Bridget Kromhout
40e4678a45 goo.gl deprecation 2018-04-10 12:41:07 -05:00
Bridget Kromhout
d3c0a60de9 link to VM prep README 2018-04-10 12:30:46 -05:00
Bridget Kromhout
83bba80f3b URL update 2018-04-10 12:25:44 -05:00
Bridget Kromhout
44e0cfb878 Adding an article 2018-04-10 12:22:24 -05:00
Bridget Kromhout
a58e21e313 URL update 2018-04-10 12:15:01 -05:00
Bridget Kromhout
1131635006 Stalling for time during download 2018-04-10 11:52:52 -05:00
Bridget Kromhout
c6e477e6ab Clarify versions validated 2018-04-10 11:35:28 -05:00
Jerome Petazzoni
18a81120bc Add helper script to gauge chapter weights 2018-04-10 08:41:23 -05:00
Jerome Petazzoni
17cd67f4d0 Breakdown container internals chapter 2018-04-10 08:41:05 -05:00
Jerome Petazzoni
38a40d56a0 Label use-cases and rollouts
This adds a few realistic examples of label usage.
It also adds explanations about why deploying a new
version of the worker doesn't seem to be effective
immediately (the worker doesn't handle signals).
2018-04-10 06:04:17 -05:00
Jerome Petazzoni
96fd2e26fd Minor fixes for autopilot 2018-04-10 05:30:42 -05:00
Jerome Petazzoni
581bbc847d Add demo logo for k8s demo 2018-04-10 04:25:08 -05:00
Jerome Petazzoni
da7cbc41d2 Merge branch 'master' of github.com:jpetazzo/container.training 2018-04-09 17:06:35 -05:00
Jerome Petazzoni
282e22acb9 Improve chapters about container deep dive 2018-04-09 17:06:29 -05:00
Jérôme Petazzoni
9374eebdf6 Merge pull request #180 from bridgetkromhout/links-before-thanks
Moving links before thanks
2018-04-09 13:23:32 -07:00
Bridget Kromhout
dcd5c5b39a Moving links before thanks 2018-04-09 14:58:56 -05:00
Jérôme Petazzoni
974f8ee244 Merge pull request #179 from bridgetkromhout/mosh-tmux
Clarifications for tmux and mosh
2018-04-09 12:55:03 -07:00
Bridget Kromhout
8212aa378a Merge pull request #1 from jpetazzo/ode-to-mosh-and-tmux
Add even more info about mosh and tmux
2018-04-09 14:54:16 -05:00
Jerome Petazzoni
403d4c6408 Add even more info about mosh and tmux 2018-04-09 14:52:21 -05:00
Jerome Petazzoni
142681fa27 Merge branch 'master' of github.com:jpetazzo/container.training 2018-04-09 14:19:45 -05:00
Jerome Petazzoni
69c9141817 Enable new content in self-paced kube workshop 2018-04-09 14:19:27 -05:00
Bridget Kromhout
9ed88e7608 Clarifications for tmux and mosh 2018-04-09 14:19:16 -05:00
Jérôme Petazzoni
b216f4d90b Merge pull request #178 from bridgetkromhout/clarify-live
Formatting fixes
2018-04-09 12:13:07 -07:00
Bridget Kromhout
26ee07d8ba Format fix 2018-04-09 13:20:23 -05:00
Bridget Kromhout
a8e5b02fb4 Clarify live feedback 2018-04-09 13:18:25 -05:00
Jérôme Petazzoni
80a8912a53 Merge pull request #177 from jpetazzo/avril-2018
Avril 2018
2018-04-09 11:08:21 -07:00
Jérôme Petazzoni
1ba6797f25 Merge pull request #176 from bridgetkromhout/version-bump
Updating versions
2018-04-09 10:57:32 -07:00
Bridget Kromhout
11a2167dea Updating versions 2018-04-09 12:52:47 -05:00
Jérôme Petazzoni
af4eeb6e6b Merge pull request #175 from jpetazzo/helm-and-namespaces
Add two chapters: Helm and namespaces
2018-04-09 10:20:33 -07:00
Jérôme Petazzoni
ea6459e2bd Merge pull request #174 from jpetazzo/centralized-logging-with-efk
Add a chapter about centralized logging
2018-04-09 10:19:44 -07:00
Bridget Kromhout
2dfa5a9660 Update logs-centralized.md 2018-04-09 11:59:19 -05:00
Jerome Petazzoni
b86434fbd3 Merge branch 'master' of github.com:jpetazzo/container.training 2018-04-09 11:57:32 -05:00
Jerome Petazzoni
223525cc69 Add the new chapters
The new chapters are commented our right now.
But they're ready to be enabled whenever needed.
2018-04-09 11:57:16 -05:00
Bridget Kromhout
fd63c079c8 Update namespaces.md
typo fix
2018-04-09 11:44:45 -05:00
Jerome Petazzoni
ebe4511c57 Remove useless mkdir 2018-04-09 11:43:27 -05:00
Jérôme Petazzoni
e1a81ef8f3 Merge pull request #171 from jpetazzo/show-stern-to-view-logs
Show how to install and use Stern
2018-04-09 09:38:47 -07:00
Jerome Petazzoni
3382c83d6e Add link to Helm and say it's open source 2018-04-09 11:35:59 -05:00
Bridget Kromhout
a89430673f Update logs-cli.md
clarifications
2018-04-09 11:32:02 -05:00
Jerome Petazzoni
fcea6dbdb6 Clarify Stern installation comments 2018-04-09 11:29:19 -05:00
Bridget Kromhout
c744a7d168 Update helm.md
typo fixes
2018-04-09 11:27:34 -05:00
Bridget Kromhout
0256dc8640 Update logs-centralized.md
A few typo fixes
2018-04-09 11:22:43 -05:00
Jerome Petazzoni
41819794d7 Rename kube-halfday
We now have a full day of content. Rejoice.
2018-04-09 11:19:24 -05:00
Jerome Petazzoni
836903cb02 Merge branch 'master' of github.com:jpetazzo/container.training 2018-04-09 11:11:33 -05:00
Jerome Petazzoni
7f822d33b5 Clean up index.html
Comment out a bunch of older workshops (for which more recent
versions have been delivered since then). Update the links
to self-paced content.
2018-04-09 11:11:26 -05:00
Jérôme Petazzoni
232fdbb1ff Merge pull request #170 from jpetazzo/headless-services
Add headless services
2018-04-09 09:05:33 -07:00
Jerome Petazzoni
f3f6111622 Replace logistics.md with generic version
The current version of the logistics.md slide shows AJ and JP.
The new version is an obvious template, i.e. it says 'this slide
should be customized' and it uses imaginary personas instead.
2018-04-09 10:59:55 -05:00
Jerome Petazzoni
a8378e7e7f Clarify endpoints 2018-04-09 10:12:22 -05:00
Jerome Petazzoni
eb3165096f Add Logging section and manifests 2018-04-09 09:37:28 -05:00
Jerome Petazzoni
90ca58cda8 Add a few slides about network policies
This is a very high-level overview (we can't cover a lot within the current time constraints) but it gives a primer about network policies and a few links to explore further.
2018-04-09 08:27:31 -05:00
Jerome Petazzoni
5a81526387 Add two chapters: Helm and namespaces
In these chapters, we:
- show how to install Helm
- run the Helm tiller on our cluster
- use Helm to install Prometheus
- don't do anything fancy with
  Prometheus (it's just for the
  sake of installing something)
- create a basic Helm chart for
  DockerCoins
- explain namespace concepts
- show how to use contexts to hop
  between namespaces
- use Helm to deploy DockerCoins
  to a new namespace

These two chapters go together.
2018-04-09 07:57:27 -05:00
Jerome Petazzoni
8df073b8ac Add a chapter about centralized logging
Explain the purpose of centralized logging. Describe the
EFK stack. Deploy a simplified EFK stack through a YAML
file. Use it to view container logs. Profit.
2018-04-09 04:17:00 -05:00
Jérôme Petazzoni
0f7356b002 Merge pull request #167 from jgarrouste/avril-2018
Small changes
2018-04-09 00:26:13 -07:00
Jérôme Petazzoni
0c2166fb5f Merge pull request #172 from jpetazzo/clarify-daemonset-bonus-exercises
Clarify the bonus exercises
2018-04-09 00:24:26 -07:00
Jerome Petazzoni
d228222fa6 Reword headless services
Hopefully this explains better the use of headless services.
I also added a slide about endpoints, with a couple of simple
commands to show them.
2018-04-08 17:59:42 -05:00
Bridget Kromhout
e4b7d3244e Merge pull request #173 from bridgetkromhout/muracon-past
MuraCon to past
2018-04-08 17:50:09 -05:00
Bridget Kromhout
7d0e841a73 MuraCon to past 2018-04-08 17:46:55 -05:00
Jerome Petazzoni
9859e441e1 Clarify the bonus exercises
We had two open-ended exercises (questions without
answers). We have added more explanations, as well
as solutions for the exercises. It lets us show a
few more tricks with selectors, and how to apply
changes to sets of resources.
2018-04-08 17:16:27 -05:00
Jerome Petazzoni
e1c638439f Bump versions
Bump up Compose and Machine to latest versions.
Bump down Engine to stable branch.

I'm pushing straight to master because YOLO^W^W
because @bridgetkromhout is using the kube101.yaml
file anyway, so this shouldn't break her things.

(Famous last words...)
2018-04-08 16:34:48 -05:00
Jérôme Petazzoni
253aaaad97 Merge pull request #169 from jpetazzo/what-is-cni
Add slide about CNI
2018-04-08 14:32:17 -07:00
Jérôme Petazzoni
a249ccc12b Merge pull request #168 from jpetazzo/clarify-control-plane
Clarify control plane
2018-04-08 14:29:50 -07:00
Jerome Petazzoni
22fb898267 Show how to install and use Stern
Stern is super cool to stream the logs of multiple
containers.
2018-04-08 16:26:08 -05:00
Bridget Kromhout
e038797875 Update concepts-k8s.md
A few suggested clarifications to your (excellent) clarifications
2018-04-08 15:16:42 -05:00
Jerome Petazzoni
7b9f9e23c0 Add headless services 2018-04-08 11:10:07 -05:00
Jerome Petazzoni
01d062a68f Add slide about CNI 2018-04-08 10:31:17 -05:00
Jerome Petazzoni
a66dfb5faf Clarify control plane
Explain better that the control plane can run outside
of the cluster, and that the word master can be
confusing (does it designate the control plane, or
the node running the control plane? What if there is
no node running the control plane, because the control
plane is external?)
2018-04-08 09:57:51 -05:00
Jerome Petazzoni
ac1480680a Add ecosystem chapter 2018-04-08 08:40:20 -05:00
Jerome Petazzoni
13a9b5ca00 What IS docker?
Explain what the engine is
2018-04-08 07:21:47 -05:00
Jérémy GARROUSTE
0cdf6abf0b Add .center for some images 2018-04-07 20:16:29 +02:00
Jérémy GARROUSTE
2071694983 Add .small[] 2018-04-07 20:16:13 +02:00
Jérôme Petazzoni
12e2b18a6f Merge pull request #166 from jgarrouste/avril-2018
Update the output of docker version and docker build command
2018-04-07 09:30:11 -07:00
Jerome Petazzoni
28e128756d How to pass container config 2018-04-07 11:28:42 -05:00
Jerome Petazzoni
a15109a12c Add chapter about labels 2018-04-07 09:57:35 -05:00
Jerome Petazzoni
e500fb57e8 Add --mount syntax 2018-04-07 09:37:27 -05:00
Jerome Petazzoni
f1849092eb add chapter on Docker Machine 2018-04-07 07:33:28 -05:00
Jerome Petazzoni
f1dbd7e8a6 Copy on write 2018-04-06 09:27:29 -05:00
Jerome Petazzoni
d417f454dd Finalize section on namespaces and cgroups 2018-04-06 09:27:20 -05:00
Jérémy GARROUSTE
d79718d834 Update docker build output 2018-04-06 11:20:09 +02:00
Jérémy GARROUSTE
de9c3a1550 Update docker version output 2018-04-06 10:04:41 +02:00
Jerome Petazzoni
90fc7a4ed3 Merge branch 'avril-2018' of github.com:jpetazzo/container.training into avril-2018 2018-04-05 17:58:55 -05:00
Jerome Petazzoni
09edbc24bc Container deep dive: namespaces, cgroups, etc. 2018-04-05 17:58:43 -05:00
Jérémy GARROUSTE
92f8701c37 Update output of docker build 2018-04-06 00:00:27 +02:00
Jérôme Petazzoni
c828888770 Merge pull request #165 from jgarrouste/avril-2018
Update output of 'docker build'
2018-04-05 14:57:05 -07:00
Jérémy GARROUSTE
bb7728e7e7 Update docker build output 2018-04-05 23:52:37 +02:00
Jerome Petazzoni
5f544f9c78 Add container engines chapter; orchestration overview chapter 2018-04-04 17:09:21 -05:00
Jerome Petazzoni
5b6a7d1995 Update my email address 2018-04-02 18:52:48 -05:00
Jerome Petazzoni
b21185dde7 Introduce EXPOSE 2018-04-02 00:10:45 -05:00
Jerome Petazzoni
deaee0dc82 Explain why use Docker Inc's repos 2018-04-01 23:58:10 -05:00
Jerome Petazzoni
4206346496 MacOS -> macOS 2018-04-01 23:52:38 -05:00
Jerome Petazzoni
6658b632b3 Add reason why we use VMs 2018-04-01 23:49:08 -05:00
Jerome Petazzoni
d9be7160ef Move 'extra details' explanation slide to common deck 2018-04-01 23:34:19 -05:00
Jérôme Petazzoni
d56424a287 Merge pull request #164 from bridgetkromhout/adding-k8s-101
Adding more k8s 101 dates
2018-03-29 16:02:31 -07:00
Bridget Kromhout
2d397c5cb8 Adding more k8s 101 dates 2018-03-29 09:39:20 -07:00
Jérôme Petazzoni
08004caa5d Merge pull request #163 from BretFisher/bret-dates-2018q2
adding more dates
2018-03-28 10:26:07 -07:00
Frank Farmer
522358a004 Small typo 2018-03-28 12:23:47 -05:00
Jérôme Petazzoni
e00a6c36e3 Merge pull request #157 from bridgetkromhout/increase-ulimit
Increase allowed open files
2018-03-28 10:07:11 -07:00
Jérôme Petazzoni
4664497cbc Merge pull request #156 from bridgetkromhout/symlinks-on-rerun
Symlink and directory fixes for multiple runs
2018-03-28 10:06:39 -07:00
Bret Fisher
6be424bde5 adding more dates 2018-03-28 03:27:18 -04:00
Bridget Kromhout
0903438242 Increase allowed open files 2018-03-27 09:36:04 -07:00
Bridget Kromhout
b874b68e57 Symlink fixes for multiple runs 2018-03-27 09:25:48 -07:00
Bridget Kromhout
6af9385c5f Merge pull request #155 from bridgetkromhout/update-index
Updating index
2018-03-27 11:08:14 -05:00
Bridget Kromhout
29398ac33b Updating index 2018-03-27 09:06:03 -07:00
Jérôme Petazzoni
7525739b24 Merge pull request #151 from sadiqkhoja/patch-1
corrected number of containers
2018-03-27 05:50:50 -07:00
Bridget Kromhout
50ff71f3f3 Merge pull request #152 from bridgetkromhout/current-versions
Updating versions
2018-03-27 05:04:14 -05:00
Bridget Kromhout
70a9215c9d Updating versions 2018-03-27 03:02:17 -07:00
Sadiq Khoja
9c1a5d9a7d corrected number of containers 2018-03-17 14:39:05 +05:00
Jérôme Petazzoni
9a9b4a6892 Merge pull request #150 from inful/patch-3
Fix: Kubicorn URL
2018-03-14 11:03:28 -07:00
Jone Marius Vignes
e5502c724e Fix: Kubicorn URL
Kubicorn has moved permanently to https://github.com/kubicorn/kubicorn
2018-03-14 14:50:56 +01:00
Jérôme Petazzoni
125878e280 Merge pull request #147 from bridgetkromhout/clarify-socat-port
Clarifying how to find the port needed.
2018-03-13 13:27:51 -07:00
Bridget Kromhout
b4c1498ca1 Clarifying instructions 2018-03-13 20:55:11 +01:00
Bridget Kromhout
88d534a7f2 Clarifying how to find the port needed. 2018-03-13 20:36:19 +01:00
Jérôme Petazzoni
6ce4ed0937 Merge pull request #146 from bridgetkromhout/version-update
Versions updated
2018-03-13 11:53:51 -07:00
Bridget Kromhout
1b9ba62dc8 Versions updated 2018-03-13 19:27:42 +01:00
Jérôme Petazzoni
f3639e6200 Merge pull request #145 from bridgetkromhout/increase-timeout
Increasing timeout for slow mirrors
2018-03-12 13:49:24 -07:00
Bridget Kromhout
1fe56cf401 Increasing timeout for slow mirrors 2018-03-12 21:41:47 +01:00
Jerome Petazzoni
a3add3d816 Get inside a container (live and post mortem) 2018-03-12 11:57:34 -05:00
Jérôme Petazzoni
2807de2123 Merge pull request #144 from wlonkly/patch-2
Remove duplicate line
2018-03-10 14:55:39 -08:00
Jérôme Petazzoni
5029b956d2 Merge pull request #143 from wlonkly/patch-1
Fix typo: compiler -> container
2018-03-10 14:53:50 -08:00
Rich Lafferty
815aaefad9 Remove duplicate line 2018-03-10 15:43:40 -05:00
Rich Lafferty
7ea740f647 Fix typo: compiler -> container 2018-03-10 15:09:32 -05:00
Jerome Petazzoni
eaf25e5b36 Improve kubetest error reporting
The kubetest command used to say [SUCCESS] on completely
fresh nodes. Now we check the existence of the /tmp/node
file, as well as of the kubectl executable.
2018-03-07 16:17:57 -08:00
Jerome Petazzoni
3b336a9127 Merge branch 'bridgetkromhout-attribute-authorship' 2018-03-07 15:47:39 -08:00
Jerome Petazzoni
cc4d1fd1c7 Slight rewording 2018-03-07 15:47:38 -08:00
Jerome Petazzoni
17ec6441a0 Merge branch 'attribute-authorship' of git://github.com/bridgetkromhout/container.training into bridgetkromhout-attribute-authorship 2018-03-07 15:42:49 -08:00
Jerome Petazzoni
a1b107cecb Add Paris sessions 2018-03-07 15:39:23 -08:00
Jérôme Petazzoni
2e06bc2352 Merge pull request #140 from atsaloli/patch-2
Fix tiny typo (missing "o" in "outbound"
2018-03-06 09:54:38 -08:00
Aleksey Tsalolikhin
af0a239bd9 Fix tiny typo (missing "o" in "outbound" 2018-03-06 09:22:42 -08:00
Bridget Kromhout
92939ca3f2 Merge pull request #138 from jpetazzo/lets-tag-things-properly
Tag images properly
2018-03-05 19:55:09 -06:00
Jerome Petazzoni
aca51901a1 Tag images properly
This tags the first build with v0.1, allowing for a smoother, more
logical rollback. Also adds a slide explaining why to stay away
from latest. @kelseyhightower would be proud :-)
2018-03-05 16:13:30 -08:00
Jérôme Petazzoni
8d15dba26d Merge pull request #137 from bridgetkromhout/checklist-edits
Clarifications and links for checklist
2018-03-05 16:13:06 -08:00
Bridget Kromhout
cdca5655fc Clarifications and links for checklist 2018-03-05 17:08:06 -06:00
Jerome Petazzoni
c778fc84ed Add a dump of the checklist I use when delivering 2018-03-05 14:30:39 -08:00
Bridget Kromhout
7f72ee1296 Credit to multiple contributors 2018-03-05 15:53:42 -06:00
Jérôme Petazzoni
1981ac0b93 Merge pull request #135 from bridgetkromhout/bridget-specific
Adding Bridget-specific files
2018-03-05 13:36:06 -08:00
Jérôme Petazzoni
a8f2fb4586 Merge pull request #134 from bridgetkromhout/dedup-thanks
De-dup thanks; add comma
2018-03-05 13:35:45 -08:00
Jérôme Petazzoni
a69d3d0828 Merge pull request #133 from bridgetkromhout/no-chatroom
Makes more sense for "in person" chat
2018-03-05 13:32:51 -08:00
Jérôme Petazzoni
40760f9e98 Merge pull request #131 from bridgetkromhout/change-instance-type
Changing Azure instance type
2018-03-05 13:25:49 -08:00
Bridget Kromhout
b64b16dd67 Adding Bridget-specific files 2018-03-05 14:54:28 -06:00
Bridget Kromhout
8c2c9bc5df De-dup thanks; add comma 2018-03-05 14:51:26 -06:00
Bridget Kromhout
3a21cbc72b Makes more sense for "in person" chat 2018-03-05 14:37:10 -06:00
Bridget Kromhout
5438fca35a Attribute authorship 2018-03-05 14:34:41 -06:00
Bridget Kromhout
a09521ceb1 Changing Azure instance type 2018-03-05 13:44:02 -06:00
Jérôme Petazzoni
0d6501a926 Merge pull request #130 from atsaloli/patch-1
Two small fixes
2018-03-05 10:10:25 -08:00
Aleksey Tsalolikhin
c25f7a119b Fix very small typo -- remove extra "v" in "code" 2018-03-04 19:58:27 -08:00
Aleksey Tsalolikhin
1958c85a96 Fix noun plural tense (change "instructions" -> "instruction")
"An" means one. So "an instruction" rather than "an instructions".  (Small grammar fix.)
2018-03-04 19:56:03 -08:00
Jérôme Petazzoni
a7ba4418c6 Merge pull request #129 from bridgetkromhout/improve-directions
Improve directions
2018-03-03 19:52:15 -06:00
Bridget Kromhout
d6fcbb85e8 Improve directions 2018-03-03 18:44:56 -06:00
Jérôme Petazzoni
278fbf285a Merge pull request #128 from bridgetkromhout/cleanup
Cleanup
2018-03-03 14:39:56 -06:00
Bridget Kromhout
ca828343e4 Remove azure instances post-workshop. 2018-03-03 08:51:54 -06:00
Bridget Kromhout
5c663f9e09 Updating help output 2018-03-03 08:48:02 -06:00
Bridget Kromhout
9debd76816 Document kubetest 2018-03-03 08:44:58 -06:00
Bridget Kromhout
848679829d Removed -i and trailing space 2018-03-02 18:18:04 -06:00
Bridget Kromhout
6727007754 Missing variable 2018-03-02 18:11:32 -06:00
Jerome Petazzoni
03a563c172 Merge branch 'master' of github.com:jpetazzo/container.training 2018-03-02 14:17:54 -06:00
Jerome Petazzoni
cfbd54bebf Add hacky-backslashy kubetest command 2018-03-02 14:17:37 -06:00
Jérôme Petazzoni
7f1e9db0fa Missing curly brace 2018-03-02 13:08:48 -06:00
Jérôme Petazzoni
1367a30a11 Merge pull request #126 from bridgetkromhout/add-azure
Adding Azure examples
2018-03-02 12:46:02 -06:00
Bridget Kromhout
31b234ee3a Adding Azure examples 2018-03-02 12:42:55 -06:00
Jérôme Petazzoni
57dd5e295e Merge pull request #125 from bridgetkromhout/increase-timeouts
Increase timeouts
2018-03-01 17:43:29 -06:00
Bridget Kromhout
c188923f1a Increase timeouts 2018-03-01 17:39:51 -06:00
Jérôme Petazzoni
7a8716d38b Merge pull request #124 from bridgetkromhout/postprep
Postprep is now python
2018-03-01 17:17:04 -06:00
Bridget Kromhout
2e77c13297 Postprep is now python 2018-03-01 17:15:01 -06:00
Jerome Petazzoni
d5279d881d Add info about pre-built images 2018-03-01 15:13:39 -06:00
Jerome Petazzoni
34e9cc1944 Don't assume 5 nodes 2018-03-01 14:55:02 -06:00
Jerome Petazzoni
2a7498e30e A bit of rewording, and a couple of links about dashboard security 2018-03-01 14:51:00 -06:00
Jerome Petazzoni
4689d09e1f One typo and two minor tweaks 2018-03-01 14:18:48 -06:00
Jerome Petazzoni
b818a38307 Correctly report errors happening in functions
`trap ... ERR` does not automatically propagate to functions. Therefore,
Our fancy error-reporting mechanism did not catch errors happening in
functions; and we do most of the actual work in functions. The solution
is to `set -E` or `set -o errtrace`.
2018-03-01 13:56:08 -06:00
Jérôme Petazzoni
7e5d869472 Merge pull request #123 from bridgetkromhout/kube101
Kube101 & non-AWS
2018-03-01 13:23:04 -06:00
Jérôme Petazzoni
3eaf31fd48 Merge pull request #122 from bridgetkromhout/pssh-clarity
Pssh clarity
2018-03-01 13:21:05 -06:00
Bridget Kromhout
fe5e22f5ae How to set up non-AWS workshops 2018-02-28 21:45:36 -06:00
Bridget Kromhout
61da583080 Don't overwrite ip file if exists 2018-02-28 21:44:58 -06:00
Bridget Kromhout
94dfe1a0cd Adding sample file mentioned in README 2018-02-28 21:44:29 -06:00
Bridget Kromhout
412dbadafd Adding settings for kube101 2018-02-28 21:43:41 -06:00
Bridget Kromhout
8c5e4e0b09 Require pssh 2018-02-28 21:28:20 -06:00
Bridget Kromhout
2ac6072d80 Invoke as pssh 2018-02-28 21:26:17 -06:00
Jerome Petazzoni
ef4591c4fc Allow to override instance type (closes #39) 2018-02-28 13:45:08 -06:00
Jerome Petazzoni
22dfbab09b Minor formatting 2018-02-28 13:41:22 -06:00
Jérôme Petazzoni
37f595c480 Merge pull request #120 from bridgetkromhout/clarify-kube-public
Clarify kube-public; define kube-system
2018-02-27 17:42:11 -06:00
Bridget Kromhout
1fc951037d Slight clarification per request 2018-02-27 17:39:52 -06:00
Jérôme Petazzoni
affd46dd88 Merge pull request #121 from bridgetkromhout/obviate-https
Remove need for https in the workshop dashboard
2018-02-27 17:34:27 -06:00
Bridget Kromhout
cfaff3df04 Remove need for https in the workshop dashboard 2018-02-27 17:31:14 -06:00
Jérôme Petazzoni
ce2451971d Merge pull request #118 from bridgetkromhout/twice-the-steps
Proper attribution
2018-02-27 16:57:52 -06:00
Jérôme Petazzoni
8cf5d0efbd Merge pull request #119 from bridgetkromhout/naming-things
Naming things is hard; considering scope here
2018-02-27 16:40:40 -06:00
Bridget Kromhout
f61d61223d Clarify kube-public; define kube-system 2018-02-27 16:31:36 -06:00
Bridget Kromhout
6b6eb50f9a Naming things is hard; considering scope here 2018-02-27 15:26:43 -06:00
Jerome Petazzoni
89ab66335f ... and trim down kube half-day 2018-02-27 14:49:39 -06:00
Jerome Petazzoni
5bc4e95515 Clarify service discovery 2018-02-27 14:45:08 -06:00
Jerome Petazzoni
893f05e401 Move docker-compose logs to the composescale.md chapter 2018-02-27 14:38:41 -06:00
Bridget Kromhout
4abc8ce34c Proper attribution 2018-02-27 14:38:32 -06:00
Jérôme Petazzoni
34d2c610bf Merge pull request #117 from bridgetkromhout/self-deprecating-humor
Attributing humor so it doesn't sound negative
2018-02-27 14:06:58 -06:00
Jerome Petazzoni
1492a8a0bc Rephrase daemon set intro to fit even without the entropy spiel 2018-02-27 13:53:34 -06:00
Bridget Kromhout
388d616048 Attributing humor so it doesn't sound negative 2018-02-27 13:46:19 -06:00
Jerome Petazzoni
28589f5a83 Remove cluster-size specific reference 2018-02-27 13:40:52 -06:00
Jerome Petazzoni
e7a80f7bfb Merge branch 'master' of github.com:jpetazzo/container.training 2018-02-27 13:39:55 -06:00
Jerome Petazzoni
ea47e0ac05 Add link to brigade 2018-02-27 13:39:50 -06:00
Jérôme Petazzoni
09d204038f Merge pull request #116 from bridgetkromhout/versions-installed
Clarify that these are the installed versions
2018-02-27 13:36:40 -06:00
Jérôme Petazzoni
47cb0afac2 Merge pull request #115 from bridgetkromhout/any-cloud
More cloud-provider generic
2018-02-27 13:36:10 -06:00
Jerome Petazzoni
8e2e7f44d3 Break out 'scale things on a single node' section 2018-02-27 13:35:03 -06:00
Bridget Kromhout
8c7702deda Clarify that these are the installed versions
* "Brand new" is a moving target
2018-02-27 13:29:40 -06:00
Bridget Kromhout
bdc1ca01cd More cloud-provider generic 2018-02-27 13:27:11 -06:00
Jerome Petazzoni
dca58d6663 Merge Lucas awesome diagram 2018-02-27 12:22:02 -06:00
Jerome Petazzoni
a0cf4b97c0 Add Lucas' amazing diagram 2018-02-27 12:17:10 -06:00
Jerome Petazzoni
a1c239260f Add Lucas' amazing diagram 2018-02-27 12:17:02 -06:00
Jerome Petazzoni
a8a2cf54a5 Factor out links in separate files 2018-02-27 12:01:53 -06:00
Jerome Petazzoni
d5ba80da55 Replace 'five VMs' with 'a cluster of VMs' 2018-02-27 11:53:01 -06:00
Jerome Petazzoni
3f2da04763 CSS is hard but it's not an excuse 2018-02-27 09:44:32 -06:00
Jerome Petazzoni
e092f50645 Branch out intro/intro.md into per-workshop variants 2018-02-27 09:40:54 -06:00
Jérôme Petazzoni
7f698bd690 Merge pull request #114 from bridgetkromhout/master
Adding upcoming events
2018-02-27 09:28:27 -06:00
Bridget Kromhout
7fe04b9944 Adding upcoming events 2018-02-27 09:26:03 -06:00
Jerome Petazzoni
2671714df3 Move indexconf2018 to past workshops section 2018-02-27 09:11:09 -06:00
Jerome Petazzoni
630e275d99 Merge branch 'bridgetkromhout-master-updates' 2018-02-26 17:52:14 -06:00
Jerome Petazzoni
614f10432e Mostly reformatting so that slides are nice and tidy 2018-02-26 17:52:06 -06:00
Bridget Kromhout
223b5e152b Version updates 2018-02-26 16:56:45 -06:00
Bridget Kromhout
ec55cd2465 Including ACR as one of the cloud k8s offerings 2018-02-26 16:55:56 -06:00
Bridget Kromhout
c59510f921 Updates & clarifications 2018-02-26 16:54:41 -06:00
Bridget Kromhout
0f5f481213 Typo fix 2018-02-26 16:52:23 -06:00
Bridget Kromhout
b40fa45fd3 Clarifications 2018-02-26 16:50:31 -06:00
Bridget Kromhout
8faaf35da0 Clarify we didn't tag the v1 release 2018-02-26 16:48:52 -06:00
Bridget Kromhout
ce0f79af16 Updates & links for all cloud-provided k8s 2018-02-26 16:46:49 -06:00
Bridget Kromhout
faa420f9fd Clarify language and explain https use 2018-02-26 16:41:21 -06:00
Jerome Petazzoni
aab519177d Add indexconf2018 to index 2018-02-19 15:55:22 -08:00
Jerome Petazzoni
5116ad7c44 Use kubeadm token generate to simplify things a bit.
Thanks @rmb938 for the suggestion!

Closes #110.
2018-01-18 21:14:40 +01:00
Jerome Petazzoni
7305e911e5 Update for k8s 1.9 2018-01-10 17:12:49 +01:00
Jerome Petazzoni
b2f670acf6 Add error checking for AMI finder script 2018-01-10 16:48:04 +01:00
Jerome Petazzoni
dc040aa693 Make sleep interruptible; fix slide count 2017-12-23 19:38:32 +01:00
Jerome Petazzoni
9b7a8494b0 Fix logic to advance to next snippet 2017-12-23 18:49:42 +01:00
Jerome Petazzoni
ae6c1bb8eb Major UI refactor
Navigation now includes all slides and all snippets.
ENTER skips to the next snippet, or executes the
selected snippet.

More improvements to come: allow SPACE to navigate
step by step through slides and snippets, executing
the snippets.
2017-12-23 09:31:01 +01:00
Jerome Petazzoni
a9a4f0ea07 Create only one remote session 2017-12-23 05:06:30 +01:00
Jerome Petazzoni
68af5940e3 Script node3 setup as well 2017-12-23 05:00:22 +01:00
Jerome Petazzoni
9df5313da4 Remove spurious output from desktop integration 2017-12-22 23:15:21 +01:00
Jerome Petazzoni
ba3f00e64e Clear screen before showing UI 2017-12-22 23:11:11 +01:00
Jerome Petazzoni
4d7a6d5c70 Stupid typo 2017-12-22 23:03:48 +01:00
Jerome Petazzoni
aef833c3f5 Add pause before switching away from browser 2017-12-22 23:02:47 +01:00
Jerome Petazzoni
6f58fee29b Automatically open links in intro section 2017-12-22 22:54:08 +01:00
Jerome Petazzoni
dda09ddbcb slightly edit tmux commands 2017-12-22 22:49:53 +01:00
Jerome Petazzoni
8b13fe6eb4 fix formatting in PWD reference 2017-12-22 22:48:42 +01:00
Jerome Petazzoni
21f345a96a Improve open command 2017-12-22 22:42:41 +01:00
Jerome Petazzoni
eaa4dc63bf Instruct to use PWD in self-paced mode 2017-12-22 22:40:23 +01:00
Jerome Petazzoni
af5ea2188b More typos 2017-12-22 22:26:08 +01:00
Jerome Petazzoni
7f23a4c964 Fix minor typos 2017-12-22 22:24:37 +01:00
Jerome Petazzoni
345e04c956 Improve tmux detection logic and add instructions 2017-12-21 22:24:27 +01:00
Jerome Petazzoni
2a138102fc Add client address in pub/sub server 2017-12-21 05:53:24 +01:00
Jerome Petazzoni
ef5e8f00f8 Add script to remember myself of how to customize tmux status bar 2017-12-21 05:46:57 +01:00
Jerome Petazzoni
badb73a413 Slower pace for virtual typist 2017-12-21 05:45:38 +01:00
Jerome Petazzoni
2aced95c86 Improve UX for remote control 2017-12-21 05:40:35 +01:00
Jerome Petazzoni
720989e829 Add remote control of slide deck 2017-12-21 05:29:59 +01:00
Jerome Petazzoni
718031565e Exit gracefully if server is not running instead of waiting forever 2017-12-21 05:29:45 +01:00
Jerome Petazzoni
ec7b46b779 Add remote.js to workshop template and pub/sub server 2017-12-21 04:51:49 +01:00
Jerome Petazzoni
270c36b29a Add pub/sub server and CLI remote 2017-12-21 04:43:42 +01:00
Jerome Petazzoni
bc2eb53bb2 Python 3 compatibility 2017-12-21 04:33:35 +01:00
Jerome Petazzoni
afe7b8523c Move autotest to autopilot/ directory 2017-12-21 04:32:16 +01:00
Jérôme Petazzoni
a7743a4314 Update Engine version 2017-12-20 18:05:52 -06:00
Jérôme Petazzoni
ba74fdc841 Round of update for video content 2017-12-20 00:17:49 -06:00
Jérôme Petazzoni
41c047e12a Always start in interactive mode 2017-12-20 00:17:40 -06:00
Jérôme Petazzoni
f4fc055405 Add manifest for video content 2017-12-20 00:17:25 -06:00
Jérôme Petazzoni
2eb6fcfbf5 Add command to backtrack 1 slide 2017-12-18 18:46:24 -06:00
Jérôme Petazzoni
c665e1a2d6 httping only 3 requests is enough 2017-12-18 18:45:40 -06:00
Jérôme Petazzoni
bb7cdafe47 Comment out machine chapter 2017-12-18 18:39:33 -06:00
Jérôme Petazzoni
95fcfadb17 state.yml -> state.yaml to avoid collision with manifests 2017-12-18 18:39:17 -06:00
Jérôme Petazzoni
1ef47531c8 autotest: save all parameters in state.yml 2017-12-18 18:36:46 -06:00
Jérôme Petazzoni
9589b641b6 Another fix in CNC script 2017-12-18 18:35:57 -06:00
Jérôme Petazzoni
63463bda64 Merge branch 'master' of github.com:jpetazzo/container.training 2017-12-18 17:46:11 -06:00
Jérôme Petazzoni
b642412639 Clarify listen-addr and advertise-addr
Closes #108
2017-12-18 17:46:06 -06:00
Jérôme Petazzoni
21f9b73cb4 Update CNC deployment script + workshopctl deps 2017-12-18 17:45:29 -06:00
Jérôme Petazzoni
b73e5432f3 Merge pull request #109 from juliogomez/patch-6
curl is not installed in this step
2017-12-18 17:20:52 -06:00
Jérôme Petazzoni
de5cc9b0bf Merge branch 'master' of github.com:jpetazzo/container.training 2017-12-18 15:25:48 -06:00
Jérôme Petazzoni
08b38127d3 Clarify license for slides since they're not code 2017-12-18 15:25:41 -06:00
Julio
383804b7f1 curl is not installed in that step
curl was actually installed in a previous step, not here
2017-12-16 23:05:29 +01:00
Jérôme Petazzoni
20bf80910e Merge pull request #107 from juliogomez/patch-3
Fixing number of replicas per node
2017-12-16 09:26:18 -06:00
Jérôme Petazzoni
29a2014745 Merge pull request #106 from juliogomez/patch-2
Typo correction in detach mode?
2017-12-16 09:24:36 -06:00
Julio
40f6ee236f Fixing number of replicas per node
If 3 copies per node are 15, 4 copies per node should be 20.
2017-12-15 20:46:25 +01:00
Julio
5551cbd11f Typo correction in detach mode?
While you wrote:
`--detach=false` does not complete *faster*. It just *doesn't wait* for completion.
I think you actually meant:
`--detach=TRUE` does not complete *faster*. It just *doesn't wait* for completion.
2017-12-15 20:25:29 +01:00
Jérôme Petazzoni
9e84a05325 Merge pull request #105 from juliogomez/patch-1
Fixed missing image name (tomcat) in 'docker run' command
2017-12-14 15:33:24 -06:00
Julio
558e990907 Fixed missing image name in command 2017-12-14 22:15:29 +01:00
Jérôme Petazzoni
c2e88bb343 add qcon video 2017-12-07 14:28:46 -06:00
Jérôme Petazzoni
b7582397fe Add quote by not-Benjamin-Franklin 2017-12-04 18:19:04 -06:00
Jérôme Petazzoni
3e7b8615ab Move kube workshop to archives section 2017-12-04 13:57:17 -06:00
Jérôme Petazzoni
6f5d8c5372 Merge pull request #104 from gurayyildirim/patch-1
Kubernetes.io link fixed.
2017-11-24 11:31:07 -06:00
gurayyildirim
c116d75408 Kubernetes.io link fixed.
Kubernetes.io link had a wrong ']' mark which was causing a 404 from Kubernetes.io blog.
2017-11-24 02:45:49 +03:00
Jérôme Petazzoni
bb4ee4e77d Add helper script to setup CNC node 2017-11-20 17:04:38 -08:00
Jérôme Petazzoni
fc0e46988c Fix hint for ssh agent 2017-11-20 16:37:17 -08:00
Jérôme Petazzoni
c71b93c3a7 Add files to generate a CSV file with nodes 2017-11-20 16:35:25 -08:00
Jérôme Petazzoni
2c6b79c17d Add kube image to cards.html 2017-11-20 16:33:08 -08:00
Jérôme Petazzoni
f264838ec5 Update versions 2017-11-19 23:34:27 -08:00
Jérôme Petazzoni
54e7d10226 Add internal training 2017-11-19 17:45:24 -08:00
Jérôme Petazzoni
f8d3246005 Move QCON to 'done' section 2017-11-18 11:15:21 -08:00
Jérôme Petazzoni
7856e8c5f2 Put chat room in index 2017-11-16 23:32:12 -08:00
Jérôme Petazzoni
69bafe332f Update interstitials with self-hosted version 2017-11-16 23:29:37 -08:00
Jérôme Petazzoni
e2b24a20d2 Remove pixabay for now: 2017-11-16 08:46:47 -08:00
Jerome Petazzoni
d2d1771fd3 Better emoji support 2017-11-15 23:41:14 +01:00
Jérôme Petazzoni
6c5e3eb3f3 Update versions 2017-11-13 22:39:21 -08:00
Jérôme Petazzoni
d99dbd5878 Add first support to auto-open URLs 2017-11-12 22:47:07 -08:00
Jérôme Petazzoni
6d4894458a Add note about interstitials 2017-11-12 18:06:43 -08:00
Jérôme Petazzoni
bc367a1297 Simplify reference to PWD in intro slides 2017-11-12 17:45:15 -08:00
Jérôme Petazzoni
31d1074ee0 autotest: process single keypresses 2017-11-12 17:38:01 -08:00
Jérôme Petazzoni
cd18a87b8c Add self-paced kube manifest + small fixes in kube content 2017-11-12 17:37:40 -08:00
Jérôme Petazzoni
8279a3bce9 Add QCON slides 2017-11-10 23:01:17 -08:00
Jérôme Petazzoni
93524898cc Fix build script exit status 2017-11-10 22:57:06 -08:00
Jérôme Petazzoni
e9319060f6 Add pause images between chapters 2017-11-10 22:48:20 -08:00
Jérôme Petazzoni
4322478a4a A bunch of changes in there
- added self-paced manifest for intro workshop
- refactored intro content to work for all workshops
- fixed footnote CSS to work in all contexts
- intro+logistics content is good to go
2017-11-10 19:24:38 -08:00
Jérôme Petazzoni
00262c767e Move autotest.py to the slides/ directory 2017-11-10 13:31:00 -08:00
Jérôme Petazzoni
c8030e1500 Move autotest.py to the slides/ directory 2017-11-10 13:30:43 -08:00
Jérôme Petazzoni
3717b90444 Fix one long title 2017-11-10 13:08:19 -08:00
Jérôme Petazzoni
d003bdb765 Update --detach explanations 2017-11-10 13:06:52 -08:00
Jérôme Petazzoni
8b246ac334 Fix overflowing titles and slides in kube material 2017-11-10 12:55:13 -08:00
Jérôme Petazzoni
9df543a6bb Fix long titles and long slides in Swarm content 2017-11-09 19:58:55 -08:00
Jérôme Petazzoni
77befc1092 Improve appearance of code snippets 2017-11-09 19:58:35 -08:00
Jérôme Petazzoni
4417771315 Allow to automatically check slides + append check result at the end 2017-11-09 19:58:22 -08:00
Jérôme Petazzoni
04fa6ec1d8 Fix overflow in intro material 2017-11-09 16:43:56 -08:00
Jérôme Petazzoni
5e8bdcb1f6 Improve intro section 2017-11-09 14:27:30 -08:00
Jérôme Petazzoni
07d99763d3 Fix back-to-toc links 2017-11-09 13:41:29 -08:00
Jérôme Petazzoni
87a2051b24 Move one stray image 2017-11-09 13:36:21 -08:00
Jérôme Petazzoni
0eddc876f1 Add typist simulator 2017-11-08 23:24:43 -08:00
Jérôme Petazzoni
1a67a1397b Misc autotest improvements 2017-11-08 23:10:34 -08:00
Jérôme Petazzoni
dc6bf9d0cf Improve autotest by setting up tmux automatically 2017-11-08 23:10:25 -08:00
Jérôme Petazzoni
84f8bf007e Add spacer row 2017-11-08 21:28:22 -08:00
Jérôme Petazzoni
6a2a66c165 Improve local devel workflow; add notes about immutable infra 2017-11-08 18:49:40 -08:00
Jérôme Petazzoni
f491d559e3 Setting up an automated build 2017-11-08 14:32:04 -08:00
Jérôme Petazzoni
5d9bdc303c Fix title capitalization 2017-11-08 13:39:34 -08:00
Jérôme Petazzoni
f7f0ecddd4 Pushing to the hub 2017-11-08 13:31:22 -08:00
Jérôme Petazzoni
f0f03e2440 Rename other images 2017-11-08 11:04:51 -08:00
Jérôme Petazzoni
1f78264e9f Add helper script to rename assets 2017-11-08 10:41:56 -08:00
Jérôme Petazzoni
2aad5319f9 Rename title images for consistency 2017-11-08 10:41:46 -08:00
Jérôme Petazzoni
479b858398 Update use-cases and testimonials 2017-11-08 09:57:00 -08:00
Jérôme Petazzoni
34b8bfd1b2 Improve reporting for slide layout checker 2017-11-08 09:56:38 -08:00
Jérôme Petazzoni
408036b09c Implement checker for slides too high/too wide 2017-11-08 00:08:00 -08:00
Jérôme Petazzoni
a45ec1cb84 Reorg intro material a bit 2017-11-07 22:41:32 -08:00
Jérôme Petazzoni
8decf1852f Refactor build-tag-push
We now have two clean classes: btp-manual and btp-auto

Exclude one or the other depending on whether you want to
show the full process of building and pushing images, or
if you want to shortcut and use stack files directly.
2017-11-07 19:43:42 -08:00
Jérôme Petazzoni
350fac21f6 Add PyCon intro to docker 2017-11-07 18:41:48 -08:00
Jérôme Petazzoni
cedd386eee Add LISA16 recording 2017-11-07 18:29:08 -08:00
Jérôme Petazzoni
5751765d66 MOAR materials; smaller footer 2017-11-07 18:09:38 -08:00
Jérôme Petazzoni
7293c071bd CSS is hard, yo 2017-11-07 17:46:56 -08:00
Jérôme Petazzoni
98cf8f4f04 Rename manifests 2017-11-07 14:48:20 -08:00
Jérôme Petazzoni
c61ccd1c27 Uniformize selfpaced/halfday/fullday 2017-11-07 11:30:36 -08:00
Jérôme Petazzoni
6b3d0efa56 split out the 'declarative/imperative' explanation 2017-11-07 11:23:53 -08:00
Jérôme Petazzoni
164578f1c8 Images should be good now 2017-11-06 23:26:39 -08:00
Jérôme Petazzoni
938fe956cf Better closing links 2017-11-06 22:48:21 -08:00
Jérôme Petazzoni
b44d402c1d Tweak warning image 2017-11-06 22:43:50 -08:00
Jérôme Petazzoni
fbaa511813 add colophon 2017-11-06 22:17:54 -08:00
Jérôme Petazzoni
f000594c62 Refactored CSS 2017-11-06 22:15:12 -08:00
Jérôme Petazzoni
71ba94063e Add explanations when using Docker Machine or Toolbox
Thanks @jgarrouste for reminding me of this issue :-)
2017-11-06 17:05:34 -08:00
Jérôme Petazzoni
b025a8c966 add application metrics 2017-11-06 16:47:32 -08:00
Jérôme Petazzoni
c36aab132b Add prev/next navigation links + fix TOC backlinks 2017-11-06 16:39:02 -08:00
Jérôme Petazzoni
1e7a47ed37 Factor conclusion 2017-11-06 11:40:30 -08:00
Jérôme Petazzoni
87f544774e Factor pre-requirements 2017-11-06 11:26:16 -08:00
Jérôme Petazzoni
db9ee5f03a Factor title, toc, logistics, thankyou slides 2017-11-05 12:41:30 -08:00
Jérôme Petazzoni
d0f5d69157 Add some extra debug info in first slide 2017-11-05 11:52:27 -08:00
Jérôme Petazzoni
742c7a78bc Debug bar now shows manifest file 2017-11-05 10:22:44 -08:00
Jérôme Petazzoni
918d3a6c23 orchestration-workshop -> container.training (in slides) 2017-11-05 10:16:01 -08:00
Jérôme Petazzoni
1f9b304eec Update homepage 2017-11-05 10:08:19 -08:00
228 changed files with 14961 additions and 3835 deletions

5
.gitignore vendored
View File

@@ -7,4 +7,7 @@ prepare-vms/ips.pdf
prepare-vms/settings.yaml
prepare-vms/tags
slides/*.yml.html
autotest/nextstep
slides/autopilot/state.yaml
slides/index.html
slides/past.html
node_modules

24
CHECKLIST.md Normal file
View File

@@ -0,0 +1,24 @@
Checklist to use when delivering a workshop
Authored by Jérôme; additions by Bridget
- [ ] Create event-named branch (such as `conferenceYYYY`) in the [main repo](https://github.com/jpetazzo/container.training/)
- [ ] Create file `slides/_redirects` containing a link to the desired tutorial: `/ /kube-halfday.yml.html 200`
- [ ] Push local branch to GitHub and merge into main repo
- [ ] [Netlify setup](https://app.netlify.com/sites/container-training/settings/domain): create subdomain for event-named branch
- [ ] Add link to event-named branch to [container.training front page](https://github.com/jpetazzo/container.training/blob/master/slides/index.html)
- [ ] Update the slides that says which versions we are using for [kube](https://github.com/jpetazzo/container.training/blob/master/slides/kube/versions-k8s.md) or [swarm](https://github.com/jpetazzo/container.training/blob/master/slides/swarm/versions.md) workshops
- [ ] Update the version of Compose and Machine in [settings](https://github.com/jpetazzo/container.training/tree/master/prepare-vms/settings)
- [ ] (optional) Create chatroom
- [ ] (optional) Set chatroom in YML ([kube half-day example](https://github.com/jpetazzo/container.training/blob/master/slides/kube-halfday.yml#L6-L8)) and deploy
- [ ] (optional) Put chat link on [container.training front page](https://github.com/jpetazzo/container.training/blob/master/slides/index.html)
- [ ] How many VMs do we need? Check with event organizers ahead of time
- [ ] Provision VMs (slightly more than we think we'll need)
- [ ] Change password on presenter's VMs (to forestall any hijinx)
- [ ] Onsite: walk the room to count seats, check power supplies, lectern, A/V setup
- [ ] Print cards
- [ ] Cut cards
- [ ] Last-minute merge from master
- [ ] Check that all looks good
- [ ] DELIVER!
- [ ] Shut down VMs
- [ ] Update index.html to remove chat link and move session to past things

19
LICENSE
View File

@@ -1,13 +1,12 @@
Copyright 2015 Jérôme Petazzoni
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
The code in this repository is licensed under the Apache License
Version 2.0. You may obtain a copy of this license at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The instructions and slides in this repository (e.g. the files
with extension .md and .yml in the "slides" subdirectory) are
under the Creative Commons Attribution 4.0 International Public
License. You may obtain a copy of this license at:
https://creativecommons.org/licenses/by/4.0/legalcode

View File

@@ -39,14 +39,16 @@ your own tutorials.
All these materials have been gathered in a single repository
because they have a few things in common:
- a [build system](slides/) generating HTML slides from
Markdown source files;
- some [common slides](slides/common/) that are re-used
(and updated) identically between different decks;
- a [build system](slides/) generating HTML slides from
Markdown source files;
- a [semi-automated test harness](slides/autopilot/) to check
that the exercises and examples provided work properly;
- a [PhantomJS script](slides/slidechecker.js) to check
that the slides look good and don't have formatting issues;
- [deployment scripts](prepare-vms/) to start training
VMs in bulk;
- a [semi-automated test harness](autotest/) to check
that the exercises and examples provided work properly;
- a fancy pipeline powered by
[Netlify](https://www.netlify.com/) and continuously
deploying `master` to http://container.training/.
@@ -74,9 +76,6 @@ a few other contributors. It is actively maintained.
## Repository structure
- [autotest](autotest/)
- Semi-automated testing system to check that all the exercises
in the slides work properly.
- [bin](bin/)
- A few helper scripts that you can safely ignore for now.
- [dockercoins](dockercoins/)
@@ -248,6 +247,17 @@ content but you also know to skip during presentation.
- Last 15-30 minutes is for stateful services, DAB files, and questions.
### Pre-built images
There are pre-built images for the 4 components of the DockerCoins demo app: `dockercoins/hasher:v0.1`, `dockercoins/rng:v0.1`, `dockercoins/webui:v0.1`, and `dockercoins/worker:v0.1`. They correspond to the code in this repository.
There are also three variants, for demo purposes:
- `dockercoins/rng:v0.2` is broken (the server won't even start),
- `dockercoins/webui:v0.2` has bigger font on the Y axis and a green graph (instead of blue),
- `dockercoins/worker:v0.2` is 11x slower than `v0.1`.
## Past events
Since its inception, this workshop has been delivered dozens of times,
@@ -282,15 +292,31 @@ If there is a bug and you can't even reproduce it:
sorry. It is probably an Heisenbug. We can't act on it
until it's reproducible, alas.
If you have attended this workshop and have feedback,
or if you want somebody to deliver that workshop at your
conference or for your company: you can contact one of us!
- jerome at docker dot com
# “Please teach us!”
If you have attended one of these workshops, and want
your team or organization to attend a similar one, you
can look at the list of upcoming events on
http://container.training/.
You are also welcome to reuse these materials to run
your own workshop, for your team or even at a meetup
or conference. In that case, you might enjoy watching
[Bridget Kromhout's talk at KubeCon 2018 Europe](
https://www.youtube.com/watch?v=mYsp_cGY2O0), explaining
precisely how to run such a workshop yourself.
Finally, you can also contact the following persons,
who are experienced speakers, are familiar with the
material, and are available to deliver these workshops
at your conference or for your company:
- jerome dot petazzoni at gmail dot com
- bret at bretfisher dot com
If you are willing and able to deliver such workshops,
feel free to submit a PR to add your name to that list!
(If you are willing and able to deliver such workshops,
feel free to submit a PR to add your name to that list!)
**Thank you!**

View File

@@ -1,229 +0,0 @@
#!/usr/bin/env python
import uuid
import logging
import os
import re
import subprocess
import sys
import time
import uuid
logging.basicConfig(level=logging.DEBUG)
TIMEOUT = 60 # 1 minute
def hrule():
return "="*int(subprocess.check_output(["tput", "cols"]))
# A "snippet" is something that the user is supposed to do in the workshop.
# Most of the "snippets" are shell commands.
# Some of them can be key strokes or other actions.
# In the markdown source, they are the code sections (identified by triple-
# quotes) within .exercise[] sections.
class Snippet(object):
def __init__(self, slide, content):
self.slide = slide
self.content = content
self.actions = []
def __str__(self):
return self.content
class Slide(object):
current_slide = 0
def __init__(self, content):
Slide.current_slide += 1
self.number = Slide.current_slide
# Remove commented-out slides
# (remark.js considers ??? to be the separator for speaker notes)
content = re.split("\n\?\?\?\n", content)[0]
self.content = content
self.snippets = []
exercises = re.findall("\.exercise\[(.*)\]", content, re.DOTALL)
for exercise in exercises:
if "```" in exercise:
for snippet in exercise.split("```")[1::2]:
self.snippets.append(Snippet(self, snippet))
else:
logging.warning("Exercise on slide {} does not have any ``` snippet."
.format(self.number))
self.debug()
def __str__(self):
text = self.content
for snippet in self.snippets:
text = text.replace(snippet.content, ansi("7")(snippet.content))
return text
def debug(self):
logging.debug("\n{}\n{}\n{}".format(hrule(), self.content, hrule()))
def ansi(code):
return lambda s: "\x1b[{}m{}\x1b[0m".format(code, s)
def wait_for_string(s):
logging.debug("Waiting for string: {}".format(s))
deadline = time.time() + TIMEOUT
while time.time() < deadline:
output = capture_pane()
if s in output:
return
time.sleep(1)
raise Exception("Timed out while waiting for {}!".format(s))
def wait_for_prompt():
logging.debug("Waiting for prompt.")
deadline = time.time() + TIMEOUT
while time.time() < deadline:
output = capture_pane()
# If we are not at the bottom of the screen, there will be a bunch of extra \n's
output = output.rstrip('\n')
if output[-2:] == "\n$":
return
time.sleep(1)
raise Exception("Timed out while waiting for prompt!")
def check_exit_status():
token = uuid.uuid4().hex
data = "echo {} $?\n".format(token)
logging.debug("Sending {!r} to get exit status.".format(data))
send_keys(data)
time.sleep(0.5)
wait_for_prompt()
screen = capture_pane()
status = re.findall("\n{} ([0-9]+)\n".format(token), screen, re.MULTILINE)
logging.debug("Got exit status: {}.".format(status))
if len(status) == 0:
raise Exception("Couldn't retrieve status code {}. Timed out?".format(token))
if len(status) > 1:
raise Exception("More than one status code {}. I'm seeing double! Shoot them both.".format(token))
code = int(status[0])
if code != 0:
raise Exception("Non-zero exit status: {}.".format(code))
# Otherwise just return peacefully.
slides = []
content = open(sys.argv[1]).read()
for slide in re.split("\n---?\n", content):
slides.append(Slide(slide))
actions = []
for slide in slides:
for snippet in slide.snippets:
content = snippet.content
# Extract the "method" (e.g. bash, keys, ...)
# On multi-line snippets, the method is alone on the first line
# On single-line snippets, the data follows the method immediately
if '\n' in content:
method, data = content.split('\n', 1)
else:
method, data = content.split(' ', 1)
actions.append((slide, snippet, method, data))
def send_keys(data):
subprocess.check_call(["tmux", "send-keys", data])
def capture_pane():
return subprocess.check_output(["tmux", "capture-pane", "-p"])
try:
i = int(open("nextstep").read())
logging.info("Loaded next step ({}) from file.".format(i))
except Exception as e:
logging.warning("Could not read nextstep file ({}), initializing to 0.".format(e))
i = 0
interactive = True
while i < len(actions):
with open("nextstep", "w") as f:
f.write(str(i))
slide, snippet, method, data = actions[i]
# Remove extra spaces (we don't want them in the terminal) and carriage returns
data = data.strip()
print(hrule())
print(slide.content.replace(snippet.content, ansi(7)(snippet.content)))
print(hrule())
if interactive:
print("[{}/{}] Shall we execute that snippet above?".format(i, len(actions)))
print("(ENTER to execute, 'c' to continue until next error, N to jump to step #N)")
command = raw_input("> ")
else:
command = ""
# For now, remove the `highlighted` sections
# (Make sure to use $() in shell snippets!)
if '`' in data:
logging.info("Stripping ` from snippet.")
data = data.replace('`', '')
if command == "c":
# continue until next timeout
interactive = False
elif command.isdigit():
i = int(command)
elif command == "":
logging.info("Running with method {}: {}".format(method, data))
if method == "keys":
send_keys(data)
elif method == "bash":
# Make sure that we're ready
wait_for_prompt()
# Strip leading spaces
data = re.sub("\n +", "\n", data)
# Add "RETURN" at the end of the command :)
data += "\n"
# Send command
send_keys(data)
# Force a short sleep to avoid race condition
time.sleep(0.5)
_, _, next_method, next_data = actions[i+1]
if next_method == "wait":
wait_for_string(next_data)
else:
wait_for_prompt()
# Verify return code FIXME should be optional
check_exit_status()
elif method == "copypaste":
screen = capture_pane()
matches = re.findall(data, screen, flags=re.DOTALL)
if len(matches) == 0:
raise Exception("Could not find regex {} in output.".format(data))
# Arbitrarily get the most recent match
match = matches[-1]
# Remove line breaks (like a screen copy paste would do)
match = match.replace('\n', '')
send_keys(match + '\n')
# FIXME: we should factor out the "bash" method
wait_for_prompt()
check_exit_status()
else:
logging.warning("Unknown method {}: {!r}".format(method, data))
i += 1
else:
i += 1
logging.warning("Unknown command {}, skipping to next step.".format(command))
# Reset slide counter
with open("nextstep", "w") as f:
f.write(str(0))

View File

@@ -1,15 +1,22 @@
# Trainer tools to create and prepare VMs for Docker workshops on AWS
# Trainer tools to create and prepare VMs for Docker workshops on AWS or Azure
## Prerequisites
- [Docker](https://docs.docker.com/engine/installation/)
- [Docker Compose](https://docs.docker.com/compose/install/)
- [Parallel SSH](https://code.google.com/archive/p/parallel-ssh/) (on a Mac: `brew install pssh`) - the configuration scripts require this
And if you want to generate printable cards:
- [pyyaml](https://pypi.python.org/pypi/PyYAML) (on a Mac: `brew install pyyaml`)
- [jinja2](https://pypi.python.org/pypi/Jinja2) (on a Mac: `brew install jinja2`)
## General Workflow
- fork/clone repo
- set required environment variables for AWS
- set required environment variables
- create your own setting file from `settings/example.yaml`
- if necessary, increase allowed open files: `ulimit -Sn 10000`
- run `./workshopctl` commands to create instances, install docker, setup each users environment in node1, other management tasks
- run `./workshopctl cards` command to generate PDF for printing handouts of each users host IP's and login info
@@ -35,6 +42,16 @@ The Docker Compose file here is used to build a image with all the dependencies
- `AWS_SECRET_ACCESS_KEY`
- `AWS_DEFAULT_REGION`
If you're not using AWS, set these to placeholder values:
```
export AWS_ACCESS_KEY_ID="foo"
export AWS_SECRET_ACCESS_KEY="foo"
export AWS_DEFAULT_REGION="foo"
```
If you don't have the `aws` CLI installed, you will get a warning that it's a missing dependency. If you're not using AWS you can ignore this.
### Update/copy `settings/example.yaml`
Then pass `settings/YOUR_WORKSHOP_NAME-settings.yaml` as an argument to `./workshopctl deploy`, `./workshopctl cards`, etc.
@@ -48,6 +65,7 @@ workshopctl - the orchestration workshop swiss army knife
Commands:
ami Show the AMI that will be used for deployment
amis List Ubuntu AMIs in the current region
build Build the Docker image to run this program in a container
cards Generate ready-to-print cards for a batch of VMs
deploy Install Docker on a bunch of running VMs
ec2quotas Check our EC2 quotas (max instances)
@@ -55,6 +73,7 @@ help Show available commands
ids List the instance IDs belonging to a given tag or token
ips List the IP addresses of the VMs for a given tag or token
kube Setup kubernetes clusters with kubeadm (must be run AFTER deploy)
kubetest Check that all notes are reporting as Ready
list List available batches in the current region
opensg Open the default security group to ALL ingress traffic
pull_images Pre-pull a bunch of Docker images
@@ -63,6 +82,7 @@ start Start a batch of VMs
status List instance status for a given batch
stop Stop (terminate, shutdown, kill, remove, destroy...) instances
test Run tests (pre-flight checks) on a batch of VMs
wrap Run this program in a container
```
### Summary of What `./workshopctl` Does For You
@@ -75,19 +95,80 @@ test Run tests (pre-flight checks) on a batch of VMs
- During `start` it will add your default local SSH key to all instances under the `ubuntu` user.
- During `deploy` it will create the `docker` user with password `training`, which is printing on the cards for students. For now, this is hard coded.
### Example Steps to Launch a Batch of Instances for a Workshop
### Example Steps to Launch a Batch of AWS Instances for a Workshop
- Run `./workshopctl start N` Creates `N` EC2 instances
- Your local SSH key will be synced to instances under `ubuntu` user
- AWS instances will be created and tagged based on date, and IP's stored in `prepare-vms/tags/`
- Run `./workshopctl deploy TAG settings/somefile.yaml` to run `scripts/postprep.rc` via parallel-ssh
- Run `./workshopctl deploy TAG settings/somefile.yaml` to run `lib/postprep.py` via parallel-ssh
- If it errors or times out, you should be able to rerun
- Requires good connection to run all the parallel SSH connections, up to 100 parallel (ProTip: create dedicated management instance in same AWS region where you run all these utils from)
- Run `./workshopctl pull-images TAG` to pre-pull a bunch of Docker images to the instances
- Run `./workshopctl pull_images TAG` to pre-pull a bunch of Docker images to the instances
- Run `./workshopctl cards TAG settings/somefile.yaml` generates PDF/HTML files to print and cut and hand out to students
- *Have a great workshop*
- Run `./workshopctl stop TAG` to terminate instances.
### Example Steps to Launch Azure Instances
- Install the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) and authenticate with a valid account
- Customize `azuredeploy.parameters.json`
- Required:
- Provide the SSH public key you plan to use for instance configuration
- Optional:
- Choose a name for the workshop (default is "workshop")
- Choose the number of instances (default is 3)
- Customize the desired instance size (default is Standard_D1_v2)
- Launch instances with your chosen resource group name and your preferred region; the examples are "workshop" and "eastus":
```
az group create --name workshop --location eastus
az group deployment create --resource-group workshop --template-file azuredeploy.json --parameters @azuredeploy.parameters.json
```
The `az group deployment create` command can take several minutes and will only say `- Running ..` until it completes, unless you increase the verbosity with `--verbose` or `--debug`.
To display the IPs of the instances you've launched:
```
az vm list-ip-addresses --resource-group workshop --output table
```
If you want to put the IPs into `prepare-vms/tags/<tag>/ips.txt` for a tag of "myworkshop":
1) If you haven't yet installed `jq` and/or created your event's tags directory in `prepare-vms`:
```
brew install jq
mkdir -p tags/myworkshop
```
2) And then generate the IP list:
```
az vm list-ip-addresses --resource-group workshop --output json | jq -r '.[].virtualMachine.network.publicIpAddresses[].ipAddress' > tags/myworkshop/ips.txt
```
After the workshop is over, remove the instances:
```
az group delete --resource-group workshop
```
### Example Steps to Configure Instances from a non-AWS Source
- Launch instances via your preferred method. You'll need to get the instance IPs and be able to ssh into them.
- Set placeholder values for [AWS environment variable settings](#required-environment-variables).
- Choose a tag. It could be an event name, datestamp, etc. Ensure you have created a directory for your tag: `prepare-vms/tags/<tag>/`
- If you have not already generated a file with the IPs to be configured:
- The file should be named `prepare-vms/tags/<tag>/ips.txt`
- Format is one IP per line, no other info needed.
- Ensure the settings file is as desired (especially the number of nodes): `prepare-vms/settings/kube101.yaml`
- For a tag called `myworkshop`, configure instances: `workshopctl deploy myworkshop settings/kube101.yaml`
- Optionally, configure Kubernetes clusters of the size in the settings: `workshopctl kube myworkshop`
- Optionally, test your Kubernetes clusters. They may take a little time to become ready: `workshopctl kubetest myworkshop`
- Generate cards to print and hand out: `workshopctl cards myworkshop settings/kube101.yaml`
- Print the cards file: `prepare-vms/tags/myworkshop/ips.html`
## Other Tools
### Deploying your SSH key to all the machines
@@ -97,13 +178,6 @@ test Run tests (pre-flight checks) on a batch of VMs
- Run `pcopykey`.
### Installing extra packages
- Source `postprep.rc`.
(This will install a few extra packages, add entries to
/etc/hosts, generate SSH keys, and deploy them on all hosts.)
## Even More Details
#### Sync of SSH keys
@@ -132,16 +206,20 @@ Instances can be deployed manually using the `deploy` command:
$ ./workshopctl deploy TAG settings/somefile.yaml
The `postprep.rc` file will be copied via parallel-ssh to all of the VMs and executed.
The `postprep.py` file will be copied via parallel-ssh to all of the VMs and executed.
#### Pre-pull images
$ ./workshopctl pull-images TAG
$ ./workshopctl pull_images TAG
#### Generate cards
$ ./workshopctl cards TAG settings/somefile.yaml
If you want to generate both HTML and PDF cards, install [wkhtmltopdf](https://wkhtmltopdf.org/downloads.html); without that installed, only HTML cards will be generated.
If you don't have `wkhtmltopdf` installed, you will get a warning that it is a missing dependency. If you plan to just print the HTML cards, you can ignore this.
#### List tags
$ ./workshopctl list

View File

@@ -0,0 +1,250 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workshopName": {
"type": "string",
"defaultValue": "workshop",
"metadata": {
"description": "Workshop name."
}
},
"vmPrefix": {
"type": "string",
"defaultValue": "node",
"metadata": {
"description": "Prefix for VM names."
}
},
"numberOfInstances": {
"type": "int",
"defaultValue": 3,
"metadata": {
"description": "Number of VMs to create."
}
},
"adminUsername": {
"type": "string",
"defaultValue": "ubuntu",
"metadata": {
"description": "Admin username for VMs."
}
},
"sshKeyData": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "SSH rsa public key file as a string."
}
},
"imagePublisher": {
"type": "string",
"defaultValue": "Canonical",
"metadata": {
"description": "OS image publisher; default Canonical."
}
},
"imageOffer": {
"type": "string",
"defaultValue": "UbuntuServer",
"metadata": {
"description": "The name of the image offer. The default is Ubuntu"
}
},
"imageSKU": {
"type": "string",
"defaultValue": "16.04-LTS",
"metadata": {
"description": "Version of the image. The default is 16.04-LTS"
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_D1_v2",
"metadata": {
"description": "VM Size."
}
}
},
"variables": {
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnet1Ref": "[concat(variables('vnetID'),'/subnets/',variables('subnet1Name'))]",
"vmName": "[parameters('vmPrefix')]",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
"publicIPAddressName": "PublicIP",
"publicIPAddressType": "Dynamic",
"virtualNetworkName": "MyVNET",
"netSecurityGroup": "MyNSG",
"addressPrefix": "10.0.0.0/16",
"subnet1Name": "subnet-1",
"subnet1Prefix": "10.0.0.0/24",
"nicName": "myVMNic"
},
"resources": [
{
"apiVersion": "2017-11-01",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[concat(variables('publicIPAddressName'),copyIndex(1))]",
"location": "[resourceGroup().location]",
"copy": {
"name": "publicIPLoop",
"count": "[parameters('numberOfInstances')]"
},
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
},
"tags": {
"workshop": "[parameters('workshopName')]"
}
},
{
"apiVersion": "2017-11-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('netSecurityGroup'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnet1Name')]",
"properties": {
"addressPrefix": "[variables('subnet1Prefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('netSecurityGroup'))]"
}
}
}
]
},
"tags": {
"workshop": "[parameters('workshopName')]"
}
},
{
"apiVersion": "2017-11-01",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(variables('nicName'),copyIndex(1))]",
"location": "[resourceGroup().location]",
"copy": {
"name": "nicLoop",
"count": "[parameters('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'),copyIndex(1))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyIndex(1)))]"
},
"subnet": {
"id": "[variables('subnet1Ref')]"
}
}
}
]
},
"tags": {
"workshop": "[parameters('workshopName')]"
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(variables('vmName'),copyIndex(1))]",
"location": "[resourceGroup().location]",
"copy": {
"name": "vmLoop",
"count": "[parameters('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), copyIndex(1))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"osProfile": {
"computerName": "[concat(variables('vmName'),copyIndex(1))]",
"adminUsername": "[parameters('adminUsername')]",
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[variables('sshKeyPath')]",
"keyData": "[parameters('sshKeyData')]"
}
]
}
}
},
"storageProfile": {
"osDisk": {
"createOption": "FromImage"
},
"imageReference": {
"publisher": "[parameters('imagePublisher')]",
"offer": "[parameters('imageOffer')]",
"sku": "[parameters('imageSKU')]",
"version": "latest"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'),copyIndex(1)))]"
}
]
}
},
"tags": {
"workshop": "[parameters('workshopName')]"
}
},
{
"apiVersion": "2017-11-01",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('netSecurityGroup')]",
"location": "[resourceGroup().location]",
"tags": {
"workshop": "[parameters('workshopName')]"
},
"properties": {
"securityRules": [
{
"name": "default-open-ports",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 1000,
"direction": "Inbound"
}
}
]
}
}
],
"outputs": {
"resourceID": {
"type": "string",
"value": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'),'1'))]"
}
}
}

View File

@@ -0,0 +1,18 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sshKeyData": {
"value": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXTIl/M9oeSlcsC5Rfe+nZr4Jc4sl200pSw2lpdxlZ3xzeP15NgSSMJnigUrKUXHfqRQ+2wiPxEf0Odz2GdvmXvR0xodayoOQsO24AoERjeSBXCwqITsfp1bGKzMb30/3ojRBo6LBR6r1+lzJYnNCGkT+IQwLzRIpm0LCNz1j08PUI2aZ04+mcDANvHuN/hwi/THbLLp6SNWN43m9r02RcC6xlCNEhJi4wk4VzMzVbSv9RlLGST2ocbUHwmQ2k9OUmpzoOx73aQi9XNnEaFh2w/eIdXM75VtkT3mRryyykg9y0/hH8/MVmIuRIdzxHQqlm++DLXVH5Ctw6a4kS+ki7 workshop"
},
"workshopName": {
"value": "workshop"
},
"numberOfInstances": {
"value": 3
},
"vmSize": {
"value": "Standard_D1_v2"
}
}
}

View File

@@ -12,7 +12,9 @@
{%- set cluster_or_machine = "cluster" -%}
{%- set this_or_each = "each" -%}
{%- set machine_is_or_machines_are = "machines are" -%}
{%- set image_src = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%}
{%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%}
{%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%}
{%- set image_src = image_src_swarm -%}
{%- endif -%}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>

5
prepare-vms/clusters.csv Normal file
View File

@@ -0,0 +1,5 @@
Put your initials in the first column to "claim" a cluster.
Initials{% for node in clusters[0] %} node{{ loop.index }}{% endfor %}
{% for cluster in clusters -%}
{%- for node in cluster %} {{ node|trim }}{% endfor %}
{% endfor %}
Can't render this file because it contains an unexpected character in line 1 and column 42.

21
prepare-vms/cncsetup.sh Normal file
View File

@@ -0,0 +1,21 @@
#!/bin/sh
if [ $(whoami) != ubuntu ]; then
echo "This script should be executed on a freshly deployed node,"
echo "with the 'ubuntu' user. Aborting."
exit 1
fi
if id docker; then
sudo userdel -r docker
fi
pip install --user awscli jinja2 pdfkit
sudo apt-get install -y wkhtmltopdf xvfb
tmux new-session \; send-keys "
[ -f ~/.ssh/id_rsa ] || ssh-keygen
eval \$(ssh-agent)
ssh-add
Xvfb :0 &
export DISPLAY=:0
mkdir -p ~/www
sudo docker run -d -p 80:80 -v \$HOME/www:/usr/share/nginx/html nginx
"

View File

@@ -7,7 +7,6 @@ services:
working_dir: /root/prepare-vms
volumes:
- $HOME/.aws/:/root/.aws/
- /etc/localtime:/etc/localtime:ro
- $SSH_AUTH_SOCK:$SSH_AUTH_SOCK
- $PWD/:/root/prepare-vms/
environment:
@@ -15,5 +14,6 @@ services:
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION}
AWS_INSTANCE_TYPE: ${AWS_INSTANCE_TYPE}
USER: ${USER}
entrypoint: /root/prepare-vms/workshopctl

View File

@@ -2,7 +2,7 @@
_ERR() {
error "Command $BASH_COMMAND failed (exit status: $?)"
}
set -e
set -eE
trap _ERR ERR
die() {

View File

@@ -39,13 +39,16 @@ _cmd_cards() {
need_tag $TAG
need_settings $SETTINGS
aws_get_instance_ips_by_tag $TAG >tags/$TAG/ips.txt
# If you're not using AWS, populate the ips.txt file manually
if [ ! -f tags/$TAG/ips.txt ]; then
aws_get_instance_ips_by_tag $TAG >tags/$TAG/ips.txt
fi
# Remove symlinks to old cards
rm -f ips.html ips.pdf
# This will generate two files in the base dir: ips.pdf and ips.html
python lib/ips-txt-to-html.py $SETTINGS
lib/ips-txt-to-html.py $SETTINGS
for f in ips.html ips.pdf; do
# Remove old versions of cards if they exist
@@ -124,27 +127,21 @@ _cmd kube "Setup kubernetes clusters with kubeadm (must be run AFTER deploy)"
_cmd_kube() {
# Install packages
pssh "
pssh --timeout 200 "
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg |
sudo apt-key add - &&
echo deb http://apt.kubernetes.io/ kubernetes-xenial main |
sudo tee /etc/apt/sources.list.d/kubernetes.list"
pssh "
pssh --timeout 200 "
sudo apt-get update -q &&
sudo apt-get install -qy kubelet kubeadm kubectl
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl"
# Work around https://github.com/kubernetes/kubernetes/issues/53356
pssh "
if [ ! -f /etc/kubernetes/kubelet.conf ]; then
sudo systemctl stop kubelet
sudo rm -rf /var/lib/kubelet/pki
fi"
# Initialize kube master
pssh "
pssh --timeout 200 "
if grep -q node1 /tmp/node && [ ! -f /etc/kubernetes/admin.conf ]; then
sudo kubeadm init
kubeadm token generate > /tmp/token
sudo kubeadm init --token \$(cat /tmp/token)
fi"
# Put kubeconfig in ubuntu's and docker's accounts
@@ -157,15 +154,6 @@ _cmd_kube() {
sudo chown -R docker /home/docker/.kube
fi"
# Get bootstrap token
pssh "
if grep -q node1 /tmp/node; then
TOKEN_NAME=\$(kubectl -n kube-system get secret -o name | grep bootstrap-token)
TOKEN_ID=\$(kubectl -n kube-system get \$TOKEN_NAME -o go-template --template '{{ index .data \"token-id\" }}' | base64 -d)
TOKEN_SECRET=\$(kubectl -n kube-system get \$TOKEN_NAME -o go-template --template '{{ index .data \"token-secret\" }}' | base64 -d)
echo \$TOKEN_ID.\$TOKEN_SECRET >/tmp/token
fi"
# Install weave as the pod network
pssh "
if grep -q node1 /tmp/node; then
@@ -174,15 +162,30 @@ _cmd_kube() {
fi"
# Join the other nodes to the cluster
pssh "
pssh --timeout 200 "
if ! grep -q node1 /tmp/node && [ ! -f /etc/kubernetes/kubelet.conf ]; then
TOKEN=\$(ssh -o StrictHostKeyChecking=no node1 cat /tmp/token)
sudo kubeadm join --token \$TOKEN node1:6443
sudo kubeadm join --discovery-token-unsafe-skip-ca-verification --token \$TOKEN node1:6443
fi"
sep "Done"
}
_cmd kubetest "Check that all notes are reporting as Ready"
_cmd_kubetest() {
# There are way too many backslashes in the command below.
# Feel free to make that better ♥
pssh "
set -e
[ -f /tmp/node ]
if grep -q node1 /tmp/node; then
which kubectl
for NODE in \$(awk /\ node/\ {print\ \\\$2} /etc/hosts); do
echo \$NODE ; kubectl get nodes | grep -w \$NODE | grep -w Ready
done
fi"
}
_cmd ids "List the instance IDs belonging to a given tag or token"
_cmd_ids() {
TAG=$1
@@ -280,6 +283,9 @@ _cmd_start() {
key_name=$(sync_keys)
AMI=$(_cmd_ami) # Retrieve the AWS image ID
if [ -z "$AMI" ]; then
die "I could not find which AMI to use in this region. Try another region?"
fi
TOKEN=$(get_token) # generate a timestamp token for this batch of VMs
AWS_KEY_NAME=$(make_key_name)
@@ -292,7 +298,7 @@ _cmd_start() {
result=$(aws ec2 run-instances \
--key-name $AWS_KEY_NAME \
--count $COUNT \
--instance-type t2.medium \
--instance-type ${AWS_INSTANCE_TYPE-t2.medium} \
--client-token $TOKEN \
--image-id $AMI)
reservation_id=$(echo "$result" | head -1 | awk '{print $2}')
@@ -387,9 +393,23 @@ pull_tag() {
ubuntu:latest \
fedora:latest \
centos:latest \
elasticsearch:2 \
postgres \
redis \
alpine \
registry \
nicolaka/netshoot \
jpetazzo/trainingwheels \
golang \
training/namer \
dockercoins/hasher \
dockercoins/rng \
dockercoins/webui \
dockercoins/worker \
logstash \
prom/node-exporter \
google/cadvisor \
dockersamples/visualizer \
nathanleclaire/redisonrails; do
sudo -u docker docker pull $I
done'
@@ -430,6 +450,7 @@ tag_is_reachable() {
}
test_tag() {
TAG=$1
ips_file=tags/$TAG/ips.txt
info "Picking a random IP address in $ips_file to run tests."
n=$((1 + $RANDOM % $(wc -l <$ips_file)))

View File

@@ -45,7 +45,7 @@ def system(cmd):
# On EC2, the ephemeral disk might be mounted on /mnt.
# If /mnt is a mountpoint, place Docker workspace on it.
system("if mountpoint -q /mnt; then sudo mkdir /mnt/docker && sudo ln -s /mnt/docker /var/lib/docker; fi")
system("if mountpoint -q /mnt; then sudo mkdir -p /mnt/docker && sudo ln -sfn /mnt/docker /var/lib/docker; fi")
# Put our public IP in /tmp/ipv4
# ipv4_retrieval_endpoint = "http://169.254.169.254/latest/meta-data/public-ipv4"
@@ -108,7 +108,7 @@ system("sudo chmod +x /usr/local/bin/docker-machine")
system("docker-machine version")
system("sudo apt-get remove -y --purge dnsmasq-base")
system("sudo apt-get -qy install python-setuptools pssh apache2-utils httping htop unzip mosh")
system("sudo apt-get -qy install python-setuptools pssh apache2-utils httping htop unzip mosh tree")
### Wait for Docker to be up.
### (If we don't do this, Docker will not be responsive during the next step.)

View File

@@ -0,0 +1,5 @@
# Number of VMs per cluster
clustersize: 5
# Jinja2 template to use to generate ready-to-cut cards
cards_template: clusters.csv

View File

@@ -0,0 +1,24 @@
# customize your cluster size, your cards template, and the versions
# Number of VMs per cluster
clustersize: 5
# Jinja2 template to use to generate ready-to-cut cards
cards_template: cards.html
# Use "Letter" in the US, and "A4" everywhere else
paper_size: Letter
# Feel free to reduce this if your printer can handle it
paper_margin: 0.2in
# Note: paper_size and paper_margin only apply to PDF generated with pdfkit.
# If you print (or generate a PDF) using ips.html, they will be ignored.
# (The equivalent parameters must be set from the browser's print dialog.)
# This can be "test" or "stable"
engine_version: test
# These correspond to the version numbers visible on their respective GitHub release pages
compose_version: 1.18.0
machine_version: 0.13.0

View File

@@ -17,8 +17,8 @@ paper_margin: 0.2in
# (The equivalent parameters must be set from the browser's print dialog.)
# This can be "test" or "stable"
engine_version: test
engine_version: stable
# These correspond to the version numbers visible on their respective GitHub release pages
compose_version: 1.16.1
machine_version: 0.12.0
compose_version: 1.21.1
machine_version: 0.14.0

View File

@@ -0,0 +1,106 @@
{# Feel free to customize or override anything in there! #}
{%- set url = "http://container.training/" -%}
{%- set pagesize = 12 -%}
{%- if clustersize == 1 -%}
{%- set workshop_name = "Docker workshop" -%}
{%- set cluster_or_machine = "machine" -%}
{%- set this_or_each = "this" -%}
{%- set machine_is_or_machines_are = "machine is" -%}
{%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%}
{%- else -%}
{%- set workshop_name = "Kubernetes workshop" -%}
{%- set cluster_or_machine = "cluster" -%}
{%- set this_or_each = "each" -%}
{%- set machine_is_or_machines_are = "machines are" -%}
{%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%}
{%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%}
{%- set image_src = image_src_kube -%}
{%- endif -%}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><style>
body, table {
margin: 0;
padding: 0;
line-height: 1em;
font-size: 14px;
}
table {
border-spacing: 0;
margin-top: 0.4em;
margin-bottom: 0.4em;
border-left: 0.8em double grey;
padding-left: 0.4em;
}
div {
float: left;
border: 1px dotted black;
padding-top: 1%;
padding-bottom: 1%;
/* columns * (width+left+right) < 100% */
width: 21.5%;
padding-left: 1.5%;
padding-right: 1.5%;
}
p {
margin: 0.4em 0 0.4em 0;
}
img {
height: 4em;
float: right;
margin-right: -0.4em;
}
.logpass {
font-family: monospace;
font-weight: bold;
}
.pagebreak {
page-break-after: always;
clear: both;
display: block;
height: 8px;
}
</style></head>
<body>
{% for cluster in clusters %}
{% if loop.index0>0 and loop.index0%pagesize==0 %}
<span class="pagebreak"></span>
{% endif %}
<div>
<p>
Here is the connection information to your very own
{{ cluster_or_machine }} for this {{ workshop_name }}.
You can connect to {{ this_or_each }} VM with any SSH client.
</p>
<p>
<img src="{{ image_src }}" />
<table>
<tr><td>login:</td></tr>
<tr><td class="logpass">docker</td></tr>
<tr><td>password:</td></tr>
<tr><td class="logpass">training</td></tr>
</table>
</p>
<p>
Your {{ machine_is_or_machines_are }}:
<table>
{% for node in cluster %}
<tr><td>node{{ loop.index }}:</td><td>{{ node }}</td></tr>
{% endfor %}
</table>
</p>
<p>You can find the slides at:
<center>{{ url }}</center>
</p>
</div>
{% endfor %}
</body>
</html>

View File

@@ -0,0 +1,24 @@
# 3 nodes for k8s 101 workshops
# Number of VMs per cluster
clustersize: 3
# Jinja2 template to use to generate ready-to-cut cards
cards_template: settings/kube101.html
# Use "Letter" in the US, and "A4" everywhere else
paper_size: Letter
# Feel free to reduce this if your printer can handle it
paper_margin: 0.2in
# Note: paper_size and paper_margin only apply to PDF generated with pdfkit.
# If you print (or generate a PDF) using ips.html, they will be ignored.
# (The equivalent parameters must be set from the browser's print dialog.)
# This can be "test" or "stable"
engine_version: stable
# These correspond to the version numbers visible on their respective GitHub release pages
compose_version: 1.21.1
machine_version: 0.14.0

View File

@@ -1,7 +1,7 @@
# This file is passed by trainer-cli to scripts/ips-txt-to-html.py
# Number of VMs per cluster
clustersize: 5
clustersize: 3
# Jinja2 template to use to generate ready-to-cut cards
cards_template: cards.html
@@ -17,8 +17,8 @@ paper_margin: 0.2in
# (The equivalent parameters must be set from the browser's print dialog.)
# This can be "test" or "stable"
engine_version: test
engine_version: stable
# These correspond to the version numbers visible on their respective GitHub release pages
compose_version: 1.16.1
machine_version: 0.12.0
compose_version: 1.21.1
machine_version: 0.14.0

View File

@@ -38,7 +38,7 @@ check_envvars() {
if [ -z "${!envvar}" ]; then
error "Environment variable $envvar is not set."
if [ "$envvar" = "SSH_AUTH_SOCK" ]; then
error "Hint: run '\$(ssh-agent) ; ssh-add' and try again?"
error "Hint: run 'eval \$(ssh-agent) ; ssh-add' and try again?"
fi
status=1
fi

1
slides/_redirects Normal file
View File

@@ -0,0 +1 @@
/ /kube-halfday.yml.html 200!

17
slides/appendcheck.py Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env python
import logging
import os
import subprocess
import sys
logging.basicConfig(level=os.environ.get("LOG_LEVEL", "INFO"))
filename = sys.argv[1]
logging.info("Checking file {}...".format(filename))
text = subprocess.check_output(["./slidechecker.js", filename])
html = open(filename).read()
html = html.replace("</textarea>", "\n---\n```\n{}\n```\n</textarea>".format(text))
open(filename, "w").write(html)

418
slides/autopilot/autotest.py Executable file
View File

@@ -0,0 +1,418 @@
#!/usr/bin/env python
# coding: utf-8
import click
import logging
import os
import random
import re
import select
import subprocess
import sys
import time
import uuid
import yaml
logging.basicConfig(level=os.environ.get("LOG_LEVEL", "INFO"))
TIMEOUT = 60 # 1 minute
# This one is not a constant. It's an ugly global.
IPADDR = None
class State(object):
def __init__(self):
self.interactive = True
self.verify_status = False
self.simulate_type = True
self.slide = 1
self.snippet = 0
def load(self):
data = yaml.load(open("state.yaml"))
self.interactive = bool(data["interactive"])
self.verify_status = bool(data["verify_status"])
self.simulate_type = bool(data["simulate_type"])
self.slide = int(data["slide"])
self.snippet = int(data["snippet"])
def save(self):
with open("state.yaml", "w") as f:
yaml.dump(dict(
interactive=self.interactive,
verify_status=self.verify_status,
simulate_type=self.simulate_type,
slide=self.slide,
snippet=self.snippet,
), f, default_flow_style=False)
state = State()
def hrule():
return "="*int(subprocess.check_output(["tput", "cols"]))
# A "snippet" is something that the user is supposed to do in the workshop.
# Most of the "snippets" are shell commands.
# Some of them can be key strokes or other actions.
# In the markdown source, they are the code sections (identified by triple-
# quotes) within .exercise[] sections.
class Snippet(object):
def __init__(self, slide, content):
self.slide = slide
self.content = content
# Extract the "method" (e.g. bash, keys, ...)
# On multi-line snippets, the method is alone on the first line
# On single-line snippets, the data follows the method immediately
if '\n' in content:
self.method, self.data = content.split('\n', 1)
else:
self.method, self.data = content.split(' ', 1)
self.data = self.data.strip()
self.next = None
def __str__(self):
return self.content
class Slide(object):
current_slide = 0
def __init__(self, content):
self.number = Slide.current_slide
Slide.current_slide += 1
# Remove commented-out slides
# (remark.js considers ??? to be the separator for speaker notes)
content = re.split("\n\?\?\?\n", content)[0]
self.content = content
self.snippets = []
exercises = re.findall("\.exercise\[(.*)\]", content, re.DOTALL)
for exercise in exercises:
if "```" in exercise:
previous = None
for snippet_content in exercise.split("```")[1::2]:
snippet = Snippet(self, snippet_content)
if previous:
previous.next = snippet
previous = snippet
self.snippets.append(snippet)
else:
logging.warning("Exercise on slide {} does not have any ``` snippet."
.format(self.number))
self.debug()
def __str__(self):
text = self.content
for snippet in self.snippets:
text = text.replace(snippet.content, ansi("7")(snippet.content))
return text
def debug(self):
logging.debug("\n{}\n{}\n{}".format(hrule(), self.content, hrule()))
def focus_slides():
subprocess.check_output(["i3-msg", "workspace", "3"])
subprocess.check_output(["i3-msg", "workspace", "1"])
def focus_terminal():
subprocess.check_output(["i3-msg", "workspace", "2"])
subprocess.check_output(["i3-msg", "workspace", "1"])
def focus_browser():
subprocess.check_output(["i3-msg", "workspace", "4"])
subprocess.check_output(["i3-msg", "workspace", "1"])
def ansi(code):
return lambda s: "\x1b[{}m{}\x1b[0m".format(code, s)
# Sleeps the indicated delay, but interruptible by pressing ENTER.
# If interrupted, returns True.
def interruptible_sleep(t):
rfds, _, _ = select.select([0], [], [], t)
return 0 in rfds
def wait_for_string(s, timeout=TIMEOUT):
logging.debug("Waiting for string: {}".format(s))
deadline = time.time() + timeout
while time.time() < deadline:
output = capture_pane()
if s in output:
return
if interruptible_sleep(1): return
raise Exception("Timed out while waiting for {}!".format(s))
def wait_for_prompt():
logging.debug("Waiting for prompt.")
deadline = time.time() + TIMEOUT
while time.time() < deadline:
output = capture_pane()
# If we are not at the bottom of the screen, there will be a bunch of extra \n's
output = output.rstrip('\n')
last_line = output.split('\n')[-1]
# Our custom prompt on the VMs has two lines; the 2nd line is just '$'
if last_line == "$":
# This is a perfect opportunity to grab the node's IP address
global IPADDR
IPADDR = re.findall("^\[(.*)\]", output, re.MULTILINE)[-1]
return
# When we are in an alpine container, the prompt will be "/ #"
if last_line == "/ #":
return
# We did not recognize a known prompt; wait a bit and check again
logging.debug("Could not find a known prompt on last line: {!r}"
.format(last_line))
if interruptible_sleep(1): return
raise Exception("Timed out while waiting for prompt!")
def check_exit_status():
if not state.verify_status:
return
token = uuid.uuid4().hex
data = "echo {} $?\n".format(token)
logging.debug("Sending {!r} to get exit status.".format(data))
send_keys(data)
time.sleep(0.5)
wait_for_prompt()
screen = capture_pane()
status = re.findall("\n{} ([0-9]+)\n".format(token), screen, re.MULTILINE)
logging.debug("Got exit status: {}.".format(status))
if len(status) == 0:
raise Exception("Couldn't retrieve status code {}. Timed out?".format(token))
if len(status) > 1:
raise Exception("More than one status code {}. I'm seeing double! Shoot them both.".format(token))
code = int(status[0])
if code != 0:
raise Exception("Non-zero exit status: {}.".format(code))
# Otherwise just return peacefully.
def setup_tmux_and_ssh():
if subprocess.call(["tmux", "has-session"]):
logging.error("Couldn't connect to tmux. Please setup tmux first.")
ipaddr = open("../../prepare-vms/ips.txt").read().split("\n")[0]
uid = os.getuid()
raise Exception("""
1. If you're running this directly from a node:
tmux
2. If you want to control a remote tmux:
rm -f /tmp/tmux-{uid}/default && ssh -t -L /tmp/tmux-{uid}/default:/tmp/tmux-1001/default docker@{ipaddr} tmux new-session -As 0
3. If you cannot control a remote tmux:
tmux new-session ssh docker@{ipaddr}
""".format(uid=uid, ipaddr=ipaddr))
else:
logging.info("Found tmux session. Trying to acquire shell prompt.")
wait_for_prompt()
logging.info("Successfully connected to test cluster in tmux session.")
slides = [Slide("Dummy slide zero")]
content = open(sys.argv[1]).read()
# OK, this part is definitely hackish, and will break if the
# excludedClasses parameter is not on a single line.
excluded_classes = re.findall("excludedClasses: (\[.*\])", content)
excluded_classes = set(eval(excluded_classes[0]))
for slide in re.split("\n---?\n", content):
slide_classes = re.findall("class: (.*)", slide)
if slide_classes:
slide_classes = slide_classes[0].split(",")
slide_classes = [c.strip() for c in slide_classes]
if excluded_classes & set(slide_classes):
logging.info("Skipping excluded slide.")
continue
slides.append(Slide(slide))
def send_keys(data):
if state.simulate_type and data[0] != '^':
for key in data:
if key == ";":
key = "\\;"
if key == "\n":
if interruptible_sleep(1): return
subprocess.check_call(["tmux", "send-keys", key])
if interruptible_sleep(0.15*random.random()): return
if key == "\n":
if interruptible_sleep(1): return
else:
subprocess.check_call(["tmux", "send-keys", data])
def capture_pane():
return subprocess.check_output(["tmux", "capture-pane", "-p"]).decode('utf-8')
setup_tmux_and_ssh()
try:
state.load()
logging.info("Successfully loaded state from file.")
# Let's override the starting state, so that when an error occurs,
# we can restart the auto-tester and then single-step or debug.
# (Instead of running again through the same issue immediately.)
state.interactive = True
except Exception as e:
logging.exception("Could not load state from file.")
logging.warning("Using default values.")
def move_forward():
state.snippet += 1
if state.snippet > len(slides[state.slide].snippets):
state.slide += 1
state.snippet = 0
check_bounds()
def move_backward():
state.snippet -= 1
if state.snippet < 0:
state.slide -= 1
state.snippet = 0
check_bounds()
def check_bounds():
if state.slide < 1:
state.slide = 1
if state.slide >= len(slides):
state.slide = len(slides)-1
while True:
state.save()
slide = slides[state.slide]
snippet = slide.snippets[state.snippet-1] if state.snippet else None
click.clear()
print("[Slide {}/{}] [Snippet {}/{}] [simulate_type:{}] [verify_status:{}]"
.format(state.slide, len(slides)-1,
state.snippet, len(slide.snippets) if slide.snippets else 0,
state.simulate_type, state.verify_status))
print(hrule())
if snippet:
print(slide.content.replace(snippet.content, ansi(7)(snippet.content)))
focus_terminal()
else:
print(slide.content)
subprocess.check_output(["./gotoslide.js", str(slide.number)])
focus_slides()
print(hrule())
if state.interactive:
print("y/⎵/⏎ Execute snippet or advance to next snippet")
print("p/← Previous")
print("n/→ Next")
print("s Simulate keystrokes")
print("v Validate exit status")
print("g Go to a specific slide")
print("q Quit")
print("c Continue non-interactively until next error")
command = click.getchar()
else:
command = "y"
if command in ("n", "\x1b[C"):
move_forward()
elif command in ("p", "\x1b[D"):
move_backward()
elif command == "s":
state.simulate_type = not state.simulate_type
elif command == "v":
state.verify_status = not state.verify_status
elif command == "g":
state.slide = click.prompt("Enter slide number", type=int)
state.snippet = 0
check_bounds()
elif command == "q":
break
elif command == "c":
# continue until next timeout
state.interactive = False
elif command in ("y", "\r", " "):
if not snippet:
# Advance to next snippet
# Advance until a slide that has snippets
while not slides[state.slide].snippets:
move_forward()
# But stop if we reach the last slide
if state.slide == len(slides)-1:
break
# And then advance to the snippet
move_forward()
continue
method, data = snippet.method, snippet.data
logging.info("Running with method {}: {}".format(method, data))
if method == "keys":
send_keys(data)
elif method == "bash":
# Make sure that we're ready
wait_for_prompt()
# Strip leading spaces
data = re.sub("\n +", "\n", data)
# Remove backticks (they are used to highlight sections)
data = data.replace('`', '')
# Add "RETURN" at the end of the command :)
data += "\n"
# Send command
send_keys(data)
# Force a short sleep to avoid race condition
time.sleep(0.5)
if snippet.next and snippet.next.method == "wait":
wait_for_string(snippet.next.data)
elif snippet.next and snippet.next.method == "longwait":
wait_for_string(snippet.next.data, 10*TIMEOUT)
else:
wait_for_prompt()
# Verify return code
check_exit_status()
elif method == "copypaste":
screen = capture_pane()
matches = re.findall(data, screen, flags=re.DOTALL)
if len(matches) == 0:
raise Exception("Could not find regex {} in output.".format(data))
# Arbitrarily get the most recent match
match = matches[-1]
# Remove line breaks (like a screen copy paste would do)
match = match.replace('\n', '')
send_keys(match + '\n')
# FIXME: we should factor out the "bash" method
wait_for_prompt()
check_exit_status()
elif method == "open":
# Cheap way to get node1's IP address
screen = capture_pane()
url = data.replace("/node1", "/{}".format(IPADDR))
# This should probably be adapted to run on different OS
subprocess.check_output(["xdg-open", url])
focus_browser()
if state.interactive:
print("Press any key to continue to next step...")
click.getchar()
else:
logging.warning("Unknown method {}: {!r}".format(method, data))
move_forward()
else:
logging.warning("Unknown command {}.".format(command))

17
slides/autopilot/gotoslide.js Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env node
/* Expects a slide number as first argument.
* Will connect to the local pub/sub server,
* and issue a "go to slide X" command, which
* will be sent to all connected browsers.
*/
var io = require('socket.io-client');
var socket = io('http://localhost:3000');
socket.on('connect_error', function(){
console.log('connection error');
socket.close();
});
socket.emit('slide change', process.argv[2], function(){
socket.close();
});

603
slides/autopilot/package-lock.json generated Normal file
View File

@@ -0,0 +1,603 @@
{
"name": "container-training-pub-sub-server",
"version": "0.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"accepts": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
"integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
"requires": {
"mime-types": "2.1.17",
"negotiator": "0.6.1"
}
},
"after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"arraybuffer.slice": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz",
"integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco="
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"base64-arraybuffer": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
},
"base64id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
"integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY="
},
"better-assert": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
"requires": {
"callsite": "1.0.0"
}
},
"blob": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
"integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE="
},
"body-parser": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
"requires": {
"bytes": "3.0.0",
"content-type": "1.0.4",
"debug": "2.6.9",
"depd": "1.1.1",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"on-finished": "2.3.0",
"qs": "6.5.1",
"raw-body": "2.3.2",
"type-is": "1.6.15"
}
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"callsite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
},
"component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
},
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
},
"content-disposition": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"depd": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
},
"engine.io": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.4.tgz",
"integrity": "sha1-PQIRtwpVLOhB/8fahiezAamkFi4=",
"requires": {
"accepts": "1.3.3",
"base64id": "1.0.0",
"cookie": "0.3.1",
"debug": "2.6.9",
"engine.io-parser": "2.1.1",
"uws": "0.14.5",
"ws": "3.3.3"
},
"dependencies": {
"accepts": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
"integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
"requires": {
"mime-types": "2.1.17",
"negotiator": "0.6.1"
}
}
}
},
"engine.io-client": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.4.tgz",
"integrity": "sha1-T88TcLRxY70s6b4nM5ckMDUNTqE=",
"requires": {
"component-emitter": "1.2.1",
"component-inherit": "0.0.3",
"debug": "2.6.9",
"engine.io-parser": "2.1.1",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"ws": "3.3.3",
"xmlhttprequest-ssl": "1.5.4",
"yeast": "0.1.2"
}
},
"engine.io-parser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.1.tgz",
"integrity": "sha1-4Ps/DgRi9/WLt3waUun1p+JuRmg=",
"requires": {
"after": "0.8.2",
"arraybuffer.slice": "0.0.6",
"base64-arraybuffer": "0.1.5",
"blob": "0.0.4",
"has-binary2": "1.0.2"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.16.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
"integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=",
"requires": {
"accepts": "1.3.4",
"array-flatten": "1.1.1",
"body-parser": "1.18.2",
"content-disposition": "0.5.2",
"content-type": "1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "1.1.1",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"finalhandler": "1.1.0",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "1.1.2",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"path-to-regexp": "0.1.7",
"proxy-addr": "2.0.2",
"qs": "6.5.1",
"range-parser": "1.2.0",
"safe-buffer": "5.1.1",
"send": "0.16.1",
"serve-static": "1.13.1",
"setprototypeof": "1.1.0",
"statuses": "1.3.1",
"type-is": "1.6.15",
"utils-merge": "1.0.1",
"vary": "1.1.2"
}
},
"finalhandler": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
"integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
"requires": {
"debug": "2.6.9",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"statuses": "1.3.1",
"unpipe": "1.0.0"
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"has-binary2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz",
"integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=",
"requires": {
"isarray": "2.0.1"
}
},
"has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
},
"http-errors": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
"integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
"requires": {
"depd": "1.1.1",
"inherits": "2.0.3",
"setprototypeof": "1.0.3",
"statuses": "1.3.1"
},
"dependencies": {
"setprototypeof": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
"integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
}
}
},
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
"indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz",
"integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A="
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
},
"mime-db": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
},
"mime-types": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
"requires": {
"mime-db": "1.30.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"object-component": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"parseqs": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
"requires": {
"better-assert": "1.0.2"
}
},
"parseuri": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
"requires": {
"better-assert": "1.0.2"
}
},
"parseurl": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"proxy-addr": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz",
"integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=",
"requires": {
"forwarded": "0.1.2",
"ipaddr.js": "1.5.2"
}
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
"raw-body": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
"integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
"requires": {
"bytes": "3.0.0",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"unpipe": "1.0.0"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"send": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz",
"integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==",
"requires": {
"debug": "2.6.9",
"depd": "1.1.1",
"destroy": "1.0.4",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"fresh": "0.5.2",
"http-errors": "1.6.2",
"mime": "1.4.1",
"ms": "2.0.0",
"on-finished": "2.3.0",
"range-parser": "1.2.0",
"statuses": "1.3.1"
}
},
"serve-static": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
"integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==",
"requires": {
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"parseurl": "1.3.2",
"send": "0.16.1"
}
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
},
"socket.io": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz",
"integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=",
"requires": {
"debug": "2.6.9",
"engine.io": "3.1.4",
"socket.io-adapter": "1.1.1",
"socket.io-client": "2.0.4",
"socket.io-parser": "3.1.2"
}
},
"socket.io-adapter": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
"integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
},
"socket.io-client": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz",
"integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=",
"requires": {
"backo2": "1.0.2",
"base64-arraybuffer": "0.1.5",
"component-bind": "1.0.0",
"component-emitter": "1.2.1",
"debug": "2.6.9",
"engine.io-client": "3.1.4",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"object-component": "0.0.3",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"socket.io-parser": "3.1.2",
"to-array": "0.1.4"
}
},
"socket.io-parser": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.2.tgz",
"integrity": "sha1-28IoIVH8T6675Aru3Ady66YZ9/I=",
"requires": {
"component-emitter": "1.2.1",
"debug": "2.6.9",
"has-binary2": "1.0.2",
"isarray": "2.0.1"
}
},
"statuses": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
"integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
},
"to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
},
"type-is": {
"version": "1.6.15",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
"integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
"requires": {
"media-typer": "0.3.0",
"mime-types": "2.1.17"
}
},
"ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uws": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz",
"integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=",
"optional": true
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"ws": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
"requires": {
"async-limiter": "1.0.0",
"safe-buffer": "5.1.1",
"ultron": "1.1.1"
}
},
"xmlhttprequest-ssl": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.4.tgz",
"integrity": "sha1-BPVgkVcks4kIhxXMDteBPpZ3v1c="
},
"yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
}
}
}

View File

@@ -0,0 +1,8 @@
{
"name": "container-training-pub-sub-server",
"version": "0.0.1",
"dependencies": {
"express": "^4.16.2",
"socket.io": "^2.0.4"
}
}

View File

@@ -0,0 +1,21 @@
/* This snippet is loaded from the workshop HTML file.
* It sets up callbacks to synchronize the local slide
* number with the remote pub/sub server.
*/
var socket = io();
var leader = true;
slideshow.on('showSlide', function (slide) {
if (leader) {
var n = slide.getSlideIndex()+1;
socket.emit('slide change', n);
}
});
socket.on('slide change', function (n) {
leader = false;
slideshow.gotoSlide(n);
leader = true;
});

41
slides/autopilot/server.js Executable file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env node
/* This is a very simple pub/sub server, allowing to
* remote control browsers displaying the slides.
* The browsers connect to this pub/sub server using
* Socket.IO, and the server tells them which slides
* to display.
*
* The server can be controlled with a little CLI,
* or by one of the browsers.
*/
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.send('container.training autopilot pub/sub server');
});
/* Serve remote.js from the current directory */
app.use(express.static('.'));
/* Serve slides etc. from current and the parent directory */
app.use(express.static('..'));
io.on('connection', function(socket){
console.log('a client connected: ' + socket.handshake.address);
socket.on('slide change', function(n, ack){
console.log('slide change: ' + n);
socket.broadcast.emit('slide change', n);
if (typeof ack === 'function') {
ack();
}
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});

7
slides/autopilot/tmux-style.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/sh
# This removes the clock (and other extraneous stuff) from the
# tmux status bar, and it gives it a non-default color.
tmux set-option -g status-left ""
tmux set-option -g status-right ""
tmux set-option -g status-style bg=cyan

View File

@@ -1,15 +1,29 @@
#!/bin/sh
set -e
case "$1" in
once)
./index.py
for YAML in *.yml; do
./markmaker.py < $YAML > $YAML.html || {
./markmaker.py $YAML > $YAML.html || {
rm $YAML.html
break
}
done
if [ -n "$SLIDECHECKER" ]; then
for YAML in *.yml; do
./appendcheck.py $YAML.html
done
fi
;;
forever)
set +e
# check if entr is installed
if ! command -v entr >/dev/null; then
echo >&2 "First install 'entr' with apt, brew, etc."
exit
fi
# There is a weird bug in entr, at least on MacOS,
# where it doesn't restore the terminal to a clean
# state when exitting. So let's try to work around

View File

@@ -0,0 +1,48 @@
## About these slides
- All the content is available in a public GitHub repository:
https://@@GITREPO@@
- You can get updated "builds" of the slides there:
http://container.training/
<!--
.exercise[
```open https://@@GITREPO@@```
```open http://container.training/```
]
-->
--
- Typos? Mistakes? Questions? Feel free to hover over the bottom of the slide ...
.footnote[.emoji[👇] Try it! The source file will be shown and you can view it on GitHub and fork and edit it.]
<!--
.exercise[
```open https://@@GITREPO@@/tree/master/slides/common/about-slides.md```
]
-->
---
class: extra-details
## Extra details
- This slide has a little magnifying glass in the top left corner
- This magnifying glass indicates slides that provide extra details
- Feel free to skip them if:
- you are in a hurry
- you are new to this and want to avoid cognitive overload
- you want only the most essential information
- You can review these slides another time if you want, they'll be waiting for you ☺

View File

@@ -0,0 +1,12 @@
## Clean up
- Before moving on, let's remove those containers
.exercise[
- Tell Compose to remove everything:
```bash
docker-compose down
```
]

View File

@@ -0,0 +1,220 @@
## Restarting in the background
- Many flags and commands of Compose are modeled after those of `docker`
.exercise[
- Start the app in the background with the `-d` option:
```bash
docker-compose up -d
```
- Check that our app is running with the `ps` command:
```bash
docker-compose ps
```
]
`docker-compose ps` also shows the ports exposed by the application.
---
class: extra-details
## Viewing logs
- The `docker-compose logs` command works like `docker logs`
.exercise[
- View all logs since container creation and exit when done:
```bash
docker-compose logs
```
- Stream container logs, starting at the last 10 lines for each container:
```bash
docker-compose logs --tail 10 --follow
```
<!--
```wait units of work done```
```keys ^C```
-->
]
Tip: use `^S` and `^Q` to pause/resume log output.
---
## Scaling up the application
- Our goal is to make that performance graph go up (without changing a line of code!)
--
- Before trying to scale the application, we'll figure out if we need more resources
(CPU, RAM...)
- For that, we will use good old UNIX tools on our Docker node
---
## Looking at resource usage
- Let's look at CPU, memory, and I/O usage
.exercise[
- run `top` to see CPU and memory usage (you should see idle cycles)
<!--
```bash top```
```wait Tasks```
```keys ^C```
-->
- run `vmstat 1` to see I/O usage (si/so/bi/bo)
<br/>(the 4 numbers should be almost zero, except `bo` for logging)
<!--
```bash vmstat 1```
```wait memory```
```keys ^C```
-->
]
We have available resources.
- Why?
- How can we use them?
---
## Scaling workers on a single node
- Docker Compose supports scaling
- Let's scale `worker` and see what happens!
.exercise[
- Start one more `worker` container:
```bash
docker-compose up -d --scale worker=2
```
- Look at the performance graph (it should show a x2 improvement)
- Look at the aggregated logs of our containers (`worker_2` should show up)
- Look at the impact on CPU load with e.g. top (it should be negligible)
]
---
## Adding more workers
- Great, let's add more workers and call it a day, then!
.exercise[
- Start eight more `worker` containers:
```bash
docker-compose up -d --scale worker=10
```
- Look at the performance graph: does it show a x10 improvement?
- Look at the aggregated logs of our containers
- Look at the impact on CPU load and memory usage
]
---
# Identifying bottlenecks
- You should have seen a 3x speed bump (not 10x)
- Adding workers didn't result in linear improvement
- *Something else* is slowing us down
--
- ... But what?
--
- The code doesn't have instrumentation
- Let's use state-of-the-art HTTP performance analysis!
<br/>(i.e. good old tools like `ab`, `httping`...)
---
## Accessing internal services
- `rng` and `hasher` are exposed on ports 8001 and 8002
- This is declared in the Compose file:
```yaml
...
rng:
build: rng
ports:
- "8001:80"
hasher:
build: hasher
ports:
- "8002:80"
...
```
---
## Measuring latency under load
We will use `httping`.
.exercise[
- Check the latency of `rng`:
```bash
httping -c 3 localhost:8001
```
- Check the latency of `hasher`:
```bash
httping -c 3 localhost:8002
```
]
`rng` has a much higher latency than `hasher`.
---
## Let's draw hasty conclusions
- The bottleneck seems to be `rng`
- *What if* we don't have enough entropy and can't generate enough random numbers?
- We need to scale out the `rng` service on multiple machines!
Note: this is a fiction! We have enough entropy. But we need a pretext to scale out.
(In fact, the code of `rng` uses `/dev/urandom`, which never runs out of entropy...
<br/>
...and is [just as good as `/dev/random`](http://www.slideshare.net/PacSecJP/filippo-plain-simple-reality-of-entropy).)

View File

@@ -0,0 +1,63 @@
# Declarative vs imperative
- Our container orchestrator puts a very strong emphasis on being *declarative*
- Declarative:
*I would like a cup of tea.*
- Imperative:
*Boil some water. Pour it in a teapot. Add tea leaves. Steep for a while. Serve in a cup.*
--
- Declarative seems simpler at first ...
--
- ... As long as you know how to brew tea
---
## Declarative vs imperative
- What declarative would really be:
*I want a cup of tea, obtained by pouring an infusion¹ of tea leaves in a cup.*
--
*¹An infusion is obtained by letting the object steep a few minutes in hot² water.*
--
*²Hot liquid is obtained by pouring it in an appropriate container³ and setting it on a stove.*
--
*³Ah, finally, containers! Something we know about. Let's get to work, shall we?*
--
.footnote[Did you know there was an [ISO standard](https://en.wikipedia.org/wiki/ISO_3103)
specifying how to brew tea?]
---
## Declarative vs imperative
- Imperative systems:
- simpler
- if a task is interrupted, we have to restart from scratch
- Declarative systems:
- if a task is interrupted (or if we show up to the party half-way through),
we can figure out what's missing and do only what's necessary
- we need to be able to *observe* the system
- ... and compute a "diff" between *what we have* and *what we want*

309
slides/common/prereqs.md Normal file
View File

@@ -0,0 +1,309 @@
# Pre-requirements
- Be comfortable with the UNIX command line
- navigating directories
- editing files
- a little bit of bash-fu (environment variables, loops)
- Some Docker knowledge
- `docker run`, `docker ps`, `docker build`
- ideally, you know how to write a Dockerfile and build it
<br/>
(even if it's a `FROM` line and a couple of `RUN` commands)
- It's totally OK if you are not a Docker expert!
---
class: title
*Tell me and I forget.*
<br/>
*Teach me and I remember.*
<br/>
*Involve me and I learn.*
Misattributed to Benjamin Franklin
[(Probably inspired by Chinese Confucian philosopher Xunzi)](https://www.barrypopik.com/index.php/new_york_city/entry/tell_me_and_i_forget_teach_me_and_i_may_remember_involve_me_and_i_will_lear/)
---
## Hands-on sections
- The whole workshop is hands-on
- We are going to build, ship, and run containers!
- You are invited to reproduce all the demos
- All hands-on sections are clearly identified, like the gray rectangle below
.exercise[
- This is the stuff you're supposed to do!
- Go to @@SLIDES@@ to view these slides
- Join the chat room: @@CHAT@@
<!-- ```open @@SLIDES@@``` -->
]
---
class: in-person
## Where are we going to run our containers?
---
class: in-person, pic
![You get a cluster](images/you-get-a-cluster.jpg)
---
class: in-person
## You get a cluster of cloud VMs
- Each person gets a private cluster of cloud VMs (not shared with anybody else)
- They'll remain up for the duration of the workshop
- You should have a little card with login+password+IP addresses
- You can automatically SSH from one VM to another
- The nodes have aliases: `node1`, `node2`, etc.
---
class: in-person
## Why don't we run containers locally?
- Installing that stuff can be hard on some machines
(32 bits CPU or OS... Laptops without administrator access... etc.)
- *"The whole team downloaded all these container images from the WiFi!
<br/>... and it went great!"* (Literally no-one ever)
- All you need is a computer (or even a phone or tablet!), with:
- an internet connection
- a web browser
- an SSH client
---
class: in-person
## SSH clients
- On Linux, OS X, FreeBSD... you are probably all set
- On Windows, get one of these:
- [putty](http://www.putty.org/)
- Microsoft [Win32 OpenSSH](https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH)
- [Git BASH](https://git-for-windows.github.io/)
- [MobaXterm](http://mobaxterm.mobatek.net/)
- On Android, [JuiceSSH](https://juicessh.com/)
([Play Store](https://play.google.com/store/apps/details?id=com.sonelli.juicessh))
works pretty well
- Nice-to-have: [Mosh](https://mosh.org/) instead of SSH, if your internet connection tends to lose packets
---
class: in-person, extra-details
## What is this Mosh thing?
*You don't have to use Mosh or even know about it to follow along.
<br/>
We're just telling you about it because some of us think it's cool!*
- Mosh is "the mobile shell"
- It is essentially SSH over UDP, with roaming features
- It retransmits packets quickly, so it works great even on lossy connections
(Like hotel or conference WiFi)
- It has intelligent local echo, so it works great even in high-latency connections
(Like hotel or conference WiFi)
- It supports transparent roaming when your client IP address changes
(Like when you hop from hotel to conference WiFi)
---
class: in-person, extra-details
## Using Mosh
- To install it: `(apt|yum|brew) install mosh`
- It has been pre-installed on the VMs that we are using
- To connect to a remote machine: `mosh user@host`
(It is going to establish an SSH connection, then hand off to UDP)
- It requires UDP ports to be open
(By default, it uses a UDP port between 60000 and 61000)
---
class: in-person
## Connecting to our lab environment
.exercise[
- Log into the first VM (`node1`) with your SSH client
<!--
```bash
for N in $(awk '/\Wnode/{print $2}' /etc/hosts); do
ssh -o StrictHostKeyChecking=no $N true
done
```
```bash
if which kubectl; then
kubectl get all -o name | grep -v service/kubernetes | xargs -rn1 kubectl delete
fi
```
-->
- Check that you can SSH (without password) to `node2`:
```bash
ssh node2
```
- Type `exit` or `^D` to come back to `node1`
<!-- ```bash exit``` -->
]
If anything goes wrong — ask for help!
---
## Doing or re-doing the workshop on your own?
- Use something like
[Play-With-Docker](http://play-with-docker.com/) or
[Play-With-Kubernetes](https://medium.com/@marcosnils/introducing-pwk-play-with-k8s-159fcfeb787b)
Zero setup effort; but environment are short-lived and
might have limited resources
- Create your own cluster (local or cloud VMs)
Small setup effort; small cost; flexible environments
- Create a bunch of clusters for you and your friends
([instructions](https://@@GITREPO@@/tree/master/prepare-vms))
Bigger setup effort; ideal for group training
---
class: self-paced
## Get your own Docker nodes
- If you already have some Docker nodes: great!
- If not: let's get some thanks to Play-With-Docker
.exercise[
- Go to http://www.play-with-docker.com/
- Log in
- Create your first node
<!-- ```open http://www.play-with-docker.com/``` -->
]
You will need a Docker ID to use Play-With-Docker.
(Creating a Docker ID is free.)
---
## We will (mostly) interact with node1 only
*These remarks apply only when using multiple nodes, of course.*
- Unless instructed, **all commands must be run from the first VM, `node1`**
- We will only checkout/copy the code on `node1`
- During normal operations, we do not need access to the other nodes
- If we had to troubleshoot issues, we would use a combination of:
- SSH (to access system logs, daemon status...)
- Docker API (to check running containers and container engine status)
---
## Terminals
Once in a while, the instructions will say:
<br/>"Open a new terminal."
There are multiple ways to do this:
- create a new window or tab on your machine, and SSH into the VM;
- use screen or tmux on the VM and open a new window from there.
You are welcome to use the method that you feel the most comfortable with.
---
## Tmux cheatsheet
[Tmux](https://en.wikipedia.org/wiki/Tmux) is a terminal multiplexer like `screen`.
*You don't have to use it or even know about it to follow along.
<br/>
But some of us like to use it to switch between terminals.
<br/>
It has been preinstalled on your workshop nodes.*
- Ctrl-b c → creates a new window
- Ctrl-b n → go to next window
- Ctrl-b p → go to previous window
- Ctrl-b " → split window top/bottom
- Ctrl-b % → split window left/right
- Ctrl-b Alt-1 → rearrange windows in columns
- Ctrl-b Alt-2 → rearrange windows in rows
- Ctrl-b arrows → navigate to other windows
- Ctrl-b d → detach session
- tmux attach → reattach to session

19
slides/common/pwd.md Normal file
View File

@@ -0,0 +1,19 @@
## Using Play-With-Docker
- Open a new browser tab to [www.play-with-docker.com](http://www.play-with-docker.com/)
- Confirm that you're not a robot
- Click on "ADD NEW INSTANCE": congratulations, you have your first Docker node!
- When you will need more nodes, just click on "ADD NEW INSTANCE" again
- Note the countdown in the corner; when it expires, your instances are destroyed
- If you give your URL to somebody else, they can access your nodes too
<br/>
(You can use that for pair programming, or to get help from a mentor)
- Loving it? Not loving it? Tell it to the wonderful authors,
[@marcosnils](https://twitter.com/marcosnils) &
[@xetorthio](https://twitter.com/xetorthio)!

View File

@@ -1,16 +1,71 @@
# Our sample application
- We will clone the GitHub repository onto our `node1`
- The repository also contains scripts and tools that we will use through the workshop
.exercise[
<!--
```bash
if [ -d container.training ]; then
mv container.training container.training.$$
fi
```
-->
- Clone the repository on `node1`:
```bash
git clone git://@@GITREPO@@
```
]
(You can also fork the repository on GitHub and clone your fork if you prefer that.)
---
## Downloading and running the application
Let's start this before we look around, as downloading will take a little time...
.exercise[
- Go to the `dockercoins` directory, in the cloned repo:
```bash
cd ~/container.training/dockercoins
```
- Use Compose to build and run all containers:
```bash
docker-compose up
```
<!--
```longwait units of work done```
-->
]
Compose tells Docker to build all container images (pulling
the corresponding base images), then starts all containers,
and displays aggregated logs.
---
## More detail on our sample application
- Visit the GitHub repository with all the materials of this workshop:
<br/>https://github.com/jpetazzo/orchestration-workshop
<br/>https://@@GITREPO@@
- The application is in the [dockercoins](
https://github.com/jpetazzo/orchestration-workshop/tree/master/dockercoins)
https://@@GITREPO@@/tree/master/dockercoins)
subdirectory
- Let's look at the general layout of the source code:
there is a Compose file [docker-compose.yml](
https://github.com/jpetazzo/orchestration-workshop/blob/master/dockercoins/docker-compose.yml) ...
https://@@GITREPO@@/blob/master/dockercoins/docker-compose.yml) ...
... and 4 other services, each in its own directory:
@@ -39,6 +94,43 @@ class: extra-details
---
## Service discovery in container-land
- We do not hard-code IP addresses in the code
- We do not hard-code FQDN in the code, either
- We just connect to a service name, and container-magic does the rest
(And by container-magic, we mean "a crafty, dynamic, embedded DNS server")
---
## Example in `worker/worker.py`
```python
redis = Redis("`redis`")
def get_random_bytes():
r = requests.get("http://`rng`/32")
return r.content
def hash_bytes(data):
r = requests.post("http://`hasher`/",
data=data,
headers={"Content-Type": "application/octet-stream"})
```
(Full source code available [here](
https://@@GITREPO@@/blob/8279a3bce9398f7c1a53bdd95187c53eda4e6435/dockercoins/worker/worker.py#L17
))
---
class: extra-details
## Links, naming, and service discovery
- Containers can have network aliases (resolvable through DNS)
@@ -47,37 +139,21 @@ class: extra-details
- Compose file version 1 did require "links" sections
- Our code can connect to services using their short name
(instead of e.g. IP address or FQDN)
- Network aliases are automatically namespaced
(i.e. you can have multiple apps declaring and using a service named `database`)
- you can have multiple apps declaring and using a service named `database`
---
- containers in the blue app will resolve `database` to the IP of the blue database
## Example in `worker/worker.py`
![Service discovery](images/service-discovery.png)
- containers in the green app will resolve `database` to the IP of the green database
---
## What's this application?
---
--
class: pic
![DockerCoins logo](images/dockercoins.png)
(DockerCoins 2016 logo courtesy of [@XtlCnslt](https://twitter.com/xtlcnslt) and [@ndeloof](https://twitter.com/ndeloof). Thanks!)
---
## What's this application?
- It is a DockerCoin miner! 💰🐳📦🚢
- It is a DockerCoin miner! .emoji[💰🐳📦🚢]
--
@@ -99,156 +175,22 @@ class: pic
---
## Getting the application source code
## Our application at work
- We will clone the GitHub repository
- On the left-hand side, the "rainbow strip" shows the container names
- The repository also contains scripts and tools that we will use through the workshop
.exercise[
<!--
```bash
if [ -d orchestration-workshop ]; then
mv orchestration-workshop orchestration-workshop.$$
fi
```
-->
- Clone the repository on `node1`:
```bash
git clone git://github.com/jpetazzo/orchestration-workshop
```
]
(You can also fork the repository on GitHub and clone your fork if you prefer that.)
---
# Running the application
Without further ado, let's start our application.
.exercise[
- Go to the `dockercoins` directory, in the cloned repo:
```bash
cd ~/orchestration-workshop/dockercoins
```
- Use Compose to build and run all containers:
```bash
docker-compose up
```
<!--
```wait units of work done```
```keys ^C```
-->
]
Compose tells Docker to build all container images (pulling
the corresponding base images), then starts all containers,
and displays aggregated logs.
---
## Lots of logs
- The application continuously generates logs
- On the right-hand side, we see the output of our containers
- We can see the `worker` service making requests to `rng` and `hasher`
- Let's put that in the background
.exercise[
- Stop the application by hitting `^C`
]
- `^C` stops all containers by sending them the `TERM` signal
- Some containers exit immediately, others take longer
<br/>(because they don't handle `SIGTERM` and end up being killed after a 10s timeout)
---
## Restarting in the background
- Many flags and commands of Compose are modeled after those of `docker`
.exercise[
- Start the app in the background with the `-d` option:
```bash
docker-compose up -d
```
- Check that our app is running with the `ps` command:
```bash
docker-compose ps
```
]
`docker-compose ps` also shows the ports exposed by the application.
---
class: extra-details
## Viewing logs
- The `docker-compose logs` command works like `docker logs`
.exercise[
- View all logs since container creation and exit when done:
```bash
docker-compose logs
```
- Stream container logs, starting at the last 10 lines for each container:
```bash
docker-compose logs --tail 10 --follow
```
<!--
```wait units of work done```
```keys ^C```
-->
]
Tip: use `^S` and `^Q` to pause/resume log output.
---
class: extra-details
## Upgrading from Compose 1.6
.warning[The `logs` command has changed between Compose 1.6 and 1.7!]
- Up to 1.6
- `docker-compose logs` is the equivalent of `logs --follow`
- `docker-compose logs` must be restarted if containers are added
- Since 1.7
- `--follow` must be specified explicitly
- new containers are automatically picked up by `docker-compose logs`
- For `rng` and `hasher`, we see HTTP access logs
---
## Connecting to the web UI
- "Logs are exciting and fun!" (No-one, ever)
- The `webui` container exposes a web dashboard; let's view it
.exercise[
@@ -263,11 +205,31 @@ class: extra-details
]
You should see a speed of approximately 4 hashes/second.
A drawing area should show up, and after a few seconds, a blue
graph will appear.
More precisely: 4 hashes/second, with regular dips down to zero.
<br/>This is because Jérôme is incapable of writing good frontend code.
<br/>Don't ask. Seriously, don't ask. This is embarrassing.
---
class: self-paced, extra-details
## If the graph doesn't load
If you just see a `Page not found` error, it might be because your
Docker Engine is running on a different machine. This can be the case if:
- you are using the Docker Toolbox
- you are using a VM (local or remote) created with Docker Machine
- you are controlling a remote Docker Engine
When you run DockerCoins in development mode, the web UI static files
are mapped to the container using a volume. Alas, volumes can only
work on a local environment, or when using Docker4Mac or Docker4Windows.
How to fix this?
Stop the app with `^C`, edit `dockercoins.yml`, comment out the `volumes` section, and try again.
---
@@ -275,203 +237,67 @@ class: extra-details
## Why does the speed seem irregular?
- It *looks like* the speed is approximately 4 hashes/second
- Or more precisely: 4 hashes/second, with regular dips down to zero
- Why?
--
class: extra-details
- The app actually has a constant, steady speed: 3.33 hashes/second
<br/>
(which corresponds to 1 hash every 0.3 seconds, for *reasons*)
- Yes, and?
---
class: extra-details
## The reason why this graph is *not awesome*
- The worker doesn't update the counter after every loop, but up to once per second
- The speed is computed by the browser, checking the counter about once per second
- Between two consecutive updates, the counter will increase either by 4, or by 0
- The perceived speed will therefore be 4 - 4 - 4 - 0 - 4 - 4 - etc.
- The perceived speed will therefore be 4 - 4 - 4 - 0 - 4 - 4 - 0 etc.
*We told you to not ask!!!*
---
## Scaling up the application
- Our goal is to make that performance graph go up (without changing a line of code!)
- What can we conclude from this?
--
- Before trying to scale the application, we'll figure out if we need more resources
class: extra-details
(CPU, RAM...)
- For that, we will use good old UNIX tools on our Docker node
- "I'm clearly incapable of writing good frontend code!" 😀 — Jérôme
---
## Looking at resource usage
## Stopping the application
- Let's look at CPU, memory, and I/O usage
- If we interrupt Compose (with `^C`), it will politely ask the Docker Engine to stop the app
- The Docker Engine will send a `TERM` signal to the containers
- If the containers do not exit in a timely manner, the Engine sends a `KILL` signal
.exercise[
- run `top` to see CPU and memory usage (you should see idle cycles)
- Stop the application by hitting `^C`
<!--
```bash top```
```wait Tasks```
```keys ^C```
-->
- run `vmstat 1` to see I/O usage (si/so/bi/bo)
<br/>(the 4 numbers should be almost zero, except `bo` for logging)
<!--
```bash vmstat 1```
```wait memory```
```keys ^C```
-->
]
We have available resources.
- Why?
- How can we use them?
---
## Scaling workers on a single node
- Docker Compose supports scaling
- Let's scale `worker` and see what happens!
.exercise[
- Start one more `worker` container:
```bash
docker-compose scale worker=2
```
- Look at the performance graph (it should show a x2 improvement)
- Look at the aggregated logs of our containers (`worker_2` should show up)
- Look at the impact on CPU load with e.g. top (it should be negligible)
]
---
## Adding more workers
- Great, let's add more workers and call it a day, then!
.exercise[
- Start eight more `worker` containers:
```bash
docker-compose scale worker=10
```
- Look at the performance graph: does it show a x10 improvement?
- Look at the aggregated logs of our containers
- Look at the impact on CPU load and memory usage
]
---
# Identifying bottlenecks
- You should have seen a 3x speed bump (not 10x)
- Adding workers didn't result in linear improvement
- *Something else* is slowing us down
--
- ... But what?
Some containers exit immediately, others take longer.
--
The containers that do not handle `SIGTERM` end up being killed after a 10s timeout. If we are very impatient, we can hit `^C` a second time!
- The code doesn't have instrumentation
- Let's use state-of-the-art HTTP performance analysis!
<br/>(i.e. good old tools like `ab`, `httping`...)
---
## Accessing internal services
- `rng` and `hasher` are exposed on ports 8001 and 8002
- This is declared in the Compose file:
```yaml
...
rng:
build: rng
ports:
- "8001:80"
hasher:
build: hasher
ports:
- "8002:80"
...
```
---
## Measuring latency under load
We will use `httping`.
.exercise[
- Check the latency of `rng`:
```bash
httping -c 10 localhost:8001
```
- Check the latency of `hasher`:
```bash
httping -c 10 localhost:8002
```
]
`rng` has a much higher latency than `hasher`.
---
## Let's draw hasty conclusions
- The bottleneck seems to be `rng`
- *What if* we don't have enough entropy and can't generate enough random numbers?
- We need to scale out the `rng` service on multiple machines!
Note: this is a fiction! We have enough entropy. But we need a pretext to scale out.
(In fact, the code of `rng` uses `/dev/urandom`, which never runs out of entropy...
<br/>
...and is [just as good as `/dev/random`](http://www.slideshare.net/PacSecJP/filippo-plain-simple-reality-of-entropy).)
---
## Clean up
- Before moving on, let's remove those containers
.exercise[
- Tell Compose to remove everything:
```bash
docker-compose down
```
]

11
slides/common/thankyou.md Normal file
View File

@@ -0,0 +1,11 @@
class: title, self-paced
Thank you!
---
class: title, in-person
That's all, folks! <br/> Questions?
![end](images/end.jpg)

21
slides/common/title.md Normal file
View File

@@ -0,0 +1,21 @@
class: title, self-paced
@@TITLE@@
.nav[*Self-paced version*]
---
class: title, in-person
@@TITLE@@<br/></br>
.footnote[
**Be kind to the WiFi!**<br/>
<!-- *Use the 5G network.* -->
*Don't use your hotspot.*<br/>
*Don't stream videos or download big files during the workshop.*<br/>
*Thank you!*
**Slides: @@SLIDES@@**
]

4
slides/common/toc.md Normal file
View File

@@ -0,0 +1,4 @@
@@TOC@@

57
slides/count-slides.py Executable file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python
import re
import sys
PREFIX = "name: toc-"
EXCLUDED = ["in-person"]
class State(object):
def __init__(self):
self.current_slide = 1
self.section_title = None
self.section_start = 0
self.section_slides = 0
self.chapters = {}
self.sections = {}
def show(self):
if self.section_title.startswith("chapter-"):
return
print("{0.section_title}\t{0.section_start}\t{0.section_slides}".format(self))
self.sections[self.section_title] = self.section_slides
state = State()
title = None
for line in open(sys.argv[1]):
line = line.rstrip()
if line.startswith(PREFIX):
if state.section_title is None:
print("{}\t{}\t{}".format("title", "index", "size"))
else:
state.show()
state.section_title = line[len(PREFIX):].strip()
state.section_start = state.current_slide
state.section_slides = 0
if line == "---":
state.current_slide += 1
state.section_slides += 1
if line == "--":
state.current_slide += 1
toc_links = re.findall("\(#toc-(.*)\)", line)
if toc_links and state.section_title.startswith("chapter-"):
if state.section_title not in state.chapters:
state.chapters[state.section_title] = []
state.chapters[state.section_title].append(toc_links[0])
# This is really hackish
if line.startswith("class:"):
for klass in EXCLUDED:
if klass in line:
state.section_slides -= 1
state.current_slide -= 1
state.show()
for chapter in sorted(state.chapters):
chapter_size = sum(state.sections[s] for s in state.chapters[chapter])
print("{}\t{}\t{}".format("total size for", chapter, chapter_size))

View File

@@ -1,182 +0,0 @@
chat: "[Slack](https://dockercommunity.slack.com/messages/C7ET1GY4Q)"
exclude:
- self-paced
- snap
- auto-btp
- benchmarking
- elk-manual
- prom-manual
title: "Swarm: from Zero to Hero (DC17EU)"
chapters:
- |
class: title
.small[
Swarm: from Zero to Hero
.small[.small[
**Be kind to the WiFi!**
*Use the 5G network*
<br/>
*Don't use your hotspot*
<br/>
*Don't stream videos from YouTube, Netflix, etc.
<br/>(if you're bored, watch local content instead)*
Also: share the power outlets
<br/>
*(with limited power comes limited responsibility?)*
<br/>
*(or something?)*
Thank you!
]
]
]
---
## Intros
<!--
- Hello! We are
AJ ([@s0ulshake](https://twitter.com/s0ulshake))
&
Jérôme ([@jpetazzo](https://twitter.com/jpetazzo))
-->
- Hello! We are Jérôme, Lee, Nicholas, and Scott
<!--
I am
Jérôme ([@jpetazzo](https://twitter.com/jpetazzo))
-->
--
- This is our collective Docker knowledge:
![Bell Curve](images/bell-curve.jpg)
---
## "From zero to hero"
--
- It rhymes, but it's a pretty bad title, to be honest
--
- None of you is a "zero"
--
- None of us is a "hero"
--
- None of us should even try to be a hero
--
*The hero syndrome is a phenomenon affecting people who seek heroism or recognition,
usually by creating a desperate situation which they can resolve.
This can include unlawful acts, such as arson.
The phenomenon has been noted to affect civil servants,
such as firefighters, nurses, police officers, and security guards.*
(Wikipedia page on [hero syndrome](https://en.wikipedia.org/wiki/Hero_syndrome))
---
## Agenda
.small[
- 09:00-09:10 Hello!
- 09:10-10:30 Part 1
- 10:30-11:00 coffee break
- 11:00-12:30 Part 2
- 12:30-13:30 lunch break
- 13:30-15:00 Part 3
- 15:00-15:30 coffee break
- 15:30-17:00 Part 4
- 17:00-18:00 Afterhours and Q&A
]
<!--
- The tutorial will run from 9:00am to 12:20pm
- This will be fast-paced, but DON'T PANIC!
- There will be a coffee break at 10:30am
<br/>
(please remind me if I forget about it!)
-->
- All the content is publicly available (slides, code samples, scripts)
Upstream URL: https://github.com/jpetazzo/orchestration-workshop
- Feel free to interrupt for questions at any time
- Live feedback, questions, help on [Gitter](chat)
http://container.training/chat
- swarm/intro.md
- |
@@TOC@@
- - swarm/prereqs.md
- swarm/versions.md
- |
class: title
All right!
<br/>
We're all set.
<br/>
Let's do this.
- common/sampleapp.md
- swarm/swarmkit.md
- swarm/creatingswarm.md
- swarm/morenodes.md
- - swarm/firstservice.md
- swarm/ourapponswarm.md
- swarm/updatingservices.md
- swarm/healthchecks.md
- - swarm/operatingswarm.md
- swarm/netshoot.md
- swarm/ipsec.md
- swarm/swarmtools.md
- swarm/security.md
- swarm/secrets.md
- swarm/encryptionatrest.md
- swarm/leastprivilege.md
- swarm/apiscope.md
- - swarm/logging.md
- swarm/metrics.md
- swarm/stateful.md
- swarm/extratips.md
- swarm/end.md
- |
class: title
That's all folks! <br/> Questions?
.small[.small[
Jérôme ([@jpetazzo](https://twitter.com/jpetazzo)) — [@docker](https://twitter.com/docker)
]]
<!--
Tiffany ([@tiffanyfayj](https://twitter.com/tiffanyfayj))
AJ ([@s0ulshake](https://twitter.com/s0ulshake))
-->

2
slides/find-non-ascii.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
grep --color=auto -P -n "[^\x00-\x80]" */*.md

View File

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
slides/images/bridge1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
slides/images/bridge2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
slides/images/conductor.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

BIN
slides/images/demo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1,213 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 445 390" enable-background="new 0 0 445 390" xml:space="preserve">
<g>
<path fill="#3A4D54" d="M158.8,352.2h-25.9c3.2,0,5.8-2.6,5.8-5.9s-2.6-5.9-5.8-5.9h-19c3.2,0,5.8-2.6,5.8-5.9s-2.6-5.9-5.8-5.9
h25.3c3.2,0,5.8-2.6,5.8-5.9c0-3.2-2.6-5.9-5.8-5.9h-15.9c3.2,0,5.8-2.6,5.8-5.9s-2.6-5.9-5.8-5.9h6.8c3.2,0,5.8-2.6,5.8-5.9
c0-3.2-2.6-5.9-5.8-5.9H64.9c-0.1,0-0.3,0-0.4,0c3,0.2,5.4,2.7,5.4,5.9c0,3.1-2.4,5.7-5.4,5.9c0.1,0,0.3,0,0.4,0h-0.8h-6.1
c-3.2,0-5.8,2.6-5.8,5.9s2.6,5.9,5.8,5.9H74h3.7c3.2,0,5.8,2.6,5.8,5.9c0,3.2-2.6,5.9-5.8,5.9H74H47.9c-3.2,0-5.8,2.6-5.8,5.9
s2.6,5.9,5.8,5.9h44.8H93c0,0-0.1,0-0.1,0c3.1,0.1,5.6,2.7,5.6,5.9c0,3.2-2.5,5.8-5.6,5.9c0,0,0.1,0,0.1,0h-0.2
c-3.2,0-5.8,2.6-5.8,5.9c0,3.2,2.6,5.9,5.8,5.9h66c3.2,0,5.8-2.6,5.8-5.9C164.6,354.8,162,352.2,158.8,352.2z"/>
<circle fill="#FBBF45" stroke="#3A4D54" stroke-width="4" stroke-miterlimit="10" cx="214.6" cy="124.2" r="68.7"/>
<circle fill="#3A4D54" cx="367.5" cy="335.5" r="5.9"/>
<g>
<polygon fill="#E8593A" stroke="#3A4D54" stroke-width="4" stroke-miterlimit="10" points="116.1,199.1 116.1,214.6 302.9,214.5
302.9,199.1 "/>
<rect x="159.4" y="78.6" fill="#3A4D54" width="4.2" height="50.4"/>
<rect x="174.5" y="93.8" fill="#3A4D54" width="4.2" height="35.1"/>
<rect x="280.2" y="108.2" fill="#3A4D54" width="4.2" height="20.8"/>
<rect x="190.2" y="106.9" fill="#3A4D54" width="4.2" height="22"/>
<rect x="143.3" y="59.8" fill="#3A4D54" width="4.2" height="69.1"/>
<path fill="#3A4D54" d="M294.3,107.9c3.5-2.3,6.9-4.8,10.4-7.4V87.7c-5.2,4.3-10.6,8.2-15.9,11.6c-7.8,4.9-15.1,8.5-22.4,11
c-7.9,2.8-15.7,4.3-23.4,4.7c-7.6,0.3-15.3-0.5-22.8-2.6c-6.9-1.9-13.7-4.7-20.4-8.6C188.8,97.5,178.4,89,168,77.6
c-7.7-8.4-14.7-17.7-21.6-28.2c-5-7.8-9.6-15.8-13.6-23.9c-4-8.1-6.1-13.5-6.9-16c-0.7-1.8-1-3.1-1.2-3.8l0-0.1l0.1-2.7l-0.5,0
l0-0.1H123l-8.1-0.6l-3.1-0.1l-0.1,3.4l0,0.4c0,1.2,0.2,1.9,0.3,2.5l0,0.1c0.3,1.4,0.9,3.2,1.7,5.3c1.2,3.4,3.6,9.1,7.7,17.2
c4.3,8.4,9.2,16.8,14.6,25c7.3,11.1,14.9,20.8,23.2,29.6c11.4,12.1,22.9,21.3,35.1,28.1c7.6,4.2,15.4,7.4,23.2,9.4
c7,1.8,14.2,2.7,21.4,2.7c0,0,0,0,0,0c1.6,0,3.2,0,4.7-0.1c8.7-0.5,17.6-2.4,26.4-5.6 M141.1,52.8c-5.2-7.9-10-16.1-14.2-24.4
c-4-7.9-6.3-13.4-7.5-16.6c-0.5-1.3-0.8-2.4-1.1-3.3l1,0.1c0.3,0.9,0.6,1.9,1,2.9c1.6,4.5,4.2,10.4,7.2,16.6
c4.1,8.3,8.8,16.5,13.9,24.5c5.5,8.5,11.1,16.2,17.1,23.3C152.4,68.9,146.7,61.3,141.1,52.8z"/>
<path fill="#E8593A" stroke="#3A4D54" stroke-width="4" stroke-miterlimit="10" d="M340.9,53h-7.9h-4.3v8.2h-19.4V53h-4.3h-7.9
h-4.3v8.2v2.7v186.7c0,0.8,0.6,1.4,1.3,1.4h3h42.4h4.3c0.7,0,1.3-0.6,1.3-1.4V62v-0.8V53H340.9z M334.8,206.6h-31.5V152
c0-0.4,0.3-0.7,0.6-0.7h30.2c0.4,0,0.6,0.3,0.6,0.7V206.6z M334.8,142.1h-31.5V125c0-0.4,0.3-0.7,0.6-0.7h30.2
c0.4,0,0.6,0.3,0.6,0.7V142.1z M334.8,115.1h-31.5V97.9c0-0.4,0.3-0.7,0.6-0.7h30.2c0.4,0,0.6,0.3,0.6,0.7V115.1z M334.8,88h-31.5
V70.9c0-0.4,0.3-0.7,0.6-0.7h30.2c0.4,0,0.6,0.3,0.6,0.7V88z"/>
<polygon fill="#E8593A" points="272.2,203 286.7,201.1 297.2,201.1 297.2,214.6 271.7,214.6 "/>
<path fill="#E8593A" d="M298.7,96.2c-2.7,2-5.5,3.9-8.3,5.7c-7.3,4.6-15,8.5-23,11.3c-7.9,2.8-16.1,4.5-24.3,4.8
c-8.1,0.4-16.1-0.6-23.7-2.7c-7.6-2-14.6-5.1-21.1-8.9c-13-7.5-23.7-17.1-32.6-26.8c-8.9-9.8-16-19.6-21.9-28.6
c-5.8-9-10.3-17.3-13.7-24.2c-3.4-6.9-5.7-12.5-7.1-16.3c-0.7-1.9-1.1-3.3-1.3-4.2c-0.1-0.4-0.1-0.7-0.1-0.4l0,0.1
c0,0,0-0.1,0-0.1c0-0.1,0-0.1,0-0.1c0-0.1,0-0.1,0-0.1l-7-0.5c0,0,0,0,0,0.1c0,0,0,0.1,0,0.1c0,0,0,0.1,0,0.1c0,0.1,0,0.2,0,0.3
c0,0.9,0.1,1.4,0.3,2.1c0.3,1.3,0.8,2.9,1.6,5c1.5,4.1,4,9.8,7.6,16.9c3.6,7.1,8.3,15.5,14.4,24.7c6.1,9.2,13.5,19.2,22.9,29.2
c9.3,9.9,20.5,19.8,34.3,27.5c6.9,3.8,14.4,7,22.5,9.1c8,2.1,16.6,3,25.2,2.5c8.6-0.5,17.3-2.4,25.5-5.4c8.3-3,16.2-7.2,23.7-12
c2-1.3,4.1-2.7,6-4.2V96.2z"/>
<path fill="#E8593A" stroke="#3A4D54" stroke-width="4" stroke-miterlimit="10" d="M122.9,4.2h-3.2h-6.6v11.7H66.1V4.2h-4.6h-6.2
h-6.6v11.7v3.8v265.1c0,1.1,0.9,2,2,2h4.6h65.7h6.6c1.1,0,2-0.9,2-2V17v-1.1V4.2H122.9z M113.5,204.2H64.7v-59.4c0-0.6,0.4-1,1-1
h46.7c0.6,0,1,0.4,1,1V204.2z M113.5,130.8H64.7v-24.3c0-0.6,0.4-1,1-1h46.7c0.6,0,1,0.4,1,1V130.8z M113.5,92.4H64.7V68.1
c0-0.6,0.4-1,1-1h46.7c0.6,0,1,0.4,1,1V92.4z M113.5,54H64.7V29.7c0-0.6,0.4-1,1-1h46.7c0.6,0,1,0.4,1,1V54z"/>
<g>
<g>
<path fill="#2BB8EB" stroke="#3A4D54" stroke-width="5" stroke-miterlimit="10" d="M435.8,132.9H364c-1.4,0-2.6,1.3-2.6,3v44.2
c0,1.7,1.2,3,2.6,3h71.8c2.5,0,3.6-3.7,1.5-5.4l-11.4-13.5c-3.2-3.3-3.2-9,0-12.3l11.4-13.5
C439.3,136.6,438.3,132.9,435.8,132.9z"/>
<path fill="#FFFFFF" stroke="#3A4D54" stroke-width="5" stroke-miterlimit="10" d="M9.8,183.1h129.7c1.4,0,2.6-1.3,2.6-3v-44.2
c0-1.7-1.2-3-2.6-3H9.8c-2.5,0-3.6,3.7-1.5,5.4l11.4,13.5c3.2,3.3,3.2,9,0,12.3L8.3,177.7C6.2,179.4,7.3,183.1,9.8,183.1z"/>
<path fill="#FFFFFF" stroke="#3A4E55" stroke-width="5" stroke-miterlimit="10" d="M402.5,190H42.1c-3.6,0-6.5-1.1-6.5-4.6
v-54.7c0-3.6,2.9-6.5,6.5-6.5h360.4c3.6,0,6.5,2.9,6.5,6.5v52.9C409,187.1,406.1,190,402.5,190z"/>
<path fill="#2BB8EB" d="M402.5,124.2h-46.3V190h46.3c3.6,0,6.5-2.9,6.5-6.5v-52.9C409,127.1,406.1,124.2,402.5,124.2z"/>
<g>
<path fill="#FFFFFF" d="M376.2,144.3v21.3c0,1.1-0.9,2-2,2c-1.1,0-2-0.9-2-2v-17.8l-1.4,0.8c-0.3,0.2-0.7,0.3-1,0.3
c-0.7,0-1.3-0.4-1.7-1c-0.6-0.9-0.3-2.2,0.7-2.7l4.4-2.6c0,0,0.1,0,0.1-0.1c0.1,0,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0
c0,0,0.1,0,0.1,0c0.1,0,0.2,0,0.3,0c0,0,0.1,0,0.1,0h0c0.1,0,0.2,0,0.3,0c0,0,0.1,0,0.1,0c0.1,0,0.1,0,0.2,0.1c0,0,0.1,0,0.1,0
c0.1,0.1,0.1,0.1,0.2,0.1c0,0,0.1,0.1,0.1,0.1c0,0,0.1,0.1,0.1,0.1c0.1,0,0.1,0.1,0.1,0.1c0,0,0.1,0.1,0.1,0.1
c0,0,0.1,0.1,0.1,0.1l0,0.1c0,0,0,0.1,0,0.1c0,0.1,0.1,0.1,0.1,0.2c0,0.1,0,0.1,0.1,0.2c0,0.1,0,0.1,0,0.2c0,0.1,0,0.2,0.1,0.3
C376.2,144.3,376.2,144.3,376.2,144.3z"/>
<path fill="#FFFFFF" d="M393.4,152.3c1.8,1.7,2.6,4.1,2.6,6.4c0,2.3-0.9,4.6-2.6,6.3c-1.7,1.8-4.1,2.6-6.3,2.6
c-0.1,0-0.1,0-0.1,0c-2.2,0-4.6-0.9-6.3-2.6c-0.8-0.8-0.8-2.1,0-2.9c0.8-0.8,2.1-0.8,2.9,0c0.9,1,2.2,1.4,3.5,1.4
c1.2,0,2.5-0.5,3.4-1.4c0.9-0.9,1.4-2.2,1.4-3.4c0-1.3-0.5-2.5-1.4-3.5c-0.9-1-2.2-1.4-3.4-1.4c-1.2,0-2.5,0.4-3.5,1.4
c-0.8,0.8-2.1,0.8-2.9,0c-0.1-0.1-0.3-0.3-0.4-0.5c0-0.1,0-0.1,0-0.1c0-0.1,0-0.1-0.1-0.2c0-0.1,0-0.2,0-0.3c0,0,0,0,0-0.1
c0-0.2,0-0.4,0-0.6l1.1-9.4c0.1-0.6,0.4-1.1,0.9-1.4c0.1,0,0.1,0,0.1-0.1c0,0,0.1,0,0.1-0.1c0.3-0.1,0.6-0.2,0.9-0.2h9.2
c1.2,0,2.1,0.9,2.1,2.1c0,1.1-0.9,2-2.1,2h-7.4l-0.4,3.6c0.8-0.2,1.6-0.3,2.4-0.3C389.4,149.7,391.7,150.6,393.4,152.3z"/>
</g>
<g>
<path fill="#3A4D54" d="M157.8,142.1L157.8,142.1l-0.9,0c-0.7,0-2.6,2-3,2.5c-1.7,1.7-3.5,3.4-5.2,5.1v-13.7
c0-1.2-0.8-2.2-2-2.2h-0.3c-1.3,0-2,1-2,2.2v29.9c0,1.2,0.8,2.2,2,2.2h0.3c1.3,0,2-1,2-2.2v-5.3l3.4,3.3c1,1,2,2,3,3
c0.5,0.5,1.3,1.3,2.1,1.3h0.4c1.1,0,1.8-0.8,2-1.8l0-0.1v-0.5c0-0.4-0.1-0.7-0.3-1c-0.2-0.3-0.5-0.6-0.7-0.8
c-0.6-0.7-1.2-1.3-1.9-1.9c-2.3-2.3-4.6-4.6-6.9-6.9l5.3-5.4c1-1.1,2.1-2.1,3.1-3.2c0.5-0.5,1.3-1.4,1.3-2.1V144
C159.6,142.9,158.9,142.3,157.8,142.1z"/>
<path fill="#3A4D54" d="M138.9,143.9l-0.2-0.1c-1.9-1.3-4.1-2-6.5-2h-0.9c-2.2,0-4.3,0.6-6.2,1.7c-4.1,2.4-6.5,6.2-6.5,11v0.9
c0,1.1,0.1,2.2,0.5,3.3c1.9,6.3,6.8,9.9,13.4,9.5c1.9-0.1,6.8-0.7,6.8-3.4v-0.4c0-1.1-0.8-1.7-1.8-1.9l-0.1,0h-0.8l-0.2,0.1
c-1.1,0.5-2.7,1.2-3.9,1.2c-1.3,0-2.9-0.1-4.2-0.7c-3.4-1.6-5.4-4.3-5.4-8c0-1.2,0.2-2.4,0.8-3.6c1.6-3.3,4.2-5.3,7.9-5.2
c0.7,0,2,0.1,2.6,0.4c0.6,0.3,2.1,1,2.7,1h0.3l0.1,0c1-0.2,1.9-0.8,1.9-1.9v-0.4c0-0.4-0.2-0.8-0.4-1.2L138.9,143.9z"/>
<path fill="#3A4D54" d="M85.2,133.7h-0.4c-1.3,0-2,1-2,2.2v9.3c-2.3-2-5.1-3.3-8.3-3.3h-0.9c-2.2,0-4.3,0.6-6.2,1.7
c-4.1,2.4-6.5,6.2-6.5,11v0.9c0,2.2,0.6,4.3,1.7,6.2c2.4,4.1,6.2,6.5,11,6.5h0.9c2.2,0,4.3-0.6,6.2-1.7c4.1-2.4,6.5-6.2,6.5-11
v-19.6C87.2,134.6,86.5,133.7,85.2,133.7z M81.6,159.3c-1.7,2.9-4.2,4.5-7.6,4.5c-1.4,0-2.7-0.4-3.9-1c-3-1.7-4.7-4.3-4.7-7.7
c0-1.2,0.2-2.4,0.8-3.6c1.6-3.3,4.3-5.2,8-5.2c1.8,0,3.4,0.5,4.9,1.6c2.4,1.7,3.8,4.1,3.8,7.1C82.8,156.5,82.4,158,81.6,159.3z
"/>
<path fill="#3A4D54" d="M103.1,141.9h-0.6c-2.2,0-4.3,0.6-6.2,1.7c-4.1,2.4-6.5,6.2-6.5,11v0.9c0,2.2,0.6,4.3,1.7,6.2
c2.4,4.1,6.2,6.5,11,6.5h0.9c2.2,0,4.3-0.6,6.2-1.7c4.1-2.4,6.5-6.2,6.5-11v-0.9c0-2-0.5-4-1.5-5.8
C112.1,144.4,108.2,141.9,103.1,141.9z M110.5,159.3c-1.7,2.8-4.2,4.5-7.5,4.5c-1.6,0-3-0.4-4.3-1.2c-2.8-1.7-4.5-4.2-4.5-7.6
c0-1.2,0.2-2.4,0.8-3.6c1.6-3.3,4.3-5.2,8-5.2c1.7,0,3.3,0.5,4.7,1.4c2.6,1.7,4.1,4.1,4.1,7.2
C111.7,156.5,111.3,158,110.5,159.3z"/>
<path fill="#3A4D54" d="M186.4,148c-1.2-2.1-3-3.7-5.2-4.8c-4-2-8.3-2.2-12.2,0.1l-0.6,0.3c-1.6,0.9-3,2.1-4,3.6
c-3,4.4-3.4,9.3-0.7,14l0.3,0.5c1.1,2,2.7,3.6,4.6,4.6c4.2,2.3,8.6,2.6,12.8,0.2l0.4-0.2c1.1-0.7,1.4-1.8,0.8-3
c-0.2-0.5-0.7-0.8-1.2-1.1l-0.1-0.1l-0.1,0c-0.8-0.1-2.9,0.8-3.8,1.2c-1.6,0.3-3.5,0.4-5.1-0.2c2.9-2.5,5.8-5.1,8.8-7.6
c1.3-1.1,2.7-2.4,4.1-3.5c1.2-0.9,2.3-2.2,1.4-3.8L186.4,148z M178.4,152.1c-3.3,2.8-6.5,5.6-9.8,8.4c-0.3-0.4-0.6-0.8-0.9-1.2
c-0.7-1.2-1.1-2.5-1.1-3.9c-0.1-3.5,1.2-6.3,4.2-8.1c2.3-1.3,4.8-1.7,7.4-0.7c1.3,0.5,2.7,1.3,3.6,2.4
C180.7,150.2,179.5,151.2,178.4,152.1z"/>
<path fill="#3A4D54" d="M204.2,142.1h-0.4c-2.6,0-5,0.8-7.1,2.3c-3.5,2.5-5.6,6-5.6,10.4V166c0,1.2,0.8,2.2,2,2.2h0.3
c1.3,0,2-1,2-2.2v-10.7c0-2.4,0.7-4.5,2.4-6.2c1.4-1.3,3.3-2.5,5.2-2.5c1.5,0,3.3-0.5,3.3-2.3
C206.4,142.9,205.5,142.1,204.2,142.1z"/>
</g>
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#2BB8EB" d="M281.3,146.6c-0.7-0.3-1.9-0.4-2.6-0.4
c-3.7-0.1-6.4,1.9-7.9,5.2c-0.5,1.1-0.8,2.3-0.8,3.6c0,3.8,2,6.4,5.4,8c1.2,0.6,2.8,0.7,4.2,0.7c1.2,0,2.9-0.7,3.9-1.2l0.2-0.1
h0.8l0.1,0c1,0.2,1.8,0.8,1.8,1.9v0.4c0,2.7-4.9,3.3-6.8,3.4c-6.6,0.5-11.6-3.2-13.4-9.5c-0.3-1.1-0.5-2.2-0.5-3.3v-0.9
c0-4.8,2.4-8.6,6.5-11c1.9-1.1,4-1.7,6.2-1.7h0.9c2.4,0,4.5,0.7,6.5,2l0.2,0.1l0.1,0.2c0.2,0.3,0.4,0.7,0.4,1.2v0.4
c0,1.1-0.8,1.7-1.9,1.9l-0.1,0H284C283.4,147.6,281.9,146.9,281.3,146.6z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#2BB8EB" d="M301.3,141.9h0.6c5.1,0,9,2.5,11.5,6.9c1,1.8,1.5,3.7,1.5,5.8
v0.9c0,4.8-2.4,8.6-6.5,11c-1.9,1.1-4,1.7-6.2,1.7h-0.9c-4.8,0-8.6-2.4-11-6.5c-1.1-1.9-1.7-4-1.7-6.2v-0.9
c0-4.8,2.4-8.6,6.5-11C297,142.4,299.1,141.9,301.3,141.9z M293,155c0,3.4,1.6,5.8,4.5,7.6c1.3,0.8,2.8,1.2,4.3,1.2
c3.3,0,5.8-1.7,7.5-4.5c0.8-1.3,1.2-2.8,1.2-4.4c0-3.1-1.5-5.5-4.1-7.2c-1.4-0.9-3-1.4-4.7-1.4c-3.7,0-6.4,1.9-8,5.2
C293.3,152.6,293,153.8,293,155z"/>
<path fill="#2BB8EB" d="M344,148.8c-2.5-4.5-6.4-6.9-11.5-6.9h-0.6c-2.2,0-4.3,0.6-6.2,1.7c-4.1,2.4-6.5,6.2-6.5,11v0.3v11
c0,1.2,0.8,2.2,2,2.2h0.3c1.3,0,2-1,2-2.2v-11h0c0-1.2,0.3-2.4,0.8-3.5c1.6-3.3,4.3-5.2,8-5.2c1.7,0,3.3,0.5,4.7,1.4
c2.6,1.7,4.1,4.1,4.1,7.2v11c0,1.2,0.8,2.2,2,2.2h0.3c1.3,0,2-1,2-2.2v-11v-0.3C345.5,152.6,345,150.6,344,148.8z"/>
</g>
</g>
<path fill="none" stroke="#3A4D54" stroke-width="5" stroke-miterlimit="10" d="M402.5,190H42.1c-3.6,0-6.5-2.9-6.5-6.5v-52.9
c0-3.6,2.9-6.5,6.5-6.5h360.4c3.6,0,6.5,2.9,6.5,6.5v52.9C409,187.1,406.1,190,402.5,190z"/>
</g>
<polygon fill="#E8593A" points="147.8,203 133.3,201.1 122.8,201.1 122.8,214.6 148.3,214.6 "/>
<rect x="353.6" y="124.2" fill="#3A4D54" width="5.1" height="55.2"/>
</g>
<g>
<path fill="#3A4D54" d="M91.8,293.4H20.2c-3.2,0-5.8-2.6-5.8-5.9s2.6-5.9,5.8-5.9h71.6c3.2,0,5.8,2.6,5.8,5.9S95,293.4,91.8,293.4
z"/>
</g>
<path fill="#3A4D54" d="M428.9,282.7h-83c-3.2,0-5.8,2.6-5.8,5.9c0,3.2,2.6,5.9,5.8,5.9h-54.7c-3.2,0-5.8,2.6-5.8,5.9
c0,3.2,2.6,5.9,5.8,5.9H308c-3.2,0-5.8,2.6-5.8,5.9c0,3.2,2.6,5.9,5.8,5.9h-28.9c-3.2,0-5.8,2.6-5.8,5.9c0,3.2,2.6,5.9,5.8,5.9H262
c-3.2,0-5.8,2.6-5.8,5.9s2.6,5.9,5.8,5.9h13.7c-3.2,0-5.8,2.6-5.8,5.9s2.6,5.9,5.8,5.9h-37.8c-3.2,0-5.8,2.6-5.8,5.9
c0,3,2.2,5.5,5.1,5.8h-48.8c-0.9-0.6-2-1-3.2-1h-47.1c3.2,0,5.8,2.6,5.8,5.9c0,3.2-2.6,5.9-5.8,5.9h-2.8c-3.2,0-5.8,2.9-5.8,6.4
c0,3.5,2.6,6.4,5.8,6.4h58.5h7.5H286c3.2,0,5.8-2.6,5.8-5.9c0-3.2-2.6-5.9-5.8-5.9H286h-2.7c-3.2,0-5.8-2.6-5.8-5.9
c0-3.2,2.6-5.9,5.8-5.9h66c0.2,0,0.4,0,0.6,0h6.7c3.2,0,5.8-2.6,5.8-5.9c0-3.2-2.6-5.9-5.8-5.9h-27.2c0,0,0,0,0,0h-0.7
c-3.2,0-5.8-2.6-5.8-5.9c0-3.2,2.6-5.9,5.8-5.9h0.7h14.1c3.2,0,5.8-2.6,5.8-5.9s-2.6-5.9-5.8-5.9h0.2c-3.2,0-5.8-2.6-5.8-5.9
c0-3.2,2.6-5.9,5.8-5.9h0.7h28.9c3.2,0,5.8-2.6,5.8-5.9c0-3.2-2.6-5.9-5.8-5.9h-16.1h-0.8c0.1,0,0.3,0,0.4,0
c-3-0.2-5.4-2.7-5.4-5.9c0-3.1,2.4-5.7,5.4-5.9c-0.1,0-0.3,0-0.4,0h0.8h65.2h6.5c3.2,0,5.8-2.6,5.8-5.9
C434.6,285.3,432.1,282.7,428.9,282.7z"/>
<g>
<path id="outline_3_" fill-rule="evenodd" clip-rule="evenodd" fill="#3A4D54" d="M258,210.8h37v37.8h18.7
c8.6,0,17.5-1.5,25.7-4.3c4-1.4,8.5-3.3,12.5-5.6c-5.2-6.8-7.9-15.4-8.7-23.9c-1.1-11.5,1.3-26.5,9.1-35.6l3.9-4.5l4.6,3.7
c11.7,9.4,21.5,22.5,23.2,37.4c14-4.1,30.5-3.2,42.9,4l5.1,2.9l-2.7,5.2c-10.5,20.4-32.3,26.7-53.7,25.6
C343.5,333.3,273.8,371,189.4,371c-43.6,0-83.7-16.3-106.5-55l-0.4-0.6l-3.3-6.8c-7.7-17-10.3-35.7-8.5-54.4l0.5-5.6h31.6v-37.8
h37v-37h73.9v-37H258V210.8z"/>
<g id="body_colors_3_">
<path fill="#08AADA" d="M377.8,224.8c2.5-19.3-11.9-34.4-20.9-41.6c-10.3,11.9-11.9,43.1,4.3,56.3c-9,8-28,15.3-47.5,15.3H76.8
c-1.9,20.3,1.7,39,9.8,55l2.7,4.9c1.7,2.9,3.6,5.7,5.6,8.4h0c9.7,0.6,18.7,0.8,26.9,0.7c0,0,0,0,0,0c16.1-0.4,29.3-2.3,39.3-5.7
c1.5-0.5,3.1,0.3,3.6,1.8c0.5,1.5-0.3,3.1-1.8,3.6c-1.3,0.5-2.7,0.9-4.1,1.3c0,0,0,0,0,0c-7.9,2.2-16.3,3.8-27.2,4.4
c0.6,0-0.7,0.1-0.7,0.1c-0.4,0-0.8,0.1-1.2,0.1c-4.3,0.2-8.9,0.3-13.6,0.3c-5.2,0-10.3-0.1-15.9-0.4l-0.1,0.1
c19.7,22.2,50.6,35.5,89.3,35.5c81.9,0,151.3-36.3,182.1-117.8c21.8,2.2,42.8-3.3,52.3-21.9C408.6,216.4,389,219.2,377.8,224.8z"
/>
<path fill="#2BB8EB" d="M377.8,224.8c2.5-19.3-11.9-34.4-20.9-41.6c-10.3,11.9-11.9,43.1,4.3,56.3c-9,8-28,15.3-47.5,15.3H90.8
c-1,31.1,10.6,54.7,31,69c0,0,0,0,0,0c16.1-0.4,29.3-2.3,39.3-5.7c1.5-0.5,3.1,0.3,3.6,1.8c0.5,1.5-0.3,3.1-1.8,3.6
c-1.3,0.5-2.7,0.9-4.1,1.3c0,0,0,0,0,0c-7.9,2.2-17,3.9-27.9,4.6c0,0-0.3-0.3-0.3-0.3c27.9,14.3,68.3,14.2,114.6-3.6
c51.9-20,100.3-58,134-101.5C378.8,224.3,378.3,224.6,377.8,224.8z"/>
<path fill="#088CB9" d="M76.6,279.5c1.5,10.9,4.7,21.1,9.4,30.4l2.7,4.9c1.7,2.9,3.6,5.7,5.6,8.4c9.7,0.6,18.7,0.8,26.9,0.7
c16.1-0.4,29.3-2.3,39.3-5.7c1.5-0.5,3.1,0.3,3.6,1.8c0.5,1.5-0.3,3.1-1.8,3.6c-1.3,0.5-2.7,0.9-4.1,1.3c0,0,0,0,0,0
c-7.9,2.2-17,3.9-27.8,4.5c-0.4,0-1,0-1.4,0c-4.3,0.2-8.9,0.4-13.6,0.4c-5.2,0-10.4-0.1-16.1-0.4c19.7,22.2,50.8,35.5,89.5,35.5
c70.1,0,131.1-26.6,166.5-85.4H76.6z"/>
<path fill="#069BC6" d="M92.9,279.5c4.2,19.1,14.3,34.1,28.9,44.3c16.1-0.4,29.3-2.3,39.3-5.7c1.5-0.5,3.1,0.3,3.6,1.8
c0.5,1.5-0.3,3.1-1.8,3.6c-1.3,0.5-2.7,0.9-4.1,1.3c0,0,0,0,0,0c-7.9,2.2-17.2,3.9-28,4.5c27.9,14.3,68.2,14.1,114.5-3.7
c28-10.8,55-26.8,79.2-46.1H92.9z"/>
</g>
<g id="Containers_3_">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#00ACD2" d="M135.8,219.7h2.5v26.7h-2.5V219.7z M130.9,219.7h2.6v26.7h-2.6
V219.7z M126.1,219.7h2.6v26.7h-2.6V219.7z M121.2,219.7h2.6v26.7h-2.6V219.7z M116.3,219.7h2.6v26.7h-2.6V219.7z M111.6,219.7
h2.5v26.7h-2.5V219.7z M108.9,217h32v32h-32V217z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#00ACD2" d="M172.7,182.7h2.5v26.7h-2.5V182.7z M167.9,182.7h2.6v26.7h-2.6
V182.7z M163,182.7h2.6v26.7H163V182.7z M158.2,182.7h2.6v26.7h-2.6V182.7z M153.3,182.7h2.6v26.7h-2.6V182.7z M148.6,182.7h2.5
v26.7h-2.5V182.7z M145.9,180h32v32h-32V180z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#26C2EE" d="M172.7,219.7h2.5v26.7h-2.5V219.7z M167.9,219.7h2.6v26.7h-2.6
V219.7z M163,219.7h2.6v26.7H163V219.7z M158.2,219.7h2.6v26.7h-2.6V219.7z M153.3,219.7h2.6v26.7h-2.6V219.7z M148.6,219.7h2.5
v26.7h-2.5V219.7z M145.9,217h32v32h-32V217z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#00ACD2" d="M209.7,219.7h2.5v26.7h-2.5V219.7z M204.8,219.7h2.6v26.7h-2.6
V219.7z M200,219.7h2.6v26.7H200V219.7z M195.1,219.7h2.6v26.7h-2.6V219.7z M190.3,219.7h2.6v26.7h-2.6V219.7z M185.5,219.7h2.5
v26.7h-2.5V219.7z M182.9,217h32v32h-32V217z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#26C2EE" d="M209.7,182.7h2.5v26.7h-2.5V182.7z M204.8,182.7h2.6v26.7h-2.6
V182.7z M200,182.7h2.6v26.7H200V182.7z M195.1,182.7h2.6v26.7h-2.6V182.7z M190.3,182.7h2.6v26.7h-2.6V182.7z M185.5,182.7h2.5
v26.7h-2.5V182.7z M182.9,180h32v32h-32V180z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#26C2EE" d="M246.7,219.7h2.5v26.7h-2.5V219.7z M241.8,219.7h2.6v26.7h-2.6
V219.7z M237,219.7h2.6v26.7H237V219.7z M232.1,219.7h2.6v26.7h-2.6V219.7z M227.3,219.7h2.6v26.7h-2.6V219.7z M222.5,219.7h2.5
v26.7h-2.5V219.7z M219.8,217h32v32h-32V217z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#00ACD2" d="M246.7,182.7h2.5v26.7h-2.5V182.7z M241.8,182.7h2.6v26.7h-2.6
V182.7z M237,182.7h2.6v26.7H237V182.7z M232.1,182.7h2.6v26.7h-2.6V182.7z M227.3,182.7h2.6v26.7h-2.6V182.7z M222.5,182.7h2.5
v26.7h-2.5V182.7z M219.8,180h32v32h-32V180z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#26C2EE" d="M246.7,145.7h2.5v26.7h-2.5V145.7z M241.8,145.7h2.6v26.7h-2.6
V145.7z M237,145.7h2.6v26.7H237V145.7z M232.1,145.7h2.6v26.7h-2.6V145.7z M227.3,145.7h2.6v26.7h-2.6V145.7z M222.5,145.7h2.5
v26.7h-2.5V145.7z M219.8,143.1h32v32h-32V143.1z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#00ACD2" d="M283.6,219.7h2.5v26.7h-2.5V219.7z M278.8,219.7h2.6v26.7h-2.6
V219.7z M273.9,219.7h2.6v26.7h-2.6V219.7z M269.1,219.7h2.6v26.7h-2.6V219.7z M264.2,219.7h2.6v26.7h-2.6V219.7z M259.5,219.7
h2.5v26.7h-2.5V219.7z M256.8,217h32v32h-32V217z"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#D4EDF1" d="M175.9,301c4.9,0,8.8,4,8.8,8.8s-4,8.8-8.8,8.8
c-4.9,0-8.8-4-8.8-8.8S171,301,175.9,301"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#3A4D54" d="M175.9,303.5c0.8,0,1.6,0.2,2.3,0.4c-0.8,0.4-1.3,1.3-1.3,2.2
c0,1.4,1.2,2.6,2.6,2.6c1,0,1.8-0.5,2.3-1.3c0.3,0.7,0.5,1.6,0.5,2.4c0,3.5-2.8,6.3-6.3,6.3c-3.5,0-6.3-2.8-6.3-6.3
C169.6,306.3,172.4,303.5,175.9,303.5"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#3A4D54" d="M19.6,282.7h193.6h23.9h190.5c0.4,0,1.6,0.1,1.2,0
c-9.2-2.2-24.9-6.2-23.5-15.8c0.1-0.7-0.2-0.8-0.6-0.3c-16.6,17.5-54.1,12.2-64.3,3.2c-0.2-0.1-0.4-0.1-0.5,0.1
c-11.5,15.4-73.3,9.7-79.3-2.3c-0.1-0.2-0.4-0.3-0.6-0.1c-14.1,15.7-55.7,15.7-69.8,0c-0.2-0.2-0.5-0.1-0.6,0.1
c-6,12-67.8,17.7-79.3,2.3c-0.1-0.2-0.3-0.2-0.5-0.1c-10.1,8.9-44.5,14.3-61.2-3c-0.3-0.3-0.8-0.1-0.8,0.4
C48.9,277.6,28.1,280.5,19.6,282.7"/>
<path fill="#C0DBE0" d="M199.4,364.7c-21.9-10.4-33.9-24.5-40.6-39.9c-8.1,2.3-17.9,3.8-29.3,4.4c-4.3,0.2-8.8,0.4-13.5,0.4
c-5.4,0-11.2-0.2-17.2-0.5c20.1,20.1,44.8,35.5,90.5,35.8C192.7,364.9,196.1,364.8,199.4,364.7z"/>
<path fill="#D4EDF1" d="M167,339c-3-4.1-6-9.3-8.1-14.2c-8.1,2.3-17.9,3.8-29.3,4.4C137.4,333.4,148.5,337.4,167,339z"/>
</g>
<circle fill="#3A4D54" cx="34.8" cy="311" r="5.9"/>
<path fill="#3A4D54" d="M346.8,297.2l-1-2.8c0,0,5.3-11.7-7.4-11.7c-12.7,0,3.5-4.7,3.5-4.7l21.8,2.8l9.6,6.8l-16.1,4.1
L346.8,297.2z"/>
<path fill="#3A4D54" d="M78.7,297.2l1-2.8c0,0-5.3-11.7,7.4-11.7s-3.5-4.7-3.5-4.7l-21.8,2.8l-9.6,6.8l16.1,4.1L78.7,297.2z"/>
<path fill="#3A4D54" d="M361.7,279.5v4.4l15.6,6.7l45.5-4.1l7.3-3.7c0,0-3.8-0.6-7.3-1.7c-3.6-1.1-15.2-1.6-15.2-1.6h-28.3
l-13.6,1.8L361.7,279.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
slides/images/fu-face.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 350 KiB

View File

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 155 KiB

View File

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

View File

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

View File

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

BIN
slides/images/tangram.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
slides/images/tesla.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

BIN
slides/images/tetris-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
slides/images/tetris-2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 KiB

BIN
slides/images/tetris-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

Before

Width:  |  Height:  |  Size: 927 KiB

After

Width:  |  Height:  |  Size: 927 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 190 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 595 KiB

After

Width:  |  Height:  |  Size: 595 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Some files were not shown because too many files have changed in this diff Show More