From add83246b19f4c79a64ac1380da76ca408ecd613 Mon Sep 17 00:00:00 2001 From: Jan B Date: Fri, 27 Jul 2018 17:36:33 +0200 Subject: [PATCH 1/3] Moved cloud-provider docs to individual pages (no content change) --- .../en/config-options/add-ons/_index.md | 2 +- .../add-ons/ingress-controllers/_index.md | 2 +- .../add-ons/network-plugins/_index.md | 2 +- .../add-ons/user-defined-add-ons/_index.md | 2 +- .../config-options/cloud-providers/_index.md | 387 +----------------- .../cloud-providers/aws/_index.md | 55 +++ .../cloud-providers/azure/_index.md | 71 ++++ .../cloud-providers/custom/_index.md | 28 ++ .../cloud-providers/openstack/_index.md | 106 +++++ 9 files changed, 272 insertions(+), 383 deletions(-) create mode 100644 content/rke/v0.1.x/en/config-options/cloud-providers/aws/_index.md create mode 100644 content/rke/v0.1.x/en/config-options/cloud-providers/azure/_index.md create mode 100644 content/rke/v0.1.x/en/config-options/cloud-providers/custom/_index.md create mode 100644 content/rke/v0.1.x/en/config-options/cloud-providers/openstack/_index.md diff --git a/content/rke/v0.1.x/en/config-options/add-ons/_index.md b/content/rke/v0.1.x/en/config-options/add-ons/_index.md index 47c90019ef5..c03a3c31d9b 100644 --- a/content/rke/v0.1.x/en/config-options/add-ons/_index.md +++ b/content/rke/v0.1.x/en/config-options/add-ons/_index.md @@ -1,6 +1,6 @@ --- title: Add-Ons -weight: 250 +weight: 260 --- RKE supports pluggable add-ons. Add-ons are used to deploy several cluster components including: diff --git a/content/rke/v0.1.x/en/config-options/add-ons/ingress-controllers/_index.md b/content/rke/v0.1.x/en/config-options/add-ons/ingress-controllers/_index.md index bcd3ed5ee3a..b5d365fab82 100644 --- a/content/rke/v0.1.x/en/config-options/add-ons/ingress-controllers/_index.md +++ b/content/rke/v0.1.x/en/config-options/add-ons/ingress-controllers/_index.md @@ -1,6 +1,6 @@ --- title: Ingress Controllers -weight: 252 +weight: 262 --- By default, RKE deploys the nginx ingress controller on all schedulable nodes. diff --git a/content/rke/v0.1.x/en/config-options/add-ons/network-plugins/_index.md b/content/rke/v0.1.x/en/config-options/add-ons/network-plugins/_index.md index d956e788fa0..a450cc3b661 100644 --- a/content/rke/v0.1.x/en/config-options/add-ons/network-plugins/_index.md +++ b/content/rke/v0.1.x/en/config-options/add-ons/network-plugins/_index.md @@ -1,6 +1,6 @@ --- title: Network Plug-ins -weight: 251 +weight: 261 --- RKE supports the following network plug-ins that are deployed as add-ons: diff --git a/content/rke/v0.1.x/en/config-options/add-ons/user-defined-add-ons/_index.md b/content/rke/v0.1.x/en/config-options/add-ons/user-defined-add-ons/_index.md index 6aeb9c1f705..7301025d39e 100644 --- a/content/rke/v0.1.x/en/config-options/add-ons/user-defined-add-ons/_index.md +++ b/content/rke/v0.1.x/en/config-options/add-ons/user-defined-add-ons/_index.md @@ -1,6 +1,6 @@ --- title: User-Defined Add-Ons -weight: 253 +weight: 263 --- Besides the [network plug-in]({{< baseurl >}}/rke/v0.1.x/en/config-options/network-plugins/) and [ingress controllers]({{< baseurl >}}/rke/v0.1.x/en/config-options/ingress-controllers/), you can define any add-on that you want deployed after the Kubernetes cluster is deployed. diff --git a/content/rke/v0.1.x/en/config-options/cloud-providers/_index.md b/content/rke/v0.1.x/en/config-options/cloud-providers/_index.md index ed5c74546ee..aeced55a22d 100644 --- a/content/rke/v0.1.x/en/config-options/cloud-providers/_index.md +++ b/content/rke/v0.1.x/en/config-options/cloud-providers/_index.md @@ -1,385 +1,14 @@ --- title: Cloud Providers -weight: 245 +weight: 250 --- -RKE supports the ability to set your specific [cloud provider](https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/) for your Kubernetes cluster. There are specific cloud configurations for these cloud providers: +RKE supports the ability to set your specific [cloud provider](https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/) for your Kubernetes cluster. There are specific cloud configurations for these cloud providers. +To enable a cloud provider its name as well as any required configuration options must be provided under the `cloud_provider` directive in the cluster YML. -* [AWS](#aws) -* [Azure](#azure) -* [OpenStack](#openstack) -* [vSphere](#vsphere) +* [AWS]({{< baseurl >}}/rke/v0.1.x/en/config-options/cloud-providers/aws) +* [Azure]({{< baseurl >}}/rke/v0.1.x/en/config-options/cloud-providers/azure) +* [OpenStack]({{< baseurl >}}/rke/v0.1.x/en/config-options/cloud-providers/openstack) +* [vSphere]({{< baseurl >}}/rke/v0.1.x/en/config-options/cloud-providers/vsphere) -Outside of this list, RKE also supports the ability to handle any [custom cloud provider](#custom-cloud-provider). - -The `cloud_provider` directive must be filled out with minimally a name. For each cloud provider, there are different configuration options to enable the cloud provider in Kubernetes. - -### AWS - -To enable the AWS cloud provider, there are no configuration options. You only need to set the name as `aws`. In order to use the AWS cloud provider, all cluster nodes must have already been configured with an appropriate IAM role. - -```yaml -cloud_provider: - name: aws -``` - -#### IAM Requirements - -The nodes used in RKE that will be running the AWS cloud provider must have at least the following IAM policy. - -```json -{ - "Effect": "Allow", - "Action": "ec2:Describe*", - "Resource": "*" -} -``` - -In order to use Elastic Load Balancers (ELBs) and EBS with Kubernetes, the node(s) will need to have the an IAM role with appropriate access. - -##### Example Policy for IAM Role: - -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": "ec2:Describe*", - "Resource": "*" - }, - { - "Effect": "Allow", - "Action": "ec2:AttachVolume", - "Resource": "*" - }, - { - "Effect": "Allow", - "Action": "ec2:DetachVolume", - "Resource": "*" - }, - { - "Effect": "Allow", - "Action": ["elasticloadbalancing:*"], - "Resource": ["*"] - } - ] -} -``` - -### Azure - -To enable the Azure cloud provider, besides setting the name as `azure`, there are specific configuration options that must be set. Additionally, the Azure node name must also match the Kubernetes node name. - -```yaml -cloud_provider: - name: azure - azureCloudProvider: - aadClientId: xxxxxxxxx - aadClientSecret: xxxxxxxxx - location: xxxxxxxxx - resourceGroup: xxxxxxxxx - subnetName: xxxxxxxxx - subscriptionId: xxxxxxxxx - vnetName: xxxxxxxxx - tenantId: xxxxxxxxx - securityGroupName: xxxxxxxxx -``` - -#### Overriding the hostname - -Since the Azure node name must match the Kubernetes node name, you override the Kubernetes name on the node by setting the `hostname_override` for each node. If you do not set the `hostname_override`, the Kubernetes node name will be set as the `address`, which will cause the Azure cloud provider to fail. - -```yaml -nodes: - - address: x.x.x.x - hostname_override: azure-rke1 - user: ubuntu - role: - - controlplane - - etcd - - worker -``` - -#### Azure Configuration Options - -Besides the minimum set of options, there are many other options that are supported in RKE: - -| Azure Configuration Options | Type | Required | -|:----------------------------: |:------: |:---------:| -| tenantId | string | * | -| subscriptionId | string | * | -| aadClientId | string | * | -| aadClientSecret | string | * | -| cloud | string | | -| resourceGroup | string | | -| location | string | | -| vnetName | string | | -| vnetResourceGroup | string | | -| subnetName | string | | -| securityGroupName | string | | -| routeTableName | string | | -| primaryAvailabilitySetName | string | | -| vmType | string | | -| primaryScaleSetName | string | | -| aadClientCertPath | string | | -| aadClientCertPassword | string | | -| cloudProviderBackoff | bool | | -| cloudProviderBackoffRetries | int | | -| cloudProviderBackoffExponent | int | | -| cloudProviderBackoffDuration | int | | -| cloudProviderBackoffJitter | int | | -| cloudProviderRateLimit | bool | | -| cloudProviderRateLimitQPS | int | | -| cloudProviderRateLimitBucket | int | | -| useInstanceMetadata | bool | | -| useManagedIdentityExtension | bool | | -| maximumLoadBalancerRuleCount | int | | - -### Openstack - -To enable the Openstack cloud provider, besides setting the name as `openstack`, there are specific configuration options that must be set. The Openstack configuration options are grouped into different sections. - -```yaml -cloud_provider: - name: openstack - openstackCloudProvider: - global: - username: xxxxxxxxxxxxxx - password: xxxxxxxxxxxxxx - auth-url: https://1.2.3.4/identity/v3 - tenant-id: xxxxxxxxxxxxxx - domain-id: xxxxxxxxxxxxxx - load_balancer: - subnet-id: xxxxxxxxxxxxxx - block_storage: - ignore-volume-az: true - route: - router-id: xxxxxxxxxxxxxx - metadata: - search-order: xxxxxxxxxxxxxx -``` - -#### Overriding the hostname - -The OpenStack cloud provider uses the instance name (as determined from OpenStack metadata) as the name of the Kubernetes Node object, you must override the Kubernetes name on the node by setting the `hostname_override` for each node. If you do not set the `hostname_override`, the Kubernetes node name will be set as the `address`, which will cause the Openstack cloud provider to fail. - -#### Openstack Configuration Options - -The Openstack configuration options are divided into 5 groups. - -* Global -* Load Balancer -* Block Storage -* Route -* Metadata - -##### Global - -These are the options that are available under the `global` directive. - -| OpenStack's Global Configuration Options | Type | Required | -|:--------------------: |:------: |:---------:| -| auth_url | string | * | -| username | string | * | -| user-id | string | * | -| password | string | * | -| tenant-id | string | * | -| tenant-name | string | | -| trust-id | string | | -| domain-id | string | | -| domain-name | string | | -| region | string | | -| ca-file | string | | - -##### Load Balancer - -These are the options that are available under the `load_balancer` directive. - -| OpenStack's Load Balancer Configuration Options | Type | Required | -|:----------------------: |:------: |:---------:| -| lb-version | string | | -| use-octavia | bool | | -| subnet-id | string | | -| floating-network-id | string | | -| lb-method | string | | -| lb-provider | string | | -| manage-security-groups | bool | | -| create-monitor | bool | | -| monitor-delay | int | * if `create-monitor` is true | -| monitor-timeout | int | * if `create-monitor` is true | -| monitor-max-retries | int | * if `create-monitor` is true | - - -##### Block Storage - -These are the options that are available under the `block_storage` directive. - -| OpenStack's Block Storage Configuration Options | Type | Required | -|:--------------------: |:------: |:---------:| -| bs-version | string | | -| trust-device-path | bool | | -| ignore-volume-az | bool | | - -##### Route - -This is the option that is available under the `route` directive. - -| OpenStack's Route Configuration Option | Type | Required | -|:--------------------: |:------: |:---------:| -| router-id | string | | - -##### Metadata - -These are the options that are available under the `metadata` directive. - -| OpenStack's Metadata Configuration Options | Type | Required | -|:--------------------: |:------: |:---------:| -| search-order | string | | -| request-timeout | int | | - -For more information of Openstack configurations options please refer to the official Kubernetes [documentation](https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/#openstack). - -### vSphere - -To enable the vSphere cloud provider, besides setting the name as `vsphere`, there are specific configuration options that must be set. The vSphere configuration options are grouped into different sections. - -```yaml -cloud_provider: - name: vsphere - vsphereCloudProvider: - global: - user: user - password: pass - server: 1.2.3.4 - port: 22 - virtual_center: - 1.2.3.4: - user: test - password: test - port: test - 5.6.7.8: - user: test - password: test - port: test - workspace: - server: test.test.com - datacenter: test - folder: test - default-datastore: test - resourcepool-path: test - network: - public-network: xxxxxxxxxxxxxx - disk: - scsicontrollertype: xxxxxxxxxxxxxx -``` - -#### vSphere Configuration Options - -The vSphere configuration options are divided into 5 groups. - -* Global -* Virtual Center -* Workspace -* Network -* Disk - -##### Global - -These are the options that are available under the `global` directive. - -| vSphere's Global Configuration Options | Type | Required | -|:--------------------: |:------: |:---------:| -| user | string | | -| password | string | | -| server | string | | -| port | string | | -| insecure-flag | bool | | -| datacenter | string | | -| datacenters | string | | -| datastore | string | | -| working-dir | string | | -| soap-roundtrip-count | int | | -| vm-uuid | string | | -|vm-name |string | | - - -##### Virtual Center - -These are the options that are available under `virtual_center`, which is a dictionary of vCenters. Each vCenter is defined individually. - -```yaml -virtual_center: - : - user: test - password: test - port: test - : - user: test - password: test - port: test -``` - -For each `virtual_center`, these are the available configuration options to be used under the each virtual center. The virtual center's are separated from each other based on their IP. - -| vSphere's Virtual Center Configuration Options | Type | Required | -|:--------------------: |:------: |:---------:| -| user | string | * if `global` `user` is not set | -| password | string | * if `global` `password` is not set | -| port | string | | -| datacenters | string | | -| soap-roundtrip-count | int | | - -##### Workspace - -These are the options that are available under the `workspace` directive. - -| vSphere's Workspace Configuration Options | Type | Required | -|:--------------------: |:------: |:---------:| -| server | string | * | -| datacenter | string | * | -| folder | string | * | -| default-datastore | string | * | -| resourcepool-path | string | * | - -##### Network - -This is the option that is available under the `network` directive. - -| vSphere's Network Configuration Option | Type | Required | -|:--------------------: |:------: |:---------:| -| public-network | string | | - -##### Disk - -This is the option that is available under the `disk` directive. - -| vSphere's Disk Configuration Option | Type | Required | -|:--------------------: |:------: |:---------:| -| scsicontrollertype | string | | - -### Custom Cloud Provider - -If you want to enable a different cloud provider, RKE allows for custom cloud provider options. A name must be provided and the custom Cloud Provider options can be passed in as a multiline string in `customCloudProvider`. - -For example, in order to use the oVirt cloud provider with Kubernetes, here's the following cloud provider information: - -``` -[connection] -uri = https://localhost:8443/ovirt-engine/api -username = admin@internal -password = admin -``` - -To add this cloud config file to RKE, the `cloud_provider` would be need to be set. - -```yaml -cloud_provider: - name: ovirt - # Note the pipe as this is what indicates a multiline string - customCloudProvider: |- - [connection] - uri = https://localhost:8443/ovirt-engine/api - username = admin@internal - password = admin -``` +Outside of this list, RKE also supports the ability to handle any [custom cloud provider]({{< baseurl >}}/rke/v0.1.x/en/config-options/cloud-providers/custom). diff --git a/content/rke/v0.1.x/en/config-options/cloud-providers/aws/_index.md b/content/rke/v0.1.x/en/config-options/cloud-providers/aws/_index.md new file mode 100644 index 00000000000..639b77d85d1 --- /dev/null +++ b/content/rke/v0.1.x/en/config-options/cloud-providers/aws/_index.md @@ -0,0 +1,55 @@ +--- +title: AWS Cloud Provider +weight: 251 +--- + +To enable the AWS cloud provider, there are no configuration options. You only need to set the name as `aws`. In order to use the AWS cloud provider, all cluster nodes must have already been configured with an appropriate IAM role. + +```yaml +cloud_provider: + name: aws +``` + +## IAM Requirements + +The nodes used in RKE that will be running the AWS cloud provider must have at least the following IAM policy. + +```json +{ + "Effect": "Allow", + "Action": "ec2:Describe*", + "Resource": "*" +} +``` + +In order to use Elastic Load Balancers (ELBs) and EBS with Kubernetes, the node(s) will need to have the an IAM role with appropriate access. + +## Example Policy for IAM Role: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:Describe*", + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "ec2:AttachVolume", + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "ec2:DetachVolume", + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": ["elasticloadbalancing:*"], + "Resource": ["*"] + } + ] +} +``` diff --git a/content/rke/v0.1.x/en/config-options/cloud-providers/azure/_index.md b/content/rke/v0.1.x/en/config-options/cloud-providers/azure/_index.md new file mode 100644 index 00000000000..ddbe3e1f560 --- /dev/null +++ b/content/rke/v0.1.x/en/config-options/cloud-providers/azure/_index.md @@ -0,0 +1,71 @@ +--- +title: Azure Cloud Provider +weight: 252 +--- + +To enable the Azure cloud provider, besides setting the name as `azure`, there are specific configuration options that must be set. Additionally, the Azure node name must also match the Kubernetes node name. + +```yaml +cloud_provider: + name: azure + azureCloudProvider: + aadClientId: xxxxxxxxx + aadClientSecret: xxxxxxxxx + location: xxxxxxxxx + resourceGroup: xxxxxxxxx + subnetName: xxxxxxxxx + subscriptionId: xxxxxxxxx + vnetName: xxxxxxxxx + tenantId: xxxxxxxxx + securityGroupName: xxxxxxxxx +``` + +## Overriding the hostname + +Since the Azure node name must match the Kubernetes node name, you override the Kubernetes name on the node by setting the `hostname_override` for each node. If you do not set the `hostname_override`, the Kubernetes node name will be set as the `address`, which will cause the Azure cloud provider to fail. + +```yaml +nodes: + - address: x.x.x.x + hostname_override: azure-rke1 + user: ubuntu + role: + - controlplane + - etcd + - worker +``` + +## Azure Configuration Options + +Besides the minimum set of options, there are many other options that are supported in RKE: + +| Azure Configuration Options | Type | Required | +|:----------------------------: |:------: |:---------:| +| tenantId | string | * | +| subscriptionId | string | * | +| aadClientId | string | * | +| aadClientSecret | string | * | +| cloud | string | | +| resourceGroup | string | | +| location | string | | +| vnetName | string | | +| vnetResourceGroup | string | | +| subnetName | string | | +| securityGroupName | string | | +| routeTableName | string | | +| primaryAvailabilitySetName | string | | +| vmType | string | | +| primaryScaleSetName | string | | +| aadClientCertPath | string | | +| aadClientCertPassword | string | | +| cloudProviderBackoff | bool | | +| cloudProviderBackoffRetries | int | | +| cloudProviderBackoffExponent | int | | +| cloudProviderBackoffDuration | int | | +| cloudProviderBackoffJitter | int | | +| cloudProviderRateLimit | bool | | +| cloudProviderRateLimitQPS | int | | +| cloudProviderRateLimitBucket | int | | +| useInstanceMetadata | bool | | +| useManagedIdentityExtension | bool | | +| maximumLoadBalancerRuleCount | int | | diff --git a/content/rke/v0.1.x/en/config-options/cloud-providers/custom/_index.md b/content/rke/v0.1.x/en/config-options/cloud-providers/custom/_index.md new file mode 100644 index 00000000000..1cd581f75c7 --- /dev/null +++ b/content/rke/v0.1.x/en/config-options/cloud-providers/custom/_index.md @@ -0,0 +1,28 @@ +--- +title: Custom Cloud Provider +weight: 255 +--- + +If you want to enable a different cloud provider, RKE allows for custom cloud provider options. A name must be provided and the custom Cloud Provider options can be passed in as a multiline string in `customCloudProvider`. + +For example, in order to use the oVirt cloud provider with Kubernetes, here's the following cloud provider information: + +``` +[connection] +uri = https://localhost:8443/ovirt-engine/api +username = admin@internal +password = admin +``` + +To add this cloud config file to RKE, the `cloud_provider` would be need to be set. + +```yaml +cloud_provider: + name: ovirt + # Note the pipe as this is what indicates a multiline string + customCloudProvider: |- + [connection] + uri = https://localhost:8443/ovirt-engine/api + username = admin@internal + password = admin +``` diff --git a/content/rke/v0.1.x/en/config-options/cloud-providers/openstack/_index.md b/content/rke/v0.1.x/en/config-options/cloud-providers/openstack/_index.md new file mode 100644 index 00000000000..b268ff300de --- /dev/null +++ b/content/rke/v0.1.x/en/config-options/cloud-providers/openstack/_index.md @@ -0,0 +1,106 @@ +--- +title: Openstack Cloud Provider +weight: 253 +--- + +To enable the Openstack cloud provider, besides setting the name as `openstack`, there are specific configuration options that must be set. The Openstack configuration options are grouped into different sections. + +```yaml +cloud_provider: + name: openstack + openstackCloudProvider: + global: + username: xxxxxxxxxxxxxx + password: xxxxxxxxxxxxxx + auth-url: https://1.2.3.4/identity/v3 + tenant-id: xxxxxxxxxxxxxx + domain-id: xxxxxxxxxxxxxx + load_balancer: + subnet-id: xxxxxxxxxxxxxx + block_storage: + ignore-volume-az: true + route: + router-id: xxxxxxxxxxxxxx + metadata: + search-order: xxxxxxxxxxxxxx +``` + +## Overriding the hostname + +The OpenStack cloud provider uses the instance name (as determined from OpenStack metadata) as the name of the Kubernetes Node object, you must override the Kubernetes name on the node by setting the `hostname_override` for each node. If you do not set the `hostname_override`, the Kubernetes node name will be set as the `address`, which will cause the Openstack cloud provider to fail. + +## Openstack Configuration Options + +The Openstack configuration options are divided into 5 groups. + +* Global +* Load Balancer +* Block Storage +* Route +* Metadata + +### Global + +These are the options that are available under the `global` directive. + +| OpenStack's Global Configuration Options | Type | Required | +|:--------------------: |:------: |:---------:| +| auth_url | string | * | +| username | string | * | +| user-id | string | * | +| password | string | * | +| tenant-id | string | * | +| tenant-name | string | | +| trust-id | string | | +| domain-id | string | | +| domain-name | string | | +| region | string | | +| ca-file | string | | + +### Load Balancer + +These are the options that are available under the `load_balancer` directive. + +| OpenStack's Load Balancer Configuration Options | Type | Required | +|:----------------------: |:------: |:---------:| +| lb-version | string | | +| use-octavia | bool | | +| subnet-id | string | | +| floating-network-id | string | | +| lb-method | string | | +| lb-provider | string | | +| manage-security-groups | bool | | +| create-monitor | bool | | +| monitor-delay | int | * if `create-monitor` is true | +| monitor-timeout | int | * if `create-monitor` is true | +| monitor-max-retries | int | * if `create-monitor` is true | + + +### Block Storage + +These are the options that are available under the `block_storage` directive. + +| OpenStack's Block Storage Configuration Options | Type | Required | +|:--------------------: |:------: |:---------:| +| bs-version | string | | +| trust-device-path | bool | | +| ignore-volume-az | bool | | + +### Route + +This is the option that is available under the `route` directive. + +| OpenStack's Route Configuration Option | Type | Required | +|:--------------------: |:------: |:---------:| +| router-id | string | | + +### Metadata + +These are the options that are available under the `metadata` directive. + +| OpenStack's Metadata Configuration Options | Type | Required | +|:--------------------: |:------: |:---------:| +| search-order | string | | +| request-timeout | int | | + +For more information of Openstack configurations options please refer to the official Kubernetes [documentation](https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/#openstack). From 275815c0256df1d016f1a8a967f05d2b9da94e3d Mon Sep 17 00:00:00 2001 From: Jan B Date: Fri, 27 Jul 2018 17:37:08 +0200 Subject: [PATCH 2/3] Revamped vSphere cloud provider docs --- .../cloud-providers/vsphere/_index.md | 258 ++++++++++++++++++ src/img/rke/vsphere-advanced-parameters.png | Bin 0 -> 90229 bytes .../rke/vsphere-nodedriver-enable-uuid.png | Bin 0 -> 179221 bytes 3 files changed, 258 insertions(+) create mode 100644 content/rke/v0.1.x/en/config-options/cloud-providers/vsphere/_index.md create mode 100644 src/img/rke/vsphere-advanced-parameters.png create mode 100644 src/img/rke/vsphere-nodedriver-enable-uuid.png diff --git a/content/rke/v0.1.x/en/config-options/cloud-providers/vsphere/_index.md b/content/rke/v0.1.x/en/config-options/cloud-providers/vsphere/_index.md new file mode 100644 index 00000000000..7223bfc1456 --- /dev/null +++ b/content/rke/v0.1.x/en/config-options/cloud-providers/vsphere/_index.md @@ -0,0 +1,258 @@ +--- +title: vSphere Cloud Provider +weight: 254 +--- + +The [vSphere Cloud Provider](https://vmware.github.io/vsphere-storage-for-kubernetes/documentation/) interacts with VMware infrastructure (vCenter or standalone ESXi server) to provision and manage storage for persistent volumes in a Kubernetes cluster. + +When provisioning Kubernetes using RKE CLI or using [RKE clusters]({{< baseurl >}}/rancher/v2.x/en/cluster-provisioning/rke-clusters/) in Rancher, the vSphere Cloud Provider can be enabled by configuring the `cloud_provider` directive in the cluster YAML file. + +### Prerequisites + +1. You'll need to have credentials of a vCenter/ESXi user account with privileges allowing the cloud provider to interact with the vSphere infrastructure to provision storage. Refer to [this document](https://vmware.github.io/vsphere-storage-for-kubernetes/documentation/vcp-roles.html) to create and assign a role with the required permissions in vCenter. +2. VMware Tools must be running in the Guest OS for all nodes in the cluster. +3. All nodes must be configured with disk UUIDs. This is required so that attached VMDKs present a consistent UUID to the VM, allowing the disk to be mounted properly. See [Enabling Disk UUIDs](#enabling-disk-uuids-for-vsphere-vms). + +## Clusters provisioned with RKE CLI + +To enable the vSphere Cloud Provider in the cluster, you must add the top-level `cloud_provider` directive to the cluster configuration file, set the `name` property to `vsphere` and add the `vsphereCloudProvider` directive containing the configuration matching your infrastructure. See the [configuration reference](#configuration-reference) for the gory details. + +## Clusters provisioned with Rancher + +When provisioning clusters in Rancher using the [vSphere node driver]({{< baseurl >}}/rancher/v2.x/en/cluster-provisioning/rke-clusters/node-pools/vsphere/) or on pre-created [custom nodes]({{< baseurl >}}/rancher/v2.x/en/cluster-provisioning/rke-clusters/custom-nodes/) the cluster YAML file must be modified in order to enable the cloud provider. + +1. Log in to the Rancher UI as admin user. +2. Navigate to **Clusters** in the **Global** view. +3. Click **Add Cluster** and select the **vSphere** infrastructure provider. +4. Assign a **Cluster Name**. +5. Assign **Member Roles** as required. +6. Expand **Cluster Options** and configure as required. +7. Set **Cloud Provider** option to `Custom`. + + ![vsphere-node-driver-cloudprovider]({{< baseurl >}}/img/rancher/vsphere-node-driver-cloudprovider.png) + +8. Click on **Edit as YAML** +9. Insert the following top-level structure to the pre-populated cluster YAML. Note that the `name` *must* be set to `vsphere`. Refer to the [configuration reference](#configuration-reference) to learn about the properties of the `vsphereCloudProvider` directive. + + ```yaml + cloud_provider: + name: vsphere + vsphereCloudProvider: + [Insert provider configuration] + ``` + +10. Configure the **Node Pools** per your requirements while ensuring to use a node template that enables disk UUIDs for the VMs (See [Annex - Enable disk UUIDs for vSphere VMs]). +11. Click on **Create** to start provisioning the VMs and Kubernetes services. + +## Configuration Reference + +> **Note:** This documentation reflects the new vSphere Cloud Provider configuration schema introduced in Kubernetes v1.9 which differs from previous versions. + +The vSphere configuration options are divided into 5 groups: + +* global +* virtual_center +* workspace +* disk +* network + +### global + +The main purpose of global options is to be able to define a common set of configuration parameters that will be inherited by all vCenters defined under the `virtual_center` directive unless explicitely defined there. + +Accordingly, the `global` directive accepts the same configuration options that are available under the `virtual_center` directive. Additionally it accepts a single parameter that can only be specified here: + +| global Options | Type | Required | Description | +|:---------------:|:-------:|:---------:|:-----------------------------------------------------------------------------:| +| insecure-flag | boolean | | Set to **true** if the vCenter/ESXi uses a self-signed certificate. | + +___ + +**Example:** + +```yaml +(...) + global: + insecure-flag: true +``` + +### virtual_center + +This configuration directive specifies the vCenters that are managing the nodes in the cluster. You must define at least one vCenter/ESXi server. If the nodes span multiple vCenters then all must be defined. + +Each vCenter is defined by adding a new entry under the `virtual_center` directive with the vCenter IP or FQDN as the name. All required parameters must be provided for each vCenter unless they are already defined under the `global` directive. + +| virtual_center Options | Type | Required | Description | +|:----------------------:|:--------:|:---------:|:-----------------------------------------------------------------------------:| +| user | string | * | vCenter/ESXi user used to authenticate with this server. | +| password | string | * | User's password. | +| port | string | | Port to use to connect to this server. Defaults to 443. | +| datacenters | string | * | Comma-separated list of all datacenters in which cluster nodes are running in.| +| soap-roundtrip-count | uint | | Round tripper count for API requests to the vCenter (num retries = value - 1).| + + +> The following additional options (introduced in Kubernetes v1.11) are not yet supported in RKE. + +| virtual_center Options | Type | Required | Description | +|:----------------------:|:--------:|:---------:|:-----------------------------------------------------------------------------:| +| secret-name | string | | Name of secret resource containing credential key/value pairs. Can be specified in lieu of user/password parameters.| +| secret-namespace | string | | Namespace in which the secret resource was created in. | +| ca-file | string | | Path to CA cert file used to verify the vCenter certificate. | + +___ + +**Example:** + +```yaml +(...) + virtual_center: + 172.158.111.1: {} # This vCenter inherits all it's properties from global options + 172.158.110.2: # All required options are set explicitly + user: vc-user + password: othersecret + datacenters: eu-west-2 +``` + +### workspace + +This configuration group specifies how storage for volumes is created in vSphere. +The following configuration options are available: + +| workspace Options | Type | Required | Description | +|:----------------------:|:--------:|:---------:|:-----------------------------------------------------------------------------:| +| server | string | * | IP or FQDN of the vCenter/ESXi that should be used for creating the volumes. Must match one of the vCenters defined under the `virtual_center` directive.| +| datacenter | string | * | Name of the datacenter that should be used for creating volumes. For ESXi enter *ha-datacenter*.| +| folder | string | * | Path of folder in which to create dummy VMs used for volume provisioning (relative from the root of the datastore).| +| default-datastore | string | | Name of datastore used for volumes if neither datastore or storage policy are specified in the volume options of a PVC.| +| resourcepool-path | string | | Path of the vSphere resource pool that should be used to create dummy VMs. Applies only to policy-based provisioning of vSphere volumes. See [Storage policy based provisioning](https://vmware.github.io/vsphere-storage-for-kubernetes/documentation/policy-based-mgmt.html).| + +___ + +**Example:** + +```yaml +(...) + workspace: + server: 172.158.111.1 # matches IP of vCenter defined in the virtual_center block + datacenter: eu-west-1 + folder: k8s-dummy + default-datastore: ds-1 +``` + +### disk + +The following configuration options are available under the disk directive: + +| disk Options | Type | Required | Description | +|:--------------------:|:--------:|:---------:|:-----------------------------------------------------------------------------:| +| scsicontrollertype | string | | SCSI controller type to use when attaching block storage to VMs. Must be one of: *lsilogic-sas* or *pvscsi*. Default: *pvscsi*.| + +___ + +### network + +The following configuration options are available under the network directive: + +| network Options | Type | Required | Description | +|:-------------------:|:--------:|:---------:|:-----------------------------------------------------------------------------:| +| public-network | string | | Name of public **VM Network** to which the VMs in the cluster are connected. Used to determine public IP addresses of VMs.| + + +## Configuration Example + +Given the following: + +- VMs in the cluster are running in the same datacenter `eu-west-1` managed by the vCenter `vc.example.com`. +- The vCenter has a user `provisioner` with password `secret` with the required roles assigned, see [Prerequisites](#prerequisites). +- The vCenter has a datastore named `ds-1` which should be used to store the VMDKs for volumes. +- A `k8s-dummy` folder exists in the root of the datastore. + +The corresponding configuration for the provider would then be as follows: + +```yaml +(...) +cloud_provider: + name: vsphere + vsphereCloudProvider: + virtual_center: + vc.example.com: + user: provisioner + password: secret + datacenters: eu-west-1 + workspace: + server: vc.example.com + folder: k8s-dummy + default-datastore: ds-1 + datacenter: eu-west-1 + +``` + +## Annex + +### Enabling disk UUIDs for vSphere VMs + +Depending on whether you are provisioning the VMs using the [vSphere node driver]({{< baseurl >}}/rancher/v2.x/en/cluster-provisioning/rke-clusters/node-pools/vsphere) in Rancher or using your own scripts or third-party tools, there are different methods available to enable disk UUIDs for VMs. + +#### Using the Vsphere Console + +The required property can be set while creating or modifying VMs in the vSphere Console: + +1. For each VM navigate to the tab **VM Options** and click on **Edit Configuration**. +2. Add the parameter `disk.EnableUUID` with a value of **TRUE**. + + ![vsphere-advanced-parameters]({{< baseurl >}}/img/rke/vsphere-advanced-parameters.png) + +#### Using the GOVC CLI tool + +You can also modify properties of VMs with the [govc](https://github.com/vmware/govmomi/tree/master/govc) command-line tool to enable disk UUIDs: + +```sh +$ govc vm.change -vm -e disk.enableUUID=TRUE +``` + +#### Using Rancher node template + +When creating new clusters in Rancher using vSphere node templates, you can configure the template to automatically enable disk UUIDs for all VMs created for a cluster: + +1. Navigate to the **Node Templates** in the Rancher UI while logged in as admin user. + +2. Add or edit an existing vSphere node template. + +3. Under **Instance Options** click on **Add Parameter**. + +4. Enter `disk.enableUUID` as key with a value of **TRUE**. + + ![vsphere-nodedriver-enable-uuid]({{< baseurl >}}/img/rke/vsphere-nodedriver-enable-uuid.png) + +5. Click **Create** or **Save**. + +### Troubleshooting + +If you are experiencing issues while provisioning a cluster with enabled vSphere Cloud Provider or while creating vSphere volumes for your workloads, you should inspect the logs of the following K8s services: + +- controller-manager (Manages volumes in vCenter) +- kubelet: (Mounts vSphere volumes to pods) + +If your cluster is not configured with external [Cluster Logging]({{< baseurl >}}/rancher/v2.x/en/tools/logging/), you will need to SSH into nodes to get the logs of the `kube-controller-manager` (running on one of the control plane nodes) and the `kubelet` (pertaining to the node where the stateful pod has been scheduled). + +The easiest way to create a SSH session with a node is the Rancher CLI tool. + +1. [Configure the Rancher CLI]({{< baseurl >}}/rancher/v2.x/en/cli/) for your cluster. +2. Run the following command to get a shell to the corresponding nodes: + + ```sh +$ rancher ssh + ``` + +3. Inspect the logs of the controller-manager and kubelet containers looking for errors related to the vSphere cloud provider: + + ```sh + $ docker logs --since 15m kube-controller-manager + $ docker logs --since 15m kubelet + ``` + + +### Related Links + +- [vSphere Storage for Kubernetes](https://vmware.github.io/vsphere-storage-for-kubernetes/documentation/) +- [Kubernetes Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) diff --git a/src/img/rke/vsphere-advanced-parameters.png b/src/img/rke/vsphere-advanced-parameters.png new file mode 100644 index 0000000000000000000000000000000000000000..77c558ffc5dcce79f06895ce30a840375483a974 GIT binary patch literal 90229 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