Compare commits

..

225 Commits

Author SHA1 Message Date
Jerome Petazzoni
de074e9da5 Remove cards mention 2020-05-07 14:55:09 +02:00
Jerome Petazzoni
ba826cbb99 Fix Smaïne twitter link 2020-05-07 14:53:16 +02:00
Jerome Petazzoni
b62afded35 end slide with link to form and training 2020-05-07 14:50:26 +02:00
Jerome Petazzoni
e29f24453a Add Smaïne 2020-05-07 14:04:49 +02:00
Jerome Petazzoni
db4f73ab84 Merge branch 'master' into 2020-05-helm 2020-05-07 13:24:53 +02:00
Jerome Petazzoni
eb9052ae9a Add twitch chat info 2020-05-07 13:24:35 +02:00
Jerome Petazzoni
c8f04c9b3b merge + add chat link 2020-05-07 13:13:08 +02:00
Jerome Petazzoni
8f85332d8a Advanced Dockerfiles -> Advanced Dockerfile Syntax 2020-05-06 17:25:03 +02:00
Jerome Petazzoni
0479ad2285 Add force redirects 2020-05-06 17:22:13 +02:00
Jerome Petazzoni
986d7eb9c2 Add foreword to operators design section 2020-05-05 17:24:05 +02:00
Jerome Petazzoni
3fafbb8d4e Add kustomize CLI and completion 2020-05-04 16:47:26 +02:00
Jerome Petazzoni
5a24df3fd4 Add details on Kustomize 2020-05-04 16:25:35 +02:00
Jerome Petazzoni
1bbfba0531 Add definition of idempotent 2020-05-04 02:18:05 +02:00
Jerome Petazzoni
8d98431ba0 Add Helm graduation status 2020-05-04 02:09:00 +02:00
Jerome Petazzoni
c31c81a286 Allow overriding YAML desc through env vars 2020-05-04 00:54:34 +02:00
Jerome Petazzoni
a0314fc5f5 Keep --restart=Never for folks running 1.17- 2020-05-03 17:08:32 +02:00
Jérôme Petazzoni
3f088236a4 Merge pull request #557 from barpilot/psp
psp: update deprecated parts
2020-05-03 17:07:41 +02:00
Jerome Petazzoni
ce4e2ffe46 Add sleep command in init container example
It can be tricky to illustrate what's going on here, since installing
git and cloning the repo can be so fast. So we're sleeping a few seconds
to help with this demo and make it easier to show the race condition.
2020-05-03 17:01:59 +02:00
Jérôme Petazzoni
c3a05a6393 Merge pull request #558 from barpilot/vol-init
volume: add missing pod nginx-with-init creating
2020-05-03 16:57:46 +02:00
Jerome Petazzoni
40b2b8e62e Fix deployment name in labels/selector intro
(Fixes #552)
2020-05-03 16:53:25 +02:00
Jerome Petazzoni
efdcf4905d Bump up Kubernetes dashboard to 2.0.0 2020-05-03 16:01:19 +02:00
Jérôme Petazzoni
bdb57c05b4 Merge pull request #550 from BretFisher/patch-20
update k8s dashboard versions
2020-05-03 15:55:15 +02:00
Jerome Petazzoni
af0762a0a2 Remove ':' from file names
Colons are not allowed in file names on Windows. Let's use
something else instead.

(Initially reported by @DenisBalan. This closes #549.)
2020-05-03 15:49:37 +02:00
Jerome Petazzoni
0d6c364a95 Add MacPorts instructions for stern 2020-05-03 13:40:01 +02:00
Jerome Petazzoni
690a1eb75c Move Ardan Live 2020-05-01 15:37:57 -05:00
Jerome Petazzoni
8c503f1e69 Prep helm slides 2020-05-01 10:42:36 -05:00
Jérôme Petazzoni
c796a6bfc1 Merge pull request #556 from barpilot/healthcheck
healthcheck: fix rng manifest filename
2020-04-30 22:51:37 +02:00
Jerome Petazzoni
0b10d3d40d Add a bunch of other managed offerings 2020-04-30 15:50:24 -05:00
Jérôme Petazzoni
cdb50925da Merge pull request #554 from barpilot/installer
separate managed options from deployment
2020-04-30 22:47:22 +02:00
Jérôme Petazzoni
ca1f8ec828 Merge pull request #553 from barpilot/kubeadm
Remove experimental status on kubeadm HA
2020-04-30 22:46:33 +02:00
Jerome Petazzoni
7302d3533f Use built-in dockercoins manifest instead of separate kubercoins repo 2020-04-30 15:45:12 -05:00
Jerome Petazzoni
d3c931e602 Add separate instructions for Zoom webinar 2020-04-30 15:42:41 -05:00
Guilhem Lettron
7402c8e6a8 psp: update psp apiVersion to policy/v1beta1 2020-04-29 22:46:33 +02:00
Guilhem Lettron
1de539bff8 healthcheck: fix rng manifest filename 2020-04-29 22:41:15 +02:00
Guilhem Lettron
a6c7d69986 volume: add missing pod nginx-with-init creating 2020-04-29 22:37:49 +02:00
Guilhem Lettron
b0bff595cf psp: update generator helpers
kubectl run →  kubectl create deployment
kubectl run --restart=Never → kubectl run
2020-04-29 22:33:34 +02:00
Jerome Petazzoni
6f806ed200 typo 2020-04-28 14:23:52 -05:00
Jerome Petazzoni
0c8b20f6b6 typo 2020-04-28 14:21:31 -05:00
Jerome Petazzoni
2ba35e1f8d typo 2020-04-28 14:20:22 -05:00
Jerome Petazzoni
eb0d9bed2a Update descriptions 2020-04-28 06:18:59 -05:00
Jerome Petazzoni
bab493a926 Update descriptions 2020-04-28 06:17:21 -05:00
Guilhem Lettron
f4f2d83fa4 separate managed options from deployment 2020-04-27 20:55:23 +02:00
Guilhem Lettron
9f049951ab Remove experimental status on kubeadm HA 2020-04-27 20:47:30 +02:00
Jerome Petazzoni
7257a5c594 Add outline tags to Kubernetes course 2020-04-27 07:35:14 -05:00
Jerome Petazzoni
102aef5ac5 Add outline tags to Docker short course 2020-04-26 11:36:50 -05:00
Jerome Petazzoni
d2b3a1d663 Add Ardan Live 2020-04-23 08:46:56 -05:00
Jerome Petazzoni
d84ada0927 Fix slides counter 2020-04-23 07:33:46 -05:00
Jerome Petazzoni
0e04b4a07d Modularize logistics file and add logistics-online file 2020-04-20 15:51:02 -05:00
Jerome Petazzoni
aef910b4b7 Do not show 'Module 1' if there is only one module 2020-04-20 13:01:06 -05:00
Jerome Petazzoni
298b6db20c Rename 'chapter' into 'module' 2020-04-20 11:49:35 -05:00
Jerome Petazzoni
7ec6e871c9 Add shortlink container.training/next 2020-04-15 13:17:03 -05:00
Jerome Petazzoni
a0558e4ee5 Rework kubectl run section, break it down
We now have better explanations on labels and selectors.
The kubectl run section was getting very long, so now
it is different parts: kubectl run basics; how to create
other resources like batch jobs; first contact with
labels and annotations; and showing the limitations
of kubectl logs.
2020-04-08 18:29:59 -05:00
Jerome Petazzoni
16a62f9f84 Really dirty script to add force redirects 2020-04-07 17:00:53 -05:00
Jerome Petazzoni
454843b755 Bump up versions 2020-04-02 07:39:10 -05:00
Jerome Petazzoni
63e68ab720 Update kubectl run to kubectl create deploy 2020-03-31 09:09:24 -05:00
Jerome Petazzoni
46f0bc0dfb Update kubectl run slideshow 2020-03-31 08:53:49 -05:00
Jerome Petazzoni
16bb3f1847 Split out chat room instructions for in-person vs online
Add instructions specific to Zoom, explaining how to
use the chat room and the non-verbal communication cues
2020-03-29 09:30:11 -05:00
Jerome Petazzoni
fef3fa31fb Update for Kubernetes 1.18 kubectl run
In Kubernetes 1.18, `kubectl run` no longer creates
a Deployment, and cannot create Jobs or CronJobs
anymore. It only creates Pods. Since we were using
`kubectl run` to create our first Deployment, I've
changed the materials to explain that change, and
explain how the behavior differs between 1.17- and
1.18+, since I expect that people will deal with
a mix of both scenarios for a while (at least a
year).
2020-03-28 13:53:45 -05:00
Jerome Petazzoni
b844e40372 Refactor card generation
Many improvements. QR code, fixed page size, better
use of page estate, etc.

Also pdfkit should kind of work now (not quite using
the full page size, but at least it's not utterly
broken like before).
2020-03-20 13:56:50 -05:00
Jerome Petazzoni
5b5d5946e8 Add logic for QRCode on back of cards 2020-03-20 08:24:58 -05:00
Jerome Petazzoni
af6705fb1e Add script to map DNS
This script needs:
- a list of domains managed by GANDI LiveDNS
- a list of IP addresses of clusters (like in tags/*/ips.txt)

It will replace the current configuration for these
domains so that they point to the clusters.

The apex of each domain and a wildcard entry will
have round-robin records pointing to all the nodes
of the cluster.

In addition, there will be records node[1234...]
pointing to each individual node.
2020-03-19 17:15:43 -05:00
Jerome Petazzoni
bfd63c16c6 Add tailhist to start a websocket server showing bash history on port 1088 2020-03-19 15:49:50 -05:00
Bret Fisher
2ce50007d2 update k8s dashboard versions 2020-03-16 17:57:41 -04:00
Jerome Petazzoni
c506038682 Add QCON slides; tweak title 2020-03-05 02:01:17 -06:00
Jerome Petazzoni
7d8fdd43bd Improve exec syntax section 2020-03-02 21:47:58 -06:00
Jerome Petazzoni
adf0f53aab Update coupons 2020-02-29 11:46:27 -06:00
Jérôme Petazzoni
49fe1b8e17 Merge pull request #547 from tiffanyfay/master-typo
Fix resource typo in k8s slides
2020-02-26 00:01:20 -06:00
tiffany jernigan
073a5f8c84 Fix resource typo in k8s slides 2020-02-25 21:15:01 -08:00
Jerome Petazzoni
032803806d Refactor 'last words' slides 2020-02-24 20:38:01 -06:00
Jerome Petazzoni
f7b327a33a Streamline title slide 2020-02-24 19:00:41 -06:00
Jerome Petazzoni
d3526aac00 Add exercises 2020-02-22 07:43:27 -06:00
Jerome Petazzoni
3736dd6e86 Add 2-day container course 2020-02-19 10:00:24 -06:00
Jerome Petazzoni
c03f199023 Add reference to resource monitoring tools 2020-02-17 04:56:43 -06:00
Jerome Petazzoni
8ba9c2e41b Reorg admin content
Split network interconnect in separate section
2020-02-09 15:12:55 -06:00
Jerome Petazzoni
36d1199b70 Upgrade from 1.15 to illustrate version skipping + retry logic
Instead of upgrading from 1.16 to <latest> we upgrade from 1.15
to 1.16, because upgrading from <latest-1> is a special case and
it is better to show the general case.

Also, the script that sets up admin clusters now has some retry
logic to accommodate hiccups in pssh or in the cloud provider.
2020-02-09 11:29:05 -06:00
Jerome Petazzoni
56e09eef6d Bump up kube ops versions
- Kubernetes binaries installed for ops labs bumped up to 1.17.2
- Composed-based control plane bumped up to 1.17.2
- kuberouter now uses apps/v1 DaemonSet (compatible with 1.16+)
- disable containerd (cosmetic)
2020-02-09 10:37:03 -06:00
Jerome Petazzoni
15f71506b6 Rewrite section about PV and PVC 2020-02-09 10:06:09 -06:00
Jerome Petazzoni
5eb8453597 Add namespace info to YAML section 2020-02-09 07:19:17 -06:00
Jerome Petazzoni
65ee4e3885 Streamline 1-day docker course 2020-02-09 07:05:47 -06:00
Jerome Petazzoni
ac801746eb Add OpenAPI / Swagger info 2020-02-09 06:26:15 -06:00
Jerome Petazzoni
0af16b98c9 Fix CRDs
Use v1beta1 for the first example (it's a bit simpler) and v1 for the second example.
The second example illustrate the served and storage attributes, and the fact that
each version can have a different schema.

Closes #541
2020-02-08 08:54:34 -06:00
Arthur Lutz
2fde58a3ee [cluster-backup] add bivac
Backup Interface for Volumes Attached to Containers
2020-02-08 08:43:21 -06:00
Arthur Lutz
38fec0b00d [extending-api] link to video, not playlist 2020-02-08 08:41:24 -06:00
Arthur Lutz
627800ddd5 [cluster-sizing.md] add link to Kiyot project page 2020-02-08 08:40:38 -06:00
Jérôme Petazzoni
871aab23ad Merge pull request #544 from arthurlogilab/patch-5
[compose/simple-k8s-control-plane] bump hyperkube from 1.14 to 1.16
2020-02-08 08:38:36 -06:00
Jérôme Petazzoni
8d7fa29a79 Merge pull request #543 from arthurlogilab/patch-4
[architecture] add links
2020-02-08 08:37:58 -06:00
Arthur Lutz
22f09c37a3 [compose/simple-k8s-control-plane] bump hyperkube from 1.14 to 1.16 2020-02-07 11:17:29 +01:00
Arthur Lutz
eacffe3cc5 [architecture] add kind as example 2020-02-07 09:40:36 +01:00
Arthur Lutz
d044f2bbd0 [architecture] add links 2020-02-07 09:39:00 +01:00
Jerome Petazzoni
a3da2615ff typos 2020-02-05 09:31:13 -06:00
Jerome Petazzoni
9a1ea0f1bd Expand info on kube-ps1 2020-02-05 04:29:04 -06:00
Jerome Petazzoni
67ac03e76e Highlight $IP 2020-02-05 02:51:12 -06:00
Jerome Petazzoni
38725cf3da typo 2020-02-04 06:33:54 -06:00
Jerome Petazzoni
3e98148e3f Refactor useful information to about-slide.md
prereqs.md can vary from a session to another, so I moved
the common information to about-slides.md (which should be
included all the time).
2020-02-02 10:20:39 -06:00
Jerome Petazzoni
b988c28b41 Extend section on API extension
Mention the aggregation layer.

Add an example of CRD.
2020-02-02 09:24:17 -06:00
Jerome Petazzoni
583933c492 Add kubectl delete -f and --prune 2020-02-02 08:16:28 -06:00
Jerome Petazzoni
ebadc1ca59 Upgrade the cluster upgrade chapter
Add information about version skew.
Better explain what's good/bad to do.
2020-02-02 05:41:01 -06:00
Jérôme Petazzoni
7f85c645f0 Update helm-intro.md 2020-01-31 03:53:28 -06:00
Jerome Petazzoni
ed5009c769 Tweaks after Caen 2020-01-30 14:44:44 -06:00
Jerome Petazzoni
e2f3034a96 Fix container picture generator 2020-01-30 01:11:09 -06:00
Jerome Petazzoni
8933e6aa1b Big Helm update
Revamp most of the Helm content:
- overview of Helm moved to helm-intro.md
- explanation of chart format in helm-chart-format.md
- the very crude chart example is now in helm-create-basic-chart.md
- the more advanced chart (with templates etc) is now in helm-create-better-chart.md
- deep dive into Helm internals (how it stores it's data) in helm-secrets.md

This is all for Helm 3. Helm 2 is not supported anymore.
2020-01-27 07:26:54 -06:00
Jerome Petazzoni
784b2a3e4e Big update to autopilot
Autopilot can now continue when errors happen, and it writes
success/failure of each snippet in a log file for later review.

Also added e2e.sh to provision a test environment and start
the remote tmux instance.
2020-01-20 14:23:20 -06:00
Jerome Petazzoni
f3bbd6377b Merge branch 'helm-3' 2020-01-20 02:45:05 -06:00
Jerome Petazzoni
04d3a7b360 Fix up slide about operators limitations 2020-01-19 11:34:18 -06:00
Jerome Petazzoni
a32df01165 Revamp operator example
Use Elastic Cloud for Kubernetes instead of the
UPMC Enterprises operator.
2020-01-19 11:32:04 -06:00
Jerome Petazzoni
ba323cb4e6 Update Portworx 2020-01-18 12:06:04 -06:00
Jerome Petazzoni
745a435a1a Fix linebreak on cronjob 2020-01-18 11:51:57 -06:00
Jerome Petazzoni
db276af182 Update Consul
Bump up Consul version to 1.6.

Change persistent consul demo; instead of a separate namespace,
use a different label. This way, the two manifests can be more
similar; and this simplifies the demo flow.
2020-01-18 11:33:02 -06:00
Jerome Petazzoni
87462939d9 Update dashboard to version 2.0 2020-01-18 11:12:33 -06:00
Jerome Petazzoni
7d6ab6974d Big autopilot update
'keys' does not handle special keys (like ^J) anymore.
Instead, we should use `key`, which will pass its entire
argument to tmux, without any processing. It is therefore
possible to do something like:

```key ^C```

Or

```key Escape```

Most (if not all) calls to special keys have been
converted to use 'key' instead of 'keys'.

Action ```copypaste``` has been deprecated in favor
of three separate actions:

```copy REGEX``` (searches the regex in the active pane,
and if found, places it in an internal clipboard)

```paste``` (inserts the content of the clipboard as
keystrokes)

```check``` (forces a status check)

Also, a 'tmux' command has been added. It allows to
do stuff like:

```tmux split-pane -v```
2020-01-18 09:49:18 -06:00
Jerome Petazzoni
ae606b9c40 Merge branch 'master' into helm-3 2020-01-18 03:04:24 -06:00
Jerome Petazzoni
da9921d68a Update explanations for canary 2020-01-18 02:36:41 -06:00
Jerome Petazzoni
3e9a939578 Add traffic split / canary for Traefik 2020-01-17 17:07:43 -06:00
Jerome Petazzoni
328a2edaaf Add slide about number of nodes in a cluster 2020-01-17 14:17:18 -06:00
Jerome Petazzoni
1f826d7993 Add slide about version skew 2020-01-17 12:28:27 -06:00
Jerome Petazzoni
cff9cbdfbb Add slide about versioning and cadence 2020-01-17 12:01:20 -06:00
Jerome Petazzoni
3ea6b730c8 Update the Prometheus install instructions 2020-01-17 11:46:58 -06:00
Jerome Petazzoni
1c6c76162f Add link to zip file 2020-01-17 10:11:12 -06:00
Jerome Petazzoni
52bafdb57e Update Helm chapter to Helm 3 2020-01-17 08:21:23 -06:00
Jerome Petazzoni
c4d9e6b3e1 Update deployment scripts to install Helm 3 2020-01-17 04:45:06 -06:00
Jerome Petazzoni
5160dd39a0 Add mention to ctr.run 2020-01-14 15:43:00 -06:00
Jerome Petazzoni
3c1220be83 Replace 1.1 with 127.1
This avoids pinging an external machine
2020-01-13 17:43:24 -06:00
Jerome Petazzoni
6a814cf039 Upgrade slide generator to python3; generate a zip file too 2020-01-12 13:28:48 -06:00
Jerome Petazzoni
1385a1bae2 Add QCON and Enix High-Five 2019-12-20 11:41:46 -06:00
Jerome Petazzoni
68a6546276 Fun with flags
Add flags in front of 'coming soon' workshops.
2019-12-20 11:41:37 -06:00
Jerome Petazzoni
8a2ca450ee Add extended Helm content 2019-12-10 14:21:09 -06:00
Jerome Petazzoni
6e8ac173e0 Add kube adm content to self-paced deck
/cc @bretfisher
2019-12-10 14:19:56 -06:00
Jerome Petazzoni
97e68ae185 Support : in titles 2019-12-06 16:25:16 -06:00
Jérôme Petazzoni
148ddd5174 Merge pull request #535 from jpetazzo/slides-docker-pods-anatomy
Slides docker pods anatomy
2019-12-06 22:25:40 +01:00
Jerome Petazzoni
e8eb11e257 Tweak Pods Anatomy slides for inclusion in master 2019-12-06 15:19:04 -06:00
Jérôme Petazzoni
fe9b56572e Merge pull request #534 from jpetazzo/slides-docker-init-systems
Slides docker init systems
2019-12-06 21:38:37 +01:00
Jerome Petazzoni
7281ca3ca0 Tweak content for inclusion in master branch 2019-12-06 14:16:48 -06:00
Julien Girardin
34a17aa097 Add a Pod anatomy set of slides 2019-12-06 17:15:21 +01:00
Julien Girardin
b37dd85eff Add Init_system slides 2019-12-06 11:03:48 +01:00
Jerome Petazzoni
4811420d55 Update Docker Mastery referral code 2019-11-29 12:48:59 -06:00
Jerome Petazzoni
a824afec85 Add shortlinks for uDemy course 2019-11-29 09:34:25 -06:00
Jerome Petazzoni
89d9fcb1c4 Fix port range # 2019-11-21 12:54:23 -06:00
Jérôme Petazzoni
5b488fbe62 Update Installing_Docker.md 2019-11-19 09:35:46 -06:00
Jerome Petazzoni
6d01a9d813 Add commands to prep portworx; make postgresql work on PKS 2019-11-19 07:40:01 -06:00
Jerome Petazzoni
cb81469170 Move storage class to portworx manifest 2019-11-19 06:58:49 -06:00
Jerome Petazzoni
c595a337e4 Rewrite services section
Improve the order when introducing ClusterIP, LoadBalancer, NodePort.
Explain the deal with ExternalIP and ExternalName, and reword the
Ingress slide.
2019-11-19 06:51:39 -06:00
Jerome Petazzoni
03d2d0bc5d kubectl is the new SSH 2019-11-18 16:47:10 -06:00
Jerome Petazzoni
2c46106792 Add explanations to navigate slides 2019-11-18 13:53:54 -06:00
Jerome Petazzoni
291d2a6c92 Add note about DNS integration 2019-11-18 13:30:09 -06:00
Jerome Petazzoni
f73fb92832 Put pods before services
The flow is better this way, since we can introduce pods
just after seeing them in kubectl describe node.

Also, add some extra info when we curl the Kubernetes API.
2019-11-18 12:57:26 -06:00
Jerome Petazzoni
e9e2fa0e50 Fix YAML formatting 2019-11-18 09:04:18 -06:00
Jerome Petazzoni
a0162d37f1 Add explanations to the node/pod diagram 2019-11-15 08:49:57 -06:00
Jerome Petazzoni
a61b69ad9a Merge branch 'master' of github.com:jpetazzo/container.training 2019-11-12 14:48:55 -06:00
Jerome Petazzoni
3388db4272 Update what we can do with k8s 2019-11-12 14:48:28 -06:00
Jérôme Petazzoni
d2d901302f Merge pull request #533 from BretFisher/remove-rkt
remove deprecated rkt, mention runtimes are different per distro
2019-11-12 13:15:32 +01:00
Jérôme Petazzoni
1fae4253bc Update concepts-k8s.md 2019-11-12 06:15:06 -06:00
Bret Fisher
f7f5ab1304 deprecated rkt, added more containerd/cri-o info 2019-11-12 06:45:42 -05:00
Jerome Petazzoni
7addacef22 Pin HAProxy to v1 2019-11-12 01:47:36 -06:00
Jerome Petazzoni
0136391ab5 Add rollback --to-revision 2019-11-11 01:23:28 -06:00
Jerome Petazzoni
ed27ad1d1e Expand volume section 2019-11-11 00:59:39 -06:00
Jerome Petazzoni
c15aa708df Put random values in Ingress 2019-11-11 00:25:50 -06:00
Bret Fisher
5749348883 remove deprecated rkt, mention runtimes are different per distro 2019-11-08 00:19:35 -05:00
Jerome Petazzoni
bc885f3dca Update information re/ JVM resource limits
Thanks @qerub for the heads up.
2019-11-07 11:39:19 -06:00
Jerome Petazzoni
bbe35a3901 Update the mention of Prometheus exposition format
Thanks @qerub for letting me know that the protobuf format
was deprecated in Prom 2. Also, that technical document by
@beorn7 is a real delight to read. 💯
2019-11-07 11:21:20 -06:00
Jerome Petazzoni
eb17b4c628 Tweak single-day workshop content 2019-11-07 11:15:14 -06:00
Jérôme Petazzoni
a4d50a5439 Merge pull request #532 from someara/someara/editors
adding editors
2019-11-07 14:03:24 +01:00
Sean OMeara
98d2b79c97 adding editors 2019-11-04 10:13:29 +01:00
Jerome Petazzoni
8320534a5c Add prefix to slide numbers 2019-11-03 07:42:24 -06:00
Jerome Petazzoni
74ece65947 Add Velocity slides 2019-11-03 07:11:05 -06:00
Jerome Petazzoni
7444f8d71e Add cronjobs and YAML catch up instructions 2019-11-01 22:46:43 -05:00
Jerome Petazzoni
c9bc417a32 Update logs section 2019-10-31 20:19:33 -05:00
Jerome Petazzoni
7d4331477a Get rid of $TAG and $REGISTRY
These variables are useful when deploying images
from a local registry (or from another place than
the Docker Hub) but they turned out to be quite
confusing. After holding to them for a while,
I think it is time to see the errors of my ways
and simplify that stuff.
2019-10-31 19:49:35 -05:00
Jerome Petazzoni
ff132fd728 Add mention to Review Access / rakkess 2019-10-31 17:26:01 -05:00
Jerome Petazzoni
4ec7b1d7f4 Improve section on healthchecks, and add information about startup probes 2019-10-31 17:15:01 -05:00
Jerome Petazzoni
e08e7848ed Add instructions about shpod 2019-10-31 16:07:33 -05:00
Jérôme Petazzoni
be6afa3e5e Merge pull request #531 from infomaven/master
Update troubleshooting instructions for Python 3.7 users
2019-10-30 23:23:59 +01:00
Jérôme Petazzoni
c340d909de Merge pull request #529 from joemcmahon/os-x-stern-install
Os x stern install
2019-10-30 23:19:50 +01:00
Jérôme Petazzoni
b667cf7cfc Update logs-cli.md 2019-10-30 17:19:25 -05:00
Jérôme Petazzoni
e04998e9cd Merge pull request #527 from joemcmahon/fix-jinja2-and-pyyml-install-instructions
Add instructions for pyyml, jinja2, default Python
2019-10-30 23:14:51 +01:00
Jérôme Petazzoni
84198b3fdc Update README.md 2019-10-30 17:13:13 -05:00
Nadine Whitfield
5c161d2090 Update README.md 2019-10-29 23:51:57 -07:00
Nadine Whitfield
0fc7c2316c Updated for python 3.7 2019-10-29 23:48:50 -07:00
Jerome Petazzoni
fb64c0d68f Update kube-proxy command 2019-10-29 20:31:18 -05:00
Jerome Petazzoni
23aaf7f58c Improve DMUC slides 2019-10-29 19:48:23 -05:00
Jerome Petazzoni
6cbcc4ae69 Fix CNI version (0.8 is unsupported yet) 2019-10-29 19:44:41 -05:00
Jerome Petazzoni
0b80238736 Bump up versions of kubebins 2019-10-25 12:25:49 -05:00
Joe McMahon
4c285b5318 Add instruction to install stern on OS X 2019-10-10 09:29:42 -07:00
Jérôme Petazzoni
2095a15728 Merge pull request #528 from tvroom/add.link.video.zombie.exec.healthchecks
Add link to conf video mentioning issues with zombie'd exec healthchecks
2019-10-09 21:58:56 +02:00
Tim Vroom
13ba8cef9d Add link to conference video mentioning issues with zombie'd exec healthcheck 2019-10-09 10:47:52 -07:00
Joe McMahon
be2374c672 Add instructions for pyyml, jinja2, default Python
Installing `mosh` via Homebrew may change `/usr/local/bin/python` to
Python 2. Adds docs to check and fix this so that `pyyml` and `jinja2`
can be installed.
2019-10-08 09:52:44 -07:00
Jerome Petazzoni
f96da2d260 Add dry-run, server-dry-run, kubectl diff
Closes #523.
2019-10-06 09:24:30 -05:00
Christian Bewernitz
5958874071 highlight code that is recommended to be used (#522)
Better highlight code that is recommended to be used.

(Thanks @karfau for the patch!)
2019-10-05 07:57:33 -05:00
Jerome Petazzoni
370bdf9aaf Add kube web view and kube ops view 2019-10-03 05:28:13 -05:00
Jerome Petazzoni
381cd27037 Add kube resource report 2019-10-03 05:19:51 -05:00
Jerome Petazzoni
c409c6997a Add kubecost blog post about requests and limits 2019-10-03 05:09:17 -05:00
Jerome Petazzoni
eb2e74f236 Adjust apiVersion for k8s 1.16 2019-09-23 08:53:38 -05:00
Jerome Petazzoni
169d850fc7 bump apiversion for 1.16 2019-09-23 08:30:28 -05:00
Jerome Petazzoni
96104193ba Add LISA tutorial 2019-09-20 09:57:27 -05:00
Jerome Petazzoni
5a5a08cf25 Add CLT training 2019-09-19 13:22:59 -05:00
Jerome Petazzoni
82b7b7ba88 Add slides for ENIX training 2019-09-18 13:08:54 -05:00
Jerome Petazzoni
8c4a0a3fce Merge branch 'master' of github.com:jpetazzo/container.training 2019-09-17 06:13:29 -05:00
Jerome Petazzoni
f4f0fb0f23 http.server requires python3 2019-09-17 06:13:21 -05:00
Jérôme Petazzoni
8dfcb440c8 Merge pull request #526 from BretFisher/fix-pod-yaml
fixing uppercase K in yaml for static pods
2019-09-16 15:19:38 +02:00
Bret Fisher
f3622d98fe fixing uppercase K in yaml for static pods 2019-09-13 16:49:47 -04:00
Jérôme Petazzoni
b1fc7580a1 Merge pull request #525 from BretFisher/patch-19
added GOTO Berlin to index
2019-09-09 11:44:38 +02:00
Bret Fisher
ab77d89232 added GOTO Berlin to index 2019-09-06 13:19:53 -04:00
Jerome Petazzoni
04f728c67a Add nowrap to vimrc
The certificates embedded in .kube/config make the file a bit hard
to read. This will make it easier.
2019-09-03 09:04:42 -05:00
Jerome Petazzoni
5bbce4783a Better modularize card generation
Most parameters used by the Jinja template for the cards
can now be specified in settings.yaml. This should make
the generation of cards for admin training much easier.
2019-09-03 06:51:15 -05:00
Jerome Petazzoni
889c79addb Word tweaks for eksctl
Just indicate that eksctl is now "the new way" to deploy EKS
(since AWS now supports it officially).
2019-09-03 04:49:03 -05:00
AJ Bowen
c4b408621c Create .tmux.conf to allow mouse and scrolling support and vim bindings for changing panes 2019-09-03 04:44:57 -05:00
Jerome Petazzoni
49df28d44f Add WebSSH snippet 2019-08-26 01:08:14 -05:00
Jerome Petazzoni
46878ed6c7 Update chapter about version upgrades 2019-08-23 05:48:55 -05:00
Jerome Petazzoni
b5b005b6d2 Bump k8s version 2019-08-23 05:12:48 -05:00
Jerome Petazzoni
9e991d1900 Add command to change the NodePort range
This helps when the customer's internet connection filters out
the default port range. It still requires to have a port range
open somewhere, though. here we use 10000-10999, but this should
be adjusted if necessary.
2019-08-23 05:11:05 -05:00
Jerome Petazzoni
ace911a208 Restore ingress YAML template 2019-08-23 04:45:37 -05:00
Jerome Petazzoni
ead027a62e Reorganize content flow
This introduces concepts more progressively (instead of
front-loading most of the theory before tackling first
useful commands). It was successfully testsed at PyCon
and at a few 1-day engagements and works really well.
I'm now making it the official flow.

I'm also reformatting the YAML a little bit to facilitate
content suffling.
2019-08-13 09:37:14 -05:00
Jerome Petazzoni
09c832031b Bump up ingress version in slides too 2019-08-13 08:13:37 -05:00
Jerome Petazzoni
34fca341bc Bump k8s YAML versions 2019-08-13 08:05:39 -05:00
Jerome Petazzoni
af18c5ab9f Bump versions 2019-08-13 06:04:24 -05:00
Jérôme Petazzoni
afa3a59461 Merge pull request #521 from gurayyildirim/hacknbreak2019
Add HacknBreak 2019 workshops to website
2019-08-12 14:25:05 +02:00
gurayyildirim
1abfac419b Fix date format 2019-08-12 15:21:53 +03:00
Güray Yıldırım
edd2f749c0 Add HacknBreak 2019 workshops to website 2019-08-12 15:16:11 +03:00
Jerome Petazzoni
2365b8f460 Add web server to make it easier to generate cards from CNC node 2019-08-08 07:37:05 -05:00
Jerome Petazzoni
c7a504dcb4 Replace 'iff' with something more understandable 2019-08-07 07:50:11 -05:00
Jérôme Petazzoni
ffb15c8316 Merge pull request #517 from antweiss/master
Fixing some typos
2019-08-07 14:46:29 +02:00
Jerome Petazzoni
f7fbe1b056 Add example blog post about Operator Framework 2019-08-07 05:25:49 -05:00
Jérôme Petazzoni
4be1b40586 Merge pull request #518 from antweiss/new-flux-github
Update Flux github url
2019-07-31 15:18:32 +02:00
Anton Weiss
91fb2f167c Update Flux github url 2019-07-28 16:27:53 +03:00
Anton Weiss
02dcb58f77 Fix typo in consul startup command 2019-07-28 16:05:48 +03:00
Anton Weiss
3a816568da Fix 2 typos in k8s/operators.md and k8s/operators-design.md 2019-07-28 14:21:20 +03:00
229 changed files with 12876 additions and 5264 deletions

2
.gitignore vendored
View File

@@ -3,10 +3,12 @@
*~
prepare-vms/tags
prepare-vms/infra
prepare-vms/www
slides/*.yml.html
slides/autopilot/state.yaml
slides/index.html
slides/past.html
slides/slides.zip
node_modules
### macOS ###

View File

@@ -9,21 +9,21 @@ services:
etcd:
network_mode: "service:pause"
image: k8s.gcr.io/etcd:3.3.10
image: k8s.gcr.io/etcd:3.4.3
command: etcd
kube-apiserver:
network_mode: "service:pause"
image: k8s.gcr.io/hyperkube:v1.14.0
image: k8s.gcr.io/hyperkube:v1.17.2
command: kube-apiserver --etcd-servers http://127.0.0.1:2379 --address 0.0.0.0 --disable-admission-plugins=ServiceAccount --allow-privileged
kube-controller-manager:
network_mode: "service:pause"
image: k8s.gcr.io/hyperkube:v1.14.0
image: k8s.gcr.io/hyperkube:v1.17.2
command: kube-controller-manager --master http://localhost:8080 --allocate-node-cidrs --cluster-cidr=10.CLUSTER.0.0/16
"Edit the CLUSTER placeholder first. Then, remove this line.":
kube-scheduler:
network_mode: "service:pause"
image: k8s.gcr.io/hyperkube:v1.14.0
image: k8s.gcr.io/hyperkube:v1.17.2
command: kube-scheduler --master http://localhost:8080

View File

@@ -12,7 +12,6 @@ metadata:
name: kube-router-cfg
namespace: kube-system
labels:
tier: node
k8s-app: kube-router
data:
cni-conf.json: |
@@ -32,20 +31,21 @@ data:
]
}
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
k8s-app: kube-router
tier: node
name: kube-router
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: kube-router
template:
metadata:
labels:
k8s-app: kube-router
tier: node
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ''
spec:

View File

@@ -9,20 +9,20 @@ services:
etcd:
network_mode: "service:pause"
image: k8s.gcr.io/etcd:3.3.10
image: k8s.gcr.io/etcd:3.4.3
command: etcd
kube-apiserver:
network_mode: "service:pause"
image: k8s.gcr.io/hyperkube:v1.14.0
image: k8s.gcr.io/hyperkube:v1.17.2
command: kube-apiserver --etcd-servers http://127.0.0.1:2379 --address 0.0.0.0 --disable-admission-plugins=ServiceAccount
kube-controller-manager:
network_mode: "service:pause"
image: k8s.gcr.io/hyperkube:v1.14.0
image: k8s.gcr.io/hyperkube:v1.17.2
command: kube-controller-manager --master http://localhost:8080
kube-scheduler:
network_mode: "service:pause"
image: k8s.gcr.io/hyperkube:v1.14.0
image: k8s.gcr.io/hyperkube:v1.17.2
command: kube-scheduler --master http://localhost:8080

21
k8s/canary.yaml Normal file
View File

@@ -0,0 +1,21 @@
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: whatever
annotations:
traefik.ingress.kubernetes.io/service-weights: |
whatever: 90%
whatever-new: 10%
spec:
rules:
- host: whatever.A.B.C.D.nip.io
http:
paths:
- path: /
backend:
serviceName: whatever
servicePort: 80
- path: /
backend:
serviceName: whatever-new
servicePort: 80

15
k8s/coffee-1.yaml Normal file
View File

@@ -0,0 +1,15 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: coffees.container.training
spec:
group: container.training
version: v1alpha1
scope: Namespaced
names:
plural: coffees
singular: coffee
kind: Coffee
shortNames:
- cof

35
k8s/coffee-2.yaml Normal file
View File

@@ -0,0 +1,35 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: coffees.container.training
spec:
group: container.training
scope: Namespaced
names:
plural: coffees
singular: coffee
kind: Coffee
shortNames:
- cof
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
properties:
spec:
required:
- taste
properties:
taste:
description: Subjective taste of that kind of coffee bean
type: string
additionalPrinterColumns:
- jsonPath: .spec.taste
description: Subjective taste of that kind of coffee bean
name: Taste
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date

29
k8s/coffees.yaml Normal file
View File

@@ -0,0 +1,29 @@
---
kind: Coffee
apiVersion: container.training/v1alpha1
metadata:
name: arabica
spec:
taste: strong
---
kind: Coffee
apiVersion: container.training/v1alpha1
metadata:
name: robusta
spec:
taste: stronger
---
kind: Coffee
apiVersion: container.training/v1alpha1
metadata:
name: liberica
spec:
taste: smoky
---
kind: Coffee
apiVersion: container.training/v1alpha1
metadata:
name: excelsa
spec:
taste: fruity

View File

@@ -2,8 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: consul
labels:
app: consul
rules:
- apiGroups: [""]
resources:
@@ -29,8 +27,6 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: consul
labels:
app: consul
---
apiVersion: v1
kind: Service
@@ -72,7 +68,7 @@ spec:
terminationGracePeriodSeconds: 10
containers:
- name: consul
image: "consul:1.4.4"
image: "consul:1.6"
args:
- "agent"
- "-bootstrap-expect=3"

160
k8s/dockercoins.yaml Normal file
View File

@@ -0,0 +1,160 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: hasher
name: hasher
spec:
replicas: 1
selector:
matchLabels:
app: hasher
template:
metadata:
labels:
app: hasher
spec:
containers:
- image: dockercoins/hasher:v0.1
name: hasher
---
apiVersion: v1
kind: Service
metadata:
labels:
app: hasher
name: hasher
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: hasher
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: redis
name: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- image: redis
name: redis
---
apiVersion: v1
kind: Service
metadata:
labels:
app: redis
name: redis
spec:
ports:
- port: 6379
protocol: TCP
targetPort: 6379
selector:
app: redis
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: rng
name: rng
spec:
replicas: 1
selector:
matchLabels:
app: rng
template:
metadata:
labels:
app: rng
spec:
containers:
- image: dockercoins/rng:v0.1
name: rng
---
apiVersion: v1
kind: Service
metadata:
labels:
app: rng
name: rng
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: rng
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webui
name: webui
spec:
replicas: 1
selector:
matchLabels:
app: webui
template:
metadata:
labels:
app: webui
spec:
containers:
- image: dockercoins/webui:v0.1
name: webui
---
apiVersion: v1
kind: Service
metadata:
labels:
app: webui
name: webui
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: webui
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: worker
name: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- image: dockercoins/worker:v0.1
name: worker

69
k8s/eck-cerebro.yaml Normal file
View File

@@ -0,0 +1,69 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: cerebro
name: cerebro
spec:
selector:
matchLabels:
app: cerebro
template:
metadata:
labels:
app: cerebro
spec:
volumes:
- name: conf
configMap:
name: cerebro
containers:
- image: lmenezes/cerebro
name: cerebro
volumeMounts:
- name: conf
mountPath: /conf
args:
- -Dconfig.file=/conf/application.conf
env:
- name: ELASTICSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: demo-es-elastic-user
key: elastic
---
apiVersion: v1
kind: Service
metadata:
labels:
app: cerebro
name: cerebro
spec:
ports:
- port: 9000
protocol: TCP
targetPort: 9000
selector:
app: cerebro
type: NodePort
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cerebro
data:
application.conf: |
secret = "ki:s:[[@=Ag?QI`W2jMwkY:eqvrJ]JqoJyi2axj3ZvOv^/KavOT4ViJSv?6YY4[N"
hosts = [
{
host = "http://demo-es-http.eck-demo.svc.cluster.local:9200"
name = "demo"
auth = {
username = "elastic"
password = ${?ELASTICSEARCH_PASSWORD}
}
}
]

View File

@@ -0,0 +1,19 @@
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: demo
namespace: eck-demo
spec:
http:
tls:
selfSignedCertificate:
disabled: true
nodeSets:
- name: default
count: 1
config:
node.data: true
node.ingest: true
node.master: true
node.store.allow_mmap: false
version: 7.5.1

168
k8s/eck-filebeat.yaml Normal file
View File

@@ -0,0 +1,168 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
namespace: eck-demo
labels:
k8s-app: filebeat
data:
filebeat.yml: |-
filebeat.inputs:
- type: container
paths:
- /var/log/containers/*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"
# To enable hints based autodiscover, remove `filebeat.inputs` configuration and uncomment this:
#filebeat.autodiscover:
# providers:
# - type: kubernetes
# node: ${NODE_NAME}
# hints.enabled: true
# hints.default_config:
# type: container
# paths:
# - /var/log/containers/*${data.kubernetes.container.id}.log
processors:
- add_cloud_metadata:
- add_host_metadata:
cloud.id: ${ELASTIC_CLOUD_ID}
cloud.auth: ${ELASTIC_CLOUD_AUTH}
output.elasticsearch:
hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
username: ${ELASTICSEARCH_USERNAME}
password: ${ELASTICSEARCH_PASSWORD}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
namespace: eck-demo
labels:
k8s-app: filebeat
spec:
selector:
matchLabels:
k8s-app: filebeat
template:
metadata:
labels:
k8s-app: filebeat
spec:
serviceAccountName: filebeat
terminationGracePeriodSeconds: 30
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:7.5.1
args: [
"-c", "/etc/filebeat.yml",
"-e",
]
env:
- name: ELASTICSEARCH_HOST
value: demo-es-http
- name: ELASTICSEARCH_PORT
value: "9200"
- name: ELASTICSEARCH_USERNAME
value: elastic
- name: ELASTICSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: demo-es-elastic-user
key: elastic
- name: ELASTIC_CLOUD_ID
value:
- name: ELASTIC_CLOUD_AUTH
value:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
securityContext:
runAsUser: 0
# If using Red Hat OpenShift uncomment this:
#privileged: true
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
volumeMounts:
- name: config
mountPath: /etc/filebeat.yml
readOnly: true
subPath: filebeat.yml
- name: data
mountPath: /usr/share/filebeat/data
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: config
configMap:
defaultMode: 0600
name: filebeat-config
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: varlog
hostPath:
path: /var/log
# data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
- name: data
hostPath:
path: /var/lib/filebeat-data
type: DirectoryOrCreate
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: filebeat
subjects:
- kind: ServiceAccount
name: filebeat
namespace: eck-demo
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: filebeat
labels:
k8s-app: filebeat
rules:
- apiGroups: [""] # "" indicates the core API group
resources:
- namespaces
- pods
verbs:
- get
- watch
- list
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: filebeat
namespace: eck-demo
labels:
k8s-app: filebeat
---

17
k8s/eck-kibana.yaml Normal file
View File

@@ -0,0 +1,17 @@
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: demo
spec:
version: 7.5.1
count: 1
elasticsearchRef:
name: demo
namespace: eck-demo
http:
service:
spec:
type: NodePort
tls:
selfSignedCertificate:
disabled: true

1802
k8s/eck-operator.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: fluentd
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
@@ -32,13 +33,17 @@ subjects:
name: fluentd
namespace: default
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: default
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
@@ -51,7 +56,7 @@ spec:
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1.3-debian-elasticsearch-1
image: fluent/fluentd-kubernetes-daemonset:v1.4-debian-elasticsearch-1
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch"
@@ -86,12 +91,13 @@ spec:
hostPath:
path: /var/lib/docker/containers
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: elasticsearch
name: elasticsearch
namespace: default
spec:
selector:
matchLabels:
@@ -119,6 +125,7 @@ metadata:
labels:
app: elasticsearch
name: elasticsearch
namespace: default
spec:
ports:
- port: 9200
@@ -128,12 +135,13 @@ spec:
app: elasticsearch
type: ClusterIP
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: kibana
name: kibana
namespace: default
spec:
selector:
matchLabels:
@@ -157,6 +165,7 @@ metadata:
labels:
app: kibana
name: kibana
namespace: default
spec:
ports:
- port: 5601

View File

@@ -9,7 +9,7 @@ spec:
name: haproxy
containers:
- name: haproxy
image: haproxy
image: haproxy:1
volumeMounts:
- name: config
mountPath: /usr/local/etc/haproxy/

View File

@@ -1,14 +1,13 @@
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: cheddar
name: whatever
spec:
rules:
- host: cheddar.A.B.C.D.nip.io
- host: whatever.A.B.C.D.nip.io
http:
paths:
- path: /
backend:
serviceName: cheddar
servicePort: 80
serviceName: whatever
servicePort: 1234

View File

@@ -1,3 +1,10 @@
# This file is based on the following manifest:
# https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml
# It adds the "skip login" flag, as well as an insecure hack to defeat SSL.
# As its name implies, it is INSECURE and you should not use it in production,
# or on clusters that contain any kind of important or sensitive data, or on
# clusters that have a life span of more than a few hours.
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,24 +19,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Configuration to deploy release version of the Dashboard UI compatible with
# Kubernetes 1.8.
#
# Example usage: kubectl create -f <this_file>
# ------------------- Dashboard Secret ------------------- #
apiVersion: v1
kind: Secret
kind: Namespace
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-certs
namespace: kube-system
type: Opaque
name: kubernetes-dashboard
---
# ------------------- Dashboard Service Account ------------------- #
apiVersion: v1
kind: ServiceAccount
@@ -37,70 +32,155 @@ metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
namespace: kubernetes-dashboard
---
# ------------------- Dashboard Role & Role Binding ------------------- #
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kubernetes-dashboard-minimal
namespace: kube-system
rules:
# Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret.
- apiGroups: [""]
resources: ["secrets"]
verbs: ["create"]
# Allow Dashboard to create 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["create"]
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"]
verbs: ["get", "update", "delete"]
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kubernetes-dashboard-settings"]
verbs: ["get", "update"]
# Allow Dashboard to get metrics from heapster.
- apiGroups: [""]
resources: ["services"]
resourceNames: ["heapster"]
verbs: ["proxy"]
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["heapster", "http:heapster:", "https:heapster:"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kubernetes-dashboard-minimal
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubernetes-dashboard-minimal
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system
---
# ------------------- Dashboard Deployment ------------------- #
kind: Deployment
apiVersion: apps/v1beta2
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-certs
namespace: kubernetes-dashboard
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-csrf
namespace: kubernetes-dashboard
type: Opaque
data:
csrf: ""
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-key-holder
namespace: kubernetes-dashboard
type: Opaque
---
kind: ConfigMap
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-settings
namespace: kubernetes-dashboard
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
rules:
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
verbs: ["get", "update", "delete"]
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kubernetes-dashboard-settings"]
verbs: ["get", "update"]
# Allow Dashboard to get metrics.
- apiGroups: [""]
resources: ["services"]
resourceNames: ["heapster", "dashboard-metrics-scraper"]
verbs: ["proxy"]
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
verbs: ["get"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
rules:
# Allow Metrics Scraper to get metrics from the Metrics server
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
@@ -113,60 +193,125 @@ spec:
k8s-app: kubernetes-dashboard
spec:
containers:
- name: kubernetes-dashboard
image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
# Uncomment the following line to manually specify Kubernetes API server Host
# If not specified, Dashboard will attempt to auto discover the API server and connect
# to it. Uncomment only if the default does not work.
# - --apiserver-host=http://my-address:port
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
# Create on-disk volume to store exec logs
- mountPath: /tmp
name: tmp-volume
livenessProbe:
httpGet:
scheme: HTTPS
path: /
port: 8443
initialDelaySeconds: 30
timeoutSeconds: 30
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.0.0
imagePullPolicy: Always
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
# Uncomment the following line to manually specify Kubernetes API server Host
# If not specified, Dashboard will attempt to auto discover the API server and connect
# to it. Uncomment only if the default does not work.
# - --apiserver-host=http://my-address:port
- --enable-skip-login
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
# Create on-disk volume to store exec logs
- mountPath: /tmp
name: tmp-volume
livenessProbe:
httpGet:
scheme: HTTPS
path: /
port: 8443
initialDelaySeconds: 30
timeoutSeconds: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
volumes:
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs
- name: tmp-volume
emptyDir: {}
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs
- name: tmp-volume
emptyDir: {}
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
- key: node-role.kubernetes.io/master
effect: NoSchedule
---
# ------------------- Dashboard Service ------------------- #
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
- port: 8000
targetPort: 8000
selector:
k8s-app: kubernetes-dashboard
k8s-app: dashboard-metrics-scraper
---
apiVersion: extensions/v1beta1
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: dashboard-metrics-scraper
template:
metadata:
labels:
k8s-app: dashboard-metrics-scraper
annotations:
seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
spec:
containers:
- name: dashboard-metrics-scraper
image: kubernetesui/metrics-scraper:v1.0.4
ports:
- containerPort: 8000
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTP
path: /
port: 8000
initialDelaySeconds: 30
timeoutSeconds: 30
volumeMounts:
- mountPath: /tmp
name: tmp-volume
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
volumes:
- name: tmp-volume
emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
@@ -185,10 +330,12 @@ spec:
- args:
- sh
- -c
- apk add --no-cache socat && socat TCP-LISTEN:80,fork,reuseaddr OPENSSL:kubernetes-dashboard.kube-system:443,verify=0
- apk add --no-cache socat && socat TCP-LISTEN:80,fork,reuseaddr OPENSSL:kubernetes-dashboard.kubernetes-dashboard:443,verify=0
image: alpine
name: dashboard
---
apiVersion: v1
kind: Service
metadata:
@@ -203,13 +350,13 @@ spec:
selector:
app: dashboard
type: NodePort
---
apiVersion: rbac.authorization.k8s.io/v1beta1
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
labels:
k8s-app: kubernetes-dashboard
name: insecure-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
@@ -217,4 +364,4 @@ roleRef:
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system
namespace: kubernetes-dashboard

View File

@@ -1,5 +1,5 @@
apiVersion: v1
Kind: Pod
kind: Pod
metadata:
name: hello
namespace: default

View File

@@ -1,3 +1,6 @@
# This is a copy of the following file:
# https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,24 +15,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Configuration to deploy release version of the Dashboard UI compatible with
# Kubernetes 1.8.
#
# Example usage: kubectl create -f <this_file>
# ------------------- Dashboard Secret ------------------- #
apiVersion: v1
kind: Secret
kind: Namespace
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-certs
namespace: kube-system
type: Opaque
name: kubernetes-dashboard
---
# ------------------- Dashboard Service Account ------------------- #
apiVersion: v1
kind: ServiceAccount
@@ -37,70 +28,155 @@ metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
namespace: kubernetes-dashboard
---
# ------------------- Dashboard Role & Role Binding ------------------- #
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kubernetes-dashboard-minimal
namespace: kube-system
rules:
# Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret.
- apiGroups: [""]
resources: ["secrets"]
verbs: ["create"]
# Allow Dashboard to create 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["create"]
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"]
verbs: ["get", "update", "delete"]
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kubernetes-dashboard-settings"]
verbs: ["get", "update"]
# Allow Dashboard to get metrics from heapster.
- apiGroups: [""]
resources: ["services"]
resourceNames: ["heapster"]
verbs: ["proxy"]
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["heapster", "http:heapster:", "https:heapster:"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kubernetes-dashboard-minimal
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubernetes-dashboard-minimal
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system
---
# ------------------- Dashboard Deployment ------------------- #
kind: Deployment
apiVersion: apps/v1beta2
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-certs
namespace: kubernetes-dashboard
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-csrf
namespace: kubernetes-dashboard
type: Opaque
data:
csrf: ""
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-key-holder
namespace: kubernetes-dashboard
type: Opaque
---
kind: ConfigMap
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-settings
namespace: kubernetes-dashboard
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
rules:
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
verbs: ["get", "update", "delete"]
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kubernetes-dashboard-settings"]
verbs: ["get", "update"]
# Allow Dashboard to get metrics.
- apiGroups: [""]
resources: ["services"]
resourceNames: ["heapster", "dashboard-metrics-scraper"]
verbs: ["proxy"]
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
verbs: ["get"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
rules:
# Allow Metrics Scraper to get metrics from the Metrics server
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
@@ -113,55 +189,117 @@ spec:
k8s-app: kubernetes-dashboard
spec:
containers:
- name: kubernetes-dashboard
image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
# Uncomment the following line to manually specify Kubernetes API server Host
# If not specified, Dashboard will attempt to auto discover the API server and connect
# to it. Uncomment only if the default does not work.
# - --apiserver-host=http://my-address:port
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
# Create on-disk volume to store exec logs
- mountPath: /tmp
name: tmp-volume
livenessProbe:
httpGet:
scheme: HTTPS
path: /
port: 8443
initialDelaySeconds: 30
timeoutSeconds: 30
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.0.0
imagePullPolicy: Always
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
# Uncomment the following line to manually specify Kubernetes API server Host
# If not specified, Dashboard will attempt to auto discover the API server and connect
# to it. Uncomment only if the default does not work.
# - --apiserver-host=http://my-address:port
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
# Create on-disk volume to store exec logs
- mountPath: /tmp
name: tmp-volume
livenessProbe:
httpGet:
scheme: HTTPS
path: /
port: 8443
initialDelaySeconds: 30
timeoutSeconds: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
volumes:
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs
- name: tmp-volume
emptyDir: {}
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs
- name: tmp-volume
emptyDir: {}
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
- key: node-role.kubernetes.io/master
effect: NoSchedule
---
# ------------------- Dashboard Service ------------------- #
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
- port: 8000
targetPort: 8000
selector:
k8s-app: kubernetes-dashboard
k8s-app: dashboard-metrics-scraper
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: dashboard-metrics-scraper
template:
metadata:
labels:
k8s-app: dashboard-metrics-scraper
annotations:
seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
spec:
containers:
- name: dashboard-metrics-scraper
image: kubernetesui/metrics-scraper:v1.0.4
ports:
- containerPort: 8000
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTP
path: /
port: 8000
initialDelaySeconds: 30
timeoutSeconds: 30
volumeMounts:
- mountPath: /tmp
name: tmp-volume
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
volumes:
- name: tmp-volume
emptyDir: {}

View File

@@ -45,7 +45,7 @@ subjects:
name: local-path-provisioner-service-account
namespace: local-path-storage
---
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: local-path-provisioner

View File

@@ -58,7 +58,7 @@ metadata:
name: metrics-server
namespace: kube-system
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: metrics-server
@@ -82,7 +82,7 @@ spec:
emptyDir: {}
containers:
- name: metrics-server
image: k8s.gcr.io/metrics-server-amd64:v0.3.1
image: k8s.gcr.io/metrics-server-amd64:v0.3.3
imagePullPolicy: Always
volumeMounts:
- name: tmp-dir

View File

@@ -0,0 +1,8 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-without-volume
spec:
containers:
- name: nginx
image: nginx

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-volume
spec:
volumes:
- name: www
containers:
- name: nginx
image: nginx
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html/

21
k8s/nginx-3-with-git.yaml Normal file
View File

@@ -0,0 +1,21 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-git
spec:
volumes:
- name: www
containers:
- name: nginx
image: nginx
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html/
- name: git
image: alpine
command: [ "sh", "-c", "apk add git && git clone https://github.com/octocat/Spoon-Knife /www" ]
volumeMounts:
- name: www
mountPath: /www/
restartPolicy: OnFailure

View File

@@ -1,7 +1,7 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-volume
name: nginx-with-init
spec:
volumes:
- name: www
@@ -11,11 +11,10 @@ spec:
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html/
initContainers:
- name: git
image: alpine
command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/octocat/Spoon-Knife /www" ]
command: [ "sh", "-c", "apk add git && sleep 5 && git clone https://github.com/octocat/Spoon-Knife /www" ]
volumeMounts:
- name: www
mountPath: /www/
restartPolicy: OnFailure

View File

@@ -1,51 +1,54 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
kind: ClusterRole
metadata:
name: consul
name: persistentconsul
rules:
- apiGroups: [ "" ]
resources: [ pods ]
verbs: [ get, list ]
- apiGroups: [""]
resources:
- pods
verbs:
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
kind: ClusterRoleBinding
metadata:
name: consul
name: persistentconsul
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: consul
kind: ClusterRole
name: persistentconsul
subjects:
- kind: ServiceAccount
name: consul
namespace: orange
name: persistentconsul
namespace: default
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: consul
name: persistentconsul
---
apiVersion: v1
kind: Service
metadata:
name: consul
name: persistentconsul
spec:
ports:
- port: 8500
name: http
selector:
app: consul
app: persistentconsul
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: consul
name: persistentconsul
spec:
serviceName: consul
serviceName: persistentconsul
replicas: 3
selector:
matchLabels:
app: consul
app: persistentconsul
volumeClaimTemplates:
- metadata:
name: data
@@ -58,9 +61,9 @@ spec:
template:
metadata:
labels:
app: consul
app: persistentconsul
spec:
serviceAccountName: consul
serviceAccountName: persistentconsul
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
@@ -69,19 +72,19 @@ spec:
- key: app
operator: In
values:
- consul
- persistentconsul
topologyKey: kubernetes.io/hostname
terminationGracePeriodSeconds: 10
containers:
- name: consul
image: "consul:1.4.4"
image: "consul:1.6"
volumeMounts:
- name: data
mountPath: /consul/data
args:
- "agent"
- "-bootstrap-expect=3"
- "-retry-join=provider=k8s namespace=orange label_selector=\"app=consul\""
- "-retry-join=provider=k8s label_selector=\"app=persistentconsul\""
- "-client=0.0.0.0"
- "-data-dir=/consul/data"
- "-server"

File diff suppressed because it is too large Load Diff

View File

@@ -12,10 +12,17 @@ spec:
labels:
app: postgres
spec:
schedulerName: stork
#schedulerName: stork
initContainers:
- name: rmdir
image: alpine
volumeMounts:
- mountPath: /vol
name: postgres
command: ["sh", "-c", "if [ -d /vol/lost+found ]; then rmdir /vol/lost+found; fi"]
containers:
- name: postgres
image: postgres:10.5
image: postgres:11
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres

View File

@@ -1,5 +1,5 @@
---
apiVersion: extensions/v1beta1
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
annotations:

View File

@@ -6,13 +6,16 @@ metadata:
namespace: kube-system
---
kind: DaemonSet
apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
name: traefik-ingress-controller
namespace: kube-system
labels:
k8s-app: traefik-ingress-lb
spec:
selector:
matchLabels:
k8s-app: traefik-ingress-lb
template:
metadata:
labels:
@@ -26,7 +29,7 @@ spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
containers:
- image: traefik
- image: traefik:1.7
name: traefik-ingress-lb
ports:
- name: http

View File

@@ -8,24 +8,24 @@ metadata:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: users:jean.doe
name: user=jean.doe
rules:
- apiGroups: [ certificates.k8s.io ]
resources: [ certificatesigningrequests ]
verbs: [ create ]
- apiGroups: [ certificates.k8s.io ]
resourceNames: [ users:jean.doe ]
resourceNames: [ user=jean.doe ]
resources: [ certificatesigningrequests ]
verbs: [ get, create, delete, watch ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: users:jean.doe
name: user=jean.doe
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: users:jean.doe
name: user=jean.doe
subjects:
- kind: ServiceAccount
name: jean.doe

View File

@@ -7,9 +7,9 @@ workshop.
## 1. Prerequisites
Virtualbox, Vagrant and Ansible
- Virtualbox: https://www.virtualbox.org/wiki/Downloads
- Vagrant: https://www.vagrantup.com/downloads.html
@@ -25,7 +25,7 @@ Virtualbox, Vagrant and Ansible
$ git clone --recursive https://github.com/ansible/ansible.git
$ cd ansible
$ git checkout stable-2.0.0.1
$ git checkout stable-{{ getStableVersionFromAnsibleProject }}
$ git submodule update
- source the setup script to make Ansible available on this terminal session:
@@ -38,6 +38,7 @@ Virtualbox, Vagrant and Ansible
## 2. Preparing the environment
Change into directory that has your Vagrantfile
Run the following commands:
@@ -66,6 +67,14 @@ will reflect inside the instance.
- Depending on the Vagrant version, `sudo apt-get install bsdtar` may be needed
- If you get an error like "no Vagrant file found" or you have a file but "cannot open base box" when running `vagrant up`,
chances are good you not in the correct directory.
Make sure you are in sub directory named "prepare-local". It has all the config files required by ansible, vagrant and virtualbox
- If you are using Python 3.7, running the ansible-playbook provisioning, see an error like "SyntaxError: invalid syntax" and it mentions
the word "async", you need to upgrade your Ansible version to 2.6 or higher to resolve the keyword conflict.
https://github.com/ansible/ansible/issues/42105
- If you get strange Ansible errors about dependencies, try to check your pip
version with `pip --version`. The current version is 8.1.1. If your pip is
older than this, upgrade it with `sudo pip install --upgrade pip`, restart

View File

@@ -10,15 +10,21 @@ These tools can help you to create VMs on:
- [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
- [Parallel SSH](https://code.google.com/archive/p/parallel-ssh/) (on a Mac: `brew install pssh`)
Depending on the infrastructure that you want to use, you also need to install
the Azure CLI, the AWS CLI, or terraform (for OpenStack deployment).
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`)
- [pyyaml](https://pypi.python.org/pypi/PyYAML)
- [jinja2](https://pypi.python.org/pypi/Jinja2)
You can install them with pip (perhaps with `pip install --user`, or even use `virtualenv` if that's your thing).
These require Python 3. If you are on a Mac, see below for specific instructions on setting up
Python 3 to be the default Python on a Mac. In particular, if you installed `mosh`, Homebrew
may have changed your default Python to Python 2.
## General Workflow
@@ -87,26 +93,37 @@ You're all set!
```
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 group of VMs
deploy Install Docker on a bunch of running VMs
ec2quotas Check our EC2 quotas (max instances)
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 groups in the current region
opensg Open the default security group to ALL ingress traffic
pull_images Pre-pull a bunch of Docker images
retag Apply a new tag to a group of VMs
start Start a group of VMs
status List instance status for a given group
stop Stop (terminate, shutdown, kill, remove, destroy...) instances
test Run tests (pre-flight checks) on a group of VMs
wrap Run this program in a container
build Build the Docker image to run this program in a container
cards Generate ready-to-print cards for a group of VMs
deploy Install Docker on a bunch of running VMs
disableaddrchecks Disable source/destination IP address checks
disabledocker Stop Docker Engine and don't restart it automatically
helmprom Install Helm and Prometheus
help Show available commands
ids (FIXME) List the instance IDs belonging to a given tag or token
kubebins Install Kubernetes and CNI binaries but don't start anything
kubereset Wipe out Kubernetes configuration on all nodes
kube Setup kubernetes clusters with kubeadm (must be run AFTER deploy)
kubetest Check that all nodes are reporting as Ready
listall List VMs running on all configured infrastructures
list List available groups for a given infrastructure
netfix Disable GRO and run a pinger job on the VMs
opensg Open the default security group to ALL ingress traffic
ping Ping VMs in a given tag, to check that they have network access
pssh Run an arbitrary command on all nodes
pull_images Pre-pull a bunch of Docker images
quotas Check our infrastructure quotas (max instances)
remap_nodeports Remap NodePort range to 10000-10999
retag (FIXME) Apply a new tag to a group of VMs
ssh Open an SSH session to the first node of a tag
start Start a group of VMs
stop Stop (terminate, shutdown, kill, remove, destroy...) instances
tags List groups of VMs known locally
test Run tests (pre-flight checks) on a group of VMs
weavetest Check that weave seems properly setup
webssh Install a WEB SSH server on the machines (port 1080)
wrap Run this program in a container
www Run a web server to access card HTML and PDF
```
### Summary of What `./workshopctl` Does For You
@@ -245,3 +262,32 @@ If you don't have `wkhtmltopdf` installed, you will get a warning that it is a m
- Don't write to bash history in system() in postprep
- compose, etc version inconsistent (int vs str)
## Making sure Python3 is the default (Mac only)
Check the `/usr/local/bin/python` symlink. It should be pointing to
`/usr/local/Cellar/python/3`-something. If it isn't, follow these
instructions.
1) Verify that Python 3 is installed.
```
ls -la /usr/local/Cellar/Python
```
You should see one or more versions of Python 3. If you don't,
install it with `brew install python`.
2) Verify that `python` points to Python3.
```
ls -la /usr/local/bin/python
```
If this points to `/usr/local/Cellar/python@2`, then we'll need to change it.
```
rm /usr/local/bin/python
ln -s /usr/local/Cellar/Python/xxxx /usr/local/bin/python
# where xxxx is the most recent Python 3 version you saw above
```

10
prepare-vms/e2e.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
set -e
TAG=$(./workshopctl maketag)
./workshopctl start --settings settings/jerome.yaml --infra infra/aws-eu-central-1 --tag $TAG
./workshopctl deploy $TAG
./workshopctl kube $TAG
./workshopctl helmprom $TAG
while ! ./workshopctl kubetest $TAG; do sleep 1; done
./workshopctl tmux $TAG
echo ./workshopctl stop $TAG

View File

@@ -33,9 +33,14 @@ _cmd_cards() {
../../lib/ips-txt-to-html.py settings.yaml
)
ln -sf ../tags/$TAG/ips.html www/$TAG.html
ln -sf ../tags/$TAG/ips.pdf www/$TAG.pdf
info "Cards created. You can view them with:"
info "xdg-open tags/$TAG/ips.html tags/$TAG/ips.pdf (on Linux)"
info "open tags/$TAG/ips.html (on macOS)"
info "Or you can start a web server with:"
info "$0 www"
}
_cmd deploy "Install Docker on a bunch of running VMs"
@@ -108,9 +113,12 @@ _cmd_disabledocker() {
TAG=$1
need_tag
pssh "sudo systemctl disable docker.service"
pssh "sudo systemctl disable docker.socket"
pssh "sudo systemctl stop docker"
pssh "
sudo systemctl disable docker.service
sudo systemctl disable docker.socket
sudo systemctl stop docker
sudo killall containerd
"
}
_cmd kubebins "Install Kubernetes and CNI binaries but don't start anything"
@@ -122,23 +130,20 @@ _cmd_kubebins() {
set -e
cd /usr/local/bin
if ! [ -x etcd ]; then
curl -L https://github.com/etcd-io/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz \
##VERSION##
curl -L https://github.com/etcd-io/etcd/releases/download/v3.4.3/etcd-v3.4.3-linux-amd64.tar.gz \
| sudo tar --strip-components=1 --wildcards -zx '*/etcd' '*/etcdctl'
fi
if ! [ -x hyperkube ]; then
curl -L https://dl.k8s.io/v1.14.1/kubernetes-server-linux-amd64.tar.gz \
| sudo tar --strip-components=3 -zx kubernetes/server/bin/hyperkube
fi
if ! [ -x kubelet ]; then
for BINARY in kubectl kube-apiserver kube-scheduler kube-controller-manager kubelet kube-proxy;
do
sudo ln -s hyperkube \$BINARY
done
##VERSION##
curl -L https://dl.k8s.io/v1.17.2/kubernetes-server-linux-amd64.tar.gz \
| sudo tar --strip-components=3 -zx \
kubernetes/server/bin/kube{ctl,let,-proxy,-apiserver,-scheduler,-controller-manager}
fi
sudo mkdir -p /opt/cni/bin
cd /opt/cni/bin
if ! [ -x bridge ]; then
curl -L https://github.com/containernetworking/plugins/releases/download/v0.7.5/cni-plugins-amd64-v0.7.5.tgz \
curl -L https://github.com/containernetworking/plugins/releases/download/v0.7.6/cni-plugins-amd64-v0.7.6.tgz \
| sudo tar -zx
fi
"
@@ -152,10 +157,10 @@ _cmd_kube() {
# Optional version, e.g. 1.13.5
KUBEVERSION=$2
if [ "$KUBEVERSION" ]; then
EXTRA_KUBELET="=$KUBEVERSION-00"
EXTRA_APTGET="=$KUBEVERSION-00"
EXTRA_KUBEADM="--kubernetes-version=v$KUBEVERSION"
else
EXTRA_KUBELET=""
EXTRA_APTGET=""
EXTRA_KUBEADM=""
fi
@@ -167,7 +172,7 @@ _cmd_kube() {
sudo tee /etc/apt/sources.list.d/kubernetes.list"
pssh --timeout 200 "
sudo apt-get update -q &&
sudo apt-get install -qy kubelet$EXTRA_KUBELET kubeadm kubectl &&
sudo apt-get install -qy kubelet$EXTRA_APTGET kubeadm$EXTRA_APTGET kubectl$EXTRA_APTGET &&
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl"
# Initialize kube master
@@ -237,13 +242,22 @@ EOF"
# Install helm
pssh "
if [ ! -x /usr/local/bin/helm ]; then
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | sudo bash &&
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get-helm-3 | sudo bash &&
helm completion bash | sudo tee /etc/bash_completion.d/helm
fi"
# Install kustomize
pssh "
if [ ! -x /usr/local/bin/kustomize ]; then
curl -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v3.5.4/kustomize_v3.5.1_linux_amd64.tar.gz |
sudo tar -C /usr/local/bin -zx kustomize
echo complete -C /usr/local/bin/kustomize kustomize | sudo tee /etc/bash_completion.d/kustomize
fi"
# Install ship
pssh "
if [ ! -x /usr/local/bin/ship ]; then
##VERSION##
curl -L https://github.com/replicatedhq/ship/releases/download/v0.40.0/ship_0.40.0_linux_amd64.tar.gz |
sudo tar -C /usr/local/bin -zx ship
fi"
@@ -251,7 +265,7 @@ EOF"
# Install the AWS IAM authenticator
pssh "
if [ ! -x /usr/local/bin/aws-iam-authenticator ]; then
##VERSION##
##VERSION##
sudo curl -o /usr/local/bin/aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.12.7/2019-03-27/bin/linux/amd64/aws-iam-authenticator
sudo chmod +x /usr/local/bin/aws-iam-authenticator
fi"
@@ -318,6 +332,15 @@ _cmd_listall() {
done
}
_cmd maketag "Generate a quasi-unique tag for a group of instances"
_cmd_maketag() {
if [ -z $USER ]; then
export USER=anonymous
fi
MS=$(($(date +%N)/1000000))
date +%Y-%m-%d-%H-%M-$MS-$USER
}
_cmd ping "Ping VMs in a given tag, to check that they have network access"
_cmd_ping() {
TAG=$1
@@ -351,12 +374,50 @@ EOF
sudo systemctl start pinger"
}
_cmd tailhist "Install history viewer on port 1088"
_cmd_tailhist () {
TAG=$1
need_tag
pssh "
wget https://github.com/joewalnes/websocketd/releases/download/v0.3.0/websocketd-0.3.0_amd64.deb
sudo dpkg -i websocketd-0.3.0_amd64.deb
sudo mkdir -p /tmp/tailhist
sudo tee /root/tailhist.service <<EOF
[Unit]
Description=tailhist
[Install]
WantedBy=multi-user.target
[Service]
WorkingDirectory=/tmp/tailhist
ExecStart=/usr/bin/websocketd --port=1088 --staticdir=. sh -c \"tail -n +1 -f /home/docker/.history || echo 'Could not read history file. Perhaps you need to \\\"chmod +r .history\\\"?'\"
User=nobody
Group=nogroup
Restart=always
EOF
sudo systemctl enable /root/tailhist.service
sudo systemctl start tailhist"
pssh -I sudo tee /tmp/tailhist/index.html <lib/tailhist.html
}
_cmd opensg "Open the default security group to ALL ingress traffic"
_cmd_opensg() {
need_infra $1
infra_opensg
}
_cmd portworx "Prepare the nodes for Portworx deployment"
_cmd_portworx() {
TAG=$1
need_tag
pssh "
sudo truncate --size 10G /portworx.blk &&
sudo losetup /dev/loop4 /portworx.blk"
}
_cmd disableaddrchecks "Disable source/destination IP address checks"
_cmd_disableaddrchecks() {
TAG=$1
@@ -381,6 +442,20 @@ _cmd_pull_images() {
pull_tag
}
_cmd remap_nodeports "Remap NodePort range to 10000-10999"
_cmd_remap_nodeports() {
TAG=$1
need_tag
FIND_LINE=" - --service-cluster-ip-range=10.96.0.0\/12"
ADD_LINE=" - --service-node-port-range=10000-10999"
MANIFEST_FILE=/etc/kubernetes/manifests/kube-apiserver.yaml
pssh "
if i_am_first_node && ! grep -q '$ADD_LINE' $MANIFEST_FILE; then
sudo sed -i 's/\($FIND_LINE\)\$/\1\n$ADD_LINE/' $MANIFEST_FILE
fi"
}
_cmd quotas "Check our infrastructure quotas (max instances)"
_cmd_quotas() {
need_infra $1
@@ -436,7 +511,7 @@ _cmd_start() {
need_infra $INFRA
if [ -z "$TAG" ]; then
TAG=$(make_tag)
TAG=$(_cmd_maketag)
fi
mkdir -p tags/$TAG
ln -s ../../$INFRA tags/$TAG/infra.sh
@@ -498,20 +573,24 @@ _cmd_test() {
test_tag
}
_cmd tmux "Log into the first node and start a tmux server"
_cmd_tmux() {
TAG=$1
need_tag
IP=$(head -1 tags/$TAG/ips.txt)
info "Opening ssh+tmux with $IP"
rm -f /tmp/tmux-$UID/default
ssh -t -L /tmp/tmux-$UID/default:/tmp/tmux-1001/default docker@$IP tmux new-session -As 0
}
_cmd helmprom "Install Helm and Prometheus"
_cmd_helmprom() {
TAG=$1
need_tag
pssh "
if i_am_first_node; then
kubectl -n kube-system get serviceaccount helm ||
kubectl -n kube-system create serviceaccount helm
sudo -u docker -H helm init --service-account helm
kubectl get clusterrolebinding helm-can-do-everything ||
kubectl create clusterrolebinding helm-can-do-everything \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:helm
sudo -u docker -H helm upgrade --install prometheus stable/prometheus \
sudo -u docker -H helm repo add stable https://kubernetes-charts.storage.googleapis.com/
sudo -u docker -H helm install prometheus stable/prometheus \
--namespace kube-system \
--set server.service.type=NodePort \
--set server.service.nodePort=30090 \
@@ -568,6 +647,18 @@ EOF"
sudo systemctl start webssh.service"
}
_cmd www "Run a web server to access card HTML and PDF"
_cmd_www() {
cd www
IPADDR=$(curl -sL canihazip.com/s)
info "The following files are available:"
for F in *; do
echo "http://$IPADDR:8000/$F"
done
info "Press Ctrl-C to stop server."
python3 -m http.server
}
greet() {
IAMUSER=$(aws iam get-user --query 'User.UserName')
info "Hello! You seem to be UNIX user $USER, and IAM user $IAMUSER."
@@ -686,10 +777,3 @@ sync_keys() {
info "Using existing key $AWS_KEY_NAME."
fi
}
make_tag() {
if [ -z $USER ]; then
export USER=anonymous
fi
date +%Y-%m-%d-%H-%M-$USER
}

View File

@@ -4,17 +4,12 @@ import sys
import yaml
import jinja2
def prettify(l):
l = [ip.strip() for ip in l]
ret = [ "node{}: <code>{}</code>".format(i+1, s) for (i, s) in zip(range(len(l)), l) ]
return ret
# Read settings from user-provided settings file
SETTINGS = yaml.load(open(sys.argv[1]))
clustersize = SETTINGS["clustersize"]
context = yaml.safe_load(open(sys.argv[1]))
ips = list(open("ips.txt"))
clustersize = context["clustersize"]
print("---------------------------------------------")
print(" Number of IPs: {}".format(len(ips)))
@@ -30,7 +25,9 @@ while ips:
ips = ips[clustersize:]
clusters.append(cluster)
template_file_name = SETTINGS["cards_template"]
context["clusters"] = clusters
template_file_name = context["cards_template"]
template_file_path = os.path.join(
os.path.dirname(__file__),
"..",
@@ -39,18 +36,21 @@ template_file_path = os.path.join(
)
template = jinja2.Template(open(template_file_path).read())
with open("ips.html", "w") as f:
f.write(template.render(clusters=clusters, **SETTINGS))
f.write(template.render(**context))
print("Generated ips.html")
try:
import pdfkit
paper_size = context["paper_size"]
margin = {"A4": "0.5cm", "Letter": "0.2in"}[paper_size]
with open("ips.html") as f:
pdfkit.from_file(f, "ips.pdf", options={
"page-size": SETTINGS["paper_size"],
"margin-top": SETTINGS["paper_margin"],
"margin-bottom": SETTINGS["paper_margin"],
"margin-left": SETTINGS["paper_margin"],
"margin-right": SETTINGS["paper_margin"],
"page-size": paper_size,
"margin-top": margin,
"margin-bottom": margin,
"margin-left": margin,
"margin-right": margin,
})
print("Generated ips.pdf")
except ImportError:

View File

@@ -65,6 +65,15 @@ system("""sudo -u docker tee -a /home/docker/.bashrc <<SQRL
export PS1='\e[1m\e[31m[{}] \e[32m(\\$(docker-prompt)) \e[34m\u@\h\e[35m \w\e[0m\n$ '
SQRL""".format(ipv4))
# Bigger history, in a different file, and saved before executing each command
system("""sudo -u docker tee -a /home/docker/.bashrc <<SQRL
export HISTSIZE=9999
export HISTFILESIZE=9999
shopt -s histappend
trap 'history -a' DEBUG
export HISTFILE=~/.history
SQRL""")
# Custom .vimrc
system("""sudo -u docker tee /home/docker/.vimrc <<SQRL
syntax on
@@ -73,8 +82,29 @@ set expandtab
set number
set shiftwidth=2
set softtabstop=2
set nowrap
SQRL""")
# Custom .tmux.conf
system(
"""sudo -u docker tee /home/docker/.tmux.conf <<SQRL
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Allow using mouse to switch panes
set -g mouse on
# Make scrolling with wheels work
bind -n WheelUpPane if-shell -F -t = "#{mouse_any_flag}" "send-keys -M" "if -Ft= '#{pane_in_mode}' 'send-keys -M' 'select-pane -t=; copy-mode -e; send-keys -M'"
bind -n WheelDownPane select-pane -t= \; send-keys -M
SQRL"""
)
# add docker user to sudoers and allow password authentication
system("""sudo tee /etc/sudoers.d/docker <<SQRL
docker ALL=(ALL) NOPASSWD:ALL
@@ -85,6 +115,7 @@ system("sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /e
system("sudo service ssh restart")
system("sudo apt-get -q update")
system("sudo apt-get -qy install git jq")
system("sudo apt-get -qy install emacs-nox joe")
#######################
### DOCKER INSTALLS ###

View File

@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title>bash history</title>
<style>
#log {
font: bold 24px courier;
}
#log div:last-child {
background: yellow;
}
</style>
</head>
<body>
<div id="log"></div>
<script>
var ws = new WebSocket('ws://' + (location.host ? location.host : "localhost:8080") + "/");
var log = document.getElementById('log');
var echo = function(text) {
var line = document.createElement('div');
line.textContent = text;
log.appendChild(line);
line.scrollIntoView();
}
ws.onopen = function() {
document.body.style.backgroundColor = '#cfc';
};
ws.onclose = function() {
document.body.style.backgroundColor = '#fcc';
echo("Disconnected from server. Try to reload this page?");
};
ws.onmessage = function(event) {
echo(event.data);
};
</script>
</body>
</html>

49
prepare-vms/map-dns.py Executable file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python
import os
import requests
import yaml
# configurable stuff
domains_file = "../../plentydomains/domains.txt"
config_file = os.path.join(
os.environ["HOME"], ".config/gandi/config.yaml")
tag = "test"
apiurl = "https://dns.api.gandi.net/api/v5/domains"
# inferred stuff
domains = open(domains_file).read().split()
apikey = yaml.safe_load(open(config_file))["apirest"]["key"]
ips = open(f"tags/{tag}/ips.txt").read().split()
settings_file = f"tags/{tag}/settings.yaml"
clustersize = yaml.safe_load(open(settings_file))["clustersize"]
# now do the fucking work
while domains and ips:
domain = domains[0]
domains = domains[1:]
cluster = ips[:clustersize]
ips = ips[clustersize:]
print(f"{domain} => {cluster}")
zone = ""
node = 0
for ip in cluster:
node += 1
zone += f"@ 300 IN A {ip}\n"
zone += f"* 300 IN A {ip}\n"
zone += f"node{node} 300 IN A {ip}\n"
r = requests.put(
f"{apiurl}/{domain}/records",
headers={"x-api-key": apikey},
data=zone)
print(r.text)
#r = requests.get(
# f"{apiurl}/{domain}/records",
# headers={"x-api-key": apikey},
# )
if domains:
print(f"Good, we have {len(domains)} domains left.")
if ips:
print(f"Crap, we have {len(ips)} IP addresses left.")

View File

@@ -10,13 +10,6 @@ cards_template: cards.html
# Use "Letter" in the US, and "A4" everywhere else
paper_size: A4
# 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
@@ -26,3 +19,5 @@ machine_version: 0.14.0
# Password used to connect with the "docker user"
docker_user_password: training
image:

View File

@@ -10,13 +10,6 @@ cards_template: cards.html
# Use "Letter" in the US, and "A4" everywhere else
paper_size: A4
# 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
@@ -26,3 +19,6 @@ machine_version: 0.14.0
# Password used to connect with the "docker user"
docker_user_password: training
clusternumber: 100
image:

View File

@@ -10,13 +10,6 @@ cards_template: cards.html
# Use "Letter" in the US, and "A4" everywhere else
paper_size: A4
# 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
@@ -26,3 +19,6 @@ machine_version: 0.14.0
# Password used to connect with the "docker user"
docker_user_password: training
clusternumber: 200
image:

View File

@@ -10,13 +10,6 @@ cards_template: cards.html
# Use "Letter" in the US, and "A4" everywhere else
paper_size: A4
# 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
@@ -26,3 +19,5 @@ machine_version: 0.14.0
# Password used to connect with the "docker user"
docker_user_password: training
image:

View File

@@ -12,13 +12,6 @@ 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

View File

@@ -12,18 +12,11 @@ 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: stable
# These correspond to the version numbers visible on their respective GitHub release pages
compose_version: 1.24.1
compose_version: 1.25.4
machine_version: 0.15.0
# Password used to connect with the "docker user"

View File

@@ -10,18 +10,11 @@ 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: stable
# These correspond to the version numbers visible on their respective GitHub release pages
compose_version: 1.24.1
compose_version: 1.25.4
machine_version: 0.14.0
# Password used to connect with the "docker user"

View File

@@ -12,13 +12,6 @@ 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: stable

View File

@@ -12,13 +12,6 @@ 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: stable

View File

@@ -1,9 +1,24 @@
#!/bin/sh
set -e
retry () {
N=$1
I=0
shift
while ! "$@"; do
I=$(($I+1))
if [ $I -gt $N ]; then
echo "FAILED, ABORTING"
exit 1
fi
echo "FAILED, RETRYING ($I/$N)"
done
}
export AWS_INSTANCE_TYPE=t3a.small
INFRA=infra/aws-us-west-2
INFRA=infra/aws-eu-west-3
STUDENTS=2
@@ -17,9 +32,9 @@ TAG=$PREFIX-$SETTINGS
--settings settings/$SETTINGS.yaml \
--count $STUDENTS
./workshopctl deploy $TAG
./workshopctl disabledocker $TAG
./workshopctl kubebins $TAG
retry 5 ./workshopctl deploy $TAG
retry 5 ./workshopctl disabledocker $TAG
retry 5 ./workshopctl kubebins $TAG
./workshopctl cards $TAG
SETTINGS=admin-kubenet
@@ -30,9 +45,9 @@ TAG=$PREFIX-$SETTINGS
--settings settings/$SETTINGS.yaml \
--count $((3*$STUDENTS))
./workshopctl disableaddrchecks $TAG
./workshopctl deploy $TAG
./workshopctl kubebins $TAG
retry 5 ./workshopctl disableaddrchecks $TAG
retry 5 ./workshopctl deploy $TAG
retry 5 ./workshopctl kubebins $TAG
./workshopctl cards $TAG
SETTINGS=admin-kuberouter
@@ -43,9 +58,9 @@ TAG=$PREFIX-$SETTINGS
--settings settings/$SETTINGS.yaml \
--count $((3*$STUDENTS))
./workshopctl disableaddrchecks $TAG
./workshopctl deploy $TAG
./workshopctl kubebins $TAG
retry 5 ./workshopctl disableaddrchecks $TAG
retry 5 ./workshopctl deploy $TAG
retry 5 ./workshopctl kubebins $TAG
./workshopctl cards $TAG
#INFRA=infra/aws-us-west-1
@@ -60,7 +75,6 @@ TAG=$PREFIX-$SETTINGS
--settings settings/$SETTINGS.yaml \
--count $((3*$STUDENTS))
./workshopctl deploy $TAG
./workshopctl kube $TAG 1.13.5
retry 5 ./workshopctl deploy $TAG
retry 5 ./workshopctl kube $TAG 1.15.9
./workshopctl cards $TAG

View File

@@ -1,14 +1,31 @@
{# Feel free to customize or override anything in there! #}
{#
The variables below can be customized here directly, or in your
settings.yaml file. Any variable in settings.yaml will be exposed
in here as well.
#}
{%- set url = "http://FIXME.container.training/" -%}
{%- set pagesize = 9 -%}
{%- set lang = "en" -%}
{%- set event = "training session" -%}
{%- set backside = False -%}
{%- set image = "kube" -%}
{%- set clusternumber = 100 -%}
{%- set url = url
| default("http://FIXME.container.training/") -%}
{%- set pagesize = pagesize
| default(9) -%}
{%- set lang = lang
| default("en") -%}
{%- set event = event
| default("training session") -%}
{%- set backside = backside
| default(False) -%}
{%- set image = image
| default("kube") -%}
{%- set clusternumber = clusternumber
| default(None) -%}
{%- if qrcode == True -%}
{%- set qrcode = "https://container.training/q" -%}
{%- elif qrcode -%}
{%- set qrcode = qrcode -%}
{%- endif -%}
{%- set image_src = {
{# You can also set img_bottom_src instead. #}
{%- set img_logo_src = {
"docker": "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png",
"swarm": "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png",
"kube": "https://avatars1.githubusercontent.com/u/13629408",
@@ -74,9 +91,33 @@
{%- endif -%}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><style>
<head>
<style>
@import url('https://fonts.googleapis.com/css?family=Slabo+27px');
{% if paper_size == "A4" %}
@page {
size: A4; /* Change from the default size of A4 */
margin: 0.5cm; /* Set margin on each page */
}
body {
/* this is A4 minus 0.5cm margins */
width: 20cm;
height: 28.7cm;
}
{% elif paper_size == "Letter" %}
@page {
size: Letter;
margin: 0.2in;
}
body {
/* this is Letter minus 0.2in margins */
width: 8.6in;
heigth: 10.6in;
}
{% endif %}
body, table {
margin: 0;
padding: 0;
@@ -97,53 +138,45 @@ div {
float: left;
border: 1px dotted black;
{% if backside %}
height: 31%;
height: 33%;
{% endif %}
padding-top: 1%;
padding-bottom: 1%;
/* columns * (width+left+right) < 100% */
/*
width: 21.5%;
padding-left: 1.5%;
padding-right: 1.5%;
width: 24.8%;
*/
/**/
width: 30%;
padding-left: 1.5%;
padding-right: 1.5%;
width: 33%;
/**/
}
p {
margin: 0.4em 0 0.4em 0;
margin: 0.8em;
}
div.back {
border: 1px dotted white;
border: 1px dotted grey;
}
div.back p {
margin: 0.5em 1em 0 1em;
span.scale {
white-space: nowrap;
}
img {
height: 4em;
img.logo {
height: 4.5em;
float: right;
margin-right: -0.2em;
}
img.bottom {
height: 2.5em;
display: block;
margin: 0.5em auto;
}
/*
img.enix {
height: 4.0em;
margin-top: 0.4em;
.qrcode img {
width: 40%;
margin: 1em;
}
img.kube {
height: 4.2em;
margin-top: 1.7em;
}
*/
.logpass {
font-family: monospace;
font-weight: bold;
@@ -153,15 +186,44 @@ img.kube {
page-break-after: always;
clear: both;
display: block;
height: 8px;
height: 0;
}
</style></head>
<body>
</style>
<script type="text/javascript" src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script>
<script type="text/javascript">
function qrcodes() {
[].forEach.call(
document.getElementsByClassName("qrcode"),
(e, index) => {
new QRCode(e, {
text: "{{ qrcode }}",
correctLevel: QRCode.CorrectLevel.L
});
}
);
}
function scale() {
[].forEach.call(
document.getElementsByClassName("scale"),
(e, index) => {
var text_width = e.getBoundingClientRect().width;
var box_width = e.parentElement.getBoundingClientRect().width;
var percent = 100 * box_width / text_width + "%";
e.style.fontSize = percent;
}
);
}
</script>
</head>
<body onload="qrcodes(); scale();">
{% for cluster in clusters %}
<div>
<p>{{ intro }}</p>
<p>
<img src="{{ image_src }}" />
{% if img_logo_src %}
<img class="logo" src="{{ img_logo_src }}" />
{% endif %}
<table>
{% if clusternumber != None %}
<tr><td>cluster:</td></tr>
@@ -187,8 +249,15 @@ img.kube {
</p>
<p>
{% if url %}
{{ slides_are_at }}
<center>{{ url }}</center>
<p>
<span class="scale">{{ url }}</span>
</p>
{% endif %}
{% if img_bottom_src %}
<img class="bottom" src="{{ img_bottom_src }}" />
{% endif %}
</p>
</div>
{% if loop.index%pagesize==0 or loop.last %}
@@ -196,18 +265,21 @@ img.kube {
{% if backside %}
{% for x in range(pagesize) %}
<div class="back">
<br/>
<p>You got this at the workshop
<p>Thanks for attending
"Getting Started With Kubernetes and Container Orchestration"
during QCON London (March 2019).</p>
during CONFERENCE in Month YYYY!</p>
<p>If you liked that workshop,
I can train your team or organization
on Docker, container, and Kubernetes,
with curriculums of 1 to 5 days.
I can train your team, in person or
online, with custom courses of
any length and any level.
</p>
<p>Interested? Contact me at:</p>
{% if qrcode %}
<p>If you're interested, please scan that QR code to contact me:</p>
<span class="qrcode"></span>
{% else %}
<p>If you're interested, you can contact me at:</p>
{% endif %}
<p>jerome.petazzoni@gmail.com</p>
<p>Thank you!</p>
</div>
{% endfor %}
<span class="pagebreak"></span>

4
prepare-vms/www/README Normal file
View File

@@ -0,0 +1,4 @@
This directory will contain symlinks to HTML and PDF files for the cards
with the IP address, login, and password for the training environments.
The file "index.html" is empty on purpose: it prevents listing the files.

View File

View File

@@ -1,4 +1,4 @@
FROM alpine:3.9
RUN apk add --no-cache entr py-pip git
FROM alpine:3.11
RUN apk add --no-cache entr py3-pip git zip
COPY requirements.txt .
RUN pip install -r requirements.txt
RUN pip3 install -r requirements.txt

View File

@@ -1,7 +1,19 @@
# Uncomment and/or edit one of the the following lines if necessary.
#/ /kube-halfday.yml.html 200
#/ /kube-fullday.yml.html 200
#/ /kube-twodays.yml.html 200
#/ /kube-halfday.yml.html 200!
#/ /kube-fullday.yml.html 200!
#/ /kube-twodays.yml.html 200!
/ /helm.yml.html 200!
# And this allows to do "git clone https://container.training".
/info/refs service=git-upload-pack https://github.com/jpetazzo/container.training/info/refs?service=git-upload-pack
#/dockermastery https://www.udemy.com/course/docker-mastery/?referralCode=1410924A733D33635CCB
#/kubernetesmastery https://www.udemy.com/course/kubernetesmastery/?referralCode=7E09090AF9B79E6C283F
/dockermastery https://www.udemy.com/course/docker-mastery/?couponCode=SWEETFEBSALEC1
/kubernetesmastery https://www.udemy.com/course/kubernetesmastery/?couponCode=SWEETFEBSALEC4
# Shortlink for the QRCode
/q /qrcode.html 200
/next https://www.eventbrite.com/e/intensive-kubernetes-advanced-concepts-live-stream-tickets-102358725704
/chat https://gitter.im/jpetazzo/workshop-20200507-online

View File

@@ -1,34 +0,0 @@
# Our sample application
No assignment
# Kubernetes concepts
Do we want some kind of multiple-choice quiz?
# First contact with kubectl
Start some pre-defined image and check its logs
(Do we want to make a custom "mystery image" that shows a message
and then sleeps forever?)
Start another one (to make sure they understand that they need
to specify a unique name each time)
Provide as many ways as you can to figure out on which node
these pods are running (even if you only have one node).
# Exposing containers
Start a container running the official tomcat image.
Expose it.
Connect to it.
# Shipping apps
(We need a few images for a demo app other than DockerCoins?)
Start the components of the app.
Expose what needs to be exposed.
Connect to the app and check that it works.

View File

@@ -1,105 +0,0 @@
## Assignment: get Kubernetes
- In order to do the other assignments, we need a Kubernetes cluster
- Here are some *free* options:
- Docker Desktop
- Minikube
- Online sandbox like Katacoda
- You can also get a managed cluster (but this costs some money)
---
## Recommendation 1: Docker Desktop
- If you are already using Docker Desktop, use it for Kubernetes
- If you are running MacOS, [install Docker Desktop](https://docs.docker.com/docker-for-mac/install/)
- you will need a post-2010 Mac
- you will need macOS Sierra 10.12 or later
- If you are running Windows 10, [install Docker Desktop](https://docs.docker.com/docker-for-windows/install/)
- you will need Windows 10 64 bits Pro, Enterprise, or Education
- virtualization needs to be enabled in your BIOS
- Then [enable Kubernetes](https://blog.docker.com/2018/07/kubernetes-is-now-available-in-docker-desktop-stable-channel/) if it's not already on
---
## Recommendation 2: Minikube
- In some scenarios, you can't use Docker Desktop:
- if you run Linux
- if you are running an unsupported version of Windows
- You might also want to install Minikube for other reasons
(there are more tutorials and instructions out there for Minikube)
- Minikube installation is a bit more complex
(depending on which hypervisor and OS you are using)
---
## Minikube installation details
- Minikube typically runs in a local virtual machine
- It supports multiple hypervisors:
- VirtualBox (Linux, Mac, Windows)
- HyperV (Windows)
- HyperKit, VMware (Mac)
- KVM (Linux)
- Check the [documentation](https://kubernetes.io/docs/tasks/tools/install-minikube/) for details relevant to your setup
---
## Recommendation 3: learning platform
- Sometimes, you can't even install Minikube
(computer locked by IT policies; insufficient resources...)
- In that case, you can use a platform like:
- Katacoda
- Play-with-Kubernetes
---
## Recommendation 4: hosted cluster
- You can also get your own hosted cluster
- This will cost a little bit of money
(unless you have free hosting credits)
- Setup will vary depending on the provider, platform, etc.
---
class: assignment
- Make sure that you have a Kubernetes cluster
- You should be able to run `kubectl get nodes` and see a list of nodes
- These nodes should be in `Ready` state

View File

@@ -26,9 +26,10 @@ IPADDR = None
class State(object):
def __init__(self):
self.clipboard = ""
self.interactive = True
self.verify_status = False
self.simulate_type = True
self.verify_status = True
self.simulate_type = False
self.switch_desktop = False
self.sync_slides = False
self.open_links = False
@@ -38,6 +39,7 @@ class State(object):
def load(self):
data = yaml.load(open("state.yaml"))
self.clipboard = str(data["clipboard"])
self.interactive = bool(data["interactive"])
self.verify_status = bool(data["verify_status"])
self.simulate_type = bool(data["simulate_type"])
@@ -51,6 +53,7 @@ class State(object):
def save(self):
with open("state.yaml", "w") as f:
yaml.dump(dict(
clipboard=self.clipboard,
interactive=self.interactive,
verify_status=self.verify_status,
simulate_type=self.simulate_type,
@@ -66,6 +69,8 @@ class State(object):
state = State()
outfile = open("autopilot.log", "w")
def hrule():
return "="*int(subprocess.check_output(["tput", "cols"]))
@@ -85,9 +90,11 @@ class Snippet(object):
# On single-line snippets, the data follows the method immediately
if '\n' in content:
self.method, self.data = content.split('\n', 1)
else:
self.data = self.data.strip()
elif ' ' in content:
self.method, self.data = content.split(' ', 1)
self.data = self.data.strip()
else:
self.method, self.data = content, None
self.next = None
def __str__(self):
@@ -186,7 +193,7 @@ def wait_for_prompt():
if last_line == "$":
# This is a perfect opportunity to grab the node's IP address
global IPADDR
IPADDR = re.findall("^\[(.*)\]", output, re.MULTILINE)[-1]
IPADDR = re.findall("\[(.*)\]", output, re.MULTILINE)[-1]
return
# When we are in an alpine container, the prompt will be "/ #"
if last_line == "/ #":
@@ -235,6 +242,8 @@ 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
(Or use workshopctl tmux)
3. If you cannot control a remote tmux:
tmux new-session ssh docker@{ipaddr}
@@ -259,26 +268,11 @@ for slide in re.split("\n---?\n", content):
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.")
logging.debug("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')
@@ -288,7 +282,7 @@ setup_tmux_and_ssh()
try:
state.load()
logging.info("Successfully loaded state from file.")
logging.debug("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.)
@@ -297,6 +291,7 @@ 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):
@@ -320,10 +315,147 @@ def check_bounds():
state.slide = len(slides)-1
##########################################################
# All functions starting with action_ correspond to the
# code to be executed when seeing ```foo``` blocks in the
# input. ```foo``` would call action_foo(state, snippet).
##########################################################
def send_keys(keys):
subprocess.check_call(["tmux", "send-keys", keys])
# Send a single key.
# Useful for special keys, e.g. tmux interprets these strings:
# ^C (and all other sequences starting with a caret)
# Space
# ... and many others (check tmux manpage for details).
def action_key(state, snippet):
send_keys(snippet.data)
# Send multiple keys.
# If keystroke simulation is off, all keys are sent at once.
# If keystroke simulation is on, keys are sent one by one, with a delay between them.
def action_keys(state, snippet, keys=None):
if keys is None:
keys = snippet.data
if not state.simulate_type:
send_keys(keys)
else:
for key in keys:
if key == ";":
key = "\\;"
if key == "\n":
if interruptible_sleep(1): return
send_keys(key)
if interruptible_sleep(0.15*random.random()): return
if key == "\n":
if interruptible_sleep(1): return
def action_hide(state, snippet):
if state.run_hidden:
action_bash(state, snippet)
def action_bash(state, snippet):
data = snippet.data
# 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
action_keys(state, snippet, 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()
def action_copy(state, snippet):
screen = capture_pane()
matches = re.findall(snippet.data, screen, flags=re.DOTALL)
if len(matches) == 0:
raise Exception("Could not find regex {} in output.".format(snippet.data))
# Arbitrarily get the most recent match
match = matches[-1]
# Remove line breaks (like a screen copy paste would do)
match = match.replace('\n', '')
logging.debug("Copied {} to clipboard.".format(match))
state.clipboard = match
def action_paste(state, snippet):
logging.debug("Pasting {} from clipboard.".format(state.clipboard))
action_keys(state, snippet, state.clipboard)
def action_check(state, snippet):
wait_for_prompt()
check_exit_status()
def action_open(state, snippet):
# Cheap way to get node1's IP address
screen = capture_pane()
url = snippet.data.replace("/node1", "/{}".format(IPADDR))
# This should probably be adapted to run on different OS
if state.open_links:
subprocess.check_output(["xdg-open", url])
focus_browser()
if state.interactive:
print("Press any key to continue to next step...")
click.getchar()
def action_tmux(state, snippet):
subprocess.check_call(["tmux"] + snippet.data.split())
def action_unknown(state, snippet):
logging.warning("Unknown method {}: {!r}".format(snippet.method, snippet.data))
def run_snippet(state, snippet):
logging.info("Running with method {}: {}".format(snippet.method, snippet.data))
try:
action = globals()["action_"+snippet.method]
except KeyError:
action = action_unknown
try:
action(state, snippet)
result = "OK"
except:
result = "ERR"
logging.exception("While running method {} with {!r}".format(snippet.method, snippet.data))
# Try to recover
try:
wait_for_prompt()
except:
subprocess.check_call(["tmux", "new-window"])
wait_for_prompt()
outfile.write("{} SLIDE={} METHOD={} DATA={!r}\n".format(result, state.slide, snippet.method, snippet.data))
outfile.flush()
while True:
state.save()
slide = slides[state.slide]
snippet = slide.snippets[state.snippet-1] if state.snippet else None
if state.snippet and state.snippet <= len(slide.snippets):
snippet = slide.snippets[state.snippet-1]
else:
snippet = None
click.clear()
print("[Slide {}/{}] [Snippet {}/{}] [simulate_type:{}] [verify_status:{}] "
"[switch_desktop:{}] [sync_slides:{}] [open_links:{}] [run_hidden:{}]"
@@ -385,7 +517,10 @@ while True:
# continue until next timeout
state.interactive = False
elif command in ("y", "\r", " "):
if not snippet:
if snippet:
run_snippet(state, snippet)
move_forward()
else:
# Advance to next snippet
# Advance until a slide that has snippets
while not slides[state.slide].snippets:
@@ -395,59 +530,5 @@ while True:
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" or (method == "hide" and state.run_hidden):
# 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
if state.open_links:
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))

View File

@@ -14,6 +14,7 @@ once)
./appendcheck.py $YAML.html
done
fi
zip -qr slides.zip . && echo "Created slides.zip archive."
;;
forever)

View File

@@ -1,7 +1,7 @@
class: title
# Advanced Dockerfiles
# Advanced Dockerfile Syntax
![construction](images/title-advanced-dockerfiles.jpg)
@@ -12,7 +12,10 @@ class: title
We have seen simple Dockerfiles to illustrate how Docker build
container images.
In this section, we will see more Dockerfile commands.
In this section, we will give a recap of the Dockerfile syntax,
and introduce advanced Dockerfile commands that we might
come across sometimes; or that we might want to use in some
specific scenarios.
---
@@ -420,3 +423,8 @@ ONBUILD COPY . /src
* You can't chain `ONBUILD` instructions with `ONBUILD`.
* `ONBUILD` can't be used to trigger `FROM` instructions.
???
:EN:- Advanced Dockerfile syntax
:FR:- Dockerfile niveau expert

View File

@@ -280,3 +280,8 @@ CONTAINER ID IMAGE ... CREATED STATUS
5c1dfd4d81f1 jpetazzo/clock ... 40 min. ago Exited (0) 40 min. ago
b13c164401fb ubuntu ... 55 min. ago Exited (130) 53 min. ago
```
???
:EN:- Foreground and background containers
:FR:- Exécution interactive ou en arrière-plan

View File

@@ -167,3 +167,8 @@ Automated process = good.
In the next chapter, we will learn how to automate the build
process by writing a `Dockerfile`.
???
:EN:- Building our first images interactively
:FR:- Fabriquer nos premières images à la main

View File

@@ -222,21 +222,63 @@ f9e8f1642759 About an hour ago /bin/sh -c apt-get install fi 1.627 MB
---
## Introducing JSON syntax
class: extra-details
Most Dockerfile arguments can be passed in two forms:
## Why `sh -c`?
* plain string:
* On UNIX, to start a new program, we need two system calls:
- `fork()`, to create a new child process;
- `execve()`, to replace the new child process with the program to run.
* Conceptually, `execve()` works like this:
`execve(program, [list, of, arguments])`
* When we run a command, e.g. `ls -l /tmp`, something needs to parse the command.
(i.e. split the program and its arguments into a list.)
* The shell is usually doing that.
(It also takes care of expanding environment variables and special things like `~`.)
---
class: extra-details
## Why `sh -c`?
* When we do `RUN ls -l /tmp`, the Docker builder needs to parse the command.
* Instead of implementing its own parser, it outsources the job to the shell.
* That's why we see `sh -c ls -l /tmp` in that case.
* But we can also do the parsing jobs ourselves.
* This means passing `RUN` a list of arguments.
* This is called the *exec syntax*.
---
## Shell syntax vs exec syntax
Dockerfile commands that execute something can have two forms:
* plain string, or *shell syntax*:
<br/>`RUN apt-get install figlet`
* JSON list:
* JSON list, or *exec syntax*:
<br/>`RUN ["apt-get", "install", "figlet"]`
We are going to change our Dockerfile to see how it affects the resulting image.
---
## Using JSON syntax in our Dockerfile
## Using exec syntax in our Dockerfile
Let's change our Dockerfile as follows!
@@ -254,7 +296,7 @@ $ docker build -t figlet .
---
## JSON syntax vs string syntax
## History with exec syntax
Compare the new history:
@@ -269,24 +311,62 @@ IMAGE CREATED CREATED BY SIZE
<missing> 4 days ago /bin/sh -c #(nop) ADD file:b 187.8 MB
```
* JSON syntax specifies an *exact* command to execute.
* Exec syntax specifies an *exact* command to execute.
* String syntax specifies a command to be wrapped within `/bin/sh -c "..."`.
* Shell syntax specifies a command to be wrapped within `/bin/sh -c "..."`.
---
## When to use JSON syntax and string syntax
## When to use exec syntax and shell syntax
* String syntax:
* shell syntax:
* is easier to write
* interpolates environment variables and other shell expressions
* creates an extra process (`/bin/sh -c ...`) to parse the string
* requires `/bin/sh` to exist in the container
* JSON syntax:
* exec syntax:
* is harder to write (and read!)
* passes all arguments without extra processing
* doesn't create an extra process
* doesn't require `/bin/sh` to exist in the container
---
## Pro-tip: the `exec` shell built-in
POSIX shells have a built-in command named `exec`.
`exec` should be followed by a program and its arguments.
From a user perspective:
- it looks like the shell exits right away after the command execution,
- in fact, the shell exits just *before* command execution;
- or rather, the shell gets *replaced* by the command.
---
## Example using `exec`
```dockerfile
CMD exec figlet -f script hello
```
In this example, `sh -c` will still be used, but
`figlet` will be PID 1 in the container.
The shell gets replaced by `figlet` when `figlet` starts execution.
This allows to run processes as PID 1 without using JSON.
???
:EN:- Towards automated, reproducible builds
:EN:- Writing our first Dockerfile
:FR:- Rendre le processus automatique et reproductible
:FR:- Écrire son premier Dockerfile

View File

@@ -272,3 +272,7 @@ $ docker run -it --entrypoint bash myfiglet
root@6027e44e2955:/#
```
???
:EN:- CMD and ENTRYPOINT
:FR:- CMD et ENTRYPOINT

View File

@@ -322,3 +322,11 @@ You can:
Each copy will run in a different network, totally isolated from the other.
This is ideal to debug regressions, do side-by-side comparisons, etc.
???
:EN:- Using compose to describe an environment
:EN:- Connecting services together with a *Compose file*
:FR:- Utiliser Compose pour décrire son environnement
:FR:- Écrire un *Compose file* pour connecter les services entre eux

View File

@@ -104,22 +104,6 @@ like Windows, macOS, Solaris, FreeBSD ...
---
## rkt
* Compares to `runc`.
* No daemon or API.
* Strong emphasis on security (through privilege separation).
* Networking has to be set up separately (e.g. through CNI plugins).
* Partial image management (pull, but no push).
(Image build is handled by separate tools.)
---
## CRI-O
* Designed to be used with Kubernetes as a simple, basic runtime.

View File

@@ -226,3 +226,13 @@ We've learned how to:
In the next chapter, we will see how to connect
containers together without exposing their ports.
???
:EN:Connecting containers
:EN:- Container networking basics
:EN:- Exposing a container
:FR:Connecter les conteneurs
:FR:- Description du modèle réseau des conteneurs
:FR:- Exposer un conteneur

View File

@@ -98,3 +98,8 @@ Success!
* Place it in a different directory, with the `WORKDIR` instruction.
* Even better, use the `gcc` official image.
???
:EN:- The build cache
:FR:- Tirer parti du cache afin d'optimiser la vitesse de *build*

View File

@@ -431,3 +431,8 @@ services:
- It's OK (and even encouraged) to start simple and evolve as needed.
- Feel free to review this chapter later (after writing a few Dockerfiles) for inspiration!
???
:EN:- Dockerfile tips, tricks, and best practices
:FR:- Bonnes pratiques pour la construction des images

View File

@@ -290,3 +290,8 @@ bash: figlet: command not found
* We have a clear definition of our environment, and can share it reliably with others.
* Let's see in the next chapters how to bake a custom image with `figlet`!
???
:EN:- Running our first container
:FR:- Lancer nos premiers conteneurs

View File

@@ -226,3 +226,8 @@ docker export <container_id> | tar tv
```
This will give a detailed listing of the content of the container.
???
:EN:- Troubleshooting and getting inside a container
:FR:- Inspecter un conteneur en détail, en *live* ou *post-mortem*

View File

@@ -0,0 +1,137 @@
# Init systems and PID 1
In this chapter, we will consider:
- the role of PID 1 in the world of Docker,
- how to avoid some common pitfalls due to the misuse of init systems.
---
## What's an init system?
- On UNIX, the "init system" (or "init" in short) is PID 1.
- It is the first process started by the kernel when the system starts.
- It has multiple responsibilities:
- start every other process on the machine,
- reap orphaned zombie processes.
---
class: extra-details
## Orphaned zombie processes ?!?
- When a process exits (or "dies"), it becomes a "zombie".
(Zombie processes show up in `ps` or `top` with the status code `Z`.)
- Its parent process must *reap* the zombie process.
(This is done by calling `waitpid()` to retrieve the process' exit status.)
- When a process exits, if it has child processes, these processes are "orphaned."
- They are then re-parented to PID 1, init.
- Init therefore needs to take care of these orphaned processes when they exit.
---
## Don't use init systems in containers
- It's often tempting to use an init system or a process manager.
(Examples: *systemd*, *supervisord*...)
- Our containers are then called "system containers".
(By contrast with "application containers".)
- "System containers" are similar to lightweight virtual machines.
- They have multiple downsides:
- when starting multiple processes, their logs get mixed on stdout,
- if the application process dies, the container engine doesn't see it.
- Overall, they make it harder to operate troubleshoot containerized apps.
---
## Exceptions and workarounds
- Sometimes, it's convenient to run a real init system like *systemd*.
(Example: a CI system whose goal is precisely to test an init script or unit file.)
- If we need to run multiple processes: can we use multiple containers?
(Example: [this Compose file](https://github.com/jpetazzo/container.training/blob/master/compose/simple-k8s-control-plane/docker-compose.yaml) runs multiple processes together.)
- When deploying with Kubernetes:
- a container belong to a pod,
- a pod can have multiple containers.
---
## What about these zombie processes?
- Our application runs as PID 1 in the container.
- Our application may or may not be designed to reap zombie processes.
- If our application uses subprocesses and doesn't reap them ...
... this can lead to PID exhaustion!
(Or, more realistically, to a confusing herd of zombie processes.)
- How can we solve this?
---
## Tini to the rescue
- Docker can automatically provide a minimal `init` process.
- This is enabled with `docker run --init ...`
- It uses a small init system ([tini](https://github.com/krallin/tini)) as PID 1:
- it reaps zombies,
- it forwards signals,
- it exits when the child exits.
- It is totally transparent to our application.
- We should use it if our application creates subprocess but doesn't reap them.
---
class: extra-details
## What about Kubernetes?
- Kubernetes does not expose that `--init` option.
- However, we can achieve the same result with [Process Namespace Sharing](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/).
- When Process Namespace Sharing is enabled, PID 1 will be `pause`.
- That `pause` process takes care of reaping zombies.
- Process Namespace Sharing is available since Kubernetes 1.16.
- If you're using an older version of Kubernetes ...
... you might have to add `tini` explicitly to your Docker image.

View File

@@ -375,3 +375,13 @@ We've learned how to:
* Understand Docker image namespacing.
* Search and download images.
???
:EN:Building images
:EN:- Containers, images, and layers
:EN:- Image addresses and tags
:EN:- Finding and transferring images
:FR:Construire des images
:FR:- La différence entre un conteneur et une image
:FR:- La notion de *layer* partagé entre images

View File

@@ -102,29 +102,44 @@ class: extra-details
---
## Docker Desktop for Mac and Docker Desktop for Windows
## Docker Desktop
* Special Docker Editions that integrate well with their respective host OS
* Special Docker edition available for Mac and Windows
* Provide user-friendly GUI to edit Docker configuration and settings
* Integrates well with the host OS:
* Leverage the host OS virtualization subsystem (e.g. the [Hypervisor API](https://developer.apple.com/documentation/hypervisor) on macOS)
* installed like normal user applications on the host
* Installed like normal user applications on the host
* provides user-friendly GUI to edit Docker configuration and settings
* Under the hood, they both run a tiny VM (transparent to our daily use)
* Only support running one Docker VM at a time ...
* Access network resources like normal applications
<br/>(and therefore, play better with enterprise VPNs and firewalls)
* Support filesystem sharing through volumes (we'll talk about this later)
* They only support running one Docker VM at a time ...
<br/>
... but we can use `docker-machine`, the Docker Toolbox, VirtualBox, etc. to get a cluster.
---
class: extra-details
## Docker Desktop internals
* Leverages the host OS virtualization subsystem
(e.g. the [Hypervisor API](https://developer.apple.com/documentation/hypervisor) on macOS)
* Under the hood, runs a tiny VM
(transparent to our daily use)
* Accesses network resources like normal applications
(and therefore, plays better with enterprise VPNs and firewalls)
* Supports filesystem sharing through volumes
(we'll talk about this later)
---
## Running Docker on macOS and Windows
When you execute `docker version` from the terminal:

View File

@@ -80,3 +80,8 @@ $ docker ps --filter label=owner=alice
(To determine internal cross-billing, or who to page in case of outage.)
* etc.
???
:EN:- Using labels to identify containers
:FR:- Étiqueter ses conteneurs avec des méta-données

View File

@@ -391,3 +391,10 @@ We've learned how to:
* Use a simple local development workflow.
???
:EN:Developing with containers
:EN:- “Containerize” a development environment
:FR:Développer au jour le jour
:FR:- « Containeriser » son environnement de développement

View File

@@ -313,3 +313,11 @@ virtually "free."
* Sometimes, we want to inspect a specific intermediary build stage.
* Or, we want to describe multiple images using a single Dockerfile.
???
:EN:Optimizing our images and their build process
:EN:- Leveraging multi-stage builds
:FR:Optimiser les images et leur construction
:FR:- Utilisation d'un *multi-stage build*

View File

@@ -130,3 +130,12 @@ $ docker inspect --format '{{ json .Created }}' <containerID>
* The optional `json` keyword asks for valid JSON output.
<br/>(e.g. here it adds the surrounding double-quotes.)
???
:EN:Managing container lifecycle
:EN:- Naming and inspecting containers
:FR:Suivre ses conteneurs à la loupe
:FR:- Obtenir des informations détaillées sur un conteneur
:FR:- Associer un identifiant unique à un conteneur

View File

@@ -0,0 +1,47 @@
# Container Super-structure
- Multiple orchestration platforms support some kind of container super-structure.
(i.e., a construct or abstraction bigger than a single container.)
- For instance, on Kubernetes, this super-structure is called a *pod*.
- A pod is a group of containers (it could be a single container, too).
- These containers run together, on the same host.
(A pod cannot straddle multiple hosts.)
- All the containers in a pod have the same IP address.
- How does that map to the Docker world?
---
class: pic
## Anatomy of a Pod
![Pods](images/kubernetes_pods.svg)
---
## Pods in Docker
- The containers inside a pod share the same network namespace.
(Just like when using `docker run --net=container:<container_id>` with the CLI.)
- As a result, they can communicate together over `localhost`.
- In addition to "our" containers, the pod has a special container, the *sandbox*.
- That container uses a special image: `k8s.gcr.io/pause`.
(This is visible when listing containers running on a Kubernetes node.)
- Containers within a pod have independent filesystems.
- They can share directories by using a mechanism called *volumes.*
(Which is similar to the concept of volumes in Docker.)

View File

@@ -100,3 +100,25 @@ class: extra-details
* In "Build rules" block near page bottom, put `/www` in "Build Context" column (or whichever directory the Dockerfile is in).
* Click "Save and Build" to build the repository immediately (without waiting for a git push).
* Subsequent builds will happen automatically, thanks to GitHub hooks.
---
## Building on the fly
- Some services can build images on the fly from a repository
- Example: [ctr.run](https://ctr.run/)
.exercise[
- Use ctr.run to automatically build a container image and run it:
```bash
docker run ctr.run/github.com/undefinedlabs/hello-world
```
]
There might be a long pause before the first layer is pulled,
because the API behind `docker pull` doesn't allow to stream build logs, and there is no feedback during the build.
It is possible to view the build logs by setting up an account on [ctr.run](https://ctr.run/).

View File

@@ -175,3 +175,10 @@ class: extra-details
* This will cause some CLI and TUI programs to redraw the screen.
* But not all of them.
???
:EN:- Restarting old containers
:EN:- Detaching and reattaching to container
:FR:- Redémarrer des anciens conteneurs
:FR:- Se détacher et rattacher à des conteneurs

View File

@@ -125,3 +125,11 @@ Server:
]
If this doesn't work, raise your hand so that an instructor can assist you!
???
:EN:Container concepts
:FR:Premier contact avec les conteneurs
:EN:- What's a container engine?
:FR:- Qu'est-ce qu'un *container engine* ?

View File

@@ -1 +0,0 @@
../swarm/links.md

View File

@@ -0,0 +1,12 @@
# Links and resources
- [Docker Community Slack](https://community.docker.com/registrations/groups/4316)
- [Docker Community Forums](https://forums.docker.com/)
- [Docker Hub](https://hub.docker.com)
- [Docker Blog](https://blog.docker.com/)
- [Docker documentation](https://docs.docker.com/)
- [Docker on StackOverflow](https://stackoverflow.com/questions/tagged/docker)
- [Docker on Twitter](https://twitter.com/docker)
- [Play With Docker Hands-On Labs](https://training.play-with-docker.com/)
.footnote[These slides (and future updates) are on → https://container.training/]

View File

@@ -11,10 +11,10 @@ class State(object):
self.section_title = None
self.section_start = 0
self.section_slides = 0
self.chapters = {}
self.modules = {}
self.sections = {}
def show(self):
if self.section_title.startswith("chapter-"):
if self.section_title.startswith("module-"):
return
print("{0.section_title}\t{0.section_start}\t{0.section_slides}".format(self))
self.sections[self.section_title] = self.section_slides
@@ -38,10 +38,10 @@ for line in open(sys.argv[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])
if toc_links and state.section_title.startswith("module-"):
if state.section_title not in state.modules:
state.modules[state.section_title] = []
state.modules[state.section_title].append(toc_links[0])
# This is really hackish
if line.startswith("class:"):
for klass in EXCLUDED:
@@ -51,7 +51,7 @@ for line in open(sys.argv[1]):
state.show()
for chapter in sorted(state.chapters, key=lambda f: int(f.split("-")[1])):
chapter_size = sum(state.sections[s] for s in state.chapters[chapter])
print("{}\t{}\t{}".format("total size for", chapter, chapter_size))
for module in sorted(state.modules, key=lambda f: int(f.split("-")[1])):
module_size = sum(state.sections[s] for s in state.modules[module])
print("{}\t{}\t{}".format("total size for", module, module_size))

118
slides/fix-redirects.sh Executable file
View File

@@ -0,0 +1,118 @@
#!/bin/sh
# This script helps to add "force-redirects" where needed.
# This might replace your entire git repos with Vogon poetry.
# Use at your own peril!
set -eu
# The easiest way to set this env var is by copy-pasting from
# the netlify web dashboard, then doctoring the output a bit.
# Yeah, that's gross, but after spending 10 minutes with the
# API and the CLI and OAuth, it took about 10 seconds to do it
# with le copier-coller, so ... :)
SITES="
2020-01-caen
2020-01-zr
2020-02-caen
2020-02-enix
2020-02-outreach
2020-02-vmware
2020-03-ardan
2020-03-qcon
alfun-2019-06
boosterconf2018
clt-2019-10
dc17eu
decembre2018
devopsdaysams2018
devopsdaysmsp2018
gotochgo2018
gotochgo2019
indexconf2018
intro-2019-01
intro-2019-04
intro-2019-06
intro-2019-08
intro-2019-09
intro-2019-11
intro-2019-12
k8s2d
kadm-2019-04
kadm-2019-06
kube
kube-2019-01
kube-2019-02
kube-2019-03
kube-2019-04
kube-2019-06
kube-2019-08
kube-2019-09
kube-2019-10
kube-2019-11
lisa-2019-10
lisa16t1
lisa17m7
lisa17t9
maersk-2019-07
maersk-2019-08
ndcminnesota2018
nr-2019-08
oscon2018
oscon2019
osseu17
pycon2019
qconsf18wkshp
qconsf2017intro
qconsf2017swarm
qconsf2018
qconuk2019
septembre2018
sfsf-2019-06
srecon2018
swarm2017
velny-k8s101-2018
velocity-2019-11
velocityeu2018
velocitysj2018
vmware-2019-11
weka
wwc-2019-10
wwrk-2019-05
wwrk-2019-06
"
for SITE in $SITES; do
echo "##### $SITE"
git checkout -q origin/$SITE
# No _redirects? No problem.
if ! [ -f _redirects ]; then
continue
fi
# If there is already a force redirect on /, we're good.
if grep '^/ .* 200!' _redirects; then
continue
fi
# If there is a redirect on / ... and it's not forced ... do something.
if grep "^/ .* 200$" _redirects; then
echo "##### $SITE needs to be patched"
sed -i 's,^/ \(.*\) 200$,/ \1 200!,' _redirects
git add _redirects
git commit -m "fix-redirects.sh: adding forced redirect"
git push origin HEAD:$SITE
continue
fi
if grep "^/ " _redirects; then
echo "##### $SITE with / but no status code"
echo "##### Should I add '200!' ?"
read foo
sed -i 's,^/ \(.*\)$,/ \1 200!,' _redirects
git add _redirects
git commit -m "fix-redirects.sh: adding status code and forced redirect"
git push origin HEAD:$SITE
continue
fi
echo "##### $SITE without / ?"
cat _redirects
done

36
slides/helm.yml Normal file
View File

@@ -0,0 +1,36 @@
title: |
Helm Workshop
CNCF Paris
chat: "[Gitter](https://gitter.im/jpetazzo/workshop-20200507-online)"
gitrepo: github.com/jpetazzo/container.training
slides: https://2020-05-helm.container.training/
#slidenumberprefix: "#SomeHashTag &mdash; "
exclude:
- self-paced
content:
- shared/title.md
- logistics.md
- k8s/intro.md
- shared/about-slides.md
- shared/chat-room-twitch.md
#- shared/chat-room-zoom-meeting.md
#- shared/chat-room-zoom-webinar.md
- shared/toc.md
-
- shared/prereqs.md
- shared/webssh.md
- shared/connecting.md
- k8s/kubercoins.md
- k8s/helm-intro.md
- k8s/helm-chart-format.md
- k8s/helm-create-basic-chart.md
- k8s/helm-create-better-chart.md
- k8s/helm-secrets.md
#- k8s/exercise-helm.md
- shared/thankyou.md

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -13,7 +13,7 @@
viewBox="0 0 1600 900"
version="1.1"
id="svg696"
sodipodi:docname="how-k8s-works-3.svg"
sodipodi:docname="03.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
enable-background="new">
<metadata
@@ -42,12 +42,12 @@
id="namedview698"
showgrid="false"
inkscape:zoom="0.64"
inkscape:cx="796.38378"
inkscape:cx="521.38378"
inkscape:cy="596.50212"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-y="1098"
inkscape:window-maximized="0"
inkscape:current-layer="g4090"
inkscape:current-layer="g3333"
units="px"
inkscape:snap-object-midpoints="true" />
<title
@@ -561,17 +561,17 @@
id="tspan3660"
y="334.98642"
x="-215.28352"
sodipodi:role="line">$ kubectl run web \</tspan><tspan
sodipodi:role="line">$ kubectl create \</tspan><tspan
style="stroke-width:0.89526182"
y="379.74951"
x="-215.28352"
sodipodi:role="line"
id="tspan4926"> --image=nginx \</tspan><tspan
id="tspan1139"> deployment web \</tspan><tspan
style="stroke-width:0.89526182"
y="424.5126"
x="-215.28352"
sodipodi:role="line"
id="tspan4928"> --replicas=3</tspan></text>
id="tspan4928"> --image=nginx</tspan></text>
</g>
<g
transform="matrix(2.7869707,0,0,2.7869707,980.45108,349.43174)"

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -13,7 +13,7 @@
viewBox="0 0 1600 900"
version="1.1"
id="svg696"
sodipodi:docname="how-k8s-works-4.svg"
sodipodi:docname="04.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
enable-background="new">
<metadata
@@ -42,12 +42,12 @@
id="namedview698"
showgrid="false"
inkscape:zoom="0.64"
inkscape:cx="796.38378"
inkscape:cx="521.38378"
inkscape:cy="596.50212"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-y="1098"
inkscape:window-maximized="0"
inkscape:current-layer="g1250"
inkscape:current-layer="g3333"
units="px"
inkscape:snap-object-midpoints="true" />
<title
@@ -561,17 +561,17 @@
id="tspan3660"
y="334.98642"
x="-215.28352"
sodipodi:role="line">$ kubectl run web \</tspan><tspan
sodipodi:role="line">$ kubectl create \</tspan><tspan
style="stroke-width:0.89526182"
y="379.74951"
x="-215.28352"
sodipodi:role="line"
id="tspan4926"> --image=nginx \</tspan><tspan
id="tspan1139"> deployment web \</tspan><tspan
style="stroke-width:0.89526182"
y="424.5126"
x="-215.28352"
sodipodi:role="line"
id="tspan4928"> --replicas=3</tspan></text>
id="tspan4928"> --image=nginx</tspan></text>
</g>
<g
transform="matrix(2.7869707,0,0,2.7869707,980.45108,349.43174)"

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -13,7 +13,7 @@
viewBox="0 0 1600 900"
version="1.1"
id="svg696"
sodipodi:docname="how-k8s-works-05.svg"
sodipodi:docname="05.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
enable-background="new">
<metadata
@@ -42,10 +42,10 @@
id="namedview698"
showgrid="false"
inkscape:zoom="0.64"
inkscape:cx="521.38378"
inkscape:cx="246.38378"
inkscape:cy="596.50212"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-y="1098"
inkscape:window-maximized="0"
inkscape:current-layer="g3333"
units="px"
@@ -558,37 +558,32 @@
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:35.8104744px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.89526182"
xml:space="preserve"><tspan
style="stroke-width:0.89526182"
id="tspan3660"
y="334.98642"
x="-215.28352"
sodipodi:role="line">$ kubectl run web \</tspan><tspan
sodipodi:role="line"
id="tspan1146">$ kubectl create \</tspan><tspan
style="stroke-width:0.89526182"
y="379.74951"
x="-215.28352"
sodipodi:role="line"
id="tspan4926"> --image=nginx \</tspan><tspan
id="tspan1150"> deployment web \</tspan><tspan
style="stroke-width:0.89526182"
y="424.5126"
x="-215.28352"
sodipodi:role="line"
id="tspan4928"> --replicas=3</tspan><tspan
id="tspan4926"> --image=nginx</tspan><tspan
style="stroke-width:0.89526182"
y="469.2757"
x="-215.28352"
sodipodi:role="line"
id="tspan1141">...</tspan><tspan
id="tspan1143">deployment.apps/web</tspan><tspan
style="stroke-width:0.89526182"
y="514.03882"
x="-215.28352"
sodipodi:role="line"
id="tspan1143">deployment.apps/web</tspan><tspan
style="stroke-width:0.89526182"
y="558.80188"
x="-215.28352"
sodipodi:role="line"
id="tspan1147">created</tspan><tspan
style="stroke-width:0.89526182"
y="603.565"
y="558.80188"
x="-215.28352"
sodipodi:role="line"
id="tspan1145">$</tspan></text>

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -13,7 +13,7 @@
viewBox="0 0 1600 900"
version="1.1"
id="svg696"
sodipodi:docname="how-k8s-works-11.svg"
sodipodi:docname="11.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
enable-background="new">
<metadata
@@ -42,10 +42,10 @@
id="namedview698"
showgrid="false"
inkscape:zoom="0.64"
inkscape:cx="796.38378"
inkscape:cx="521.38378"
inkscape:cy="596.50212"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-y="1098"
inkscape:window-maximized="0"
inkscape:current-layer="g3409"
units="px"
@@ -1132,78 +1132,6 @@
y="125.23392"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.49064583">PENDING</tspan></text>
</g>
<g
inkscape:label="pod 2"
id="g1233"
style="display:inline">
<rect
y="139.72913"
x="287.1362"
height="36.022667"
width="174.12718"
id="rect15580"
style="display:inline;opacity:1;fill:#ffaaaa;fill-opacity:1;stroke:none;stroke-width:8.37233353;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter15564)" />
<text
id="text15584"
y="166.5461"
x="292.32904"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.96796608px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.69919914"
xml:space="preserve"><tspan
style="stroke-width:0.69919914"
y="166.5461"
x="292.32904"
id="tspan15582"
sodipodi:role="line">Pod</tspan></text>
<text
id="text15598"
y="165.23392"
x="351.05563"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.49064583"
xml:space="preserve"
inkscape:label="pod 2 status"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.49064583"
y="165.23392"
x="351.05563"
id="tspan15596"
sodipodi:role="line">PENDING</tspan></text>
</g>
<g
inkscape:label="pod 3"
id="g1226"
style="display:inline">
<rect
style="display:inline;opacity:1;fill:#ffaaaa;fill-opacity:1;stroke:none;stroke-width:8.37233353;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter15564)"
id="rect15586"
width="174.12718"
height="36.022667"
x="287.1362"
y="179.72913"
inkscape:label="rectangle" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.96796608px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.69919914"
x="292.32904"
y="206.5461"
id="text15590"
inkscape:label="label"><tspan
sodipodi:role="line"
id="tspan15588"
x="292.32904"
y="206.5461"
style="stroke-width:0.69919914">Pod</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.49064583"
x="351.05563"
y="205.23392"
id="text15602"
inkscape:label="status"><tspan
sodipodi:role="line"
id="tspan15600"
x="351.05563"
y="205.23392"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.49064583">PENDING</tspan></text>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -13,7 +13,7 @@
viewBox="0 0 1600 900"
version="1.1"
id="svg696"
sodipodi:docname="how-k8s-works-12.svg"
sodipodi:docname="12.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
enable-background="new">
<metadata
@@ -42,12 +42,12 @@
id="namedview698"
showgrid="false"
inkscape:zoom="0.64"
inkscape:cx="796.38378"
inkscape:cx="521.38378"
inkscape:cy="596.50212"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-y="1098"
inkscape:window-maximized="0"
inkscape:current-layer="g4153"
inkscape:current-layer="g3409"
units="px"
inkscape:snap-object-midpoints="true" />
<title
@@ -1132,78 +1132,6 @@
y="125.23392"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.49064583">PENDING</tspan></text>
</g>
<g
inkscape:label="pod 2"
id="g1233"
style="display:inline">
<rect
y="139.72913"
x="287.1362"
height="36.022667"
width="174.12718"
id="rect15580"
style="display:inline;opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:8.37233353;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter15564)" />
<text
id="text15584"
y="166.5461"
x="292.32904"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.96796608px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.69919914"
xml:space="preserve"><tspan
style="stroke-width:0.69919914"
y="166.5461"
x="292.32904"
id="tspan15582"
sodipodi:role="line">Pod</tspan></text>
<text
id="text15598"
y="165.23392"
x="351.05563"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.49064583"
xml:space="preserve"
inkscape:label="pod 2 status"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.49064583"
y="165.23392"
x="351.05563"
id="tspan15596"
sodipodi:role="line">PENDING</tspan></text>
</g>
<g
inkscape:label="pod 3"
id="g1226"
style="display:inline">
<rect
style="display:inline;opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:8.37233353;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter15564)"
id="rect15586"
width="174.12718"
height="36.022667"
x="287.1362"
y="179.72913"
inkscape:label="rectangle" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.96796608px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.69919914"
x="292.32904"
y="206.5461"
id="text15590"
inkscape:label="label"><tspan
sodipodi:role="line"
id="tspan15588"
x="292.32904"
y="206.5461"
style="stroke-width:0.69919914">Pod</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.49064583"
x="351.05563"
y="205.23392"
id="text15602"
inkscape:label="status"><tspan
sodipodi:role="line"
id="tspan15600"
x="351.05563"
y="205.23392"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.62533379px;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.49064583">PENDING</tspan></text>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 78 KiB

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