-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create a playbook to deploy a simple flask web app into high availability architecture #97
Changes from 19 commits
747d809
548c588
c017dd2
f4afa3d
aa69319
b54b0e8
d8c4e17
7bfdb59
1dd5ce7
7880cf1
c14ad49
e34e7b3
d31b416
68522ba
cc1c20b
cb6457f
fe49153
4082b9e
e8714c9
93fce44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--- | ||
minor_changes: | ||
- "Add a playbook to deploy a simple flask web app into high availability architecture (https://github.com/redhat-cop/cloud.aws_ops/pull/97)." |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,7 +85,7 @@ To delete the webapp: | |
### Common | ||
|
||
* **operation** (str): Operation for the webapp playbook to perform, either `create` or `delete`. Default: `create` | ||
* **resource_prefix** (str): (Required) A prefix to prepend to the name of all AWS resources created for the webapp | ||
* **resource_prefix** (str): A prefix to prepend to the name of all AWS resources created for the webapp. Default: `ansible-test` | ||
* **resource_tags** (dict, elements dict): Tags to apply to all AWS resources created for the webapp. Default: `prefix: "{{ resource_prefix }}"` | ||
* **aws_access_key** (str): (Required) AWS access key ID for user account with the above permissions | ||
* **aws_secret_key** (str): (Required) AWS secret access key for user account with the above permissions | ||
|
@@ -157,6 +157,25 @@ To delete the webapp: | |
``` | ||
* **deploy_flask_app_force_init** (bool): Whether to drop existing tables and create new ones when deploying the webapp database. Default: `false` | ||
|
||
### webapp deployment in HA architecture | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this deployment deploy_flask_app_workers_instance_type uses a t3.micro and cannot see where it is documented. It will be probably better to create a dedicated README for the high availability deployment especially if some default values from the webapp deployment are not retained. I personally find it clearer to to have separate READMEs, you can also reference the other rather than duplicating information. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have referenced the other variables used for this playbook here - https://github.com/redhat-cop/cloud.aws_ops/pull/97/files#diff-9ac3987075e323c6dbca1ada8d6a37a9768cbc9f22ae5168b3d84c49556422e1R164. I can add a link. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding the usage of t3.micro , based on this comment, I am retaining the default value - 't2.xlarge'. I will remove t3.micro from the playbooks and use it only for our testing. |
||
|
||
`webapp_ha_aurora.yaml` playbook deploys the flask app to a cross region high availability architecture. The playbook replicates the app deployment to a second region. The backend is an Aurora global cluster. For adding the write forwarding feature, aurora-mysql can be used. Default db engine is aurora-postgresql. The app in each region is configured to access the associated Aurora cluster. In front of the two regions, route53 records are added to provide cross region DNS (failover scenario). | ||
|
||
Along with the [above](https://github.com/redhat-cop/cloud.aws_ops/blob/main/playbooks/webapp/README.md#playbook-variables) variables, following variables are needed for this playbook: | ||
|
||
* **rds_instance_class** (str): DB instance class for the aurora db instances. Default: `db.r5.large` | ||
* **rds_global_cluster_name** (str): Name of the global cluster. Default: "{{ resource_prefix }}-global-cluster" | ||
* **rds_primary_cluster_name** (str): Name of the primary cluster. Default: "{{ resource_prefix }}-primary-cluster" | ||
* **rds_primary_cluster_region** (str): Primary Region. Default: `us-west-2` | ||
* **rds_primary_cluster_instance_name** (str): Name of primary db instance. Default: "{{ resource_prefix }}-primary-instance" | ||
* **rds_replica_cluster_name** (str): Name of the replica cluster. Default: "{{ resource_prefix }}-replica-cluster" | ||
* **rds_replica_cluster_region** (str): Replica Region. Default: `us-east-2` | ||
* **rds_replica_cluster_instance_name** (str): Name of the replica db instance. Default: "{{ resource_prefix }}-replica-instance" | ||
|
||
#### vars for route53 records | ||
* **route53_zone_name** (str): (required) Route53 Zone name. | ||
* **route53_subdomain** (str): Sub domain name for the application url. Default: "flaskapp" | ||
|
||
## Example Usage | ||
|
||
Create a `credentials.yaml` file with the folling contents: | ||
|
@@ -187,3 +206,16 @@ ansible-playbook migrate_webapp.yaml -e "@credentials.yaml" -e "dest_region=my-n | |
``` | ||
|
||
Note: migrating a webapp does not delete the app resources from the source region by default. To delete the source webapp, set var `delete_source: true`. | ||
|
||
To deploy the app in a high availability architecture, run: | ||
|
||
```bash | ||
ansible-playbook webapp_ha_aurora.yaml -e "@credentials.yaml" -e "operation=create" | ||
``` | ||
|
||
To delete the webapp resources created by the above playbook, run: | ||
|
||
```bash | ||
ansible-playbook webapp_ha_aurora.yaml -e "@credentials.yaml" -e "operation=delete" | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ | |
- name: Migrate webapp | ||
hosts: localhost | ||
gather_facts: false | ||
|
||
vars_files: | ||
- vars/main.yaml | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
--- | ||
- name: Add Route53 configurations | ||
module_defaults: | ||
group/aws: | ||
aws_access_key: "{{ aws_access_key | default(omit) }}" | ||
aws_secret_key: "{{ aws_secret_key | default(omit) }}" | ||
security_token: "{{ security_token | default(omit) }}" | ||
block: | ||
|
||
- name: Add route53 health check for the load balancer in primary region | ||
amazon.aws.route53_health_check: | ||
health_check_name: "healthchk-lb-primary" | ||
fqdn: "{{ primary_lb.elb.dns_name }}" | ||
port: 5000 | ||
type: HTTP | ||
use_unique_names: true | ||
state: present | ||
register: healthchk_primary_result | ||
|
||
- name: Add route53 health check for the load balancer in replica region | ||
amazon.aws.route53_health_check: | ||
health_check_name: "healthchk-lb-replica" | ||
fqdn: "{{ replica_lb.elb.dns_name }}" | ||
port: 5000 | ||
type: HTTP | ||
use_unique_names: true | ||
state: present | ||
register: healthchk_replica_result | ||
|
||
- name: Pause for 30 secs for the health check status to be in sync | ||
ansible.builtin.pause: | ||
seconds: 30 | ||
|
||
- name: Add an alias record that points to an aws ELB in the primary region | ||
amazon.aws.route53: | ||
state: present | ||
zone: "{{ route53_zone_name }}" | ||
record: "{{ route53_subdomain }}.{{ route53_zone_name }}" | ||
type: A | ||
value: "{{ primary_lb.elb.dns_name }}" | ||
alias: true | ||
identifier: "primary-record" | ||
failover: "PRIMARY" | ||
health_check: "{{ healthchk_primary_result.health_check.id }}" | ||
alias_hosted_zone_id: "{{ primary_lb.elb.hosted_zone_id }}" | ||
register: alias_record_primary_result | ||
|
||
- name: Add an alias record that points to an aws ELB in the replica region | ||
amazon.aws.route53: | ||
state: present | ||
zone: "{{ route53_zone_name }}" | ||
record: "{{ route53_subdomain }}.{{ route53_zone_name }}" | ||
type: A | ||
value: "{{ replica_lb.elb.dns_name }}" | ||
alias: true | ||
identifier: "replica-record" | ||
failover: "SECONDARY" | ||
health_check: "{{ healthchk_replica_result.health_check.id }}" | ||
alias_hosted_zone_id: "{{ replica_lb.elb.hosted_zone_id }}" | ||
register: alias_record_replica_result | ||
|
||
- name: Pause for 30 secs for the alias records to be active | ||
ansible.builtin.pause: | ||
seconds: 30 | ||
|
||
- name: Get Application URL | ||
ansible.builtin.debug: | ||
msg: "Application url: {{ route53_subdomain }}.{{ route53_zone_name }}:{{ deploy_flask_app_listening_port }}" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
--- | ||
- name: Create resources playbook | ||
module_defaults: | ||
group/aws: | ||
aws_access_key: "{{ aws_access_key | default(omit) }}" | ||
aws_secret_key: "{{ aws_secret_key | default(omit) }}" | ||
security_token: "{{ security_token | default(omit) }}" | ||
block: | ||
- name: Get security group id - primary region | ||
amazon.aws.ec2_security_group_info: | ||
filters: | ||
group-name: "{{ rds_secgroup_name }}" | ||
region: "{{ rds_primary_cluster_region }}" | ||
register: rds_primary_sg | ||
|
||
- name: Get security group id - replica region | ||
amazon.aws.ec2_security_group_info: | ||
filters: | ||
group-name: "{{ rds_secgroup_name }}" | ||
region: "{{ rds_replica_cluster_region }}" | ||
register: rds_replica_sg | ||
|
||
- name: Create Aurora db cluster | ||
ansible.builtin.include_role: | ||
name: cloud.aws_ops.create_rds_global_cluster | ||
vars: | ||
create_rds_global_cluster_operation: create | ||
create_rds_global_cluster_engine: "{{ rds_engine }}" | ||
create_rds_global_cluster_engine_version: "{{ rds_engine_version }}" | ||
create_rds_global_cluster_instance_class: "{{ rds_instance_class }}" | ||
create_rds_global_cluster_master_username: "{{ deploy_flask_app_rds_master_username }}" | ||
create_rds_global_cluster_master_user_password: "{{ deploy_flask_app_rds_master_password }}" | ||
create_rds_global_cluster_global_cluster_name: "{{ rds_global_cluster_name }}" | ||
create_rds_global_cluster_primary_cluster_name: "{{ rds_primary_cluster_name }}" | ||
create_rds_global_cluster_primary_cluster_region: "{{ rds_primary_cluster_region }}" | ||
create_rds_global_cluster_primary_cluster_instance_name: "{{ rds_primary_cluster_instance_name }}" | ||
create_rds_global_cluster_replica_cluster_name: "{{ rds_replica_cluster_name }}" | ||
create_rds_global_cluster_replica_cluster_region: "{{ rds_replica_cluster_region }}" | ||
create_rds_global_cluster_replica_cluster_instance_name: "{{ rds_replica_cluster_instance_name }}" | ||
create_rds_global_cluster_db_subnet_group_name: "{{ rds_subnet_group_name }}" | ||
create_rds_global_cluster_primary_cluster_db_name: "{{ rds_instance_name }}" | ||
create_rds_global_cluster_primary_cluster_vpc_security_group_ids: | ||
- "{{ rds_primary_sg.security_groups[0].group_id }}" | ||
create_rds_global_cluster_replica_cluster_vpc_security_group_ids: | ||
- "{{ rds_replica_sg.security_groups[0].group_id }}" | ||
|
||
- name: Get primary instance info | ||
amazon.aws.rds_instance_info: | ||
db_instance_identifier: "{{ rds_primary_cluster_instance_name }}" | ||
region: "{{ rds_primary_cluster_region }}" | ||
register: primary_instance_info_result | ||
|
||
- name: Get primary cluster info | ||
amazon.aws.rds_cluster_info: | ||
db_cluster_identifier: "{{ rds_primary_cluster_name }}" | ||
region: "{{ rds_primary_cluster_region }}" | ||
register: primary_cluster_info_result | ||
|
||
- name: Get replica cluster info | ||
amazon.aws.rds_cluster_info: | ||
db_cluster_identifier: "{{ rds_replica_cluster_name }}" | ||
region: "{{ rds_replica_cluster_region }}" | ||
register: replica_cluster_info_result | ||
|
||
- name: Get replica instance info | ||
amazon.aws.rds_instance_info: | ||
db_instance_identifier: "{{ rds_replica_cluster_instance_name }}" | ||
region: "{{ rds_replica_cluster_region }}" | ||
register: replica_instance_info_result | ||
|
||
- name: Get global db info | ||
Check failure on line 71 in playbooks/webapp/tasks/create_aurora_db_cluster.yaml GitHub Actions / ansible-lintsyntax-check[specific]
|
||
amazon.aws.rds_global_cluster_info: | ||
global_cluster_identifier: "{{ rds_global_cluster_name }}" | ||
region: "{{ rds_primary_cluster_region }}" | ||
register: global_cluster_info | ||
|
||
- name: Assert that primary and replica cluster are part of global db | ||
ansible.builtin.assert: | ||
that: | ||
- global_cluster_info.global_clusters[0].global_cluster_members[0].db_cluster_arn == primary_cluster_info_result.clusters[0].db_cluster_arn | ||
- global_cluster_info.global_clusters[0].global_cluster_members[1].db_cluster_arn == replica_cluster_info_result.clusters[0].db_cluster_arn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a breaking_change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This modification should have no impact on current users of this playbook. I don't consider it a breaking change. I believed that setting a default value, rather than making it a required parameter, was a more practical approach.