diff --git a/k8s/insecure-dashboard.yaml b/k8s/insecure-dashboard.yaml
index ebf49362..373ec001 100644
--- a/k8s/insecure-dashboard.yaml
+++ b/k8s/insecure-dashboard.yaml
@@ -1,3 +1,10 @@
+# This file is based on the following manifest:
+# https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml
+# It adds the "skip login" flag, as well as an insecure hack to defeat SSL.
+# As its name implies, it is INSECURE and you should not use it in production,
+# or on clusters that contain any kind of important or sensitive data, or on
+# clusters that have a life span of more than a few hours.
+
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -187,7 +194,7 @@ spec:
spec:
containers:
- name: kubernetes-dashboard
- image: kubernetesui/dashboard:v2.0.0-rc2
+ image: kubernetesui/dashboard:v2.0.0
imagePullPolicy: Always
ports:
- containerPort: 8443
@@ -226,7 +233,7 @@ spec:
emptyDir: {}
serviceAccountName: kubernetes-dashboard
nodeSelector:
- "beta.kubernetes.io/os": linux
+ "kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
@@ -272,7 +279,7 @@ spec:
spec:
containers:
- name: dashboard-metrics-scraper
- image: kubernetesui/metrics-scraper:v1.0.2
+ image: kubernetesui/metrics-scraper:v1.0.4
ports:
- containerPort: 8000
protocol: TCP
@@ -293,7 +300,7 @@ spec:
runAsGroup: 2001
serviceAccountName: kubernetes-dashboard
nodeSelector:
- "beta.kubernetes.io/os": linux
+ "kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
diff --git a/k8s/kubernetes-dashboard.yaml b/k8s/kubernetes-dashboard.yaml
index ee6977bf..b2e5802b 100644
--- a/k8s/kubernetes-dashboard.yaml
+++ b/k8s/kubernetes-dashboard.yaml
@@ -1,3 +1,6 @@
+# This is a copy of the following file:
+# https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml
+
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,19 +15,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# ------------------- Dashboard Secret ------------------- #
-
apiVersion: v1
-kind: Secret
+kind: Namespace
metadata:
- labels:
- k8s-app: kubernetes-dashboard
- name: kubernetes-dashboard-certs
- namespace: kube-system
-type: Opaque
+ name: kubernetes-dashboard
---
-# ------------------- Dashboard Service Account ------------------- #
apiVersion: v1
kind: ServiceAccount
@@ -32,62 +28,147 @@ metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
- namespace: kube-system
+ namespace: kubernetes-dashboard
+
+---
+
+kind: Service
+apiVersion: v1
+metadata:
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard
+ namespace: kubernetes-dashboard
+spec:
+ ports:
+ - port: 443
+ targetPort: 8443
+ selector:
+ k8s-app: kubernetes-dashboard
+
+---
+
+apiVersion: v1
+kind: Secret
+metadata:
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard-certs
+ namespace: kubernetes-dashboard
+type: Opaque
+
+---
+
+apiVersion: v1
+kind: Secret
+metadata:
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard-csrf
+ namespace: kubernetes-dashboard
+type: Opaque
+data:
+ csrf: ""
+
+---
+
+apiVersion: v1
+kind: Secret
+metadata:
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard-key-holder
+ namespace: kubernetes-dashboard
+type: Opaque
+
+---
+
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard-settings
+ namespace: kubernetes-dashboard
---
-# ------------------- Dashboard Role & Role Binding ------------------- #
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
- name: kubernetes-dashboard-minimal
- namespace: kube-system
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard
+ namespace: kubernetes-dashboard
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"]
+ - apiGroups: [""]
+ resources: ["secrets"]
+ resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
+ verbs: ["get", "update", "delete"]
+ # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
+ - apiGroups: [""]
+ resources: ["configmaps"]
+ resourceNames: ["kubernetes-dashboard-settings"]
+ verbs: ["get", "update"]
+ # Allow Dashboard to get metrics.
+ - apiGroups: [""]
+ resources: ["services"]
+ resourceNames: ["heapster", "dashboard-metrics-scraper"]
+ verbs: ["proxy"]
+ - apiGroups: [""]
+ resources: ["services/proxy"]
+ resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
+ verbs: ["get"]
---
+
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard
+rules:
+ # Allow Metrics Scraper to get metrics from the Metrics server
+ - apiGroups: ["metrics.k8s.io"]
+ resources: ["pods", "nodes"]
+ verbs: ["get", "list", "watch"]
+
+---
+
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
- name: kubernetes-dashboard-minimal
- namespace: kube-system
+ labels:
+ k8s-app: kubernetes-dashboard
+ name: kubernetes-dashboard
+ namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
- name: kubernetes-dashboard-minimal
-subjects:
-- kind: ServiceAccount
name: kubernetes-dashboard
- namespace: kube-system
+subjects:
+ - kind: ServiceAccount
+ name: kubernetes-dashboard
+ namespace: kubernetes-dashboard
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: kubernetes-dashboard
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: kubernetes-dashboard
+subjects:
+ - kind: ServiceAccount
+ name: kubernetes-dashboard
+ namespace: kubernetes-dashboard
---
-# ------------------- Dashboard Deployment ------------------- #
kind: Deployment
apiVersion: apps/v1
@@ -95,7 +176,7 @@ metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
- namespace: kube-system
+ namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
@@ -108,55 +189,117 @@ spec:
k8s-app: kubernetes-dashboard
spec:
containers:
- - name: kubernetes-dashboard
- image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1
- ports:
- - containerPort: 8443
- protocol: TCP
- args:
- - --auto-generate-certificates
- # Uncomment the following line to manually specify Kubernetes API server Host
- # If not specified, Dashboard will attempt to auto discover the API server and connect
- # to it. Uncomment only if the default does not work.
- # - --apiserver-host=http://my-address:port
- volumeMounts:
- - name: kubernetes-dashboard-certs
- mountPath: /certs
- # Create on-disk volume to store exec logs
- - mountPath: /tmp
- name: tmp-volume
- livenessProbe:
- httpGet:
- scheme: HTTPS
- path: /
- port: 8443
- initialDelaySeconds: 30
- timeoutSeconds: 30
+ - name: kubernetes-dashboard
+ image: kubernetesui/dashboard:v2.0.0
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 8443
+ protocol: TCP
+ args:
+ - --auto-generate-certificates
+ - --namespace=kubernetes-dashboard
+ # Uncomment the following line to manually specify Kubernetes API server Host
+ # If not specified, Dashboard will attempt to auto discover the API server and connect
+ # to it. Uncomment only if the default does not work.
+ # - --apiserver-host=http://my-address:port
+ volumeMounts:
+ - name: kubernetes-dashboard-certs
+ mountPath: /certs
+ # Create on-disk volume to store exec logs
+ - mountPath: /tmp
+ name: tmp-volume
+ livenessProbe:
+ httpGet:
+ scheme: HTTPS
+ path: /
+ port: 8443
+ initialDelaySeconds: 30
+ timeoutSeconds: 30
+ securityContext:
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: true
+ runAsUser: 1001
+ runAsGroup: 2001
volumes:
- - name: kubernetes-dashboard-certs
- secret:
- secretName: kubernetes-dashboard-certs
- - name: tmp-volume
- emptyDir: {}
+ - name: kubernetes-dashboard-certs
+ secret:
+ secretName: kubernetes-dashboard-certs
+ - name: tmp-volume
+ emptyDir: {}
serviceAccountName: kubernetes-dashboard
+ nodeSelector:
+ "kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- - key: node-role.kubernetes.io/master
- effect: NoSchedule
+ - key: node-role.kubernetes.io/master
+ effect: NoSchedule
---
-# ------------------- Dashboard Service ------------------- #
kind: Service
apiVersion: v1
metadata:
labels:
- k8s-app: kubernetes-dashboard
- name: kubernetes-dashboard
- namespace: kube-system
+ k8s-app: dashboard-metrics-scraper
+ name: dashboard-metrics-scraper
+ namespace: kubernetes-dashboard
spec:
ports:
- - port: 443
- targetPort: 8443
+ - port: 8000
+ targetPort: 8000
selector:
- k8s-app: kubernetes-dashboard
+ k8s-app: dashboard-metrics-scraper
+
+---
+
+kind: Deployment
+apiVersion: apps/v1
+metadata:
+ labels:
+ k8s-app: dashboard-metrics-scraper
+ name: dashboard-metrics-scraper
+ namespace: kubernetes-dashboard
+spec:
+ replicas: 1
+ revisionHistoryLimit: 10
+ selector:
+ matchLabels:
+ k8s-app: dashboard-metrics-scraper
+ template:
+ metadata:
+ labels:
+ k8s-app: dashboard-metrics-scraper
+ annotations:
+ seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
+ spec:
+ containers:
+ - name: dashboard-metrics-scraper
+ image: kubernetesui/metrics-scraper:v1.0.4
+ ports:
+ - containerPort: 8000
+ protocol: TCP
+ livenessProbe:
+ httpGet:
+ scheme: HTTP
+ path: /
+ port: 8000
+ initialDelaySeconds: 30
+ timeoutSeconds: 30
+ volumeMounts:
+ - mountPath: /tmp
+ name: tmp-volume
+ securityContext:
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: true
+ runAsUser: 1001
+ runAsGroup: 2001
+ serviceAccountName: kubernetes-dashboard
+ nodeSelector:
+ "kubernetes.io/os": linux
+ # Comment the following tolerations if Dashboard must not be deployed on master
+ tolerations:
+ - key: node-role.kubernetes.io/master
+ effect: NoSchedule
+ volumes:
+ - name: tmp-volume
+ emptyDir: {}
diff --git a/k8s/nginx-4-with-init.yaml b/k8s/nginx-4-with-init.yaml
index d41ecd7a..c3023070 100644
--- a/k8s/nginx-4-with-init.yaml
+++ b/k8s/nginx-4-with-init.yaml
@@ -14,7 +14,7 @@ spec:
initContainers:
- name: git
image: alpine
- command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/octocat/Spoon-Knife /www" ]
+ command: [ "sh", "-c", "apk add git && sleep 5 && git clone https://github.com/octocat/Spoon-Knife /www" ]
volumeMounts:
- name: www
mountPath: /www/
diff --git a/k8s/portworx.yaml b/k8s/portworx.yaml
index f29a54c3..39816339 100644
--- a/k8s/portworx.yaml
+++ b/k8s/portworx.yaml
@@ -1,4 +1,4 @@
-# SOURCE: https://install.portworx.com/?mc=false&kbver=1.17.1&b=true&s=%2Fdev%2Floop4&j=auto&c=px-workshop&stork=true&csi=true&lh=true&st=k8s
+# SOURCE: https://install.portworx.com/?mc=false&kbver=1.18.2&b=true&s=%2Fdev%2Floop4&j=auto&c=px-workshop&stork=true&csi=true&lh=true&st=k8s
---
kind: Service
apiVersion: v1
@@ -233,6 +233,9 @@ rules:
- apiGroups: [""]
resources: ["persistentvolumeclaims", "persistentvolumes"]
verbs: ["get", "list"]
+- apiGroups: ["storage.k8s.io"]
+ resources: ["storageclasses"]
+ verbs: ["get", "list"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "update", "create"]
@@ -246,6 +249,9 @@ rules:
- apiGroups: ["stork.libopenstorage.org"]
resources: ["backuplocations"]
verbs: ["get", "list"]
+- apiGroups: ["core.libopenstorage.org"]
+ resources: ["*"]
+ verbs: ["*"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create"]
@@ -293,6 +299,7 @@ roleRef:
name: px-role
apiGroup: rbac.authorization.k8s.io
---
+
apiVersion: apps/v1
kind: DaemonSet
metadata:
@@ -300,8 +307,6 @@ metadata:
namespace: kube-system
labels:
name: portworx
- annotations:
- portworx.com/install-source: "https://install.portworx.com/?mc=false&kbver=1.17.1&b=true&s=%2Fdev%2Floop4&j=auto&c=px-workshop&stork=true&csi=true&lh=true&st=k8s"
spec:
selector:
matchLabels:
@@ -331,7 +336,7 @@ spec:
hostPID: false
containers:
- name: portworx
- image: portworx/oci-monitor:2.3.2
+ image: portworx/oci-monitor:2.5.1
imagePullPolicy: Always
args:
["-c", "px-workshop", "-s", "/dev/loop4", "-secret_type", "k8s", "-j", "auto", "-b",
@@ -341,7 +346,7 @@ spec:
value: "1500"
- name: "PX_TEMPLATE_VERSION"
value: "v4"
- - name: CSI_ENDPOINT
+ - name: CSI_ENDPOINT
value: unix:///var/lib/kubelet/plugins/pxd.portworx.com/csi.sock
livenessProbe:
@@ -375,8 +380,6 @@ spec:
mountPath: /etc/pwx
- name: dev
mountPath: /dev
- - name: csi-driver-path
- mountPath: /var/lib/kubelet/plugins/pxd.portworx.com
- name: optpwx
mountPath: /opt/pwx
- name: procmount
@@ -393,11 +396,11 @@ spec:
mountPath: /var/run/dbus
- name: csi-node-driver-registrar
image: quay.io/k8scsi/csi-node-driver-registrar:v1.1.0
+ imagePullPolicy: Always
args:
- "--v=5"
- "--csi-address=$(ADDRESS)"
- "--kubelet-registration-path=/var/lib/kubelet/plugins/pxd.portworx.com/csi.sock"
- imagePullPolicy: Always
env:
- name: ADDRESS
value: /csi/csi.sock
@@ -507,7 +510,7 @@ rules:
resources: ["secrets"]
verbs: ["get", "list"]
- apiGroups: ["snapshot.storage.k8s.io"]
- resources: ["volumesnapshots", "volumesnapshotcontents", "volumesnapshotclasses", "volumesnapshots/status"]
+ resources: ["volumesnapshots", "volumesnapshotcontents", "volumesnapshotclasses", "volumesnapshots/status", "volumesnapshotcontents/status"]
verbs: ["create", "get", "list", "watch", "update", "delete"]
- apiGroups: [""]
resources: ["nodes"]
@@ -578,8 +581,8 @@ spec:
serviceAccount: px-csi-account
containers:
- name: csi-external-provisioner
+ image: quay.io/openstorage/csi-provisioner:v1.6.0-1
imagePullPolicy: Always
- image: quay.io/openstorage/csi-provisioner:v1.4.0-1
args:
- "--v=5"
- "--provisioner=pxd.portworx.com"
@@ -595,7 +598,7 @@ spec:
- name: socket-dir
mountPath: /csi
- name: csi-snapshotter
- image: quay.io/k8scsi/csi-snapshotter:v2.0.0
+ image: quay.io/k8scsi/csi-snapshotter:v2.1.0
imagePullPolicy: Always
args:
- "--v=3"
@@ -609,9 +612,23 @@ spec:
volumeMounts:
- name: socket-dir
mountPath: /csi
+ - name: csi-snapshot-controller
+ image: quay.io/k8scsi/snapshot-controller:v2.1.0
+ imagePullPolicy: Always
+ args:
+ - "--v=3"
+ - "--leader-election=true"
+ env:
+ - name: ADDRESS
+ value: /csi/csi.sock
+ securityContext:
+ privileged: true
+ volumeMounts:
+ - name: socket-dir
+ mountPath: /csi
- name: csi-resizer
+ image: quay.io/k8scsi/csi-resizer:v0.5.0
imagePullPolicy: Always
- image: quay.io/k8scsi/csi-resizer:v0.3.0
args:
- "--v=5"
- "--csi-address=$(ADDRESS)"
@@ -630,6 +647,510 @@ spec:
path: /var/lib/kubelet/plugins/pxd.portworx.com
type: DirectoryOrCreate
---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.2.5
+ api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/260"
+ creationTimestamp: null
+ name: volumesnapshotclasses.snapshot.storage.k8s.io
+spec:
+ additionalPrinterColumns:
+ - JSONPath: .driver
+ name: Driver
+ type: string
+ - JSONPath: .deletionPolicy
+ description: Determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass
+ should be deleted when its bound VolumeSnapshot is deleted.
+ name: DeletionPolicy
+ type: string
+ - JSONPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ group: snapshot.storage.k8s.io
+ names:
+ kind: VolumeSnapshotClass
+ listKind: VolumeSnapshotClassList
+ plural: volumesnapshotclasses
+ singular: volumesnapshotclass
+ preserveUnknownFields: false
+ scope: Cluster
+ subresources: {}
+ validation:
+ openAPIV3Schema:
+ description: VolumeSnapshotClass specifies parameters that a underlying storage
+ system uses when creating a volume snapshot. A specific VolumeSnapshotClass
+ is used by specifying its name in a VolumeSnapshot object. VolumeSnapshotClasses
+ are non-namespaced
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ deletionPolicy:
+ description: deletionPolicy determines whether a VolumeSnapshotContent created
+ through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot
+ is deleted. Supported values are "Retain" and "Delete". "Retain" means
+ that the VolumeSnapshotContent and its physical snapshot on underlying
+ storage system are kept. "Delete" means that the VolumeSnapshotContent
+ and its physical snapshot on underlying storage system are deleted. Required.
+ enum:
+ - Delete
+ - Retain
+ type: string
+ driver:
+ description: driver is the name of the storage driver that handles this
+ VolumeSnapshotClass. Required.
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ parameters:
+ additionalProperties:
+ type: string
+ description: parameters is a key-value map with storage driver specific
+ parameters for creating snapshots. These values are opaque to Kubernetes.
+ type: object
+ required:
+ - deletionPolicy
+ - driver
+ type: object
+ version: v1beta1
+ versions:
+ - name: v1beta1
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.2.5
+ api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/260"
+ creationTimestamp: null
+ name: volumesnapshots.snapshot.storage.k8s.io
+spec:
+ additionalPrinterColumns:
+ - JSONPath: .status.readyToUse
+ description: Indicates if a snapshot is ready to be used to restore a volume.
+ name: ReadyToUse
+ type: boolean
+ - JSONPath: .spec.source.persistentVolumeClaimName
+ description: Name of the source PVC from where a dynamically taken snapshot will
+ be created.
+ name: SourcePVC
+ type: string
+ - JSONPath: .spec.source.volumeSnapshotContentName
+ description: Name of the VolumeSnapshotContent which represents a pre-provisioned
+ snapshot.
+ name: SourceSnapshotContent
+ type: string
+ - JSONPath: .status.restoreSize
+ description: Represents the complete size of the snapshot.
+ name: RestoreSize
+ type: string
+ - JSONPath: .spec.volumeSnapshotClassName
+ description: The name of the VolumeSnapshotClass requested by the VolumeSnapshot.
+ name: SnapshotClass
+ type: string
+ - JSONPath: .status.boundVolumeSnapshotContentName
+ description: The name of the VolumeSnapshotContent to which this VolumeSnapshot
+ is bound.
+ name: SnapshotContent
+ type: string
+ - JSONPath: .status.creationTime
+ description: Timestamp when the point-in-time snapshot is taken by the underlying
+ storage system.
+ name: CreationTime
+ type: date
+ - JSONPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ group: snapshot.storage.k8s.io
+ names:
+ kind: VolumeSnapshot
+ listKind: VolumeSnapshotList
+ plural: volumesnapshots
+ singular: volumesnapshot
+ preserveUnknownFields: false
+ scope: Namespaced
+ subresources:
+ status: {}
+ validation:
+ openAPIV3Schema:
+ description: VolumeSnapshot is a user's request for either creating a point-in-time
+ snapshot of a persistent volume, or binding to a pre-existing snapshot.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ description: 'spec defines the desired characteristics of a snapshot requested
+ by a user. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots
+ Required.'
+ properties:
+ source:
+ description: source specifies where a snapshot will be created from.
+ This field is immutable after creation. Required.
+ properties:
+ persistentVolumeClaimName:
+ description: persistentVolumeClaimName specifies the name of the
+ PersistentVolumeClaim object in the same namespace as the VolumeSnapshot
+ object where the snapshot should be dynamically taken from. This
+ field is immutable.
+ type: string
+ volumeSnapshotContentName:
+ description: volumeSnapshotContentName specifies the name of a pre-existing
+ VolumeSnapshotContent object. This field is immutable.
+ type: string
+ type: object
+ volumeSnapshotClassName:
+ description: 'volumeSnapshotClassName is the name of the VolumeSnapshotClass
+ requested by the VolumeSnapshot. If not specified, the default snapshot
+ class will be used if one exists. If not specified, and there is no
+ default snapshot class, dynamic snapshot creation will fail. Empty
+ string is not allowed for this field. TODO(xiangqian): a webhook validation
+ on empty string. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshot-classes'
+ type: string
+ required:
+ - source
+ type: object
+ status:
+ description: 'status represents the current information of a snapshot. NOTE:
+ status can be modified by sources other than system controllers, and must
+ not be depended upon for accuracy. Controllers should only use information
+ from the VolumeSnapshotContent object after verifying that the binding
+ is accurate and complete.'
+ properties:
+ boundVolumeSnapshotContentName:
+ description: 'boundVolumeSnapshotContentName represents the name of
+ the VolumeSnapshotContent object to which the VolumeSnapshot object
+ is bound. If not specified, it indicates that the VolumeSnapshot object
+ has not been successfully bound to a VolumeSnapshotContent object
+ yet. NOTE: Specified boundVolumeSnapshotContentName alone does not
+ mean binding is valid. Controllers MUST always verify bidirectional
+ binding between VolumeSnapshot and VolumeSnapshotContent to
+ avoid possible security issues.'
+ type: string
+ creationTime:
+ description: creationTime is the timestamp when the point-in-time snapshot
+ is taken by the underlying storage system. In dynamic snapshot creation
+ case, this field will be filled in with the "creation_time" value
+ returned from CSI "CreateSnapshotRequest" gRPC call. For a pre-existing
+ snapshot, this field will be filled with the "creation_time" value
+ returned from the CSI "ListSnapshots" gRPC call if the driver supports
+ it. If not specified, it indicates that the creation time of the snapshot
+ is unknown.
+ format: date-time
+ type: string
+ error:
+ description: error is the last observed error during snapshot creation,
+ if any. This field could be helpful to upper level controllers(i.e.,
+ application controller) to decide whether they should continue on
+ waiting for the snapshot to be created based on the type of error
+ reported.
+ properties:
+ message:
+ description: 'message is a string detailing the encountered error
+ during snapshot creation if specified. NOTE: message may be logged,
+ and it should not contain sensitive information.'
+ type: string
+ time:
+ description: time is the timestamp when the error was encountered.
+ format: date-time
+ type: string
+ type: object
+ readyToUse:
+ description: readyToUse indicates if a snapshot is ready to be used
+ to restore a volume. In dynamic snapshot creation case, this field
+ will be filled in with the "ready_to_use" value returned from CSI
+ "CreateSnapshotRequest" gRPC call. For a pre-existing snapshot, this
+ field will be filled with the "ready_to_use" value returned from the
+ CSI "ListSnapshots" gRPC call if the driver supports it, otherwise,
+ this field will be set to "True". If not specified, it means the readiness
+ of a snapshot is unknown.
+ type: boolean
+ restoreSize:
+ anyOf:
+ - type: integer
+ - type: string
+ description: restoreSize represents the complete size of the snapshot
+ in bytes. In dynamic snapshot creation case, this field will be filled
+ in with the "size_bytes" value returned from CSI "CreateSnapshotRequest"
+ gRPC call. For a pre-existing snapshot, this field will be filled
+ with the "size_bytes" value returned from the CSI "ListSnapshots"
+ gRPC call if the driver supports it. When restoring a volume from
+ this snapshot, the size of the volume MUST NOT be smaller than the
+ restoreSize if it is specified, otherwise the restoration will fail.
+ If not specified, it indicates that the size is unknown.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ required:
+ - spec
+ type: object
+ version: v1beta1
+ versions:
+ - name: v1beta1
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
+
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.2.5
+ api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/260"
+ creationTimestamp: null
+ name: volumesnapshotcontents.snapshot.storage.k8s.io
+spec:
+ additionalPrinterColumns:
+ - JSONPath: .status.readyToUse
+ description: Indicates if a snapshot is ready to be used to restore a volume.
+ name: ReadyToUse
+ type: boolean
+ - JSONPath: .status.restoreSize
+ description: Represents the complete size of the snapshot in bytes
+ name: RestoreSize
+ type: integer
+ - JSONPath: .spec.deletionPolicy
+ description: Determines whether this VolumeSnapshotContent and its physical snapshot
+ on the underlying storage system should be deleted when its bound VolumeSnapshot
+ is deleted.
+ name: DeletionPolicy
+ type: string
+ - JSONPath: .spec.driver
+ description: Name of the CSI driver used to create the physical snapshot on the
+ underlying storage system.
+ name: Driver
+ type: string
+ - JSONPath: .spec.volumeSnapshotClassName
+ description: Name of the VolumeSnapshotClass to which this snapshot belongs.
+ name: VolumeSnapshotClass
+ type: string
+ - JSONPath: .spec.volumeSnapshotRef.name
+ description: Name of the VolumeSnapshot object to which this VolumeSnapshotContent
+ object is bound.
+ name: VolumeSnapshot
+ type: string
+ - JSONPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ group: snapshot.storage.k8s.io
+ names:
+ kind: VolumeSnapshotContent
+ listKind: VolumeSnapshotContentList
+ plural: volumesnapshotcontents
+ singular: volumesnapshotcontent
+ preserveUnknownFields: false
+ scope: Cluster
+ subresources:
+ status: {}
+ validation:
+ openAPIV3Schema:
+ description: VolumeSnapshotContent represents the actual "on-disk" snapshot
+ object in the underlying storage system
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ description: spec defines properties of a VolumeSnapshotContent created
+ by the underlying storage system. Required.
+ properties:
+ deletionPolicy:
+ description: deletionPolicy determines whether this VolumeSnapshotContent
+ and its physical snapshot on the underlying storage system should
+ be deleted when its bound VolumeSnapshot is deleted. Supported values
+ are "Retain" and "Delete". "Retain" means that the VolumeSnapshotContent
+ and its physical snapshot on underlying storage system are kept. "Delete"
+ means that the VolumeSnapshotContent and its physical snapshot on
+ underlying storage system are deleted. In dynamic snapshot creation
+ case, this field will be filled in with the "DeletionPolicy" field
+ defined in the VolumeSnapshotClass the VolumeSnapshot refers to. For
+ pre-existing snapshots, users MUST specify this field when creating
+ the VolumeSnapshotContent object. Required.
+ enum:
+ - Delete
+ - Retain
+ type: string
+ driver:
+ description: driver is the name of the CSI driver used to create the
+ physical snapshot on the underlying storage system. This MUST be the
+ same as the name returned by the CSI GetPluginName() call for that
+ driver. Required.
+ type: string
+ source:
+ description: source specifies from where a snapshot will be created.
+ This field is immutable after creation. Required.
+ properties:
+ snapshotHandle:
+ description: snapshotHandle specifies the CSI "snapshot_id" of a
+ pre-existing snapshot on the underlying storage system. This field
+ is immutable.
+ type: string
+ volumeHandle:
+ description: volumeHandle specifies the CSI "volume_id" of the volume
+ from which a snapshot should be dynamically taken from. This field
+ is immutable.
+ type: string
+ type: object
+ volumeSnapshotClassName:
+ description: name of the VolumeSnapshotClass to which this snapshot
+ belongs.
+ type: string
+ volumeSnapshotRef:
+ description: volumeSnapshotRef specifies the VolumeSnapshot object to
+ which this VolumeSnapshotContent object is bound. VolumeSnapshot.Spec.VolumeSnapshotContentName
+ field must reference to this VolumeSnapshotContent's name for the
+ bidirectional binding to be valid. For a pre-existing VolumeSnapshotContent
+ object, name and namespace of the VolumeSnapshot object MUST be provided
+ for binding to happen. This field is immutable after creation. Required.
+ properties:
+ apiVersion:
+ description: API version of the referent.
+ type: string
+ fieldPath:
+ description: 'If referring to a piece of an object instead of an
+ entire object, this string should contain a valid JSON/Go field
+ access statement, such as desiredState.manifest.containers[2].
+ For example, if the object reference is to a container within
+ a pod, this would take on a value like: "spec.containers{name}"
+ (where "name" refers to the name of the container that triggered
+ the event) or if no container name is specified "spec.containers[2]"
+ (container with index 2 in this pod). This syntax is chosen only
+ to have some well-defined way of referencing a part of an object.
+ TODO: this design is not final and this field is subject to change
+ in the future.'
+ type: string
+ kind:
+ description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
+ type: string
+ namespace:
+ description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
+ type: string
+ resourceVersion:
+ description: 'Specific resourceVersion to which this reference is
+ made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
+ type: string
+ uid:
+ description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
+ type: string
+ type: object
+ required:
+ - deletionPolicy
+ - driver
+ - source
+ - volumeSnapshotRef
+ type: object
+ status:
+ description: status represents the current information of a snapshot.
+ properties:
+ creationTime:
+ description: creationTime is the timestamp when the point-in-time snapshot
+ is taken by the underlying storage system. In dynamic snapshot creation
+ case, this field will be filled in with the "creation_time" value
+ returned from CSI "CreateSnapshotRequest" gRPC call. For a pre-existing
+ snapshot, this field will be filled with the "creation_time" value
+ returned from the CSI "ListSnapshots" gRPC call if the driver supports
+ it. If not specified, it indicates the creation time is unknown. The
+ format of this field is a Unix nanoseconds time encoded as an int64.
+ On Unix, the command `date +%s%N` returns the current time in nanoseconds
+ since 1970-01-01 00:00:00 UTC.
+ format: int64
+ type: integer
+ error:
+ description: error is the latest observed error during snapshot creation,
+ if any.
+ properties:
+ message:
+ description: 'message is a string detailing the encountered error
+ during snapshot creation if specified. NOTE: message may be logged,
+ and it should not contain sensitive information.'
+ type: string
+ time:
+ description: time is the timestamp when the error was encountered.
+ format: date-time
+ type: string
+ type: object
+ readyToUse:
+ description: readyToUse indicates if a snapshot is ready to be used
+ to restore a volume. In dynamic snapshot creation case, this field
+ will be filled in with the "ready_to_use" value returned from CSI
+ "CreateSnapshotRequest" gRPC call. For a pre-existing snapshot, this
+ field will be filled with the "ready_to_use" value returned from the
+ CSI "ListSnapshots" gRPC call if the driver supports it, otherwise,
+ this field will be set to "True". If not specified, it means the readiness
+ of a snapshot is unknown.
+ type: boolean
+ restoreSize:
+ description: restoreSize represents the complete size of the snapshot
+ in bytes. In dynamic snapshot creation case, this field will be filled
+ in with the "size_bytes" value returned from CSI "CreateSnapshotRequest"
+ gRPC call. For a pre-existing snapshot, this field will be filled
+ with the "size_bytes" value returned from the CSI "ListSnapshots"
+ gRPC call if the driver supports it. When restoring a volume from
+ this snapshot, the size of the volume MUST NOT be smaller than the
+ restoreSize if it is specified, otherwise the restoration will fail.
+ If not specified, it indicates that the size is unknown.
+ format: int64
+ minimum: 0
+ type: integer
+ snapshotHandle:
+ description: snapshotHandle is the CSI "snapshot_id" of a snapshot on
+ the underlying storage system. If not specified, it indicates that
+ dynamic snapshot creation has either failed or it is still in progress.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ version: v1beta1
+ versions:
+ - name: v1beta1
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
+---
kind: Service
apiVersion: v1
metadata:
@@ -711,29 +1232,6 @@ spec:
podInfoOnMount: false
---
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:8099",
- "apiVersion": "v1beta1",
- "filterVerb": "filter",
- "prioritizeVerb": "prioritize",
- "weight": 5,
- "enableHttps": false,
- "nodeCacheCapable": false
- }
- ]
- }
----
-apiVersion: v1
kind: ServiceAccount
metadata:
name: stork-account
@@ -761,19 +1259,6 @@ roleRef:
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: apps/v1
kind: Deployment
metadata:
@@ -801,23 +1286,6 @@ spec:
name: stork
tier: control-plane
spec:
- containers:
- - command:
- - /stork
- - --driver=pxd
- - --verbose
- - --leader-elect=true
- - --health-monitor-interval=120
- imagePullPolicy: Always
- image: openstorage/stork:2.3.1
- env:
- - name: "PX_SERVICE_NAME"
- value: "portworx-api"
- resources:
- requests:
- cpu: '0.1'
- name: stork
- hostPID: false
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
@@ -828,6 +1296,23 @@ spec:
values:
- stork
topologyKey: "kubernetes.io/hostname"
+ hostPID: false
+ containers:
+ - command:
+ - /stork
+ - --driver=pxd
+ - --verbose
+ - --leader-elect=true
+ - --health-monitor-interval=120
+ image: openstorage/stork:2.4.0
+ imagePullPolicy: Always
+ env:
+ - name: "PX_SERVICE_NAME"
+ value: "portworx-api"
+ resources:
+ requests:
+ cpu: '0.1'
+ name: stork
serviceAccountName: stork-account
---
kind: StorageClass
@@ -836,6 +1321,43 @@ metadata:
name: stork-snapshot-sc
provisioner: stork-snapshot
---
+kind: Service
+apiVersion: v1
+metadata:
+ name: stork-service
+ namespace: kube-system
+spec:
+ selector:
+ name: stork
+ ports:
+ - protocol: TCP
+ port: 8099
+ targetPort: 8099
+---
+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:8099",
+ "apiVersion": "v1beta1",
+ "filterVerb": "filter",
+ "prioritizeVerb": "prioritize",
+ "weight": 5,
+ "enableHttps": false,
+ "nodeCacheCapable": false,
+ "httpTimeout": 300000000000
+ }
+ ]
+ }
+---
apiVersion: v1
kind: ServiceAccount
metadata:
@@ -929,29 +1451,6 @@ spec:
name: stork-scheduler
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.17.1
- 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:
@@ -963,6 +1462,30 @@ spec:
- stork-scheduler
topologyKey: "kubernetes.io/hostname"
hostPID: false
+ 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.18.2
+ imagePullPolicy: Always
+ livenessProbe:
+ httpGet:
+ path: /healthz
+ port: 10251
+ initialDelaySeconds: 15
+ name: stork-scheduler
+ readinessProbe:
+ httpGet:
+ path: /healthz
+ port: 10251
+ resources:
+ requests:
+ cpu: '0.1'
serviceAccountName: stork-scheduler-account
---
apiVersion: v1
@@ -1067,7 +1590,7 @@ spec:
spec:
initContainers:
- name: config-init
- image: portworx/lh-config-sync:2.0.5
+ image: portworx/lh-config-sync:2.0.7
imagePullPolicy: Always
args:
- "init"
@@ -1076,7 +1599,7 @@ spec:
mountPath: /config/lh
containers:
- name: px-lighthouse
- image: portworx/px-lighthouse:2.0.6
+ image: portworx/px-lighthouse:2.0.7
imagePullPolicy: Always
args: [ "-kubernetes", "true" ]
ports:
@@ -1086,7 +1609,7 @@ spec:
- name: config
mountPath: /config/lh
- name: config-sync
- image: portworx/lh-config-sync:2.0.5
+ image: portworx/lh-config-sync:2.0.7
imagePullPolicy: Always
args:
- "sync"
@@ -1094,13 +1617,135 @@ spec:
- name: config
mountPath: /config/lh
- name: stork-connector
- image: portworx/lh-stork-connector:2.0.5
+ image: portworx/lh-stork-connector:2.0.7
imagePullPolicy: Always
serviceAccountName: px-lh-account
volumes:
- name: config
emptyDir: {}
---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: autopilot-config
+ namespace: kube-system
+data:
+ config.yaml: |-
+ providers:
+ - name: default
+ type: prometheus
+ params: url=http://prometheus:9090
+ min_poll_interval: 2
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: autopilot-account
+ namespace: kube-system
+---
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: autopilot-role
+rules:
+ - apiGroups: ["*"]
+ resources: ["*"]
+ verbs: ["*"]
+---
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: autopilot-role-binding
+subjects:
+- kind: ServiceAccount
+ name: autopilot-account
+ namespace: kube-system
+roleRef:
+ kind: ClusterRole
+ name: autopilot-role
+ apiGroup: rbac.authorization.k8s.io
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ scheduler.alpha.kubernetes.io/critical-pod: ""
+ labels:
+ tier: control-plane
+ name: autopilot
+ namespace: kube-system
+spec:
+ selector:
+ matchLabels:
+ name: autopilot
+ strategy:
+ rollingUpdate:
+ maxSurge: 1
+ maxUnavailable: 1
+ type: RollingUpdate
+ replicas: 1
+ template:
+ metadata:
+ annotations:
+ scheduler.alpha.kubernetes.io/critical-pod: ""
+ labels:
+ name: autopilot
+ tier: control-plane
+ spec:
+ affinity:
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchExpressions:
+ - key: "name"
+ operator: In
+ values:
+ - autopilot
+ topologyKey: "kubernetes.io/hostname"
+ hostPID: false
+ containers:
+ - command:
+ - /autopilot
+ - -f
+ - ./etc/config/config.yaml
+ - -log-level
+ - debug
+ imagePullPolicy: Always
+ image: portworx/autopilot:1.2.0
+ resources:
+ requests:
+ cpu: '0.1'
+ securityContext:
+ privileged: false
+ name: autopilot
+ volumeMounts:
+ - name: config-volume
+ mountPath: /etc/config
+ serviceAccountName: autopilot-account
+ volumes:
+ - name: config-volume
+ configMap:
+ name: autopilot-config
+ items:
+ - key: config.yaml
+ path: config.yaml
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: autopilot
+ namespace: kube-system
+ labels:
+ name: autopilot-service
+spec:
+ ports:
+ - name: autopilot
+ protocol: TCP
+ port: 9628
+ selector:
+ name: autopilot
+ tier: control-plane
+---
# That one is an extra.
# Create a default Storage Class to simplify Portworx setup.
kind: StorageClass
@@ -1113,4 +1758,59 @@ provisioner: kubernetes.io/portworx-volume
parameters:
repl: "2"
priority_io: "high"
-
+---
+# This DaemonSet will set up the (virtual) block device
+# used by portworx.
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+ name: setup-loop4-for-portworx
+ namespace: kube-system
+spec:
+ selector:
+ matchLabels:
+ app: setup-loop4-for-portworx
+ template:
+ metadata:
+ labels:
+ app: setup-loop4-for-portworx
+ spec:
+ volumes:
+ - name: hostfs
+ hostPath:
+ path: /
+ tolerations:
+ - effect: NoSchedule
+ operator: Exists
+ initContainers:
+ - name: setup-loop4-for-portworx
+ image: alpine
+ volumeMounts:
+ - name: hostfs
+ mountPath: /hostfs
+ securityContext:
+ privileged: true
+ command:
+ - chroot
+ - /hostfs
+ - /bin/sh
+ - -c
+ - |
+ set -e
+ if ! [ -f /portworx.blk ]; then
+ echo "Creating /portworx.blk..."
+ truncate --size 10G /portworx.blk
+ fi
+ if ! grep -q loop /proc/devices; then
+ echo "Loading loop module..."
+ modprobe loop
+ fi
+ echo "Checking /dev/loop4..."
+ if ! losetup /dev/loop4; then
+ echo "Associating /dev/loop4 with /portworx.blk..."
+ losetup /dev/loop4 /portworx.blk
+ fi
+ echo "Loop device setup complete."
+ containers:
+ - name: do-nothing
+ image: k8s.gcr.io/pause
diff --git a/k8s/postgres.yaml b/k8s/postgres.yaml
index a9331f2a..69c90c37 100644
--- a/k8s/postgres.yaml
+++ b/k8s/postgres.yaml
@@ -22,7 +22,10 @@ spec:
command: ["sh", "-c", "if [ -d /vol/lost+found ]; then rmdir /vol/lost+found; fi"]
containers:
- name: postgres
- image: postgres:11
+ image: postgres:12
+ env:
+ - name: POSTGRES_HOST_AUTH_METHOD
+ value: trust
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres
diff --git a/k8s/psp-restricted.yaml b/k8s/psp-restricted.yaml
index a73e7049..962685d0 100644
--- a/k8s/psp-restricted.yaml
+++ b/k8s/psp-restricted.yaml
@@ -1,5 +1,5 @@
---
-apiVersion: extensions/v1beta1
+apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
annotations:
diff --git a/k8s/users:jean.doe.yaml b/k8s/user=jean.doe.yaml
similarity index 85%
rename from k8s/users:jean.doe.yaml
rename to k8s/user=jean.doe.yaml
index ef96d39e..4789038d 100644
--- a/k8s/users:jean.doe.yaml
+++ b/k8s/user=jean.doe.yaml
@@ -8,24 +8,24 @@ metadata:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
- name: users:jean.doe
+ name: user=jean.doe
rules:
- apiGroups: [ certificates.k8s.io ]
resources: [ certificatesigningrequests ]
verbs: [ create ]
- apiGroups: [ certificates.k8s.io ]
- resourceNames: [ users:jean.doe ]
+ resourceNames: [ user=jean.doe ]
resources: [ certificatesigningrequests ]
verbs: [ get, create, delete, watch ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
- name: users:jean.doe
+ name: user=jean.doe
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
- name: users:jean.doe
+ name: user=jean.doe
subjects:
- kind: ServiceAccount
name: jean.doe
diff --git a/prepare-vms/lib/commands.sh b/prepare-vms/lib/commands.sh
index 5493f62f..b49e56dc 100644
--- a/prepare-vms/lib/commands.sh
+++ b/prepare-vms/lib/commands.sh
@@ -246,11 +246,21 @@ EOF"
helm completion bash | sudo tee /etc/bash_completion.d/helm
fi"
+ # Install kustomize
+ pssh "
+ if [ ! -x /usr/local/bin/kustomize ]; then
+ curl -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v3.5.4/kustomize_v3.5.1_linux_amd64.tar.gz |
+ sudo tar -C /usr/local/bin -zx kustomize
+ echo complete -C /usr/local/bin/kustomize kustomize | sudo tee /etc/bash_completion.d/kustomize
+ fi"
+
# Install ship
+ # Note: 0.51.3 is the last version that doesn't display GIN-debug messages
+ # (don't want to get folks confused by that!)
pssh "
if [ ! -x /usr/local/bin/ship ]; then
##VERSION##
- curl -L https://github.com/replicatedhq/ship/releases/download/v0.40.0/ship_0.40.0_linux_amd64.tar.gz |
+ curl -L https://github.com/replicatedhq/ship/releases/download/v0.51.3/ship_0.51.3_linux_amd64.tar.gz |
sudo tar -C /usr/local/bin -zx ship
fi"
@@ -329,7 +339,7 @@ _cmd_maketag() {
if [ -z $USER ]; then
export USER=anonymous
fi
- MS=$(($(date +%N)/1000000))
+ MS=$(($(date +%N | tr -d 0)/1000000))
date +%Y-%m-%d-%H-%M-$MS-$USER
}
@@ -483,6 +493,7 @@ _cmd_start() {
--settings) SETTINGS=$2; shift 2;;
--count) COUNT=$2; shift 2;;
--tag) TAG=$2; shift 2;;
+ --students) STUDENTS=$2; shift 2;;
*) die "Unrecognized parameter: $1."
esac
done
@@ -494,8 +505,14 @@ _cmd_start() {
die "Please add --settings flag to specify which settings file to use."
fi
if [ -z "$COUNT" ]; then
- COUNT=$(awk '/^clustersize:/ {print $2}' $SETTINGS)
- warning "No --count option was specified. Using value from settings file ($COUNT)."
+ CLUSTERSIZE=$(awk '/^clustersize:/ {print $2}' $SETTINGS)
+ if [ -z "$STUDENTS" ]; then
+ warning "Neither --count nor --students was specified."
+ warning "According to the settings file, the cluster size is $CLUSTERSIZE."
+ warning "Deploying one cluster of $CLUSTERSIZE nodes."
+ STUDENTS=1
+ fi
+ COUNT=$(($STUDENTS*$CLUSTERSIZE))
fi
# Check that the specified settings and infrastructure are valid.
@@ -513,11 +530,41 @@ _cmd_start() {
infra_start $COUNT
sep
info "Successfully created $COUNT instances with tag $TAG"
- sep
echo created > tags/$TAG/status
- info "To deploy Docker on these instances, you can run:"
- info "$0 deploy $TAG"
+ # If the settings.yaml file has a "steps" field,
+ # automatically execute all the actions listed in that field.
+ # If an action fails, retry it up to 10 times.
+ python -c 'if True: # hack to deal with indentation
+ import sys, yaml
+ settings = yaml.safe_load(sys.stdin)
+ print ("\n".join(settings.get("steps", [])))
+ ' < tags/$TAG/settings.yaml \
+ | while read step; do
+ if [ -z "$step" ]; then
+ break
+ fi
+ sep
+ info "Automatically executing step '$step'."
+ TRY=1
+ MAXTRY=10
+ while ! $0 $step $TAG ; do
+ TRY=$(($TRY+1))
+ if [ $TRY -gt $MAXTRY ]; then
+ error "This step ($step) failed after $MAXTRY attempts."
+ info "You can troubleshoot the situation manually, or terminate these instances with:"
+ info "$0 stop $TAG"
+ die "Giving up."
+ else
+ sep
+ info "Step '$step' failed. Let's wait 10 seconds and try again."
+ info "(Attempt $TRY out of $MAXTRY.)"
+ sleep 10
+ fi
+ done
+ done
+ sep
+ info "Deployment successful."
info "To terminate these instances, you can run:"
info "$0 stop $TAG"
}
diff --git a/prepare-vms/settings/fundamentals.yaml b/prepare-vms/settings/fundamentals.yaml
index 1c4000ce..3dc70a27 100644
--- a/prepare-vms/settings/fundamentals.yaml
+++ b/prepare-vms/settings/fundamentals.yaml
@@ -21,3 +21,9 @@ machine_version: 0.15.0
# Password used to connect with the "docker user"
docker_user_password: training
+
+steps:
+ - deploy
+ - webssh
+ - tailhist
+ - cards
diff --git a/prepare-vms/settings/jerome.yaml b/prepare-vms/settings/jerome.yaml
index 626751c5..57470504 100644
--- a/prepare-vms/settings/jerome.yaml
+++ b/prepare-vms/settings/jerome.yaml
@@ -20,3 +20,10 @@ machine_version: 0.14.0
# Password used to connect with the "docker user"
docker_user_password: training
+steps:
+ - deploy
+ - webssh
+ - tailhist
+ - kube
+ - cards
+ - kubetest
diff --git a/slides/1.yml b/slides/1.yml
index 192a525e..a8b4b6b8 100644
--- a/slides/1.yml
+++ b/slides/1.yml
@@ -1,5 +1,4 @@
title: |
- Module 1
Docker Intensif
chat: "[Gitter](https://gitter.im/jpetazzo/formation-highfive-202006)"
@@ -19,7 +18,8 @@ content:
- containers/intro.md
- shared/about-slides.md
- shared/chat-room-im.md
-#- shared/chat-room-zoom.md
+#- shared/chat-room-zoom-meeting.md
+#- shared/chat-room-zoom-webinar.md
- shared/toc.md
-
#- containers/Docker_Overview.md
diff --git a/slides/2.yml b/slides/2.yml
index 9e94bc42..94299417 100644
--- a/slides/2.yml
+++ b/slides/2.yml
@@ -1,5 +1,4 @@
title: |
- Module 2
Fondamentaux Kubernetes
chat: "[Gitter](https://gitter.im/jpetazzo/formation-highfive-202006)"
@@ -19,7 +18,8 @@ content:
- k8s/intro.md
- shared/about-slides.md
- shared/chat-room-im.md
-#- shared/chat-room-zoom.md
+#- shared/chat-room-zoom-meeting.md
+#- shared/chat-room-zoom-webinar.md
- shared/toc.md
-
- shared/prereqs.md
@@ -34,10 +34,9 @@ content:
- k8s/kubectlget.md
- k8s/kubectl-run.md
-
- - k8s/batch-jobs.md
- - k8s/labels-annotations.md
- - k8s/kubectl-logs.md
- - k8s/logs-cli.md
+ - shared/declarative.md
+ - k8s/declarative.md
+ - k8s/deploymentslideshow.md
- k8s/kubenet.md
- k8s/kubectlexpose.md
- k8s/shippingimages.md
@@ -46,43 +45,32 @@ content:
- k8s/ourapponkube.md
#- k8s/exercise-wordsmith.md
-
- - shared/declarative.md
- - k8s/declarative.md
- - k8s/deploymentslideshow.md
+ - k8s/batch-jobs.md
+ - k8s/labels-annotations.md
+ - k8s/kubectl-logs.md
+ - k8s/logs-cli.md
- k8s/yamldeploy.md
- - k8s/setup-k8s.md
- - k8s/localkubeconfig.md
- - k8s/namespaces.md
- - k8s/accessinternal.md
- - k8s/kubectlproxy.md
--
- - k8s/dashboard.md
#- k8s/kubectlscale.md
- k8s/scalingdockercoins.md
- shared/hastyconclusions.md
- k8s/daemonset.md
- #- k8s/exercise-yaml.md FIXME
-
#- k8s/dryrun.md
- k8s/rollout.md
- - k8s/healthchecks.md
- - k8s/healthchecks-more.md
- k8s/record.md
+ - k8s/healthchecks.md
+ #- k8s/healthchecks-more.md
+ - k8s/setup-overview.md
+ - k8s/setup-devel.md
+ - k8s/setup-managed.md
+ #- k8s/setup-selfhosted.md
+-
+ - k8s/namespaces.md
+ - k8s/localkubeconfig.md
+ - k8s/accessinternal.md
+ - k8s/kubectlproxy.md
+ - k8s/dashboard.md
- k8s/ingress.md
- #- k8s/kustomize.md
- #- k8s/helm-intro.md
- #- k8s/helm-chart-format.md
- #- k8s/helm-create-basic-chart.md
- #- k8s/helm-create-better-chart.md
- #- k8s/helm-secrets.md
- #- k8s/exercise-helm.md
- #- k8s/create-chart.md
- #- k8s/create-more-charts.md
- #- k8s/netpol.md
- #- k8s/authn-authz.md
- #- k8s/csr-api.md
- #- k8s/openid-connect.md
- #- k8s/podsecuritypolicy.md
-
- k8s/volumes.md
#- k8s/exercise-configmap.md
@@ -100,7 +88,7 @@ content:
#- k8s/staticpods.md
#- k8s/owners-and-dependents.md
#- k8s/gitworkflows.md
- - k8s/whatsnext.md
- - k8s/lastwords.md
- - k8s/links.md
+ #- k8s/whatsnext.md
+ #- k8s/lastwords.md
- shared/thankyou.md
+ - k8s/links.md
diff --git a/slides/3.yml b/slides/3.yml
index 505c0d15..b5c5b6b3 100644
--- a/slides/3.yml
+++ b/slides/3.yml
@@ -1,5 +1,4 @@
title: |
- Module 3
Packaging d'applications
pour Kubernetes
diff --git a/slides/4.yml b/slides/4.yml
index f9936706..2898340c 100644
--- a/slides/4.yml
+++ b/slides/4.yml
@@ -1,5 +1,4 @@
title: |
- Module 4
Kubernetes Avancé
chat: "[Gitter](https://gitter.im/jpetazzo/formation-highfive-202006)"
diff --git a/slides/5.yml b/slides/5.yml
index 57075c02..b5aa67bd 100644
--- a/slides/5.yml
+++ b/slides/5.yml
@@ -1,5 +1,4 @@
title: |
- Module 5
Opérer Kubernetes
chat: "[Gitter](https://gitter.im/jpetazzo/formation-highfive-202006)"
@@ -19,7 +18,8 @@ content:
- k8s/intro.md
- shared/about-slides.md
- shared/chat-room-im.md
-#- shared/chat-room-zoom.md
+#- shared/chat-room-zoom-meeting.md
+#- shared/chat-room-zoom-webinar.md
- shared/toc.md
# DAY 1
-
@@ -33,6 +33,8 @@ content:
- k8s/interco.md
-
- k8s/apilb.md
+ - k8s/setup-overview.md
+ - k8s/setup-devel.md
- k8s/setup-managed.md
- k8s/setup-selfhosted.md
- k8s/staticpods.md
diff --git a/slides/_redirects b/slides/_redirects
index 0b02b1bd..9107fe66 100644
--- a/slides/_redirects
+++ b/slides/_redirects
@@ -1,7 +1,7 @@
# Uncomment and/or edit one of the the following lines if necessary.
-#/ /kube-halfday.yml.html 200
-#/ /kube-fullday.yml.html 200
-#/ /kube-twodays.yml.html 200
+#/ /kube-halfday.yml.html 200!
+#/ /kube-fullday.yml.html 200!
+#/ /kube-twodays.yml.html 200!
# And this allows to do "git clone https://container.training".
/info/refs service=git-upload-pack https://github.com/jpetazzo/container.training/info/refs?service=git-upload-pack
@@ -13,6 +13,5 @@
# Shortlink for the QRCode
/q /qrcode.html 200
-/next https://www.eventbrite.com/e/intensive-kubernetes-advanced-concepts-live-stream-tickets-102358725704
/ highfive.html 200!
diff --git a/slides/containers/Advanced_Dockerfiles.md b/slides/containers/Advanced_Dockerfiles.md
index 58cb1713..770f9cbd 100644
--- a/slides/containers/Advanced_Dockerfiles.md
+++ b/slides/containers/Advanced_Dockerfiles.md
@@ -1,7 +1,7 @@
class: title
-# Advanced Dockerfiles
+# Advanced Dockerfile Syntax

@@ -12,7 +12,10 @@ class: title
We have seen simple Dockerfiles to illustrate how Docker build
container images.
-In this section, we will see more Dockerfile commands.
+In this section, we will give a recap of the Dockerfile syntax,
+and introduce advanced Dockerfile commands that we might
+come across sometimes; or that we might want to use in some
+specific scenarios.
---
@@ -420,3 +423,8 @@ ONBUILD COPY . /src
* You can't chain `ONBUILD` instructions with `ONBUILD`.
* `ONBUILD` can't be used to trigger `FROM` instructions.
+
+???
+
+:EN:- Advanced Dockerfile syntax
+:FR:- Dockerfile niveau expert
diff --git a/slides/index.py b/slides/index.py
index 2a5ad0ff..bfba3bfb 100755
--- a/slides/index.py
+++ b/slides/index.py
@@ -22,7 +22,7 @@ TEMPLATE="""
| Note: while some workshops are delivered in other languages, slides are always in English. |
- | Free video of our latest workshop |
+ | Free Kubernetes intro course |
| Getting Started With Kubernetes and Container Orchestration |
@@ -40,7 +40,7 @@ TEMPLATE="""
{% if coming_soon %}
- | Coming soon near you |
+ | Coming soon |
{% for item in coming_soon %}
@@ -141,13 +141,26 @@ import yaml
items = yaml.safe_load(open("index.yaml"))
+
+def prettyparse(date):
+ months = [
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ ]
+ month = months[date.month-1]
+ suffix = {
+ 1: "st", 2: "nd", 3: "rd",
+ 21: "st", 22: "nd", 23: "rd",
+ 31: "st"}.get(date.day, "th")
+ return date.year, month, "{}{}".format(date.day, suffix)
+
+
# Items with a date correspond to scheduled sessions.
# Items without a date correspond to self-paced content.
# The date should be specified as a string (e.g. 2018-11-26).
# It can also be a list of two elements (e.g. [2018-11-26, 2018-11-28]).
# The latter indicates an event spanning multiple dates.
-# The first date will be used in the generated page, but the event
-# will be considered "current" (and therefore, shown in the list of
+# The event will be considered "current" (shown in the list of
# upcoming events) until the second date.
for item in items:
@@ -157,19 +170,23 @@ for item in items:
date_begin, date_end = date
else:
date_begin, date_end = date, date
- suffix = {
- 1: "st", 2: "nd", 3: "rd",
- 21: "st", 22: "nd", 23: "rd",
- 31: "st"}.get(date_begin.day, "th")
- # %e is a non-standard extension (it displays the day, but without a
- # leading zero). If strftime fails with ValueError, try to fall back
- # on %d (which displays the day but with a leading zero when needed).
- try:
- item["prettydate"] = date_begin.strftime("%B %e{}, %Y").format(suffix)
- except ValueError:
- item["prettydate"] = date_begin.strftime("%B %d{}, %Y").format(suffix)
+ y1, m1, d1 = prettyparse(date_begin)
+ y2, m2, d2 = prettyparse(date_end)
+ if (y1, m1, d1) == (y2, m2, d2):
+ # Single day event
+ pretty_date = "{} {}, {}".format(m1, d1, y1)
+ elif (y1, m1) == (y2, m2):
+ # Multi-day event within a single month
+ pretty_date = "{} {}-{}, {}".format(m1, d1, d2, y1)
+ elif y1 == y2:
+ # Multi-day event spanning more than a month
+ pretty_date = "{} {}-{} {}, {}".format(m1, d1, m2, d2, y1)
+ else:
+ # Event spanning the turn of the year (REALLY???)
+ pretty_date = "{} {}, {}-{} {}, {}".format(m1, d1, y1, m2, d2, y2)
item["begin"] = date_begin
item["end"] = date_end
+ item["prettydate"] = pretty_date
item["flag"] = FLAGS.get(item.get("country"),"")
today = datetime.date.today()
diff --git a/slides/index.yaml b/slides/index.yaml
index f73be801..45677214 100644
--- a/slides/index.yaml
+++ b/slides/index.yaml
@@ -1,12 +1,4 @@
-- date: [2020-06-16, 2020-06-18]
- country: www
- city: streaming
- event: Ardan Live
- speaker: jpetazzo
- title: Intensive Kubernetes Bootcamp
- attend: https://www.eventbrite.com/e/livestream-intensive-kubernetes-bootcamp-tickets-103262336428
-
-- date: [2020-05-19, 2020-05-21]
+- date: [2020-07-07, 2020-07-09]
country: www
city: streaming
event: Ardan Live
@@ -14,6 +6,59 @@
title: Intensive Docker Bootcamp
attend: https://www.eventbrite.com/e/livestream-intensive-docker-bootcamp-tickets-103258886108
+- date: [2020-06-15, 2020-06-16]
+ country: www
+ city: streaming
+ event: ENIX SAS
+ speaker: jpetazzo
+ title: Docker intensif (en français)
+ lang: fr
+ attend: https://enix.io/fr/services/formation/online/
+
+- date: [2020-06-17, 2020-06-19]
+ country: www
+ city: streaming
+ event: ENIX SAS
+ speaker: jpetazzo
+ title: Fondamentaux Kubernetes (en français)
+ lang: fr
+ attend: https://enix.io/fr/services/formation/online/
+
+- date: 2020-06-22
+ country: www
+ city: streaming
+ event: ENIX SAS
+ speaker: jpetazzo
+ title: Packaging pour Kubernetes (en français)
+ lang: fr
+ attend: https://enix.io/fr/services/formation/online/
+
+- date: [2020-06-23, 2020-06-24]
+ country: www
+ city: streaming
+ event: ENIX SAS
+ speaker: jpetazzo
+ title: Kubernetes avancé (en français)
+ lang: fr
+ attend: https://enix.io/fr/services/formation/online/
+
+- date: [2020-06-25, 2020-06-26]
+ country: www
+ city: streaming
+ event: ENIX SAS
+ speaker: jpetazzo
+ title: Opérer Kubernetes (en français)
+ lang: fr
+ attend: https://enix.io/fr/services/formation/online/
+
+- date: [2020-06-09, 2020-06-11]
+ country: www
+ city: streaming
+ event: Ardan Live
+ speaker: jpetazzo
+ title: Intensive Kubernetes Bootcamp
+ attend: https://www.eventbrite.com/e/livestream-intensive-kubernetes-bootcamp-tickets-103262336428
+
- date: [2020-05-04, 2020-05-08]
country: www
city: streaming
@@ -29,7 +74,7 @@
speaker: jpetazzo
title: Intensive Docker and Kubernetes
attend: https://www.eventbrite.com/e/ardan-labs-live-worldwide-march-30-april-2-2020-tickets-100331129108#
- slides: https://https://2020-03-ardan.container.training/
+ slides: https://2020-03-ardan.container.training/
- date: 2020-03-06
country: uk
diff --git a/slides/k8s/authn-authz.md b/slides/k8s/authn-authz.md
index 47fd3ea1..6d91dc51 100644
--- a/slides/k8s/authn-authz.md
+++ b/slides/k8s/authn-authz.md
@@ -1,6 +1,74 @@
# Authentication and authorization
-*And first, a little refresher!*
+- In this section, we will:
+
+ - define authentication and authorization
+
+ - explain how they are implemented in Kubernetes
+
+ - talk about tokens, certificates, service accounts, RBAC ...
+
+- But first: why do we need all this?
+
+---
+
+## The need for fine-grained security
+
+- The Kubernetes API should only be available for identified users
+
+ - we don't want "guest access" (except in very rare scenarios)
+
+ - we don't want strangers to use our compute resources, delete our apps ...
+
+ - our keys and passwords should not be exposed to the public
+
+- Users will often have different access rights
+
+ - cluster admin (similar to UNIX "root") can do everything
+
+ - developer might access specific resources, or a specific namespace
+
+ - supervision might have read only access to *most* resources
+
+---
+
+## Example: custom HTTP load balancer
+
+- Let's imagine that we have a custom HTTP load balancer for multiple apps
+
+- Each app has its own *Deployment* resource
+
+- By default, the apps are "sleeping" and scaled to zero
+
+- When a request comes in, the corresponding app gets woken up
+
+- After some inactivity, the app is scaled down again
+
+- This HTTP load balancer needs API access (to scale up/down)
+
+- What if *a wild vulnerability appears*?
+
+---
+
+## Consequences of vulnerability
+
+- If the HTTP load balancer has the same API access as we do:
+
+ *full cluster compromise (easy data leak, cryptojacking...)*
+
+- If the HTTP load balancer has `update` permissions on the Deployments:
+
+ *defacement (easy), MITM / impersonation (medium to hard)*
+
+- If the HTTP load balancer only has permission to `scale` the Deployments:
+
+ *denial-of-service*
+
+- All these outcomes are bad, but some are worse than others
+
+---
+
+## Definitions
- Authentication = verifying the identity of a person
@@ -147,7 +215,7 @@ class: extra-details
(if their key is compromised, or they leave the organization)
-- Option 1: re-create a new CA and re-issue everyone's certificates
+- Option 1: re-create a new CA and re-issue everyone's certificates
→ Maybe OK if we only have a few users; no way otherwise
@@ -631,7 +699,7 @@ class: extra-details
- Let's look for these in existing ClusterRoleBindings:
```bash
- kubectl get clusterrolebindings -o yaml |
+ kubectl get clusterrolebindings -o yaml |
grep -e kubernetes-admin -e system:masters
```
diff --git a/slides/k8s/csr-api.md b/slides/k8s/csr-api.md
index 47c83cac..fabf5c5f 100644
--- a/slides/k8s/csr-api.md
+++ b/slides/k8s/csr-api.md
@@ -132,11 +132,33 @@ For a user named `jean.doe`, we will have:
- ServiceAccount `jean.doe` in Namespace `users`
-- CertificateSigningRequest `users:jean.doe`
+- CertificateSigningRequest `user=jean.doe`
-- ClusterRole `users:jean.doe` giving read/write access to that CSR
+- ClusterRole `user=jean.doe` giving read/write access to that CSR
-- ClusterRoleBinding `users:jean.doe` binding ClusterRole and ServiceAccount
+- ClusterRoleBinding `user=jean.doe` binding ClusterRole and ServiceAccount
+
+---
+
+class: extra-details
+
+## About resource name constraints
+
+- Most Kubernetes identifiers and names are fairly restricted
+
+- They generally are DNS-1123 *labels* or *subdomains* (from [RFC 1123](https://tools.ietf.org/html/rfc1123))
+
+- A label is lowercase letters, numbers, dashes; can't start or finish with a dash
+
+- A subdomain is one or multiple labels separated by dots
+
+- Some resources have more relaxed constraints, and can be "path segment names"
+
+ (uppercase are allowed, as well as some characters like `#:?!,_`)
+
+- This includes RBAC objects (like Roles, RoleBindings...) and CSRs
+
+- See the [Identifiers and Names](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/identifiers.md) design document and the [Object Names and IDs](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#path-segment-names) documentation page for more details
---
@@ -153,7 +175,7 @@ For a user named `jean.doe`, we will have:
- Create the ServiceAccount, ClusterRole, ClusterRoleBinding for `jean.doe`:
```bash
- kubectl apply -f ~/container.training/k8s/users:jean.doe.yaml
+ kubectl apply -f ~/container.training/k8s/user=jean.doe.yaml
```
]
@@ -195,7 +217,13 @@ For a user named `jean.doe`, we will have:
- Add a new context using that identity:
```bash
- kubectl config set-context jean.doe --user=token:jean.doe --cluster=kubernetes
+ kubectl config set-context jean.doe --user=token:jean.doe --cluster=`kubernetes`
+ ```
+ (Make sure to adapt the cluster name if yours is different!)
+
+- Use that context:
+ ```bash
+ kubectl config use-context jean.doe
```
]
@@ -216,7 +244,7 @@ For a user named `jean.doe`, we will have:
- Try to access "our" CertificateSigningRequest:
```bash
- kubectl get csr users:jean.doe
+ kubectl get csr user=jean.doe
```
(This should tell us "NotFound")
@@ -273,7 +301,7 @@ The command above generates:
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
- name: users:jean.doe
+ name: user=jean.doe
spec:
request: $(base64 -w0 < csr.pem)
usages:
@@ -324,12 +352,12 @@ The command above generates:
- Inspect the CSR:
```bash
- kubectl describe csr users:jean.doe
+ kubectl describe csr user=jean.doe
```
- Approve it:
```bash
- kubectl certificate approve users:jean.doe
+ kubectl certificate approve user=jean.doe
```
]
@@ -347,7 +375,7 @@ The command above generates:
- Retrieve the updated CSR object and extract the certificate:
```bash
- kubectl get csr users:jean.doe \
+ kubectl get csr user=jean.doe \
-o jsonpath={.status.certificate} \
| base64 -d > cert.pem
```
diff --git a/slides/k8s/healthchecks-more.md b/slides/k8s/healthchecks-more.md
index 8e6b51b2..16ea8cf1 100644
--- a/slides/k8s/healthchecks-more.md
+++ b/slides/k8s/healthchecks-more.md
@@ -154,9 +154,9 @@ It will use the default success threshold (1 successful attempt = alive).
.exercise[
-- Edit `rng-daemonset.yaml` and add the liveness probe
+- Edit `rng-deployment.yaml` and add the liveness probe
```bash
- vim rng-daemonset.yaml
+ vim rng-deployment.yaml
```
- Load the YAML for all the resources of DockerCoins:
diff --git a/slides/k8s/healthchecks.md b/slides/k8s/healthchecks.md
index ad31ab77..e0031783 100644
--- a/slides/k8s/healthchecks.md
+++ b/slides/k8s/healthchecks.md
@@ -286,4 +286,4 @@ If the Redis process becomes unresponsive, it will be killed.
???
:EN:- Using healthchecks to improve availability
-:FR:- Utiliser des *healthchecks* pour amémliorer la disponibilité
+:FR:- Utiliser des *healthchecks* pour améliorer la disponibilité
diff --git a/slides/k8s/helm-create-better-chart.md b/slides/k8s/helm-create-better-chart.md
index a96d46dc..992f7fd2 100644
--- a/slides/k8s/helm-create-better-chart.md
+++ b/slides/k8s/helm-create-better-chart.md
@@ -121,7 +121,7 @@ This creates a basic chart in the directory `helmcoins`.
helm install COMPONENT-NAME CHART-DIRECTORY
```
-- We can also use the following command, which is idempotent:
+- We can also use the following command, which is *idempotent*:
```bash
helm upgrade COMPONENT-NAME CHART-DIRECTORY --install
```
@@ -139,6 +139,28 @@ This creates a basic chart in the directory `helmcoins`.
---
+class: extra-details
+
+## "Idempotent"
+
+- Idempotent = that can be applied multiple times without changing the result
+
+ (the word is commonly used in maths and computer science)
+
+- In this context, this means:
+
+ - if the action (installing the chart) wasn't done, do it
+
+ - if the action was already done, don't do anything
+
+- Ideally, when such an action fails, it can be retried safely
+
+ (as opposed to, e.g., installing a new release each time we run it)
+
+- Other example: `kubectl -f some-file.yaml`
+
+---
+
## Checking what we've done
- Let's see if DockerCoins is working!
diff --git a/slides/k8s/helm-intro.md b/slides/k8s/helm-intro.md
index 6e200148..2db93989 100644
--- a/slides/k8s/helm-intro.md
+++ b/slides/k8s/helm-intro.md
@@ -18,6 +18,25 @@
---
+## CNCF graduation status
+
+- On April 30th 2020, Helm was the 10th project to *graduate* within the CNCF
+
+ .emoji[🎉]
+
+ (alongside Containerd, Prometheus, and Kubernetes itself)
+
+- This is an acknowledgement by the CNCF for projects that
+
+ *demonstrate thriving adoption, an open governance process,
+
+ and a strong commitment to community, sustainability, and inclusivity.*
+
+- See [CNCF announcement](https://www.cncf.io/announcement/2020/04/30/cloud-native-computing-foundation-announces-helm-graduation/)
+ and [Helm announcement](https://helm.sh/blog/celebrating-helms-cncf-graduation/)
+
+---
+
## Helm concepts
- `helm` is a CLI tool
@@ -427,6 +446,3 @@ All unspecified values will take the default values defined in the chart.
:FR:- Fonctionnement général de Helm
:FR:- Installer des composants via Helm
:FR:- Helm 2, Helm 3, et le *Helm Hub*
-
-
-:FR:- Comment
diff --git a/slides/k8s/kubercoins.md b/slides/k8s/kubercoins.md
index ea0ef31f..4cbcc57e 100644
--- a/slides/k8s/kubercoins.md
+++ b/slides/k8s/kubercoins.md
@@ -31,23 +31,17 @@
---
-## Cloning some repos
+## Cloning the repository
-- We will need two repositories:
+- We will need to clone the training repository
- - the first one has the "DockerCoins" demo app
+- It has the DockerCoins demo app ...
- - the second one has these slides, some scripts, more manifests ...
+- ... as well as these slides, some scripts, more manifests
.exercise[
-- Clone the kubercoins repository on `node1`:
- ```bash
- git clone https://github.com/jpetazzo/kubercoins
- ```
-
-
-- Clone the container.training repository as well:
+- Clone the repository on `node1`:
```bash
git clone https://@@GITREPO@@
```
@@ -62,9 +56,9 @@ Without further ado, let's start this application!
.exercise[
-- Apply all the manifests from the kubercoins repository:
+- Apply the manifest for dockercoins:
```bash
- kubectl apply -f kubercoins/
+ kubectl apply -f ~/container.training/k8s/dockercoins.yaml
```
]
@@ -247,4 +241,3 @@ graph will appear.
:EN:- Deploying a sample app with YAML manifests
:FR:- Lancer une application de démo avec du YAML
-
diff --git a/slides/k8s/kustomize.md b/slides/k8s/kustomize.md
index 84fa9d19..db3dd89d 100644
--- a/slides/k8s/kustomize.md
+++ b/slides/k8s/kustomize.md
@@ -8,45 +8,164 @@
- They are left untouched by Kustomize
-- Kustomize lets us define *overlays* that extend or change the resource files
+- Kustomize lets us define *kustomizations*
+
+- A *kustomization* is conceptually similar to a *layer*
+
+- Technically, a *kustomization* is a file named `kustomization.yaml`
+
+ (or a directory containing that files + additional files)
---
-## Differences with Helm
+## What's in a kustomization
-- Helm charts use placeholders `{{ like.this }}`
+- A kustomization can do any combination of the following:
-- Kustomize "bases" are standard Kubernetes YAML
+ - include other kustomizations
-- It is possible to use an existing set of YAML as a Kustomize base
+ - include Kubernetes resources defined in YAML files
-- As a result, writing a Helm chart is more work ...
+ - patch Kubernetes resources (change values)
-- ... But Helm charts are also more powerful; e.g. they can:
+ - add labels or annotations to all resources
- - use flags to conditionally include resources or blocks
+ - specify ConfigMaps and Secrets from literal values or local files
- - check if a given Kubernetes API group is supported
-
- - [and much more](https://helm.sh/docs/chart_template_guide/)
+(... And a few more advanced features that we won't cover today!)
---
-## Kustomize concepts
+## A simple kustomization
-- Kustomize needs a `kustomization.yaml` file
+This features a Deployment, Service, and Ingress (in separate files),
+and a couple of patches (to change the number of replicas and the hostname
+used in the Ingress).
-- That file can be a *base* or a *variant*
+```yaml
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+patchesStrategicMerge:
+- scale-deployment.yaml
+- ingress-hostname.yaml
+resources:
+- deployment.yaml
+- service.yaml
+- ingress.yaml
+```
-- If it's a *base*:
+On the next slide, let's see a more complex example ...
- - it lists YAML resource files to use
+---
-- If it's a *variant* (or *overlay*):
+```yaml
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+commonLabels:
+ add-this-to-all-my-resources: please
+patchesStrategicMerge:
+- prod-scaling.yaml
+- prod-healthchecks.yaml
+bases:
+- api/
+- frontend/
+- db/
+- github.com/example/app?ref=tag-or-branch
+resources:
+- ingress.yaml
+- permissions.yaml
+configMapGenerator:
+- name: appconfig
+ files:
+ - global.conf
+ - local.conf=prod.conf
+```
- - it refers to (at least) one *base*
+---
- - and some *patches*
+## Glossary
+
+- A *base* is a kustomization that is referred to by other kustomizations
+
+- An *overlay* is a kustomization that refers to other kustomizations
+
+- A kustomization can be both a base and an overlay at the same time
+
+ (a kustomization can refer to another, which can refer to a third)
+
+- A *patch* describes how to alter an existing resource
+
+ (e.g. to change the image in a Deployment; or scaling parameters; etc.)
+
+- A *variant* is the final outcome of applying bases + overlays
+
+(See the [kustomize glossary](https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md) for more definitions!)
+
+---
+
+## What Kustomize *cannot* do
+
+- By design, there are a number of things that Kustomize won't do
+
+- For instance:
+
+ - using command-line arguments or environment variables to generate a variant
+
+ - overlays can only *add* resources, not *remove* them
+
+- See the full list of [eschewed features](https://github.com/kubernetes-sigs/kustomize/blob/master/docs/eschewedFeatures.md) for more details
+
+---
+
+## Kustomize workflows
+
+- The Kustomize documentation proposes two different workflows
+
+- *Bespoke configuration*
+
+ - base and overlays managed by the same team
+
+- *Off-the-shelf configuration* (OTS)
+
+ - base and overlays managed by different teams
+
+ - base is regularly updated by "upstream" (e.g. a vendor)
+
+ - our overlays and patches should (hopefully!) apply cleanly
+
+ - we may regularly update the base, or use a remote base
+
+---
+
+## Remote bases
+
+- Kustomize can fetch remote bases using Hashicorp go-getter library
+
+- Examples:
+
+ github.com/jpetazzo/kubercoins (remote git repository)
+
+ github.com/jpetazzo/kubercoins?ref=kustomize (specific tag or branch)
+
+ https://releases.hello.io/k/1.0.zip (remote archive)
+
+ https://releases.hello.io/k/1.0.zip//some-subdir (subdirectory in archive)
+
+- See [hashicorp/go-getter URL format docs](https://github.com/hashicorp/go-getter#url-format) for more examples
+
+---
+
+## Managing `kustomization.yaml`
+
+- There are many ways to manage `kustomization.yaml` files, including:
+
+ - web wizards like [Replicated Ship](https://www.replicated.com/ship/)
+
+ - the `kustomize` CLI
+
+ - opening the file with our favorite text editor
+
+- Let's see these in action!
---
@@ -200,7 +319,62 @@
Note: it might take a minute or two for the worker to start.
+---
+
+## Working with the `kustomize` CLI
+
+- This is another way to get started
+
+- General workflow:
+
+ `kustomize create` to generate an empty `kustomization.yaml` file
+
+ `kustomize edit add resource` to add Kubernetes YAML files to it
+
+ `kustomize edit add patch` to add patches to said resources
+
+ `kustomize build | kubectl apply -f-` or `kubectl apply -k .`
+
+---
+
+## `kubectl apply -k`
+
+- Kustomize has been integrated in `kubectl`
+
+- The `kustomize` tool is still needed if we want to use `create`, `edit`, ...
+
+- Also, warning: `kubectl apply -k` is a slightly older version than `kustomize`!
+
+- In recent versions of `kustomize`, bases can be listed in `resources`
+
+ (and `kustomize edit add base` will add its arguments to `resources`)
+
+- `kubectl apply -k` requires bases to be listed in `bases`
+
+ (so after using `kustomize edit add base`, we need to fix `kustomization.yaml`)
+
+---
+
+## Differences with Helm
+
+- Helm charts use placeholders `{{ like.this }}`
+
+- Kustomize "bases" are standard Kubernetes YAML
+
+- It is possible to use an existing set of YAML as a Kustomize base
+
+- As a result, writing a Helm chart is more work ...
+
+- ... But Helm charts are also more powerful; e.g. they can:
+
+ - use flags to conditionally include resources or blocks
+
+ - check if a given Kubernetes API group is supported
+
+ - [and much more](https://helm.sh/docs/chart_template_guide/)
+
???
:EN:- Packaging and running apps with Kustomize
:FR:- *Packaging* d'applications avec Kustomize
+
diff --git a/slides/k8s/labels-annotations.md b/slides/k8s/labels-annotations.md
index 790841ba..a295c289 100644
--- a/slides/k8s/labels-annotations.md
+++ b/slides/k8s/labels-annotations.md
@@ -26,12 +26,12 @@
- Create a Deployment:
```bash
- kubectl create deployment web --image=nginx
+ kubectl create deployment clock --image=jpetazzo/clock
```
- Look at its annotations and labels:
```bash
- kubectl describe deployment web
+ kubectl describe deployment clock
```
]
diff --git a/slides/k8s/logs-cli.md b/slides/k8s/logs-cli.md
index 288d929a..93485ab2 100644
--- a/slides/k8s/logs-cli.md
+++ b/slides/k8s/logs-cli.md
@@ -45,7 +45,7 @@ Exactly what we need!
---
-## Installing Stern
+## Checking if Stern is installed
- Run `stern` (without arguments) to check if it's installed:
@@ -57,7 +57,17 @@ Exactly what we need!
stern pod-query [flags]
```
-- If it is not installed, the easiest method is to download a [binary release](https://github.com/wercker/stern/releases)
+- If it's missing, let's see how to install it
+
+---
+
+## Installing Stern
+
+- Stern is written in Go, and Go programs are usually shipped as a single binary
+
+- We just need to download that binary and put it in our `PATH`!
+
+- Binary releases are available [here](https://github.com/wercker/stern/releases) on GitHub
- The following commands will install Stern on a Linux Intel 64 bit machine:
```bash
@@ -66,7 +76,7 @@ Exactly what we need!
sudo chmod +x /usr/local/bin/stern
```
-- On OS X, just `brew install stern`
+- On macOS, we can also `brew install stern` or `port install stern`
diff --git a/slides/k8s/operators-design.md b/slides/k8s/operators-design.md
index d64eb22b..3e481556 100644
--- a/slides/k8s/operators-design.md
+++ b/slides/k8s/operators-design.md
@@ -1,3 +1,35 @@
+# Designing an operator
+
+- Once we understand CRDs and operators, it's tempting to use them everywhere
+
+- Yes, we can do (almost) everything with operators ...
+
+- ... But *should we?*
+
+- Very often, the answer is **“no!”**
+
+- Operators are powerful, but significantly more complex than other solutions
+
+---
+
+## When should we (not) use operators?
+
+- Operators are great if our app needs to react to cluster events
+
+ (nodes or pods going down, and requiring extensive reconfiguration)
+
+- Operators *might* be helpful to encapsulate complexity
+
+ (manipulate one single custom resource for an entire stack)
+
+- Operators are probably overkill if a Helm chart would suffice
+
+- That being said, if we really want to write an operator ...
+
+ Read on!
+
+---
+
## What does it take to write an operator?
- Writing a quick-and-dirty operator, or a POC/MVP, is easy
diff --git a/slides/k8s/operators.md b/slides/k8s/operators.md
index 46b471b8..d4b6c643 100644
--- a/slides/k8s/operators.md
+++ b/slides/k8s/operators.md
@@ -93,11 +93,11 @@ Examples:
- Representing and managing external resources
- (Example: [AWS Service Operator](https://operatorhub.io/operator/alpha/aws-service-operator.v0.0.1))
+ (Example: [AWS S3 Operator](https://operatorhub.io/operator/awss3-operator-registry))
- Managing complex cluster add-ons
- (Example: [Istio operator](https://operatorhub.io/operator/beta/istio-operator.0.1.6))
+ (Example: [Istio operator](https://operatorhub.io/operator/istio))
- Deploying and managing our applications' lifecycles
diff --git a/slides/k8s/podsecuritypolicy.md b/slides/k8s/podsecuritypolicy.md
index 8e0e9a0c..6542362a 100644
--- a/slides/k8s/podsecuritypolicy.md
+++ b/slides/k8s/podsecuritypolicy.md
@@ -287,7 +287,7 @@
- Try to create a Deployment:
```bash
- kubectl run testpsp2 --image=nginx
+ kubectl create deployment testpsp2 --image=nginx
```
- Look at existing resources:
@@ -350,7 +350,7 @@ We can get hints at what's happening by looking at the ReplicaSet and Events.
- Create a Deployment as well:
```bash
- kubectl run testpsp4 --image=nginx
+ kubectl create deployment testpsp4 --image=nginx
```
- Confirm that the Deployment is *not* creating any Pods:
diff --git a/slides/k8s/portworx.md b/slides/k8s/portworx.md
index 796d29e5..0a0badac 100644
--- a/slides/k8s/portworx.md
+++ b/slides/k8s/portworx.md
@@ -74,29 +74,78 @@
---
-## Portworx requirements
+## Installing Portworx
-- Kubernetes cluster ✔️
+- Portworx installation is relatively simple
-- Optional key/value store (etcd or Consul) ❌
+- ... But we made it *even simpler!*
-- At least one available block device ❌
+- We are going to use a YAML manifest that will take care of everything
+
+- Warning: this manifest is customized for a very specific setup
+
+ (like the VMs that we provide during workshops and training sessions)
+
+- It will probably *not work* If you are using a different setup
+
+ (like Docker Desktop, k3s, MicroK8S, Minikube ...)
---
-## The key-value store
+## The simplified Portworx installer
-- In the current version of Portworx (1.4) it is recommended to use etcd or Consul
+- The Portworx installation will take a few minutes
-- But Portworx also has beta support for an embedded key/value store
+- Let's start it, then we'll explain what happens behind the scenes
-- For simplicity, we are going to use the latter option
+.exercise[
- (but if we have deployed Consul or etcd, we can use that, too)
+- Install Portworx:
+ ```bash
+ kubectl apply -f ~/container.training/k8s/portworx.yaml
+ ```
+
+]
+
+
+
+*Note: this was tested with Kubernetes 1.18. Newer versions may or may not work.*
---
-## One available block device
+class: extra-details
+
+## What's in this YAML manifest?
+
+- Portworx installation itself, pre-configured for our setup
+
+- A default *Storage Class* using Portworx
+
+- A *Daemon Set* to create loop devices on each node of the cluster
+
+---
+
+class: extra-details
+
+## Portworx installation
+
+- The official way to install Portworx is to use [PX-Central](https://central.portworx.com/)
+
+ (this requires a free account)
+
+- PX-Central will ask us a few questions about our cluster
+
+ (Kubernetes version, on-prem/cloud deployment, etc.)
+
+- Using our answers, it will generate a YAML manifest that we can use
+
+---
+
+class: extra-details
+
+## Portworx storage configuration
+
+- Portworx needs at least one *block device*
- Block device = disk or partition on a disk
@@ -112,71 +161,41 @@
---
+class: extra-details
+
## Setting up a loop device
-- We are going to create a 10 GB (empty) file on each node
+- Our `portworx.yaml` manifest includes a *Daemon Set* that will:
-- Then make a loop device from it, to be used by Portworx
+ - create a 10 GB (empty) file on each node
-.exercise[
+ - load the `loop` module (if it's not already loaded)
-- Create a 10 GB file on each node:
- ```bash
- for N in $(seq 1 4); do ssh node$N sudo truncate --size 10G /portworx.blk; done
- ```
- (If SSH asks to confirm host keys, enter `yes` each time.)
+ - associate a loop device with the 10 GB file
-- Associate the file to a loop device on each node:
- ```bash
- for N in $(seq 1 4); do ssh node$N sudo losetup /dev/loop4 /portworx.blk; done
- ```
-
-]
-
----
-
-## Installing Portworx
-
-- To install Portworx, we need to go to https://install.portworx.com/
-
-- This website will ask us a bunch of questions about our cluster
-
-- Then, it will generate a YAML file that we should apply to our cluster
-
---
-
-- Or, we can just apply that YAML file directly (it's in `k8s/portworx.yaml`)
-
-.exercise[
-
-- Install Portworx:
- ```bash
- kubectl apply -f ~/container.training/k8s/portworx.yaml
- ```
-
-]
+- After these steps, we have a block device that Portworx can use
---
class: extra-details
-## Generating a custom YAML file
+## Implementation details
-If you want to generate a YAML file tailored to your own needs, the easiest
-way is to use https://install.portworx.com/.
+- The file is `/portworx.blk`
-FYI, this is how we obtained the YAML file used earlier:
-```
-KBVER=$(kubectl version -o json | jq -r .serverVersion.gitVersion)
-BLKDEV=/dev/loop4
-curl https://install.portworx.com/1.4/?kbver=$KBVER&b=true&s=$BLKDEV&c=px-workshop&stork=true&lh=true
-```
-If you want to use an external key/value store, add one of the following:
-```
-&k=etcd://`XXX`:2379
-&k=consul://`XXX`:8500
-```
-... where `XXX` is the name or address of your etcd or Consul server.
+ (it is a [sparse file](https://en.wikipedia.org/wiki/Sparse_file) created with `truncate`)
+
+- The loop device is `/dev/loop4`
+
+- This can be verified by running `sudo losetup`
+
+- The *Daemon Set* uses a privileged *Init Container*
+
+- We can check the logs of that container with:
+ ```bash
+ kubectl logs --selector=app=setup-loop4-for-portworx \
+ -c setup-loop4-for-portworx
+ ```
---
@@ -276,11 +295,9 @@ parameters:
priority_io: "high"
```
-- It says "use Portworx to create volumes"
+- It says "use Portworx to create volumes and keep 2 replicas of these volumes"
-- It tells Portworx to "keep 2 replicas of these volumes"
-
-- It marks the Storage Class as being the default one
+- The annotation makes this Storage Class the default one
---
@@ -323,7 +340,10 @@ spec:
schedulerName: stork
containers:
- name: postgres
- image: postgres:11
+ image: postgres:12
+ env:
+ - name: POSTGRES_HOST_AUTH_METHOD
+ value: trust
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres
@@ -401,14 +421,14 @@ autopilot prompt detection expects $ or # at the beginning of the line.
- Populate it with `pgbench`:
```bash
- pgbench -i -s 10 demo
+ pgbench -i demo
```
]
- The `-i` flag means "create tables"
-- The `-s 10` flag means "create 10 x 100,000 rows"
+- If you want more data in the test tables, add e.g. `-s 10` (to get 10x more rows)
---
@@ -428,11 +448,55 @@ autopilot prompt detection expects $ or # at the beginning of the line.
psql demo -c "select count(*) from pgbench_accounts"
```
-
+- Check that `pgbench_history` is currently empty:
+ ```bash
+ psql demo -c "select count(*) from pgbench_history"
+ ```
]
-(We should see a count of 1,000,000 rows.)
+---
+
+## Testing the load generator
+
+- Let's use `pgbench` to generate a few transactions
+
+.exercise[
+
+- Run `pgbench` for 10 seconds, reporting progress every second:
+ ```bash
+ pgbench -P 1 -T 10 demo
+ ```
+
+- Check the size of the history table now:
+ ```bash
+ psql demo -c "select count(*) from pgbench_history"
+ ```
+
+]
+
+Note: on small cloud instances, a typical speed is about 100 transactions/second.
+
+---
+
+## Generating transactions
+
+- Now let's use `pgbench` to generate more transactions
+
+- While it's running, we will disrupt the database server
+
+.exercise[
+
+- Run `pgbench` for 10 minutes, reporting progress every second:
+ ```bash
+ pgbench -P 1 -T 600 demo
+ ```
+
+- You can use a longer time period if you need more time to run the next steps
+
+
+
+]
---
@@ -522,15 +586,18 @@ By "disrupt" we mean: "disconnect it from the network".
```key ^J```
-->
-- Check the number of rows in the `pgbench_accounts` table:
+- Check how many transactions are now in the `pgbench_history` table:
```bash
- psql demo -c "select count(*) from pgbench_accounts"
+ psql demo -c "select count(*) from pgbench_history"
```
]
+If the 10-second test that we ran earlier gave e.g. 80 transactions per second,
+and we failed the node after 30 seconds, we should have about 2400 row in that table.
+
---
## Double-check that the pod has really moved
@@ -598,7 +665,7 @@ class: extra-details
- If we need to see what's going on with Portworx:
```
- PXPOD=$(kubectl -n kube-system get pod -l name=portworx -o json |
+ PXPOD=$(kubectl -n kube-system get pod -l name=portworx -o json |
jq -r .items[0].metadata.name)
kubectl -n kube-system exec $PXPOD -- /opt/pwx/bin/pxctl status
```
diff --git a/slides/k8s/setup-devel.md b/slides/k8s/setup-devel.md
new file mode 100644
index 00000000..8d31f295
--- /dev/null
+++ b/slides/k8s/setup-devel.md
@@ -0,0 +1,145 @@
+# Running a local development cluster
+
+- Let's review some options to run Kubernetes locally
+
+- There is no "best option", it depends what you value:
+
+ - ability to run on all platforms (Linux, Mac, Windows, other?)
+
+ - ability to run clusters with multiple nodes
+
+ - ability to run multiple clusters side by side
+
+ - ability to run recent (or even, unreleased) versions of Kubernetes
+
+ - availability of plugins
+
+ - etc.
+
+---
+
+## Docker Desktop
+
+- Available on Mac and Windows
+
+- Gives you one cluster with one node
+
+- Rather old version of Kubernetes
+
+- Very easy to use if you are already using Docker Desktop:
+
+ go to Docker Desktop preferences and enable Kubernetes
+
+- Ideal for Docker users who need good integration between both platforms
+
+---
+
+## [k3d](https://k3d.io/)
+
+- Based on [K3s](https://k3s.io/) by Rancher Labs
+
+- Requires Docker
+
+- Runs Kubernetes nodes in Docker containers
+
+- Can deploy multiple clusters, with multiple nodes, and multiple master nodes
+
+- As of June 2020, two versions co-exist: stable (1.7) and beta (3.0)
+
+- They have different syntax and options, this can be confusing
+
+ (but don't let that stop you!)
+
+---
+
+## k3d in action
+
+- Get `k3d` beta 3 binary on https://github.com/rancher/k3d/releases
+
+- Create a simple cluster:
+ ```bash
+ k3d create cluster petitcluster --update-kubeconfig
+ ```
+
+- Use it:
+ ```bash
+ kubectl config use-context k3d-petitcluster
+ ```
+
+- Create a more complex cluster with a custom version:
+ ```bash
+ k3d create cluster groscluster --update-kubeconfig \
+ --image rancher/k3s:v1.18.3-k3s1 --masters 3 --workers 5 --api-port 6444
+ ```
+
+ (note: API port seems to be necessary when running multiple clusters)
+
+---
+
+## [KinD](https://kind.sigs.k8s.io/)
+
+- Kubernetes-in-Docker
+
+- Requires Docker (obviously!)
+
+- Deploying a single node cluster using the latest version is simple:
+ ```bash
+ kind create cluster
+ ```
+
+- More advanced scenarios require writing a short [config file](https://kind.sigs.k8s.io/docs/user/quick-start#configuring-your-kind-cluster)
+
+ (to define multiple nodes, multiple master nodes, set Kubernetes versions ...)
+
+- Can deploy multiple clusters
+
+---
+
+## [Minikube](https://minikube.sigs.k8s.io/docs/)
+
+- The "legacy" option!
+
+ (note: this is not a bad thing, it means that it's very stable, has lots of plugins, etc.)
+
+- Supports many [drivers](https://minikube.sigs.k8s.io/docs/drivers/)
+
+ (HyperKit, Hyper-V, KVM, VirtualBox, but also Docker and many others)
+
+- Can deploy a single cluster; recent versions can deploy multiple nodes
+
+- Great option if you want a "Kubernetes first" experience
+
+ (i.e. if you don't already have Docker and/or don't want/need it)
+
+---
+
+## [MicroK8s](https://microk8s.io/)
+
+- Available on Linux, and since recently, on Mac and Windows as well
+
+- The Linux version is installed through Snap
+
+ (which is pre-installed on all recent versions of Ubuntu)
+
+- Also supports clustering (as in, multiple machines running MicroK8s)
+
+- DNS is not enabled by default; enable it with `microk8s enable dns`
+
+---
+
+## VM with custom install
+
+- Choose your own adventure!
+
+- Pick any Linux distribution!
+
+- Build your cluster from scratch or use a Kubernetes installer!
+
+- Discover exotic CNI plugins and container runtimes!
+
+- The only limit is yourself, and the time you are willing to sink in!
+
+???
+
+:EN:- Kubernetes options for local development
+:FR:- Installation de Kubernetes pour travailler en local
diff --git a/slides/k8s/setup-k8s.md b/slides/k8s/setup-k8s.md
deleted file mode 100644
index 994b8c11..00000000
--- a/slides/k8s/setup-k8s.md
+++ /dev/null
@@ -1,99 +0,0 @@
-# Setting up Kubernetes
-
-- How did we set up these Kubernetes clusters that we're using?
-
---
-
-
-
-- We used `kubeadm` on freshly installed VM instances running Ubuntu LTS
-
- 1. Install Docker
-
- 2. Install Kubernetes packages
-
- 3. Run `kubeadm init` on the first node (it deploys the control plane on that node)
-
- 4. Set up Weave (the overlay network)
-
- (that step is just one `kubectl apply` command; discussed later)
-
- 5. Run `kubeadm join` on the other nodes (with the token produced by `kubeadm init`)
-
- 6. Copy the configuration file generated by `kubeadm init`
-
-- Check the [prepare VMs README](https://@@GITREPO@@/blob/master/prepare-vms/README.md) for more details
-
----
-
-## `kubeadm` drawbacks
-
-- Doesn't set up Docker or any other container engine
-
-- Doesn't set up the overlay network
-
-- Doesn't set up multi-master (no high availability)
-
---
-
- (At least ... not yet! Though it's [experimental in 1.12](https://kubernetes.io/docs/setup/independent/high-availability/).)
-
---
-
-- "It's still twice as many steps as setting up a Swarm cluster 😕" -- Jérôme
-
----
-
-## Other deployment options
-
-- [AKS](https://azure.microsoft.com/services/kubernetes-service/):
- managed Kubernetes on Azure
-
-- [GKE](https://cloud.google.com/kubernetes-engine/):
- managed Kubernetes on Google Cloud
-
-- [EKS](https://aws.amazon.com/eks/),
- [eksctl](https://eksctl.io/):
- managed Kubernetes on AWS
-
-- [kops](https://github.com/kubernetes/kops):
- customizable deployments on AWS, Digital Ocean, GCE (beta), vSphere (alpha)
-
-- [minikube](https://kubernetes.io/docs/setup/minikube/),
- [kubespawn](https://github.com/kinvolk/kube-spawn),
- [Docker Desktop](https://docs.docker.com/docker-for-mac/kubernetes/),
- [kind](https://kind.sigs.k8s.io):
- for local development
-
-- [kubicorn](https://github.com/kubicorn/kubicorn),
- the [Cluster API](https://blogs.vmware.com/cloudnative/2019/03/14/what-and-why-of-cluster-api/):
- deploy your clusters declaratively, "the Kubernetes way"
-
----
-
-## Even more deployment options
-
-- If you like Ansible:
- [kubespray](https://github.com/kubernetes-incubator/kubespray)
-
-- If you like Terraform:
- [typhoon](https://github.com/poseidon/typhoon)
-
-- If you like Terraform and Puppet:
- [tarmak](https://github.com/jetstack/tarmak)
-
-- You can also learn how to install every component manually, with
- the excellent tutorial [Kubernetes The Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way)
-
- *Kubernetes The Hard Way is optimized for learning, which means taking the long route to ensure you understand each task required to bootstrap a Kubernetes cluster.*
-
-- There are also many commercial options available!
-
-- For a longer list, check the Kubernetes documentation:
-
- it has a great guide to [pick the right solution](https://kubernetes.io/docs/setup/#production-environment) to set up Kubernetes.
-
-???
-
-:EN:- Overview of the kubeadm installer
-:FR:- Survol de kubeadm
diff --git a/slides/k8s/setup-managed.md b/slides/k8s/setup-managed.md
index 05dedb66..6f8e3356 100644
--- a/slides/k8s/setup-managed.md
+++ b/slides/k8s/setup-managed.md
@@ -1,4 +1,4 @@
-# Installing a managed cluster
+# Deploying a managed cluster
*"The easiest way to install Kubernetes is to get someone
else to do it for you."
@@ -11,6 +11,8 @@ else to do it for you."
(the goal is to show the actual steps to get started)
+- The list is sorted alphabetically
+
- All the options mentioned here require an account
with a cloud provider
@@ -18,123 +20,6 @@ with a cloud provider
---
-## EKS (the old way)
-
-- [Read the doc](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html)
-
-- Create service roles, VPCs, and a bunch of other oddities
-
-- Try to figure out why it doesn't work
-
-- Start over, following an [official AWS blog post](https://aws.amazon.com/blogs/aws/amazon-eks-now-generally-available/)
-
-- Try to find the missing Cloud Formation template
-
---
-
-.footnote[(╯°□°)╯︵ ┻━┻]
-
----
-
-## EKS (the new way)
-
-- Install `eksctl`
-
-- Set the usual environment variables
-
- ([AWS_DEFAULT_REGION](https://docs.aws.amazon.com/general/latest/gr/rande.html#eks_region), AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY)
-
-- Create the cluster:
- ```bash
- eksctl create cluster
- ```
-
-- Wait 15-20 minutes (yes, it's sloooooooooooooooooow)
-
-- Add cluster add-ons
-
- (by default, it doesn't come with metrics-server, logging, etc.)
-
----
-
-## EKS (cleanup)
-
-- Delete the cluster:
- ```bash
- eksctl delete cluster
- ```
-
-- If you need to find the name of the cluster:
- ```bash
- eksctl get clusters
- ```
-
-.footnote[Note: the AWS documentation has been updated and now includes [eksctl instructions](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html).]
-
----
-
-## GKE (initial setup)
-
-- Install `gcloud`
-
-- Login:
- ```bash
- gcloud auth init
- ```
-
-- Create a "project":
- ```bash
- gcloud projects create my-gke-project
- gcloud config set project my-gke-project
- ```
-
-- Pick a [region](https://cloud.google.com/compute/docs/regions-zones/)
-
- (example: `europe-west1`, `us-west1`, ...)
-
----
-
-## GKE (create cluster)
-
-- Create the cluster:
- ```bash
- gcloud container clusters create my-gke-cluster --region us-west1 --num-nodes=2
- ```
-
- (without `--num-nodes` you might exhaust your IP address quota!)
-
-- The first time you try to create a cluster in a given project, you get an error
-
- - you need to enable the Kubernetes Engine API
- - the error message gives you a link
- - follow the link and enable the API (and billing)
-
(it's just a couple of clicks and it's instantaneous)
-
-- Wait a couple of minutes (yes, it's faaaaaaaaast)
-
-- The cluster comes with many add-ons
-
----
-
-## GKE (cleanup)
-
-- List clusters (if you forgot its name):
- ```bash
- gcloud container clusters list
- ```
-
-- Delete the cluster:
- ```bash
- gcloud container clusters delete my-gke-cluster --region us-west1
- ```
-
-- Delete the project (optional):
- ```bash
- gcloud projects delete my-gke-project
- ```
-
----
-
## AKS (initial setup)
- Install the Azure CLI
@@ -168,8 +53,6 @@ with a cloud provider
az aks get-credentials --resource-group my-aks-group --name my-aks-cluster
```
-- The cluster has useful components pre-installed, such as the metrics server
-
---
## AKS (cleanup)
@@ -190,6 +73,95 @@ with a cloud provider
---
+## AKS (notes)
+
+- The cluster has useful components pre-installed, such as the metrics server
+
+- There is also a product called [AKS Engine](https://github.com/Azure/aks-engine):
+
+ - leverages ARM (Azure Resource Manager) templates to deploy Kubernetes
+
+ - it's "the library used by AKS"
+
+ - fully customizable
+
+ - think of it as "half-managed" Kubernetes option
+
+---
+
+## Amazon EKS (the old way)
+
+- [Read the doc](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html)
+
+- Create service roles, VPCs, and a bunch of other oddities
+
+- Try to figure out why it doesn't work
+
+- Start over, following an [official AWS blog post](https://aws.amazon.com/blogs/aws/amazon-eks-now-generally-available/)
+
+- Try to find the missing Cloud Formation template
+
+--
+
+.footnote[(╯°□°)╯︵ ┻━┻]
+
+---
+
+## Amazon EKS (the new way)
+
+- Install `eksctl`
+
+- Set the usual environment variables
+
+ ([AWS_DEFAULT_REGION](https://docs.aws.amazon.com/general/latest/gr/rande.html#eks_region), AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY)
+
+- Create the cluster:
+ ```bash
+ eksctl create cluster
+ ```
+
+- Cluster can take a long time to be ready (15-20 minutes is typical)
+
+- Add cluster add-ons
+
+ (by default, it doesn't come with metrics-server, logging, etc.)
+
+---
+
+## Amazon EKS (cleanup)
+
+- Delete the cluster:
+ ```bash
+ eksctl delete cluster
+ ```
+
+- If you need to find the name of the cluster:
+ ```bash
+ eksctl get clusters
+ ```
+
+.footnote[Note: the AWS documentation has been updated and now includes [eksctl instructions](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html).]
+
+---
+
+## Amazon EKS (notes)
+
+- Convenient if you *have to* use AWS
+
+- Needs extra steps to be truly production-ready
+
+- [Versions tend to be outdated](https://twitter.com/jpetazzo/status/1252948707680686081)
+
+- The only officially supported pod network is the [Amazon VPC CNI plugin](https://docs.aws.amazon.com/eks/latest/userguide/pod-networking.html)
+
+ - integrates tightly with security groups and VPC networking
+
+ - not suitable for high density clusters (with many small pods on big nodes)
+
+ - other plugins [should still work](https://docs.aws.amazon.com/eks/latest/userguide/alternate-cni-plugins.html) but will require extra work
+
+---
+
## Digital Ocean (initial setup)
- Install `doctl`
@@ -242,15 +214,181 @@ with a cloud provider
---
+## GKE (initial setup)
+
+- Install `gcloud`
+
+- Login:
+ ```bash
+ gcloud auth init
+ ```
+
+- Create a "project":
+ ```bash
+ gcloud projects create my-gke-project
+ gcloud config set project my-gke-project
+ ```
+
+- Pick a [region](https://cloud.google.com/compute/docs/regions-zones/)
+
+ (example: `europe-west1`, `us-west1`, ...)
+
+---
+
+## GKE (create cluster)
+
+- Create the cluster:
+ ```bash
+ gcloud container clusters create my-gke-cluster --region us-west1 --num-nodes=2
+ ```
+
+ (without `--num-nodes` you might exhaust your IP address quota!)
+
+- The first time you try to create a cluster in a given project, you get an error
+
+ - you need to enable the Kubernetes Engine API
+ - the error message gives you a link
+ - follow the link and enable the API (and billing)
+
(it's just a couple of clicks and it's instantaneous)
+
+- Clutser should be ready in a couple of minutes
+
+---
+
+## GKE (cleanup)
+
+- List clusters (if you forgot its name):
+ ```bash
+ gcloud container clusters list
+ ```
+
+- Delete the cluster:
+ ```bash
+ gcloud container clusters delete my-gke-cluster --region us-west1
+ ```
+
+- Delete the project (optional):
+ ```bash
+ gcloud projects delete my-gke-project
+ ```
+
+---
+
+## GKE (notes)
+
+- Well-rounded product overall
+
+ (it used to be one of the best managed Kubernetes offerings available;
+ now that many other providers entered the game, that title is debatable)
+
+- The cluster comes with many add-ons
+
+- Versions lag a bit:
+
+ - latest minor version (e.g. 1.18) tends to be unsupported
+
+ - previous minor version (e.g. 1.17) supported through alpha channel
+
+ - previous versions (e.g. 1.14-1.16) supported
+
+---
+
+## Scaleway (initial setup)
+
+- After creating your account, make sure you set a password or get an API key
+
+ (by default, it uses email "magic links" to sign in)
+
+- Install `scw`
+
+ (you need [CLI v2](https://github.com/scaleway/scaleway-cli/tree/v2#Installation), which in beta as of May 2020)
+
+- Generate the CLI configuration with `scw init`
+
+ (it will prompt for your API key, or email + password)
+
+---
+
+## Scaleway (create cluster)
+
+- Create the cluster:
+ ```bash
+ k8s cluster create name=my-kapsule-cluster version=1.18.3 cni=cilium \
+ default-pool-config.node-type=DEV1-M default-pool-config.size=3
+ ```
+
+- After less than 5 minutes, cluster state will be `ready`
+
+ (check cluster status with e.g. `scw k8s cluster list` on a wide terminal
+)
+
+- Add connection information to your `.kube/config` file:
+ ```bash
+ scw k8s kubeconfig install `CLUSTERID`
+ ```
+
+ (the cluster ID is shown by `scw k8s cluster list`)
+
+---
+
+class: extra-details
+
+## Scaleway (automation)
+
+- If you want to obtain the cluster ID programmatically, this will do it:
+
+ ```bash
+ scw k8s cluster list
+ # or
+ CLUSTERID=$(scw k8s cluster list -o json | \
+ jq -r '.[] | select(.name="my-kapsule-cluster") | .id')
+ ```
+
+---
+
+## Scaleway (cleanup)
+
+- Get cluster ID (e.g. with `scw k8s cluster list`)
+
+- Delete the cluster:
+ ```bash
+ scw cluster delete cluster-id=$CLUSTERID
+ ```
+
+- Warning: as of May 2020, load balancers have to be deleted separately!
+
+---
+
+## Scaleway (notes)
+
+- The `create` command is a bit more complex than with other providers
+
+ (you must specify the Kubernetes version, CNI plugin, and node type)
+
+- To see available versions and CNI plugins, run `scw k8s version list`
+
+- As of May 2020, Kapsule supports:
+
+ - multiple CNI plugins, including: cilium, calico, weave, flannel
+
+ - Kubernetes versions 1.15 to 1.18
+
+ - multiple container runtimes, including: Docker, containerd, CRI-O
+
+- To see available node types and their price, check their [pricing page](
+https://www.scaleway.com/en/pricing/)
+
+---
+
## More options
- Alibaba Cloud
- [IBM Cloud](https://console.bluemix.net/docs/containers/cs_cli_install.html#cs_cli_install)
-- OVH
+- [Linode Kubernetes Engine (LKE)](https://www.linode.com/products/kubernetes/)
-- Scaleway
+- OVHcloud [Managed Kubernetes Service](https://www.ovhcloud.com/en/public-cloud/kubernetes/)
- ...
diff --git a/slides/k8s/setup-overview.md b/slides/k8s/setup-overview.md
new file mode 100644
index 00000000..e6cff5bc
--- /dev/null
+++ b/slides/k8s/setup-overview.md
@@ -0,0 +1,192 @@
+# Setting up Kubernetes
+
+- Kubernetes is made of many components that require careful configuration
+
+- Secure operation typically requires TLS certificates and a local CA
+
+ (certificate authority)
+
+- Setting up everything manually is possible, but rarely done
+
+ (except for learning purposes)
+
+- Let's do a quick overview of available options!
+
+---
+
+## Local development
+
+- Are you writing code that will eventually run on Kubernetes?
+
+- Then it's a good idea to have a development cluster!
+
+- Development clusters only need one node
+
+- This simplifies their setup a lot:
+
+ - pod networking doesn't even need CNI plugins, overlay networks, etc.
+
+ - they can be fully contained (no pun intended) in an easy-to-ship VM image
+
+ - some of the security aspects may be simplified (different threat model)
+
+- Examples: Docker Desktop, k3d, KinD, MicroK8s, Minikube
+
+ (some of these also support clusters with multiple nodes)
+
+---
+
+## Managed clusters
+
+- Many cloud providers and hosting providers offer "managed Kubernetes"
+
+- The deployment and maintenance of the cluster is entirely managed by the provider
+
+ (ideally, clusters can be spun up automatically through an API, CLI, or web interface)
+
+- Given the complexity of Kubernetes, this approach is *strongly recommended*
+
+ (at least for your first production clusters)
+
+- After working for a while with Kubernetes, you will be better equipped to decide:
+
+ - whether to operate it yourself or use a managed offering
+
+ - which offering or which distribution works best for you and your needs
+
+---
+
+## Managed clusters details
+
+- Pricing models differ from one provider to another
+
+ - nodes are generally charged at their usual price
+
+ - control plane may be free or incur a small nominal fee
+
+- Beyond pricing, there are *huge* differences in features between providers
+
+- The "major" providers are not always the best ones!
+
+---
+
+## Managed clusters differences
+
+- Most providers let you pick which Kubernetes version you want
+
+ - some providers offer up-to-date versions
+
+ - others lag significantly (sometimes by 2 or 3 minor versions)
+
+- Some providers offer multiple networking or storage options
+
+- Others will only support one, tied to their infrastructure
+
+ (changing that is in theory possible, but might be complex or unsupported)
+
+- Some providers let you configure or customize the control plane
+
+ (generally through Kubernetes "feature gates")
+
+---
+
+## Kubernetes distributions and installers
+
+- If you want to run Kubernetes yourselves, there are many options
+
+ (free, commercial, proprietary, open source ...)
+
+- Some of them are installers, while some are complete platforms
+
+- Some of them leverage other well-known deployment tools
+
+ (like Puppet, Terraform ...)
+
+- A good starting point to explore these options is this [guide](https://v1-16.docs.kubernetes.io/docs/setup/#production-environment)
+
+ (it defines categories like "managed", "turnkey" ...)
+
+---
+
+## kubeadm
+
+- kubeadm is a tool part of Kubernetes to facilitate cluster setup
+
+- Many other installers and distributions use it (but not all of them)
+
+- It can also be used by itself
+
+- Excellent starting point to install Kubernetes on your own machines
+
+ (virtual, physical, it doesn't matter)
+
+- It even supports highly available control planes, or "multi-master"
+
+ (this is more complex, though, because it introduces the need for an API load balancer)
+
+---
+
+## Manual setup
+
+- The resources below are mainly for educational purposes!
+
+- [Kubernetes The Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way) by Kelsey Hightower
+
+ - step by step guide to install Kubernetes on Google Cloud
+
+ - covers certificates, high availability ...
+
+ - *“Kubernetes The Hard Way is optimized for learning, which means taking the long route to ensure you understand each task required to bootstrap a Kubernetes cluster.”*
+
+- [Deep Dive into Kubernetes Internals for Builders and Operators](https://www.youtube.com/watch?v=3KtEAa7_duA)
+
+ - conference presentation showing step-by-step control plane setup
+
+ - emphasis on simplicity, not on security and availability
+
+---
+
+## About our training clusters
+
+- How did we set up these Kubernetes clusters that we're using?
+
+--
+
+- We used `kubeadm` on freshly installed VM instances running Ubuntu LTS
+
+ 1. Install Docker
+
+ 2. Install Kubernetes packages
+
+ 3. Run `kubeadm init` on the first node (it deploys the control plane on that node)
+
+ 4. Set up Weave (the overlay network) with a single `kubectl apply` command
+
+ 5. Run `kubeadm join` on the other nodes (with the token produced by `kubeadm init`)
+
+ 6. Copy the configuration file generated by `kubeadm init`
+
+- Check the [prepare VMs README](https://@@GITREPO@@/blob/master/prepare-vms/README.md) for more details
+
+---
+
+## `kubeadm` "drawbacks"
+
+- Doesn't set up Docker or any other container engine
+
+ (this is by design, to give us choice)
+
+- Doesn't set up the overlay network
+
+ (this is also by design, for the same reasons)
+
+- HA control plane requires [some extra steps](https://kubernetes.io/docs/setup/independent/high-availability/)
+
+- Note that HA control plane also requires setting up a specific API load balancer
+
+ (which is beyond the scope of kubeadm)
+
+???
+
+:EN:- Various ways to install Kubernetes
+:FR:- Survol des techniques d'installation de Kubernetes
diff --git a/slides/k8s/setup-selfhosted.md b/slides/k8s/setup-selfhosted.md
index f3c245fe..11ee661e 100644
--- a/slides/k8s/setup-selfhosted.md
+++ b/slides/k8s/setup-selfhosted.md
@@ -1,5 +1,15 @@
# Kubernetes distributions and installers
+- Sometimes, we need to run Kubernetes ourselves
+
+ (as opposed to "use a managed offering")
+
+- Beware: it takes *a lot of work* to set up and maintain Kubernetes
+
+- It might be necessary if you have specific security or compliance requirements
+
+ (e.g. national security for states that don't have a suitable domestic cloud)
+
- There are [countless](https://kubernetes.io/docs/setup/pick-right-solution/) distributions available
- We can't review them all
@@ -8,7 +18,7 @@
---
-## kops
+## [kops](https://github.com/kubernetes/kops)
- Deploys Kubernetes using cloud infrastructure
@@ -32,7 +42,7 @@
---
-## Kubespray
+## [kubespray](https://github.com/kubernetes-incubator/kubespray)
- Based on Ansible
@@ -78,15 +88,21 @@
## And many more ...
+- [AKS Engine](https://github.com/Azure/aks-engine)
+
- Docker Enterprise Edition
-- [AKS Engine](https://github.com/Azure/aks-engine)
+- [Lokomotive](https://github.com/kinvolk/lokomotive), leveraging Terraform and [Flatcar Linux](https://www.flatcar-linux.org/)
- Pivotal Container Service (PKS)
-- Tectonic by CoreOS
+- [Tarmak](https://github.com/jetstack/tarmak), leveraging Puppet and Terraform
-- etc.
+- Tectonic by CoreOS (now being integrated into Red Hat OpenShift)
+
+- [Typhoon](https://typhoon.psdn.io/), leveraging Terraform
+
+- VMware Tanzu Kubernetes Grid (TKG)
---
@@ -111,5 +127,5 @@
???
-:EN:- Various ways to set up Kubernetes
-:FR:- Différentes méthodes pour installer Kubernetes
+:EN:- Kubernetes distributions and installers
+:FR:- L'offre Kubernetes "on premises"
diff --git a/slides/k8s/volumes.md b/slides/k8s/volumes.md
index 2870877b..8e408c2f 100644
--- a/slides/k8s/volumes.md
+++ b/slides/k8s/volumes.md
@@ -404,7 +404,7 @@ spec:
initContainers:
- name: git
image: alpine
- command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/octocat/Spoon-Knife /www" ]
+ command: [ "sh", "-c", "apk add git && git clone https://github.com/octocat/Spoon-Knife /www" ]
volumeMounts:
- name: www
mountPath: /www/
@@ -417,9 +417,12 @@ spec:
.exercise[
-- Repeat the same operation as earlier
+- Create the pod:
+ ```bash
+ kubectl create -f ~/container.training/k8s/nginx-4-with-init.yaml
+ ```
- (try to send HTTP requests as soon as the pod comes up)
+- Try to send HTTP requests as soon as the pod comes up