Extending an AWS VPC cluster into an AWS Outpost
In OpenShift Container Platform version 4.14, you could install a cluster on Amazon Web Services (AWS) with compute nodes running in AWS Outposts as a Technology Preview. As of OpenShift Container Platform version 4.15, this installation method is no longer supported.
Instead, you can install a cluster on AWS into an existing VPC, and provision compute nodes on AWS Outposts as a postinstallation configuration task.
After following the instructions in "Installing a cluster on Amazon Web Services (AWS) into an existing Amazon Virtual Private Cloud (VPC)", you can create a compute machine set that deploys compute machines in AWS Outposts. AWS Outposts is an AWS edge compute service that enables using many features of a cloud-based AWS deployment with the reduced latency of an on-premise environment. For more information, see the "AWS Outposts documentation".
AWS Outposts on OpenShift Container Platform requirements and limitations
You can manage the resources on your AWS Outpost similarly to those on a cloud-based AWS cluster if you configure your OpenShift Container Platform cluster to accommodate several requirements and limitations.
You must accommodate the following requirements and limitations:
-
To extend an OpenShift Container Platform cluster on AWS into an Outpost, you must have installed the cluster into an existing Amazon Virtual Private Cloud (VPC).
-
The infrastructure of an Outpost is tied to an availability zone in an AWS region and uses a dedicated subnet. Edge compute machines deployed into an Outpost must use the Outpost subnet and the availability zone that the Outpost is tied to.
-
When the AWS Kubernetes cloud controller manager discovers an Outpost subnet, it attempts to create service load balancers in the Outpost subnet. AWS Outposts do not support running service load balancers. To prevent the cloud controller manager from creating unsupported services in the Outpost subnet, you must include the
kubernetes.io/cluster/unmanagedtag in the Outpost subnet configuration. This requirement is a workaround in OpenShift Container Platform version 4.22. For more information, see OCPBUGS-30041. -
OpenShift Container Platform clusters on AWS include the
gp3-csiandgp2-csistorage classes. These classes correspond to Amazon Elastic Block Store (EBS) gp3 and gp2 volumes. OpenShift Container Platform clusters use thegp3-csistorage class by default, but AWS Outposts does not support EBS gp3 volumes. -
This implementation uses the
node-role.kubernetes.io/outpoststaint to prevent spreading regular cluster workloads to the Outpost nodes. To schedule user workloads in the Outpost, you must specify a corresponding toleration in theDeploymentresource for your application. Reserving the AWS Outpost infrastructure for user workloads avoids additional configuration requirements, such as updating the default CSI togp2-csiso that it is compatible. -
To create a volume in the Outpost, the CSI driver requires the Outpost Amazon Resource Name (ARN). The driver uses the topology keys stored on the
CSINodeobjects to determine the Outpost ARN. To ensure that the driver uses the correct topology values, you must set the volume binding mode toWaitForConsumerand avoid setting allowed topologies on any new storage classes that you create. -
When you extend an AWS VPC cluster into an Outpost, you have two types of compute resources. The Outpost has edge compute nodes, while the VPC has cloud-based compute nodes. The cloud-based AWS Elastic Block volume cannot attach to Outpost edge compute nodes, and the Outpost volumes cannot attach to cloud-based compute nodes. As a result, you cannot use CSI snapshots to migrate applications that use persistent storage from cloud-based compute nodes to edge compute nodes or directly use the original persistent volume. To migrate persistent storage data for applications, you must perform a manual backup and restore operation.
-
AWS Outposts does not support AWS Network Load Balancers or AWS Classic Load Balancers. You must use AWS Application Load Balancers to enable load balancing for edge compute resources in the AWS Outposts environment. To provision an Application Load Balancer, you must use an Ingress resource and install the AWS Load Balancer Operator. If your cluster contains both edge and cloud-based compute instances that share workloads, additional configuration is required.
For more information, see "Using the AWS Load Balancer Operator in an AWS VPC cluster extended into an Outpost".
Additional resources
Obtaining information about your environment
To extend an AWS VPC cluster to your Outpost, you must provide information about your OpenShift Container Platform cluster and your Outpost environment. You use this information to complete network configuration tasks and configure a compute machine set that creates compute machines in your Outpost.
You can use command-line tools to gather the required details.
Obtaining information from your OpenShift Container Platform cluster
You can use the OpenShift CLI (oc) to obtain information from your OpenShift Container Platform cluster.
You might find it convenient to store some or all of these values as environment variables by using the export command.
Prerequisites
- You have installed an OpenShift Container Platform cluster into a custom VPC on AWS.
- You have access to the cluster using an account with
cluster-adminpermissions. - You have installed the OpenShift CLI (
oc).
Procedure
- List the infrastructure ID for the cluster by running the following command. Retain this value.
$ oc get -o jsonpath='{.status.infrastructureName}{"\n"}' infrastructures.config.openshift.io cluster
- Obtain details about the compute machine sets that the installation program created by running the following commands:
-
List the compute machine sets on your cluster:
$ oc get machinesets.machine.openshift.io -n openshift-machine-apiExample outputNAME DESIRED CURRENT READY AVAILABLE AGE<compute_machine_set_name_1> 1 1 1 1 55m<compute_machine_set_name_2> 1 1 1 1 55m -
Display the Amazon Machine Image (AMI) ID for one of the listed compute machine sets. Retain this value.
$ oc get machinesets.machine.openshift.io <compute_machine_set_name_1> \-n openshift-machine-api \-o jsonpath='{.spec.template.spec.providerSpec.value.ami.id}' -
Display the subnet ID for the AWS VPC cluster. Retain this value.
$ oc get machinesets.machine.openshift.io <compute_machine_set_name_1> \-n openshift-machine-api \-o jsonpath='{.spec.template.spec.providerSpec.value.subnet.id}'
-
Obtaining information from your AWS account
You can use the AWS CLI (aws) to obtain information from your AWS account.
You might find it convenient to store some or all of these values as environment variables by using the export command.
Prerequisites
- You have an AWS Outposts site with the required hardware setup complete.
- Your Outpost is connected to your AWS account.
- You have access to your AWS account by using the AWS CLI (
aws) as a user with permissions to perform the required tasks.
Procedure
- List the Outposts that are connected to your AWS account by running the following command:
$ aws outposts list-outposts
- Retain the following values from the output of the
aws outposts list-outpostscommand:-
The Outpost ID.
-
The Amazon Resource Name (ARN) for the Outpost.
-
The Outpost availability zone.
noteThe output of the
aws outposts list-outpostscommand includes two values related to the availability zone:AvailabilityZoneandAvailabilityZoneId. You use theAvailablilityZonevalue to configure a compute machine set that creates compute machines in your Outpost.
-
- Using the value of the Outpost ID, show the instance types that are available in your Outpost by running the following command. Retain the values of the available instance types.
$ aws outposts get-outpost-instance-types \--outpost-id <outpost_id_value>
- Using the value of the Outpost ARN, show the subnet ID for the Outpost by running the following command. Retain this value.
$ aws ec2 describe-subnets \--filters Name=outpost-arn,Values=<outpost_arn_value>
Configuring your network for your Outpost
To extend your VPC cluster into an Outpost, you must complete two network configuration tasks.
The following network configuration tasks must be completed:
- Change the Cluster Network MTU.
- Create a subnet in your Outpost.
Changing the cluster network MTU to support AWS Outposts
You might need to decrease the maximum transmission unit (MTU) value for the cluster network to support an AWS Outposts subnet. During installation, the MTU for the cluster network is detected automatically based on the MTU of the primary network interface of nodes in the cluster.
You cannot roll back an MTU value for nodes during the MTU migration process, but you can roll back the value after the MTU migration process completes.
The migration is disruptive and nodes in your cluster might be temporarily unavailable as the MTU update takes effect.
For more details about the migration process, including important service interruption considerations, see "Changing the MTU for the cluster network".
Prerequisites for changing the cluster network MTU
Before you change the cluster network maximum transmission unit (MTU), verify that you have the required access, tools, and network infrastructure to support the new MTU value.
Ensure that the following conditions are met before you begin:
- You have installed the OpenShift CLI (
oc). - You have access to the cluster using an account with
cluster-adminpermissions. - You have identified the target MTU for your cluster. The MTU for the OVN-Kubernetes network plugin must be set to
100less than the lowest hardware MTU value in your cluster. - If your nodes are physical machines, ensure that the cluster network and the connected network switches support jumbo frames.
- If your nodes are virtual machines (VMs), ensure that the hypervisor and the connected network switches support jumbo frames.
Check the current cluster MTU value
To ensure network stability and performance in a hybrid environment where part of your cluster is in the cloud and part is an on-premise environment, you can obtain the current maximum transmission unit (MTU) for the cluster network.
Procedure
-
To obtain the current MTU for the cluster network, enter the following command:
$ oc describe network.config clusterExample output...Status:Cluster Network:Cidr: 10.217.0.0/22Host Prefix: 23Cluster Network MTU: 1400Network Type: OVNKubernetesService Network:10.217.4.0/23...
Begin the MTU migration
Start the maximum transmission unit (MTU) migration by specifying the migration configuration for the cluster network and machine interfaces. The Machine Config Operator performs a rolling reboot of the nodes to prepare the cluster for the MTU change.
Procedure
-
To begin the MTU migration, specify the migration configuration by entering the following command. The Machine Config Operator performs a rolling reboot of the nodes in the cluster in preparation for the MTU change.
$ oc patch Network.operator.openshift.io cluster --type=merge --patch \'{"spec": { "migration": { "mtu": { "network": { "from": <overlay_from>, "to": <overlay_to> } , "machine": { "to" : <machine_to> } } } } }'where:
<overlay_from>- Specifies the current cluster network MTU value.
<overlay_to>- Specifies the target MTU for the cluster network. This value is set relative to the value of
<machine_to>. For OVN-Kubernetes, this value must be100less than the value of<machine_to>. <machine_to>- Specifies the MTU for the primary network interface on the underlying host network.
$ oc patch Network.operator.openshift.io cluster --type=merge --patch \'{"spec": { "migration": { "mtu": { "network": { "from": 1400, "to": 1000 } , "machine": { "to" : 1100} } } } }' -
As the Machine Config Operator updates machines in each machine config pool, the Operator reboots each node one by one. You must wait until all the nodes are updated. Check the machine config pool status by entering the following command:
$ oc get machineconfigpoolsA successfully updated node has the following status:
UPDATED=true,UPDATING=false,DEGRADED=false.noteBy default, the Machine Config Operator updates one machine per pool at a time, causing the total time the migration takes to increase with the size of the cluster.
Verify the machine configuration
Verify the machine configuration on your hosts to confirm that the maximum transmission unit (MTU) migration applied successfully. Checking the configuration state and system settings help ensures that the nodes use the correct migration script.
Procedure
- Confirm the status of the new machine configuration on the hosts:
-
To list the machine configuration state and the name of the applied machine configuration, enter the following command:
$ oc describe node | egrep "hostname|machineconfig"Example outputkubernetes.io/hostname=master-0machineconfiguration.openshift.io/currentConfig: rendered-master-c53e221d9d24e1c8bb6ee89dd3d8ad7bmachineconfiguration.openshift.io/desiredConfig: rendered-master-c53e221d9d24e1c8bb6ee89dd3d8ad7bmachineconfiguration.openshift.io/reason:machineconfiguration.openshift.io/state: Done -
Verify that the following statements are true:
- The value of
machineconfiguration.openshift.io/statefield isDone. - The value of the
machineconfiguration.openshift.io/currentConfigfield is equal to the value of themachineconfiguration.openshift.io/desiredConfigfield.
- The value of
-
To confirm that the machine config is correct, enter the following command:
$ oc get machineconfig <config_name> -o yaml | grep ExecStartwhere:
<config_name>- Specifies the name of the machine config from the
machineconfiguration.openshift.io/currentConfigfield.
The machine config must include the following update to the systemd configuration:
ExecStart=/usr/local/bin/mtu-migration.sh
-
Finalize the MTU migration
Finalize the MTU migration to apply the new maximum transmission unit (MTU) settings to the OVN-Kubernetes network plugin. This updates the cluster configuration and triggers a rolling reboot of the nodes to complete the process.
Procedure
-
To finalize the MTU migration, enter the following command for the OVN-Kubernetes network plugin:
$ oc patch Network.operator.openshift.io cluster --type=merge --patch \'{"spec": { "migration": null, "defaultNetwork":{ "ovnKubernetesConfig": { "mtu": <mtu> }}}}'where:
<mtu>- Specifies the new cluster network MTU that you specified with
<overlay_to>.
-
After finalizing the MTU migration, each machine config pool node is rebooted one by one. You must wait until all the nodes are updated. Check the machine config pool status by entering the following command:
$ oc get machineconfigpoolsA successfully updated node has the following status:
UPDATED=true,UPDATING=false,DEGRADED=false.
Verification
- Verify that the node in your cluster uses the MTU that you specified by entering the following command:
$ oc describe network.config cluster
Additional resources
Creating subnets for AWS edge compute services
You can automate creating subnets, route tables, and Carrier Gateways in AWS AWS Outposts to extend clusters into ultra-low-latency edge locations for edge workloads. Before you configure a machine set for edge compute nodes in your OpenShift Container Platform cluster, you must create a subnet in AWS Outposts.
You can use the provided CloudFormation template and create a CloudFormation stack. You can then use this stack to custom provision a subnet.
If you do not use the provided CloudFormation template to create your AWS infrastructure, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.
Prerequisites
- You configured an AWS account.
- You added your AWS keys and region to your local AWS profile by running
aws configure. - You have obtained the required information about your environment from your OpenShift Container Platform cluster, Outpost, and AWS account.
Procedure
-
Go to the section of the documentation named "CloudFormation template for the VPC subnet", and copy the syntax from the template. Save the copied template syntax as a YAML file on your local system. This template describes the VPC that your cluster requires.
-
Run the following command to deploy the CloudFormation template, which creates a stack of AWS resources that represent the VPC:
$ aws cloudformation create-stack --stack-name <stack_name> \--region ${CLUSTER_REGION} \--template-body file://<template>.yaml \--parameters \ParameterKey=VpcId,ParameterValue="${VPC_ID}" \ParameterKey=ClusterName,ParameterValue="${CLUSTER_NAME}" \ParameterKey=ZoneName,ParameterValue="${ZONE_NAME}" \ParameterKey=PublicRouteTableId,ParameterValue="${ROUTE_TABLE_PUB}" \ParameterKey=PublicSubnetCidr,ParameterValue="${SUBNET_CIDR_PUB}" \ParameterKey=PrivateRouteTableId,ParameterValue="${ROUTE_TABLE_PVT}" \ParameterKey=PrivateSubnetCidr,ParameterValue="${SUBNET_CIDR_PVT}" \ParameterKey=PrivateSubnetLabel,ParameterValue="private-outpost" \ParameterKey=PublicSubnetLabel,ParameterValue="public-outpost" \ParameterKey=OutpostArn,ParameterValue="${OUTPOST_ARN}"where
<stack_name>- Specifies the name for the CloudFormation stack, such as
cluster-<outpost_name>. <template>- Specifies the relative path and the name of the CloudFormation template YAML file that you saved.
${VPC_ID}- Specifies the VPC ID, which is the value
VpcIDin the output of the CloudFormation template for the VPC. ${CLUSTER_NAME}- Specifies the value of ClusterName to be used as a prefix of the new AWS resource names.
${ZONE_NAME}- Specifies the value of AWS Outposts name to create the subnets.
${ROUTE_TABLE_PUB}- Specifies the Public Route Table ID created in the
${VPC_ID}used to associate the public subnets on Outposts. Specify the public route table to associate the Outpost subnet created by this stack. ${SUBNET_CIDR_PUB}- Specifies a valid CIDR block that is used to create the public subnet. This block must be part of the VPC CIDR block
VpcCidr. ${OUTPOST_ARN}- Specifies the Amazon Resource Name (ARN) for the Outpost.
${SUBNET_CIDR_PVT}- Specifies a valid CIDR block that is used to create the private subnet. This block must be part of the VPC CIDR block
VpcCidr. ${ROUTE_TABLE_PVT}- Specifies the Private Route Table ID created in the
${VPC_ID}used to associate the private subnets on Outposts. Specify the private route table to associate the Outpost subnet created by this stack.
Example outputarn:aws:cloudformation:us-east-1:123456789012:stack/<stack_name>/dbedae40-820e-11eb-2fd3-12a48460849f
Verification
-
Confirm that the template components exist by running the following command:
$ aws cloudformation describe-stacks --stack-name <stack_name>After the
StackStatusdisplaysCREATE_COMPLETE, the output displays values for the following parameters:PublicSubnetId- The IDs of the public subnet created by the CloudFormation stack.
PrivateSubnetId- The IDs of the private subnet created by the CloudFormation stack.
Ensure that you provide these parameter values to the other CloudFormation templates that you run to create for your cluster.
CloudFormation template for the VPC subnet
Use the CloudFormation template to deploy the private and public subnets in a zone on AWS Outposts infrastructure. The template provisions an AWS::EC2::Subnet and associates it with a specific AWS Outposts and VPC route table to reduce latency.
AWSTemplateFormatVersion: 2010-09-09
Description: Template for Best Practice Subnets (Public and Private)
Parameters:
VpcId:
Description: VPC ID that comprises all the target subnets.
Type: String
AllowedPattern: ^(?:(?:vpc)(?:-[a-zA-Z0-9]+)?\b|(?:[0-9]{1,3}\.){3}[0-9]{1,3})$
ConstraintDescription: VPC ID must be with valid name, starting with vpc-.*.
ClusterName:
Description: Cluster name or prefix name to prepend the Name tag for each subnet.
Type: String
AllowedPattern: ".+"
ConstraintDescription: ClusterName parameter must be specified.
ZoneName:
Description: Zone Name to create the subnets, such as us-west-2-lax-1a.
Type: String
AllowedPattern: ".+"
ConstraintDescription: ZoneName parameter must be specified.
PublicRouteTableId:
Description: Public Route Table ID to associate the public subnet.
Type: String
AllowedPattern: ".+"
ConstraintDescription: PublicRouteTableId parameter must be specified.
PublicSubnetCidr:
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-4]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
Default: 10.0.128.0/20
Description: CIDR block for public subnet.
Type: String
PrivateRouteTableId:
Description: Private Route Table ID to associate the private subnet.
Type: String
AllowedPattern: ".+"
ConstraintDescription: PrivateRouteTableId parameter must be specified.
PrivateSubnetCidr:
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-4]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
Default: 10.0.128.0/20
Description: CIDR block for private subnet.
Type: String
PrivateSubnetLabel:
Default: "private"
Description: Subnet label to be added when building the subnet name.
Type: String
PublicSubnetLabel:
Default: "public"
Description: Subnet label to be added when building the subnet name.
Type: String
OutpostArn:
Default: ""
Description: OutpostArn when creating subnets on AWS Outpost.
Type: String
Conditions:
OutpostEnabled: !Not [!Equals [!Ref "OutpostArn", ""]]
Resources:
PublicSubnet:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref VpcId
CidrBlock: !Ref PublicSubnetCidr
AvailabilityZone: !Ref ZoneName
OutpostArn: !If [ OutpostEnabled, !Ref OutpostArn, !Ref "AWS::NoValue"]
Tags:
- Key: Name
Value: !Join ['-', [ !Ref ClusterName, !Ref PublicSubnetLabel, !Ref ZoneName]]
- Key: kubernetes.io/cluster/unmanaged
Value: true
PublicSubnetRouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTableId
PrivateSubnet:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref VpcId
CidrBlock: !Ref PrivateSubnetCidr
AvailabilityZone: !Ref ZoneName
OutpostArn: !If [ OutpostEnabled, !Ref OutpostArn, !Ref "AWS::NoValue"]
Tags:
- Key: Name
Value: !Join ['-', [!Ref ClusterName, !Ref PrivateSubnetLabel, !Ref ZoneName]]
- Key: kubernetes.io/cluster/unmanaged
Value: true
PrivateSubnetRouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnet
RouteTableId: !Ref PrivateRouteTableId
Outputs:
PublicSubnetId:
Description: Subnet ID of the public subnets.
Value:
!Join ["", [!Ref PublicSubnet]]
PrivateSubnetId:
Description: Subnet ID of the private subnets.
Value:
!Join ["", [!Ref PrivateSubnet]]
where:
kubernetes.io/cluster/unmanaged- You must include the
kubernetes.io/cluster/unmanagedtag in the public subnet configuration for AWS Outposts. kubernetes.io/cluster/unmanaged- You must include the
kubernetes.io/cluster/unmanagedtag in the private subnet configuration for AWS Outposts.