Installing a cluster on user-provisioned infrastructure in AWS by using CloudFormation templates

In OKD version 4.6, you can install a cluster on Amazon Web Services (AWS) that uses infrastructure that you provide.

One way to create this infrastructure is to use the provided CloudFormation templates. You can modify the templates to customize your infrastructure or use the information that they contain to create AWS objects according to your company’s policies.

The steps for performing a user-provisioned infrastructure installation are provided as an example only. Installing a cluster with infrastructure you provide requires knowledge of the cloud provider and the installation process of OKD. Several CloudFormation templates are provided to assist in completing these steps or to help model your own. You are also free to create the required resources through other methods; the templates are just an example.

Prerequisites

  • You reviewed details about the OKD installation and update processes.

  • You configured an AWS account to host the cluster.

    If you have an AWS profile stored on your computer, it must not use a temporary session token that you generated while using a multi-factor authentication device. The cluster continues to use your current AWS credentials to create AWS resources for the entire life of the cluster, so you must use key-based, long-lived credentials. To generate appropriate keys, see Managing Access Keys for IAM Users in the AWS documentation. You can supply the keys when you run the installation program.

  • You downloaded the AWS CLI and installed it on your computer. See Install the AWS CLI Using the Bundled Installer (Linux, macOS, or Unix) in the AWS documentation.

  • If you use a firewall, you configured it to allow the sites that your cluster requires access to.

    Be sure to also review this site list if you are configuring a proxy.

  • If you do not allow the system to manage identity and access management (IAM), then a cluster administrator can manually create and maintain IAM credentials. Manual mode can also be used in environments where the cloud IAM APIs are not reachable.

Required AWS infrastructure components

To install OKD on user-provisioned infrastructure in Amazon Web Services (AWS), you must manually create both the machines and their supporting infrastructure.

For more information about the integration testing for different platforms, see the OpenShift Container Platform 4.x Tested Integrations page.

By using the provided CloudFormation templates, you can create stacks of AWS resources that represent the following components:

  • An AWS Virtual Private Cloud (VPC)

  • Networking and load balancing components

  • Security groups and roles

  • An OKD bootstrap node

  • OKD control plane nodes

  • An OKD compute node

Alternatively, you can manually create the components or you can reuse existing infrastructure that meets the cluster requirements. Review the CloudFormation templates for more details about how the components interrelate.

Cluster machines

You need AWS::EC2::Instance objects for the following machines:

  • A bootstrap machine. This machine is required during installation, but you can remove it after your cluster deploys.

  • Three control plane machines. The control plane machines are not governed by a machine set.

  • Compute machines. You must create at least two compute machines, which are also known as worker machines, during installation. These machines are not governed by a machine set.

You can use the following instance types for the cluster machines with the provided CloudFormation templates.

If m4 instance types are not available in your region, such as with eu-west-3, use m5 types instead.

Table 1. Instance types for machines
Instance typeBootstrapControl planeCompute

i3.large

x

m4.large

x

m4.xlarge

x

x

m4.2xlarge

x

x

m4.4xlarge

x

x

m4.8xlarge

x

x

m4.10xlarge

x

x

m4.16xlarge

x

x

m5.large

x

m5.xlarge

x

x

m5.2xlarge

x

x

m5.4xlarge

x

x

m5.8xlarge

x

x

m5.10xlarge

x

x

m5.16xlarge

x

x

c4.large

x

c4.xlarge

x

c4.2xlarge

x

x

c4.4xlarge

x

x

c4.8xlarge

x

x

r4.large

x

r4.xlarge

x

x

r4.2xlarge

x

x

r4.4xlarge

x

x

r4.8xlarge

x

x

r4.16xlarge

x

x

You might be able to use other instance types that meet the specifications of these instance types.

Certificate signing requests management

Because your cluster has limited access to automatic machine management when you use infrastructure that you provision, you must provide a mechanism for approving cluster certificate signing requests (CSRs) after installation. The kube-controller-manager only approves the kubelet client CSRs. The machine-approver cannot guarantee the validity of a serving certificate that is requested by using kubelet credentials because it cannot confirm that the correct machine issued the request. You must determine and implement a method of verifying the validity of the kubelet serving certificate requests and approving them.

Other infrastructure components

  • A VPC

  • DNS entries

  • Load balancers (classic or network) and listeners

  • A public and a private Route 53 zone

  • Security groups

  • IAM roles

  • S3 buckets

If you are working in a disconnected environment or use a proxy, you cannot reach the public IP addresses for EC2 and ELB endpoints. To reach these endpoints, you must create a VPC endpoint and attach it to the subnet that the clusters are using. Create the following endpoints:

  • ec2.<region>.amazonaws.com

  • elasticloadbalancing.<region>.amazonaws.com

  • s3.<region>.amazonaws.com

Required VPC components

You must provide a suitable VPC and subnets that allow communication to your machines.

ComponentAWS typeDescription

VPC

  • AWS::EC2::VPC

  • AWS::EC2::VPCEndpoint

You must provide a public VPC for the cluster to use. The VPC uses an endpoint that references the route tables for each subnet to improve communication with the registry that is hosted in S3.

Public subnets

  • AWS::EC2::Subnet

  • AWS::EC2::SubnetNetworkAclAssociation

Your VPC must have public subnets for between 1 and 3 availability zones and associate them with appropriate Ingress rules.

Internet gateway

  • AWS::EC2::InternetGateway

  • AWS::EC2::VPCGatewayAttachment

  • AWS::EC2::RouteTable

  • AWS::EC2::Route

  • AWS::EC2::SubnetRouteTableAssociation

  • AWS::EC2::NatGateway

  • AWS::EC2::EIP

You must have a public Internet gateway, with public routes, attached to the VPC. In the provided templates, each public subnet has a NAT gateway with an EIP address. These NAT gateways allow cluster resources, like private subnet instances, to reach the Internet and are not required for some restricted network or proxy scenarios.

Network access control

  • AWS::EC2::NetworkAcl

  • AWS::EC2::NetworkAclEntry

You must allow the VPC to access the following ports:

Port

Reason

80

Inbound HTTP traffic

443

Inbound HTTPS traffic

22

Inbound SSH traffic

1024 - 65535

Inbound ephemeral traffic

0 - 65535

Outbound ephemeral traffic

Private subnets

  • AWS::EC2::Subnet

  • AWS::EC2::RouteTable

  • AWS::EC2::SubnetRouteTableAssociation

Your VPC can have private subnets. The provided CloudFormation templates can create private subnets for between 1 and 3 availability zones. If you use private subnets, you must provide appropriate routes and tables for them.

Required DNS and load balancing components

Your DNS and load balancer configuration needs to use a public hosted zone and can use a private hosted zone similar to the one that the installation program uses if it provisions the cluster’s infrastructure. You must create a DNS entry that resolves to your load balancer. An entry for api.<cluster_name>.<domain> must point to the external load balancer, and an entry for api-int.<cluster_name>.<domain> must point to the internal load balancer.

The cluster also requires load balancers and listeners for port 6443, which are required for the Kubernetes API and its extensions, and port 22623, which are required for the Ignition config files for new machines. The targets will be the control plane nodes (also known as the master nodes). Port 6443 must be accessible to both clients external to the cluster and nodes within the cluster. Port 22623 must be accessible to nodes within the cluster.

ComponentAWS typeDescription

DNS

AWS::Route53::HostedZone

The hosted zone for your internal DNS.

etcd record sets

AWS::Route53::RecordSet

The registration records for etcd for your control plane machines.

Public load balancer

AWS::ElasticLoadBalancingV2::LoadBalancer

The load balancer for your public subnets.

External API server record

AWS::Route53::RecordSetGroup

Alias records for the external API server.

External listener

AWS::ElasticLoadBalancingV2::Listener

A listener on port 6443 for the external load balancer.

External target group

AWS::ElasticLoadBalancingV2::TargetGroup

The target group for the external load balancer.

Private load balancer

AWS::ElasticLoadBalancingV2::LoadBalancer

The load balancer for your private subnets.

Internal API server record

AWS::Route53::RecordSetGroup

Alias records for the internal API server.

Internal listener

AWS::ElasticLoadBalancingV2::Listener

A listener on port 22623 for the internal load balancer.

Internal target group

AWS::ElasticLoadBalancingV2::TargetGroup

The target group for the internal load balancer.

Internal listener

AWS::ElasticLoadBalancingV2::Listener

A listener on port 6443 for the internal load balancer.

Internal target group

AWS::ElasticLoadBalancingV2::TargetGroup

The target group for the internal load balancer.

Security groups

The control plane and worker machines require access to the following ports:

GroupTypeIP ProtocolPort range

MasterSecurityGroup

AWS::EC2::SecurityGroup

icmp

0

tcp

22

tcp

6443

tcp

22623

WorkerSecurityGroup

AWS::EC2::SecurityGroup

icmp

0

tcp

22

BootstrapSecurityGroup

AWS::EC2::SecurityGroup

tcp

22

tcp

19531

Control plane Ingress

The control plane machines require the following Ingress groups. Each Ingress group is a AWS::EC2::SecurityGroupIngress resource.

Ingress groupDescriptionIP protocolPort range

MasterIngressEtcd

etcd

tcp

2379- 2380

MasterIngressVxlan

Vxlan packets

udp

4789

MasterIngressWorkerVxlan

Vxlan packets

udp

4789

MasterIngressInternal

Internal cluster communication and Kubernetes proxy metrics

tcp

9000 - 9999

MasterIngressWorkerInternal

Internal cluster communication

tcp

9000 - 9999

MasterIngressKube

Kubernetes kubelet, scheduler and controller manager

tcp

10250 - 10259

MasterIngressWorkerKube

Kubernetes kubelet, scheduler and controller manager

tcp

10250 - 10259

MasterIngressIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

MasterIngressWorkerIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

Worker Ingress

The worker machines require the following Ingress groups. Each Ingress group is a AWS::EC2::SecurityGroupIngress resource.

Ingress groupDescriptionIP protocolPort range

WorkerIngressVxlan

Vxlan packets

udp

4789

WorkerIngressWorkerVxlan

Vxlan packets

udp

4789

WorkerIngressInternal

Internal cluster communication

tcp

9000 - 9999

WorkerIngressWorkerInternal

Internal cluster communication

tcp

9000 - 9999

WorkerIngressKube

Kubernetes kubelet, scheduler, and controller manager

tcp

10250

WorkerIngressWorkerKube

Kubernetes kubelet, scheduler, and controller manager

tcp

10250

WorkerIngressIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

WorkerIngressWorkerIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

Roles and instance profiles

You must grant the machines permissions in AWS. The provided CloudFormation templates grant the machines Allow permissions for the following AWS::IAM::Role objects and provide a AWS::IAM::InstanceProfile for each set of roles. If you do not use the templates, you can grant the machines the following broad permissions or the following individual permissions.

RoleEffectActionResource

Master

Allow

ec2:

Allow

elasticloadbalancing:

Allow

iam:PassRole

Allow

s3:GetObject

Worker

Allow

ec2:Describe

Bootstrap

Allow

ec2:Describe

Allow

ec2:AttachVolume

Allow

ec2:DetachVolume

Required AWS permissions

When you attach the AdministratorAccess policy to the IAM user that you create in Amazon Web Services (AWS), you grant that user all of the required permissions. To deploy all components of an OKD cluster, the IAM user requires the following permissions:

Required EC2 permissions for installation

  • tag:TagResources

  • tag:UntagResources

  • ec2:AllocateAddress

  • ec2:AssociateAddress

  • ec2:AuthorizeSecurityGroupEgress

  • ec2:AuthorizeSecurityGroupIngress

  • ec2:CopyImage

  • ec2:CreateNetworkInterface

  • ec2:AttachNetworkInterface

  • ec2:CreateSecurityGroup

  • ec2:CreateTags

  • ec2:CreateVolume

  • ec2:DeleteSecurityGroup

  • ec2:DeleteSnapshot

  • ec2:DeleteTags

  • ec2:DeregisterImage

  • ec2:DescribeAccountAttributes

  • ec2:DescribeAddresses

  • ec2:DescribeAvailabilityZones

  • ec2:DescribeDhcpOptions

  • ec2:DescribeImages

  • ec2:DescribeInstanceAttribute

  • ec2:DescribeInstanceCreditSpecifications

  • ec2:DescribeInstances

  • ec2:DescribeInternetGateways

  • ec2:DescribeKeyPairs

  • ec2:DescribeNatGateways

  • ec2:DescribeNetworkAcls

  • ec2:DescribeNetworkInterfaces

  • ec2:DescribePrefixLists

  • ec2:DescribeRegions

  • ec2:DescribeRouteTables

  • ec2:DescribeSecurityGroups

  • ec2:DescribeSubnets

  • ec2:DescribeTags

  • ec2:DescribeVolumes

  • ec2:DescribeVpcAttribute

  • ec2:DescribeVpcClassicLink

  • ec2:DescribeVpcClassicLinkDnsSupport

  • ec2:DescribeVpcEndpoints

  • ec2:DescribeVpcs

  • ec2:GetEbsDefaultKmsKeyId

  • ec2:ModifyInstanceAttribute

  • ec2:ModifyNetworkInterfaceAttribute

  • ec2:ReleaseAddress

  • ec2:RevokeSecurityGroupEgress

  • ec2:RevokeSecurityGroupIngress

  • ec2:RunInstances

  • ec2:TerminateInstances

Required permissions for creating network resources during installation

  • ec2:AssociateDhcpOptions

  • ec2:AssociateRouteTable

  • ec2:AttachInternetGateway

  • ec2:CreateDhcpOptions

  • ec2:CreateInternetGateway

  • ec2:CreateNatGateway

  • ec2:CreateRoute

  • ec2:CreateRouteTable

  • ec2:CreateSubnet

  • ec2:CreateVpc

  • ec2:CreateVpcEndpoint

  • ec2:ModifySubnetAttribute

  • ec2:ModifyVpcAttribute

If you use an existing VPC, your account does not require these permissions for creating network resources.

Required Elastic Load Balancing permissions for installation

  • elasticloadbalancing:AddTags

  • elasticloadbalancing:ApplySecurityGroupsToLoadBalancer

  • elasticloadbalancing:AttachLoadBalancerToSubnets

  • elasticloadbalancing:ConfigureHealthCheck

  • elasticloadbalancing:CreateListener

  • elasticloadbalancing:CreateLoadBalancer

  • elasticloadbalancing:CreateLoadBalancerListeners

  • elasticloadbalancing:CreateTargetGroup

  • elasticloadbalancing:DeleteLoadBalancer

  • elasticloadbalancing:DeregisterInstancesFromLoadBalancer

  • elasticloadbalancing:DeregisterTargets

  • elasticloadbalancing:DescribeInstanceHealth

  • elasticloadbalancing:DescribeListeners

  • elasticloadbalancing:DescribeLoadBalancerAttributes

  • elasticloadbalancing:DescribeLoadBalancers

  • elasticloadbalancing:DescribeTags

  • elasticloadbalancing:DescribeTargetGroupAttributes

  • elasticloadbalancing:DescribeTargetHealth

  • elasticloadbalancing:ModifyLoadBalancerAttributes

  • elasticloadbalancing:ModifyTargetGroup

  • elasticloadbalancing:ModifyTargetGroupAttributes

  • elasticloadbalancing:RegisterInstancesWithLoadBalancer

  • elasticloadbalancing:RegisterTargets

  • elasticloadbalancing:SetLoadBalancerPoliciesOfListener

Required IAM permissions for installation

  • iam:AddRoleToInstanceProfile

  • iam:CreateInstanceProfile

  • iam:CreateRole

  • iam:DeleteInstanceProfile

  • iam:DeleteRole

  • iam:DeleteRolePolicy

  • iam:GetInstanceProfile

  • iam:GetRole

  • iam:GetRolePolicy

  • iam:GetUser

  • iam:ListInstanceProfilesForRole

  • iam:ListRoles

  • iam:ListUsers

  • iam:PassRole

  • iam:PutRolePolicy

  • iam:RemoveRoleFromInstanceProfile

  • iam:SimulatePrincipalPolicy

  • iam:TagRole

If you have not created an elastic load balancer (ELB) in your AWS account, the IAM user also requires the iam:CreateServiceLinkedRole permission.

Required Route 53 permissions for installation

  • route53:ChangeResourceRecordSets

  • route53:ChangeTagsForResource

  • route53:CreateHostedZone

  • route53:DeleteHostedZone

  • route53:GetChange

  • route53:GetHostedZone

  • route53:ListHostedZones

  • route53:ListHostedZonesByName

  • route53:ListResourceRecordSets

  • route53:ListTagsForResource

  • route53:UpdateHostedZoneComment

Required S3 permissions for installation

  • s3:CreateBucket

  • s3:DeleteBucket

  • s3:GetAccelerateConfiguration

  • s3:GetBucketAcl

  • s3:GetBucketCors

  • s3:GetBucketLocation

  • s3:GetBucketLogging

  • s3:GetBucketObjectLockConfiguration

  • s3:GetBucketReplication

  • s3:GetBucketRequestPayment

  • s3:GetBucketTagging

  • s3:GetBucketVersioning

  • s3:GetBucketWebsite

  • s3:GetEncryptionConfiguration

  • s3:GetLifecycleConfiguration

  • s3:GetReplicationConfiguration

  • s3:ListBucket

  • s3:PutBucketAcl

  • s3:PutBucketTagging

  • s3:PutEncryptionConfiguration

S3 permissions that cluster Operators require

  • s3:DeleteObject

  • s3:GetObject

  • s3:GetObjectAcl

  • s3:GetObjectTagging

  • s3:GetObjectVersion

  • s3:PutObject

  • s3:PutObjectAcl

  • s3:PutObjectTagging

Required permissions to delete base cluster resources

  • autoscaling:DescribeAutoScalingGroups

  • ec2:DeleteNetworkInterface

  • ec2:DeleteVolume

  • elasticloadbalancing:DeleteTargetGroup

  • elasticloadbalancing:DescribeTargetGroups

  • iam:DeleteAccessKey

  • iam:DeleteUser

  • iam:ListAttachedRolePolicies

  • iam:ListInstanceProfiles

  • iam:ListRolePolicies

  • iam:ListUserPolicies

  • s3:DeleteObject

  • s3:ListBucketVersions

  • tag:GetResources

Required permissions to delete network resources

  • ec2:DeleteDhcpOptions

  • ec2:DeleteInternetGateway

  • ec2:DeleteNatGateway

  • ec2:DeleteRoute

  • ec2:DeleteRouteTable

  • ec2:DeleteSubnet

  • ec2:DeleteVpc

  • ec2:DeleteVpcEndpoints

  • ec2:DetachInternetGateway

  • ec2:DisassociateRouteTable

  • ec2:ReplaceRouteTableAssociation

If you use an existing VPC, your account does not require these permissions to delete network resources.

Additional IAM and S3 permissions that are required to create manifests

  • iam:CreateAccessKey

  • iam:CreateUser

  • iam:DeleteAccessKey

  • iam:DeleteUser

  • iam:DeleteUserPolicy

  • iam:GetUserPolicy

  • iam:ListAccessKeys

  • iam:PutUserPolicy

  • iam:TagUser

  • iam:GetUserPolicy

  • iam:ListAccessKeys

  • s3:PutBucketPublicAccessBlock

  • s3:GetBucketPublicAccessBlock

  • s3:PutLifecycleConfiguration

  • s3:HeadBucket

  • s3:ListBucketMultipartUploads

  • s3:AbortMultipartUpload

Optional permission for quota checks for installation

  • servicequotas:ListAWSDefaultServiceQuotas

Obtaining the installation program

Before you install OKD, download the installation file on a local computer.

Prerequisites

  • You have a computer that runs Linux or macOS, with 500 MB of local disk space

Procedure

  1. Download installer from https://github.com/openshift/okd/releases

    The installation program creates several files on the computer that you use to install your cluster. You must keep the installation program and the files that the installation program creates after you finish installing the cluster. Both files are required to delete the cluster.

    Deleting the files created by the installation program does not remove your cluster, even if the cluster failed during installation. To remove your cluster, complete the OKD uninstallation procedures for your specific cloud provider.

  2. Extract the installation program. For example, on a computer that uses a Linux operating system, run the following command:

    1. $ tar xvf openshift-install-linux.tar.gz
  3. From the Pull Secret page on the Red Hat OpenShift Cluster Manager site, download your installation pull secret as a .txt file. This pull secret allows you to authenticate with the services that are provided by the included authorities, including Quay.io, which serves the container images for OKD components.

    Using a pull secret from the Red Hat OpenShift Cluster Manager site is not required. You can use a pull secret for another private registry. Or, if you do not need the cluster to pull images from a private registry, you can use {"auths":{"fake":{"auth":"aWQ6cGFzcwo="}}} as the pull secret when prompted during the installation.

    If you do not use the pull secret from the Red Hat OpenShift Cluster Manager site:

    • Red Hat Operators are not available.

    • The Telemetry and Insights operators do not send data to Red Hat.

    • Content from the Red Hat Container Catalog registry, such as image streams and Operators, are not available.

