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