install-pks-vsphere-local
The deployment model on this page is still in alpha stage. If possible, Portworx by Everpure recommends you use Portworx install on TKGI on vSphere using shared datastores.
Pre-requisites
- This page assumes you have a running etcd cluster. If not, return to Install on TKGI.
Architecture
Below diagram gives an overview of the Portworx architecture for TKGI on vSphere using local datastores.
- Portworx runs as a Daemonset hence each Kubernetes minion/worker will have the Portworx daemon running.
- A Single Portworx instance on each ESXi host will create its disk on the configured Datastore. So if there are 2 worker VMs on a single ESXi, Portworx instance on the first worker VM will create and manage the disks. Subsequent Portworx instances on that ESXi host will still be part of the cluster and will function as storageless nodes.
- Portworx will aggregate all of the disks and form a single storage cluster. End users can carve PVCs (Persistent Volume Claims), PVs (Persistent Volumes) and Snapshots from this storage cluster.
- Portworx tracks and manages the disks that it creates. So in a failure event, if a new VM spins up, Portworx on the new VM will be able to attach to the same disk that was previously created by the node on the failed VM.

ESXi datastore preparation
On each ESXi host in the cluster, create a local datastore which is dedicated for Portworx storage. Use a common prefix for the names of the datastores. We will be giving this prefix during Portworx installation.
Portworx installation
- Create a secret.
- Deploy the Portworx spec.
Once you have the spec, proceed below.
Wipe Portworx installation
Below are the steps to wipe your entire Portworx installation on PKS.
- Run cluster-scoped wipe:
curl -fsL "https://install.portworx.com/px-wipe" | bash -s -- -T pks
- Go to each virtual machine and delete the additional vmdks Portworx created.
References
Secret for vSphere credentials
The Portworx spec
Things to replace in the below spec to match your environment:
-
PX etcd endpoint in the -k argument.
-
Cluster ID in the -c argument. Choose a unique cluster ID.
-
VSPHERE_VCENTER: Hostname of the vCenter server.
-
VSPHERE_DATASTORE_PREFIX: Prefix of the ESXi datastores that Portworx will use for storage.
apiVersion: v1kind: ServiceAccountmetadata:name: px-accountnamespace: kube-system---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: node-get-put-list-rolerules:- apiGroups: [""]resources: ["nodes"]verbs: ["watch", "get", "update", "list"]- apiGroups: [""]resources: ["pods"]verbs: ["delete", "get", "list"]- apiGroups: [""]resources: ["persistentvolumeclaims", "persistentvolumes"]verbs: ["get", "list"]- apiGroups: [""]resources: ["configmaps"]verbs: ["get", "list", "update", "create"]- apiGroups: ["extensions"]resources: ["podsecuritypolicies"]resourceNames: ["privileged"]verbs: ["use"]- apiGroups: ["portworx.io"]resources: ["volumeplacementstrategies"]verbs: ["get", "list"]---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:name: node-role-bindingsubjects:- kind: ServiceAccountname: px-accountnamespace: kube-systemroleRef:kind: ClusterRolename: node-get-put-list-roleapiGroup: rbac.authorization.k8s.io---kind: ServiceapiVersion: v1metadata:name: portworx-servicenamespace: kube-systemlabels:name: portworxspec:selector:name: portworxports:- name: px-apiprotocol: TCPport: 9001targetPort: 9001---apiVersion: apps/v1kind: DaemonSetmetadata:name: portworxnamespace: kube-systemspec:selector:matchLabels:name: portworxminReadySeconds: 0updateStrategy:type: RollingUpdaterollingUpdate:maxUnavailable: 1template:metadata:labels:name: portworxspec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: px/enabledoperator: NotInvalues:- "false"- key: node-role.kubernetes.io/masteroperator: DoesNotExisthostNetwork: truehostPID: truecontainers:- name: portworximage: portworx/oci-monitor:2.0.2.1imagePullPolicy: Alwaysargs:["-c", "px-pks-demo-1", "-k", "etcd:http://PUT-YOUR-ETCD-HOST:PUT-YOUR-ETCD-PORT", "-x", "kubernetes", "-s", "type=lazyzeroedthick", "--keep-px-up"]env:- name: "PX_TEMPLATE_VERSION"value: "v2"- name: "PRE-EXEC"value: 'if [ ! -x /bin/systemctl ]; then apt-get update; apt-get install -y systemd; fi'- name: VSPHERE_VCENTERvalue: pks-vcenter.k8s-demo.com- name: VSPHERE_VCENTER_PORTvalue: "443"- name: VSPHERE_DATASTORE_PREFIXvalue: "px-datastore"- name: VSPHERE_INSTALL_MODEvalue: "local"- name: VSPHERE_INSECUREvalue: "true"- name: VSPHERE_USERvalueFrom:secretKeyRef:name: px-vsphere-secretkey: VSPHERE_USER- name: VSPHERE_PASSWORDvalueFrom:secretKeyRef:name: px-vsphere-secretkey: VSPHERE_PASSWORDlivenessProbe:periodSeconds: 30initialDelaySeconds: 840 # allow image pull in slow networkshttpGet:host: 127.0.0.1path: /statusport: 9001readinessProbe:periodSeconds: 10httpGet:host: 127.0.0.1path: /healthport: 9015terminationMessagePath: "/tmp/px-termination-log"securityContext:privileged: truevolumeMounts:- name: dockersockmountPath: /var/run/docker.sock- name: etcpwxmountPath: /etc/pwx- name: optpwxmountPath: /opt/pwx- name: proc1nsmountmountPath: /host_proc/1/ns- name: sysdmountmountPath: /etc/systemd/systemrestartPolicy: AlwaysserviceAccountName: px-accountvolumes:- name: dockersockhostPath:path: /var/vcap/sys/run/docker/docker.sock- name: etcpwxhostPath:path: /var/vcap/store/etc/pwx- name: optpwxhostPath:path: /var/vcap/store/opt/pwx- name: proc1nsmounthostPath:path: /proc/1/ns- name: sysdmounthostPath:path: /etc/systemd/system---apiVersion: v1kind: ServiceAccountmetadata:name: portworx-pvc-controller-accountnamespace: kube-system---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: portworx-pvc-controller-rolerules:- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["create","delete","get","list","update","watch"]- apiGroups: [""]resources: ["persistentvolumes/status"]verbs: ["update"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "update", "watch"]- apiGroups: [""]resources: ["persistentvolumeclaims/status"]verbs: ["update"]- apiGroups: [""]resources: ["pods"]verbs: ["create", "delete", "get", "list", "watch"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["endpoints", "services"]verbs: ["create", "delete", "get"]- apiGroups: [""]resources: ["secrets"]verbs: ["get", "list"]- apiGroups: [""]resources: ["nodes"]verbs: ["get", "list"]- apiGroups: [""]resources: ["events"]verbs: ["watch"]- apiGroups: [""]resources: ["events"]verbs: ["create", "patch", "update"]- apiGroups: [""]resources: ["serviceaccounts"]verbs: ["get"]- apiGroups: [""]resources: ["configmaps"]verbs: ["get", "create", "update"]---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:name: portworx-pvc-controller-role-bindingsubjects:- kind: ServiceAccountname: portworx-pvc-controller-accountnamespace: kube-systemroleRef:kind: ClusterRolename: portworx-pvc-controller-roleapiGroup: rbac.authorization.k8s.io---apiVersion: apps/v1kind: Deploymentmetadata:annotations:scheduler.alpha.kubernetes.io/critical-pod: ""labels:tier: control-planename: portworx-pvc-controllernamespace: kube-systemspec:selector:matchLabels:name: portworx-pvc-controllerreplicas: 3strategy:rollingUpdate:maxSurge: 1maxUnavailable: 1type: RollingUpdatetemplate:metadata:annotations:scheduler.alpha.kubernetes.io/critical-pod: ""labels:name: portworx-pvc-controllertier: control-planespec:containers:- command:- kube-controller-manager- --leader-elect=true- --address=0.0.0.0- --controllers=persistentvolume-binder,persistentvolume-expander- --use-service-account-credentials=true- --leader-elect-resource-lock=configmapsimage: gcr.io/google_containers/kube-controller-manager-amd64:v1.10.4livenessProbe:failureThreshold: 8httpGet:host: 127.0.0.1path: /healthzport: 10252scheme: HTTPinitialDelaySeconds: 15timeoutSeconds: 15name: portworx-pvc-controller-managerresources:requests:cpu: 200mhostNetwork: trueaffinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: "name"operator: Invalues:- portworx-pvc-controllertopologyKey: "kubernetes.io/hostname"serviceAccountName: portworx-pvc-controller-account---apiVersion: v1kind: ConfigMapmetadata:name: stork-confignamespace: kube-systemdata:policy.cfg: |-{"kind": "Policy","apiVersion": "v1","extenders": [{"urlPrefix": "http://stork-service.kube-system.svc:8099","apiVersion": "v1beta1","filterVerb": "filter","prioritizeVerb": "prioritize","weight": 5,"enableHttps": false,"nodeCacheCapable": false}]}---apiVersion: v1kind: ServiceAccountmetadata:name: stork-accountnamespace: kube-system---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: stork-rolerules:- apiGroups: [""]resources: ["pods", "pods/exec"]verbs: ["get", "list", "delete", "create"]- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get", "list", "watch", "create", "delete"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "watch", "update"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["events"]verbs: ["list", "watch", "create", "update", "patch"]- apiGroups: ["stork.libopenstorage.org"]resources: ["rules"]verbs: ["get", "list"]- apiGroups: ["stork.libopenstorage.org"]resources: ["migrations", "clusterpairs", "groupvolumesnapshots"]verbs: ["get", "list", "watch", "update", "patch"]- apiGroups: ["apiextensions.k8s.io"]resources: ["customresourcedefinitions"]verbs: ["create", "get"]- apiGroups: ["volumesnapshot.external-storage.k8s.io"]resources: ["volumesnapshots"]verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]- apiGroups: ["volumesnapshot.external-storage.k8s.io"]resources: ["volumesnapshotdatas"]verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]- apiGroups: [""]resources: ["configmaps"]verbs: ["get", "create", "update"]- apiGroups: [""]resources: ["services"]verbs: ["get"]- apiGroups: [""]resources: ["nodes"]verbs: ["get", "list", "watch"]- apiGroups: ["*"]resources: ["deployments", "deployments/extensions"]verbs: ["list", "get", "watch", "patch", "update", "initialize"]- apiGroups: ["*"]resources: ["statefulsets", "statefulsets/extensions"]verbs: ["list", "get", "watch", "patch", "update", "initialize"]- apiGroups: ["*"]resources: ["*"]verbs: ["list", "get"]---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:name: stork-role-bindingsubjects:- kind: ServiceAccountname: stork-accountnamespace: kube-systemroleRef:kind: ClusterRolename: stork-roleapiGroup: rbac.authorization.k8s.io---kind: ServiceapiVersion: v1metadata:name: stork-servicenamespace: kube-systemspec:selector:name: storkports:- protocol: TCPport: 8099targetPort: 8099---apiVersion: apps/v1kind: Deploymentmetadata:annotations:scheduler.alpha.kubernetes.io/critical-pod: ""labels:tier: control-planename: storknamespace: kube-systemspec:selector:matchLabels:name: storkstrategy:rollingUpdate:maxSurge: 1maxUnavailable: 1type: RollingUpdatereplicas: 3template:metadata:annotations:scheduler.alpha.kubernetes.io/critical-pod: ""labels:name: storktier: control-planespec:containers:- command:- /stork- --driver=pxd- --verbose- --leader-elect=trueimagePullPolicy: Alwaysimage: openstorage/stork:2.1.1resources:requests:cpu: '0.1'name: storkhostPID: falseaffinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: "name"operator: Invalues:- storktopologyKey: "kubernetes.io/hostname"serviceAccountName: stork-account---kind: StorageClassapiVersion: storage.k8s.io/v1metadata:name: stork-snapshot-scprovisioner: stork-snapshot---apiVersion: v1kind: ServiceAccountmetadata:name: stork-scheduler-accountnamespace: kube-system---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: stork-scheduler-rolerules:- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "update"]- apiGroups: [""]resources: ["configmaps"]verbs: ["get"]- apiGroups: [""]resources: ["events"]verbs: ["create", "patch", "update"]- apiGroups: [""]resources: ["endpoints"]verbs: ["create"]- apiGroups: [""]resourceNames: ["kube-scheduler"]resources: ["endpoints"]verbs: ["delete", "get", "patch", "update"]- apiGroups: [""]resources: ["nodes"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["pods"]verbs: ["delete", "get", "list", "watch"]- apiGroups: [""]resources: ["bindings", "pods/binding"]verbs: ["create"]- apiGroups: [""]resources: ["pods/status"]verbs: ["patch", "update"]- apiGroups: [""]resources: ["replicationcontrollers", "services"]verbs: ["get", "list", "watch"]- apiGroups: ["app", "extensions"]resources: ["replicasets"]verbs: ["get", "list", "watch"]- apiGroups: ["apps"]resources: ["statefulsets"]verbs: ["get", "list", "watch"]- apiGroups: ["policy"]resources: ["poddisruptionbudgets"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["persistentvolumeclaims", "persistentvolumes"]verbs: ["get", "list", "watch"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:name: stork-scheduler-role-bindingsubjects:- kind: ServiceAccountname: stork-scheduler-accountnamespace: kube-systemroleRef:kind: ClusterRolename: stork-scheduler-roleapiGroup: rbac.authorization.k8s.io---apiVersion: apps/v1kind: Deploymentmetadata:labels:component: schedulertier: control-planename: stork-schedulername: stork-schedulernamespace: kube-systemspec:selector:matchLabels:component: schedulerreplicas: 3template:metadata:labels:component: schedulertier: control-planename: stork-schedulerspec: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-schedulerimage: gcr.io/google_containers/kube-scheduler-amd64:v1.10.4livenessProbe:httpGet:path: /healthzport: 10251initialDelaySeconds: 15name: stork-schedulerreadinessProbe:httpGet:path: /healthzport: 10251resources:requests:cpu: '0.1'affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: "name"operator: Invalues:- stork-schedulertopologyKey: "kubernetes.io/hostname"hostPID: falseserviceAccountName: stork-scheduler-account
Limitations
If a Portworx storage node goes down and cluster is still in quorum, a storageless node will not automatically replace the storage node.