Generating an SSH private key and adding it to the agent

If you want to perform installation debugging or disaster recovery on your cluster, you must provide an SSH key to both your ssh-agent and the installation program. You can use this key to access the bootstrap machine in a public cluster to troubleshoot installation issues.

In a production environment, you require disaster recovery and debugging.

You can use this key to SSH into the master nodes as the user core. When you deploy the cluster, the key is added to the core user’s ~/.ssh/authorized_keys list.

You must use a local key, not one that you configured with platform-specific approaches such as AWS key pairs.

On clusters running Fedora CoreOS (FCOS), the SSH keys specified in the Ignition config files are written to the /home/core/.ssh/authorized_keys.d/core file. However, the Machine Config Operator manages SSH keys in the /home/core/.ssh/authorized_keys file and configures sshd to ignore the /home/core/.ssh/authorized_keys.d/core file. As a result, newly provisioned OKD nodes are not accessible using SSH until the Machine Config Operator reconciles the machine configs with the authorized_keys file. After you can access the nodes using SSH, you can delete the /home/core/.ssh/authorized_keys.d/core file.

Procedure

  1. If you do not have an SSH key that is configured for password-less authentication on your computer, create one. For example, on a computer that uses a Linux operating system, run the following command:

    1. $ ssh-keygen -t ed25519 -N '' \
    2. -f <path>/<file_name> (1)
    1Specify the path and file name, such as ~/.ssh/id_rsa, of the new SSH key. If you have an existing key pair, ensure your public key is in the your ~/.ssh directory.

    Running this command generates an SSH key that does not require a password in the location that you specified.

    If you plan to install an OKD cluster that uses FIPS Validated / Modules in Process cryptographic libraries on the x86_64 architecture, do not create a key that uses the ed25519 algorithm. Instead, create a key that uses the rsa or ecdsa algorithm.

  2. Start the ssh-agent process as a background task:

    1. $ eval "$(ssh-agent -s)"

    Example output

    1. Agent pid 31874

    If your cluster is in FIPS mode, only use FIPS-compliant algorithms to generate the SSH key. The key must be either RSA or ECDSA.

  3. Add your SSH private key to the ssh-agent:

    1. $ ssh-add <path>/<file_name> (1)

    Example output

    1. Identity added: /home/<you>/<path>/<file_name> (<computer_name>)
    1Specify the path and file name for your SSH private key, such as ~/.ssh/id_rsa

Next steps

  • When you install OKD, provide the SSH public key to the installation program. If you install a cluster on infrastructure that you provision, you must provide this key to your cluster’s machines.

Creating the installation files for AWS

To install OKD on Amazon Web Services (AWS) using user-provisioned infrastructure, you must generate the files that the installation program needs to deploy your cluster and modify them so that the cluster creates only the machines that it will use. You generate and customize the install-config.yaml file, Kubernetes manifests, and Ignition config files. You also have the option to first set up a separate var partition during the preparation phases of installation.

Optional: Creating a separate /var partition

It is recommended that disk partitioning for OKD be left to the installer. However, there are cases where you might want to create separate partitions in a part of the filesystem that you expect to grow.

OKD supports the addition of a single partition to attach storage to either the /var partition or a subdirectory of /var. For example:

  • /var/lib/containers: Holds container-related content that can grow as more images and containers are added to a system.

  • /var/lib/etcd: Holds data that you might want to keep separate for purposes such as performance optimization of etcd storage.

  • /var: Holds data that you might want to keep separate for purposes such as auditing.

Storing the contents of a /var directory separately makes it easier to grow storage for those areas as needed and reinstall OKD at a later date and keep that data intact. With this method, you will not have to pull all your containers again, nor will you have to copy massive log files when you update systems.

Because /var must be in place before a fresh installation of Fedora CoreOS (FCOS), the following procedure sets up the separate /var partition by creating a machine config that is inserted during the openshift-install preparation phases of an OKD installation.

If you follow the steps to create a separate /var partition in this procedure, it is not necessary to create the Kubernetes manifest and Ignition config files again as described later in this section.

Prerequisites

  • If container storage is on the root partition, ensure that this root partition is mounted with the pquota option by including rootflags=pquota in the GRUB command line.

  • If the container storage is on a partition that is mounted by /etc/fstab, ensure that the following mount option is included in the /etc/fstab file:

    1. /dev/sdb1 /var xfs defaults,pquota 0 0
  • If the container storage is on a partition that is mounted by systemd, ensure that the MachineConfig object includes the following mount option as in this example:

    1. spec:
    2. config:
    3. ignition:
    4. version: 3.1.0
    5. storage:
    6. disks:
    7. - device: /dev/sdb
    8. partitions:
    9. - label: var
    10. sizeMiB: 240000
    11. startMiB: 0
    12. filesystems:
    13. - device: /dev/disk/by-partlabel/var
    14. format: xfs
    15. path: /var
    16. systemd:
    17. units:
    18. - contents: |
    19. [Unit]
    20. Before=local-fs.target
    21. [Mount]
    22. Where=/var
    23. What=/dev/disk/by-partlabel/var
    24. Options=defaults,pquota
    25. [Install]
    26. WantedBy=local-fs.target
    27. enabled: true
    28. name: var.mount

Procedure

  1. Create a directory to hold the OKD installation files:

    1. $ mkdir $HOME/clusterconfig
  2. Run openshift-install to create a set of files in the manifest and openshift subdirectories. Answer the system questions as you are prompted:

    1. $ openshift-install create manifests --dir $HOME/clusterconfig

    Example output

    1. ? SSH Public Key ...
    2. INFO Credentials loaded from the "myprofile" profile in file "/home/myuser/.aws/credentials"
    3. INFO Consuming Install Config from target directory
    4. INFO Manifests created in: $HOME/clusterconfig/manifests and $HOME/clusterconfig/openshift
  3. Optional: Confirm that the installation program created manifests in the clusterconfig/openshift directory:

    1. $ ls $HOME/clusterconfig/openshift/

    Example output

    1. 99_kubeadmin-password-secret.yaml
    2. 99_openshift-cluster-api_master-machines-0.yaml
    3. 99_openshift-cluster-api_master-machines-1.yaml
    4. 99_openshift-cluster-api_master-machines-2.yaml
    5. ...
  4. Create a MachineConfig object and add it to a file in the openshift directory. For example, name the file 98-var-partition.yaml, change the disk device name to the name of the storage device on the worker systems, and set the storage size as appropriate. This attaches storage to a separate /var directory.

    1. apiVersion: machineconfiguration.openshift.io/v1
    2. kind: MachineConfig
    3. metadata:
    4. labels:
    5. machineconfiguration.openshift.io/role: worker
    6. name: 98-var-partition
    7. spec:
    8. config:
    9. ignition:
    10. version: 3.1.0
    11. storage:
    12. disks:
    13. - device: /dev/<device_name> (1)
    14. partitions:
    15. - sizeMiB: <partition_size>
    16. startMiB: <partition_start_offset> (2)
    17. label: var
    18. filesystems:
    19. - path: /var
    20. device: /dev/disk/by-partlabel/var
    21. format: xfs
    22. systemd:
    23. units:
    24. - name: var.mount
    25. enabled: true
    26. contents: |
    27. [Unit]
    28. Before=local-fs.target
    29. [Mount]
    30. Where=/var
    31. What=/dev/disk/by-partlabel/var
    32. [Install]
    33. WantedBy=local-fs.target
    1The storage device name of the disk that you want to partition.
    2When adding a data partition to the boot disk, a minimum value of 25000 MiB (Mebibytes) is recommended. The root file system is automatically resized to fill all available space up to the specified offset. If no value is specified, or if the specified value is smaller than the recommended minimum, the resulting root file system will be too small, and future reinstalls of FCOS might overwrite the beginning of the data partition.
  5. Run openshift-install again to create Ignition configs from a set of files in the manifest and openshift subdirectories:

    1. $ openshift-install create ignition-configs --dir $HOME/clusterconfig
    2. $ ls $HOME/clusterconfig/
    3. auth bootstrap.ign master.ign metadata.json worker.ign

Now you can use the Ignition config files as input to the installation procedures to install Fedora CoreOS (FCOS) systems.

Creating the installation configuration file

Generate and customize the installation configuration file that the installation program needs to deploy your cluster.

Prerequisites

  • You obtained the OKD installation program for user-provisioned infrastructure and the pull secret for your cluster.

  • You checked that you are deploying your cluster to a region with an accompanying Fedora CoreOS (FCOS) AMI published by Red Hat. If you are deploying to a region that requires a custom AMI, such as an AWS GovCloud region, you must create the install-config.yaml file manually.

Procedure

  1. Create the install-config.yaml file.

    1. Change to the directory that contains the installation program and run the following command:

      1. $ ./openshift-install create install-config --dir=<installation_directory> (1)
      1For <installation_directory>, specify the directory name to store the files that the installation program creates.

      Specify an empty directory. Some installation assets, like bootstrap X.509 certificates have short expiration intervals, so you must not reuse an installation directory. If you want to reuse individual files from another cluster installation, you can copy them into your directory. However, the file names for the installation assets might change between releases. Use caution when copying installation files from an earlier OKD version.

    2. At the prompts, provide the configuration details for your cloud:

      1. Optional: Select an SSH key to use to access your cluster machines.

        For production OKD clusters on which you want to perform installation debugging or disaster recovery, specify an SSH key that your ssh-agent process uses.

      2. Select aws as the platform to target.

      3. If you do not have an AWS profile stored on your computer, enter the AWS access key ID and secret access key for the user that you configured to run the installation program.

        The AWS access key ID and secret access key are stored in ~/.aws/credentials in the home directory of the current user on the installation host. You are prompted for the credentials by the installation program if the credentials for the exported profile are not present in the file. Any credentials that you provide to the installation program are stored in the file.

      4. Select the AWS region to deploy the cluster to.

      5. Select the base domain for the Route 53 service that you configured for your cluster.

      6. Enter a descriptive name for your cluster.

      7. Paste the pull secret that you obtained from the Pull Secret page on the Red Hat OpenShift Cluster Manager site. This field is optional.

  1. Optional: Back up the install-config.yaml file.

    The install-config.yaml file is consumed during the installation process. If you want to reuse the file, you must back it up now.

Additional resources

Configuring the cluster-wide proxy during installation

Production environments can deny direct access to the Internet and instead have an HTTP or HTTPS proxy available. You can configure a new OKD cluster to use a proxy by configuring the proxy settings in the install-config.yaml file.

Prerequisites

  • You have an existing install-config.yaml file.

  • You reviewed the sites that your cluster requires access to and determined whether any of them need to bypass the proxy. By default, all cluster egress traffic is proxied, including calls to hosting cloud provider APIs. You added sites to the Proxy object’s spec.noProxy field to bypass the proxy if necessary.

    The Proxy object status.noProxy field is populated with the values of the networking.machineNetwork[].cidr, networking.clusterNetwork[].cidr, and networking.serviceNetwork[] fields from your installation configuration.

    For installations on Amazon Web Services (AWS), Google Cloud Platform (GCP), Microsoft Azure, and Red Hat OpenStack Platform (RHOSP), the Proxy object status.noProxy field is also populated with the instance metadata endpoint (169.254.169.254).

  • If your cluster is on AWS, you added the ec2.<region>.amazonaws.com, elasticloadbalancing.<region>.amazonaws.com, and s3.<region>.amazonaws.com endpoints to your VPC endpoint. These endpoints are required to complete requests from the nodes to the AWS EC2 API. Because the proxy works on the container level, not the node level, you must route these requests to the AWS EC2 API through the AWS private network. Adding the public IP address of the EC2 API to your allowlist in your proxy server is not sufficient.

Procedure

  1. Edit your install-config.yaml file and add the proxy settings. For example:

    1. apiVersion: v1
    2. baseDomain: my.domain.com
    3. proxy:
    4. httpProxy: http://<username>:<pswd>@<ip>:<port> (1)
    5. httpsProxy: https://<username>:<pswd>@<ip>:<port> (2)
    6. noProxy: example.com (3)
    7. additionalTrustBundle: | (4)
    8. -----BEGIN CERTIFICATE-----
    9. <MY_TRUSTED_CA_CERT>
    10. -----END CERTIFICATE-----
    11. ...
    1A proxy URL to use for creating HTTP connections outside the cluster. The URL scheme must be http. If you use an MITM transparent proxy network that does not require additional proxy configuration but requires additional CAs, you must not specify an httpProxy value.
    2A proxy URL to use for creating HTTPS connections outside the cluster. If you use an MITM transparent proxy network that does not require additional proxy configuration but requires additional CAs, you must not specify an httpsProxy value.
    3A comma-separated list of destination domain names, domains, IP addresses, or other network CIDRs to exclude proxying. Preface a domain with . to match subdomains only. For example, .y.com matches x.y.com, but not y.com. Use * to bypass proxy for all destinations.
    4If provided, the installation program generates a config map that is named user-ca-bundle in the openshift-config namespace that contains one or more additional CA certificates that are required for proxying HTTPS connections. The Cluster Network Operator then creates a trusted-ca-bundle config map that merges these contents with the Fedora CoreOS (FCOS) trust bundle, and this config map is referenced in the Proxy object’s trustedCA field. The additionalTrustBundle field is required unless the proxy’s identity certificate is signed by an authority from the FCOS trust bundle. If you use an MITM transparent proxy network that does not require additional proxy configuration but requires additional CAs, you must provide the MITM CA certificate.

    The installation program does not support the proxy readinessEndpoints field.

  2. Save the file and reference it when installing OKD.

The installation program creates a cluster-wide proxy that is named cluster that uses the proxy settings in the provided install-config.yaml file. If no proxy settings are provided, a cluster Proxy object is still created, but it will have a nil spec.

Only the Proxy object named cluster is supported, and no additional proxies can be created.

Creating the Kubernetes manifest and Ignition config files

Because you must modify some cluster definition files and manually start the cluster machines, you must generate the Kubernetes manifest and Ignition config files that the cluster needs to make its machines.

The installation configuration file transforms into the Kubernetes manifests. The manifests wrap into the Ignition configuration files, which are later used to create the cluster.

The Ignition config files that the installation program generates contain certificates that expire after 24 hours, which are then renewed at that time. If the cluster is shut down before renewing the certificates and the cluster is later restarted after the 24 hours have elapsed, the cluster automatically recovers the expired certificates. The exception is that you must manually approve the pending node-bootstrapper certificate signing requests (CSRs) to recover kubelet certificates. See the documentation for Recovering from expired control plane certificates for more information.

Prerequisites

  • You obtained the OKD installation program.

  • You created the install-config.yaml installation configuration file.

Procedure

  1. Change to the directory that contains the installation program and generate the Kubernetes manifests for the cluster:

    1. $ ./openshift-install create manifests --dir=<installation_directory> (1)

    Example output

    1. INFO Credentials loaded from the "myprofile" profile in file "/home/myuser/.aws/credentials"
    2. INFO Consuming Install Config from target directory
    3. INFO Manifests created in: install_dir/manifests and install_dir/openshift
    1For <installation_directory>, specify the installation directory that contains the install-config.yaml file you created.
  2. Remove the Kubernetes manifest files that define the control plane machines:

    1. $ rm -f <installation_directory>/openshift/99_openshift-cluster-api_master-machines-*.yaml

    By removing these files, you prevent the cluster from automatically generating control plane machines.

  3. Remove the Kubernetes manifest files that define the worker machines:

    1. $ rm -f <installation_directory>/openshift/99_openshift-cluster-api_worker-machineset-*.yaml

    Because you create and manage the worker machines yourself, you do not need to initialize these machines.

  4. Check that the mastersSchedulable parameter in the <installation_directory>/manifests/cluster-scheduler-02-config.yml Kubernetes manifest file is set to false. This setting prevents pods from being scheduled on the control plane machines:

    1. Open the <installation_directory>/manifests/cluster-scheduler-02-config.yml file.

    2. Locate the mastersSchedulable parameter and ensure that it is set to false.

    3. Save and exit the file.

  5. Optional: If you do not want the Ingress Operator to create DNS records on your behalf, remove the privateZone and publicZone sections from the <installation_directory>/manifests/cluster-dns-02-config.yml DNS configuration file:

    1. apiVersion: config.openshift.io/v1
    2. kind: DNS
    3. metadata:
    4. creationTimestamp: null
    5. name: cluster
    6. spec:
    7. baseDomain: example.openshift.com
    8. privateZone: (1)
    9. id: mycluster-100419-private-zone
    10. publicZone: (1)
    11. id: example.openshift.com
    12. status: {}
    1Remove this section completely.

    If you do so, you must add ingress DNS records manually in a later step.

  6. To create the Ignition configuration files, run the following command from the directory that contains the installation program:

    1. $ ./openshift-install create ignition-configs --dir=<installation_directory> (1)
    1For <installation_directory>, specify the same installation directory.

    The following files are generated in the directory:

    1. .
    2. ├── auth
    3. ├── kubeadmin-password
    4. └── kubeconfig
    5. ├── bootstrap.ign
    6. ├── master.ign
    7. ├── metadata.json
    8. └── worker.ign

Extracting the infrastructure name

The Ignition config files contain a unique cluster identifier that you can use to uniquely identify your cluster in Amazon Web Services (AWS). The infrastructure name is also used to locate the appropriate AWS resources during an OKD installation. The provided CloudFormation templates contain references to this infrastructure name, so you must extract it.

Prerequisites

  • You obtained the OKD installation program and the pull secret for your cluster.

  • You generated the Ignition config files for your cluster.

  • You installed the jq package.

Procedure

  • To extract and view the infrastructure name from the Ignition config file metadata, run the following command:

    1. $ jq -r .infraID <installation_directory>/metadata.json (1)
    1For <installation_directory>, specify the path to the directory that you stored the installation files in.

    Example output

    1. openshift-vw9j6 (1)
    1The output of this command is your cluster name and a random string.

Creating a VPC in AWS

You must create a Virtual Private Cloud (VPC) in Amazon Web Services (AWS) for your OKD cluster to use. You can customize the VPC to meet your requirements, including VPN and route tables.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources that represent the VPC.

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 generated the Ignition config files for your cluster.

Procedure

  1. Create a JSON file that contains the parameter values that the template requires:

    1. [
    2. {
    3. "ParameterKey": "VpcCidr", (1)
    4. "ParameterValue": "10.0.0.0/16" (2)
    5. },
    6. {
    7. "ParameterKey": "AvailabilityZoneCount", (3)
    8. "ParameterValue": "1" (4)
    9. },
    10. {
    11. "ParameterKey": "SubnetBits", (5)
    12. "ParameterValue": "12" (6)
    13. }
    14. ]
    1The CIDR block for the VPC.
    2Specify a CIDR block in the format x.x.x.x/16-24.
    3The number of availability zones to deploy the VPC in.
    4Specify an integer between 1 and 3.
    5The size of each subnet in each availability zone.
    6Specify an integer between 5 and 13, where 5 is /27 and 13 is /19.
  2. Copy the template from the CloudFormation template for the VPC section of this topic and save it as a YAML file on your computer. This template describes the VPC that your cluster requires.

  3. Launch the CloudFormation template to create a stack of AWS resources that represent the VPC:

    You must enter the command on a single line.

    1. $ aws cloudformation create-stack --stack-name <name> (1)
    2. --template-body file://<template>.yaml (2)
    3. --parameters file://<parameters>.json (3)
    1<name> is the name for the CloudFormation stack, such as cluster-vpc. You need the name of this stack if you remove the cluster.
    2<template> is the relative path to and name of the CloudFormation template YAML file that you saved.
    3<parameters> is the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    1. arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-vpc/dbedae40-2fd3-11eb-820e-12a48460849f
  4. Confirm that the template components exist:

    1. $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must provide these parameter values to the other CloudFormation templates that you run to create your cluster:

    VpcId

    The ID of your VPC.

    PublicSubnetIds

    The IDs of the new public subnets.

    PrivateSubnetIds

    The IDs of the new private subnets.

CloudFormation template for the VPC

You can use the following CloudFormation template to deploy the VPC that you need for your OKD cluster.

