13.11. AWS에서 네트워킹 및 로드 밸런싱 구성 요소 생성
AWS(Amazon Web Services)에서 OpenShift Container Platform 클러스터가 사용할 수 있는 네트워킹 및 클래식 또는 네트워크 로드 밸런싱을 구성해야 합니다.
제공된 CloudFormation 템플릿과 사용자 정의 매개변수 파일을 사용하여 AWS 리소스 스택을 생성할 수 있습니다. 스택은 OpenShift Container Platform 클러스터에 필요한 네트워킹 및 로드 밸런싱 구성 요소를 나타냅니다. 템플릿은 호스팅 영역 및 서브넷 태그도 생성합니다.
단일 VPC(Virtual Private Cloud)에서 템플릿을 여러 번 실행할 수 있습니다.
AWS 인프라를 생성하는 데 제공된 CloudFormation 템플릿을 사용하지 않는 경우, 제공된 정보를 검토하고 수동으로 인프라를 생성해야 합니다. 클러스터가 올바르게 초기화되지 않은 경우, Red Hat 지원팀에 설치 로그를 제시하여 문의해야 할 수도 있습니다.
사전 요구 사항
- AWS 계정을 구성했습니다.
-
aws 구성을 실행하여 AWS 키와 리전을 로컬 AWS 프로필에 추가하셨습니다. - 클러스터에 대한 Ignition 구성 파일을 생성하셨습니다.
- AWS에서 VPC 및 관련 서브넷을 생성하고 구성하셨습니다.
프로세스
클러스터의
install-config.yaml파일에서 지정한 Route 53 기본 도메인의 호스팅 영역 ID를 가져옵니다. 다음 명령을 실행하여 호스팅 영역에 대한 세부 정보를 얻을 수 있습니다.$ aws route53 list-hosted-zones-by-name --dns-name <route53_domain>1 - 1
<route53_domain>은 클러스터의install-config.yaml파일을 생성할 때 사용한 Route 53 기본 도메인을 지정합니다.
출력 예
mycluster.example.com. False 100 HOSTEDZONES 65F8F38E-2268-B835-E15C-AB55336FCBFA /hostedzone/Z21IXYZABCZ2A4 mycluster.example.com. 10예제 출력에서 호스팅 영역 ID는
Z21IXYZABCZ2A4입니다.템플릿에 필요한 매개변수 값이 포함된 JSON 파일을 생성합니다.
[ { "ParameterKey": "ClusterName",1 "ParameterValue": "mycluster"2 }, { "ParameterKey": "InfrastructureName",3 "ParameterValue": "mycluster-<random_string>"4 }, { "ParameterKey": "HostedZoneId",5 "ParameterValue": "<random_string>"6 }, { "ParameterKey": "HostedZoneName",7 "ParameterValue": "example.com"8 }, { "ParameterKey": "PublicSubnets",9 "ParameterValue": "subnet-<random_string>"10 }, { "ParameterKey": "PrivateSubnets",11 "ParameterValue": "subnet-<random_string>"12 }, { "ParameterKey": "VpcId",13 "ParameterValue": "vpc-<random_string>"14 } ]- 1
- 호스트 이름에 사용할 짧은 대표 클러스터 이름입니다.
- 2
- 클러스터의
install-config.yaml파일을 생성할 때 사용한 클러스터 이름을 지정합니다. - 3
- 클러스터에 대해 Ignition 구성 파일에 인코딩되는 클러스터 인프라의 이름입니다.
- 4
- Ignition 구성 파일 메타데이터에서 추출한 인프라 이름을
<cluster-name>-<random-string>형식으로 지정합니다. - 5
- 대상을 등록할 Route 53 공용 영역 ID입니다.
- 6
- Route 53 공용 영역 ID를
Z21IXYZABCZ2A4와 유사한 형식으로 지정합니다. 이 값은 AWS 콘솔에서 가져올 수 있습니다. - 7
- 대상을 등록할 Route 53 영역입니다.
- 8
- 클러스터의
install-config.yaml파일을 생성할 때 사용한 Route 53 기본 도메인을 지정합니다. AWS 콘솔에 표시되는 후행 마침표(.)는 포함하지 마십시오. - 9
- VPC용으로 만든 퍼블릭 서브넷입니다.
- 10
- VPC에 대한 CloudFormation 템플릿의 출력에서
PublicSubnetIds값을 지정합니다. - 11
- VPC용으로 만든 프라이빗 서브넷입니다.
- 12
- VPC에 대한 CloudFormation 템플릿의 출력에서
PrivateSubnetIds값을 지정합니다. - 13
- 클러스터용으로 만든 VPC입니다.
- 14
- VPC에 대한 CloudFormation 템플릿의 출력에서
VpcId값을 지정합니다.
이 항목의 네트워크 및 로드 밸런서에 대한 CloudFormation 템플릿 섹션에서 템플릿을 복사하여 사용자 컴퓨터에 YAML 파일로 저장합니다. 이 템플릿은 클러스터에 필요한 네트워킹 및 로드 밸런싱 개체를 설명합니다.
중요클러스터를 AWS 정부 또는 시크릿 리전에 배포하는 경우
CNAME레코드를 사용하여 CloudFormation 템플릿에서InternalApiServerRecord를 업데이트해야 합니다.ALIAS유형의 레코드는 AWS 정부 리전에서 지원되지 않습니다.CloudFormation 템플릿을 시작하여 네트워킹 및 로드 밸런싱 구성 요소를 제공하는 AWS 리소스 스택을 생성합니다.
중요명령은 한 줄로 입력해야 합니다.
$ aws cloudformation create-stack --stack-name <name>1 --template-body file://<template>.yaml2 --parameters file://<parameters>.json3 --capabilities CAPABILITY_NAMED_IAM4 출력 예
arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-dns/cd3e5de0-2fd4-11eb-5cf0-12be5c33a183템플릿 구성 요소가 있는지 확인합니다.
$ aws cloudformation describe-stacks --stack-name <name>StackStatus에CREATE_COMPLETE이 표시된 후 다음 매개변수의 출력 값이 표시됩니다. 클러스터를 생성하기 위해 실행하는 다른 CloudFormation 템플릿에 이러한 매개변수 값을 제공해야 합니다.PrivateHostedZoneId프라이빗 DNS의 호스팅 영역 ID입니다.
ExternalApiLoadBalancerName외부 API 로드 밸런서의 전체 이름입니다.
InternalApiLoadBalancerName내부 API 로드 밸런서의 전체 이름입니다.
ApiServerDnsNameAPI 서버의 전체 호스트 이름입니다.
RegisterNlbIpTargetsLambda이러한 로드 밸런서의 IP 대상 등록/등록 취소에 유용한 Lambda ARN입니다.
ExternalApiTargetGroupArn외부 API 대상 그룹의 ARN입니다.
InternalApiTargetGroupArn내부 API 대상 그룹의 ARN입니다.
InternalServiceTargetGroupArn내부 서비스 대상 그룹의 ARN입니다.
13.11.1. 네트워크 및 로드 밸런서에 대한 CloudFormation 템플릿 링크 복사링크가 클립보드에 복사되었습니다!
다음 CloudFormation 템플릿을 사용하여 OpenShift Container Platform 클러스터에 필요한 네트워킹 개체 및 로드 밸런서를 배포할 수 있습니다.
예 13.17. 네트워크 및 로드 밸런서에 대한 CloudFormation 템플릿
AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Network Elements (Route53 & LBs)
Parameters:
ClusterName:
AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
MaxLength: 27
MinLength: 1
ConstraintDescription: Cluster name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
Description: A short, representative cluster name to use for host names and other identifying names.
Type: String
InfrastructureName:
AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
MaxLength: 27
MinLength: 1
ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
Type: String
HostedZoneId:
Description: The Route53 public zone ID to register the targets with, such as Z21IXYZABCZ2A4.
Type: String
HostedZoneName:
Description: The Route53 zone to register the targets with, such as example.com. Omit the trailing period.
Type: String
Default: "example.com"
PublicSubnets:
Description: The internet-facing subnets.
Type: List<AWS::EC2::Subnet::Id>
PrivateSubnets:
Description: The internal subnets.
Type: List<AWS::EC2::Subnet::Id>
VpcId:
Description: The VPC-scoped resources will belong to this VPC.
Type: AWS::EC2::VPC::Id
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Cluster Information"
Parameters:
- ClusterName
- InfrastructureName
- Label:
default: "Network Configuration"
Parameters:
- VpcId
- PublicSubnets
- PrivateSubnets
- Label:
default: "DNS"
Parameters:
- HostedZoneName
- HostedZoneId
ParameterLabels:
ClusterName:
default: "Cluster Name"
InfrastructureName:
default: "Infrastructure Name"
VpcId:
default: "VPC ID"
PublicSubnets:
default: "Public Subnets"
PrivateSubnets:
default: "Private Subnets"
HostedZoneName:
default: "Public Hosted Zone Name"
HostedZoneId:
default: "Public Hosted Zone ID"
Resources:
ExtApiElb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Join ["-", [!Ref InfrastructureName, "ext"]]
IpAddressType: ipv4
Subnets: !Ref PublicSubnets
Type: network
IntApiElb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Join ["-", [!Ref InfrastructureName, "int"]]
Scheme: internal
IpAddressType: ipv4
Subnets: !Ref PrivateSubnets
Type: network
IntDns:
Type: "AWS::Route53::HostedZone"
Properties:
HostedZoneConfig:
Comment: "Managed by CloudFormation"
Name: !Join [".", [!Ref ClusterName, !Ref HostedZoneName]]
HostedZoneTags:
- Key: Name
Value: !Join ["-", [!Ref InfrastructureName, "int"]]
- Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
Value: "owned"
VPCs:
- VPCId: !Ref VpcId
VPCRegion: !Ref "AWS::Region"
ExternalApiServerRecord:
Type: AWS::Route53::RecordSetGroup
Properties:
Comment: Alias record for the API server
HostedZoneId: !Ref HostedZoneId
RecordSets:
- Name:
!Join [
".",
["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
]
Type: A
AliasTarget:
HostedZoneId: !GetAtt ExtApiElb.CanonicalHostedZoneID
DNSName: !GetAtt ExtApiElb.DNSName
InternalApiServerRecord:
Type: AWS::Route53::RecordSetGroup
Properties:
Comment: Alias record for the API server
HostedZoneId: !Ref IntDns
RecordSets:
- Name:
!Join [
".",
["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
]
Type: A
AliasTarget:
HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
DNSName: !GetAtt IntApiElb.DNSName
- Name:
!Join [
".",
["api-int", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
]
Type: A
AliasTarget:
HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
DNSName: !GetAtt IntApiElb.DNSName
ExternalApiListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn:
Ref: ExternalApiTargetGroup
LoadBalancerArn:
Ref: ExtApiElb
Port: 6443
Protocol: TCP
ExternalApiTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 10
HealthCheckPath: "/readyz"
HealthCheckPort: 6443
HealthCheckProtocol: HTTPS
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Port: 6443
Protocol: TCP
TargetType: ip
VpcId:
Ref: VpcId
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 60
InternalApiListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn:
Ref: InternalApiTargetGroup
LoadBalancerArn:
Ref: IntApiElb
Port: 6443
Protocol: TCP
InternalApiTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 10
HealthCheckPath: "/readyz"
HealthCheckPort: 6443
HealthCheckProtocol: HTTPS
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Port: 6443
Protocol: TCP
TargetType: ip
VpcId:
Ref: VpcId
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 60
InternalServiceInternalListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn:
Ref: InternalServiceTargetGroup
LoadBalancerArn:
Ref: IntApiElb
Port: 22623
Protocol: TCP
InternalServiceTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 10
HealthCheckPath: "/healthz"
HealthCheckPort: 22623
HealthCheckProtocol: HTTPS
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Port: 22623
Protocol: TCP
TargetType: ip
VpcId:
Ref: VpcId
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 60
RegisterTargetLambdaIamRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Join ["-", [!Ref InfrastructureName, "nlb", "lambda", "role"]]
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: !Join ["-", [!Ref InfrastructureName, "master", "policy"]]
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
[
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:DeregisterTargets",
]
Resource: !Ref InternalApiTargetGroup
- Effect: "Allow"
Action:
[
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:DeregisterTargets",
]
Resource: !Ref InternalServiceTargetGroup
- Effect: "Allow"
Action:
[
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:DeregisterTargets",
]
Resource: !Ref ExternalApiTargetGroup
RegisterNlbIpTargets:
Type: "AWS::Lambda::Function"
Properties:
Handler: "index.handler"
Role:
Fn::GetAtt:
- "RegisterTargetLambdaIamRole"
- "Arn"
Code:
ZipFile: |
import json
import boto3
import cfnresponse
def handler(event, context):
elb = boto3.client('elbv2')
if event['RequestType'] == 'Delete':
elb.deregister_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
elif event['RequestType'] == 'Create':
elb.register_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
responseData = {}
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['TargetArn']+event['ResourceProperties']['TargetIp'])
Runtime: "python3.8"
Timeout: 120
RegisterSubnetTagsLambdaIamRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Join ["-", [!Ref InfrastructureName, "subnet-tags-lambda-role"]]
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: !Join ["-", [!Ref InfrastructureName, "subnet-tagging-policy"]]
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
[
"ec2:DeleteTags",
"ec2:CreateTags"
]
Resource: "arn:aws:ec2:*:*:subnet/*"
- Effect: "Allow"
Action:
[
"ec2:DescribeSubnets",
"ec2:DescribeTags"
]
Resource: "*"
RegisterSubnetTags:
Type: "AWS::Lambda::Function"
Properties:
Handler: "index.handler"
Role:
Fn::GetAtt:
- "RegisterSubnetTagsLambdaIamRole"
- "Arn"
Code:
ZipFile: |
import json
import boto3
import cfnresponse
def handler(event, context):
ec2_client = boto3.client('ec2')
if event['RequestType'] == 'Delete':
for subnet_id in event['ResourceProperties']['Subnets']:
ec2_client.delete_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName']}]);
elif event['RequestType'] == 'Create':
for subnet_id in event['ResourceProperties']['Subnets']:
ec2_client.create_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName'], 'Value': 'shared'}]);
responseData = {}
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['InfrastructureName']+event['ResourceProperties']['Subnets'][0])
Runtime: "python3.8"
Timeout: 120
RegisterPublicSubnetTags:
Type: Custom::SubnetRegister
Properties:
ServiceToken: !GetAtt RegisterSubnetTags.Arn
InfrastructureName: !Ref InfrastructureName
Subnets: !Ref PublicSubnets
RegisterPrivateSubnetTags:
Type: Custom::SubnetRegister
Properties:
ServiceToken: !GetAtt RegisterSubnetTags.Arn
InfrastructureName: !Ref InfrastructureName
Subnets: !Ref PrivateSubnets
Outputs:
PrivateHostedZoneId:
Description: Hosted zone ID for the private DNS, which is required for private records.
Value: !Ref IntDns
ExternalApiLoadBalancerName:
Description: Full name of the external API load balancer.
Value: !GetAtt ExtApiElb.LoadBalancerFullName
InternalApiLoadBalancerName:
Description: Full name of the internal API load balancer.
Value: !GetAtt IntApiElb.LoadBalancerFullName
ApiServerDnsName:
Description: Full hostname of the API server, which is required for the Ignition config files.
Value: !Join [".", ["api-int", !Ref ClusterName, !Ref HostedZoneName]]
RegisterNlbIpTargetsLambda:
Description: Lambda ARN useful to help register or deregister IP targets for these load balancers.
Value: !GetAtt RegisterNlbIpTargets.Arn
ExternalApiTargetGroupArn:
Description: ARN of the external API target group.
Value: !Ref ExternalApiTargetGroup
InternalApiTargetGroupArn:
Description: ARN of the internal API target group.
Value: !Ref InternalApiTargetGroup
InternalServiceTargetGroupArn:
Description: ARN of the internal service target group.
Value: !Ref InternalServiceTargetGroup
클러스터를 AWS 정부 또는 시크릿 리전에 배포하는 경우 CNAME 레코드를 사용하도록 InternalApiServerRecord를 업데이트해야 합니다. ALIAS 유형의 레코드는 AWS 정부 리전에서 지원되지 않습니다. 예를 들면 다음과 같습니다.
Type: CNAME
TTL: 10
ResourceRecords:
- !GetAtt IntApiElb.DNSName