github.com/openshift/installer@v1.4.17/docs/user/aws/install_upi.md (about) 1 # Install: User Provided Infrastructure (UPI) 2 3 The steps for performing a UPI-based install are outlined here. Several [CloudFormation][cloudformation] templates are 4 provided to assist in completing these steps or to help model your own. You are also free to create the required 5 resources through other methods; the CloudFormation templates are just an example. 6 7 ## Create Configuration 8 9 Create an install configuration as for [the usual approach](install.md#create-configuration): 10 11 ```console 12 $ openshift-install create install-config 13 ? SSH Public Key /home/user_id/.ssh/id_rsa.pub 14 ? Platform aws 15 ? Region us-east-2 16 ? Base Domain example.com 17 ? Cluster Name openshift 18 ? Pull Secret [? for help] 19 ``` 20 21 ### Optional: Create Encrypted AMIs 22 23 The IPI-based installer creates an encrypted AMI by default. If you wish to have an encrypted AMI for UPI-based 24 installs, you will need to create it directly. See [CoreOS bootimages](../overview.md#coreos-bootimages) for more information 25 about bootimages, including how to find the AMI identifiers. 26 27 You will make an encrypted copy of the AMI according to the [AWS documentation][encrypted-copy]. 28 29 With the new AMI, you can [customize](customization.md) the install-config created on the previous step to override 30 the default. Additionally, you would pass it to the templates or EC2 launch instance commands according to how 31 you intend to launch your hosts. 32 33 ### Empty Compute Pools 34 35 We'll be providing the control-plane and compute machines ourselves, so edit the resulting `install-config.yaml` to set `replicas` to 0 for the `compute` pool: 36 37 ```sh 38 python -c ' 39 import yaml; 40 path = "install-config.yaml"; 41 data = yaml.load(open(path)); 42 data["compute"][0]["replicas"] = 0; 43 open(path, "w").write(yaml.dump(data, default_flow_style=False))' 44 ``` 45 46 ## Edit Manifests 47 48 Use [a staged install](../overview.md#multiple-invocations) to make some adjustments which are not exposed via the install configuration. 49 50 ```console 51 $ openshift-install create manifests 52 INFO Consuming "Install Config" from target directory 53 ``` 54 55 ### Remove Machines and MachineSets 56 57 Remove the control-plane Machines and compute MachineSets, because we'll be providing those ourselves and don't want to involve [the machine-API operator][machine-api-operator]: 58 59 ```console 60 $ rm -f openshift/99_openshift-cluster-api_master-machines-*.yaml openshift/99_openshift-cluster-api_worker-machineset-*.yaml 99_openshift-machine-api_master-control-plane-machine-set.yaml 61 ``` 62 63 You are free to leave the compute MachineSets in if you want to create compute machines via the machine API, but if you do you may need to update the various references (`subnet`, etc.) to match your environment. 64 65 ### Make control-plane nodes unschedulable 66 67 Currently [emptying the compute pools](#empty-compute-pools) makes control-plane nodes schedulable. 68 But due to a [Kubernetes limitation][kubernetes-service-load-balancers-exclude-masters], router pods running on control-plane nodes will not be reachable by the ingress load balancer. 69 Update the scheduler configuration to keep router pods and other workloads off the control-plane nodes: 70 71 ```sh 72 python -c ' 73 import yaml; 74 path = "manifests/cluster-scheduler-02-config.yml" 75 data = yaml.load(open(path)); 76 data["spec"]["mastersSchedulable"] = False; 77 open(path, "w").write(yaml.dump(data, default_flow_style=False))' 78 ``` 79 80 ### Adjust DNS Zones 81 82 [The ingress operator][ingress-operator] is able to manage DNS records on your behalf. 83 Depending on whether you want operator-managed DNS or user-managed DNS, you can choose to [identify the internal DNS zone](#identify-the-internal-dns-zone) or [remove DNS zones](#remove-dns-zones) from the DNS configuration. 84 85 #### Identify the internal DNS zone 86 87 If you want [the ingress operator][ingress-operator] to manage DNS records on your behalf, adjust the `privateZone` section in the DNS configuration to identify the zone it should use. 88 By default it will use a `kubernetes.io/cluster/{infrastructureName}: owned` tag, but that tag is only appropriate if `openshift-install destroy cluster` should remove the zone. 89 For user-provided zones, you can remove `tags` completely and use the zone ID instead: 90 91 ```sh 92 python -c ' 93 import yaml; 94 path = "manifests/cluster-dns-02-config.yml"; 95 data = yaml.load(open(path)); 96 del data["spec"]["privateZone"]["tags"]; 97 data["spec"]["privateZone"]["id"] = "Z21IZ5YJJMZ2A4"; 98 open(path, "w").write(yaml.dump(data, default_flow_style=False))' 99 ``` 100 101 #### Remove DNS zones 102 103 If you don't want [the ingress operator][ingress-operator] to manage DNS records on your behalf, remove the `privateZone` and `publicZone` sections from the DNS configuration: 104 105 ```sh 106 python -c ' 107 import yaml; 108 path = "manifests/cluster-dns-02-config.yml"; 109 data = yaml.load(open(path)); 110 del data["spec"]["publicZone"]; 111 del data["spec"]["privateZone"]; 112 open(path, "w").write(yaml.dump(data, default_flow_style=False))' 113 ``` 114 115 If you do so, you'll need to [add ingress DNS records manually](#add-the-ingress-dns-records) later on. 116 117 #### Disconnected clusters 118 119 For disconnected clusters, Openshift has to be configured [not to manage DNS](#remove-dns-zones), otherwise [the ingress operator][ingress-operator] will try to contact the STS endpoint "sts.amazon.com" directly as opposed to the configured VPC endpoint for the cluster. 120 121 ## Create Ignition Configs 122 123 Now we can create the bootstrap Ignition configs: 124 125 ```console 126 $ openshift-install create ignition-configs 127 ``` 128 129 After running the command, several files will be available in the directory. 130 131 ```console 132 $ tree 133 . 134 ├── auth 135 │ └── kubeconfig 136 ├── bootstrap.ign 137 ├── master.ign 138 ├── metadata.json 139 └── worker.ign 140 ``` 141 142 ### Extract Infrastructure Name from Ignition Metadata 143 144 Many of the operators and functions within OpenShift rely on tagging AWS resources. By default, Ignition 145 generates a unique cluster identifier comprised of the cluster name specified during the invocation of the installer 146 and a short string known internally as the infrastructure name. These values are seeded in the initial manifests within 147 the Ignition configuration. To use the output of the default, generated 148 `ignition-configs` extracting the internal infrastructure name is necessary. 149 150 An example of a way to get this is below: 151 152 ``` 153 $ jq -r .infraID metadata.json 154 openshift-vw9j6 155 ``` 156 157 ## Create/Identify the VPC to be Used 158 159 You may create a VPC with various desirable characteristics for your situation (VPN, route tables, etc.). The 160 VPC configuration and a CloudFormation template is provided [here](../../../upi/aws/cloudformation/01_vpc.yaml). 161 162 A created VPC via the template or manually should approximate a setup similar to this: 163 164 <div style="text-align:center"> 165 <img src="images/install_upi_vpc.svg" width="100%" /> 166 </div> 167 168 ## Create DNS entries and Load Balancers for Control Plane Components 169 170 The DNS and load balancer configuration within a CloudFormation template is provided 171 [here](../../../upi/aws/cloudformation/02_cluster_infra.yaml). It uses a public hosted zone and creates a private hosted 172 zone similar to the IPI installation method. 173 It also creates load balancers, listeners, as well as hosted zone and subnet tags the same way as the IPI 174 installation method. 175 This template can be run multiple times within a single VPC and in combination with the VPC 176 template provided above. 177 178 ### Optional: Manually Create Load Balancer Configuration 179 180 It is needed to create a TCP load balancer for ports 6443 (the Kubernetes API and its extensions) and 22623 (Ignition 181 configurations for new machines). The targets will be the master nodes. Port 6443 must be accessible to both clients 182 external to the cluster and nodes within the cluster. Port 22623 must be accessible to nodes within the cluster. 183 184 ### Optional: Manually Create Route53 Hosted Zones & Records 185 186 For the cluster name identified earlier in [Create Ignition Configs](#create-ignition-configs), you must create a DNS entry which resolves to your created load balancer. 187 The entry `api.$clustername.$domain` should point to the external load balancer and `api-int.$clustername.$domain` should point to the internal load balancer. 188 189 ## Create Security Groups and IAM Roles 190 191 The security group and IAM configuration within a CloudFormation template is provided 192 [here](../../../upi/aws/cloudformation/03_cluster_security.yaml). Run this template to get the minimal and permanent 193 set of security groups and IAM roles needed for an operational cluster. It can also be inspected for the current 194 set of required rules to facilitate manual creation. 195 196 ## Launch Temporary Bootstrap Resource 197 198 The bootstrap launch and other necessary, temporary security group plus IAM configuration and a CloudFormation 199 template is provided [here](../../../upi/aws/cloudformation/04_cluster_bootstrap.yaml). Upload your generated `bootstrap.ign` 200 file to an S3 bucket in your account and run this template to get a bootstrap node along with a predictable clean up of 201 the resources when complete. It can also be inspected for the set of required attributes via manual creation. 202 203 ## Launch Permanent Master Nodes 204 205 The master launch and other necessary DNS entries for etcd are provided within a CloudFormation 206 template [here](../../../upi/aws/cloudformation/05_cluster_master_nodes.yaml). Run this template to get three master 207 nodes. It can also be inspected for the set of required attributes needed for manual creation of the nodes, DNS entries 208 and load balancer configuration. 209 210 ## Monitor for `bootstrap-complete` and Initialization 211 212 ```console 213 $ bin/openshift-install wait-for bootstrap-complete 214 INFO Waiting up to 30m0s for the Kubernetes API at https://api.test.example.com:6443... 215 INFO API v1.12.4+c53f462 up 216 INFO Waiting up to 30m0s for the bootstrap-complete event... 217 ``` 218 219 ## Destroy Bootstrap Resources 220 221 At this point, you should delete the bootstrap resources. If using the CloudFormation template, you would [delete the 222 stack][delete-stack] created for the bootstrap to clean up all the temporary resources. 223 224 ## Launch Additional Compute Nodes 225 226 You may create compute nodes by launching individual EC2 instances discretely or by automated processes outside the cluster (e.g. Auto Scaling Groups). 227 You can also take advantage of the built in cluster scaling mechanisms and the machine API in OpenShift, as mentioned [above](#create-ignition-configs). 228 In this example, we'll manually launch instances via the CloudFormatio template [here](../../../upi/aws/cloudformation/06_cluster_worker_node.yaml). 229 You can launch a CloudFormation stack to manage each individual compute node (you should launch at least two for a high-availability ingress router). 230 A similar launch configuration could be used by outside automation or AWS auto scaling groups. 231 232 #### Approving the CSR requests for nodes 233 234 The CSR requests for client and server certificates for nodes joining the cluster will need to be approved by the administrator. 235 You can view them with: 236 237 ```console 238 $ oc get csr 239 NAME AGE REQUESTOR CONDITION 240 csr-8b2br 15m system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Approved,Issued 241 csr-8vnps 15m system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Approved,Issued 242 csr-b96j4 25s system:node:ip-10-0-52-215.us-east-2.compute.internal Approved,Issued 243 csr-bfd72 5m26s system:node:ip-10-0-50-126.us-east-2.compute.internal Pending 244 csr-c57lv 5m26s system:node:ip-10-0-95-157.us-east-2.compute.internal Pending 245 ... 246 ``` 247 248 Administrators should carefully examine each CSR request and approve only the ones that belong to the nodes created by them. 249 CSRs can be approved by name, for example: 250 251 ```sh 252 oc adm certificate approve csr-bfd72 253 ``` 254 255 ## Add the Ingress DNS Records 256 257 If you removed the DNS Zone configuration [earlier](#remove-dns-zones), you'll need to manually create some DNS records pointing at the ingress load balancer. 258 You can create either a wildcard `*.apps.{baseDomain}.` or specific records (more on the specific records below). 259 You can use A, CNAME, [alias][route53-alias], etc. records, as you see fit. 260 For example, you can create wildcard alias records by retrieving the ingress load balancer status: 261 262 ```console 263 $ oc -n openshift-ingress get service router-default 264 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 265 router-default LoadBalancer 172.30.62.215 ab37f072ec51d11e98a7a02ae97362dd-240922428.us-east-2.elb.amazonaws.com 80:31499/TCP,443:30693/TCP 5m 266 ``` 267 268 Then find the hosted zone ID for the load balancer (or use [this table][route53-zones-for-load-balancers]): 269 270 ```console 271 $ aws elb describe-load-balancers | jq -r '.LoadBalancerDescriptions[] | select(.DNSName == "ab37f072ec51d11e98a7a02ae97362dd-240922428.us-east-2.elb.amazonaws.com").CanonicalHostedZoneNameID' 272 Z3AADJGX6KTTL2 273 ``` 274 275 And finally, add the alias records to your private and public zones: 276 277 ```console 278 $ aws route53 change-resource-record-sets --hosted-zone-id "${YOUR_PRIVATE_ZONE}" --change-batch '{ 279 > "Changes": [ 280 > { 281 > "Action": "CREATE", 282 > "ResourceRecordSet": { 283 > "Name": "\\052.apps.your.cluster.domain.example.com", 284 > "Type": "A", 285 > "AliasTarget":{ 286 > "HostedZoneId": "Z3AADJGX6KTTL2", 287 > "DNSName": "ab37f072ec51d11e98a7a02ae97362dd-240922428.us-east-2.elb.amazonaws.com.", 288 > "EvaluateTargetHealth": false 289 > } 290 > } 291 > } 292 > ] 293 > }' 294 $ aws route53 change-resource-record-sets --hosted-zone-id "${YOUR_PUBLIC_ZONE}" --change-batch '{ 295 > "Changes": [ 296 > { 297 > "Action": "CREATE", 298 > "ResourceRecordSet": { 299 > "Name": "\\052.apps.your.cluster.domain.example.com", 300 > "Type": "A", 301 > "AliasTarget":{ 302 > "HostedZoneId": "Z3AADJGX6KTTL2", 303 > "DNSName": "ab37f072ec51d11e98a7a02ae97362dd-240922428.us-east-2.elb.amazonaws.com.", 304 > "EvaluateTargetHealth": false 305 > } 306 > } 307 > } 308 > ] 309 > }' 310 ``` 311 312 If you prefer to add explicit domains instead of using a wildcard, you can create entries for each of the cluster's current routes: 313 314 ```console 315 $ oc get --all-namespaces -o jsonpath='{range .items[*]}{range .status.ingress[*]}{.host}{"\n"}{end}{end}' routes 316 oauth-openshift.apps.your.cluster.domain.example.com 317 console-openshift-console.apps.your.cluster.domain.example.com 318 downloads-openshift-console.apps.your.cluster.domain.example.com 319 alertmanager-main-openshift-monitoring.apps.your.cluster.domain.example.com 320 grafana-openshift-monitoring.apps.your.cluster.domain.example.com 321 prometheus-k8s-openshift-monitoring.apps.your.cluster.domain.example.com 322 ``` 323 324 ## Monitor for Cluster Completion 325 326 ```console 327 $ bin/openshift-install wait-for install-complete 328 INFO Waiting up to 30m0s for the cluster to initialize... 329 ``` 330 331 Also, you can observe the running state of your cluster pods: 332 333 ```console 334 $ oc get pods --all-namespaces 335 NAMESPACE NAME READY STATUS RESTARTS AGE 336 kube-system etcd-member-ip-10-0-3-111.us-east-2.compute.internal 1/1 Running 0 35m 337 kube-system etcd-member-ip-10-0-3-239.us-east-2.compute.internal 1/1 Running 0 37m 338 kube-system etcd-member-ip-10-0-3-24.us-east-2.compute.internal 1/1 Running 0 35m 339 openshift-apiserver-operator openshift-apiserver-operator-6d6674f4f4-h7t2t 1/1 Running 1 37m 340 openshift-apiserver apiserver-fm48r 1/1 Running 0 30m 341 openshift-apiserver apiserver-fxkvv 1/1 Running 0 29m 342 openshift-apiserver apiserver-q85nm 1/1 Running 0 29m 343 ... 344 openshift-service-ca-operator openshift-service-ca-operator-66ff6dc6cd-9r257 1/1 Running 0 37m 345 openshift-service-ca apiservice-cabundle-injector-695b6bcbc-cl5hm 1/1 Running 0 35m 346 openshift-service-ca configmap-cabundle-injector-8498544d7-25qn6 1/1 Running 0 35m 347 openshift-service-ca service-serving-cert-signer-6445fc9c6-wqdqn 1/1 Running 0 35m 348 openshift-service-catalog-apiserver-operator openshift-service-catalog-apiserver-operator-549f44668b-b5q2w 1/1 Running 0 32m 349 openshift-service-catalog-controller-manager-operator openshift-service-catalog-controller-manager-operator-b78cr2lnm 1/1 Running 0 31m 350 ``` 351 352 [cloudformation]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html 353 [delete-stack]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html 354 [ingress-operator]: https://github.com/openshift/cluster-ingress-operator 355 [kubernetes-service-load-balancers-exclude-masters]: https://github.com/kubernetes/kubernetes/issues/65618 356 [machine-api-operator]: https://github.com/openshift/machine-api-operator 357 [route53-alias]: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-choosing-alias-non-alias.html 358 [route53-zones-for-load-balancers]: https://docs.aws.amazon.com/general/latest/gr/rande.html#elb_region 359 [encrypted-copy]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html#create-ami-encrypted-root-snapshot