CloudFormation template for the VPC

  1. AWSTemplateFormatVersion: 2010-09-09
  2. Description: Template for Best Practice VPC with 1-3 AZs
  3. Parameters:
  4. VpcCidr:
  5. 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]))$
  6. ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
  7. Default: 10.0.0.0/16
  8. Description: CIDR block for VPC.
  9. Type: String
  10. AvailabilityZoneCount:
  11. ConstraintDescription: "The number of availability zones. (Min: 1, Max: 3)"
  12. MinValue: 1
  13. MaxValue: 3
  14. Default: 1
  15. Description: "How many AZs to create VPC subnets for. (Min: 1, Max: 3)"
  16. Type: Number
  17. SubnetBits:
  18. ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/19-27.
  19. MinValue: 5
  20. MaxValue: 13
  21. Default: 12
  22. Description: "Size of each subnet to create within the availability zones. (Min: 5 = /27, Max: 13 = /19)"
  23. Type: Number
  24. Metadata:
  25. AWS::CloudFormation::Interface:
  26. ParameterGroups:
  27. - Label:
  28. default: "Network Configuration"
  29. Parameters:
  30. - VpcCidr
  31. - SubnetBits
  32. - Label:
  33. default: "Availability Zones"
  34. Parameters:
  35. - AvailabilityZoneCount
  36. ParameterLabels:
  37. AvailabilityZoneCount:
  38. default: "Availability Zone Count"
  39. VpcCidr:
  40. default: "VPC CIDR"
  41. SubnetBits:
  42. default: "Bits Per Subnet"
  43. Conditions:
  44. DoAz3: !Equals [3, !Ref AvailabilityZoneCount]
  45. DoAz2: !Or [!Equals [2, !Ref AvailabilityZoneCount], Condition: DoAz3]
  46. Resources:
  47. VPC:
  48. Type: "AWS::EC2::VPC"
  49. Properties:
  50. EnableDnsSupport: "true"
  51. EnableDnsHostnames: "true"
  52. CidrBlock: !Ref VpcCidr
  53. PublicSubnet:
  54. Type: "AWS::EC2::Subnet"
  55. Properties:
  56. VpcId: !Ref VPC
  57. CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
  58. AvailabilityZone: !Select
  59. - 0
  60. - Fn::GetAZs: !Ref "AWS::Region"
  61. PublicSubnet2:
  62. Type: "AWS::EC2::Subnet"
  63. Condition: DoAz2
  64. Properties:
  65. VpcId: !Ref VPC
  66. CidrBlock: !Select [1, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
  67. AvailabilityZone: !Select
  68. - 1
  69. - Fn::GetAZs: !Ref "AWS::Region"
  70. PublicSubnet3:
  71. Type: "AWS::EC2::Subnet"
  72. Condition: DoAz3
  73. Properties:
  74. VpcId: !Ref VPC
  75. CidrBlock: !Select [2, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
  76. AvailabilityZone: !Select
  77. - 2
  78. - Fn::GetAZs: !Ref "AWS::Region"
  79. InternetGateway:
  80. Type: "AWS::EC2::InternetGateway"
  81. GatewayToInternet:
  82. Type: "AWS::EC2::VPCGatewayAttachment"
  83. Properties:
  84. VpcId: !Ref VPC
  85. InternetGatewayId: !Ref InternetGateway
  86. PublicRouteTable:
  87. Type: "AWS::EC2::RouteTable"
  88. Properties:
  89. VpcId: !Ref VPC
  90. PublicRoute:
  91. Type: "AWS::EC2::Route"
  92. DependsOn: GatewayToInternet
  93. Properties:
  94. RouteTableId: !Ref PublicRouteTable
  95. DestinationCidrBlock: 0.0.0.0/0
  96. GatewayId: !Ref InternetGateway
  97. PublicSubnetRouteTableAssociation:
  98. Type: "AWS::EC2::SubnetRouteTableAssociation"
  99. Properties:
  100. SubnetId: !Ref PublicSubnet
  101. RouteTableId: !Ref PublicRouteTable
  102. PublicSubnetRouteTableAssociation2:
  103. Type: "AWS::EC2::SubnetRouteTableAssociation"
  104. Condition: DoAz2
  105. Properties:
  106. SubnetId: !Ref PublicSubnet2
  107. RouteTableId: !Ref PublicRouteTable
  108. PublicSubnetRouteTableAssociation3:
  109. Condition: DoAz3
  110. Type: "AWS::EC2::SubnetRouteTableAssociation"
  111. Properties:
  112. SubnetId: !Ref PublicSubnet3
  113. RouteTableId: !Ref PublicRouteTable
  114. PrivateSubnet:
  115. Type: "AWS::EC2::Subnet"
  116. Properties:
  117. VpcId: !Ref VPC
  118. CidrBlock: !Select [3, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
  119. AvailabilityZone: !Select
  120. - 0
  121. - Fn::GetAZs: !Ref "AWS::Region"
  122. PrivateRouteTable:
  123. Type: "AWS::EC2::RouteTable"
  124. Properties:
  125. VpcId: !Ref VPC
  126. PrivateSubnetRouteTableAssociation:
  127. Type: "AWS::EC2::SubnetRouteTableAssociation"
  128. Properties:
  129. SubnetId: !Ref PrivateSubnet
  130. RouteTableId: !Ref PrivateRouteTable
  131. NAT:
  132. DependsOn:
  133. - GatewayToInternet
  134. Type: "AWS::EC2::NatGateway"
  135. Properties:
  136. AllocationId:
  137. "Fn::GetAtt":
  138. - EIP
  139. - AllocationId
  140. SubnetId: !Ref PublicSubnet
  141. EIP:
  142. Type: "AWS::EC2::EIP"
  143. Properties:
  144. Domain: vpc
  145. Route:
  146. Type: "AWS::EC2::Route"
  147. Properties:
  148. RouteTableId:
  149. Ref: PrivateRouteTable
  150. DestinationCidrBlock: 0.0.0.0/0
  151. NatGatewayId:
  152. Ref: NAT
  153. PrivateSubnet2:
  154. Type: "AWS::EC2::Subnet"
  155. Condition: DoAz2
  156. Properties:
  157. VpcId: !Ref VPC
  158. CidrBlock: !Select [4, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
  159. AvailabilityZone: !Select
  160. - 1
  161. - Fn::GetAZs: !Ref "AWS::Region"
  162. PrivateRouteTable2:
  163. Type: "AWS::EC2::RouteTable"
  164. Condition: DoAz2
  165. Properties:
  166. VpcId: !Ref VPC
  167. PrivateSubnetRouteTableAssociation2:
  168. Type: "AWS::EC2::SubnetRouteTableAssociation"
  169. Condition: DoAz2
  170. Properties:
  171. SubnetId: !Ref PrivateSubnet2
  172. RouteTableId: !Ref PrivateRouteTable2
  173. NAT2:
  174. DependsOn:
  175. - GatewayToInternet
  176. Type: "AWS::EC2::NatGateway"
  177. Condition: DoAz2
  178. Properties:
  179. AllocationId:
  180. "Fn::GetAtt":
  181. - EIP2
  182. - AllocationId
  183. SubnetId: !Ref PublicSubnet2
  184. EIP2:
  185. Type: "AWS::EC2::EIP"
  186. Condition: DoAz2
  187. Properties:
  188. Domain: vpc
  189. Route2:
  190. Type: "AWS::EC2::Route"
  191. Condition: DoAz2
  192. Properties:
  193. RouteTableId:
  194. Ref: PrivateRouteTable2
  195. DestinationCidrBlock: 0.0.0.0/0
  196. NatGatewayId:
  197. Ref: NAT2
  198. PrivateSubnet3:
  199. Type: "AWS::EC2::Subnet"
  200. Condition: DoAz3
  201. Properties:
  202. VpcId: !Ref VPC
  203. CidrBlock: !Select [5, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
  204. AvailabilityZone: !Select
  205. - 2
  206. - Fn::GetAZs: !Ref "AWS::Region"
  207. PrivateRouteTable3:
  208. Type: "AWS::EC2::RouteTable"
  209. Condition: DoAz3
  210. Properties:
  211. VpcId: !Ref VPC
  212. PrivateSubnetRouteTableAssociation3:
  213. Type: "AWS::EC2::SubnetRouteTableAssociation"
  214. Condition: DoAz3
  215. Properties:
  216. SubnetId: !Ref PrivateSubnet3
  217. RouteTableId: !Ref PrivateRouteTable3
  218. NAT3:
  219. DependsOn:
  220. - GatewayToInternet
  221. Type: "AWS::EC2::NatGateway"
  222. Condition: DoAz3
  223. Properties:
  224. AllocationId:
  225. "Fn::GetAtt":
  226. - EIP3
  227. - AllocationId
  228. SubnetId: !Ref PublicSubnet3
  229. EIP3:
  230. Type: "AWS::EC2::EIP"
  231. Condition: DoAz3
  232. Properties:
  233. Domain: vpc
  234. Route3:
  235. Type: "AWS::EC2::Route"
  236. Condition: DoAz3
  237. Properties:
  238. RouteTableId:
  239. Ref: PrivateRouteTable3
  240. DestinationCidrBlock: 0.0.0.0/0
  241. NatGatewayId:
  242. Ref: NAT3
  243. S3Endpoint:
  244. Type: AWS::EC2::VPCEndpoint
  245. Properties:
  246. PolicyDocument:
  247. Version: 2012-10-17
  248. Statement:
  249. - Effect: Allow
  250. Principal: '*'
  251. Action:
  252. - '*'
  253. Resource:
  254. - '*'
  255. RouteTableIds:
  256. - !Ref PublicRouteTable
  257. - !Ref PrivateRouteTable
  258. - !If [DoAz2, !Ref PrivateRouteTable2, !Ref "AWS::NoValue"]
  259. - !If [DoAz3, !Ref PrivateRouteTable3, !Ref "AWS::NoValue"]
  260. ServiceName: !Join
  261. - ''
  262. - - com.amazonaws.
  263. - !Ref 'AWS::Region'
  264. - .s3
  265. VpcId: !Ref VPC
  266. Outputs:
  267. VpcId:
  268. Description: ID of the new VPC.
  269. Value: !Ref VPC
  270. PublicSubnetIds:
  271. Description: Subnet IDs of the public subnets.
  272. Value:
  273. !Join [
  274. ",",
  275. [!Ref PublicSubnet, !If [DoAz2, !Ref PublicSubnet2, !Ref "AWS::NoValue"], !If [DoAz3, !Ref PublicSubnet3, !Ref "AWS::NoValue"]]
  276. ]
  277. PrivateSubnetIds:
  278. Description: Subnet IDs of the private subnets.
  279. Value:
  280. !Join [
  281. ",",
  282. [!Ref PrivateSubnet, !If [DoAz2, !Ref PrivateSubnet2, !Ref "AWS::NoValue"], !If [DoAz3, !Ref PrivateSubnet3, !Ref "AWS::NoValue"]]
  283. ]

Additional resources

Creating networking and load balancing components in AWS

You must configure networking and classic or network load balancing in Amazon Web Services (AWS) that your OKD cluster can use.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the networking and load balancing components that your OKD cluster requires. The template also creates a hosted zone and subnet tags.

You can run the template multiple times within a single Virtual Private Cloud (VPC).

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 generated the Ignition config files for your cluster.

  • You created and configured a VPC and associated subnets in AWS.

Procedure

  1. Obtain the hosted zone ID for the Route 53 base domain that you specified in the install-config.yaml file for your cluster. You can obtain details about your hosted zone by running the following command:

    1. $ aws route53 list-hosted-zones-by-name --dns-name <route53_domain> (1)
    1For the <route53_domain>, specify the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster.

    Example output

    1. mycluster.example.com. False 100
    2. HOSTEDZONES 65F8F38E-2268-B835-E15C-AB55336FCBFA /hostedzone/Z21IXYZABCZ2A4 mycluster.example.com. 10

    In the example output, the hosted zone ID is Z21IXYZABCZ2A4.

  2. Create a JSON file that contains the parameter values that the template requires:

    1. [
    2. {
    3. "ParameterKey": "ClusterName", (1)
    4. "ParameterValue": "mycluster" (2)
    5. },
    6. {
    7. "ParameterKey": "InfrastructureName", (3)
    8. "ParameterValue": "mycluster-<random_string>" (4)
    9. },
    10. {
    11. "ParameterKey": "HostedZoneId", (5)
    12. "ParameterValue": "<random_string>" (6)
    13. },
    14. {
    15. "ParameterKey": "HostedZoneName", (7)
    16. "ParameterValue": "example.com" (8)
    17. },
    18. {
    19. "ParameterKey": "PublicSubnets", (9)
    20. "ParameterValue": "subnet-<random_string>" (10)
    21. },
    22. {
    23. "ParameterKey": "PrivateSubnets", (11)
    24. "ParameterValue": "subnet-<random_string>" (12)
    25. },
    26. {
    27. "ParameterKey": "VpcId", (13)
    28. "ParameterValue": "vpc-<random_string>" (14)
    29. }
    30. ]
    1A short, representative cluster name to use for hostnames, etc.
    2Specify the cluster name that you used when you generated the install-config.yaml file for the cluster.
    3The name for your cluster infrastructure that is encoded in your Ignition config files for the cluster.
    4Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster-name>-<random-string>.
    5The Route 53 public zone ID to register the targets with.
    6Specify the Route 53 public zone ID, which as a format similar to Z21IXYZABCZ2A4. You can obtain this value from the AWS console.
    7The Route 53 zone to register the targets with.
    8Specify the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster. Do not include the trailing period (.) that is displayed in the AWS console.
    9The public subnets that you created for your VPC.
    10Specify the PublicSubnetIds value from the output of the CloudFormation template for the VPC.
    11The private subnets that you created for your VPC.
    12Specify the PrivateSubnetIds value from the output of the CloudFormation template for the VPC.
    13The VPC that you created for the cluster.
    14Specify the VpcId value from the output of the CloudFormation template for the VPC.
  3. Copy the template from the CloudFormation template for the network and load balancers section of this topic and save it as a YAML file on your computer. This template describes the networking and load balancing objects that your cluster requires.

    If you are deploying your cluster to an AWS government region, you must update the InternalApiServerRecord in the CloudFormation template to use CNAME records. Records of type ALIAS are not supported for AWS government regions.

  4. Launch the CloudFormation template to create a stack of AWS resources that provide the networking and load balancing components:

    You must enter the command on a single line.

    1. $ aws cloudformation create-stack --stack-name <name> (1)
    2. --template-body file://<template>.yaml (2)
    3. --parameters file://<parameters>.json (3)
    4. --capabilities CAPABILITY_NAMED_IAM (4)
    1<name> is the name for the CloudFormation stack, such as cluster-dns. You need the name of this stack if you remove the cluster.
    2<template> is the relative path to and name of the CloudFormation template YAML file that you saved.
    3<parameters> is the relative path to and name of the CloudFormation parameters JSON file.
    4You must explicitly declare the CAPABILITY_NAMED_IAM capability because the provided template creates some AWS::IAM::Role resources.

    Example output

    1. arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-dns/cd3e5de0-2fd4-11eb-5cf0-12be5c33a183
  5. Confirm that the template components exist:

    1. $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must provide these parameter values to the other CloudFormation templates that you run to create your cluster:

    PrivateHostedZoneId

    Hosted zone ID for the private DNS.

    ExternalApiLoadBalancerName

    Full name of the external API load balancer.

    InternalApiLoadBalancerName

    Full name of the internal API load balancer.

    ApiServerDnsName

    Full hostname of the API server.

    RegisterNlbIpTargetsLambda

    Lambda ARN useful to help register/deregister IP targets for these load balancers.

    ExternalApiTargetGroupArn

    ARN of external API target group.

    InternalApiTargetGroupArn

    ARN of internal API target group.

    InternalServiceTargetGroupArn

    ARN of internal service target group.

CloudFormation template for the network and load balancers

You can use the following CloudFormation template to deploy the networking objects and load balancers that you need for your OKD cluster.

CloudFormation template for the network and load balancers

  1. AWSTemplateFormatVersion: 2010-09-09
  2. Description: Template for OpenShift Cluster Network Elements (Route53 & LBs)
  3. Parameters:
  4. ClusterName:
  5. AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
  6. MaxLength: 27
  7. MinLength: 1
  8. ConstraintDescription: Cluster name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
  9. Description: A short, representative cluster name to use for host names and other identifying names.
  10. Type: String
  11. InfrastructureName:
  12. AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
  13. MaxLength: 27
  14. MinLength: 1
  15. ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
  16. Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
  17. Type: String
  18. HostedZoneId:
  19. Description: The Route53 public zone ID to register the targets with, such as Z21IXYZABCZ2A4.
  20. Type: String
  21. HostedZoneName:
  22. Description: The Route53 zone to register the targets with, such as example.com. Omit the trailing period.
  23. Type: String
  24. Default: "example.com"
  25. PublicSubnets:
  26. Description: The internet-facing subnets.
  27. Type: List<AWS::EC2::Subnet::Id>
  28. PrivateSubnets:
  29. Description: The internal subnets.
  30. Type: List<AWS::EC2::Subnet::Id>
  31. VpcId:
  32. Description: The VPC-scoped resources will belong to this VPC.
  33. Type: AWS::EC2::VPC::Id
  34. Metadata:
  35. AWS::CloudFormation::Interface:
  36. ParameterGroups:
  37. - Label:
  38. default: "Cluster Information"
  39. Parameters:
  40. - ClusterName
  41. - InfrastructureName
  42. - Label:
  43. default: "Network Configuration"
  44. Parameters:
  45. - VpcId
  46. - PublicSubnets
  47. - PrivateSubnets
  48. - Label:
  49. default: "DNS"
  50. Parameters:
  51. - HostedZoneName
  52. - HostedZoneId
  53. ParameterLabels:
  54. ClusterName:
  55. default: "Cluster Name"
  56. InfrastructureName:
  57. default: "Infrastructure Name"
  58. VpcId:
  59. default: "VPC ID"
  60. PublicSubnets:
  61. default: "Public Subnets"
  62. PrivateSubnets:
  63. default: "Private Subnets"
  64. HostedZoneName:
  65. default: "Public Hosted Zone Name"
  66. HostedZoneId:
  67. default: "Public Hosted Zone ID"
  68. Resources:
  69. ExtApiElb:
  70. Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  71. Properties:
  72. Name: !Join ["-", [!Ref InfrastructureName, "ext"]]
  73. IpAddressType: ipv4
  74. Subnets: !Ref PublicSubnets
  75. Type: network
  76. IntApiElb:
  77. Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  78. Properties:
  79. Name: !Join ["-", [!Ref InfrastructureName, "int"]]
  80. Scheme: internal
  81. IpAddressType: ipv4
  82. Subnets: !Ref PrivateSubnets
  83. Type: network
  84. IntDns:
  85. Type: "AWS::Route53::HostedZone"
  86. Properties:
  87. HostedZoneConfig:
  88. Comment: "Managed by CloudFormation"
  89. Name: !Join [".", [!Ref ClusterName, !Ref HostedZoneName]]
  90. HostedZoneTags:
  91. - Key: Name
  92. Value: !Join ["-", [!Ref InfrastructureName, "int"]]
  93. - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
  94. Value: "owned"
  95. VPCs:
  96. - VPCId: !Ref VpcId
  97. VPCRegion: !Ref "AWS::Region"
  98. ExternalApiServerRecord:
  99. Type: AWS::Route53::RecordSetGroup
  100. Properties:
  101. Comment: Alias record for the API server
  102. HostedZoneId: !Ref HostedZoneId
  103. RecordSets:
  104. - Name:
  105. !Join [
  106. ".",
  107. ["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
  108. ]
  109. Type: A
  110. AliasTarget:
  111. HostedZoneId: !GetAtt ExtApiElb.CanonicalHostedZoneID
  112. DNSName: !GetAtt ExtApiElb.DNSName
  113. InternalApiServerRecord:
  114. Type: AWS::Route53::RecordSetGroup
  115. Properties:
  116. Comment: Alias record for the API server
  117. HostedZoneId: !Ref IntDns
  118. RecordSets:
  119. - Name:
  120. !Join [
  121. ".",
  122. ["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
  123. ]
  124. Type: A
  125. AliasTarget:
  126. HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
  127. DNSName: !GetAtt IntApiElb.DNSName
  128. - Name:
  129. !Join [
  130. ".",
  131. ["api-int", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
  132. ]
  133. Type: A
  134. AliasTarget:
  135. HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
  136. DNSName: !GetAtt IntApiElb.DNSName
  137. ExternalApiListener:
  138. Type: AWS::ElasticLoadBalancingV2::Listener
  139. Properties:
  140. DefaultActions:
  141. - Type: forward
  142. TargetGroupArn:
  143. Ref: ExternalApiTargetGroup
  144. LoadBalancerArn:
  145. Ref: ExtApiElb
  146. Port: 6443
  147. Protocol: TCP
  148. ExternalApiTargetGroup:
  149. Type: AWS::ElasticLoadBalancingV2::TargetGroup
  150. Properties:
  151. HealthCheckIntervalSeconds: 10
  152. HealthCheckPath: "/readyz"
  153. HealthCheckPort: 6443
  154. HealthCheckProtocol: HTTPS
  155. HealthyThresholdCount: 2
  156. UnhealthyThresholdCount: 2
  157. Port: 6443
  158. Protocol: TCP
  159. TargetType: ip
  160. VpcId:
  161. Ref: VpcId
  162. TargetGroupAttributes:
  163. - Key: deregistration_delay.timeout_seconds
  164. Value: 60
  165. InternalApiListener:
  166. Type: AWS::ElasticLoadBalancingV2::Listener
  167. Properties:
  168. DefaultActions:
  169. - Type: forward
  170. TargetGroupArn:
  171. Ref: InternalApiTargetGroup
  172. LoadBalancerArn:
  173. Ref: IntApiElb
  174. Port: 6443
  175. Protocol: TCP
  176. InternalApiTargetGroup:
  177. Type: AWS::ElasticLoadBalancingV2::TargetGroup
  178. Properties:
  179. HealthCheckIntervalSeconds: 10
  180. HealthCheckPath: "/readyz"
  181. HealthCheckPort: 6443
  182. HealthCheckProtocol: HTTPS
  183. HealthyThresholdCount: 2
  184. UnhealthyThresholdCount: 2
  185. Port: 6443
  186. Protocol: TCP
  187. TargetType: ip
  188. VpcId:
  189. Ref: VpcId
  190. TargetGroupAttributes:
  191. - Key: deregistration_delay.timeout_seconds
  192. Value: 60
  193. InternalServiceInternalListener:
  194. Type: AWS::ElasticLoadBalancingV2::Listener
  195. Properties:
  196. DefaultActions:
  197. - Type: forward
  198. TargetGroupArn:
  199. Ref: InternalServiceTargetGroup
  200. LoadBalancerArn:
  201. Ref: IntApiElb
  202. Port: 22623
  203. Protocol: TCP
  204. InternalServiceTargetGroup:
  205. Type: AWS::ElasticLoadBalancingV2::TargetGroup
  206. Properties:
  207. HealthCheckIntervalSeconds: 10
  208. HealthCheckPath: "/healthz"
  209. HealthCheckPort: 22623
  210. HealthCheckProtocol: HTTPS
  211. HealthyThresholdCount: 2
  212. UnhealthyThresholdCount: 2
  213. Port: 22623
  214. Protocol: TCP
  215. TargetType: ip
  216. VpcId:
  217. Ref: VpcId
  218. TargetGroupAttributes:
  219. - Key: deregistration_delay.timeout_seconds
  220. Value: 60
  221. RegisterTargetLambdaIamRole:
  222. Type: AWS::IAM::Role
  223. Properties:
  224. RoleName: !Join ["-", [!Ref InfrastructureName, "nlb", "lambda", "role"]]
  225. AssumeRolePolicyDocument:
  226. Version: "2012-10-17"
  227. Statement:
  228. - Effect: "Allow"
  229. Principal:
  230. Service:
  231. - "lambda.amazonaws.com"
  232. Action:
  233. - "sts:AssumeRole"
  234. Path: "/"
  235. Policies:
  236. - PolicyName: !Join ["-", [!Ref InfrastructureName, "master", "policy"]]
  237. PolicyDocument:
  238. Version: "2012-10-17"
  239. Statement:
  240. - Effect: "Allow"
  241. Action:
  242. [
  243. "elasticloadbalancing:RegisterTargets",
  244. "elasticloadbalancing:DeregisterTargets",
  245. ]
  246. Resource: !Ref InternalApiTargetGroup
  247. - Effect: "Allow"
  248. Action:
  249. [
  250. "elasticloadbalancing:RegisterTargets",
  251. "elasticloadbalancing:DeregisterTargets",
  252. ]
  253. Resource: !Ref InternalServiceTargetGroup
  254. - Effect: "Allow"
  255. Action:
  256. [
  257. "elasticloadbalancing:RegisterTargets",
  258. "elasticloadbalancing:DeregisterTargets",
  259. ]
  260. Resource: !Ref ExternalApiTargetGroup
  261. RegisterNlbIpTargets:
  262. Type: "AWS::Lambda::Function"
  263. Properties:
  264. Handler: "index.handler"
  265. Role:
  266. Fn::GetAtt:
  267. - "RegisterTargetLambdaIamRole"
  268. - "Arn"
  269. Code:
  270. ZipFile: |
  271. import json
  272. import boto3
  273. import cfnresponse
  274. def handler(event, context):
  275. elb = boto3.client('elbv2')
  276. if event['RequestType'] == 'Delete':
  277. elb.deregister_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
  278. elif event['RequestType'] == 'Create':
  279. elb.register_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
  280. responseData = {}
  281. cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['TargetArn']+event['ResourceProperties']['TargetIp'])
  282. Runtime: "python3.7"
  283. Timeout: 120
  284. RegisterSubnetTagsLambdaIamRole:
  285. Type: AWS::IAM::Role
  286. Properties:
  287. RoleName: !Join ["-", [!Ref InfrastructureName, "subnet-tags-lambda-role"]]
  288. AssumeRolePolicyDocument:
  289. Version: "2012-10-17"
  290. Statement:
  291. - Effect: "Allow"
  292. Principal:
  293. Service:
  294. - "lambda.amazonaws.com"
  295. Action:
  296. - "sts:AssumeRole"
  297. Path: "/"
  298. Policies:
  299. - PolicyName: !Join ["-", [!Ref InfrastructureName, "subnet-tagging-policy"]]
  300. PolicyDocument:
  301. Version: "2012-10-17"
  302. Statement:
  303. - Effect: "Allow"
  304. Action:
  305. [
  306. "ec2:DeleteTags",
  307. "ec2:CreateTags"
  308. ]
  309. Resource: "arn:aws:ec2:*:*:subnet/*"
  310. - Effect: "Allow"
  311. Action:
  312. [
  313. "ec2:DescribeSubnets",
  314. "ec2:DescribeTags"
  315. ]
  316. Resource: "*"
  317. RegisterSubnetTags:
  318. Type: "AWS::Lambda::Function"
  319. Properties:
  320. Handler: "index.handler"
  321. Role:
  322. Fn::GetAtt:
  323. - "RegisterSubnetTagsLambdaIamRole"
  324. - "Arn"
  325. Code:
  326. ZipFile: |
  327. import json
  328. import boto3
  329. import cfnresponse
  330. def handler(event, context):
  331. ec2_client = boto3.client('ec2')
  332. if event['RequestType'] == 'Delete':
  333. for subnet_id in event['ResourceProperties']['Subnets']:
  334. ec2_client.delete_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName']}]);
  335. elif event['RequestType'] == 'Create':
  336. for subnet_id in event['ResourceProperties']['Subnets']:
  337. ec2_client.create_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName'], 'Value': 'shared'}]);
  338. responseData = {}
  339. cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['InfrastructureName']+event['ResourceProperties']['Subnets'][0])
  340. Runtime: "python3.7"
  341. Timeout: 120
  342. RegisterPublicSubnetTags:
  343. Type: Custom::SubnetRegister
  344. Properties:
  345. ServiceToken: !GetAtt RegisterSubnetTags.Arn
  346. InfrastructureName: !Ref InfrastructureName
  347. Subnets: !Ref PublicSubnets
  348. RegisterPrivateSubnetTags:
  349. Type: Custom::SubnetRegister
  350. Properties:
  351. ServiceToken: !GetAtt RegisterSubnetTags.Arn
  352. InfrastructureName: !Ref InfrastructureName
  353. Subnets: !Ref PrivateSubnets
  354. Outputs:
  355. PrivateHostedZoneId:
  356. Description: Hosted zone ID for the private DNS, which is required for private records.
  357. Value: !Ref IntDns
  358. ExternalApiLoadBalancerName:
  359. Description: Full name of the external API load balancer.
  360. Value: !GetAtt ExtApiElb.LoadBalancerFullName
  361. InternalApiLoadBalancerName:
  362. Description: Full name of the internal API load balancer.
  363. Value: !GetAtt IntApiElb.LoadBalancerFullName
  364. ApiServerDnsName:
  365. Description: Full hostname of the API server, which is required for the Ignition config files.
  366. Value: !Join [".", ["api-int", !Ref ClusterName, !Ref HostedZoneName]]
  367. RegisterNlbIpTargetsLambda:
  368. Description: Lambda ARN useful to help register or deregister IP targets for these load balancers.
  369. Value: !GetAtt RegisterNlbIpTargets.Arn
  370. ExternalApiTargetGroupArn:
  371. Description: ARN of the external API target group.
  372. Value: !Ref ExternalApiTargetGroup
  373. InternalApiTargetGroupArn:
  374. Description: ARN of the internal API target group.
  375. Value: !Ref InternalApiTargetGroup
  376. InternalServiceTargetGroupArn:
  377. Description: ARN of the internal service target group.
  378. Value: !Ref InternalServiceTargetGroup

If you are deploying your cluster to an AWS government region, you must update the InternalApiServerRecord to use CNAME records. Records of type ALIAS are not supported for AWS government regions. For example:

  1. Type: CNAME
  2. TTL: 10
  3. ResourceRecords:
  4. - !GetAtt IntApiElb.DNSName

Additional resources

Creating security group and roles in AWS

You must create security groups and roles in Amazon Web Services (AWS) for your OKD cluster to use.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the security groups and roles that your OKD cluster requires.

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 generated the Ignition config files for your cluster.

  • You created and configured a VPC and associated subnets in AWS.

Procedure

  1. Create a JSON file that contains the parameter values that the template requires:

    1. [
    2. {
    3. "ParameterKey": "InfrastructureName", (1)
    4. "ParameterValue": "mycluster-<random_string>" (2)
    5. },
    6. {
    7. "ParameterKey": "VpcCidr", (3)
    8. "ParameterValue": "10.0.0.0/16" (4)
    9. },
    10. {
    11. "ParameterKey": "PrivateSubnets", (5)
    12. "ParameterValue": "subnet-<random_string>" (6)
    13. },
    14. {
    15. "ParameterKey": "VpcId", (7)
    16. "ParameterValue": "vpc-<random_string>" (8)
    17. }
    18. ]
    1The name for your cluster infrastructure that is encoded in your Ignition config files for the cluster.
    2Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster-name>-<random-string>.
    3The CIDR block for the VPC.
    4Specify the CIDR block parameter that you used for the VPC that you defined in the form x.x.x.x/16-24.
    5The private subnets that you created for your VPC.
    6Specify the PrivateSubnetIds value from the output of the CloudFormation template for the VPC.
    7The VPC that you created for the cluster.
    8Specify the VpcId value from the output of the CloudFormation template for the VPC.
  2. Copy the template from the CloudFormation template for security objects section of this topic and save it as a YAML file on your computer. This template describes the security groups and roles that your cluster requires.

  3. Launch the CloudFormation template to create a stack of AWS resources that represent the security groups and roles:

    You must enter the command on a single line.

    1. $ aws cloudformation create-stack --stack-name <name> (1)
    2. --template-body file://<template>.yaml (2)
    3. --parameters file://<parameters>.json (3)
    4. --capabilities CAPABILITY_NAMED_IAM (4)
    1<name> is the name for the CloudFormation stack, such as cluster-sec. You need the name of this stack if you remove the cluster.
    2<template> is the relative path to and name of the CloudFormation template YAML file that you saved.
    3<parameters> is the relative path to and name of the CloudFormation parameters JSON file.
    4You must explicitly declare the CAPABILITY_NAMED_IAM capability because the provided template creates some AWS::IAM::Role and AWS::IAM::InstanceProfile resources.

    Example output

    1. arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-sec/03bd4210-2ed7-11eb-6d7a-13fc0b61e9db
  4. Confirm that the template components exist:

    1. $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must provide these parameter values to the other CloudFormation templates that you run to create your cluster:

    MasterSecurityGroupId

    Master Security Group ID

    WorkerSecurityGroupId

    Worker Security Group ID

    MasterInstanceProfile

    Master IAM Instance Profile

    WorkerInstanceProfile

    Worker IAM Instance Profile

CloudFormation template for security objects

You can use the following CloudFormation template to deploy the security objects that you need for your OKD cluster.

CloudFormation template for security objects

  1. AWSTemplateFormatVersion: 2010-09-09
  2. Description: Template for OpenShift Cluster Security Elements (Security Groups & IAM)
  3. Parameters:
  4. InfrastructureName:
  5. AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
  6. MaxLength: 27
  7. MinLength: 1
  8. ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
  9. Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
  10. Type: String
  11. VpcCidr:
  12. 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]))$
  13. ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
  14. Default: 10.0.0.0/16
  15. Description: CIDR block for VPC.
  16. Type: String
  17. VpcId:
  18. Description: The VPC-scoped resources will belong to this VPC.
  19. Type: AWS::EC2::VPC::Id
  20. PrivateSubnets:
  21. Description: The internal subnets.
  22. Type: List<AWS::EC2::Subnet::Id>
  23. Metadata:
  24. AWS::CloudFormation::Interface:
  25. ParameterGroups:
  26. - Label:
  27. default: "Cluster Information"
  28. Parameters:
  29. - InfrastructureName
  30. - Label:
  31. default: "Network Configuration"
  32. Parameters:
  33. - VpcId
  34. - VpcCidr
  35. - PrivateSubnets
  36. ParameterLabels:
  37. InfrastructureName:
  38. default: "Infrastructure Name"
  39. VpcId:
  40. default: "VPC ID"
  41. VpcCidr:
  42. default: "VPC CIDR"
  43. PrivateSubnets:
  44. default: "Private Subnets"
  45. Resources:
  46. MasterSecurityGroup:
  47. Type: AWS::EC2::SecurityGroup
  48. Properties:
  49. GroupDescription: Cluster Master Security Group
  50. SecurityGroupIngress:
  51. - IpProtocol: icmp
  52. FromPort: 0
  53. ToPort: 0
  54. CidrIp: !Ref VpcCidr
  55. - IpProtocol: tcp
  56. FromPort: 22
  57. ToPort: 22
  58. CidrIp: !Ref VpcCidr
  59. - IpProtocol: tcp
  60. ToPort: 6443
  61. FromPort: 6443
  62. CidrIp: !Ref VpcCidr
  63. - IpProtocol: tcp
  64. FromPort: 22623
  65. ToPort: 22623
  66. CidrIp: !Ref VpcCidr
  67. VpcId: !Ref VpcId
  68. WorkerSecurityGroup:
  69. Type: AWS::EC2::SecurityGroup
  70. Properties:
  71. GroupDescription: Cluster Worker Security Group
  72. SecurityGroupIngress:
  73. - IpProtocol: icmp
  74. FromPort: 0
  75. ToPort: 0
  76. CidrIp: !Ref VpcCidr
  77. - IpProtocol: tcp
  78. FromPort: 22
  79. ToPort: 22
  80. CidrIp: !Ref VpcCidr
  81. VpcId: !Ref VpcId
  82. MasterIngressEtcd:
  83. Type: AWS::EC2::SecurityGroupIngress
  84. Properties:
  85. GroupId: !GetAtt MasterSecurityGroup.GroupId
  86. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  87. Description: etcd
  88. FromPort: 2379
  89. ToPort: 2380
  90. IpProtocol: tcp
  91. MasterIngressVxlan:
  92. Type: AWS::EC2::SecurityGroupIngress
  93. Properties:
  94. GroupId: !GetAtt MasterSecurityGroup.GroupId
  95. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  96. Description: Vxlan packets
  97. FromPort: 4789
  98. ToPort: 4789
  99. IpProtocol: udp
  100. MasterIngressWorkerVxlan:
  101. Type: AWS::EC2::SecurityGroupIngress
  102. Properties:
  103. GroupId: !GetAtt MasterSecurityGroup.GroupId
  104. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  105. Description: Vxlan packets
  106. FromPort: 4789
  107. ToPort: 4789
  108. IpProtocol: udp
  109. MasterIngressGeneve:
  110. Type: AWS::EC2::SecurityGroupIngress
  111. Properties:
  112. GroupId: !GetAtt MasterSecurityGroup.GroupId
  113. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  114. Description: Geneve packets
  115. FromPort: 6081
  116. ToPort: 6081
  117. IpProtocol: udp
  118. MasterIngressWorkerGeneve:
  119. Type: AWS::EC2::SecurityGroupIngress
  120. Properties:
  121. GroupId: !GetAtt MasterSecurityGroup.GroupId
  122. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  123. Description: Geneve packets
  124. FromPort: 6081
  125. ToPort: 6081
  126. IpProtocol: udp
  127. MasterIngressInternal:
  128. Type: AWS::EC2::SecurityGroupIngress
  129. Properties:
  130. GroupId: !GetAtt MasterSecurityGroup.GroupId
  131. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  132. Description: Internal cluster communication
  133. FromPort: 9000
  134. ToPort: 9999
  135. IpProtocol: tcp
  136. MasterIngressWorkerInternal:
  137. Type: AWS::EC2::SecurityGroupIngress
  138. Properties:
  139. GroupId: !GetAtt MasterSecurityGroup.GroupId
  140. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  141. Description: Internal cluster communication
  142. FromPort: 9000
  143. ToPort: 9999
  144. IpProtocol: tcp
  145. MasterIngressInternalUDP:
  146. Type: AWS::EC2::SecurityGroupIngress
  147. Properties:
  148. GroupId: !GetAtt MasterSecurityGroup.GroupId
  149. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  150. Description: Internal cluster communication
  151. FromPort: 9000
  152. ToPort: 9999
  153. IpProtocol: udp
  154. MasterIngressWorkerInternalUDP:
  155. Type: AWS::EC2::SecurityGroupIngress
  156. Properties:
  157. GroupId: !GetAtt MasterSecurityGroup.GroupId
  158. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  159. Description: Internal cluster communication
  160. FromPort: 9000
  161. ToPort: 9999
  162. IpProtocol: udp
  163. MasterIngressKube:
  164. Type: AWS::EC2::SecurityGroupIngress
  165. Properties:
  166. GroupId: !GetAtt MasterSecurityGroup.GroupId
  167. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  168. Description: Kubernetes kubelet, scheduler and controller manager
  169. FromPort: 10250
  170. ToPort: 10259
  171. IpProtocol: tcp
  172. MasterIngressWorkerKube:
  173. Type: AWS::EC2::SecurityGroupIngress
  174. Properties:
  175. GroupId: !GetAtt MasterSecurityGroup.GroupId
  176. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  177. Description: Kubernetes kubelet, scheduler and controller manager
  178. FromPort: 10250
  179. ToPort: 10259
  180. IpProtocol: tcp
  181. MasterIngressIngressServices:
  182. Type: AWS::EC2::SecurityGroupIngress
  183. Properties:
  184. GroupId: !GetAtt MasterSecurityGroup.GroupId
  185. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  186. Description: Kubernetes ingress services
  187. FromPort: 30000
  188. ToPort: 32767
  189. IpProtocol: tcp
  190. MasterIngressWorkerIngressServices:
  191. Type: AWS::EC2::SecurityGroupIngress
  192. Properties:
  193. GroupId: !GetAtt MasterSecurityGroup.GroupId
  194. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  195. Description: Kubernetes ingress services
  196. FromPort: 30000
  197. ToPort: 32767
  198. IpProtocol: tcp
  199. MasterIngressIngressServicesUDP:
  200. Type: AWS::EC2::SecurityGroupIngress
  201. Properties:
  202. GroupId: !GetAtt MasterSecurityGroup.GroupId
  203. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  204. Description: Kubernetes ingress services
  205. FromPort: 30000
  206. ToPort: 32767
  207. IpProtocol: udp
  208. MasterIngressWorkerIngressServicesUDP:
  209. Type: AWS::EC2::SecurityGroupIngress
  210. Properties:
  211. GroupId: !GetAtt MasterSecurityGroup.GroupId
  212. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  213. Description: Kubernetes ingress services
  214. FromPort: 30000
  215. ToPort: 32767
  216. IpProtocol: udp
  217. WorkerIngressVxlan:
  218. Type: AWS::EC2::SecurityGroupIngress
  219. Properties:
  220. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  221. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  222. Description: Vxlan packets
  223. FromPort: 4789
  224. ToPort: 4789
  225. IpProtocol: udp
  226. WorkerIngressMasterVxlan:
  227. Type: AWS::EC2::SecurityGroupIngress
  228. Properties:
  229. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  230. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  231. Description: Vxlan packets
  232. FromPort: 4789
  233. ToPort: 4789
  234. IpProtocol: udp
  235. WorkerIngressGeneve:
  236. Type: AWS::EC2::SecurityGroupIngress
  237. Properties:
  238. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  239. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  240. Description: Geneve packets
  241. FromPort: 6081
  242. ToPort: 6081
  243. IpProtocol: udp
  244. WorkerIngressMasterGeneve:
  245. Type: AWS::EC2::SecurityGroupIngress
  246. Properties:
  247. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  248. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  249. Description: Geneve packets
  250. FromPort: 6081
  251. ToPort: 6081
  252. IpProtocol: udp
  253. WorkerIngressInternal:
  254. Type: AWS::EC2::SecurityGroupIngress
  255. Properties:
  256. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  257. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  258. Description: Internal cluster communication
  259. FromPort: 9000
  260. ToPort: 9999
  261. IpProtocol: tcp
  262. WorkerIngressMasterInternal:
  263. Type: AWS::EC2::SecurityGroupIngress
  264. Properties:
  265. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  266. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  267. Description: Internal cluster communication
  268. FromPort: 9000
  269. ToPort: 9999
  270. IpProtocol: tcp
  271. WorkerIngressInternalUDP:
  272. Type: AWS::EC2::SecurityGroupIngress
  273. Properties:
  274. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  275. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  276. Description: Internal cluster communication
  277. FromPort: 9000
  278. ToPort: 9999
  279. IpProtocol: udp
  280. WorkerIngressMasterInternalUDP:
  281. Type: AWS::EC2::SecurityGroupIngress
  282. Properties:
  283. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  284. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  285. Description: Internal cluster communication
  286. FromPort: 9000
  287. ToPort: 9999
  288. IpProtocol: udp
  289. WorkerIngressKube:
  290. Type: AWS::EC2::SecurityGroupIngress
  291. Properties:
  292. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  293. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  294. Description: Kubernetes secure kubelet port
  295. FromPort: 10250
  296. ToPort: 10250
  297. IpProtocol: tcp
  298. WorkerIngressWorkerKube:
  299. Type: AWS::EC2::SecurityGroupIngress
  300. Properties:
  301. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  302. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  303. Description: Internal Kubernetes communication
  304. FromPort: 10250
  305. ToPort: 10250
  306. IpProtocol: tcp
  307. WorkerIngressIngressServices:
  308. Type: AWS::EC2::SecurityGroupIngress
  309. Properties:
  310. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  311. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  312. Description: Kubernetes ingress services
  313. FromPort: 30000
  314. ToPort: 32767
  315. IpProtocol: tcp
  316. WorkerIngressMasterIngressServices:
  317. Type: AWS::EC2::SecurityGroupIngress
  318. Properties:
  319. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  320. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  321. Description: Kubernetes ingress services
  322. FromPort: 30000
  323. ToPort: 32767
  324. IpProtocol: tcp
  325. WorkerIngressIngressServicesUDP:
  326. Type: AWS::EC2::SecurityGroupIngress
  327. Properties:
  328. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  329. SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
  330. Description: Kubernetes ingress services
  331. FromPort: 30000
  332. ToPort: 32767
  333. IpProtocol: udp
  334. WorkerIngressMasterIngressServicesUDP:
  335. Type: AWS::EC2::SecurityGroupIngress
  336. Properties:
  337. GroupId: !GetAtt WorkerSecurityGroup.GroupId
  338. SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
  339. Description: Kubernetes ingress services
  340. FromPort: 30000
  341. ToPort: 32767
  342. IpProtocol: udp
  343. MasterIamRole:
  344. Type: AWS::IAM::Role
  345. Properties:
  346. AssumeRolePolicyDocument:
  347. Version: "2012-10-17"
  348. Statement:
  349. - Effect: "Allow"
  350. Principal:
  351. Service:
  352. - "ec2.amazonaws.com"
  353. Action:
  354. - "sts:AssumeRole"
  355. Policies:
  356. - PolicyName: !Join ["-", [!Ref InfrastructureName, "master", "policy"]]
  357. PolicyDocument:
  358. Version: "2012-10-17"
  359. Statement:
  360. - Effect: "Allow"
  361. Action:
  362. - "ec2:AttachVolume"
  363. - "ec2:AuthorizeSecurityGroupIngress"
  364. - "ec2:CreateSecurityGroup"
  365. - "ec2:CreateTags"
  366. - "ec2:CreateVolume"
  367. - "ec2:DeleteSecurityGroup"
  368. - "ec2:DeleteVolume"
  369. - "ec2:Describe*"
  370. - "ec2:DetachVolume"
  371. - "ec2:ModifyInstanceAttribute"
  372. - "ec2:ModifyVolume"
  373. - "ec2:RevokeSecurityGroupIngress"
  374. - "elasticloadbalancing:AddTags"
  375. - "elasticloadbalancing:AttachLoadBalancerToSubnets"
  376. - "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer"
  377. - "elasticloadbalancing:CreateListener"
  378. - "elasticloadbalancing:CreateLoadBalancer"
  379. - "elasticloadbalancing:CreateLoadBalancerPolicy"
  380. - "elasticloadbalancing:CreateLoadBalancerListeners"
  381. - "elasticloadbalancing:CreateTargetGroup"
  382. - "elasticloadbalancing:ConfigureHealthCheck"
  383. - "elasticloadbalancing:DeleteListener"
  384. - "elasticloadbalancing:DeleteLoadBalancer"
  385. - "elasticloadbalancing:DeleteLoadBalancerListeners"
  386. - "elasticloadbalancing:DeleteTargetGroup"
  387. - "elasticloadbalancing:DeregisterInstancesFromLoadBalancer"
  388. - "elasticloadbalancing:DeregisterTargets"
  389. - "elasticloadbalancing:Describe*"
  390. - "elasticloadbalancing:DetachLoadBalancerFromSubnets"
  391. - "elasticloadbalancing:ModifyListener"
  392. - "elasticloadbalancing:ModifyLoadBalancerAttributes"
  393. - "elasticloadbalancing:ModifyTargetGroup"
  394. - "elasticloadbalancing:ModifyTargetGroupAttributes"
  395. - "elasticloadbalancing:RegisterInstancesWithLoadBalancer"
  396. - "elasticloadbalancing:RegisterTargets"
  397. - "elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer"
  398. - "elasticloadbalancing:SetLoadBalancerPoliciesOfListener"
  399. - "kms:DescribeKey"
  400. Resource: "*"
  401. MasterInstanceProfile:
  402. Type: "AWS::IAM::InstanceProfile"
  403. Properties:
  404. Roles:
  405. - Ref: "MasterIamRole"
  406. WorkerIamRole:
  407. Type: AWS::IAM::Role
  408. Properties:
  409. AssumeRolePolicyDocument:
  410. Version: "2012-10-17"
  411. Statement:
  412. - Effect: "Allow"
  413. Principal:
  414. Service:
  415. - "ec2.amazonaws.com"
  416. Action:
  417. - "sts:AssumeRole"
  418. Policies:
  419. - PolicyName: !Join ["-", [!Ref InfrastructureName, "worker", "policy"]]
  420. PolicyDocument:
  421. Version: "2012-10-17"
  422. Statement:
  423. - Effect: "Allow"
  424. Action:
  425. - "ec2:DescribeInstances"
  426. - "ec2:DescribeRegions"
  427. Resource: "*"
  428. WorkerInstanceProfile:
  429. Type: "AWS::IAM::InstanceProfile"
  430. Properties:
  431. Roles:
  432. - Ref: "WorkerIamRole"
  433. Outputs:
  434. MasterSecurityGroupId:
  435. Description: Master Security Group ID
  436. Value: !GetAtt MasterSecurityGroup.GroupId
  437. WorkerSecurityGroupId:
  438. Description: Worker Security Group ID
  439. Value: !GetAtt WorkerSecurityGroup.GroupId
  440. MasterInstanceProfile:
  441. Description: Master IAM Instance Profile
  442. Value: !Ref MasterInstanceProfile
  443. WorkerInstanceProfile:
  444. Description: Worker IAM Instance Profile
  445. Value: !Ref WorkerInstanceProfile

Additional resources

FCOS AMIs for the AWS infrastructure

Red Hat provides Fedora CoreOS (FCOS) AMIs valid for the various Amazon Web Services (AWS) zones you can specify for your OKD nodes.

You can also install to regions that do not have a FCOS AMI published by importing your own AMI.

AWS regions without a published FCOS AMI

You can deploy an OKD cluster to Amazon Web Services (AWS) regions without native support for a Fedora CoreOS (FCOS) Amazon Machine Image (AMI) or the AWS software development kit (SDK). If a published AMI is not available for an AWS region, you can upload a custom AMI prior to installing the cluster. This is required if you are deploying your cluster to an AWS government region.

If you are deploying to a non-government region that does not have a published FCOS AMI, and you do not specify a custom AMI, the installation program copies the us-east-1 AMI to the user account automatically. Then the installation program creates the control plane machines with encrypted EBS volumes using the default or user-specified Key Management Service (KMS) key. This allows the AMI to follow the same process workflow as published FCOS AMIs.

A region without native support for an FCOS AMI is not available to select from the terminal during cluster creation because it is not published. However, you can install to this region by configuring the custom AMI in the install-config.yaml file.

Uploading a custom FCOS AMI in AWS

If you are deploying to a custom Amazon Web Services (AWS) region, you must upload a custom Fedora CoreOS (FCOS) Amazon Machine Image (AMI) that belongs to that region.

Prerequisites

Procedure

  1. Export your AWS profile as an environment variable:

    1. $ export AWS_PROFILE=<aws_profile> (1)
    1The AWS profile name that holds your AWS credentials, like govcloud.
  2. Export the region to associate with your custom AMI as an environment variable:

    1. $ export AWS_DEFAULT_REGION=<aws_region> (1)
    1The AWS region, like us-gov-east-1.
  3. Export the version of FCOS you uploaded to Amazon S3 as an environment variable:

    1. $ export RHCOS_VERSION=<version> (1)
    1The FCOS VMDK version, like 4.6.0.
  4. Export the Amazon S3 bucket name as an environment variable:

    1. $ export VMIMPORT_BUCKET_NAME=<s3_bucket_name>
  5. Create the containers.json file and define your FCOS VMDK file:

    1. $ cat <<EOF > containers.json
    2. {
    3. "Description": "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64",
    4. "Format": "vmdk",
    5. "UserBucket": {
    6. "S3Bucket": "${VMIMPORT_BUCKET_NAME}",
    7. "S3Key": "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64.vmdk"
    8. }
    9. }
    10. EOF
  6. Import the FCOS disk as an Amazon EBS snapshot:

    1. $ aws ec2 import-snapshot --region ${AWS_DEFAULT_REGION} \
    2. --description "<description>" \ (1)
    3. --disk-container "file://<file_path>/containers.json" (2)
    1The description of your FCOS disk being imported, like rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64.
    2The file path to the JSON file describing your FCOS disk. The JSON file should contain your Amazon S3 bucket name and key.
  7. Check the status of the image import:

    1. $ watch -n 5 aws ec2 describe-import-snapshot-tasks --region ${AWS_DEFAULT_REGION}

    Example output

    1. {
    2. "ImportSnapshotTasks": [
    3. {
    4. "Description": "rhcos-4.6.0-x86_64-aws.x86_64",
    5. "ImportTaskId": "import-snap-fh6i8uil",
    6. "SnapshotTaskDetail": {
    7. "Description": "rhcos-4.6.0-x86_64-aws.x86_64",
    8. "DiskImageSize": 819056640.0,
    9. "Format": "VMDK",
    10. "SnapshotId": "snap-06331325870076318",
    11. "Status": "completed",
    12. "UserBucket": {
    13. "S3Bucket": "external-images",
    14. "S3Key": "rhcos-4.6.0-x86_64-aws.x86_64.vmdk"
    15. }
    16. }
    17. }
    18. ]
    19. }

    Copy the SnapshotId to register the image.

  8. Create a custom FCOS AMI from the FCOS snapshot:

    1. $ aws ec2 register-image \
    2. --region ${AWS_DEFAULT_REGION} \
    3. --architecture x86_64 \ (1)
    4. --description "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64" \ (2)
    5. --ena-support \
    6. --name "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64" \ (3)
    7. --virtualization-type hvm \
    8. --root-device-name '/dev/xvda' \
    9. --block-device-mappings 'DeviceName=/dev/xvda,Ebs={DeleteOnTermination=true,SnapshotId=<snapshot_ID>}' (4)
    1The FCOS VMDK architecture type, like x86_64, s390x, or ppc64le.
    2The Description from the imported snapshot.
    3The name of the FCOS AMI.
    4The SnapshotID from the imported snapshot.

To learn more about these APIs, see the AWS documentation for importing snapshots and creating EBS-backed AMIs.

Creating the bootstrap node in AWS

You must create the bootstrap node in Amazon Web Services (AWS) to use during OKD cluster initialization.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the bootstrap node that your OKD installation requires.

If you do not use the provided CloudFormation template to create your bootstrap node, 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 generated the Ignition config files for your cluster.

  • You created and configured a VPC and associated subnets in AWS.

  • You created and configured DNS, load balancers, and listeners in AWS.

  • You created the security groups and roles required for your cluster in AWS.

Procedure

  1. Provide a location to serve the bootstrap.ign Ignition config file to your cluster. This file is located in your installation directory. One way to do this is to create an S3 bucket in your cluster’s region and upload the Ignition config file to it.

    The provided CloudFormation Template assumes that the Ignition config files for your cluster are served from an S3 bucket. If you choose to serve the files from another location, you must modify the templates.

    If you are deploying to a region that has endpoints that differ from the AWS SDK, or you are providing your own custom endpoints, you must use a presigned URL for your S3 bucket instead of the s3:// schema.

    The bootstrap Ignition config file does contain secrets, like X.509 keys. The following steps provide basic security for the S3 bucket. To provide additional security, you can enable an S3 bucket policy to allow only certain users, such as the OpenShift IAM user, to access objects that the bucket contains. You can avoid S3 entirely and serve your bootstrap Ignition config file from any address that the bootstrap machine can reach.

    1. Create the bucket:

      1. $ aws s3 mb s3://<cluster-name>-infra (1)
      1<cluster-name>-infra is the bucket name. When creating the install-config.yaml file, replace <cluster-name> with the name specified for the cluster.
    2. Upload the bootstrap.ign Ignition config file to the bucket:

      1. $ aws s3 cp <installation_directory>/bootstrap.ign s3://<cluster-name>-infra/bootstrap.ign (1)
      1For <installation_directory>, specify the path to the directory that you stored the installation files in.
    3. Verify that the file uploaded:

      1. $ aws s3 ls s3://<cluster-name>-infra/

      Example output

      1. 2019-04-03 16:15:16 314878 bootstrap.ign
  2. Create a JSON file that contains the parameter values that the template requires:

    1. [
    2. {
    3. "ParameterKey": "InfrastructureName", (1)
    4. "ParameterValue": "mycluster-<random_string>" (2)
    5. },
    6. {
    7. "ParameterKey": "RhcosAmi", (3)
    8. "ParameterValue": "ami-<random_string>" (4)
    9. },
    10. {
    11. "ParameterKey": "AllowedBootstrapSshCidr", (5)
    12. "ParameterValue": "0.0.0.0/0" (6)
    13. },
    14. {
    15. "ParameterKey": "PublicSubnet", (7)
    16. "ParameterValue": "subnet-<random_string>" (8)
    17. },
    18. {
    19. "ParameterKey": "MasterSecurityGroupId", (9)
    20. "ParameterValue": "sg-<random_string>" (10)
    21. },
    22. {
    23. "ParameterKey": "VpcId", (11)
    24. "ParameterValue": "vpc-<random_string>" (12)
    25. },
    26. {
    27. "ParameterKey": "BootstrapIgnitionLocation", (13)
    28. "ParameterValue": "s3://<bucket_name>/bootstrap.ign" (14)
    29. },
    30. {
    31. "ParameterKey": "AutoRegisterELB", (15)
    32. "ParameterValue": "yes" (16)
    33. },
    34. {
    35. "ParameterKey": "RegisterNlbIpTargetsLambdaArn", (17)
    36. "ParameterValue": "arn:aws:lambda:<region>:<account_number>:function:<dns_stack_name>-RegisterNlbIpTargets-<random_string>" (18)
    37. },
    38. {
    39. "ParameterKey": "ExternalApiTargetGroupArn", (19)
    40. "ParameterValue": "arn:aws:elasticloadbalancing:<region>:<account_number>:targetgroup/<dns_stack_name>-Exter-<random_string>" (20)
    41. },
    42. {
    43. "ParameterKey": "InternalApiTargetGroupArn", (21)
    44. "ParameterValue": "arn:aws:elasticloadbalancing:<region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>" (22)
    45. },
    46. {
    47. "ParameterKey": "InternalServiceTargetGroupArn", (23)
    48. "ParameterValue": "arn:aws:elasticloadbalancing:<region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>" (24)
    49. }
    50. ]
    1The name for your cluster infrastructure that is encoded in your Ignition config files for the cluster.
    2Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster-name>-<random-string>.
    3Current Fedora CoreOS (FCOS) AMI to use for the bootstrap node.
    4Specify a valid AWS::EC2::Image::Id value.
    5CIDR block to allow SSH access to the bootstrap node.
    6Specify a CIDR block in the format x.x.x.x/16-24.
    7The public subnet that is associated with your VPC to launch the bootstrap node into.
    8Specify the PublicSubnetIds value from the output of the CloudFormation template for the VPC.
    9The master security group ID (for registering temporary rules)
    10Specify the MasterSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    11The VPC created resources will belong to.
    12Specify the VpcId value from the output of the CloudFormation template for the VPC.
    13Location to fetch bootstrap Ignition config file from.
    14Specify the S3 bucket and file name in the form s3://<bucket_name>/bootstrap.ign.
    15Whether or not to register a network load balancer (NLB).
    16Specify yes or no. If you specify yes, you must provide a Lambda Amazon Resource Name (ARN) value.
    17The ARN for NLB IP target registration lambda group.
    18Specify the RegisterNlbIpTargetsLambda value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    19The ARN for external API load balancer target group.
    20Specify the ExternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    21The ARN for internal API load balancer target group.
    22Specify the InternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    23The ARN for internal service load balancer target group.
    24Specify the InternalServiceTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
  3. Copy the template from the CloudFormation template for the bootstrap machine section of this topic and save it as a YAML file on your computer. This template describes the bootstrap machine that your cluster requires.

  4. Launch the CloudFormation template to create a stack of AWS resources that represent the bootstrap node:

    You must enter the command on a single line.

    1. $ aws cloudformation create-stack --stack-name <name> (1)
    2. --template-body file://<template>.yaml (2)
    3. --parameters file://<parameters>.json (3)
    4. --capabilities CAPABILITY_NAMED_IAM (4)
    1<name> is the name for the CloudFormation stack, such as cluster-bootstrap. You need the name of this stack if you remove the cluster.
    2<template> is the relative path to and name of the CloudFormation template YAML file that you saved.
    3<parameters> is the relative path to and name of the CloudFormation parameters JSON file.
    4You must explicitly declare the CAPABILITY_NAMED_IAM capability because the provided template creates some AWS::IAM::Role and AWS::IAM::InstanceProfile resources.

    Example output

    1. arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-bootstrap/12944486-2add-11eb-9dee-12dace8e3a83
  5. Confirm that the template components exist:

    1. $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must provide these parameter values to the other CloudFormation templates that you run to create your cluster:

    BootstrapInstanceId

    The bootstrap Instance ID.

    BootstrapPublicIp

    The bootstrap node public IP address.

    BootstrapPrivateIp

    The bootstrap node private IP address.

CloudFormation template for the bootstrap machine

You can use the following CloudFormation template to deploy the bootstrap machine that you need for your OKD cluster.

CloudFormation template for the bootstrap machine

  1. AWSTemplateFormatVersion: 2010-09-09
  2. Description: Template for OpenShift Cluster Bootstrap (EC2 Instance, Security Groups and IAM)
  3. Parameters:
  4. InfrastructureName:
  5. AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
  6. MaxLength: 27
  7. MinLength: 1
  8. ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
  9. Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
  10. Type: String
  11. RhcosAmi:
  12. Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
  13. Type: AWS::EC2::Image::Id
  14. AllowedBootstrapSshCidr:
  15. 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])(\/([0-9]|1[0-9]|2[0-9]|3[0-2]))$
  16. ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/0-32.
  17. Default: 0.0.0.0/0
  18. Description: CIDR block to allow SSH access to the bootstrap node.
  19. Type: String
  20. PublicSubnet:
  21. Description: The public subnet to launch the bootstrap node into.
  22. Type: AWS::EC2::Subnet::Id
  23. MasterSecurityGroupId:
  24. Description: The master security group ID for registering temporary rules.
  25. Type: AWS::EC2::SecurityGroup::Id
  26. VpcId:
  27. Description: The VPC-scoped resources will belong to this VPC.
  28. Type: AWS::EC2::VPC::Id
  29. BootstrapIgnitionLocation:
  30. Default: s3://my-s3-bucket/bootstrap.ign
  31. Description: Ignition config file location.
  32. Type: String
  33. AutoRegisterELB:
  34. Default: "yes"
  35. AllowedValues:
  36. - "yes"
  37. - "no"
  38. Description: Do you want to invoke NLB registration, which requires a Lambda ARN parameter?
  39. Type: String
  40. RegisterNlbIpTargetsLambdaArn:
  41. Description: ARN for NLB IP target registration lambda.
  42. Type: String
  43. ExternalApiTargetGroupArn:
  44. Description: ARN for external API load balancer target group.
  45. Type: String
  46. InternalApiTargetGroupArn:
  47. Description: ARN for internal API load balancer target group.
  48. Type: String
  49. InternalServiceTargetGroupArn:
  50. Description: ARN for internal service load balancer target group.
  51. Type: String
  52. Metadata:
  53. AWS::CloudFormation::Interface:
  54. ParameterGroups:
  55. - Label:
  56. default: "Cluster Information"
  57. Parameters:
  58. - InfrastructureName
  59. - Label:
  60. default: "Host Information"
  61. Parameters:
  62. - RhcosAmi
  63. - BootstrapIgnitionLocation
  64. - MasterSecurityGroupId
  65. - Label:
  66. default: "Network Configuration"
  67. Parameters:
  68. - VpcId
  69. - AllowedBootstrapSshCidr
  70. - PublicSubnet
  71. - Label:
  72. default: "Load Balancer Automation"
  73. Parameters:
  74. - AutoRegisterELB
  75. - RegisterNlbIpTargetsLambdaArn
  76. - ExternalApiTargetGroupArn
  77. - InternalApiTargetGroupArn
  78. - InternalServiceTargetGroupArn
  79. ParameterLabels:
  80. InfrastructureName:
  81. default: "Infrastructure Name"
  82. VpcId:
  83. default: "VPC ID"
  84. AllowedBootstrapSshCidr:
  85. default: "Allowed SSH Source"
  86. PublicSubnet:
  87. default: "Public Subnet"
  88. RhcosAmi:
  89. default: "Red Hat Enterprise Linux CoreOS AMI ID"
  90. BootstrapIgnitionLocation:
  91. default: "Bootstrap Ignition Source"
  92. MasterSecurityGroupId:
  93. default: "Master Security Group ID"
  94. AutoRegisterELB:
  95. default: "Use Provided ELB Automation"
  96. Conditions:
  97. DoRegistration: !Equals ["yes", !Ref AutoRegisterELB]
  98. Resources:
  99. BootstrapIamRole:
  100. Type: AWS::IAM::Role
  101. Properties:
  102. AssumeRolePolicyDocument:
  103. Version: "2012-10-17"
  104. Statement:
  105. - Effect: "Allow"
  106. Principal:
  107. Service:
  108. - "ec2.amazonaws.com"
  109. Action:
  110. - "sts:AssumeRole"
  111. Path: "/"
  112. Policies:
  113. - PolicyName: !Join ["-", [!Ref InfrastructureName, "bootstrap", "policy"]]
  114. PolicyDocument:
  115. Version: "2012-10-17"
  116. Statement:
  117. - Effect: "Allow"
  118. Action: "ec2:Describe*"
  119. Resource: "*"
  120. - Effect: "Allow"
  121. Action: "ec2:AttachVolume"
  122. Resource: "*"
  123. - Effect: "Allow"
  124. Action: "ec2:DetachVolume"
  125. Resource: "*"
  126. - Effect: "Allow"
  127. Action: "s3:GetObject"
  128. Resource: "*"
  129. BootstrapInstanceProfile:
  130. Type: "AWS::IAM::InstanceProfile"
  131. Properties:
  132. Path: "/"
  133. Roles:
  134. - Ref: "BootstrapIamRole"
  135. BootstrapSecurityGroup:
  136. Type: AWS::EC2::SecurityGroup
  137. Properties:
  138. GroupDescription: Cluster Bootstrap Security Group
  139. SecurityGroupIngress:
  140. - IpProtocol: tcp
  141. FromPort: 22
  142. ToPort: 22
  143. CidrIp: !Ref AllowedBootstrapSshCidr
  144. - IpProtocol: tcp
  145. ToPort: 19531
  146. FromPort: 19531
  147. CidrIp: 0.0.0.0/0
  148. VpcId: !Ref VpcId
  149. BootstrapInstance:
  150. Type: AWS::EC2::Instance
  151. Properties:
  152. ImageId: !Ref RhcosAmi
  153. IamInstanceProfile: !Ref BootstrapInstanceProfile
  154. InstanceType: "i3.large"
  155. NetworkInterfaces:
  156. - AssociatePublicIpAddress: "true"
  157. DeviceIndex: "0"
  158. GroupSet:
  159. - !Ref "BootstrapSecurityGroup"
  160. - !Ref "MasterSecurityGroupId"
  161. SubnetId: !Ref "PublicSubnet"
  162. UserData:
  163. Fn::Base64: !Sub
  164. - '{"ignition":{"config":{"replace":{"source":"${S3Loc}"}},"version":"3.1.0"}}'
  165. - {
  166. S3Loc: !Ref BootstrapIgnitionLocation
  167. }
  168. RegisterBootstrapApiTarget:
  169. Condition: DoRegistration
  170. Type: Custom::NLBRegister
  171. Properties:
  172. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  173. TargetArn: !Ref ExternalApiTargetGroupArn
  174. TargetIp: !GetAtt BootstrapInstance.PrivateIp
  175. RegisterBootstrapInternalApiTarget:
  176. Condition: DoRegistration
  177. Type: Custom::NLBRegister
  178. Properties:
  179. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  180. TargetArn: !Ref InternalApiTargetGroupArn
  181. TargetIp: !GetAtt BootstrapInstance.PrivateIp
  182. RegisterBootstrapInternalServiceTarget:
  183. Condition: DoRegistration
  184. Type: Custom::NLBRegister
  185. Properties:
  186. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  187. TargetArn: !Ref InternalServiceTargetGroupArn
  188. TargetIp: !GetAtt BootstrapInstance.PrivateIp
  189. Outputs:
  190. BootstrapInstanceId:
  191. Description: Bootstrap Instance ID.
  192. Value: !Ref BootstrapInstance
  193. BootstrapPublicIp:
  194. Description: The bootstrap node public IP address.
  195. Value: !GetAtt BootstrapInstance.PublicIp
  196. BootstrapPrivateIp:
  197. Description: The bootstrap node private IP address.
  198. Value: !GetAtt BootstrapInstance.PrivateIp

Additional resources

Creating the control plane machines in AWS

You must create the control plane machines in Amazon Web Services (AWS) that your cluster will use.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources that represent the control plane nodes.

The CloudFormation template creates a stack that represents three control plane nodes.

If you do not use the provided CloudFormation template to create your control plane nodes, 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 generated the Ignition config files for your cluster.

  • You created and configured a VPC and associated subnets in AWS.

  • You created and configured DNS, load balancers, and listeners in AWS.

  • You created the security groups and roles required for your cluster in AWS.

  • You created the bootstrap machine.

Procedure

  1. Create a JSON file that contains the parameter values that the template requires:

    1. [
    2. {
    3. "ParameterKey": "InfrastructureName", (1)
    4. "ParameterValue": "mycluster-<random_string>" (2)
    5. },
    6. {
    7. "ParameterKey": "RhcosAmi", (3)
    8. "ParameterValue": "ami-<random_string>" (4)
    9. },
    10. {
    11. "ParameterKey": "AutoRegisterDNS", (5)
    12. "ParameterValue": "yes" (6)
    13. },
    14. {
    15. "ParameterKey": "PrivateHostedZoneId", (7)
    16. "ParameterValue": "<random_string>" (8)
    17. },
    18. {
    19. "ParameterKey": "PrivateHostedZoneName", (9)
    20. "ParameterValue": "mycluster.example.com" (10)
    21. },
    22. {
    23. "ParameterKey": "Master0Subnet", (11)
    24. "ParameterValue": "subnet-<random_string>" (12)
    25. },
    26. {
    27. "ParameterKey": "Master1Subnet", (11)
    28. "ParameterValue": "subnet-<random_string>" (12)
    29. },
    30. {
    31. "ParameterKey": "Master2Subnet", (11)
    32. "ParameterValue": "subnet-<random_string>" (12)
    33. },
    34. {
    35. "ParameterKey": "MasterSecurityGroupId", (13)
    36. "ParameterValue": "sg-<random_string>" (14)
    37. },
    38. {
    39. "ParameterKey": "IgnitionLocation", (15)
    40. "ParameterValue": "https://api-int.<cluster_name>.<domain_name>:22623/config/master" (16)
    41. },
    42. {
    43. "ParameterKey": "CertificateAuthorities", (17)
    44. "ParameterValue": "data:text/plain;charset=utf-8;base64,ABC...xYz==" (18)
    45. },
    46. {
    47. "ParameterKey": "MasterInstanceProfileName", (19)
    48. "ParameterValue": "<roles_stack>-MasterInstanceProfile-<random_string>" (20)
    49. },
    50. {
    51. "ParameterKey": "MasterInstanceType", (21)
    52. "ParameterValue": "m4.xlarge" (22)
    53. },
    54. {
    55. "ParameterKey": "AutoRegisterELB", (23)
    56. "ParameterValue": "yes" (24)
    57. },
    58. {
    59. "ParameterKey": "RegisterNlbIpTargetsLambdaArn", (25)
    60. "ParameterValue": "arn:aws:lambda:<region>:<account_number>:function:<dns_stack_name>-RegisterNlbIpTargets-<random_string>" (26)
    61. },
    62. {
    63. "ParameterKey": "ExternalApiTargetGroupArn", (27)
    64. "ParameterValue": "arn:aws:elasticloadbalancing:<region>:<account_number>:targetgroup/<dns_stack_name>-Exter-<random_string>" (28)
    65. },
    66. {
    67. "ParameterKey": "InternalApiTargetGroupArn", (29)
    68. "ParameterValue": "arn:aws:elasticloadbalancing:<region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>" (30)
    69. },
    70. {
    71. "ParameterKey": "InternalServiceTargetGroupArn", (31)
    72. "ParameterValue": "arn:aws:elasticloadbalancing:<region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>" (32)
    73. }
    74. ]
    1The name for your cluster infrastructure that is encoded in your Ignition config files for the cluster.
    2Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster-name>-<random-string>.
    3CurrentFedora CoreOS (FCOS) AMI to use for the control plane machines.
    4Specify an AWS::EC2::Image::Id value.
    5Whether or not to perform DNS etcd registration.
    6Specify yes or no. If you specify yes, you must provide hosted zone information.
    7The Route 53 private zone ID to register the etcd targets with.
    8Specify the PrivateHostedZoneId value from the output of the CloudFormation template for DNS and load balancing.
    9The Route 53 zone to register the targets with.
    10Specify <cluster_name>.<domain_name> where <domain_name> is the Route 53 base domain that you used when you generated install-config.yaml file for the cluster. Do not include the trailing period (.) that is displayed in the AWS console.
    11A subnet, preferably private, to launch the control plane machines on.
    12Specify a subnet from the PrivateSubnets value from the output of the CloudFormation template for DNS and load balancing.
    13The master security group ID to associate with control plane nodes (also known as the master nodes).
    14Specify the MasterSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    15The location to fetch control plane Ignition config file from.
    16Specify the generated Ignition config file location, https://api-int.<cluster_name>.<domain_name>:22623/config/master.
    17The base64 encoded certificate authority string to use.
    18Specify the value from the master.ign file that is in the installation directory. This value is the long string with the format data:text/plain;charset=utf-8;base64,ABC…​xYz==.
    19The IAM profile to associate with control plane nodes.
    20Specify the MasterInstanceProfile parameter value from the output of the CloudFormation template for the security group and roles.
    21The type of AWS instance to use for the control plane machines.
    22Allowed values:
    • m4.xlarge

    • m4.2xlarge

    • m4.4xlarge

    • m4.8xlarge

    • m4.10xlarge

    • m4.16xlarge

    • m5.xlarge

    • m5.2xlarge

    • m5.4xlarge

    • m5.8xlarge

    • m5.10xlarge

    • m5.16xlarge

    • c4.2xlarge

    • c4.4xlarge

    • c4.8xlarge

    • r4.xlarge

    • r4.2xlarge

    • r4.4xlarge

    • r4.8xlarge

    • r4.16xlarge

      If m4 instance types are not available in your region, such as with eu-west-3, specify an m5 type, such as m5.xlarge, instead.

    23Whether or not to register a network load balancer (NLB).
    24Specify yes or no. If you specify yes, you must provide a Lambda Amazon Resource Name (ARN) value.
    25The ARN for NLB IP target registration lambda group.
    26Specify the RegisterNlbIpTargetsLambda value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    27The ARN for external API load balancer target group.
    28Specify the ExternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    29The ARN for internal API load balancer target group.
    30Specify the InternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    31The ARN for internal service load balancer target group.
    32Specify the InternalServiceTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
  2. Copy the template from the CloudFormation template for control plane machines section of this topic and save it as a YAML file on your computer. This template describes the control plane machines that your cluster requires.

  3. If you specified an m5 instance type as the value for MasterInstanceType, add that instance type to the MasterInstanceType.AllowedValues parameter in the CloudFormation template.

  4. Launch the CloudFormation template to create a stack of AWS resources that represent the control plane nodes:

    You must enter the command on a single line.

    1. $ aws cloudformation create-stack --stack-name <name> (1)
    2. --template-body file://<template>.yaml (2)
    3. --parameters file://<parameters>.json (3)
    1<name> is the name for the CloudFormation stack, such as cluster-control-plane. You need the name of this stack if you remove the cluster.
    2<template> is the relative path to and name of the CloudFormation template YAML file that you saved.
    3<parameters> is the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    1. arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-control-plane/21c7e2b0-2ee2-11eb-c6f6-0aa34627df4b

    The CloudFormation template creates a stack that represents three control plane nodes.

  5. Confirm that the template components exist:

    1. $ aws cloudformation describe-stacks --stack-name <name>

CloudFormation template for control plane machines

You can use the following CloudFormation template to deploy the control plane machines that you need for your OKD cluster.

CloudFormation template for control plane machines

  1. AWSTemplateFormatVersion: 2010-09-09
  2. Description: Template for OpenShift Cluster Node Launch (EC2 master instances)
  3. Parameters:
  4. InfrastructureName:
  5. AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
  6. MaxLength: 27
  7. MinLength: 1
  8. ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
  9. Description: A short, unique cluster ID used to tag nodes for the kubelet cloud provider.
  10. Type: String
  11. RhcosAmi:
  12. Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
  13. Type: AWS::EC2::Image::Id
  14. AutoRegisterDNS:
  15. Default: "yes"
  16. AllowedValues:
  17. - "yes"
  18. - "no"
  19. Description: Do you want to invoke DNS etcd registration, which requires Hosted Zone information?
  20. Type: String
  21. PrivateHostedZoneId:
  22. Description: The Route53 private zone ID to register the etcd targets with, such as Z21IXYZABCZ2A4.
  23. Type: String
  24. PrivateHostedZoneName:
  25. Description: The Route53 zone to register the targets with, such as cluster.example.com. Omit the trailing period.
  26. Type: String
  27. Master0Subnet:
  28. Description: The subnets, recommend private, to launch the master nodes into.
  29. Type: AWS::EC2::Subnet::Id
  30. Master1Subnet:
  31. Description: The subnets, recommend private, to launch the master nodes into.
  32. Type: AWS::EC2::Subnet::Id
  33. Master2Subnet:
  34. Description: The subnets, recommend private, to launch the master nodes into.
  35. Type: AWS::EC2::Subnet::Id
  36. MasterSecurityGroupId:
  37. Description: The master security group ID to associate with master nodes.
  38. Type: AWS::EC2::SecurityGroup::Id
  39. IgnitionLocation:
  40. Default: https://api-int.$CLUSTER_NAME.$DOMAIN:22623/config/master
  41. Description: Ignition config file location.
  42. Type: String
  43. CertificateAuthorities:
  44. Default: data:text/plain;charset=utf-8;base64,ABC...xYz==
  45. Description: Base64 encoded certificate authority string to use.
  46. Type: String
  47. MasterInstanceProfileName:
  48. Description: IAM profile to associate with master nodes.
  49. Type: String
  50. MasterInstanceType:
  51. Default: m5.xlarge
  52. Type: String
  53. AllowedValues:
  54. - "m4.xlarge"
  55. - "m4.2xlarge"
  56. - "m4.4xlarge"
  57. - "m4.10xlarge"
  58. - "m4.16xlarge"
  59. - "m5.xlarge"
  60. - "m5.2xlarge"
  61. - "m5.4xlarge"
  62. - "m5.8xlarge"
  63. - "m5.12xlarge"
  64. - "m5.16xlarge"
  65. - "m5a.xlarge"
  66. - "m5a.2xlarge"
  67. - "m5a.4xlarge"
  68. - "m5a.8xlarge"
  69. - "m5a.10xlarge"
  70. - "m5a.16xlarge"
  71. - "c4.2xlarge"
  72. - "c4.4xlarge"
  73. - "c4.8xlarge"
  74. - "c5.2xlarge"
  75. - "c5.4xlarge"
  76. - "c5.9xlarge"
  77. - "c5.12xlarge"
  78. - "c5.18xlarge"
  79. - "c5.24xlarge"
  80. - "c5a.2xlarge"
  81. - "c5a.4xlarge"
  82. - "c5a.8xlarge"
  83. - "c5a.12xlarge"
  84. - "c5a.16xlarge"
  85. - "c5a.24xlarge"
  86. - "r4.xlarge"
  87. - "r4.2xlarge"
  88. - "r4.4xlarge"
  89. - "r4.8xlarge"
  90. - "r4.16xlarge"
  91. - "r5.xlarge"
  92. - "r5.2xlarge"
  93. - "r5.4xlarge"
  94. - "r5.8xlarge"
  95. - "r5.12xlarge"
  96. - "r5.16xlarge"
  97. - "r5.24xlarge"
  98. - "r5a.xlarge"
  99. - "r5a.2xlarge"
  100. - "r5a.4xlarge"
  101. - "r5a.8xlarge"
  102. - "r5a.12xlarge"
  103. - "r5a.16xlarge"
  104. - "r5a.24xlarge"
  105. AutoRegisterELB:
  106. Default: "yes"
  107. AllowedValues:
  108. - "yes"
  109. - "no"
  110. Description: Do you want to invoke NLB registration, which requires a Lambda ARN parameter?
  111. Type: String
  112. RegisterNlbIpTargetsLambdaArn:
  113. Description: ARN for NLB IP target registration lambda. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
  114. Type: String
  115. ExternalApiTargetGroupArn:
  116. Description: ARN for external API load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
  117. Type: String
  118. InternalApiTargetGroupArn:
  119. Description: ARN for internal API load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
  120. Type: String
  121. InternalServiceTargetGroupArn:
  122. Description: ARN for internal service load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
  123. Type: String
  124. Metadata:
  125. AWS::CloudFormation::Interface:
  126. ParameterGroups:
  127. - Label:
  128. default: "Cluster Information"
  129. Parameters:
  130. - InfrastructureName
  131. - Label:
  132. default: "Host Information"
  133. Parameters:
  134. - MasterInstanceType
  135. - RhcosAmi
  136. - IgnitionLocation
  137. - CertificateAuthorities
  138. - MasterSecurityGroupId
  139. - MasterInstanceProfileName
  140. - Label:
  141. default: "Network Configuration"
  142. Parameters:
  143. - VpcId
  144. - AllowedBootstrapSshCidr
  145. - Master0Subnet
  146. - Master1Subnet
  147. - Master2Subnet
  148. - Label:
  149. default: "DNS"
  150. Parameters:
  151. - AutoRegisterDNS
  152. - PrivateHostedZoneName
  153. - PrivateHostedZoneId
  154. - Label:
  155. default: "Load Balancer Automation"
  156. Parameters:
  157. - AutoRegisterELB
  158. - RegisterNlbIpTargetsLambdaArn
  159. - ExternalApiTargetGroupArn
  160. - InternalApiTargetGroupArn
  161. - InternalServiceTargetGroupArn
  162. ParameterLabels:
  163. InfrastructureName:
  164. default: "Infrastructure Name"
  165. VpcId:
  166. default: "VPC ID"
  167. Master0Subnet:
  168. default: "Master-0 Subnet"
  169. Master1Subnet:
  170. default: "Master-1 Subnet"
  171. Master2Subnet:
  172. default: "Master-2 Subnet"
  173. MasterInstanceType:
  174. default: "Master Instance Type"
  175. MasterInstanceProfileName:
  176. default: "Master Instance Profile Name"
  177. RhcosAmi:
  178. default: "Red Hat Enterprise Linux CoreOS AMI ID"
  179. BootstrapIgnitionLocation:
  180. default: "Master Ignition Source"
  181. CertificateAuthorities:
  182. default: "Ignition CA String"
  183. MasterSecurityGroupId:
  184. default: "Master Security Group ID"
  185. AutoRegisterDNS:
  186. default: "Use Provided DNS Automation"
  187. AutoRegisterELB:
  188. default: "Use Provided ELB Automation"
  189. PrivateHostedZoneName:
  190. default: "Private Hosted Zone Name"
  191. PrivateHostedZoneId:
  192. default: "Private Hosted Zone ID"
  193. Conditions:
  194. DoRegistration: !Equals ["yes", !Ref AutoRegisterELB]
  195. DoDns: !Equals ["yes", !Ref AutoRegisterDNS]
  196. Resources:
  197. Master0:
  198. Type: AWS::EC2::Instance
  199. Properties:
  200. ImageId: !Ref RhcosAmi
  201. BlockDeviceMappings:
  202. - DeviceName: /dev/xvda
  203. Ebs:
  204. VolumeSize: "120"
  205. VolumeType: "gp2"
  206. IamInstanceProfile: !Ref MasterInstanceProfileName
  207. InstanceType: !Ref MasterInstanceType
  208. NetworkInterfaces:
  209. - AssociatePublicIpAddress: "false"
  210. DeviceIndex: "0"
  211. GroupSet:
  212. - !Ref "MasterSecurityGroupId"
  213. SubnetId: !Ref "Master0Subnet"
  214. UserData:
  215. Fn::Base64: !Sub
  216. - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
  217. - {
  218. SOURCE: !Ref IgnitionLocation,
  219. CA_BUNDLE: !Ref CertificateAuthorities,
  220. }
  221. Tags:
  222. - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
  223. Value: "shared"
  224. RegisterMaster0:
  225. Condition: DoRegistration
  226. Type: Custom::NLBRegister
  227. Properties:
  228. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  229. TargetArn: !Ref ExternalApiTargetGroupArn
  230. TargetIp: !GetAtt Master0.PrivateIp
  231. RegisterMaster0InternalApiTarget:
  232. Condition: DoRegistration
  233. Type: Custom::NLBRegister
  234. Properties:
  235. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  236. TargetArn: !Ref InternalApiTargetGroupArn
  237. TargetIp: !GetAtt Master0.PrivateIp
  238. RegisterMaster0InternalServiceTarget:
  239. Condition: DoRegistration
  240. Type: Custom::NLBRegister
  241. Properties:
  242. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  243. TargetArn: !Ref InternalServiceTargetGroupArn
  244. TargetIp: !GetAtt Master0.PrivateIp
  245. Master1:
  246. Type: AWS::EC2::Instance
  247. Properties:
  248. ImageId: !Ref RhcosAmi
  249. BlockDeviceMappings:
  250. - DeviceName: /dev/xvda
  251. Ebs:
  252. VolumeSize: "120"
  253. VolumeType: "gp2"
  254. IamInstanceProfile: !Ref MasterInstanceProfileName
  255. InstanceType: !Ref MasterInstanceType
  256. NetworkInterfaces:
  257. - AssociatePublicIpAddress: "false"
  258. DeviceIndex: "0"
  259. GroupSet:
  260. - !Ref "MasterSecurityGroupId"
  261. SubnetId: !Ref "Master1Subnet"
  262. UserData:
  263. Fn::Base64: !Sub
  264. - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
  265. - {
  266. SOURCE: !Ref IgnitionLocation,
  267. CA_BUNDLE: !Ref CertificateAuthorities,
  268. }
  269. Tags:
  270. - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
  271. Value: "shared"
  272. RegisterMaster1:
  273. Condition: DoRegistration
  274. Type: Custom::NLBRegister
  275. Properties:
  276. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  277. TargetArn: !Ref ExternalApiTargetGroupArn
  278. TargetIp: !GetAtt Master1.PrivateIp
  279. RegisterMaster1InternalApiTarget:
  280. Condition: DoRegistration
  281. Type: Custom::NLBRegister
  282. Properties:
  283. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  284. TargetArn: !Ref InternalApiTargetGroupArn
  285. TargetIp: !GetAtt Master1.PrivateIp
  286. RegisterMaster1InternalServiceTarget:
  287. Condition: DoRegistration
  288. Type: Custom::NLBRegister
  289. Properties:
  290. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  291. TargetArn: !Ref InternalServiceTargetGroupArn
  292. TargetIp: !GetAtt Master1.PrivateIp
  293. Master2:
  294. Type: AWS::EC2::Instance
  295. Properties:
  296. ImageId: !Ref RhcosAmi
  297. BlockDeviceMappings:
  298. - DeviceName: /dev/xvda
  299. Ebs:
  300. VolumeSize: "120"
  301. VolumeType: "gp2"
  302. IamInstanceProfile: !Ref MasterInstanceProfileName
  303. InstanceType: !Ref MasterInstanceType
  304. NetworkInterfaces:
  305. - AssociatePublicIpAddress: "false"
  306. DeviceIndex: "0"
  307. GroupSet:
  308. - !Ref "MasterSecurityGroupId"
  309. SubnetId: !Ref "Master2Subnet"
  310. UserData:
  311. Fn::Base64: !Sub
  312. - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
  313. - {
  314. SOURCE: !Ref IgnitionLocation,
  315. CA_BUNDLE: !Ref CertificateAuthorities,
  316. }
  317. Tags:
  318. - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
  319. Value: "shared"
  320. RegisterMaster2:
  321. Condition: DoRegistration
  322. Type: Custom::NLBRegister
  323. Properties:
  324. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  325. TargetArn: !Ref ExternalApiTargetGroupArn
  326. TargetIp: !GetAtt Master2.PrivateIp
  327. RegisterMaster2InternalApiTarget:
  328. Condition: DoRegistration
  329. Type: Custom::NLBRegister
  330. Properties:
  331. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  332. TargetArn: !Ref InternalApiTargetGroupArn
  333. TargetIp: !GetAtt Master2.PrivateIp
  334. RegisterMaster2InternalServiceTarget:
  335. Condition: DoRegistration
  336. Type: Custom::NLBRegister
  337. Properties:
  338. ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
  339. TargetArn: !Ref InternalServiceTargetGroupArn
  340. TargetIp: !GetAtt Master2.PrivateIp
  341. EtcdSrvRecords:
  342. Condition: DoDns
  343. Type: AWS::Route53::RecordSet
  344. Properties:
  345. HostedZoneId: !Ref PrivateHostedZoneId
  346. Name: !Join [".", ["_etcd-server-ssl._tcp", !Ref PrivateHostedZoneName]]
  347. ResourceRecords:
  348. - !Join [
  349. " ",
  350. ["0 10 2380", !Join [".", ["etcd-0", !Ref PrivateHostedZoneName]]],
  351. ]
  352. - !Join [
  353. " ",
  354. ["0 10 2380", !Join [".", ["etcd-1", !Ref PrivateHostedZoneName]]],
  355. ]
  356. - !Join [
  357. " ",
  358. ["0 10 2380", !Join [".", ["etcd-2", !Ref PrivateHostedZoneName]]],
  359. ]
  360. TTL: 60
  361. Type: SRV
  362. Etcd0Record:
  363. Condition: DoDns
  364. Type: AWS::Route53::RecordSet
  365. Properties:
  366. HostedZoneId: !Ref PrivateHostedZoneId
  367. Name: !Join [".", ["etcd-0", !Ref PrivateHostedZoneName]]
  368. ResourceRecords:
  369. - !GetAtt Master0.PrivateIp
  370. TTL: 60
  371. Type: A
  372. Etcd1Record:
  373. Condition: DoDns
  374. Type: AWS::Route53::RecordSet
  375. Properties:
  376. HostedZoneId: !Ref PrivateHostedZoneId
  377. Name: !Join [".", ["etcd-1", !Ref PrivateHostedZoneName]]
  378. ResourceRecords:
  379. - !GetAtt Master1.PrivateIp
  380. TTL: 60
  381. Type: A
  382. Etcd2Record:
  383. Condition: DoDns
  384. Type: AWS::Route53::RecordSet
  385. Properties:
  386. HostedZoneId: !Ref PrivateHostedZoneId
  387. Name: !Join [".", ["etcd-2", !Ref PrivateHostedZoneName]]
  388. ResourceRecords:
  389. - !GetAtt Master2.PrivateIp
  390. TTL: 60
  391. Type: A
  392. Outputs:
  393. PrivateIPs:
  394. Description: The control-plane node private IP addresses.
  395. Value:
  396. !Join [
  397. ",",
  398. [!GetAtt Master0.PrivateIp, !GetAtt Master1.PrivateIp, !GetAtt Master2.PrivateIp]
  399. ]

Additional resources

Creating the worker nodes in AWS

You can create worker nodes in Amazon Web Services (AWS) for your cluster to use.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources that represent a worker node.

The CloudFormation template creates a stack that represents one worker node. You must create a stack for each worker node.

If you do not use the provided CloudFormation template to create your worker nodes, 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 generated the Ignition config files for your cluster.

  • You created and configured a VPC and associated subnets in AWS.

  • You created and configured DNS, load balancers, and listeners in AWS.

  • You created the security groups and roles required for your cluster in AWS.

  • You created the bootstrap machine.

  • You created the control plane machines.

Procedure

  1. Create a JSON file that contains the parameter values that the CloudFormation template requires:

    1. [
    2. {
    3. "ParameterKey": "InfrastructureName", (1)
    4. "ParameterValue": "mycluster-<random_string>" (2)
    5. },
    6. {
    7. "ParameterKey": "RhcosAmi", (3)
    8. "ParameterValue": "ami-<random_string>" (4)
    9. },
    10. {
    11. "ParameterKey": "Subnet", (5)
    12. "ParameterValue": "subnet-<random_string>" (6)
    13. },
    14. {
    15. "ParameterKey": "WorkerSecurityGroupId", (7)
    16. "ParameterValue": "sg-<random_string>" (8)
    17. },
    18. {
    19. "ParameterKey": "IgnitionLocation", (9)
    20. "ParameterValue": "https://api-int.<cluster_name>.<domain_name>:22623/config/worker" (10)
    21. },
    22. {
    23. "ParameterKey": "CertificateAuthorities", (11)
    24. "ParameterValue": "" (12)
    25. },
    26. {
    27. "ParameterKey": "WorkerInstanceProfileName", (13)
    28. "ParameterValue": "" (14)
    29. },
    30. {
    31. "ParameterKey": "WorkerInstanceType", (15)
    32. "ParameterValue": "m4.large" (16)
    33. }
    34. ]
    1The name for your cluster infrastructure that is encoded in your Ignition config files for the cluster.
    2Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster-name>-<random-string>.
    3Current Fedora CoreOS (FCOS) AMI to use for the worker nodes.
    4Specify an AWS::EC2::Image::Id value.
    5A subnet, preferably private, to launch the worker nodes on.
    6Specify a subnet from the PrivateSubnets value from the output of the CloudFormation template for DNS and load balancing.
    7The worker security group ID to associate with worker nodes.
    8Specify the WorkerSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    9The location to fetch bootstrap Ignition config file from.
    10Specify the generated Ignition config location, https://api-int.<cluster_name>.<domain_name>:22623/config/worker.
    11Base64 encoded certificate authority string to use.
    12Specify the value from the worker.ign file that is in the installation directory. This value is the long string with the format data:text/plain;charset=utf-8;base64,ABC…​xYz==.
    13The IAM profile to associate with worker nodes.
    14Specify the WorkerInstanceProfile parameter value from the output of the CloudFormation template for the security group and roles.
    15The type of AWS instance to use for the control plane machines.
    16Allowed values:
    • m4.large

    • m4.xlarge

    • m4.2xlarge

    • m4.4xlarge

    • m4.8xlarge

    • m4.10xlarge

    • m4.16xlarge

    • m5.large

    • m5.xlarge

    • m5.2xlarge

    • m5.4xlarge

    • m5.8xlarge

    • m5.10xlarge

    • m5.16xlarge

    • c4.large

    • c4.xlarge

    • c4.2xlarge

    • c4.4xlarge

    • c4.8xlarge

    • r4.large

    • r4.xlarge

    • r4.2xlarge

    • r4.4xlarge

    • r4.8xlarge

    • r4.16xlarge

      If m4 instance types are not available in your region, such as with eu-west-3, use m5 types instead.

  2. Copy the template from the CloudFormation template for worker machines section of this topic and save it as a YAML file on your computer. This template describes the networking objects and load balancers that your cluster requires.

  3. If you specified an m5 instance type as the value for WorkerInstanceType, add that instance type to the WorkerInstanceType.AllowedValues parameter in the CloudFormation template.

  4. Launch the CloudFormation template to create a stack of AWS resources that represent a worker node:

    You must enter the command on a single line.

    1. $ aws cloudformation create-stack --stack-name <name> (1)
    2. --template-body file://<template>.yaml \ (2)
    3. --parameters file://<parameters>.json (3)
    1<name> is the name for the CloudFormation stack, such as cluster-worker-1. You need the name of this stack if you remove the cluster.
    2<template> is the relative path to and name of the CloudFormation template YAML file that you saved.
    3<parameters> is the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    1. arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-worker-1/729ee301-1c2a-11eb-348f-sd9888c65b59

    The CloudFormation template creates a stack that represents one worker node.

  5. Confirm that the template components exist:

    1. $ aws cloudformation describe-stacks --stack-name <name>
  6. Continue to create worker stacks until you have created enough worker machines for your cluster. You can create additional worker stacks by referencing the same template and parameter files and specifying a different stack name.

    You must create at least two worker machines, so you must create at least two stacks that use this CloudFormation template.

CloudFormation template for worker machines

You can use the following CloudFormation template to deploy the worker machines that you need for your OKD cluster.

CloudFormation template for worker machines

  1. AWSTemplateFormatVersion: 2010-09-09
  2. Description: Template for OpenShift Cluster Node Launch (EC2 worker instance)
  3. Parameters:
  4. InfrastructureName:
  5. AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
  6. MaxLength: 27
  7. MinLength: 1
  8. ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
  9. Description: A short, unique cluster ID used to tag nodes for the kubelet cloud provider.
  10. Type: String
  11. RhcosAmi:
  12. Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
  13. Type: AWS::EC2::Image::Id
  14. Subnet:
  15. Description: The subnets, recommend private, to launch the master nodes into.
  16. Type: AWS::EC2::Subnet::Id
  17. WorkerSecurityGroupId:
  18. Description: The master security group ID to associate with master nodes.
  19. Type: AWS::EC2::SecurityGroup::Id
  20. IgnitionLocation:
  21. Default: https://api-int.$CLUSTER_NAME.$DOMAIN:22623/config/worker
  22. Description: Ignition config file location.
  23. Type: String
  24. CertificateAuthorities:
  25. Default: data:text/plain;charset=utf-8;base64,ABC...xYz==
  26. Description: Base64 encoded certificate authority string to use.
  27. Type: String
  28. WorkerInstanceProfileName:
  29. Description: IAM profile to associate with master nodes.
  30. Type: String
  31. WorkerInstanceType:
  32. Default: m5.large
  33. Type: String
  34. AllowedValues:
  35. - "m4.large"
  36. - "m4.xlarge"
  37. - "m4.2xlarge"
  38. - "m4.4xlarge"
  39. - "m4.10xlarge"
  40. - "m4.16xlarge"
  41. - "m5.large"
  42. - "m5.xlarge"
  43. - "m5.2xlarge"
  44. - "m5.4xlarge"
  45. - "m5.8xlarge"
  46. - "m5.12xlarge"
  47. - "m5.16xlarge"
  48. - "m5a.large"
  49. - "m5a.xlarge"
  50. - "m5a.2xlarge"
  51. - "m5a.4xlarge"
  52. - "m5a.8xlarge"
  53. - "m5a.10xlarge"
  54. - "m5a.16xlarge"
  55. - "c4.large"
  56. - "c4.xlarge"
  57. - "c4.2xlarge"
  58. - "c4.4xlarge"
  59. - "c4.8xlarge"
  60. - "c5.large"
  61. - "c5.xlarge"
  62. - "c5.2xlarge"
  63. - "c5.4xlarge"
  64. - "c5.9xlarge"
  65. - "c5.12xlarge"
  66. - "c5.18xlarge"
  67. - "c5.24xlarge"
  68. - "c5a.large"
  69. - "c5a.xlarge"
  70. - "c5a.2xlarge"
  71. - "c5a.4xlarge"
  72. - "c5a.8xlarge"
  73. - "c5a.12xlarge"
  74. - "c5a.16xlarge"
  75. - "c5a.24xlarge"
  76. - "r4.large"
  77. - "r4.xlarge"
  78. - "r4.2xlarge"
  79. - "r4.4xlarge"
  80. - "r4.8xlarge"
  81. - "r4.16xlarge"
  82. - "r5.large"
  83. - "r5.xlarge"
  84. - "r5.2xlarge"
  85. - "r5.4xlarge"
  86. - "r5.8xlarge"
  87. - "r5.12xlarge"
  88. - "r5.16xlarge"
  89. - "r5.24xlarge"
  90. - "r5a.large"
  91. - "r5a.xlarge"
  92. - "r5a.2xlarge"
  93. - "r5a.4xlarge"
  94. - "r5a.8xlarge"
  95. - "r5a.12xlarge"
  96. - "r5a.16xlarge"
  97. - "r5a.24xlarge"
  98. - "t3.large"
  99. - "t3.xlarge"
  100. - "t3.2xlarge"
  101. - "t3a.large"
  102. - "t3a.xlarge"
  103. - "t3a.2xlarge"
  104. Metadata:
  105. AWS::CloudFormation::Interface:
  106. ParameterGroups:
  107. - Label:
  108. default: "Cluster Information"
  109. Parameters:
  110. - InfrastructureName
  111. - Label:
  112. default: "Host Information"
  113. Parameters:
  114. - WorkerInstanceType
  115. - RhcosAmi
  116. - IgnitionLocation
  117. - CertificateAuthorities
  118. - WorkerSecurityGroupId
  119. - WorkerInstanceProfileName
  120. - Label:
  121. default: "Network Configuration"
  122. Parameters:
  123. - Subnet
  124. ParameterLabels:
  125. Subnet:
  126. default: "Subnet"
  127. InfrastructureName:
  128. default: "Infrastructure Name"
  129. WorkerInstanceType:
  130. default: "Worker Instance Type"
  131. WorkerInstanceProfileName:
  132. default: "Worker Instance Profile Name"
  133. RhcosAmi:
  134. default: "Red Hat Enterprise Linux CoreOS AMI ID"
  135. IgnitionLocation:
  136. default: "Worker Ignition Source"
  137. CertificateAuthorities:
  138. default: "Ignition CA String"
  139. WorkerSecurityGroupId:
  140. default: "Worker Security Group ID"
  141. Resources:
  142. Worker0:
  143. Type: AWS::EC2::Instance
  144. Properties:
  145. ImageId: !Ref RhcosAmi
  146. BlockDeviceMappings:
  147. - DeviceName: /dev/xvda
  148. Ebs:
  149. VolumeSize: "120"
  150. VolumeType: "gp2"
  151. IamInstanceProfile: !Ref WorkerInstanceProfileName
  152. InstanceType: !Ref WorkerInstanceType
  153. NetworkInterfaces:
  154. - AssociatePublicIpAddress: "false"
  155. DeviceIndex: "0"
  156. GroupSet:
  157. - !Ref "WorkerSecurityGroupId"
  158. SubnetId: !Ref "Subnet"
  159. UserData:
  160. Fn::Base64: !Sub
  161. - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
  162. - {
  163. SOURCE: !Ref IgnitionLocation,
  164. CA_BUNDLE: !Ref CertificateAuthorities,
  165. }
  166. Tags:
  167. - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
  168. Value: "shared"
  169. Outputs:
  170. PrivateIP:
  171. Description: The compute node private IP address.
  172. Value: !GetAtt Worker0.PrivateIp

Additional resources

Initializing the bootstrap sequence on AWS with user-provisioned infrastructure

After you create all of the required infrastructure in Amazon Web Services (AWS), you can start the bootstrap sequence that initializes the OKD control plane.

Prerequisites

  • You configured an AWS account.

  • You added your AWS keys and region to your local AWS profile by running aws configure.

  • You generated the Ignition config files for your cluster.

  • You created and configured a VPC and associated subnets in AWS.

  • You created and configured DNS, load balancers, and listeners in AWS.

  • You created the security groups and roles required for your cluster in AWS.

  • You created the bootstrap machine.

  • You created the control plane machines.

  • You created the worker nodes.

Procedure

  1. Change to the directory that contains the installation program and start the bootstrap process that initializes the OKD control plane:

    1. $ ./openshift-install wait-for bootstrap-complete --dir=<installation_directory> \ (1)
    2. --log-level=info (2)
    1For <installation_directory>, specify the path to the directory that you stored the installation files in.
    2To view different installation details, specify warn, debug, or error instead of info.

    Example output

    1. INFO Waiting up to 20m0s for the Kubernetes API at https://api.mycluster.example.com:6443...
    2. INFO API v1.19.0+9f84db3 up
    3. INFO Waiting up to 30m0s for bootstrapping to complete...
    4. INFO It is now safe to remove the bootstrap resources
    5. INFO Time elapsed: 1s

    If the command exits without a FATAL warning, your OKD control plane has initialized.

    After the control plane initializes, it sets up the compute nodes and installs additional services in the form of Operators.

Additional resources

Installing the OpenShift CLI by downloading the binary

You can install the OpenShift CLI (oc) in order to interact with OKD from a command-line interface. You can install oc on Linux, Windows, or macOS.

If you installed an earlier version of oc, you cannot use it to complete all of the commands in OKD 4.6. Download and install the new version of oc.

Installing the OpenShift CLI on Linux

You can install the OpenShift CLI (oc) binary on Linux by using the following procedure.

Procedure

  1. Navigate to https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/ and choose the folder for your operating system and architecture.

  2. Download oc.tar.gz.

  3. Unpack the archive:

    1. $ tar xvzf <file>
  4. Place the oc binary in a directory that is on your PATH.

    To check your PATH, execute the following command:

    1. $ echo $PATH

After you install the OpenShift CLI, it is available using the oc command:

  1. $ oc <command>

Installing the OpenShift CLI on Windows

You can install the OpenShift CLI (oc) binary on Windows by using the following procedure.

Procedure

  1. Navigate to https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/ and choose the folder for your operating system and architecture.

  2. Download oc.zip.

  3. Unzip the archive with a ZIP program.

  4. Move the oc binary to a directory that is on your PATH.

    To check your PATH, open the command prompt and execute the following command:

    1. C:\> path

After you install the OpenShift CLI, it is available using the oc command:

  1. C:\> oc <command>

Installing the OpenShift CLI on macOS

You can install the OpenShift CLI (oc) binary on macOS by using the following procedure.

Procedure

  1. Navigate to https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/ and choose the folder for your operating system and architecture.

  2. Download oc.tar.gz.

  3. Unpack and unzip the archive.

  4. Move the oc binary to a directory on your PATH.

    To check your PATH, open a terminal and execute the following command:

    1. $ echo $PATH

After you install the OpenShift CLI, it is available using the oc command:

  1. $ oc <command>

Logging in to the cluster by using the CLI

You can log in to your cluster as a default system user by exporting the cluster kubeconfig file. The kubeconfig file contains information about the cluster that is used by the CLI to connect a client to the correct cluster and API server. The file is specific to a cluster and is created during OKD installation.

Prerequisites

  • You deployed an OKD cluster.

  • You installed the oc CLI.

Procedure

  1. Export the kubeadmin credentials:

    1. $ export KUBECONFIG=<installation_directory>/auth/kubeconfig (1)
    1For <installation_directory>, specify the path to the directory that you stored the installation files in.
  2. Verify you can run oc commands successfully using the exported configuration:

    1. $ oc whoami

    Example output

    1. system:admin

Approving the certificate signing requests for your machines

When you add machines to a cluster, two pending certificate signing requests (CSRs) are generated for each machine that you added. You must confirm that these CSRs are approved or, if necessary, approve them yourself. The client requests must be approved first, followed by the server requests.

Prerequisites

  • You added machines to your cluster.

Procedure

  1. Confirm that the cluster recognizes the machines:

    1. $ oc get nodes

    Example output

    1. NAME STATUS ROLES AGE VERSION
    2. master-0 Ready master 63m v1.19.0
    3. master-1 Ready master 63m v1.19.0
    4. master-2 Ready master 64m v1.19.0
    5. worker-0 NotReady worker 76s v1.19.0
    6. worker-1 NotReady worker 70s v1.19.0

    The output lists all of the machines that you created.

    The preceding output might not include the compute nodes, also known as worker nodes, until some CSRs are approved.

  2. Review the pending CSRs and ensure that you see the client requests with the Pending or Approved status for each machine that you added to the cluster:

    1. $ oc get csr

    Example output

    1. NAME AGE REQUESTOR CONDITION
    2. csr-8b2br 15m system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending
    3. csr-8vnps 15m system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending
    4. ...

    In this example, two machines are joining the cluster. You might see more approved CSRs in the list.

  3. If the CSRs were not approved, after all of the pending CSRs for the machines you added are in Pending status, approve the CSRs for your cluster machines:

    Because the CSRs rotate automatically, approve your CSRs within an hour of adding the machines to the cluster. If you do not approve them within an hour, the certificates will rotate, and more than two certificates will be present for each node. You must approve all of these certificates. Once the client CSR is approved, the Kubelet creates a secondary CSR for the serving certificate, which requires manual approval. Then, subsequent serving certificate renewal requests are automatically approved by the machine-approver if the Kubelet requests a new certificate with identical parameters.

    For clusters running on platforms that are not machine API enabled, such as bare metal and other user-provisioned infrastructure, you must implement a method of automatically approving the kubelet serving certificate requests (CSRs). If a request is not approved, then the oc exec, oc rsh, and oc logs commands cannot succeed, because a serving certificate is required when the API server connects to the kubelet. Any operation that contacts the Kubelet endpoint requires this certificate approval to be in place. The method must watch for new CSRs, confirm that the CSR was submitted by the node-bootstrapper service account in the system:node or system:admin groups, and confirm the identity of the node.

    • To approve them individually, run the following command for each valid CSR:

      1. $ oc adm certificate approve <csr_name> (1)
      1<csr_name> is the name of a CSR from the list of current CSRs.
    • To approve all pending CSRs, run the following command:

      1. $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs --no-run-if-empty oc adm certificate approve

      Some Operators might not become available until some CSRs are approved.

  4. Now that your client requests are approved, you must review the server requests for each machine that you added to the cluster:

    1. $ oc get csr

    Example output

    1. NAME AGE REQUESTOR CONDITION
    2. csr-bfd72 5m26s system:node:ip-10-0-50-126.us-east-2.compute.internal Pending
    3. csr-c57lv 5m26s system:node:ip-10-0-95-157.us-east-2.compute.internal Pending
    4. ...
  5. If the remaining CSRs are not approved, and are in the Pending status, approve the CSRs for your cluster machines:

    • To approve them individually, run the following command for each valid CSR:

      1. $ oc adm certificate approve <csr_name> (1)
      1<csr_name> is the name of a CSR from the list of current CSRs.
    • To approve all pending CSRs, run the following command:

      1. $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs oc adm certificate approve
  6. After all client and server CSRs have been approved, the machines have the Ready status. Verify this by running the following command:

    1. $ oc get nodes

    Example output

    1. NAME STATUS ROLES AGE VERSION
    2. master-0 Ready master 73m v1.20.0
    3. master-1 Ready master 73m v1.20.0
    4. master-2 Ready master 74m v1.20.0
    5. worker-0 Ready worker 11m v1.20.0
    6. worker-1 Ready worker 11m v1.20.0

    It can take a few minutes after approval of the server CSRs for the machines to transition to the Ready status.

Additional information

Initial Operator configuration

After the control plane initializes, you must immediately configure some Operators so that they all become available.

Prerequisites

  • Your control plane has initialized.

Procedure

  1. Watch the cluster components come online:

    1. $ watch -n5 oc get clusteroperators

    Example output

    1. NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE
    2. authentication 4.6.0 True False False 3h56m
    3. cloud-credential 4.6.0 True False False 29h
    4. cluster-autoscaler 4.6.0 True False False 29h
    5. config-operator 4.6.0 True False False 6h39m
    6. console 4.6.0 True False False 3h59m
    7. csi-snapshot-controller 4.6.0 True False False 4h12m
    8. dns 4.6.0 True False False 4h15m
    9. etcd 4.6.0 True False False 29h
    10. image-registry 4.6.0 True False False 3h59m
    11. ingress 4.6.0 True False False 4h30m
    12. insights 4.6.0 True False False 29h
    13. kube-apiserver 4.6.0 True False False 29h
    14. kube-controller-manager 4.6.0 True False False 29h
    15. kube-scheduler 4.6.0 True False False 29h
    16. kube-storage-version-migrator 4.6.0 True False False 4h2m
    17. machine-api 4.6.0 True False False 29h
    18. machine-approver 4.6.0 True False False 6h34m
    19. machine-config 4.6.0 True False False 3h56m
    20. marketplace 4.6.0 True False False 4h2m
    21. monitoring 4.6.0 True False False 6h31m
    22. network 4.6.0 True False False 29h
    23. node-tuning 4.6.0 True False False 4h30m
    24. openshift-apiserver 4.6.0 True False False 3h56m
    25. openshift-controller-manager 4.6.0 True False False 4h36m
    26. openshift-samples 4.6.0 True False False 4h30m
    27. operator-lifecycle-manager 4.6.0 True False False 29h
    28. operator-lifecycle-manager-catalog 4.6.0 True False False 29h
    29. operator-lifecycle-manager-packageserver 4.6.0 True False False 3h59m
    30. service-ca 4.6.0 True False False 29h
    31. storage 4.6.0 True False False 4h30m
  2. Configure the Operators that are not available.

Image registry storage configuration

Amazon Web Services provides default storage, which means the Image Registry Operator is available after installation. However, if the Registry Operator cannot create an S3 bucket and automatically configure storage, you must manually configure registry storage.

Instructions are shown for configuring a persistent volume, which is required for production clusters. Where applicable, instructions are shown for configuring an empty directory as the storage location, which is available for only non-production clusters.

Additional instructions are provided for allowing the image registry to use block storage types by using the Recreate rollout strategy during upgrades.

You can configure registry storage for user-provisioned infrastructure in AWS to deploy OKD to hidden regions. See Configuring the registry for AWS user-provisioned infrastructure for more information.

Configuring registry storage for AWS with user-provisioned infrastructure

During installation, your cloud credentials are sufficient to create an Amazon S3 bucket and the Registry Operator will automatically configure storage.

If the Registry Operator cannot create an S3 bucket and automatically configure storage, you can create an S3 bucket and configure storage with the following procedure.

Prerequisites

  • You have a cluster on AWS with user-provisioned infrastructure.

  • For Amazon S3 storage, the secret is expected to contain two keys:

    • REGISTRY_STORAGE_S3_ACCESSKEY

    • REGISTRY_STORAGE_S3_SECRETKEY

Procedure

Use the following procedure if the Registry Operator cannot create an S3 bucket and automatically configure storage.

  1. Set up a Bucket Lifecycle Policy to abort incomplete multipart uploads that are one day old.

  2. Fill in the storage configuration in configs.imageregistry.operator.openshift.io/cluster:

    1. $ oc edit configs.imageregistry.operator.openshift.io/cluster

    Example configuration

    1. storage:
    2. s3:
    3. bucket: <bucket-name>
    4. region: <region-name>

To secure your registry images in AWS, block public access to the S3 bucket.

Configuring storage for the image registry in non-production clusters

You must configure storage for the Image Registry Operator. For non-production clusters, you can set the image registry to an empty directory. If you do so, all images are lost if you restart the registry.

Procedure

  • To set the image registry storage to an empty directory:

    1. $ oc patch configs.imageregistry.operator.openshift.io cluster --type merge --patch '{"spec":{"storage":{"emptyDir":{}}}}'

    Configure this option for only non-production clusters.

    If you run this command before the Image Registry Operator initializes its components, the oc patch command fails with the following error:

    1. Error from server (NotFound): configs.imageregistry.operator.openshift.io "cluster" not found

    Wait a few minutes and run the command again.

Deleting the bootstrap resources

After you complete the initial Operator configuration for the cluster, remove the bootstrap resources from Amazon Web Services (AWS).

Prerequisites

  • You completed the initial Operator configuration for your cluster.

Procedure

  1. Delete the bootstrap resources. If you used the CloudFormation template, delete its stack:

    • Delete the stack by using the AWS CLI:

      1. $ aws cloudformation delete-stack --stack-name <name> (1)
      1<name> is the name of your bootstrap stack.
    • Delete the stack by using the AWS CloudFormation console.

Creating the Ingress DNS Records

If you removed the DNS Zone configuration, manually create DNS records that point to the Ingress load balancer. You can create either a wildcard record or specific records. While the following procedure uses A records, you can use other record types that you require, such as CNAME or alias.

Prerequisites

Procedure

  1. Determine the routes to create.

    • To create a wildcard record, use *.apps.<cluster_name>.<domain_name>, where <cluster_name> is your cluster name, and <domain_name> is the Route 53 base domain for your OKD cluster.

    • To create specific records, you must create a record for each route that your cluster uses, as shown in the output of the following command:

      1. $ oc get --all-namespaces -o jsonpath='{range .items[*]}{range .status.ingress[*]}{.host}{"\n"}{end}{end}' routes

      Example output

      1. oauth-openshift.apps.<cluster_name>.<domain_name>
      2. console-openshift-console.apps.<cluster_name>.<domain_name>
      3. downloads-openshift-console.apps.<cluster_name>.<domain_name>
      4. alertmanager-main-openshift-monitoring.apps.<cluster_name>.<domain_name>
      5. grafana-openshift-monitoring.apps.<cluster_name>.<domain_name>
      6. prometheus-k8s-openshift-monitoring.apps.<cluster_name>.<domain_name>
  2. Retrieve the Ingress Operator load balancer status and note the value of the external IP address that it uses, which is shown in the EXTERNAL-IP column:

    1. $ oc -n openshift-ingress get service router-default

    Example output

    1. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    2. router-default LoadBalancer 172.30.62.215 ab3...28.us-east-2.elb.amazonaws.com 80:31499/TCP,443:30693/TCP 5m
  3. Locate the hosted zone ID for the load balancer:

    1. $ aws elb describe-load-balancers | jq -r '.LoadBalancerDescriptions[] | select(.DNSName == "<external_ip>").CanonicalHostedZoneNameID' (1)
    1For <external_ip>, specify the value of the external IP address of the Ingress Operator load balancer that you obtained.

    Example output

    1. Z3AADJGX6KTTL2

    The output of this command is the load balancer hosted zone ID.

  4. Obtain the public hosted zone ID for your cluster’s domain:

    1. $ aws route53 list-hosted-zones-by-name \
    2. --dns-name "<domain_name>" \ (1)
    3. --query 'HostedZones[? Config.PrivateZone != `true` && Name == `<domain_name>.`].Id' (1)
    4. --output text
    1For <domain_name>, specify the Route 53 base domain for your OKD cluster.

    Example output

    1. /hostedzone/Z3URY6TWQ91KVV

    The public hosted zone ID for your domain is shown in the command output. In this example, it is Z3URY6TWQ91KVV.

  5. Add the alias records to your private zone:

    1. $ aws route53 change-resource-record-sets --hosted-zone-id "<private_hosted_zone_id>" --change-batch '{ (1)
    2. > "Changes": [
    3. > {
    4. > "Action": "CREATE",
    5. > "ResourceRecordSet": {
    6. > "Name": "\\052.apps.<cluster_domain>", (2)
    7. > "Type": "A",
    8. > "AliasTarget":{
    9. > "HostedZoneId": "<hosted_zone_id>", (3)
    10. > "DNSName": "<external_ip>.", (4)
    11. > "EvaluateTargetHealth": false
    12. > }
    13. > }
    14. > }
    15. > ]
    16. > }'
    1For <private_hosted_zone_id>, specify the value from the output of the CloudFormation template for DNS and load balancing.
    2For <cluster_domain>, specify the domain or subdomain that you use with your OKD cluster.
    3For <hosted_zone_id>, specify the public hosted zone ID for the load balancer that you obtained.
    4For <external_ip>, specify the value of the external IP address of the Ingress Operator load balancer. Ensure that you include the trailing period (.) in this parameter value.
  6. Add the records to your public zone:

    1. $ aws route53 change-resource-record-sets --hosted-zone-id "<public_hosted_zone_id>"" --change-batch '{ (1)
    2. > "Changes": [
    3. > {
    4. > "Action": "CREATE",
    5. > "ResourceRecordSet": {
    6. > "Name": "\\052.apps.<cluster_domain>", (2)
    7. > "Type": "A",
    8. > "AliasTarget":{
    9. > "HostedZoneId": "<hosted_zone_id>", (3)
    10. > "DNSName": "<external_ip>.", (4)
    11. > "EvaluateTargetHealth": false
    12. > }
    13. > }
    14. > }
    15. > ]
    16. > }'
    1For <public_hosted_zone_id>, specify the public hosted zone for your domain.
    2For <cluster_domain>, specify the domain or subdomain that you use with your OKD cluster.
    3For <hosted_zone_id>, specify the public hosted zone ID for the load balancer that you obtained.
    4For <external_ip>, specify the value of the external IP address of the Ingress Operator load balancer. Ensure that you include the trailing period (.) in this parameter value.

