+++ title = "Deploying AWS Services with ACK - Relational Database Service RDS" chapter = false weight = 4 +++ :imagesdir: /images PREREQUISITES: This lab assumes you have completed the install of ACK on OpenShift, if you have not already completed this please complete the installing ACK lab: The following should already have been completed: * Created a project for ACK * Created a Service user account * Created a ConfigMap and Secret * Attached AWS IAM policies In this LAB we are going to a new AWS VPC separate form the one OpenShift is deployed in. No not from infrastructure as code deployed by an infrastructure team instead the OpenShift application owner will create the VPC using ACK from within OpenShift, connect it tothe OpenShift VPC using AWS VPC peering then deploy AWS RDS as a relational database into the new VPC. We will need to deploy two ACK operators for this LAB, the ACK operator for RDS and the ACK operator for EC2. We will use the EC2 Operator to provision a new VPC. Step 1:: Serach for the ACK operators from within the OpenShift operator hub While logged into the OpenShift web console: ---- Change to the administrator console. Click on Operators on the Left. Select Operator Hub. Type * AWS * into the search text box, press enter. ---- Step 2:: Install the ACK EC2 Operator ---- Find the ACK EC2 Operator in the OperatorHub and click on it Click Install Leave all settings default, Click on Install ---- Step 3:: Install the ACK RDS Operator ---- Find the ACK RDS Operator in the OperatorHub and click on it Click Install Leave all settings default, Click on Install ---- image::ackrds1.png[project] image::ackrds2.png[project] image::ackrds3.png[project] Step 4:: Confirm the operators are running ---- oc get pod -n ack-system ---- You should see something like the following: ---- NAME READY STATUS RESTARTS AGE ack-ec2-controller-5c647cc8c5-wwgck 1/1 Running 0 13m ack-rds-controller-5b5dd4745-7lj5f 1/1 Running 0 6m50s ---- Step 5:: create an OpenShift project: ---- oc new-project ack-workspace ---- Step 6:: Create a new VPC for the Database. We are going to create a separate AWS VPC for the RDS instance with CIDR block 100.68.0.0/18, this VPC will contain multiple Subnets each mapping to a different AWS availability zone so that we are able to deploy a multi-az RDS instance in order to cater for better resilience. ---- cat < ./rds-vpc.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: VPC metadata: name: rosa-rds-vpc namespace: ack-workspace labels: vpc: rosa-rds spec: cidrBlock: 100.68.0.0/18 EOF ❯ ❯ oc apply -f ./rds-vpc.yaml vpc.ec2.services.k8s.aws/rosa-rds-vpc created ❯ ❯ oc get vpc.ec2.services.k8s.aws/rosa-rds-vpc -oyaml | grep vpcID vpcID: vpc-09f8cdf865c44d5b0 ❯ ❯ export RDS_VPC_ID=vpc-09f8cdf865c44d5b0 ---- Step 7:: confirm the VPC has been created: ---- aws ec2 describe-vpcs --vpc-ids $RDS_VPC_ID ---- You should see something like : ---- { "Vpcs": [ { "CidrBlock": "100.68.0.0/18", "DhcpOptionsId": "dopt-0efa9af123cd44fa9", "State": "available", "VpcId": "vpc-09f8cdf865c44d5b0", "OwnerId": "637075021655", "InstanceTenancy": "default", "CidrBlockAssociationSet": [ { "AssociationId": "vpc-cidr-assoc-06303b36248cf51ec", "CidrBlock": "100.68.0.0/18", "CidrBlockState": { "State": "associated" } } ], "IsDefault": false } ] } ---- Step 8:: Create subnets: We will create subnets in two Availability Zones so that we can take advantage of resilience provided by multiAZ RDS. These subnets will be used when creating DB subnet group. A DB subnet group is a collection of subnets (typically private) that you create in a VPC and that you then designate for your DB instances. A DB subnet group allows you to specify a particular VPC when creating DB instances using the CLI or API. ---- cat < ./rds-subnet-a.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: Subnet metadata: name: rds-subnet-eu-west-2a namespace: ack-workspace spec: cidrBlock: 100.68.18.0/24 vpcID: $RDS_VPC_ID availabilityZone: eu-west-2a EOF ---- ---- oc apply -f ./rds-subnet-a.yaml subnet.ec2.services.k8s.aws/rds-subnet-eu-west-2a created ---- ---- cat < ./rds-subnet-b.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: Subnet metadata: name: rds-subnet-eu-west-2b namespace: ack-workspace spec: cidrBlock: 100.68.20.0/24 vpcID: $RDS_VPC_ID availabilityZone: eu-west-2b EOF ---- ---- oc apply -f ./rds-subnet-b.yaml subnet.ec2.services.k8s.aws/rds-subnet-eu-west-2b created ---- Step 9:: Export the Subnet IDs for later use: We will first decribe the subnet, then export the subnet id. Please update the explore command with the ID from the actual output as it will be different from what is seen below: ---- oc get subnet.ec2.services.k8s.aws/rds-subnet-eu-west-2a -oyaml |grep subnetID ---- you will see something like : ---- subnetID: subnet-0e93c060fb95a3f7e ---- ---- export RDS_SUBNET_A_ID=subnet-0e93c060fb95a3f7e ---- ---- oc get subnet.ec2.services.k8s.aws/rds-subnet-eu-west-2b -oyaml |grep subnetID ---- You will see something like : ---- subnetID: subnet-080e3a66c7ba6e984 ---- ---- export RDS_SUBNET_B_ID=subnet-080e3a66c7ba6e984 ---- Step 10:: Create DB Subnet Group: ---- cat < ./db-subnet-group.yaml apiVersion: rds.services.k8s.aws/v1alpha1 kind: DBSubnetGroup metadata: name: rdsdbsubnetgroup namespace: ack-workspace spec: subnetIDs: - $RDS_SUBNET_A_ID - $RDS_SUBNET_B_ID description: RDS DB subnet group name: rdsdbsubnetgroup EOF ---- ---- oc apply -f ./db-subnet-group.yaml ---- You should see something like : ---- dbsubnetgroup.rds.services.k8s.aws/rdsdbsubnetgroup created ---- Step 11:: Create a VPC Security Group: ---- cat < ./vpc-security-group.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: SecurityGroup metadata: name: rdssecuritygroup namespace: ack-workspace spec: description: RDS VPC security group name: rdssecuritygroup vpcID: $RDS_VPC_ID EOF ---- ---- oc apply -f vpc-security-group.yaml ---- Lets get the security group ID and export it so we can use it when creating the RDS instance. ---- oc get securitygroup.ec2.services.k8s.aws/rdssecuritygroup -oyaml |grep id ---- ou should see something like: ---- id: sg-0471d3fb75233f936 ---- ---- export RDS_VPC_SECURITY_GROUP_ID=sg-0471d3fb75233f936 ---- Step 12:: Create an RDS instance: First lets create a secret in OpenShift for Master database user. ---- oc create secret generic db-admin-pass \ --from-literal=password='mydbpassword' -n ack-workspace ---- Now lets create the RDS instance ---- cat < ./rds-db-instance.yaml apiVersion: rds.services.k8s.aws/v1alpha1 kind: DBInstance metadata: name: rdsmysqldb namespace: ack-workspace spec: vpcSecurityGroupIDs: - $RDS_VPC_SECURITY_GROUP_ID masterUserPassword: key: password name: db-admin-pass namespace: ack-workspace engine: mysql dbInstanceClass: db.t2.micro dbInstanceIdentifier: rdsmysqldbinstance port: 3306 availabilityZone: eu-west-2a dbName: rdsmysqldb dbSubnetGroupName: rdsdbsubnetgroup allocatedStorage: 5 engineVersion: 5.7.36 masterUsername: mydbadmin maxAllocatedStorage: 10 EOF ---- ---- oc apply -f ./rds-db-instance.yaml ---- Lets confirm status. ---- aws rds describe-db-instances --db-instance-identifier rdsmysqldbinstance ---- You should see something like : ---- { "DBInstances": [ { "DBInstanceIdentifier": "rdsmysqldbinstance", "DBInstanceClass": "db.t2.micro", "Engine": "mysql", "DBInstanceStatus": "available", "MasterUsername": "mydbadmin", "DBName": "rdsmysqldb", "Endpoint": { "Address": "rdsmysqldbinstance.abceexample.eu-west-2.rds.amazonaws.com", "Port": 3306, "HostedZoneId": "Z1TTGA775OQIYO" }, ...some output truncated... } ] } ---- Step 13:: Peering the VPCs A VPC peering connection (https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html) is a networking connection between two VPCs that enables you to route traffic between them using private IPv4 addresses or IPv6 addresses. Instances in either VPC can communicate with each other as if they are within the same network. You can create a VPC peering connection between your own VPCs, or with a VPC in another AWS account. The VPCs can be in different regions (also known as an inter-region VPC peering connection). Create and accept a VPC Peering Connection between ROSA VPC and RDS VPC Get the VpcId of the OpenShift VPC, if you made use of a ROSA cluster you can use the AWS Tags created during cluster launch which contain the OpenShift cluster name ---- ROSA_VPC_ID=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values="$ROSA_CLUSTER_NAME-*" --query "Vpcs[].VpcId" --output text) ---- Create the peering connection between ROSA VPC and RDS VPC ---- aws ec2 create-vpc-peering-connection --vpc-id $ROSA_VPC_ID --peer-vpc-id $RDS_VPC_ID ❯ VPC_PEER_ID=$(aws ec2 describe-vpc-peering-connections --query "VpcPeeringConnections[].VpcPeeringConnectionId" --output text) ---- We will need to accept the VPC peering connection ---- aws ec2 accept-vpc-peering-connection --vpc-peering-connection-id $VPC_PEER_ID ---- Update ROSA VPC Route table Get the route associated with the three public subnets of the ROSA VPC and add a route to the table so that all traffic to the RDS VPC CIDR block is via the VPC Peering Connection: ---- ROSA_ROUTE_TABLE_ID=$(aws ec2 describe-route-tables --filters Name=tag:Name,Values="$ROSA_CLUSTER_NAME-*-public" --query 'RouteTables[].RouteTableId' --output text) ---- ---- aws ec2 create-route --route-table-id ${ROSA_ROUTE_TABLE_ID} --destination-cidr-block 100.68.0.0/18 --vpc-peering-connection-id ${VPC_PEER_ID} ---- Step 14:: Update RDS Instance Security Group: Update the Security Group to allow all ingress traffic from the ROSA cluster to the RDS instance on port 3306:. ---- aws ec2 authorize-security-group-ingress --group-id ${RDS_VPC_SECURITY_GROUP_ID} --protocol tcp --port 3306 --cidr 10.0.0.0/16 ---- Step 15:: connecting OpenShift Applications to RDS ina different VPC: Validate the connection to RDS Now, you are ready to validate the connection to the RDS MySQL database from a pod running on the ROSA cluster. Create a Kubernetes Service named mysql-service of type ExternalName aliasing the RDS endpoint: ---- DB_INST_ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier rdsmysqldbinstance --query "DBInstances[].Endpoint[].Address" --output text) ---- ---- cat < ./mysql-service.yaml apiVersion: v1 kind: Service metadata: labels: app: mysql-service name: mysql-service namespace: ack-workspace spec: externalName: $DB_INST_ENDPOINT selector: app: mysql-service type: ExternalName status: loadBalancer: {} EOF ---- ---- oc apply -f ./mysql-service.yaml ---- Connect to the RDS MySQL database from a pod using mysql-57-rhel7 image ---- oc run -i --tty --rm debug --image=registry.access.redhat.com/rhscl/mysql-57-rhel7 --restart=Never -- sh ---- If you don't see a command prompt, try pressing enter. ---- which mysql ---- you should see something like: ---- /opt/rh/rh-mysql57/root/usr/bin/mysql ---- Lets log into the mysql database using the password from step 12. ---- mysql -h rdsmysqldbinstance.abceexample.eu-west-2.rds.amazonaws.com -u mydbadmin -p ---- image::ackrds5.png[project] ---- show databases ---- image::ackrds4.png[project] ---- quit exit ---- In this lab we deployed the ACK operators for RDS and EC2, used these to provision a VPC, a VPC peering link and an RDS instance. We then connected from an application workload running in OpenShift to the RDS instance.