mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-04-10 04:16:55 +00:00
Compare commits
212 Commits
oscon2018
...
qconsf2018
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
687b61dbf4 | ||
|
|
22f32ee4c0 | ||
|
|
9e051abb32 | ||
|
|
ee3c2c3030 | ||
|
|
45f9d7bf59 | ||
|
|
efb72c2938 | ||
|
|
357d341d82 | ||
|
|
d4c338c62c | ||
|
|
3ebcfd142b | ||
|
|
6c5d049c4c | ||
|
|
072ba44cba | ||
|
|
bc8a9dc4e7 | ||
|
|
d35d186249 | ||
|
|
b1ba881eee | ||
|
|
6c8172d7b1 | ||
|
|
d3fac47823 | ||
|
|
4f71074a06 | ||
|
|
37470fc5ed | ||
|
|
337a5d94ed | ||
|
|
98510f9f1c | ||
|
|
6be0751147 | ||
|
|
a40b291d54 | ||
|
|
f24687e79f | ||
|
|
9f5f16dc09 | ||
|
|
9a5989d1f2 | ||
|
|
43acccc0af | ||
|
|
4a447c7bf5 | ||
|
|
b9de73d0fd | ||
|
|
6b9b83a7ae | ||
|
|
3f7675be04 | ||
|
|
b4bb9e5958 | ||
|
|
9a6160ba1f | ||
|
|
1d243b72ec | ||
|
|
c5c1ccaa25 | ||
|
|
b68afe502b | ||
|
|
d18cacab4c | ||
|
|
2faca4a507 | ||
|
|
d797ec62ed | ||
|
|
a475d63789 | ||
|
|
dd3f2d054f | ||
|
|
73594fd505 | ||
|
|
16a1b5c6b5 | ||
|
|
ff7a257844 | ||
|
|
77046a8ddf | ||
|
|
3ca696f059 | ||
|
|
305db76340 | ||
|
|
b1672704e8 | ||
|
|
c058f67a1f | ||
|
|
ab56c63901 | ||
|
|
a5341f9403 | ||
|
|
b2bdac3384 | ||
|
|
a2531a0c63 | ||
|
|
84e2b90375 | ||
|
|
9639dfb9cc | ||
|
|
8722de6da2 | ||
|
|
f2f87e52b0 | ||
|
|
56ad2845e7 | ||
|
|
f23272d154 | ||
|
|
86e35480a4 | ||
|
|
1020a8ff86 | ||
|
|
20b1079a22 | ||
|
|
f090172413 | ||
|
|
e4251cfa8f | ||
|
|
b6dd55b21c | ||
|
|
53d1a68765 | ||
|
|
f01bc2a7a9 | ||
|
|
156ce67413 | ||
|
|
e372850b06 | ||
|
|
f543b54426 | ||
|
|
35614714c8 | ||
|
|
100c6b46cf | ||
|
|
36ccaf7ea4 | ||
|
|
4a655db1ba | ||
|
|
2a80586504 | ||
|
|
0a942118c1 | ||
|
|
2f1ad67fb3 | ||
|
|
4b0ac6d0e3 | ||
|
|
ac273da46c | ||
|
|
7a6594c96d | ||
|
|
657b7465c6 | ||
|
|
08059a845f | ||
|
|
24e2042c9d | ||
|
|
9771f054ea | ||
|
|
5db4e2adfa | ||
|
|
bde5db49a7 | ||
|
|
7c6b2730f5 | ||
|
|
7f6a15fbb7 | ||
|
|
d97b1e5944 | ||
|
|
1519196c95 | ||
|
|
f8629a2689 | ||
|
|
fadecd52ee | ||
|
|
524d6e4fc1 | ||
|
|
51f5f5393c | ||
|
|
f574afa9d2 | ||
|
|
4f49015a6e | ||
|
|
f25d12b53d | ||
|
|
78259c3eb6 | ||
|
|
adc922e4cd | ||
|
|
f68194227c | ||
|
|
29a3ce0ba2 | ||
|
|
e5fe27dd54 | ||
|
|
6016ffe7d7 | ||
|
|
7c94a6f689 | ||
|
|
5953ffe10b | ||
|
|
3016019560 | ||
|
|
0d5da73c74 | ||
|
|
91c835fcb4 | ||
|
|
d01ae0ff39 | ||
|
|
63b85da4f6 | ||
|
|
2406e72210 | ||
|
|
32e1edc2a2 | ||
|
|
84225e982f | ||
|
|
e76a06e942 | ||
|
|
0519682c30 | ||
|
|
91f7a81964 | ||
|
|
a66fcaf04c | ||
|
|
9a0649e671 | ||
|
|
d23ad0cd8f | ||
|
|
63755c1cd3 | ||
|
|
149cf79615 | ||
|
|
a627128570 | ||
|
|
91e3078d2e | ||
|
|
31dd943141 | ||
|
|
3866701475 | ||
|
|
521f8e9889 | ||
|
|
49c3fdd3b2 | ||
|
|
4bb6a49ee0 | ||
|
|
db8e8377ac | ||
|
|
510a37be44 | ||
|
|
230bd73597 | ||
|
|
7217c0ee1d | ||
|
|
77d455d894 | ||
|
|
4f9c8275d9 | ||
|
|
f11aae2514 | ||
|
|
f1e9efc38c | ||
|
|
975cc4f7df | ||
|
|
01243280a2 | ||
|
|
e652c3639d | ||
|
|
1e0954d9b4 | ||
|
|
bb21f9bbc9 | ||
|
|
25466e7950 | ||
|
|
78026ff9b8 | ||
|
|
60c7ef4e53 | ||
|
|
55952934ed | ||
|
|
3eaa844c55 | ||
|
|
f9d31f4c30 | ||
|
|
ec037e422b | ||
|
|
73f66f25d8 | ||
|
|
28174b6cf9 | ||
|
|
a80c095a07 | ||
|
|
374574717d | ||
|
|
efce5d1ad4 | ||
|
|
4eec91a9e6 | ||
|
|
57166f33aa | ||
|
|
f1ebb1f0fb | ||
|
|
8182e4df96 | ||
|
|
6f3580820c | ||
|
|
7b7fd2a4b4 | ||
|
|
f74addd0ca | ||
|
|
21ba3b7713 | ||
|
|
4eca15f822 | ||
|
|
4205f619cf | ||
|
|
c3dff823ef | ||
|
|
39876d1388 | ||
|
|
7e34aa0287 | ||
|
|
3bdafed38e | ||
|
|
3d438ff304 | ||
|
|
bcd1f37085 | ||
|
|
ba928e59fc | ||
|
|
62c01ef7d6 | ||
|
|
a71347e328 | ||
|
|
f235cfa13c | ||
|
|
45b397682b | ||
|
|
858ad02973 | ||
|
|
defeef093d | ||
|
|
b45615e2c3 | ||
|
|
b158babb7f | ||
|
|
59b7386b91 | ||
|
|
c05bcd23d9 | ||
|
|
3cb91855c8 | ||
|
|
dc0850ef3e | ||
|
|
ffdd7fda45 | ||
|
|
83b2133573 | ||
|
|
d04856f964 | ||
|
|
8373d5302f | ||
|
|
7d7cb0eadb | ||
|
|
c00c87f8f2 | ||
|
|
f599462ad7 | ||
|
|
018282f392 | ||
|
|
23b3c1c05a | ||
|
|
62686d0b7a | ||
|
|
54288502a2 | ||
|
|
efc045e40b | ||
|
|
6e9b16511f | ||
|
|
81b6e60a8c | ||
|
|
5baaf7e00a | ||
|
|
d4d460397f | ||
|
|
f66b6b2ee3 | ||
|
|
fb7f7fd8c8 | ||
|
|
dc98fa21a9 | ||
|
|
6b662d3e4c | ||
|
|
7069682c8e | ||
|
|
3b1d5b93a8 | ||
|
|
611fe55e90 | ||
|
|
481272ac22 | ||
|
|
9069e2d7db | ||
|
|
1144c16a4c | ||
|
|
9b2846633c | ||
|
|
db88c0a5bf | ||
|
|
cb407e75ab | ||
|
|
27d4612449 | ||
|
|
43ab5f79b6 |
17
.gitignore
vendored
17
.gitignore
vendored
@@ -1,13 +1,22 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
prepare-vms/ips.txt
|
|
||||||
prepare-vms/ips.html
|
|
||||||
prepare-vms/ips.pdf
|
|
||||||
prepare-vms/settings.yaml
|
|
||||||
prepare-vms/tags
|
prepare-vms/tags
|
||||||
|
prepare-vms/infra
|
||||||
slides/*.yml.html
|
slides/*.yml.html
|
||||||
slides/autopilot/state.yaml
|
slides/autopilot/state.yaml
|
||||||
slides/index.html
|
slides/index.html
|
||||||
slides/past.html
|
slides/past.html
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|||||||
62
k8s/consul.yaml
Normal file
62
k8s/consul.yaml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: consul
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 8500
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: consul
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: consul
|
||||||
|
spec:
|
||||||
|
serviceName: consul
|
||||||
|
replicas: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: consul
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: consul
|
||||||
|
spec:
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: app
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- consul
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
terminationGracePeriodSeconds: 10
|
||||||
|
containers:
|
||||||
|
- name: consul
|
||||||
|
image: "consul:1.2.2"
|
||||||
|
env:
|
||||||
|
- name: NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
|
args:
|
||||||
|
- "agent"
|
||||||
|
- "-bootstrap-expect=3"
|
||||||
|
- "-retry-join=consul-0.consul.$(NAMESPACE).svc.cluster.local"
|
||||||
|
- "-retry-join=consul-1.consul.$(NAMESPACE).svc.cluster.local"
|
||||||
|
- "-retry-join=consul-2.consul.$(NAMESPACE).svc.cluster.local"
|
||||||
|
- "-client=0.0.0.0"
|
||||||
|
- "-data-dir=/consul/data"
|
||||||
|
- "-server"
|
||||||
|
- "-ui"
|
||||||
|
lifecycle:
|
||||||
|
preStop:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- consul leave
|
||||||
28
k8s/docker-build.yaml
Normal file
28
k8s/docker-build.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: build-image
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: docker-build
|
||||||
|
image: docker
|
||||||
|
env:
|
||||||
|
- name: REGISTRY_PORT
|
||||||
|
value: #"30000"
|
||||||
|
command: ["sh", "-c"]
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
apk add --no-cache git &&
|
||||||
|
mkdir /workspace &&
|
||||||
|
git clone https://github.com/jpetazzo/container.training /workspace &&
|
||||||
|
docker build -t localhost:$REGISTRY_PORT/worker /workspace/dockercoins/worker &&
|
||||||
|
docker push localhost:$REGISTRY_PORT/worker
|
||||||
|
volumeMounts:
|
||||||
|
- name: docker-socket
|
||||||
|
mountPath: /var/run/docker.sock
|
||||||
|
volumes:
|
||||||
|
- name: docker-socket
|
||||||
|
hostPath:
|
||||||
|
path: /var/run/docker.sock
|
||||||
|
|
||||||
227
k8s/efk.yaml
Normal file
227
k8s/efk.yaml
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: fluentd
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: fluentd
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
- namespaces
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: fluentd
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: fluentd
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: fluentd
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: fluentd
|
||||||
|
labels:
|
||||||
|
k8s-app: fluentd-logging
|
||||||
|
version: v1
|
||||||
|
kubernetes.io/cluster-service: "true"
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: fluentd-logging
|
||||||
|
version: v1
|
||||||
|
kubernetes.io/cluster-service: "true"
|
||||||
|
spec:
|
||||||
|
serviceAccount: fluentd
|
||||||
|
serviceAccountName: fluentd
|
||||||
|
tolerations:
|
||||||
|
- key: node-role.kubernetes.io/master
|
||||||
|
effect: NoSchedule
|
||||||
|
containers:
|
||||||
|
- name: fluentd
|
||||||
|
image: fluent/fluentd-kubernetes-daemonset:elasticsearch
|
||||||
|
env:
|
||||||
|
- name: FLUENT_ELASTICSEARCH_HOST
|
||||||
|
value: "elasticsearch"
|
||||||
|
- name: FLUENT_ELASTICSEARCH_PORT
|
||||||
|
value: "9200"
|
||||||
|
- name: FLUENT_ELASTICSEARCH_SCHEME
|
||||||
|
value: "http"
|
||||||
|
# X-Pack Authentication
|
||||||
|
# =====================
|
||||||
|
- name: FLUENT_ELASTICSEARCH_USER
|
||||||
|
value: "elastic"
|
||||||
|
- name: FLUENT_ELASTICSEARCH_PASSWORD
|
||||||
|
value: "changeme"
|
||||||
|
- name: FLUENT_UID
|
||||||
|
value: "0"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 200Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 200Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: varlog
|
||||||
|
mountPath: /var/log
|
||||||
|
- name: varlibdockercontainers
|
||||||
|
mountPath: /var/lib/docker/containers
|
||||||
|
readOnly: true
|
||||||
|
terminationGracePeriodSeconds: 30
|
||||||
|
volumes:
|
||||||
|
- name: varlog
|
||||||
|
hostPath:
|
||||||
|
path: /var/log
|
||||||
|
- name: varlibdockercontainers
|
||||||
|
hostPath:
|
||||||
|
path: /var/lib/docker/containers
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
deployment.kubernetes.io/revision: "1"
|
||||||
|
creationTimestamp: null
|
||||||
|
generation: 1
|
||||||
|
labels:
|
||||||
|
run: elasticsearch
|
||||||
|
name: elasticsearch
|
||||||
|
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/elasticsearch
|
||||||
|
spec:
|
||||||
|
progressDeadlineSeconds: 600
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 10
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
run: elasticsearch
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
run: elasticsearch
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: elasticsearch:5.6.8
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
name: elasticsearch
|
||||||
|
resources: {}
|
||||||
|
terminationMessagePath: /dev/termination-log
|
||||||
|
terminationMessagePolicy: File
|
||||||
|
env:
|
||||||
|
- name: ES_JAVA_OPTS
|
||||||
|
value: "-Xms1g -Xmx1g"
|
||||||
|
dnsPolicy: ClusterFirst
|
||||||
|
restartPolicy: Always
|
||||||
|
schedulerName: default-scheduler
|
||||||
|
securityContext: {}
|
||||||
|
terminationGracePeriodSeconds: 30
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
run: elasticsearch
|
||||||
|
name: elasticsearch
|
||||||
|
selfLink: /api/v1/namespaces/default/services/elasticsearch
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 9200
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 9200
|
||||||
|
selector:
|
||||||
|
run: elasticsearch
|
||||||
|
sessionAffinity: None
|
||||||
|
type: ClusterIP
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
deployment.kubernetes.io/revision: "1"
|
||||||
|
creationTimestamp: null
|
||||||
|
generation: 1
|
||||||
|
labels:
|
||||||
|
run: kibana
|
||||||
|
name: kibana
|
||||||
|
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/kibana
|
||||||
|
spec:
|
||||||
|
progressDeadlineSeconds: 600
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 10
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
run: kibana
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
run: kibana
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- env:
|
||||||
|
- name: ELASTICSEARCH_URL
|
||||||
|
value: http://elasticsearch:9200/
|
||||||
|
image: kibana:5.6.8
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: kibana
|
||||||
|
resources: {}
|
||||||
|
terminationMessagePath: /dev/termination-log
|
||||||
|
terminationMessagePolicy: File
|
||||||
|
dnsPolicy: ClusterFirst
|
||||||
|
restartPolicy: Always
|
||||||
|
schedulerName: default-scheduler
|
||||||
|
securityContext: {}
|
||||||
|
terminationGracePeriodSeconds: 30
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
run: kibana
|
||||||
|
name: kibana
|
||||||
|
selfLink: /api/v1/namespaces/default/services/kibana
|
||||||
|
spec:
|
||||||
|
externalTrafficPolicy: Cluster
|
||||||
|
ports:
|
||||||
|
- port: 5601
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 5601
|
||||||
|
selector:
|
||||||
|
run: kibana
|
||||||
|
sessionAffinity: None
|
||||||
|
type: NodePort
|
||||||
14
k8s/grant-admin-to-dashboard.yaml
Normal file
14
k8s/grant-admin-to-dashboard.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: kubernetes-dashboard
|
||||||
|
labels:
|
||||||
|
k8s-app: kubernetes-dashboard
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: cluster-admin
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: kubernetes-dashboard
|
||||||
|
namespace: kube-system
|
||||||
18
k8s/haproxy.cfg
Normal file
18
k8s/haproxy.cfg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
global
|
||||||
|
daemon
|
||||||
|
maxconn 256
|
||||||
|
|
||||||
|
defaults
|
||||||
|
mode tcp
|
||||||
|
timeout connect 5000ms
|
||||||
|
timeout client 50000ms
|
||||||
|
timeout server 50000ms
|
||||||
|
|
||||||
|
frontend the-frontend
|
||||||
|
bind *:80
|
||||||
|
default_backend the-backend
|
||||||
|
|
||||||
|
backend the-backend
|
||||||
|
server google.com-80 google.com:80 maxconn 32 check
|
||||||
|
server ibm.fr-80 ibm.fr:80 maxconn 32 check
|
||||||
|
|
||||||
16
k8s/haproxy.yaml
Normal file
16
k8s/haproxy.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: haproxy
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: haproxy
|
||||||
|
containers:
|
||||||
|
- name: haproxy
|
||||||
|
image: haproxy
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /usr/local/etc/haproxy/
|
||||||
|
|
||||||
14
k8s/ingress.yaml
Normal file
14
k8s/ingress.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: cheddar
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: cheddar.A.B.C.D.nip.io
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
backend:
|
||||||
|
serviceName: cheddar
|
||||||
|
servicePort: 80
|
||||||
|
|
||||||
29
k8s/kaniko-build.yaml
Normal file
29
k8s/kaniko-build.yaml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: kaniko-build
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: git-clone
|
||||||
|
image: alpine
|
||||||
|
command: ["sh", "-c"]
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
apk add --no-cache git &&
|
||||||
|
git clone git://github.com/jpetazzo/container.training /workspace
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
|
containers:
|
||||||
|
- name: build-image
|
||||||
|
image: gcr.io/kaniko-project/executor:latest
|
||||||
|
args:
|
||||||
|
- "--context=/workspace/dockercoins/rng"
|
||||||
|
- "--insecure"
|
||||||
|
- "--destination=registry:5000/rng-kaniko:latest"
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
|
volumes:
|
||||||
|
- name: workspace
|
||||||
|
|
||||||
167
k8s/kubernetes-dashboard.yaml
Normal file
167
k8s/kubernetes-dashboard.yaml
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# Copyright 2017 The Kubernetes Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# 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
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: kubernetes-dashboard
|
||||||
|
name: kubernetes-dashboard-certs
|
||||||
|
namespace: kube-system
|
||||||
|
type: Opaque
|
||||||
|
|
||||||
|
---
|
||||||
|
# ------------------- Dashboard Service Account ------------------- #
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: kubernetes-dashboard
|
||||||
|
name: kubernetes-dashboard
|
||||||
|
namespace: kube-system
|
||||||
|
|
||||||
|
---
|
||||||
|
# ------------------- 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
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: kubernetes-dashboard
|
||||||
|
name: kubernetes-dashboard
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 10
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
k8s-app: kubernetes-dashboard
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
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
|
||||||
|
volumes:
|
||||||
|
- name: kubernetes-dashboard-certs
|
||||||
|
secret:
|
||||||
|
secretName: kubernetes-dashboard-certs
|
||||||
|
- name: tmp-volume
|
||||||
|
emptyDir: {}
|
||||||
|
serviceAccountName: kubernetes-dashboard
|
||||||
|
# Comment the following tolerations if Dashboard must not be deployed on master
|
||||||
|
tolerations:
|
||||||
|
- 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
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 443
|
||||||
|
targetPort: 8443
|
||||||
|
selector:
|
||||||
|
k8s-app: kubernetes-dashboard
|
||||||
14
k8s/netpol-allow-testcurl-for-testweb.yaml
Normal file
14
k8s/netpol-allow-testcurl-for-testweb.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
kind: NetworkPolicy
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: allow-testcurl-for-testweb
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: testweb
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
run: testcurl
|
||||||
|
|
||||||
10
k8s/netpol-deny-all-for-testweb.yaml
Normal file
10
k8s/netpol-deny-all-for-testweb.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
kind: NetworkPolicy
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: deny-all-for-testweb
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: testweb
|
||||||
|
ingress: []
|
||||||
|
|
||||||
22
k8s/netpol-dockercoins.yaml
Normal file
22
k8s/netpol-dockercoins.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
kind: NetworkPolicy
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: deny-from-other-namespaces
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector: {}
|
||||||
|
---
|
||||||
|
kind: NetworkPolicy
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: allow-webui
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: webui
|
||||||
|
ingress:
|
||||||
|
- from: []
|
||||||
|
|
||||||
21
k8s/nginx-with-volume.yaml
Normal file
21
k8s/nginx-with-volume.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
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/
|
||||||
|
- name: git
|
||||||
|
image: alpine
|
||||||
|
command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/octocat/Spoon-Knife /www" ]
|
||||||
|
volumeMounts:
|
||||||
|
- name: www
|
||||||
|
mountPath: /www/
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
|
||||||
580
k8s/portworx.yaml
Normal file
580
k8s/portworx.yaml
Normal file
@@ -0,0 +1,580 @@
|
|||||||
|
# SOURCE: https://install.portworx.com/?kbver=1.11.2&b=true&s=/dev/loop4&c=px-workshop&stork=true&lh=true
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: stork-config
|
||||||
|
namespace: kube-system
|
||||||
|
data:
|
||||||
|
policy.cfg: |-
|
||||||
|
{
|
||||||
|
"kind": "Policy",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"extenders": [
|
||||||
|
{
|
||||||
|
"urlPrefix": "http://stork-service.kube-system.svc:8099",
|
||||||
|
"apiVersion": "v1beta1",
|
||||||
|
"filterVerb": "filter",
|
||||||
|
"prioritizeVerb": "prioritize",
|
||||||
|
"weight": 5,
|
||||||
|
"enableHttps": false,
|
||||||
|
"nodeCacheCapable": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: stork-account
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
kind: ClusterRole
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: stork-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["persistentvolumes"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["persistentvolumeclaims"]
|
||||||
|
verbs: ["get", "list", "watch", "update"]
|
||||||
|
- apiGroups: ["storage.k8s.io"]
|
||||||
|
resources: ["storageclasses"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["events"]
|
||||||
|
verbs: ["list", "watch", "create", "update", "patch"]
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["create", "list", "watch", "delete"]
|
||||||
|
- apiGroups: ["volumesnapshot.external-storage.k8s.io"]
|
||||||
|
resources: ["volumesnapshots"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: ["volumesnapshot.external-storage.k8s.io"]
|
||||||
|
resources: ["volumesnapshotdatas"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["configmaps"]
|
||||||
|
verbs: ["get", "create", "update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services"]
|
||||||
|
verbs: ["get"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["nodes"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["*"]
|
||||||
|
resources: ["deployments", "deployments/extensions"]
|
||||||
|
verbs: ["list", "get", "watch", "patch", "update", "initialize"]
|
||||||
|
- apiGroups: ["*"]
|
||||||
|
resources: ["statefulsets", "statefulsets/extensions"]
|
||||||
|
verbs: ["list", "get", "watch", "patch", "update", "initialize"]
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: stork-role-binding
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: stork-account
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: stork-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
kind: Service
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: stork-service
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
name: stork
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 8099
|
||||||
|
targetPort: 8099
|
||||||
|
---
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
scheduler.alpha.kubernetes.io/critical-pod: ""
|
||||||
|
labels:
|
||||||
|
tier: control-plane
|
||||||
|
name: stork
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
|
replicas: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
scheduler.alpha.kubernetes.io/critical-pod: ""
|
||||||
|
labels:
|
||||||
|
name: stork
|
||||||
|
tier: control-plane
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- /stork
|
||||||
|
- --driver=pxd
|
||||||
|
- --verbose
|
||||||
|
- --leader-elect=true
|
||||||
|
- --health-monitor-interval=120
|
||||||
|
imagePullPolicy: Always
|
||||||
|
image: openstorage/stork:1.1.3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: '0.1'
|
||||||
|
name: stork
|
||||||
|
hostPID: false
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: "name"
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- stork
|
||||||
|
topologyKey: "kubernetes.io/hostname"
|
||||||
|
serviceAccountName: stork-account
|
||||||
|
---
|
||||||
|
kind: StorageClass
|
||||||
|
apiVersion: storage.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: stork-snapshot-sc
|
||||||
|
provisioner: stork-snapshot
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: stork-scheduler-account
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
kind: ClusterRole
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: stork-scheduler-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["endpoints"]
|
||||||
|
verbs: ["get", "update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["configmaps"]
|
||||||
|
verbs: ["get"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["events"]
|
||||||
|
verbs: ["create", "patch", "update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["endpoints"]
|
||||||
|
verbs: ["create"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resourceNames: ["kube-scheduler"]
|
||||||
|
resources: ["endpoints"]
|
||||||
|
verbs: ["delete", "get", "patch", "update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["nodes"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["delete", "get", "list", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["bindings", "pods/binding"]
|
||||||
|
verbs: ["create"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods/status"]
|
||||||
|
verbs: ["patch", "update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["replicationcontrollers", "services"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["app", "extensions"]
|
||||||
|
resources: ["replicasets"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["statefulsets"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["policy"]
|
||||||
|
resources: ["poddisruptionbudgets"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["persistentvolumeclaims", "persistentvolumes"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["storage.k8s.io"]
|
||||||
|
resources: ["storageclasses"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: stork-scheduler-role-binding
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: stork-scheduler-account
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: stork-scheduler-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
component: scheduler
|
||||||
|
tier: control-plane
|
||||||
|
name: stork-scheduler
|
||||||
|
name: stork-scheduler
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
component: scheduler
|
||||||
|
tier: control-plane
|
||||||
|
name: stork-scheduler
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- /usr/local/bin/kube-scheduler
|
||||||
|
- --address=0.0.0.0
|
||||||
|
- --leader-elect=true
|
||||||
|
- --scheduler-name=stork
|
||||||
|
- --policy-configmap=stork-config
|
||||||
|
- --policy-configmap-namespace=kube-system
|
||||||
|
- --lock-object-name=stork-scheduler
|
||||||
|
image: gcr.io/google_containers/kube-scheduler-amd64:v1.11.2
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 10251
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
name: stork-scheduler
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 10251
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: '0.1'
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: "name"
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- stork-scheduler
|
||||||
|
topologyKey: "kubernetes.io/hostname"
|
||||||
|
hostPID: false
|
||||||
|
serviceAccountName: stork-scheduler-account
|
||||||
|
---
|
||||||
|
kind: Service
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: portworx-service
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
name: portworx
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
name: portworx
|
||||||
|
ports:
|
||||||
|
- name: px-api
|
||||||
|
protocol: TCP
|
||||||
|
port: 9001
|
||||||
|
targetPort: 9001
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: px-account
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
kind: ClusterRole
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: node-get-put-list-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["nodes"]
|
||||||
|
verbs: ["watch", "get", "update", "list"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["delete", "get", "list"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["persistentvolumeclaims", "persistentvolumes"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["configmaps"]
|
||||||
|
verbs: ["get", "list", "update", "create"]
|
||||||
|
- apiGroups: ["extensions"]
|
||||||
|
resources: ["podsecuritypolicies"]
|
||||||
|
resourceNames: ["privileged"]
|
||||||
|
verbs: ["use"]
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: node-role-binding
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: px-account
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: node-get-put-list-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: portworx
|
||||||
|
---
|
||||||
|
kind: Role
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: px-role
|
||||||
|
namespace: portworx
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list", "create", "update", "patch"]
|
||||||
|
---
|
||||||
|
kind: RoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: px-role-binding
|
||||||
|
namespace: portworx
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: px-account
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: px-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: portworx
|
||||||
|
namespace: kube-system
|
||||||
|
annotations:
|
||||||
|
portworx.com/install-source: "https://install.portworx.com/?kbver=1.11.2&b=true&s=/dev/loop4&c=px-workshop&stork=true&lh=true"
|
||||||
|
spec:
|
||||||
|
minReadySeconds: 0
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
name: portworx
|
||||||
|
spec:
|
||||||
|
affinity:
|
||||||
|
nodeAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
nodeSelectorTerms:
|
||||||
|
- matchExpressions:
|
||||||
|
- key: px/enabled
|
||||||
|
operator: NotIn
|
||||||
|
values:
|
||||||
|
- "false"
|
||||||
|
- key: node-role.kubernetes.io/master
|
||||||
|
operator: DoesNotExist
|
||||||
|
hostNetwork: true
|
||||||
|
hostPID: false
|
||||||
|
containers:
|
||||||
|
- name: portworx
|
||||||
|
image: portworx/oci-monitor:1.4.2.2
|
||||||
|
imagePullPolicy: Always
|
||||||
|
args:
|
||||||
|
["-c", "px-workshop", "-s", "/dev/loop4", "-b",
|
||||||
|
"-x", "kubernetes"]
|
||||||
|
env:
|
||||||
|
- name: "PX_TEMPLATE_VERSION"
|
||||||
|
value: "v4"
|
||||||
|
|
||||||
|
livenessProbe:
|
||||||
|
periodSeconds: 30
|
||||||
|
initialDelaySeconds: 840 # allow image pull in slow networks
|
||||||
|
httpGet:
|
||||||
|
host: 127.0.0.1
|
||||||
|
path: /status
|
||||||
|
port: 9001
|
||||||
|
readinessProbe:
|
||||||
|
periodSeconds: 10
|
||||||
|
httpGet:
|
||||||
|
host: 127.0.0.1
|
||||||
|
path: /health
|
||||||
|
port: 9015
|
||||||
|
terminationMessagePath: "/tmp/px-termination-log"
|
||||||
|
securityContext:
|
||||||
|
privileged: true
|
||||||
|
volumeMounts:
|
||||||
|
- name: dockersock
|
||||||
|
mountPath: /var/run/docker.sock
|
||||||
|
- name: etcpwx
|
||||||
|
mountPath: /etc/pwx
|
||||||
|
- name: optpwx
|
||||||
|
mountPath: /opt/pwx
|
||||||
|
- name: proc1nsmount
|
||||||
|
mountPath: /host_proc/1/ns
|
||||||
|
- name: sysdmount
|
||||||
|
mountPath: /etc/systemd/system
|
||||||
|
- name: diagsdump
|
||||||
|
mountPath: /var/cores
|
||||||
|
- name: journalmount1
|
||||||
|
mountPath: /var/run/log
|
||||||
|
readOnly: true
|
||||||
|
- name: journalmount2
|
||||||
|
mountPath: /var/log
|
||||||
|
readOnly: true
|
||||||
|
- name: dbusmount
|
||||||
|
mountPath: /var/run/dbus
|
||||||
|
restartPolicy: Always
|
||||||
|
serviceAccountName: px-account
|
||||||
|
volumes:
|
||||||
|
- name: dockersock
|
||||||
|
hostPath:
|
||||||
|
path: /var/run/docker.sock
|
||||||
|
- name: etcpwx
|
||||||
|
hostPath:
|
||||||
|
path: /etc/pwx
|
||||||
|
- name: optpwx
|
||||||
|
hostPath:
|
||||||
|
path: /opt/pwx
|
||||||
|
- name: proc1nsmount
|
||||||
|
hostPath:
|
||||||
|
path: /proc/1/ns
|
||||||
|
- name: sysdmount
|
||||||
|
hostPath:
|
||||||
|
path: /etc/systemd/system
|
||||||
|
- name: diagsdump
|
||||||
|
hostPath:
|
||||||
|
path: /var/cores
|
||||||
|
- name: journalmount1
|
||||||
|
hostPath:
|
||||||
|
path: /var/run/log
|
||||||
|
- name: journalmount2
|
||||||
|
hostPath:
|
||||||
|
path: /var/log
|
||||||
|
- name: dbusmount
|
||||||
|
hostPath:
|
||||||
|
path: /var/run/dbus
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: px-lh-account
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
kind: Role
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: px-lh-role
|
||||||
|
namespace: kube-system
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["configmaps"]
|
||||||
|
verbs: ["get", "create", "update"]
|
||||||
|
---
|
||||||
|
kind: RoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: px-lh-role-binding
|
||||||
|
namespace: kube-system
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: px-lh-account
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: px-lh-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: px-lighthouse
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
tier: px-web-console
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
nodePort: 32678
|
||||||
|
- name: https
|
||||||
|
port: 443
|
||||||
|
nodePort: 32679
|
||||||
|
selector:
|
||||||
|
tier: px-web-console
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: px-lighthouse
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
tier: px-web-console
|
||||||
|
spec:
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
tier: px-web-console
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
tier: px-web-console
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: config-init
|
||||||
|
image: portworx/lh-config-sync:0.2
|
||||||
|
imagePullPolicy: Always
|
||||||
|
args:
|
||||||
|
- "init"
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /config/lh
|
||||||
|
containers:
|
||||||
|
- name: px-lighthouse
|
||||||
|
image: portworx/px-lighthouse:1.5.0
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
- containerPort: 443
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /config/lh
|
||||||
|
- name: config-sync
|
||||||
|
image: portworx/lh-config-sync:0.2
|
||||||
|
imagePullPolicy: Always
|
||||||
|
args:
|
||||||
|
- "sync"
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /config/lh
|
||||||
|
serviceAccountName: px-lh-account
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
emptyDir: {}
|
||||||
30
k8s/postgres.yaml
Normal file
30
k8s/postgres.yaml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: postgres
|
||||||
|
serviceName: postgres
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: postgres
|
||||||
|
spec:
|
||||||
|
schedulerName: stork
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: postgres:10.5
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /var/lib/postgresql/data
|
||||||
|
name: postgres
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: postgres
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
|
||||||
15
k8s/registry.yaml
Normal file
15
k8s/registry.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: registry
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: registry
|
||||||
|
image: registry
|
||||||
|
env:
|
||||||
|
- name: REGISTRY_HTTP_ADDR
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: registry
|
||||||
|
key: http.addr
|
||||||
|
|
||||||
67
k8s/socat.yaml
Normal file
67
k8s/socat.yaml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
deployment.kubernetes.io/revision: "2"
|
||||||
|
creationTimestamp: null
|
||||||
|
generation: 1
|
||||||
|
labels:
|
||||||
|
app: socat
|
||||||
|
name: socat
|
||||||
|
namespace: kube-system
|
||||||
|
selfLink: /apis/extensions/v1beta1/namespaces/kube-system/deployments/socat
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: socat
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
app: socat
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- args:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- apk add --no-cache socat && socat TCP-LISTEN:80,fork,reuseaddr OPENSSL:kubernetes-dashboard:443,verify=0
|
||||||
|
image: alpine
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: socat
|
||||||
|
resources: {}
|
||||||
|
terminationMessagePath: /dev/termination-log
|
||||||
|
terminationMessagePolicy: File
|
||||||
|
dnsPolicy: ClusterFirst
|
||||||
|
restartPolicy: Always
|
||||||
|
schedulerName: default-scheduler
|
||||||
|
securityContext: {}
|
||||||
|
terminationGracePeriodSeconds: 30
|
||||||
|
status: {}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
app: socat
|
||||||
|
name: socat
|
||||||
|
namespace: kube-system
|
||||||
|
selfLink: /api/v1/namespaces/kube-system/services/socat
|
||||||
|
spec:
|
||||||
|
externalTrafficPolicy: Cluster
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 80
|
||||||
|
selector:
|
||||||
|
app: socat
|
||||||
|
sessionAffinity: None
|
||||||
|
type: NodePort
|
||||||
|
status:
|
||||||
|
loadBalancer: {}
|
||||||
11
k8s/storage-class.yaml
Normal file
11
k8s/storage-class.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
kind: StorageClass
|
||||||
|
apiVersion: storage.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: portworx-replicated
|
||||||
|
annotations:
|
||||||
|
storageclass.kubernetes.io/is-default-class: "true"
|
||||||
|
provisioner: kubernetes.io/portworx-volume
|
||||||
|
parameters:
|
||||||
|
repl: "2"
|
||||||
|
priority_io: "high"
|
||||||
|
|
||||||
100
k8s/traefik.yaml
Normal file
100
k8s/traefik.yaml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
kind: DaemonSet
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
k8s-app: traefik-ingress-lb
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: traefik-ingress-lb
|
||||||
|
name: traefik-ingress-lb
|
||||||
|
spec:
|
||||||
|
tolerations:
|
||||||
|
- effect: NoSchedule
|
||||||
|
operator: Exists
|
||||||
|
hostNetwork: true
|
||||||
|
serviceAccountName: traefik-ingress-controller
|
||||||
|
terminationGracePeriodSeconds: 60
|
||||||
|
containers:
|
||||||
|
- image: traefik
|
||||||
|
name: traefik-ingress-lb
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 80
|
||||||
|
hostPort: 80
|
||||||
|
- name: admin
|
||||||
|
containerPort: 8080
|
||||||
|
hostPort: 8080
|
||||||
|
securityContext:
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
args:
|
||||||
|
- --api
|
||||||
|
- --kubernetes
|
||||||
|
- --logLevel=INFO
|
||||||
|
---
|
||||||
|
kind: Service
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: traefik-ingress-service
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
k8s-app: traefik-ingress-lb
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
name: web
|
||||||
|
- protocol: TCP
|
||||||
|
port: 8080
|
||||||
|
name: admin
|
||||||
|
---
|
||||||
|
kind: ClusterRole
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
- endpoints
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- extensions
|
||||||
|
resources:
|
||||||
|
- ingresses
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
namespace: kube-system
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
# Trainer tools to create and prepare VMs for Docker workshops on AWS or Azure
|
# Trainer tools to create and prepare VMs for Docker workshops
|
||||||
|
|
||||||
|
These tools can help you to create VMs on:
|
||||||
|
|
||||||
|
- Azure
|
||||||
|
- EC2
|
||||||
|
- OpenStack
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -6,6 +12,9 @@
|
|||||||
- [Docker Compose](https://docs.docker.com/compose/install/)
|
- [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`) - the configuration scripts require this
|
||||||
|
|
||||||
|
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:
|
And if you want to generate printable cards:
|
||||||
|
|
||||||
- [pyyaml](https://pypi.python.org/pypi/PyYAML) (on a Mac: `brew install pyyaml`)
|
- [pyyaml](https://pypi.python.org/pypi/PyYAML) (on a Mac: `brew install pyyaml`)
|
||||||
@@ -14,20 +23,25 @@ And if you want to generate printable cards:
|
|||||||
## General Workflow
|
## General Workflow
|
||||||
|
|
||||||
- fork/clone repo
|
- fork/clone repo
|
||||||
- set required environment variables
|
- create an infrastructure configuration in the `prepare-vms/infra` directory
|
||||||
|
(using one of the example files in that directory)
|
||||||
- create your own setting file from `settings/example.yaml`
|
- create your own setting file from `settings/example.yaml`
|
||||||
- if necessary, increase allowed open files: `ulimit -Sn 10000`
|
- if necessary, increase allowed open files: `ulimit -Sn 10000`
|
||||||
- run `./workshopctl` commands to create instances, install docker, setup each users environment in node1, other management tasks
|
- run `./workshopctl start` to create instances
|
||||||
- run `./workshopctl cards` command to generate PDF for printing handouts of each users host IP's and login info
|
- run `./workshopctl deploy` to install Docker and setup environment
|
||||||
|
- run `./workshopctl kube` (if you want to install and setup Kubernetes)
|
||||||
|
- run `./workshopctl cards` (if you want to generate PDF for printing handouts of each users host IP's and login info)
|
||||||
|
- run `./workshopctl stop` at the end of the workshop to terminate instances
|
||||||
|
|
||||||
## Clone/Fork the Repo, and Build the Tools Image
|
## Clone/Fork the Repo, and Build the Tools Image
|
||||||
|
|
||||||
The Docker Compose file here is used to build a image with all the dependencies to run the `./workshopctl` commands and optional tools. Each run of the script will check if you have those dependencies locally on your host, and will only use the container if you're [missing a dependency](workshopctl#L5).
|
The Docker Compose file here is used to build a image with all the dependencies to run the `./workshopctl` commands and optional tools. Each run of the script will check if you have those dependencies locally on your host, and will only use the container if you're [missing a dependency](workshopctl#L5).
|
||||||
|
|
||||||
$ git clone https://github.com/jpetazzo/orchestration-workshop.git
|
$ git clone https://github.com/jpetazzo/container.training
|
||||||
$ cd orchestration-workshop/prepare-vms
|
$ cd container.training/prepare-vms
|
||||||
$ docker-compose build
|
$ docker-compose build
|
||||||
|
|
||||||
|
|
||||||
## Preparing to Run `./workshopctl`
|
## Preparing to Run `./workshopctl`
|
||||||
|
|
||||||
### Required AWS Permissions/Info
|
### Required AWS Permissions/Info
|
||||||
@@ -36,27 +50,37 @@ The Docker Compose file here is used to build a image with all the dependencies
|
|||||||
- Using a non-default VPC or Security Group isn't supported out of box yet, so you will have to customize `lib/commands.sh` if you want to change that.
|
- Using a non-default VPC or Security Group isn't supported out of box yet, so you will have to customize `lib/commands.sh` if you want to change that.
|
||||||
- These instances will assign the default VPC Security Group, which does not open any ports from Internet by default. So you'll need to add Inbound rules for `SSH | TCP | 22 | 0.0.0.0/0` and `Custom TCP Rule | TCP | 8000 - 8002 | 0.0.0.0/0`, or run `./workshopctl opensg` which opens up all ports.
|
- These instances will assign the default VPC Security Group, which does not open any ports from Internet by default. So you'll need to add Inbound rules for `SSH | TCP | 22 | 0.0.0.0/0` and `Custom TCP Rule | TCP | 8000 - 8002 | 0.0.0.0/0`, or run `./workshopctl opensg` which opens up all ports.
|
||||||
|
|
||||||
### Required Environment Variables
|
### Create your `infra` file
|
||||||
|
|
||||||
- `AWS_ACCESS_KEY_ID`
|
You need to do this only once. (On AWS, you can create one `infra`
|
||||||
- `AWS_SECRET_ACCESS_KEY`
|
file per region.)
|
||||||
- `AWS_DEFAULT_REGION`
|
|
||||||
|
|
||||||
If you're not using AWS, set these to placeholder values:
|
Make a copy of one of the example files in the `infra` directory.
|
||||||
|
|
||||||
|
For instance:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp infra/example.aws infra/aws-us-west-2
|
||||||
```
|
```
|
||||||
export AWS_ACCESS_KEY_ID="foo"
|
|
||||||
export AWS_SECRET_ACCESS_KEY="foo"
|
Edit your infrastructure file to customize it.
|
||||||
export AWS_DEFAULT_REGION="foo"
|
You will probably need to put your cloud provider credentials,
|
||||||
```
|
select region...
|
||||||
|
|
||||||
If you don't have the `aws` CLI installed, you will get a warning that it's a missing dependency. If you're not using AWS you can ignore this.
|
If you don't have the `aws` CLI installed, you will get a warning that it's a missing dependency. If you're not using AWS you can ignore this.
|
||||||
|
|
||||||
### Update/copy `settings/example.yaml`
|
### Create your `settings` file
|
||||||
|
|
||||||
Then pass `settings/YOUR_WORKSHOP_NAME-settings.yaml` as an argument to `./workshopctl deploy`, `./workshopctl cards`, etc.
|
Similarly, pick one of the files in `settings` and copy it
|
||||||
|
to customize it.
|
||||||
|
|
||||||
./workshopctl cards 2016-09-28-00-33-bret settings/orchestration.yaml
|
For instance:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp settings/example.yaml settings/myworkshop.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
You're all set!
|
||||||
|
|
||||||
## `./workshopctl` Usage
|
## `./workshopctl` Usage
|
||||||
|
|
||||||
@@ -66,7 +90,7 @@ Commands:
|
|||||||
ami Show the AMI that will be used for deployment
|
ami Show the AMI that will be used for deployment
|
||||||
amis List Ubuntu AMIs in the current region
|
amis List Ubuntu AMIs in the current region
|
||||||
build Build the Docker image to 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 batch of VMs
|
cards Generate ready-to-print cards for a group of VMs
|
||||||
deploy Install Docker on a bunch of running VMs
|
deploy Install Docker on a bunch of running VMs
|
||||||
ec2quotas Check our EC2 quotas (max instances)
|
ec2quotas Check our EC2 quotas (max instances)
|
||||||
help Show available commands
|
help Show available commands
|
||||||
@@ -74,14 +98,14 @@ 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
|
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)
|
kube Setup kubernetes clusters with kubeadm (must be run AFTER deploy)
|
||||||
kubetest Check that all notes are reporting as Ready
|
kubetest Check that all notes are reporting as Ready
|
||||||
list List available batches in the current region
|
list List available groups in the current region
|
||||||
opensg Open the default security group to ALL ingress traffic
|
opensg Open the default security group to ALL ingress traffic
|
||||||
pull_images Pre-pull a bunch of Docker images
|
pull_images Pre-pull a bunch of Docker images
|
||||||
retag Apply a new tag to a batch of VMs
|
retag Apply a new tag to a group of VMs
|
||||||
start Start a batch of VMs
|
start Start a group of VMs
|
||||||
status List instance status for a given batch
|
status List instance status for a given group
|
||||||
stop Stop (terminate, shutdown, kill, remove, destroy...) instances
|
stop Stop (terminate, shutdown, kill, remove, destroy...) instances
|
||||||
test Run tests (pre-flight checks) on a batch of VMs
|
test Run tests (pre-flight checks) on a group of VMs
|
||||||
wrap Run this program in a container
|
wrap Run this program in a container
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -93,24 +117,24 @@ wrap Run this program in a container
|
|||||||
- The `./workshopctl` script can be executed directly.
|
- The `./workshopctl` script can be executed directly.
|
||||||
- It will run locally if all its dependencies are fulfilled; otherwise it will run in the Docker container you created with `docker-compose build` (preparevms_prepare-vms).
|
- It will run locally if all its dependencies are fulfilled; otherwise it will run in the Docker container you created with `docker-compose build` (preparevms_prepare-vms).
|
||||||
- During `start` it will add your default local SSH key to all instances under the `ubuntu` user.
|
- During `start` it will add your default local SSH key to all instances under the `ubuntu` user.
|
||||||
- During `deploy` it will create the `docker` user with password `training`, which is printing on the cards for students. For now, this is hard coded.
|
- During `deploy` it will create the `docker` user with password `training`, which is printing on the cards for students. This can be configured with the `docker_user_password` property in the settings file.
|
||||||
|
|
||||||
### Example Steps to Launch a Batch of AWS Instances for a Workshop
|
### Example Steps to Launch a group of AWS Instances for a Workshop
|
||||||
|
|
||||||
- Run `./workshopctl start N` Creates `N` EC2 instances
|
- Run `./workshopctl start --infra infra/aws-us-east-2 --settings/myworkshop.yaml --count 60` to create 60 EC2 instances
|
||||||
- Your local SSH key will be synced to instances under `ubuntu` user
|
- Your local SSH key will be synced to instances under `ubuntu` user
|
||||||
- AWS instances will be created and tagged based on date, and IP's stored in `prepare-vms/tags/`
|
- AWS instances will be created and tagged based on date, and IP's stored in `prepare-vms/tags/`
|
||||||
- Run `./workshopctl deploy TAG settings/somefile.yaml` to run `lib/postprep.py` via parallel-ssh
|
- Run `./workshopctl deploy TAG` to run `lib/postprep.py` via parallel-ssh
|
||||||
- If it errors or times out, you should be able to rerun
|
- If it errors or times out, you should be able to rerun
|
||||||
- Requires good connection to run all the parallel SSH connections, up to 100 parallel (ProTip: create dedicated management instance in same AWS region where you run all these utils from)
|
- Requires good connection to run all the parallel SSH connections, up to 100 parallel (ProTip: create dedicated management instance in same AWS region where you run all these utils from)
|
||||||
- Run `./workshopctl pull_images TAG` to pre-pull a bunch of Docker images to the instances
|
- Run `./workshopctl pull_images TAG` to pre-pull a bunch of Docker images to the instances
|
||||||
- Run `./workshopctl cards TAG settings/somefile.yaml` generates PDF/HTML files to print and cut and hand out to students
|
- Run `./workshopctl cards TAG` generates PDF/HTML files to print and cut and hand out to students
|
||||||
- *Have a great workshop*
|
- *Have a great workshop*
|
||||||
- Run `./workshopctl stop TAG` to terminate instances.
|
- Run `./workshopctl stop TAG` to terminate instances.
|
||||||
|
|
||||||
### Example Steps to Launch Azure Instances
|
### Example Steps to Launch Azure Instances
|
||||||
|
|
||||||
- Install the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) and authenticate with a valid account
|
- Install the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) and authenticate with a valid account (`az login`)
|
||||||
- Customize `azuredeploy.parameters.json`
|
- Customize `azuredeploy.parameters.json`
|
||||||
- Required:
|
- Required:
|
||||||
- Provide the SSH public key you plan to use for instance configuration
|
- Provide the SSH public key you plan to use for instance configuration
|
||||||
@@ -155,27 +179,16 @@ az group delete --resource-group workshop
|
|||||||
|
|
||||||
### Example Steps to Configure Instances from a non-AWS Source
|
### Example Steps to Configure Instances from a non-AWS Source
|
||||||
|
|
||||||
- Launch instances via your preferred method. You'll need to get the instance IPs and be able to ssh into them.
|
- Copy `infra/example.generic` to `infra/generic`
|
||||||
- Set placeholder values for [AWS environment variable settings](#required-environment-variables).
|
- Run `./workshopctl start --infra infra/generic --settings settings/...yaml`
|
||||||
- Choose a tag. It could be an event name, datestamp, etc. Ensure you have created a directory for your tag: `prepare-vms/tags/<tag>/`
|
- Note the `prepare-vms/tags/TAG/` path that has been auto-created.
|
||||||
- If you have not already generated a file with the IPs to be configured:
|
- Launch instances via your preferred method. You'll need to get the instance IPs and be able to SSH into them.
|
||||||
- The file should be named `prepare-vms/tags/<tag>/ips.txt`
|
- Edit the file `prepare-vms/tags/TAG/ips.txt`, it should list the IP addresses of the VMs (one per line, without any comments or other info)
|
||||||
- Format is one IP per line, no other info needed.
|
- Continue deployment of cluster configuration with `./workshopctl deploy TAG`
|
||||||
- Ensure the settings file is as desired (especially the number of nodes): `prepare-vms/settings/kube101.yaml`
|
- Optionally, configure Kubernetes clusters of the size in the settings: workshopctl kube `TAG`
|
||||||
- For a tag called `myworkshop`, configure instances: `workshopctl deploy myworkshop settings/kube101.yaml`
|
- Optionally, test your Kubernetes clusters. They may take a little time to become ready: workshopctl kubetest `TAG`
|
||||||
- Optionally, configure Kubernetes clusters of the size in the settings: `workshopctl kube myworkshop`
|
- Generate cards to print and hand out: workshopctl cards `TAG`
|
||||||
- Optionally, test your Kubernetes clusters. They may take a little time to become ready: `workshopctl kubetest myworkshop`
|
- Print the cards file: prepare-vms/tags/`TAG`/ips.html
|
||||||
- Generate cards to print and hand out: `workshopctl cards myworkshop settings/kube101.yaml`
|
|
||||||
- Print the cards file: `prepare-vms/tags/myworkshop/ips.html`
|
|
||||||
|
|
||||||
|
|
||||||
## Other Tools
|
|
||||||
|
|
||||||
### Deploying your SSH key to all the machines
|
|
||||||
|
|
||||||
- Make sure that you have SSH keys loaded (`ssh-add -l`).
|
|
||||||
- Source `rc`.
|
|
||||||
- Run `pcopykey`.
|
|
||||||
|
|
||||||
|
|
||||||
## Even More Details
|
## Even More Details
|
||||||
@@ -188,7 +201,7 @@ To see which local key will be uploaded, run `ssh-add -l | grep RSA`.
|
|||||||
|
|
||||||
#### Instance + tag creation
|
#### Instance + tag creation
|
||||||
|
|
||||||
10 VMs will be started, with an automatically generated tag (timestamp + your username).
|
The VMs will be started, with an automatically generated tag (timestamp + your username).
|
||||||
|
|
||||||
Your SSH key will be added to the `authorized_keys` of the ubuntu user.
|
Your SSH key will be added to the `authorized_keys` of the ubuntu user.
|
||||||
|
|
||||||
@@ -196,15 +209,11 @@ Your SSH key will be added to the `authorized_keys` of the ubuntu user.
|
|||||||
|
|
||||||
Following the creation of the VMs, a text file will be created containing a list of their IPs.
|
Following the creation of the VMs, a text file will be created containing a list of their IPs.
|
||||||
|
|
||||||
This ips.txt file will be created in the $TAG/ directory and a symlink will be placed in the working directory of the script.
|
|
||||||
|
|
||||||
If you create new VMs, the symlinked file will be overwritten.
|
|
||||||
|
|
||||||
#### Deployment
|
#### Deployment
|
||||||
|
|
||||||
Instances can be deployed manually using the `deploy` command:
|
Instances can be deployed manually using the `deploy` command:
|
||||||
|
|
||||||
$ ./workshopctl deploy TAG settings/somefile.yaml
|
$ ./workshopctl deploy TAG
|
||||||
|
|
||||||
The `postprep.py` file will be copied via parallel-ssh to all of the VMs and executed.
|
The `postprep.py` file will be copied via parallel-ssh to all of the VMs and executed.
|
||||||
|
|
||||||
@@ -214,7 +223,7 @@ The `postprep.py` file will be copied via parallel-ssh to all of the VMs and exe
|
|||||||
|
|
||||||
#### Generate cards
|
#### Generate cards
|
||||||
|
|
||||||
$ ./workshopctl cards TAG settings/somefile.yaml
|
$ ./workshopctl cards TAG
|
||||||
|
|
||||||
If you want to generate both HTML and PDF cards, install [wkhtmltopdf](https://wkhtmltopdf.org/downloads.html); without that installed, only HTML cards will be generated.
|
If you want to generate both HTML and PDF cards, install [wkhtmltopdf](https://wkhtmltopdf.org/downloads.html); without that installed, only HTML cards will be generated.
|
||||||
|
|
||||||
@@ -222,13 +231,11 @@ If you don't have `wkhtmltopdf` installed, you will get a warning that it is a m
|
|||||||
|
|
||||||
#### List tags
|
#### List tags
|
||||||
|
|
||||||
$ ./workshopctl list
|
$ ./workshopctl list infra/some-infra-file
|
||||||
|
|
||||||
#### List VMs
|
$ ./workshopctl listall
|
||||||
|
|
||||||
$ ./workshopctl list TAG
|
$ ./workshopctl tags
|
||||||
|
|
||||||
This will print a human-friendly list containing some information about each instance.
|
|
||||||
|
|
||||||
#### Stop and destroy VMs
|
#### Stop and destroy VMs
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,6 @@ fi
|
|||||||
if id docker; then
|
if id docker; then
|
||||||
sudo userdel -r docker
|
sudo userdel -r docker
|
||||||
fi
|
fi
|
||||||
pip install --user awscli jinja2 pdfkit
|
sudo apt-get update -q
|
||||||
sudo apt-get install -y wkhtmltopdf xvfb
|
sudo apt-get install -qy jq python-pip wkhtmltopdf xvfb
|
||||||
tmux new-session \; send-keys "
|
pip install --user awscli jinja2 pdfkit pssh
|
||||||
[ -f ~/.ssh/id_rsa ] || ssh-keygen
|
|
||||||
|
|
||||||
eval \$(ssh-agent)
|
|
||||||
ssh-add
|
|
||||||
Xvfb :0 &
|
|
||||||
export DISPLAY=:0
|
|
||||||
mkdir -p ~/www
|
|
||||||
sudo docker run -d -p 80:80 -v \$HOME/www:/usr/share/nginx/html nginx
|
|
||||||
"
|
|
||||||
|
|||||||
6
prepare-vms/infra/example.aws
Normal file
6
prepare-vms/infra/example.aws
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
INFRACLASS=aws
|
||||||
|
# If you are using AWS to deploy, copy this file (e.g. to "aws", or "us-east-1")
|
||||||
|
# and customize the variables below.
|
||||||
|
export AWS_DEFAULT_REGION=us-east-1
|
||||||
|
export AWS_ACCESS_KEY_ID=AKI...
|
||||||
|
export AWS_SECRET_ACCESS_KEY=...
|
||||||
2
prepare-vms/infra/example.generic
Normal file
2
prepare-vms/infra/example.generic
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
INFRACLASS=generic
|
||||||
|
# This is for manual provisioning. No other variable or configuration is needed.
|
||||||
9
prepare-vms/infra/example.openstack
Normal file
9
prepare-vms/infra/example.openstack
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
INFRACLASS=openstack
|
||||||
|
# If you are using OpenStack, copy this file (e.g. to "openstack" or "enix")
|
||||||
|
# and customize the variables below.
|
||||||
|
export TF_VAR_user="jpetazzo"
|
||||||
|
export TF_VAR_tenant="training"
|
||||||
|
export TF_VAR_domain="Default"
|
||||||
|
export TF_VAR_password="..."
|
||||||
|
export TF_VAR_auth_url="https://api.r1.nxs.enix.io/v3"
|
||||||
|
export TF_VAR_flavor="GP1.S"
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
aws_display_tags() {
|
|
||||||
# Print all "Name" tags in our region with their instance count
|
|
||||||
echo "[#] [Status] [Token] [Tag]" \
|
|
||||||
| awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}'
|
|
||||||
aws ec2 describe-instances \
|
|
||||||
--query "Reservations[*].Instances[*].[State.Name,ClientToken,Tags[0].Value]" \
|
|
||||||
| tr -d "\r" \
|
|
||||||
| uniq -c \
|
|
||||||
| sort -k 3 \
|
|
||||||
| awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}'
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_get_tokens() {
|
|
||||||
aws ec2 describe-instances --output text \
|
|
||||||
--query 'Reservations[*].Instances[*].[ClientToken]' \
|
|
||||||
| sort -u
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_display_instance_statuses_by_tag() {
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
|
|
||||||
IDS=$(aws ec2 describe-instances \
|
|
||||||
--filters "Name=tag:Name,Values=$TAG" \
|
|
||||||
--query "Reservations[*].Instances[*].InstanceId" | tr '\t' ' ')
|
|
||||||
|
|
||||||
aws ec2 describe-instance-status \
|
|
||||||
--instance-ids $IDS \
|
|
||||||
--query "InstanceStatuses[*].{ID:InstanceId,InstanceState:InstanceState.Name,InstanceStatus:InstanceStatus.Status,SystemStatus:SystemStatus.Status,Reachability:InstanceStatus.Status}" \
|
|
||||||
--output table
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_display_instances_by_tag() {
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
result=$(aws ec2 describe-instances --output table \
|
|
||||||
--filter "Name=tag:Name,Values=$TAG" \
|
|
||||||
--query "Reservations[*].Instances[*].[ \
|
|
||||||
InstanceId, \
|
|
||||||
State.Name, \
|
|
||||||
Tags[0].Value, \
|
|
||||||
PublicIpAddress, \
|
|
||||||
InstanceType \
|
|
||||||
]"
|
|
||||||
)
|
|
||||||
if [[ -z $result ]]; then
|
|
||||||
die "No instances found with tag $TAG in region $AWS_DEFAULT_REGION."
|
|
||||||
else
|
|
||||||
echo "$result"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_get_instance_ids_by_filter() {
|
|
||||||
FILTER=$1
|
|
||||||
aws ec2 describe-instances --filters $FILTER \
|
|
||||||
--query Reservations[*].Instances[*].InstanceId \
|
|
||||||
--output text | tr "\t" "\n" | tr -d "\r"
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_get_instance_ids_by_client_token() {
|
|
||||||
TOKEN=$1
|
|
||||||
need_tag $TOKEN
|
|
||||||
aws_get_instance_ids_by_filter Name=client-token,Values=$TOKEN
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_get_instance_ids_by_tag() {
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
aws_get_instance_ids_by_filter Name=tag:Name,Values=$TAG
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_get_instance_ips_by_tag() {
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
aws ec2 describe-instances --filter "Name=tag:Name,Values=$TAG" \
|
|
||||||
--output text \
|
|
||||||
--query "Reservations[*].Instances[*].PublicIpAddress" \
|
|
||||||
| tr "\t" "\n" \
|
|
||||||
| sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 # sort IPs
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_kill_instances_by_tag() {
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
IDS=$(aws_get_instance_ids_by_tag $TAG)
|
|
||||||
if [ -z "$IDS" ]; then
|
|
||||||
die "Invalid tag."
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Deleting instances with tag $TAG."
|
|
||||||
|
|
||||||
aws ec2 terminate-instances --instance-ids $IDS \
|
|
||||||
| grep ^TERMINATINGINSTANCES
|
|
||||||
|
|
||||||
info "Deleted instances with tag $TAG."
|
|
||||||
}
|
|
||||||
|
|
||||||
aws_tag_instances() {
|
|
||||||
OLD_TAG_OR_TOKEN=$1
|
|
||||||
NEW_TAG=$2
|
|
||||||
IDS=$(aws_get_instance_ids_by_client_token $OLD_TAG_OR_TOKEN)
|
|
||||||
[[ -n "$IDS" ]] && aws ec2 create-tags --tag Key=Name,Value=$NEW_TAG --resources $IDS >/dev/null
|
|
||||||
IDS=$(aws_get_instance_ids_by_tag $OLD_TAG_OR_TOKEN)
|
|
||||||
[[ -n "$IDS" ]] && aws ec2 create-tags --tag Key=Name,Value=$NEW_TAG --resources $IDS >/dev/null
|
|
||||||
}
|
|
||||||
@@ -50,27 +50,38 @@ sep() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
need_tag() {
|
need_infra() {
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
|
die "Please specify infrastructure file. (e.g.: infra/aws)"
|
||||||
|
fi
|
||||||
|
if [ ! -f "$1" ]; then
|
||||||
|
die "Infrastructure file $1 doesn't exist."
|
||||||
|
fi
|
||||||
|
. "$1"
|
||||||
|
. "lib/infra/$INFRACLASS.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
need_tag() {
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
die "Please specify a tag or token. To see available tags and tokens, run: $0 list"
|
die "Please specify a tag or token. To see available tags and tokens, run: $0 list"
|
||||||
fi
|
fi
|
||||||
|
if [ ! -d "tags/$TAG" ]; then
|
||||||
|
die "Tag $TAG not found (directory tags/$TAG does not exist)."
|
||||||
|
fi
|
||||||
|
for FILE in settings.yaml ips.txt infra.sh; do
|
||||||
|
if [ ! -f "tags/$TAG/$FILE" ]; then
|
||||||
|
warning "File tags/$TAG/$FILE not found."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
. "tags/$TAG/infra.sh"
|
||||||
|
. "lib/infra/$INFRACLASS.sh"
|
||||||
}
|
}
|
||||||
|
|
||||||
need_settings() {
|
need_settings() {
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
die "Please specify a settings file."
|
die "Please specify a settings file. (e.g.: settings/kube101.yaml)"
|
||||||
elif [ ! -f "$1" ]; then
|
fi
|
||||||
|
if [ ! -f "$1" ]; then
|
||||||
die "Settings file $1 doesn't exist."
|
die "Settings file $1 doesn't exist."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
need_ips_file() {
|
|
||||||
IPS_FILE=$1
|
|
||||||
if [ -z "$IPS_FILE" ]; then
|
|
||||||
die "IPS_FILE not set."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -s "$IPS_FILE" ]; then
|
|
||||||
die "IPS_FILE $IPS_FILE not found. Please run: $0 ips <TAG>"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,21 +7,11 @@ _cmd() {
|
|||||||
|
|
||||||
_cmd help "Show available commands"
|
_cmd help "Show available commands"
|
||||||
_cmd_help() {
|
_cmd_help() {
|
||||||
printf "$(basename $0) - the orchestration workshop swiss army knife\n"
|
printf "$(basename $0) - the container training swiss army knife\n"
|
||||||
printf "Commands:"
|
printf "Commands:"
|
||||||
printf "%s" "$HELP" | sort
|
printf "%s" "$HELP" | sort
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd amis "List Ubuntu AMIs in the current region"
|
|
||||||
_cmd_amis() {
|
|
||||||
find_ubuntu_ami -r $AWS_DEFAULT_REGION "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
_cmd ami "Show the AMI that will be used for deployment"
|
|
||||||
_cmd_ami() {
|
|
||||||
find_ubuntu_ami -r $AWS_DEFAULT_REGION -a amd64 -v 16.04 -t hvm:ebs -N -q
|
|
||||||
}
|
|
||||||
|
|
||||||
_cmd build "Build the Docker image to run this program in a container"
|
_cmd build "Build the Docker image to run this program in a container"
|
||||||
_cmd_build() {
|
_cmd_build() {
|
||||||
docker-compose build
|
docker-compose build
|
||||||
@@ -32,64 +22,53 @@ _cmd_wrap() {
|
|||||||
docker-compose run --rm workshopctl "$@"
|
docker-compose run --rm workshopctl "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd cards "Generate ready-to-print cards for a batch of VMs"
|
_cmd cards "Generate ready-to-print cards for a group of VMs"
|
||||||
_cmd_cards() {
|
_cmd_cards() {
|
||||||
TAG=$1
|
TAG=$1
|
||||||
SETTINGS=$2
|
need_tag
|
||||||
need_tag $TAG
|
|
||||||
need_settings $SETTINGS
|
|
||||||
|
|
||||||
# If you're not using AWS, populate the ips.txt file manually
|
# This will process ips.txt to generate two files: ips.pdf and ips.html
|
||||||
if [ ! -f tags/$TAG/ips.txt ]; then
|
(
|
||||||
aws_get_instance_ips_by_tag $TAG >tags/$TAG/ips.txt
|
cd tags/$TAG
|
||||||
fi
|
../../lib/ips-txt-to-html.py settings.yaml
|
||||||
|
)
|
||||||
# Remove symlinks to old cards
|
|
||||||
rm -f ips.html ips.pdf
|
|
||||||
|
|
||||||
# This will generate two files in the base dir: ips.pdf and ips.html
|
|
||||||
lib/ips-txt-to-html.py $SETTINGS
|
|
||||||
|
|
||||||
for f in ips.html ips.pdf; do
|
|
||||||
# Remove old versions of cards if they exist
|
|
||||||
rm -f tags/$TAG/$f
|
|
||||||
|
|
||||||
# Move the generated file and replace it with a symlink
|
|
||||||
mv -f $f tags/$TAG/$f && ln -s tags/$TAG/$f $f
|
|
||||||
done
|
|
||||||
|
|
||||||
info "Cards created. You can view them with:"
|
info "Cards created. You can view them with:"
|
||||||
info "xdg-open ips.html ips.pdf (on Linux)"
|
info "xdg-open tags/$TAG/ips.html tags/$TAG/ips.pdf (on Linux)"
|
||||||
info "open ips.html ips.pdf (on MacOS)"
|
info "open tags/$TAG/ips.html (on macOS)"
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd deploy "Install Docker on a bunch of running VMs"
|
_cmd deploy "Install Docker on a bunch of running VMs"
|
||||||
_cmd_deploy() {
|
_cmd_deploy() {
|
||||||
TAG=$1
|
TAG=$1
|
||||||
SETTINGS=$2
|
need_tag
|
||||||
need_tag $TAG
|
|
||||||
need_settings $SETTINGS
|
|
||||||
link_tag $TAG
|
|
||||||
count=$(wc -l ips.txt)
|
|
||||||
|
|
||||||
# wait until all hosts are reachable before trying to deploy
|
# wait until all hosts are reachable before trying to deploy
|
||||||
info "Trying to reach $TAG instances..."
|
info "Trying to reach $TAG instances..."
|
||||||
while ! tag_is_reachable $TAG; do
|
while ! tag_is_reachable; do
|
||||||
>/dev/stderr echo -n "."
|
>/dev/stderr echo -n "."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
>/dev/stderr echo ""
|
>/dev/stderr echo ""
|
||||||
|
|
||||||
|
echo deploying > tags/$TAG/status
|
||||||
sep "Deploying tag $TAG"
|
sep "Deploying tag $TAG"
|
||||||
pssh -I tee /tmp/settings.yaml <$SETTINGS
|
|
||||||
|
# Wait for cloudinit to be done
|
||||||
|
pssh "
|
||||||
|
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
|
||||||
|
sleep 1
|
||||||
|
done"
|
||||||
|
|
||||||
|
# Copy settings and install Python YAML parser
|
||||||
|
pssh -I tee /tmp/settings.yaml <tags/$TAG/settings.yaml
|
||||||
pssh "
|
pssh "
|
||||||
sudo apt-get update &&
|
sudo apt-get update &&
|
||||||
sudo apt-get install -y python-setuptools &&
|
sudo apt-get install -y python-yaml"
|
||||||
sudo easy_install pyyaml"
|
|
||||||
|
|
||||||
# Copy postprep.py to the remote machines, and execute it, feeding it the list of IP addresses
|
# Copy postprep.py to the remote machines, and execute it, feeding it the list of IP addresses
|
||||||
pssh -I tee /tmp/postprep.py <lib/postprep.py
|
pssh -I tee /tmp/postprep.py <lib/postprep.py
|
||||||
pssh --timeout 900 --send-input "python /tmp/postprep.py >>/tmp/pp.out 2>>/tmp/pp.err" <ips.txt
|
pssh --timeout 900 --send-input "python /tmp/postprep.py >>/tmp/pp.out 2>>/tmp/pp.err" <tags/$TAG/ips.txt
|
||||||
|
|
||||||
# Install docker-prompt script
|
# Install docker-prompt script
|
||||||
pssh -I sudo tee /usr/local/bin/docker-prompt <lib/docker-prompt
|
pssh -I sudo tee /usr/local/bin/docker-prompt <lib/docker-prompt
|
||||||
@@ -117,14 +96,17 @@ _cmd_deploy() {
|
|||||||
fi"
|
fi"
|
||||||
|
|
||||||
sep "Deployed tag $TAG"
|
sep "Deployed tag $TAG"
|
||||||
|
echo deployed > tags/$TAG/status
|
||||||
info "You may want to run one of the following commands:"
|
info "You may want to run one of the following commands:"
|
||||||
info "$0 kube $TAG"
|
info "$0 kube $TAG"
|
||||||
info "$0 pull_images $TAG"
|
info "$0 pull_images $TAG"
|
||||||
info "$0 cards $TAG $SETTINGS"
|
info "$0 cards $TAG"
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd kube "Setup kubernetes clusters with kubeadm (must be run AFTER deploy)"
|
_cmd kube "Setup kubernetes clusters with kubeadm (must be run AFTER deploy)"
|
||||||
_cmd_kube() {
|
_cmd_kube() {
|
||||||
|
TAG=$1
|
||||||
|
need_tag
|
||||||
|
|
||||||
# Install packages
|
# Install packages
|
||||||
pssh --timeout 200 "
|
pssh --timeout 200 "
|
||||||
@@ -134,14 +116,16 @@ _cmd_kube() {
|
|||||||
sudo tee /etc/apt/sources.list.d/kubernetes.list"
|
sudo tee /etc/apt/sources.list.d/kubernetes.list"
|
||||||
pssh --timeout 200 "
|
pssh --timeout 200 "
|
||||||
sudo apt-get update -q &&
|
sudo apt-get update -q &&
|
||||||
sudo apt-get install -qy kubelet kubeadm kubectl
|
sudo apt-get install -qy kubelet kubeadm kubectl &&
|
||||||
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl"
|
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl"
|
||||||
|
|
||||||
# Initialize kube master
|
# Initialize kube master
|
||||||
pssh --timeout 200 "
|
pssh --timeout 200 "
|
||||||
if grep -q node1 /tmp/node && [ ! -f /etc/kubernetes/admin.conf ]; then
|
if grep -q node1 /tmp/node && [ ! -f /etc/kubernetes/admin.conf ]; then
|
||||||
kubeadm token generate > /tmp/token
|
kubeadm token generate > /tmp/token &&
|
||||||
sudo kubeadm init --token \$(cat /tmp/token)
|
sudo kubeadm init \
|
||||||
|
--token \$(cat /tmp/token) \
|
||||||
|
--ignore-preflight-errors=SystemVerification
|
||||||
fi"
|
fi"
|
||||||
|
|
||||||
# Put kubeconfig in ubuntu's and docker's accounts
|
# Put kubeconfig in ubuntu's and docker's accounts
|
||||||
@@ -157,22 +141,69 @@ _cmd_kube() {
|
|||||||
# Install weave as the pod network
|
# Install weave as the pod network
|
||||||
pssh "
|
pssh "
|
||||||
if grep -q node1 /tmp/node; then
|
if grep -q node1 /tmp/node; then
|
||||||
kubever=\$(kubectl version | base64 | tr -d '\n')
|
kubever=\$(kubectl version | base64 | tr -d '\n') &&
|
||||||
kubectl apply -f https://cloud.weave.works/k8s/net?k8s-version=\$kubever
|
kubectl apply -f https://cloud.weave.works/k8s/net?k8s-version=\$kubever
|
||||||
fi"
|
fi"
|
||||||
|
|
||||||
# Join the other nodes to the cluster
|
# Join the other nodes to the cluster
|
||||||
pssh --timeout 200 "
|
pssh --timeout 200 "
|
||||||
if ! grep -q node1 /tmp/node && [ ! -f /etc/kubernetes/kubelet.conf ]; then
|
if ! grep -q node1 /tmp/node && [ ! -f /etc/kubernetes/kubelet.conf ]; then
|
||||||
TOKEN=\$(ssh -o StrictHostKeyChecking=no node1 cat /tmp/token)
|
TOKEN=\$(ssh -o StrictHostKeyChecking=no node1 cat /tmp/token) &&
|
||||||
sudo kubeadm join --discovery-token-unsafe-skip-ca-verification --token \$TOKEN node1:6443
|
sudo kubeadm join \
|
||||||
|
--discovery-token-unsafe-skip-ca-verification \
|
||||||
|
--ignore-preflight-errors=SystemVerification \
|
||||||
|
--token \$TOKEN node1:6443
|
||||||
|
fi"
|
||||||
|
|
||||||
|
# Install kubectx and kubens
|
||||||
|
pssh "
|
||||||
|
[ -d kubectx ] || git clone https://github.com/ahmetb/kubectx &&
|
||||||
|
sudo ln -sf /home/ubuntu/kubectx/kubectx /usr/local/bin/kctx &&
|
||||||
|
sudo ln -sf /home/ubuntu/kubectx/kubens /usr/local/bin/kns &&
|
||||||
|
sudo cp /home/ubuntu/kubectx/completion/*.bash /etc/bash_completion.d &&
|
||||||
|
[ -d kube-ps1 ] || git clone https://github.com/jonmosco/kube-ps1 &&
|
||||||
|
sudo -u docker sed -i s/docker-prompt/kube_ps1/ /home/docker/.bashrc &&
|
||||||
|
sudo -u docker tee -a /home/docker/.bashrc <<EOF
|
||||||
|
. /home/ubuntu/kube-ps1/kube-ps1.sh
|
||||||
|
KUBE_PS1_PREFIX=""
|
||||||
|
KUBE_PS1_SUFFIX=""
|
||||||
|
KUBE_PS1_SYMBOL_ENABLE="false"
|
||||||
|
KUBE_PS1_CTX_COLOR="green"
|
||||||
|
KUBE_PS1_NS_COLOR="green"
|
||||||
|
EOF"
|
||||||
|
|
||||||
|
# Install stern
|
||||||
|
pssh "
|
||||||
|
if [ ! -x /usr/local/bin/stern ]; then
|
||||||
|
##VERSION##
|
||||||
|
sudo curl -L -o /usr/local/bin/stern https://github.com/wercker/stern/releases/download/1.10.0/stern_linux_amd64 &&
|
||||||
|
sudo chmod +x /usr/local/bin/stern &&
|
||||||
|
stern --completion bash | sudo tee /etc/bash_completion.d/stern
|
||||||
|
fi"
|
||||||
|
|
||||||
|
# Install helm
|
||||||
|
pssh "
|
||||||
|
if [ ! -x /usr/local/bin/helm ]; then
|
||||||
|
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | sudo bash &&
|
||||||
|
helm completion bash | sudo tee /etc/bash_completion.d/helm
|
||||||
fi"
|
fi"
|
||||||
|
|
||||||
sep "Done"
|
sep "Done"
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd kubetest "Check that all notes are reporting as Ready"
|
_cmd kubereset "Wipe out Kubernetes configuration on all nodes"
|
||||||
|
_cmd_kubereset() {
|
||||||
|
TAG=$1
|
||||||
|
need_tag
|
||||||
|
|
||||||
|
pssh "sudo kubeadm reset --force"
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd kubetest "Check that all nodes are reporting as Ready"
|
||||||
_cmd_kubetest() {
|
_cmd_kubetest() {
|
||||||
|
TAG=$1
|
||||||
|
need_tag
|
||||||
|
|
||||||
# There are way too many backslashes in the command below.
|
# There are way too many backslashes in the command below.
|
||||||
# Feel free to make that better ♥
|
# Feel free to make that better ♥
|
||||||
pssh "
|
pssh "
|
||||||
@@ -186,7 +217,7 @@ _cmd_kubetest() {
|
|||||||
fi"
|
fi"
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd ids "List the instance IDs belonging to a given tag or token"
|
_cmd ids "(FIXME) List the instance IDs belonging to a given tag or token"
|
||||||
_cmd_ids() {
|
_cmd_ids() {
|
||||||
TAG=$1
|
TAG=$1
|
||||||
need_tag $TAG
|
need_tag $TAG
|
||||||
@@ -199,262 +230,264 @@ _cmd_ids() {
|
|||||||
aws_get_instance_ids_by_client_token $TAG
|
aws_get_instance_ids_by_client_token $TAG
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd ips "List the IP addresses of the VMs for a given tag or token"
|
_cmd list "List available groups for a given infrastructure"
|
||||||
_cmd_ips() {
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
mkdir -p tags/$TAG
|
|
||||||
aws_get_instance_ips_by_tag $TAG | tee tags/$TAG/ips.txt
|
|
||||||
link_tag $TAG
|
|
||||||
}
|
|
||||||
|
|
||||||
_cmd list "List available batches in the current region"
|
|
||||||
_cmd_list() {
|
_cmd_list() {
|
||||||
info "Listing batches in region $AWS_DEFAULT_REGION:"
|
need_infra $1
|
||||||
aws_display_tags
|
infra_list
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd status "List instance status for a given batch"
|
_cmd listall "List VMs running on all configured infrastructures"
|
||||||
_cmd_status() {
|
_cmd_listall() {
|
||||||
info "Using region $AWS_DEFAULT_REGION."
|
for infra in infra/*; do
|
||||||
|
case $infra in
|
||||||
|
infra/example.*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
info "Listing infrastructure $infra:"
|
||||||
|
need_infra $infra
|
||||||
|
infra_list
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd netfix "Disable GRO and run a pinger job on the VMs"
|
||||||
|
_cmd_netfix () {
|
||||||
TAG=$1
|
TAG=$1
|
||||||
need_tag $TAG
|
need_tag
|
||||||
describe_tag $TAG
|
|
||||||
tag_is_reachable $TAG
|
pssh "
|
||||||
info "You may be interested in running one of the following commands:"
|
sudo ethtool -K ens3 gro off
|
||||||
info "$0 ips $TAG"
|
sudo tee /root/pinger.service <<EOF
|
||||||
info "$0 deploy $TAG <settings/somefile.yaml>"
|
[Unit]
|
||||||
|
Description=pinger
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/
|
||||||
|
ExecStart=/bin/ping -w60 1.1
|
||||||
|
User=nobody
|
||||||
|
Group=nogroup
|
||||||
|
Restart=always
|
||||||
|
EOF
|
||||||
|
sudo systemctl enable /root/pinger.service
|
||||||
|
sudo systemctl start pinger"
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd opensg "Open the default security group to ALL ingress traffic"
|
_cmd opensg "Open the default security group to ALL ingress traffic"
|
||||||
_cmd_opensg() {
|
_cmd_opensg() {
|
||||||
aws ec2 authorize-security-group-ingress \
|
need_infra $1
|
||||||
--group-name default \
|
infra_opensg
|
||||||
--protocol icmp \
|
}
|
||||||
--port -1 \
|
|
||||||
--cidr 0.0.0.0/0
|
|
||||||
|
|
||||||
aws ec2 authorize-security-group-ingress \
|
_cmd pssh "Run an arbitrary command on all nodes"
|
||||||
--group-name default \
|
_cmd_pssh() {
|
||||||
--protocol udp \
|
TAG=$1
|
||||||
--port 0-65535 \
|
need_tag
|
||||||
--cidr 0.0.0.0/0
|
shift
|
||||||
|
|
||||||
aws ec2 authorize-security-group-ingress \
|
pssh "$@"
|
||||||
--group-name default \
|
|
||||||
--protocol tcp \
|
|
||||||
--port 0-65535 \
|
|
||||||
--cidr 0.0.0.0/0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd pull_images "Pre-pull a bunch of Docker images"
|
_cmd pull_images "Pre-pull a bunch of Docker images"
|
||||||
_cmd_pull_images() {
|
_cmd_pull_images() {
|
||||||
TAG=$1
|
TAG=$1
|
||||||
need_tag $TAG
|
need_tag
|
||||||
pull_tag $TAG
|
pull_tag
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd retag "Apply a new tag to a batch of VMs"
|
_cmd quotas "Check our infrastructure quotas (max instances)"
|
||||||
|
_cmd_quotas() {
|
||||||
|
need_infra $1
|
||||||
|
infra_quotas
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd retag "(FIXME) Apply a new tag to a group of VMs"
|
||||||
_cmd_retag() {
|
_cmd_retag() {
|
||||||
OLDTAG=$1
|
OLDTAG=$1
|
||||||
NEWTAG=$2
|
NEWTAG=$2
|
||||||
need_tag $OLDTAG
|
TAG=$OLDTAG
|
||||||
|
need_tag
|
||||||
if [[ -z "$NEWTAG" ]]; then
|
if [[ -z "$NEWTAG" ]]; then
|
||||||
die "You must specify a new tag to apply."
|
die "You must specify a new tag to apply."
|
||||||
fi
|
fi
|
||||||
aws_tag_instances $OLDTAG $NEWTAG
|
aws_tag_instances $OLDTAG $NEWTAG
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd start "Start a batch of VMs"
|
_cmd start "Start a group of VMs"
|
||||||
_cmd_start() {
|
_cmd_start() {
|
||||||
# Number of instances to create
|
while [ ! -z "$*" ]; do
|
||||||
COUNT=$1
|
case "$1" in
|
||||||
# Optional settings file (to carry on with deployment)
|
--infra) INFRA=$2; shift 2;;
|
||||||
SETTINGS=$2
|
--settings) SETTINGS=$2; shift 2;;
|
||||||
|
--count) COUNT=$2; shift 2;;
|
||||||
|
--tag) TAG=$2; shift 2;;
|
||||||
|
*) die "Unrecognized parameter: $1."
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$INFRA" ]; then
|
||||||
|
die "Please add --infra flag to specify which infrastructure file to use."
|
||||||
|
fi
|
||||||
|
if [ -z "$SETTINGS" ]; then
|
||||||
|
die "Please add --settings flag to specify which settings file to use."
|
||||||
|
fi
|
||||||
if [ -z "$COUNT" ]; then
|
if [ -z "$COUNT" ]; then
|
||||||
die "Indicate number of instances to start."
|
COUNT=$(awk '/^clustersize:/ {print $2}' $SETTINGS)
|
||||||
|
warning "No --count option was specified. Using value from settings file ($COUNT)."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check that the specified settings and infrastructure are valid.
|
||||||
|
need_settings $SETTINGS
|
||||||
|
need_infra $INFRA
|
||||||
|
|
||||||
# Print our AWS username, to ease the pain of credential-juggling
|
if [ -z "$TAG" ]; then
|
||||||
greet
|
TAG=$(make_tag)
|
||||||
|
|
||||||
# Upload our SSH keys to AWS if needed, to be added to each VM's authorized_keys
|
|
||||||
key_name=$(sync_keys)
|
|
||||||
|
|
||||||
AMI=$(_cmd_ami) # Retrieve the AWS image ID
|
|
||||||
if [ -z "$AMI" ]; then
|
|
||||||
die "I could not find which AMI to use in this region. Try another region?"
|
|
||||||
fi
|
fi
|
||||||
TOKEN=$(get_token) # generate a timestamp token for this batch of VMs
|
mkdir -p tags/$TAG
|
||||||
AWS_KEY_NAME=$(make_key_name)
|
ln -s ../../$INFRA tags/$TAG/infra.sh
|
||||||
|
ln -s ../../$SETTINGS tags/$TAG/settings.yaml
|
||||||
sep "Starting instances"
|
echo creating > tags/$TAG/status
|
||||||
info " Count: $COUNT"
|
|
||||||
info " Region: $AWS_DEFAULT_REGION"
|
|
||||||
info " Token/tag: $TOKEN"
|
|
||||||
info " AMI: $AMI"
|
|
||||||
info " Key name: $AWS_KEY_NAME"
|
|
||||||
result=$(aws ec2 run-instances \
|
|
||||||
--key-name $AWS_KEY_NAME \
|
|
||||||
--count $COUNT \
|
|
||||||
--instance-type ${AWS_INSTANCE_TYPE-t2.medium} \
|
|
||||||
--client-token $TOKEN \
|
|
||||||
--image-id $AMI)
|
|
||||||
reservation_id=$(echo "$result" | head -1 | awk '{print $2}')
|
|
||||||
info "Reservation ID: $reservation_id"
|
|
||||||
sep
|
|
||||||
|
|
||||||
# if instance creation succeeded, we should have some IDs
|
|
||||||
IDS=$(aws_get_instance_ids_by_client_token $TOKEN)
|
|
||||||
if [ -z "$IDS" ]; then
|
|
||||||
die "Instance creation failed."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Tag these new instances with a tag that is the same as the token
|
|
||||||
TAG=$TOKEN
|
|
||||||
aws_tag_instances $TOKEN $TAG
|
|
||||||
|
|
||||||
wait_until_tag_is_running $TAG $COUNT
|
|
||||||
|
|
||||||
|
infra_start $COUNT
|
||||||
sep
|
sep
|
||||||
info "Successfully created $COUNT instances with tag $TAG"
|
info "Successfully created $COUNT instances with tag $TAG"
|
||||||
sep
|
sep
|
||||||
|
echo created > tags/$TAG/status
|
||||||
|
|
||||||
mkdir -p tags/$TAG
|
info "To deploy Docker on these instances, you can run:"
|
||||||
IPS=$(aws_get_instance_ips_by_tag $TAG)
|
info "$0 deploy $TAG"
|
||||||
echo "$IPS" >tags/$TAG/ips.txt
|
info "To terminate these instances, you can run:"
|
||||||
link_tag $TAG
|
info "$0 stop $TAG"
|
||||||
if [ -n "$SETTINGS" ]; then
|
|
||||||
_cmd_deploy $TAG $SETTINGS
|
|
||||||
else
|
|
||||||
info "To deploy or kill these instances, run one of the following:"
|
|
||||||
info "$0 deploy $TAG <settings/somefile.yaml>"
|
|
||||||
info "$0 stop $TAG"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_cmd ec2quotas "Check our EC2 quotas (max instances)"
|
|
||||||
_cmd_ec2quotas() {
|
|
||||||
greet
|
|
||||||
|
|
||||||
max_instances=$(aws ec2 describe-account-attributes \
|
|
||||||
--attribute-names max-instances \
|
|
||||||
--query 'AccountAttributes[*][AttributeValues]')
|
|
||||||
info "In the current region ($AWS_DEFAULT_REGION) you can deploy up to $max_instances instances."
|
|
||||||
|
|
||||||
# Print list of AWS EC2 regions, highlighting ours ($AWS_DEFAULT_REGION) in the list
|
|
||||||
# If our $AWS_DEFAULT_REGION is not valid, the error message will be pretty descriptive:
|
|
||||||
# Could not connect to the endpoint URL: "https://ec2.foo.amazonaws.com/"
|
|
||||||
info "Available regions:"
|
|
||||||
aws ec2 describe-regions | awk '{print $3}' | grep --color=auto $AWS_DEFAULT_REGION -C50
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd stop "Stop (terminate, shutdown, kill, remove, destroy...) instances"
|
_cmd stop "Stop (terminate, shutdown, kill, remove, destroy...) instances"
|
||||||
_cmd_stop() {
|
_cmd_stop() {
|
||||||
TAG=$1
|
TAG=$1
|
||||||
need_tag $TAG
|
need_tag
|
||||||
aws_kill_instances_by_tag $TAG
|
infra_stop
|
||||||
|
echo stopped > tags/$TAG/status
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd test "Run tests (pre-flight checks) on a batch of VMs"
|
_cmd tags "List groups of VMs known locally"
|
||||||
|
_cmd_tags() {
|
||||||
|
(
|
||||||
|
cd tags
|
||||||
|
echo "[#] [Status] [Tag] [Infra]" \
|
||||||
|
| awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}'
|
||||||
|
for tag in *; do
|
||||||
|
if [ -f $tag/ips.txt ]; then
|
||||||
|
count="$(wc -l < $tag/ips.txt)"
|
||||||
|
else
|
||||||
|
count="?"
|
||||||
|
fi
|
||||||
|
if [ -f $tag/status ]; then
|
||||||
|
status="$(cat $tag/status)"
|
||||||
|
else
|
||||||
|
status="?"
|
||||||
|
fi
|
||||||
|
if [ -f $tag/infra.sh ]; then
|
||||||
|
infra="$(basename $(readlink $tag/infra.sh))"
|
||||||
|
else
|
||||||
|
infra="?"
|
||||||
|
fi
|
||||||
|
echo "$count $status $tag $infra" \
|
||||||
|
| awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}'
|
||||||
|
done
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd test "Run tests (pre-flight checks) on a group of VMs"
|
||||||
_cmd_test() {
|
_cmd_test() {
|
||||||
TAG=$1
|
TAG=$1
|
||||||
need_tag $TAG
|
need_tag
|
||||||
test_tag $TAG
|
test_tag
|
||||||
}
|
}
|
||||||
|
|
||||||
###
|
_cmd helmprom "Install Helm and Prometheus"
|
||||||
|
_cmd_helmprom() {
|
||||||
|
TAG=$1
|
||||||
|
need_tag
|
||||||
|
pssh "
|
||||||
|
if grep -q node1 /tmp/node; then
|
||||||
|
kubectl -n kube-system get serviceaccount helm ||
|
||||||
|
kubectl -n kube-system create serviceaccount helm
|
||||||
|
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
|
||||||
|
helm upgrade --install prometheus stable/prometheus \
|
||||||
|
--namespace kube-system \
|
||||||
|
--set server.service.type=NodePort \
|
||||||
|
--set server.service.nodePort=30090 \
|
||||||
|
--set server.persistentVolume.enabled=false \
|
||||||
|
--set alertmanager.enabled=false
|
||||||
|
fi"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sometimes, weave fails to come up on some nodes.
|
||||||
|
# Symptom: the pods on a node are unreachable (they don't even ping).
|
||||||
|
# Remedy: wipe out Weave state and delete weave pod on that node.
|
||||||
|
# Specifically, identify the weave pod that is defective, then:
|
||||||
|
# kubectl -n kube-system exec weave-net-XXXXX -c weave rm /weavedb/weave-netdata.db
|
||||||
|
# kubectl -n kube-system delete pod weave-net-XXXXX
|
||||||
|
_cmd weavetest "Check that weave seems properly setup"
|
||||||
|
_cmd_weavetest() {
|
||||||
|
TAG=$1
|
||||||
|
need_tag
|
||||||
|
pssh "
|
||||||
|
kubectl -n kube-system get pods -o name | grep weave | cut -d/ -f2 |
|
||||||
|
xargs -I POD kubectl -n kube-system exec POD -c weave -- \
|
||||||
|
sh -c \"./weave --local status | grep Connections | grep -q ' 1 failed' || ! echo POD \""
|
||||||
|
}
|
||||||
|
|
||||||
greet() {
|
greet() {
|
||||||
IAMUSER=$(aws iam get-user --query 'User.UserName')
|
IAMUSER=$(aws iam get-user --query 'User.UserName')
|
||||||
info "Hello! You seem to be UNIX user $USER, and IAM user $IAMUSER."
|
info "Hello! You seem to be UNIX user $USER, and IAM user $IAMUSER."
|
||||||
}
|
}
|
||||||
|
|
||||||
link_tag() {
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
IPS_FILE=tags/$TAG/ips.txt
|
|
||||||
need_ips_file $IPS_FILE
|
|
||||||
ln -sf $IPS_FILE ips.txt
|
|
||||||
}
|
|
||||||
|
|
||||||
pull_tag() {
|
pull_tag() {
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
link_tag $TAG
|
|
||||||
if [ ! -s $IPS_FILE ]; then
|
|
||||||
die "Nonexistent or empty IPs file $IPS_FILE."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Pre-pull a bunch of images
|
# Pre-pull a bunch of images
|
||||||
pssh --timeout 900 'for I in \
|
pssh --timeout 900 'for I in \
|
||||||
debian:latest \
|
debian:latest \
|
||||||
ubuntu:latest \
|
ubuntu:latest \
|
||||||
fedora:latest \
|
fedora:latest \
|
||||||
centos:latest \
|
centos:latest \
|
||||||
elasticsearch:2 \
|
elasticsearch:2 \
|
||||||
postgres \
|
postgres \
|
||||||
redis \
|
redis \
|
||||||
alpine \
|
alpine \
|
||||||
registry \
|
registry \
|
||||||
nicolaka/netshoot \
|
nicolaka/netshoot \
|
||||||
jpetazzo/trainingwheels \
|
jpetazzo/trainingwheels \
|
||||||
golang \
|
golang \
|
||||||
training/namer \
|
training/namer \
|
||||||
dockercoins/hasher \
|
dockercoins/hasher \
|
||||||
dockercoins/rng \
|
dockercoins/rng \
|
||||||
dockercoins/webui \
|
dockercoins/webui \
|
||||||
dockercoins/worker \
|
dockercoins/worker \
|
||||||
logstash \
|
logstash \
|
||||||
prom/node-exporter \
|
prom/node-exporter \
|
||||||
google/cadvisor \
|
google/cadvisor \
|
||||||
dockersamples/visualizer \
|
dockersamples/visualizer \
|
||||||
nathanleclaire/redisonrails; do
|
nathanleclaire/redisonrails; do
|
||||||
sudo -u docker docker pull $I
|
sudo -u docker docker pull $I
|
||||||
done'
|
done'
|
||||||
|
|
||||||
info "Finished pulling images for $TAG."
|
info "Finished pulling images for $TAG."
|
||||||
info "You may now want to run:"
|
|
||||||
info "$0 cards $TAG <settings/somefile.yaml>"
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_until_tag_is_running() {
|
|
||||||
max_retry=50
|
|
||||||
TAG=$1
|
|
||||||
COUNT=$2
|
|
||||||
i=0
|
|
||||||
done_count=0
|
|
||||||
while [[ $done_count -lt $COUNT ]]; do
|
|
||||||
let "i += 1"
|
|
||||||
info "$(printf "%d/%d instances online" $done_count $COUNT)"
|
|
||||||
done_count=$(aws ec2 describe-instances \
|
|
||||||
--filters "Name=instance-state-name,Values=running" \
|
|
||||||
"Name=tag:Name,Values=$TAG" \
|
|
||||||
--query "Reservations[*].Instances[*].State.Name" \
|
|
||||||
| tr "\t" "\n" \
|
|
||||||
| wc -l)
|
|
||||||
|
|
||||||
if [[ $i -gt $max_retry ]]; then
|
|
||||||
die "Timed out while waiting for instance creation (after $max_retry retries)"
|
|
||||||
fi
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_is_reachable() {
|
tag_is_reachable() {
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
link_tag $TAG
|
|
||||||
pssh -t 5 true 2>&1 >/dev/null
|
pssh -t 5 true 2>&1 >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
test_tag() {
|
test_tag() {
|
||||||
TAG=$1
|
|
||||||
ips_file=tags/$TAG/ips.txt
|
ips_file=tags/$TAG/ips.txt
|
||||||
info "Picking a random IP address in $ips_file to run tests."
|
info "Picking a random IP address in $ips_file to run tests."
|
||||||
n=$((1 + $RANDOM % $(wc -l <$ips_file)))
|
ip=$(shuf -n1 $ips_file)
|
||||||
ip=$(head -n $n $ips_file | tail -n 1)
|
|
||||||
test_vm $ip
|
test_vm $ip
|
||||||
info "Tests complete."
|
info "Tests complete."
|
||||||
}
|
}
|
||||||
@@ -530,17 +563,9 @@ sync_keys() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
get_token() {
|
make_tag() {
|
||||||
if [ -z $USER ]; then
|
if [ -z $USER ]; then
|
||||||
export USER=anonymous
|
export USER=anonymous
|
||||||
fi
|
fi
|
||||||
date +%Y-%m-%d-%H-%M-$USER
|
date +%Y-%m-%d-%H-%M-$USER
|
||||||
}
|
}
|
||||||
|
|
||||||
describe_tag() {
|
|
||||||
# Display instance details and reachability/status information
|
|
||||||
TAG=$1
|
|
||||||
need_tag $TAG
|
|
||||||
aws_display_instances_by_tag $TAG
|
|
||||||
aws_display_instance_statuses_by_tag $TAG
|
|
||||||
}
|
|
||||||
|
|||||||
26
prepare-vms/lib/infra.sh
Normal file
26
prepare-vms/lib/infra.sh
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Default stub functions for infrastructure libraries.
|
||||||
|
# When loading an infrastructure library, these functions will be overridden.
|
||||||
|
|
||||||
|
infra_list() {
|
||||||
|
warning "infra_list is unsupported on $INFRACLASS."
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_quotas() {
|
||||||
|
warning "infra_quotas is unsupported on $INFRACLASS."
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_start() {
|
||||||
|
warning "infra_start is unsupported on $INFRACLASS."
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_stop() {
|
||||||
|
warning "infra_stop is unsupported on $INFRACLASS."
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_quotas() {
|
||||||
|
warning "infra_quotas is unsupported on $INFRACLASS."
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_opensg() {
|
||||||
|
warning "infra_opensg is unsupported on $INFRACLASS."
|
||||||
|
}
|
||||||
206
prepare-vms/lib/infra/aws.sh
Normal file
206
prepare-vms/lib/infra/aws.sh
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
infra_list() {
|
||||||
|
aws_display_tags
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_quotas() {
|
||||||
|
greet
|
||||||
|
|
||||||
|
max_instances=$(aws ec2 describe-account-attributes \
|
||||||
|
--attribute-names max-instances \
|
||||||
|
--query 'AccountAttributes[*][AttributeValues]')
|
||||||
|
info "In the current region ($AWS_DEFAULT_REGION) you can deploy up to $max_instances instances."
|
||||||
|
|
||||||
|
# Print list of AWS EC2 regions, highlighting ours ($AWS_DEFAULT_REGION) in the list
|
||||||
|
# If our $AWS_DEFAULT_REGION is not valid, the error message will be pretty descriptive:
|
||||||
|
# Could not connect to the endpoint URL: "https://ec2.foo.amazonaws.com/"
|
||||||
|
info "Available regions:"
|
||||||
|
aws ec2 describe-regions | awk '{print $3}' | grep --color=auto $AWS_DEFAULT_REGION -C50
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_start() {
|
||||||
|
COUNT=$1
|
||||||
|
|
||||||
|
# Print our AWS username, to ease the pain of credential-juggling
|
||||||
|
greet
|
||||||
|
|
||||||
|
# Upload our SSH keys to AWS if needed, to be added to each VM's authorized_keys
|
||||||
|
key_name=$(sync_keys)
|
||||||
|
|
||||||
|
AMI=$(aws_get_ami) # Retrieve the AWS image ID
|
||||||
|
if [ -z "$AMI" ]; then
|
||||||
|
die "I could not find which AMI to use in this region. Try another region?"
|
||||||
|
fi
|
||||||
|
AWS_KEY_NAME=$(make_key_name)
|
||||||
|
|
||||||
|
sep "Starting instances"
|
||||||
|
info " Count: $COUNT"
|
||||||
|
info " Region: $AWS_DEFAULT_REGION"
|
||||||
|
info " Token/tag: $TAG"
|
||||||
|
info " AMI: $AMI"
|
||||||
|
info " Key name: $AWS_KEY_NAME"
|
||||||
|
result=$(aws ec2 run-instances \
|
||||||
|
--key-name $AWS_KEY_NAME \
|
||||||
|
--count $COUNT \
|
||||||
|
--instance-type ${AWS_INSTANCE_TYPE-t2.medium} \
|
||||||
|
--client-token $TAG \
|
||||||
|
--block-device-mapping 'DeviceName=/dev/sda1,Ebs={VolumeSize=20}' \
|
||||||
|
--image-id $AMI)
|
||||||
|
reservation_id=$(echo "$result" | head -1 | awk '{print $2}')
|
||||||
|
info "Reservation ID: $reservation_id"
|
||||||
|
sep
|
||||||
|
|
||||||
|
# if instance creation succeeded, we should have some IDs
|
||||||
|
IDS=$(aws_get_instance_ids_by_client_token $TAG)
|
||||||
|
if [ -z "$IDS" ]; then
|
||||||
|
die "Instance creation failed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Tag these new instances with a tag that is the same as the token
|
||||||
|
aws_tag_instances $TAG $TAG
|
||||||
|
|
||||||
|
# Wait until EC2 API tells us that the instances are running
|
||||||
|
wait_until_tag_is_running $TAG $COUNT
|
||||||
|
|
||||||
|
aws_get_instance_ips_by_tag $TAG > tags/$TAG/ips.txt
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_stop() {
|
||||||
|
aws_kill_instances_by_tag
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_opensg() {
|
||||||
|
aws ec2 authorize-security-group-ingress \
|
||||||
|
--group-name default \
|
||||||
|
--protocol icmp \
|
||||||
|
--port -1 \
|
||||||
|
--cidr 0.0.0.0/0
|
||||||
|
|
||||||
|
aws ec2 authorize-security-group-ingress \
|
||||||
|
--group-name default \
|
||||||
|
--protocol udp \
|
||||||
|
--port 0-65535 \
|
||||||
|
--cidr 0.0.0.0/0
|
||||||
|
|
||||||
|
aws ec2 authorize-security-group-ingress \
|
||||||
|
--group-name default \
|
||||||
|
--protocol tcp \
|
||||||
|
--port 0-65535 \
|
||||||
|
--cidr 0.0.0.0/0
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_until_tag_is_running() {
|
||||||
|
max_retry=50
|
||||||
|
i=0
|
||||||
|
done_count=0
|
||||||
|
while [[ $done_count -lt $COUNT ]]; do
|
||||||
|
let "i += 1"
|
||||||
|
info "$(printf "%d/%d instances online" $done_count $COUNT)"
|
||||||
|
done_count=$(aws ec2 describe-instances \
|
||||||
|
--filters "Name=tag:Name,Values=$TAG" \
|
||||||
|
"Name=instance-state-name,Values=running" \
|
||||||
|
--query "length(Reservations[].Instances[])")
|
||||||
|
if [[ $i -gt $max_retry ]]; then
|
||||||
|
die "Timed out while waiting for instance creation (after $max_retry retries)"
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_display_tags() {
|
||||||
|
# Print all "Name" tags in our region with their instance count
|
||||||
|
echo "[#] [Status] [Token] [Tag]" \
|
||||||
|
| awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}'
|
||||||
|
aws ec2 describe-instances \
|
||||||
|
--query "Reservations[*].Instances[*].[State.Name,ClientToken,Tags[0].Value]" \
|
||||||
|
| tr -d "\r" \
|
||||||
|
| uniq -c \
|
||||||
|
| sort -k 3 \
|
||||||
|
| awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}'
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_get_tokens() {
|
||||||
|
aws ec2 describe-instances --output text \
|
||||||
|
--query 'Reservations[*].Instances[*].[ClientToken]' \
|
||||||
|
| sort -u
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_display_instance_statuses_by_tag() {
|
||||||
|
IDS=$(aws ec2 describe-instances \
|
||||||
|
--filters "Name=tag:Name,Values=$TAG" \
|
||||||
|
--query "Reservations[*].Instances[*].InstanceId" | tr '\t' ' ')
|
||||||
|
|
||||||
|
aws ec2 describe-instance-status \
|
||||||
|
--instance-ids $IDS \
|
||||||
|
--query "InstanceStatuses[*].{ID:InstanceId,InstanceState:InstanceState.Name,InstanceStatus:InstanceStatus.Status,SystemStatus:SystemStatus.Status,Reachability:InstanceStatus.Status}" \
|
||||||
|
--output table
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_display_instances_by_tag() {
|
||||||
|
result=$(aws ec2 describe-instances --output table \
|
||||||
|
--filter "Name=tag:Name,Values=$TAG" \
|
||||||
|
--query "Reservations[*].Instances[*].[ \
|
||||||
|
InstanceId, \
|
||||||
|
State.Name, \
|
||||||
|
Tags[0].Value, \
|
||||||
|
PublicIpAddress, \
|
||||||
|
InstanceType \
|
||||||
|
]"
|
||||||
|
)
|
||||||
|
if [[ -z $result ]]; then
|
||||||
|
die "No instances found with tag $TAG in region $AWS_DEFAULT_REGION."
|
||||||
|
else
|
||||||
|
echo "$result"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_get_instance_ids_by_filter() {
|
||||||
|
FILTER=$1
|
||||||
|
aws ec2 describe-instances --filters $FILTER \
|
||||||
|
--query Reservations[*].Instances[*].InstanceId \
|
||||||
|
--output text | tr "\t" "\n" | tr -d "\r"
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_get_instance_ids_by_client_token() {
|
||||||
|
TOKEN=$1
|
||||||
|
aws_get_instance_ids_by_filter Name=client-token,Values=$TOKEN
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_get_instance_ids_by_tag() {
|
||||||
|
aws_get_instance_ids_by_filter Name=tag:Name,Values=$TAG
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_get_instance_ips_by_tag() {
|
||||||
|
aws ec2 describe-instances --filter "Name=tag:Name,Values=$TAG" \
|
||||||
|
--output text \
|
||||||
|
--query "Reservations[*].Instances[*].PublicIpAddress" \
|
||||||
|
| tr "\t" "\n" \
|
||||||
|
| sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 # sort IPs
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_kill_instances_by_tag() {
|
||||||
|
IDS=$(aws_get_instance_ids_by_tag $TAG)
|
||||||
|
if [ -z "$IDS" ]; then
|
||||||
|
die "Invalid tag."
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "Deleting instances with tag $TAG."
|
||||||
|
|
||||||
|
aws ec2 terminate-instances --instance-ids $IDS \
|
||||||
|
| grep ^TERMINATINGINSTANCES
|
||||||
|
|
||||||
|
info "Deleted instances with tag $TAG."
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_tag_instances() {
|
||||||
|
OLD_TAG_OR_TOKEN=$1
|
||||||
|
NEW_TAG=$2
|
||||||
|
IDS=$(aws_get_instance_ids_by_client_token $OLD_TAG_OR_TOKEN)
|
||||||
|
[[ -n "$IDS" ]] && aws ec2 create-tags --tag Key=Name,Value=$NEW_TAG --resources $IDS >/dev/null
|
||||||
|
IDS=$(aws_get_instance_ids_by_tag $OLD_TAG_OR_TOKEN)
|
||||||
|
[[ -n "$IDS" ]] && aws ec2 create-tags --tag Key=Name,Value=$NEW_TAG --resources $IDS >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
aws_get_ami() {
|
||||||
|
##VERSION##
|
||||||
|
find_ubuntu_ami -r $AWS_DEFAULT_REGION -a amd64 -v 18.04 -t hvm:ebs -N -q
|
||||||
|
}
|
||||||
8
prepare-vms/lib/infra/generic.sh
Normal file
8
prepare-vms/lib/infra/generic.sh
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
infra_start() {
|
||||||
|
COUNT=$1
|
||||||
|
info "You should now run your provisioning commands for $COUNT machines."
|
||||||
|
info "Note: no machines have been automatically created!"
|
||||||
|
info "Once done, put the list of IP addresses in tags/$TAG/ips.txt"
|
||||||
|
info "(one IP address per line, without any comments or extra lines)."
|
||||||
|
touch tags/$TAG/ips.txt
|
||||||
|
}
|
||||||
20
prepare-vms/lib/infra/openstack.sh
Normal file
20
prepare-vms/lib/infra/openstack.sh
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
infra_start() {
|
||||||
|
COUNT=$1
|
||||||
|
|
||||||
|
cp terraform/*.tf tags/$TAG
|
||||||
|
(
|
||||||
|
cd tags/$TAG
|
||||||
|
terraform init
|
||||||
|
echo prefix = \"$TAG\" >> terraform.tfvars
|
||||||
|
echo count = \"$COUNT\" >> terraform.tfvars
|
||||||
|
terraform apply -auto-approve
|
||||||
|
terraform output ip_addresses > ips.txt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
infra_stop() {
|
||||||
|
(
|
||||||
|
cd tags/$TAG
|
||||||
|
terraform destroy -auto-approve
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -31,7 +31,13 @@ while ips:
|
|||||||
clusters.append(cluster)
|
clusters.append(cluster)
|
||||||
|
|
||||||
template_file_name = SETTINGS["cards_template"]
|
template_file_name = SETTINGS["cards_template"]
|
||||||
template = jinja2.Template(open(template_file_name).read())
|
template_file_path = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
"..",
|
||||||
|
"templates",
|
||||||
|
template_file_name
|
||||||
|
)
|
||||||
|
template = jinja2.Template(open(template_file_path).read())
|
||||||
with open("ips.html", "w") as f:
|
with open("ips.html", "w") as f:
|
||||||
f.write(template.render(clusters=clusters, **SETTINGS))
|
f.write(template.render(clusters=clusters, **SETTINGS))
|
||||||
print("Generated ips.html")
|
print("Generated ips.html")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ COMPOSE_VERSION = config["compose_version"]
|
|||||||
MACHINE_VERSION = config["machine_version"]
|
MACHINE_VERSION = config["machine_version"]
|
||||||
CLUSTER_SIZE = config["clustersize"]
|
CLUSTER_SIZE = config["clustersize"]
|
||||||
ENGINE_VERSION = config["engine_version"]
|
ENGINE_VERSION = config["engine_version"]
|
||||||
|
DOCKER_USER_PASSWORD = config["docker_user_password"]
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
|
|
||||||
@@ -54,9 +55,9 @@ system("curl --silent {} > /tmp/ipv4".format(ipv4_retrieval_endpoint))
|
|||||||
|
|
||||||
ipv4 = open("/tmp/ipv4").read()
|
ipv4 = open("/tmp/ipv4").read()
|
||||||
|
|
||||||
# Add a "docker" user with password "training"
|
# Add a "docker" user with password coming from the settings
|
||||||
system("id docker || sudo useradd -d /home/docker -m -s /bin/bash docker")
|
system("id docker || sudo useradd -d /home/docker -m -s /bin/bash docker")
|
||||||
system("echo docker:training | sudo chpasswd")
|
system("echo docker:{} | sudo chpasswd".format(DOCKER_USER_PASSWORD))
|
||||||
|
|
||||||
# Fancy prompt courtesy of @soulshake.
|
# Fancy prompt courtesy of @soulshake.
|
||||||
system("""sudo -u docker tee -a /home/docker/.bashrc <<SQRL
|
system("""sudo -u docker tee -a /home/docker/.bashrc <<SQRL
|
||||||
@@ -82,7 +83,7 @@ system("sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /e
|
|||||||
|
|
||||||
system("sudo service ssh restart")
|
system("sudo service ssh restart")
|
||||||
system("sudo apt-get -q update")
|
system("sudo apt-get -q update")
|
||||||
system("sudo apt-get -qy install git jq python-pip")
|
system("sudo apt-get -qy install git jq")
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
### DOCKER INSTALLS ###
|
### DOCKER INSTALLS ###
|
||||||
@@ -97,7 +98,6 @@ system("sudo apt-get -q update")
|
|||||||
system("sudo apt-get -qy install docker-ce")
|
system("sudo apt-get -qy install docker-ce")
|
||||||
|
|
||||||
### Install docker-compose
|
### Install docker-compose
|
||||||
#system("sudo pip install -U docker-compose=={}".format(COMPOSE_VERSION))
|
|
||||||
system("sudo curl -sSL -o /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/{}/docker-compose-{}-{}".format(COMPOSE_VERSION, platform.system(), platform.machine()))
|
system("sudo curl -sSL -o /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/{}/docker-compose-{}-{}".format(COMPOSE_VERSION, platform.system(), platform.machine()))
|
||||||
system("sudo chmod +x /usr/local/bin/docker-compose")
|
system("sudo chmod +x /usr/local/bin/docker-compose")
|
||||||
system("docker-compose version")
|
system("docker-compose version")
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
# This file can be sourced in order to directly run commands on
|
# This file can be sourced in order to directly run commands on
|
||||||
# a batch of VMs whose IPs are located in ips.txt of the directory in which
|
# a group of VMs whose IPs are located in ips.txt of the directory in which
|
||||||
# the command is run.
|
# the command is run.
|
||||||
|
|
||||||
pssh() {
|
pssh() {
|
||||||
HOSTFILE="ips.txt"
|
if [ -z "$TAG" ]; then
|
||||||
|
>/dev/stderr echo "Variable \$TAG is not set."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
HOSTFILE="tags/$TAG/ips.txt"
|
||||||
|
|
||||||
[ -f $HOSTFILE ] || {
|
[ -f $HOSTFILE ] || {
|
||||||
>/dev/stderr echo "No hostfile found at $HOSTFILE"
|
>/dev/stderr echo "Hostfile $HOSTFILE not found."
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
prepare-vms/settings/enix.yaml
Normal file
25
prepare-vms/settings/enix.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Number of VMs per cluster
|
||||||
|
clustersize: 5
|
||||||
|
|
||||||
|
# Jinja2 template to use to generate ready-to-cut cards
|
||||||
|
cards_template: enix.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
|
||||||
|
|
||||||
|
# These correspond to the version numbers visible on their respective GitHub release pages
|
||||||
|
compose_version: 1.22.0
|
||||||
|
machine_version: 0.14.0
|
||||||
|
|
||||||
|
# Password used to connect with the "docker user"
|
||||||
|
docker_user_password: training
|
||||||
@@ -22,3 +22,6 @@ engine_version: test
|
|||||||
# These correspond to the version numbers visible on their respective GitHub release pages
|
# These correspond to the version numbers visible on their respective GitHub release pages
|
||||||
compose_version: 1.18.0
|
compose_version: 1.18.0
|
||||||
machine_version: 0.13.0
|
machine_version: 0.13.0
|
||||||
|
|
||||||
|
# Password used to connect with the "docker user"
|
||||||
|
docker_user_password: training
|
||||||
|
|||||||
@@ -20,5 +20,8 @@ paper_margin: 0.2in
|
|||||||
engine_version: stable
|
engine_version: stable
|
||||||
|
|
||||||
# These correspond to the version numbers visible on their respective GitHub release pages
|
# These correspond to the version numbers visible on their respective GitHub release pages
|
||||||
compose_version: 1.21.1
|
compose_version: 1.22.0
|
||||||
machine_version: 0.14.0
|
machine_version: 0.15.0
|
||||||
|
|
||||||
|
# Password used to connect with the "docker user"
|
||||||
|
docker_user_password: training
|
||||||
|
|||||||
25
prepare-vms/settings/jerome.yaml
Normal file
25
prepare-vms/settings/jerome.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Number of VMs per cluster
|
||||||
|
clustersize: 4
|
||||||
|
|
||||||
|
# Jinja2 template to use to generate ready-to-cut cards
|
||||||
|
cards_template: jerome.html
|
||||||
|
|
||||||
|
# Use "Letter" in the US, and "A4" everywhere else
|
||||||
|
paper_size: Letter
|
||||||
|
|
||||||
|
# Feel free to reduce this if your printer can handle it
|
||||||
|
paper_margin: 0.2in
|
||||||
|
|
||||||
|
# Note: paper_size and paper_margin only apply to PDF generated with pdfkit.
|
||||||
|
# If you print (or generate a PDF) using ips.html, they will be ignored.
|
||||||
|
# (The equivalent parameters must be set from the browser's print dialog.)
|
||||||
|
|
||||||
|
# This can be "test" or "stable"
|
||||||
|
engine_version: stable
|
||||||
|
|
||||||
|
# These correspond to the version numbers visible on their respective GitHub release pages
|
||||||
|
compose_version: 1.21.1
|
||||||
|
machine_version: 0.14.0
|
||||||
|
|
||||||
|
# Password used to connect with the "docker user"
|
||||||
|
docker_user_password: training
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
clustersize: 3
|
clustersize: 3
|
||||||
|
|
||||||
# Jinja2 template to use to generate ready-to-cut cards
|
# Jinja2 template to use to generate ready-to-cut cards
|
||||||
cards_template: settings/kube101.html
|
cards_template: kube101.html
|
||||||
|
|
||||||
# Use "Letter" in the US, and "A4" everywhere else
|
# Use "Letter" in the US, and "A4" everywhere else
|
||||||
paper_size: Letter
|
paper_size: Letter
|
||||||
@@ -22,3 +22,6 @@ engine_version: stable
|
|||||||
# These correspond to the version numbers visible on their respective GitHub release pages
|
# These correspond to the version numbers visible on their respective GitHub release pages
|
||||||
compose_version: 1.21.1
|
compose_version: 1.21.1
|
||||||
machine_version: 0.14.0
|
machine_version: 0.14.0
|
||||||
|
|
||||||
|
# Password used to connect with the "docker user"
|
||||||
|
docker_user_password: training
|
||||||
@@ -20,5 +20,8 @@ paper_margin: 0.2in
|
|||||||
engine_version: stable
|
engine_version: stable
|
||||||
|
|
||||||
# These correspond to the version numbers visible on their respective GitHub release pages
|
# These correspond to the version numbers visible on their respective GitHub release pages
|
||||||
compose_version: 1.21.1
|
compose_version: 1.22.0
|
||||||
machine_version: 0.14.0
|
machine_version: 0.15.0
|
||||||
|
|
||||||
|
# Password used to connect with the "docker user"
|
||||||
|
docker_user_password: training
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ img {
|
|||||||
<tr><td>login:</td></tr>
|
<tr><td>login:</td></tr>
|
||||||
<tr><td class="logpass">docker</td></tr>
|
<tr><td class="logpass">docker</td></tr>
|
||||||
<tr><td>password:</td></tr>
|
<tr><td>password:</td></tr>
|
||||||
<tr><td class="logpass">training</td></tr>
|
<tr><td class="logpass">{{ docker_user_password }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
Can't render this file because it contains an unexpected character in line 1 and column 42.
|
117
prepare-vms/templates/enix.html
Normal file
117
prepare-vms/templates/enix.html
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
{# Feel free to customize or override anything in there! #}
|
||||||
|
{%- set url = "http://septembre2018.container.training" -%}
|
||||||
|
{%- set pagesize = 9 -%}
|
||||||
|
{%- if clustersize == 1 -%}
|
||||||
|
{%- set workshop_name = "Docker workshop" -%}
|
||||||
|
{%- set cluster_or_machine = "machine" -%}
|
||||||
|
{%- set this_or_each = "this" -%}
|
||||||
|
{%- set machine_is_or_machines_are = "machine is" -%}
|
||||||
|
{%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- set workshop_name = "Kubernetes workshop" -%}
|
||||||
|
{%- set cluster_or_machine = "cluster" -%}
|
||||||
|
{%- set this_or_each = "each" -%}
|
||||||
|
{%- set machine_is_or_machines_are = "machines are" -%}
|
||||||
|
{%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%}
|
||||||
|
{%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%}
|
||||||
|
{%- set image_src = image_src_kube -%}
|
||||||
|
{%- endif -%}
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html>
|
||||||
|
<head><style>
|
||||||
|
body, table {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1em;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-spacing: 0;
|
||||||
|
margin-top: 0.4em;
|
||||||
|
margin-bottom: 0.4em;
|
||||||
|
border-left: 0.8em double grey;
|
||||||
|
padding-left: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
float: left;
|
||||||
|
border: 1px dotted black;
|
||||||
|
padding-top: 1%;
|
||||||
|
padding-bottom: 1%;
|
||||||
|
/* columns * (width+left+right) < 100% */
|
||||||
|
width: 30%;
|
||||||
|
padding-left: 1.5%;
|
||||||
|
padding-right: 1.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0.4em 0 0.4em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 4em;
|
||||||
|
float: right;
|
||||||
|
margin-right: -0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.enix {
|
||||||
|
height: 4.5em;
|
||||||
|
margin-top: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.kube {
|
||||||
|
height: 4.2em;
|
||||||
|
margin-top: 1.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logpass {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagebreak {
|
||||||
|
page-break-after: always;
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
</style></head>
|
||||||
|
<body>
|
||||||
|
{% for cluster in clusters %}
|
||||||
|
{% if loop.index0>0 and loop.index0%pagesize==0 %}
|
||||||
|
<span class="pagebreak"></span>
|
||||||
|
{% endif %}
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Voici les informations permettant de se connecter à votre
|
||||||
|
cluster pour cette formation. Vous pouvez vous connecter
|
||||||
|
à ces machines virtuelles avec n'importe quel client SSH.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img class="enix" src="https://enix.io/static/img/logos/logo-domain-cropped.png" />
|
||||||
|
<table>
|
||||||
|
<tr><td>identifiant:</td></tr>
|
||||||
|
<tr><td class="logpass">docker</td></tr>
|
||||||
|
<tr><td>mot de passe:</td></tr>
|
||||||
|
<tr><td class="logpass">{{ docker_user_password }}</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Vos serveurs sont :
|
||||||
|
<img class="kube" src="{{ image_src }}" />
|
||||||
|
<table>
|
||||||
|
{% for node in cluster %}
|
||||||
|
<tr><td>node{{ loop.index }}:</td><td>{{ node }}</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
<p>Le support de formation est à l'adresse suivante :
|
||||||
|
<center>{{ url }}</center>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
131
prepare-vms/templates/jerome.html
Normal file
131
prepare-vms/templates/jerome.html
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
{# Feel free to customize or override anything in there! #}
|
||||||
|
{%- set url = "http://qconsf2018.container.training/" -%}
|
||||||
|
{%- set pagesize = 9 -%}
|
||||||
|
{%- if clustersize == 1 -%}
|
||||||
|
{%- set workshop_name = "Docker workshop" -%}
|
||||||
|
{%- set cluster_or_machine = "machine" -%}
|
||||||
|
{%- set this_or_each = "this" -%}
|
||||||
|
{%- set machine_is_or_machines_are = "machine is" -%}
|
||||||
|
{%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- set workshop_name = "Kubernetes workshop" -%}
|
||||||
|
{%- set cluster_or_machine = "cluster" -%}
|
||||||
|
{%- set this_or_each = "each" -%}
|
||||||
|
{%- set machine_is_or_machines_are = "machines are" -%}
|
||||||
|
{%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%}
|
||||||
|
{%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%}
|
||||||
|
{%- set image_src = image_src_kube -%}
|
||||||
|
{%- endif -%}
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html>
|
||||||
|
<head><style>
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Slabo+27px');
|
||||||
|
body, table {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1.0em;
|
||||||
|
font-size: 15px;
|
||||||
|
font-family: 'Slabo 27px';
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-spacing: 0;
|
||||||
|
margin-top: 0.4em;
|
||||||
|
margin-bottom: 0.4em;
|
||||||
|
border-left: 0.8em double grey;
|
||||||
|
padding-left: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
float: left;
|
||||||
|
border: 1px dotted black;
|
||||||
|
height: 31%;
|
||||||
|
padding-top: 1%;
|
||||||
|
padding-bottom: 1%;
|
||||||
|
/* columns * (width+left+right) < 100% */
|
||||||
|
width: 30%;
|
||||||
|
padding-left: 1.5%;
|
||||||
|
padding-right: 1.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.back {
|
||||||
|
border: 1px dotted white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.back p {
|
||||||
|
margin: 0.5em 1em 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0.4em 0 0.8em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 5em;
|
||||||
|
float: right;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logpass {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagebreak {
|
||||||
|
page-break-after: always;
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
</style></head>
|
||||||
|
<body>
|
||||||
|
{% for cluster in clusters %}
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Here is the connection information to your very own
|
||||||
|
{{ cluster_or_machine }} for this {{ workshop_name }}.
|
||||||
|
You can connect to {{ this_or_each }} VM with any SSH client.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="{{ image_src }}" />
|
||||||
|
<table>
|
||||||
|
<tr><td>login:</td></tr>
|
||||||
|
<tr><td class="logpass">docker</td></tr>
|
||||||
|
<tr><td>password:</td></tr>
|
||||||
|
<tr><td class="logpass">{{ docker_user_password }}</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Your {{ machine_is_or_machines_are }}:
|
||||||
|
<table>
|
||||||
|
{% for node in cluster %}
|
||||||
|
<tr><td>node{{ loop.index }}:</td><td>{{ node }}</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
<p>You can find the slides at:
|
||||||
|
<center>{{ url }}</center>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% if loop.index%pagesize==0 or loop.last %}
|
||||||
|
<span class="pagebreak"></span>
|
||||||
|
{% for x in range(pagesize) %}
|
||||||
|
<div class="back">
|
||||||
|
<br/>
|
||||||
|
<p>You got this card at the workshop "Getting Started With Kubernetes and Container Orchestration"
|
||||||
|
during QCON San Francisco (November 2018).</p>
|
||||||
|
<p>That workshop was a 1-day version of a longer curriculum.</p>
|
||||||
|
<p>If you liked that workshop, the instructor (Jérôme Petazzoni) can deliver it
|
||||||
|
(or the longer version) to your team or organization.</p>
|
||||||
|
<p>You can reach him at:</p>
|
||||||
|
<p>jerome.petazzoni@gmail.com</p>
|
||||||
|
<p>Thank you!</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
<span class="pagebreak"></span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -85,7 +85,7 @@ img {
|
|||||||
<tr><td>login:</td></tr>
|
<tr><td>login:</td></tr>
|
||||||
<tr><td class="logpass">docker</td></tr>
|
<tr><td class="logpass">docker</td></tr>
|
||||||
<tr><td>password:</td></tr>
|
<tr><td>password:</td></tr>
|
||||||
<tr><td class="logpass">training</td></tr>
|
<tr><td class="logpass">{{ docker_user_password }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
5
prepare-vms/terraform/keypair.tf
Normal file
5
prepare-vms/terraform/keypair.tf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
resource "openstack_compute_keypair_v2" "ssh_deploy_key" {
|
||||||
|
name = "${var.prefix}"
|
||||||
|
public_key = "${file("~/.ssh/id_rsa.pub")}"
|
||||||
|
}
|
||||||
|
|
||||||
32
prepare-vms/terraform/machines.tf
Normal file
32
prepare-vms/terraform/machines.tf
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
resource "openstack_compute_instance_v2" "machine" {
|
||||||
|
count = "${var.count}"
|
||||||
|
name = "${format("%s-%04d", "${var.prefix}", count.index+1)}"
|
||||||
|
image_name = "Ubuntu 16.04.5 (Xenial Xerus)"
|
||||||
|
flavor_name = "${var.flavor}"
|
||||||
|
security_groups = ["${openstack_networking_secgroup_v2.full_access.name}"]
|
||||||
|
key_pair = "${openstack_compute_keypair_v2.ssh_deploy_key.name}"
|
||||||
|
|
||||||
|
network {
|
||||||
|
name = "${openstack_networking_network_v2.internal.name}"
|
||||||
|
fixed_ip_v4 = "${cidrhost("${openstack_networking_subnet_v2.internal.cidr}", count.index+10)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "openstack_compute_floatingip_v2" "machine" {
|
||||||
|
count = "${var.count}"
|
||||||
|
# This is something provided to us by Enix when our tenant was provisioned.
|
||||||
|
pool = "Public Floating"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "openstack_compute_floatingip_associate_v2" "machine" {
|
||||||
|
count = "${var.count}"
|
||||||
|
floating_ip = "${openstack_compute_floatingip_v2.machine.*.address[count.index]}"
|
||||||
|
instance_id = "${openstack_compute_instance_v2.machine.*.id[count.index]}"
|
||||||
|
fixed_ip = "${cidrhost("${openstack_networking_subnet_v2.internal.cidr}", count.index+10)}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "ip_addresses" {
|
||||||
|
value = "${join("\n", openstack_compute_floatingip_v2.machine.*.address)}"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "flavor" {}
|
||||||
23
prepare-vms/terraform/network.tf
Normal file
23
prepare-vms/terraform/network.tf
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
resource "openstack_networking_network_v2" "internal" {
|
||||||
|
name = "${var.prefix}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "openstack_networking_subnet_v2" "internal" {
|
||||||
|
name = "${var.prefix}"
|
||||||
|
network_id = "${openstack_networking_network_v2.internal.id}"
|
||||||
|
cidr = "10.10.0.0/16"
|
||||||
|
ip_version = 4
|
||||||
|
dns_nameservers = ["1.1.1.1"]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "openstack_networking_router_v2" "router" {
|
||||||
|
name = "${var.prefix}"
|
||||||
|
external_network_id = "15f0c299-1f50-42a6-9aff-63ea5b75f3fc"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "openstack_networking_router_interface_v2" "router_internal" {
|
||||||
|
router_id = "${openstack_networking_router_v2.router.id}"
|
||||||
|
subnet_id = "${openstack_networking_subnet_v2.internal.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
13
prepare-vms/terraform/provider.tf
Normal file
13
prepare-vms/terraform/provider.tf
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
provider "openstack" {
|
||||||
|
user_name = "${var.user}"
|
||||||
|
tenant_name = "${var.tenant}"
|
||||||
|
domain_name = "${var.domain}"
|
||||||
|
password = "${var.password}"
|
||||||
|
auth_url = "${var.auth_url}"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "user" {}
|
||||||
|
variable "tenant" {}
|
||||||
|
variable "domain" {}
|
||||||
|
variable "password" {}
|
||||||
|
variable "auth_url" {}
|
||||||
12
prepare-vms/terraform/secgroup.tf
Normal file
12
prepare-vms/terraform/secgroup.tf
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
resource "openstack_networking_secgroup_v2" "full_access" {
|
||||||
|
name = "${var.prefix} - full access"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "openstack_networking_secgroup_rule_v2" "full_access" {
|
||||||
|
direction = "ingress"
|
||||||
|
ethertype = "IPv4"
|
||||||
|
protocol = ""
|
||||||
|
remote_ip_prefix = "0.0.0.0/0"
|
||||||
|
security_group_id = "${openstack_networking_secgroup_v2.full_access.id}"
|
||||||
|
}
|
||||||
|
|
||||||
8
prepare-vms/terraform/vars.tf
Normal file
8
prepare-vms/terraform/vars.tf
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
variable "prefix" {
|
||||||
|
type = "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "count" {
|
||||||
|
type = "string"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,20 +1,19 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Get the script's real directory, whether we're being called directly or via a symlink
|
# Get the script's real directory.
|
||||||
|
# This should work whether we're being called directly or via a symlink.
|
||||||
if [ -L "$0" ]; then
|
if [ -L "$0" ]; then
|
||||||
export SCRIPT_DIR=$(dirname $(readlink "$0"))
|
export SCRIPT_DIR=$(dirname $(readlink "$0"))
|
||||||
else
|
else
|
||||||
export SCRIPT_DIR=$(dirname "$0")
|
export SCRIPT_DIR=$(dirname "$0")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Load all scriptlets
|
# Load all scriptlets.
|
||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
for lib in lib/*.sh; do
|
for lib in lib/*.sh; do
|
||||||
. $lib
|
. $lib
|
||||||
done
|
done
|
||||||
|
|
||||||
TRAINER_IMAGE="preparevms_prepare-vms"
|
|
||||||
|
|
||||||
DEPENDENCIES="
|
DEPENDENCIES="
|
||||||
aws
|
aws
|
||||||
ssh
|
ssh
|
||||||
@@ -25,49 +24,26 @@ DEPENDENCIES="
|
|||||||
man
|
man
|
||||||
"
|
"
|
||||||
|
|
||||||
ENVVARS="
|
# Check for missing dependencies, and issue a warning if necessary.
|
||||||
AWS_ACCESS_KEY_ID
|
missing=0
|
||||||
AWS_SECRET_ACCESS_KEY
|
for dependency in $DEPENDENCIES; do
|
||||||
AWS_DEFAULT_REGION
|
if ! command -v $dependency >/dev/null; then
|
||||||
SSH_AUTH_SOCK
|
warning "Dependency $dependency could not be found."
|
||||||
"
|
missing=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $missing = 1 ]; then
|
||||||
|
warning "At least one dependency is missing. Install it or try the image wrapper."
|
||||||
|
fi
|
||||||
|
|
||||||
check_envvars() {
|
# Check if SSH_AUTH_SOCK is set.
|
||||||
status=0
|
# (If it's not, deployment will almost certainly fail.)
|
||||||
for envvar in $ENVVARS; do
|
if [ -z "${SSH_AUTH_SOCK}" ]; then
|
||||||
if [ -z "${!envvar}" ]; then
|
warning "Environment variable SSH_AUTH_SOCK is not set."
|
||||||
error "Environment variable $envvar is not set."
|
warning "Hint: run 'eval \$(ssh-agent) ; ssh-add' and try again?"
|
||||||
if [ "$envvar" = "SSH_AUTH_SOCK" ]; then
|
fi
|
||||||
error "Hint: run 'eval \$(ssh-agent) ; ssh-add' and try again?"
|
|
||||||
fi
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return $status
|
|
||||||
}
|
|
||||||
|
|
||||||
check_dependencies() {
|
# Now check which command was invoked and execute it.
|
||||||
status=0
|
|
||||||
for dependency in $DEPENDENCIES; do
|
|
||||||
if ! command -v $dependency >/dev/null; then
|
|
||||||
warning "Dependency $dependency could not be found."
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return $status
|
|
||||||
}
|
|
||||||
|
|
||||||
check_image() {
|
|
||||||
docker inspect $TRAINER_IMAGE >/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
check_envvars \
|
|
||||||
|| die "Please set all required environment variables."
|
|
||||||
|
|
||||||
check_dependencies \
|
|
||||||
|| warning "At least one dependency is missing. Install it or try the image wrapper."
|
|
||||||
|
|
||||||
# Now check which command was invoked and execute it
|
|
||||||
if [ "$1" ]; then
|
if [ "$1" ]; then
|
||||||
cmd="$1"
|
cmd="$1"
|
||||||
shift
|
shift
|
||||||
@@ -77,6 +53,3 @@ fi
|
|||||||
fun=_cmd_$cmd
|
fun=_cmd_$cmd
|
||||||
type -t $fun | grep -q function || die "Invalid command: $cmd"
|
type -t $fun | grep -q function || die "Invalid command: $cmd"
|
||||||
$fun "$@"
|
$fun "$@"
|
||||||
|
|
||||||
# export SSH_AUTH_DIRNAME=$(dirname $SSH_AUTH_SOCK)
|
|
||||||
# docker-compose run prepare-vms "$@"
|
|
||||||
|
|||||||
1
slides/_redirects
Normal file
1
slides/_redirects
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/ /kube-fullday.yml.html 200!
|
||||||
@@ -29,6 +29,10 @@ class State(object):
|
|||||||
self.interactive = True
|
self.interactive = True
|
||||||
self.verify_status = False
|
self.verify_status = False
|
||||||
self.simulate_type = True
|
self.simulate_type = True
|
||||||
|
self.switch_desktop = False
|
||||||
|
self.sync_slides = False
|
||||||
|
self.open_links = False
|
||||||
|
self.run_hidden = True
|
||||||
self.slide = 1
|
self.slide = 1
|
||||||
self.snippet = 0
|
self.snippet = 0
|
||||||
|
|
||||||
@@ -37,6 +41,10 @@ class State(object):
|
|||||||
self.interactive = bool(data["interactive"])
|
self.interactive = bool(data["interactive"])
|
||||||
self.verify_status = bool(data["verify_status"])
|
self.verify_status = bool(data["verify_status"])
|
||||||
self.simulate_type = bool(data["simulate_type"])
|
self.simulate_type = bool(data["simulate_type"])
|
||||||
|
self.switch_desktop = bool(data["switch_desktop"])
|
||||||
|
self.sync_slides = bool(data["sync_slides"])
|
||||||
|
self.open_links = bool(data["open_links"])
|
||||||
|
self.run_hidden = bool(data["run_hidden"])
|
||||||
self.slide = int(data["slide"])
|
self.slide = int(data["slide"])
|
||||||
self.snippet = int(data["snippet"])
|
self.snippet = int(data["snippet"])
|
||||||
|
|
||||||
@@ -46,6 +54,10 @@ class State(object):
|
|||||||
interactive=self.interactive,
|
interactive=self.interactive,
|
||||||
verify_status=self.verify_status,
|
verify_status=self.verify_status,
|
||||||
simulate_type=self.simulate_type,
|
simulate_type=self.simulate_type,
|
||||||
|
switch_desktop=self.switch_desktop,
|
||||||
|
sync_slides=self.sync_slides,
|
||||||
|
open_links=self.open_links,
|
||||||
|
run_hidden=self.run_hidden,
|
||||||
slide=self.slide,
|
slide=self.slide,
|
||||||
snippet=self.snippet,
|
snippet=self.snippet,
|
||||||
), f, default_flow_style=False)
|
), f, default_flow_style=False)
|
||||||
@@ -122,14 +134,20 @@ class Slide(object):
|
|||||||
|
|
||||||
|
|
||||||
def focus_slides():
|
def focus_slides():
|
||||||
|
if not state.switch_desktop:
|
||||||
|
return
|
||||||
subprocess.check_output(["i3-msg", "workspace", "3"])
|
subprocess.check_output(["i3-msg", "workspace", "3"])
|
||||||
subprocess.check_output(["i3-msg", "workspace", "1"])
|
subprocess.check_output(["i3-msg", "workspace", "1"])
|
||||||
|
|
||||||
def focus_terminal():
|
def focus_terminal():
|
||||||
|
if not state.switch_desktop:
|
||||||
|
return
|
||||||
subprocess.check_output(["i3-msg", "workspace", "2"])
|
subprocess.check_output(["i3-msg", "workspace", "2"])
|
||||||
subprocess.check_output(["i3-msg", "workspace", "1"])
|
subprocess.check_output(["i3-msg", "workspace", "1"])
|
||||||
|
|
||||||
def focus_browser():
|
def focus_browser():
|
||||||
|
if not state.switch_desktop:
|
||||||
|
return
|
||||||
subprocess.check_output(["i3-msg", "workspace", "4"])
|
subprocess.check_output(["i3-msg", "workspace", "4"])
|
||||||
subprocess.check_output(["i3-msg", "workspace", "1"])
|
subprocess.check_output(["i3-msg", "workspace", "1"])
|
||||||
|
|
||||||
@@ -205,7 +223,7 @@ def check_exit_status():
|
|||||||
def setup_tmux_and_ssh():
|
def setup_tmux_and_ssh():
|
||||||
if subprocess.call(["tmux", "has-session"]):
|
if subprocess.call(["tmux", "has-session"]):
|
||||||
logging.error("Couldn't connect to tmux. Please setup tmux first.")
|
logging.error("Couldn't connect to tmux. Please setup tmux first.")
|
||||||
ipaddr = open("../../prepare-vms/ips.txt").read().split("\n")[0]
|
ipaddr = "$IPADDR"
|
||||||
uid = os.getuid()
|
uid = os.getuid()
|
||||||
|
|
||||||
raise Exception("""
|
raise Exception("""
|
||||||
@@ -307,17 +325,21 @@ while True:
|
|||||||
slide = slides[state.slide]
|
slide = slides[state.slide]
|
||||||
snippet = slide.snippets[state.snippet-1] if state.snippet else None
|
snippet = slide.snippets[state.snippet-1] if state.snippet else None
|
||||||
click.clear()
|
click.clear()
|
||||||
print("[Slide {}/{}] [Snippet {}/{}] [simulate_type:{}] [verify_status:{}]"
|
print("[Slide {}/{}] [Snippet {}/{}] [simulate_type:{}] [verify_status:{}] "
|
||||||
|
"[switch_desktop:{}] [sync_slides:{}] [open_links:{}] [run_hidden:{}]"
|
||||||
.format(state.slide, len(slides)-1,
|
.format(state.slide, len(slides)-1,
|
||||||
state.snippet, len(slide.snippets) if slide.snippets else 0,
|
state.snippet, len(slide.snippets) if slide.snippets else 0,
|
||||||
state.simulate_type, state.verify_status))
|
state.simulate_type, state.verify_status,
|
||||||
|
state.switch_desktop, state.sync_slides,
|
||||||
|
state.open_links, state.run_hidden))
|
||||||
print(hrule())
|
print(hrule())
|
||||||
if snippet:
|
if snippet:
|
||||||
print(slide.content.replace(snippet.content, ansi(7)(snippet.content)))
|
print(slide.content.replace(snippet.content, ansi(7)(snippet.content)))
|
||||||
focus_terminal()
|
focus_terminal()
|
||||||
else:
|
else:
|
||||||
print(slide.content)
|
print(slide.content)
|
||||||
subprocess.check_output(["./gotoslide.js", str(slide.number)])
|
if state.sync_slides:
|
||||||
|
subprocess.check_output(["./gotoslide.js", str(slide.number)])
|
||||||
focus_slides()
|
focus_slides()
|
||||||
print(hrule())
|
print(hrule())
|
||||||
if state.interactive:
|
if state.interactive:
|
||||||
@@ -326,6 +348,10 @@ while True:
|
|||||||
print("n/→ Next")
|
print("n/→ Next")
|
||||||
print("s Simulate keystrokes")
|
print("s Simulate keystrokes")
|
||||||
print("v Validate exit status")
|
print("v Validate exit status")
|
||||||
|
print("d Switch desktop")
|
||||||
|
print("k Sync slides")
|
||||||
|
print("o Open links")
|
||||||
|
print("h Run hidden commands")
|
||||||
print("g Go to a specific slide")
|
print("g Go to a specific slide")
|
||||||
print("q Quit")
|
print("q Quit")
|
||||||
print("c Continue non-interactively until next error")
|
print("c Continue non-interactively until next error")
|
||||||
@@ -341,6 +367,14 @@ while True:
|
|||||||
state.simulate_type = not state.simulate_type
|
state.simulate_type = not state.simulate_type
|
||||||
elif command == "v":
|
elif command == "v":
|
||||||
state.verify_status = not state.verify_status
|
state.verify_status = not state.verify_status
|
||||||
|
elif command == "d":
|
||||||
|
state.switch_desktop = not state.switch_desktop
|
||||||
|
elif command == "k":
|
||||||
|
state.sync_slides = not state.sync_slides
|
||||||
|
elif command == "o":
|
||||||
|
state.open_links = not state.open_links
|
||||||
|
elif command == "h":
|
||||||
|
state.run_hidden = not state.run_hidden
|
||||||
elif command == "g":
|
elif command == "g":
|
||||||
state.slide = click.prompt("Enter slide number", type=int)
|
state.slide = click.prompt("Enter slide number", type=int)
|
||||||
state.snippet = 0
|
state.snippet = 0
|
||||||
@@ -366,7 +400,7 @@ while True:
|
|||||||
logging.info("Running with method {}: {}".format(method, data))
|
logging.info("Running with method {}: {}".format(method, data))
|
||||||
if method == "keys":
|
if method == "keys":
|
||||||
send_keys(data)
|
send_keys(data)
|
||||||
elif method == "bash":
|
elif method == "bash" or (method == "hide" and state.run_hidden):
|
||||||
# Make sure that we're ready
|
# Make sure that we're ready
|
||||||
wait_for_prompt()
|
wait_for_prompt()
|
||||||
# Strip leading spaces
|
# Strip leading spaces
|
||||||
@@ -405,11 +439,12 @@ while True:
|
|||||||
screen = capture_pane()
|
screen = capture_pane()
|
||||||
url = data.replace("/node1", "/{}".format(IPADDR))
|
url = data.replace("/node1", "/{}".format(IPADDR))
|
||||||
# This should probably be adapted to run on different OS
|
# This should probably be adapted to run on different OS
|
||||||
subprocess.check_output(["xdg-open", url])
|
if state.open_links:
|
||||||
focus_browser()
|
subprocess.check_output(["xdg-open", url])
|
||||||
if state.interactive:
|
focus_browser()
|
||||||
print("Press any key to continue to next step...")
|
if state.interactive:
|
||||||
click.getchar()
|
print("Press any key to continue to next step...")
|
||||||
|
click.getchar()
|
||||||
else:
|
else:
|
||||||
logging.warning("Unknown method {}: {!r}".format(method, data))
|
logging.warning("Unknown method {}: {!r}".format(method, data))
|
||||||
move_forward()
|
move_forward()
|
||||||
|
|||||||
1
slides/autopilot/requirements.txt
Normal file
1
slides/autopilot/requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
click
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
class: title, self-paced
|
|
||||||
|
|
||||||
Thank you!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
class: title, in-person
|
|
||||||
|
|
||||||
That's all, folks! <br/> Questions?
|
|
||||||
|
|
||||||

|
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
|
||||||
|
class: title
|
||||||
|
|
||||||
# Advanced Dockerfiles
|
# Advanced Dockerfiles
|
||||||
|
|
||||||

|

|
||||||
@@ -107,9 +107,17 @@ class: pic
|
|||||||
|
|
||||||
class: pic
|
class: pic
|
||||||
|
|
||||||
|
## Two containers on a single Docker network
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
class: pic
|
||||||
|
|
||||||
## Two containers on two Docker networks
|
## Two containers on two Docker networks
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ CMD gunicorn --bind 0.0.0.0:5000 --workers 10 counter:app
|
|||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
```
|
```
|
||||||
|
|
||||||
(Source: [traininghweels Dockerfile](https://github.com/jpetazzo/trainingwheels/blob/master/www/Dockerfile))
|
(Source: [trainingwheels Dockerfile](https://github.com/jpetazzo/trainingwheels/blob/master/www/Dockerfile))
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
class: title
|
class: title
|
||||||
|
|
||||||
# Getting inside a container
|
# Getting inside a container
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
class: title
|
class: title
|
||||||
|
|
||||||
# Installing Docker
|
# Installing Docker
|
||||||
@@ -309,54 +309,6 @@ and *canary deployments*.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Improving the workflow
|
|
||||||
|
|
||||||
The workflow that we showed is nice, but it requires us to:
|
|
||||||
|
|
||||||
* keep track of all the `docker run` flags required to run the container,
|
|
||||||
|
|
||||||
* inspect the `Dockerfile` to know which path(s) to mount,
|
|
||||||
|
|
||||||
* write scripts to hide that complexity.
|
|
||||||
|
|
||||||
There has to be a better way!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Docker Compose to the rescue
|
|
||||||
|
|
||||||
* Docker Compose allows us to "encode" `docker run` parameters in a YAML file.
|
|
||||||
|
|
||||||
* Here is the `docker-compose.yml` file that we can use for our "namer" app:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
www:
|
|
||||||
build: .
|
|
||||||
volumes:
|
|
||||||
- .:/src
|
|
||||||
ports:
|
|
||||||
- 80:9292
|
|
||||||
```
|
|
||||||
|
|
||||||
* Try it:
|
|
||||||
```bash
|
|
||||||
$ docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Working with Docker Compose
|
|
||||||
|
|
||||||
* When you see a `docker-compose.yml` file, you can use `docker-compose up`.
|
|
||||||
|
|
||||||
* It can build images and run them with the required parameters.
|
|
||||||
|
|
||||||
* Compose can also deal with complex, multi-container apps.
|
|
||||||
|
|
||||||
(More on this later!)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recap of the development workflow
|
## Recap of the development workflow
|
||||||
|
|
||||||
1. Write a Dockerfile to build an image containing our development environment.
|
1. Write a Dockerfile to build an image containing our development environment.
|
||||||
@@ -24,7 +24,7 @@ Analogy: attaching to a container is like plugging a keyboard and screen to a ph
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Detaching from a container
|
## Detaching from a container (Linux/macOS)
|
||||||
|
|
||||||
* If you have started an *interactive* container (with option `-it`), you can detach from it.
|
* If you have started an *interactive* container (with option `-it`), you can detach from it.
|
||||||
|
|
||||||
@@ -41,6 +41,20 @@ What does `-it` stand for?
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Detaching cont. (Win PowerShell and cmd.exe)
|
||||||
|
|
||||||
|
* Docker for Windows has a different detach experience due to shell features.
|
||||||
|
|
||||||
|
* `^P^Q` does not work.
|
||||||
|
|
||||||
|
* `^C` will detach, rather than stop the container.
|
||||||
|
|
||||||
|
* Using Bash, Subsystem for Linux, etc. on Windows behaves like Linux/macOS shells.
|
||||||
|
|
||||||
|
* Both PowerShell and Bash work well in Win 10; just be aware of differences.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
class: extra-details
|
class: extra-details
|
||||||
|
|
||||||
## Specifying a custom detach sequence
|
## Specifying a custom detach sequence
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
class: title
|
class: title
|
||||||
|
|
||||||
# Our training environment
|
# Our training environment
|
||||||
164
slides/containers/Windows_Containers.md
Normal file
164
slides/containers/Windows_Containers.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
class: title
|
||||||
|
|
||||||
|
# Windows Containers
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objectives
|
||||||
|
|
||||||
|
At the end of this section, you will be able to:
|
||||||
|
|
||||||
|
* Understand Windows Container vs. Linux Container.
|
||||||
|
|
||||||
|
* Know about the features of Docker for Windows for choosing architecture.
|
||||||
|
|
||||||
|
* Run other container architectures via QEMU emulation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Are containers *just* for Linux?
|
||||||
|
|
||||||
|
Remember that a container must run on the kernel of the OS it's on.
|
||||||
|
|
||||||
|
- This is both a benefit and a limitation.
|
||||||
|
|
||||||
|
(It makes containers lightweight, but limits them to a specific kernel.)
|
||||||
|
|
||||||
|
- At its launch in 2013, Docker did only support Linux, and only on amd64 CPUs.
|
||||||
|
|
||||||
|
- Since then, many platforms and OS have been added.
|
||||||
|
|
||||||
|
(Windows, ARM, i386, IBM mainframes ... But no macOS or iOS yet!)
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
- Docker Desktop (macOS and Windows) can run containers for other architectures
|
||||||
|
|
||||||
|
(Check the docs to see how to [run a Raspberry Pi (ARM) or PPC container](https://docs.docker.com/docker-for-mac/multi-arch/)!)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## History of Windows containers
|
||||||
|
|
||||||
|
- Early 2016, Windows 10 gained support for running Windows binaries in containers.
|
||||||
|
|
||||||
|
- These are known as "Windows Containers"
|
||||||
|
|
||||||
|
- Win 10 expects Docker for Windows to be installed for full features
|
||||||
|
|
||||||
|
- These must run in Hyper-V mini-VM's with a Windows Server x64 kernel
|
||||||
|
|
||||||
|
- No "scratch" containers, so use "Core" and "Nano" Server OS base layers
|
||||||
|
|
||||||
|
- Since Hyper-V is required, Windows 10 Home won't work (yet...)
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
- Late 2016, Windows Server 2016 ships with native Docker support
|
||||||
|
|
||||||
|
- Installed via PowerShell, doesn't need Docker for Windows
|
||||||
|
|
||||||
|
- Can run native (without VM), or with [Hyper-V Isolation](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/hyperv-container)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LCOW (Linux Containers On Windows)
|
||||||
|
|
||||||
|
While Docker on Windows is largely playing catch up with Docker on Linux,
|
||||||
|
it's moving fast; and this is one thing that you *cannot* do on Linux!
|
||||||
|
|
||||||
|
- LCOW came with the [2017 Fall Creators Update](https://blog.docker.com/2018/02/docker-for-windows-18-02-with-windows-10-fall-creators-update/).
|
||||||
|
|
||||||
|
- It can run Linux and Windows containers side-by-side on Win 10.
|
||||||
|
|
||||||
|
- It is no longer necessary to switch the Engine to "Linux Containers".
|
||||||
|
|
||||||
|
(In fact, if you want to run both Linux and Windows containers at the same time,
|
||||||
|
make sure that your Engine is set to "Windows Containers" mode!)
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
If you are a Docker for Windows user, start your engine and try this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker pull microsoft/nanoserver:1803
|
||||||
|
```
|
||||||
|
|
||||||
|
(Make sure to switch to "Windows Containers mode" if necessary.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Run Both Windows and Linux containers
|
||||||
|
|
||||||
|
- Run a Windows Nano Server (minimal CLI-only server)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -it microsoft/nanoserver:1803 powershell
|
||||||
|
Get-Process
|
||||||
|
exit
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run busybox on Linux in LCOW
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm --platform linux busybox echo hello
|
||||||
|
```
|
||||||
|
|
||||||
|
(Although you will not be able to see them, this will create hidden
|
||||||
|
Nano and LinuxKit VMs in Hyper-V!)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Did We Say Things Move Fast
|
||||||
|
|
||||||
|
- Things keep improving.
|
||||||
|
|
||||||
|
- Now `--platform` defaults to `windows`, some images support both:
|
||||||
|
|
||||||
|
- golang, mongo, python, redis, hello-world ... and more being added
|
||||||
|
|
||||||
|
- you should still use `--plaform` with multi-os images to be certain
|
||||||
|
|
||||||
|
- Windows Containers now support `localhost` accessable containers (July 2018)
|
||||||
|
|
||||||
|
- Microsoft (April 2018) added Hyper-V support to Windows 10 Home ...
|
||||||
|
|
||||||
|
... so stay tuned for Docker support, maybe?!?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Other Windows container options
|
||||||
|
|
||||||
|
Most "official" Docker images don't run on Windows yet.
|
||||||
|
|
||||||
|
Places to Look:
|
||||||
|
|
||||||
|
- Hub Official: https://hub.docker.com/u/winamd64/
|
||||||
|
|
||||||
|
- Microsoft: https://hub.docker.com/r/microsoft/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SQL Server? Choice of Linux or Windows
|
||||||
|
|
||||||
|
- Microsoft [SQL Server for Linux 2017](https://hub.docker.com/r/microsoft/mssql-server-linux/) (amd64/linux)
|
||||||
|
|
||||||
|
- Microsoft [SQL Server Express 2017](https://hub.docker.com/r/microsoft/mssql-server-windows-express/) (amd64/windows)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Windows Tools and Tips
|
||||||
|
|
||||||
|
- PowerShell [Tab Completion: DockerCompletion](https://github.com/matt9ucci/DockerCompletion)
|
||||||
|
|
||||||
|
- Best Shell GUI: [Cmder.net](http://cmder.net/)
|
||||||
|
|
||||||
|
- Good Windows Container Blogs and How-To's
|
||||||
|
|
||||||
|
- Dockers DevRel [Elton Stoneman, Microsoft MVP](https://blog.sixeyed.com/)
|
||||||
|
|
||||||
|
- Docker Captian [Nicholas Dille](https://dille.name/blog/)
|
||||||
|
|
||||||
|
- Docker Captain [Stefan Scherer](https://stefanscherer.github.io/)
|
||||||
@@ -51,7 +51,7 @@ for line in open(sys.argv[1]):
|
|||||||
|
|
||||||
state.show()
|
state.show()
|
||||||
|
|
||||||
for chapter in sorted(state.chapters):
|
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])
|
chapter_size = sum(state.sections[s] for s in state.chapters[chapter])
|
||||||
print("{}\t{}\t{}".format("total size for", chapter, chapter_size))
|
print("{}\t{}\t{}".format("total size for", chapter, chapter_size))
|
||||||
|
|
||||||
|
|||||||
BIN
slides/images/bridge1.png
Normal file → Executable file
BIN
slides/images/bridge1.png
Normal file → Executable file
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 97 KiB |
BIN
slides/images/bridge2.png
Normal file → Executable file
BIN
slides/images/bridge2.png
Normal file → Executable file
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 119 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user