Completing an AWS installation on user-provisioned infrastructure

After you start the OKD installation on Amazon Web Service (AWS) user-provisioned infrastructure, monitor the deployment to completion.

Prerequisites

  • You removed the bootstrap node for an OKD cluster on user-provisioned AWS infrastructure.

  • You installed the oc CLI.

Procedure

  • From the directory that contains the installation program, complete the cluster installation:

    1. $ ./openshift-install --dir=<installation_directory> wait-for install-complete (1)
    1For <installation_directory>, specify the path to the directory that you stored the installation files in.

    Example output

    1. INFO Waiting up to 40m0s for the cluster at https://api.mycluster.example.com:6443 to initialize...
    2. INFO Waiting up to 10m0s for the openshift-console route to be created...
    3. INFO Install complete!
    4. INFO To access the cluster as the system:admin user when using 'oc', run 'export KUBECONFIG=/home/myuser/install_dir/auth/kubeconfig'
    5. INFO Access the OpenShift web-console here: https://console-openshift-console.apps.mycluster.example.com
    6. INFO Login to the console with user: "kubeadmin", and password: "4vYBz-Fe5en-ymBEc-Wt6NL"
    7. INFO Time elapsed: 1s

    The Ignition config files that the installation program generates contain certificates that expire after 24 hours, which are then renewed at that time. If the cluster is shut down before renewing the certificates and the cluster is later restarted after the 24 hours have elapsed, the cluster automatically recovers the expired certificates. The exception is that you must manually approve the pending node-bootstrapper certificate signing requests (CSRs) to recover kubelet certificates. See the documentation for Recovering from expired control plane certificates for more information.

Logging in to the cluster by using the web console

The kubeadmin user exists by default after an OKD installation. You can log into your cluster as the kubeadmin user by using the OKD web console.

Prerequisites

  • You have access to the installation host.

  • You completed a cluster installation and all cluster Operators are available.

Procedure

  1. Obtain the password for the kubeadmin user from the kubeadmin-password file on the installation host:

    1. $ cat <installation_directory>/auth/kubeadmin-password

    Alternatively, you can obtain the kubeadmin password from the <installation_directory>/.openshift_install.log log file on the installation host.

  2. List the OKD web console route:

    1. $ oc get routes -n openshift-console | grep 'console-openshift'

    Alternatively, you can obtain the OKD route from the <installation_directory>/.openshift_install.log log file on the installation host.

    Example output

    1. console console-openshift-console.apps.<cluster_name>.<base_domain> console https reencrypt/Redirect None
  3. Navigate to the route detailed in the output of the preceding command in a web browser and log in as the kubeadmin user.

Additional resources

Additional resources

Additional resources

  • See Working with stacks in the AWS documentation for more information about AWS CloudFormation stacks.

Next steps