After completing this section, you should be able to describe the architecture of common cloud application examples.
Cloud applications are generally deployed as stacks, which is more efficient than manual deployment. Common cloud applications use recognizable patterns, and many are already published as Heat templates. Cloud applications consist of multiple components which provide front-end and back-end platforms. The front-end platform provides the client, and the back-end platform provides compute power and storage.
There are several well-known design methods:
Web Applications (for example, a 3-tier application)
Big Data (for example, Hadoop)
eCommerce (for example, a 3-tier application used in secure retail)
Container optimized
Video processing and content delivery
Cloud architecture is made up of various components that are applicable, on-demand, and network accessed to a shared pool of resources. These components consist of networks, servers, applications, and services designed to use the agility of cloud resources to solve everyday business problems. Cloud architecture defines the components as well as the relationships between them.
A 3-tier application is a software architecture composed of three tiers, often used in client-server systems. It consists of a presentation tier, an application tier, and a data tier.
The presentation tier is the front end and provides an interface for the user. The user interface is often a GUI and accessible using a web browser or mobile application. It communicates with the other layers using API calls.
The application tier processes content and business logic.
The data tier stores information in a data storage system.
Load Balancing-as-a-Service (LBaaS) distributes incoming requests evenly between instances. Requests are distributed using one of three methods. Round robin rotates requests evenly between all instances. Source IP ensures requests from the same source IP address are always sent to the same instance. Least connections ensures requests are sent to the least busy instance.
Neutron LBaaS v1.0, is the reference architecture for the classroom. Neutron LBaaS v2.0 is available in the OpenStack Liberty release and supports Octavia and HAProxy back ends.
OpenStack images are used to create instances. Images can be preconfigured to include all required packages, configuration, and files to boot a fully operational instance. Each image creates a different type of instance, for example, an application server, a database sever, or a web server. A preconfigured image can speed up instance build time and ensures consistency, but will require patching and keeping licenses up to date. It is possible to create an instance without using an image allowing for greater flexibility, but can increase creation time and result in inconsistencies.
Instances can mount and dismount persistent block storage virtual devices, called Cinder volumes. Cinder volumes can only be attached to one instance at a time. If an instance stops working, a new instance is created and the Cinder volume is attached to the new instance.
Swift is persistent object storage. Objects are stored and retrieved using a RESTFUL API. Unlike a physical device, Swift storage is never mounted to the instance. It is built for scale and optimized for durability and availability across an entire data set.
Neutron is used to create multiple subnets, one for each tier: a presentation subnet, an application subnet, and a data subnet. Neutron routers route traffic between the subnets.
Security groups are used to filter inbound traffic. Multiple rules can be created to allow or deny traffic from specific ports, IP addresses, or ranges. All OpenStack stacks are configured with a default security group. The default security group is assigned to instances that have no other security group defined. Unless modified, the default security group denies all incoming traffic.
Heat uses template files to automate the deployment of complicated cloud applications and environments. Orchestration is more than just standing up instances; it can install software, configure networking, install patches, and set security protocols.
The ability to scale horizontally is one of the greatest advantages of cloud computing. OpenStack can automatically launch additional instances for a specific application as required. Telemetry performs the system resource monitoring and can be configured to send an alarm when thresholds are exceeded. Heat then responds to the alarm according to the configured scale-up or scale-down policy.
Web applications are generally publicly exposed, therefore perimeter security is not enough. The 3-tier web application architecture adds several layers of security by hosting the different tiers in different networks. Communication between the networks is protected through OpenStack security groups. Only traffic with the correct protocol, port, source IP, and destination IP is permitted.
The deployment of a 3-tier web application is complex, therefore it is highly recommended to use nested templates. Each tier is defined in a separate template making the templates easier to create and manage. A HOT template defines the tier templates and their resources.
At the top of the template we find the description and the version of the template, the required YAML files and parameters, and the optional parameters:
heat_template_version: 2016-10-14description: This HOT template defines the 3-tier web application stack for the application-tracker deployment. This template calls multiple nested templates which actually do the majority of the work. This file calls the required yaml files in a ./lib subdirectory REQUIRED YAML FILES: setup_net_sg.yaml, heat_app_tier.yaml, heat_sql_tier.yaml, heat_web_tier.yaml REQUIRED PARAMETERS: key_name, flavor, image, public_net_id OPTIONAL PARAMETERS: db_server_name, app_server_name, web_server_name, dns_nameserver
In this section the general parameters and restrictions of the stack are configured. The general parameters include, the access authentication mechanism, the flavor of the instances, the image to be used for the creation of the instances, the networks to be assigned and the security groups, for example:
parameters:key_name:type: stringdescription: Name of an existing key pair to use for the instancedefault: example-keypairconstraints:- custom_constraint: nova.keypairflavor:type: stringdescription: Flavor for the instance to be createddefault: defaultconstraints:- custom_constraint: nova.flavorimage:type: stringdescription: Image ID or image name to use for the instancedefault: rhel8constraints:- custom_constraint: glance.imagepublic_network_id:type: stringdescription: ID of public network for which floating IP addresses will be allocateddefault:ef95203b-7c9f-46c0-b328-e51aa7729798private_network_id:type: stringdescription: ID of private network into which instances get deployeddefault:8799e43b-2848-4772-8c4c-c6545e54db19db_server_name:type: stringdescription: Name of the database instancesdefault: db_serverapp_server_name:type: stringdescription: Name of the application instancesdefault: app_serverweb_server_name:type: stringdescription: Name of the web instancesdefault: app_serverdns_nameserver:type: comma_delimited_listdescription: The IP address of a DNS nameserver in list formatdefault:8.8.8.8,8.8.4.4
In the main HOT template the resources of the stack are defined, making reference to the template from where each one of them will be generated, grouping them for its individual deployment. Besides the network configuration for the different tiers and the launch of the storage or database resources.
resources:network_setup:type: lib/setup_net_sg.yamlproperties:public_network_id: { get_param: public_network_id }dns_nameserver: { get_param: dns_nameserver }launch_db_server:type: lib/heat_sql_tier.yamlproperties:key_name: { get_param: key_name }server_name: { get_param: db_server_name }instance_flavor: { get_param: flavor }image_id: { get_param: image_id }private_network_id: { get_param: private_network_id }security_group: { get_param: [network_setup, db_security_group_id] }app_server_resource_group:type: OS::Heat::ResourceGroupproperties:count: 2resource_def: 2type: lib/heat_app_tier.yamlproperties:key_name:get_param: key_nameserver_name:get_param: app_server_nameinstance_flavor:get_param: flavorimage_id:get_param: image_idprivate_network_id: {get_attr: [network_setup, private_network_id]}security_group: {get_attr: [network_setup, app_security_group_id]}pool_name: {get_attr: [network_setup, app_lbass_pool_name]}db_server_ip: {get_attr: [launch_db_server, instance_ip]}web_server_resource_group:type: OS::Heat::ResourceGroupproperties:count: 2resource_def: 2type: lib/heat_web_tier.yamlproperties:key_name:get_param: key_nameserver_name:get_param: web_server_nameinstance_flavor:get_param: flavorimage_id:get_param: image_idprivate_network_id: {get_attr: [network_setup, private_network_id]}app_lbaas_vip: {get_attr: [network_setup, app_lbaas_ip]}security_group: {get_attr: [network_setup, web_security_group_id]}pool_name: {get_attr: [network_setup, web_lbass_pool_name]}
The output of the main HOT template defines the output parameters of the web application stack after its creation.
outputs:web_lbaas_ip:descrption: Floating IP assigned to the web loadbalancervalue: { get_attr: [ network_setup, web_lbaas_ip ] }app_lbaas_ip:descrption: Floating IP assigned to the app loadbalancervalue: { get_attr: [ network_setup, app_lbaas_ip ] }
In addition, each of the templates that generate the resources also define different resources and outputs for each of them, using the same required and optional parameters.
This template defines the network configuration to be used in the 3-tier web application. Network segregation, load balancing and security groups are defined here. In this example, the template creates a private network and a security group containing rules for internal communication between the tiers. It also creates a pair of load balancers, one for public access to the web application and and internal one for use by the application tier and the data tier.
resources:private_network_subnet:type: OS::Neutron::Netproperties:cidr: 192.168.100.0/24gateway_ip: 192.168.100.1allocation_pools: [{ "start": 192.168.100.10, "end": 192.168.100.100 }]name: private_subnetdns_nameserver: { get_param: dns_nameserver }enable_dhcp: truepublic_router:type: OS::Neutron::Routerproperties:name: public_routerexternal_gateway_info:network: { get_param: public_network_id }public_router_interface:type: OS::Neutron::RouterInterfaceproperties:router: { get_resource: public_router }subnet: { get_resource: private_network_subnet }web_tier_loadbalancer:type: OS::Neutron::LoadBalancerproperties:protocol_port: 80pool_id: { get_resource: web_server_pool }web_tier_monitor:type: OS::Neutron::HealthMonitorproperties:type: TCPdelay: 5max_retries: 5timeout: 5web_server_pool:type: OS::Neutron::Poolproperties:protocol: HTTPmonitors: [{ get_resource: web_tier_monitor }]subnet: { get_resource: private_network_subnet }lb_method: ROUND_ROBINvip:protocol_port: 80web_vip_port:type: OS::Neutron::Portproperties:network: { get_resource: private_network }security_groups: [{ get_resource: web_security_group }]fixed_ips:subnet_id: { get_resource: private_network_subnet }web_network_floating_ip:type: OS::Neutron::FloatingIPproperties:floating_network: { get_resource: public_network_id }port_id: { get_resource: web_vip_port }association:type: OS::Neutron::FloatingIPAssociationproperties:floating_id: { get_resource: web_network_floating_ip }port_id: { get_resource: web_vip_port }app_tier_loadbalancer:type: OS::Neutron::LoadBalancerproperties:protocol_port: 80pool_id: { get_resource: app_server_pool }app_tier_monitor:type: OS::Neutron::HealthMonitorproperties:type: TCPdelay: 5max_retries: 5timeout: 5app_server_pool:type: OS::Neutron::Poolproperties:protocol: HTTPmonitors: [{ get_resource: app_tier_monitor }]subnet: { get_resource: private_network_subnet }lb_method: ROUND_ROBINvip:protocol_port: 80web_security_group:type: OS::Neutron::SecurityGroupproperties:description: A application specific security group that passes ports 22 and 80name: workload_web_security_grouprules:- protocol_port: tcpport_range_min: 22port_range_max: 22- protocol_port: tcpport_range_min: 80port_range_max: 80app_security_group:type: OS::Neutron::SecurityGroupproperties:description: A application specific security group that passes ports 22, 80 and 3306name: workload_app_security_grouprules:- protocol_port: tcpport_range_min: 22port_range_max: 22- protocol_port: tcpport_range_min: 80port_range_max: 80- protocol_port: tcpport_range_min: 3306port_range_max: 3306db_security_group:type: OS::Neutron::SecurityGroupproperties:description: A database specific security group that passes ports 22 and 3306name: workload_db_security_grouprules:- protocol_port: tcpport_range_min: 22port_range_max: 22- protocol_port: tcpport_range_min: 3306port_range_max: 3306output:web_security_group:description: web security group IDvalue: {get_resource: web_security_group}app_security_group:description: app security group IDvalue: {get_resource: app_security_group}db_security_group:description: db security group IDvalue: {get_resource: web_security_group}web_lbaas_pool_name:description: Name of Web LBaaS Poolvalue: {get_resource: web_server_pool}app_lbaas_pool_name:description: Name of App LBaaS Poolvalue: {get_resource: app_server_pool}web_lbaas_ip:description: Public floating IP assigned to web LBaaSvalue: { get_attr: [ Web_Network_Floating_IP, floating_ip_address ] }
The web tier template installs and configures the web server instances to receive requests and consume the services of the following application tier.
resources:web_server:type: OS::Nova::Serverproperties:name: { get_param: server_name }image: { get_param: image }flavor: { get_param: flavor }key_name: { get_param: key_name }networks:- network: { get_param: private_network_id }security_groups: - { get_param: security_group }user_data_format: RAWuser_data:str_replace:params:$app_lbaas_vip: { get_param: app_lbaas_vip }template: #!/bin/bash -v yum install -y httpd yum install -y wget cat >> /etc/httpd/conf/httpd.conf << EOL <VirtualHost *:*> ProxyPreserveHost On ProxyPass / http://$app_lbaas_vip/ ProxyPassReverse /http://$app_lbaas_vip/ServerName localhost </VirtualHost> EOL systemctl restart httpdPool_Member:type: OS::Neutron::PoolMemberproperties:pool_id: { get_param: pool_name }address: { get_param: [web_server, first_address]}protocol_port: 80outputs:web_private_ip:description: Private IP address of the Web Instancevalue: { get_attr: [web_server, first_address] }lb_member:description: LoadBalancer member detailsvalue: { get_attr: [Pool_Member, show] }
The app tier template creates and installs everything required by the application, allowing it to be consumed and query the data tier. In the example case, the web-tracker application was developed in node.js.
resources:app_server:type: OS::Nova::Serverproperties:name: { get_param: server_name }image: { get_param: image }flavor: { get_param: flavor }key_name: { get_param: key_name }networks:- network: { get_param: private_network_id }security_groups: - { get_param: security_group }user_data_format: RAWuser_data:str_replace:template: | #!/bin/bash -v yum groupinstall -y 'Development Tools' yum module install -y nodejs/development yum install -y wget wgethttp://materials.example.com/webtracker.tar.gztar -xz webtracker.tar.gz chmod +x webtracker.js ./webtracker.js &Pool_Member:type: OS::Neutron::PoolMemberproperties:pool_id: { get_param: pool_name }address: { get_param: [app_server, first_address]}protocol_port: 80outputs:app_private_ip:description: Private IP address of the App Instancevalue: { get_attr: [app_server, first_address] }lb_member:description: LoadBalancer member detailsvalue: { get_attr: [Pool_Member, show] }
The template for the data tier deployment, requires extra parameters to configure the instance:
parameters: ...output omitted...db_name:type: stringdescription: Database namedefault: webtrackerconstraints:- length: { min: 1, max: 64 }description: db_name must be between 1 and 64 characters- allowed_pattern: '[a-zA-Z][a-zA-Z0-9]*'description: db_name must begin with a letter and contain only alphanumeric charactersdb_username:type: stringdescription: Database admin account usernamedefault: webtradminhidden: truedb_password:type: stringdescription: Database admin account passworddefault: redhathidden: trueconstraints:- length: { min: 1, max: 41 }description: db_password must be between 1 and 41 characters- allowed_pattern: '[a-zA-Z0-9]*'description: db_password must contain only alphanumeric charactersdb_root_password:type: stringdescription: Root password for databasedefault: redhathidden: trueconstraints:- length: { min: 1, max: 41 }description: db_password must be between 1 and 41 characters- allowed_pattern: '[a-zA-Z0-9]*'description: db_root_password must contain only alphanumeric charactersdb_volume_size:type: stringdescription: Database volume size (in GB) for database filesdefault: 2hidden: trueresources:db_files_volume:type: OS::Cinder::Volumeproperties:size: { get_param: db_volume_size }name: db_filesdb_volume attachment:type: OS::Cinder::VolumeAttachmentproperties:volume_id: { get_param: db_files_volume }instance_uuid: { get_param: db_instance }db_instance:type: OS::Nova::Serverproperties:name: { get_param: server_name }image: { get_param: image }flavor: { get_param: flavor }key_name: { get_param: key_name }networks:- network: { get_param: private_network_id }security_groups: - { get_param: security_group }user_data_format: RAWuser_data:str_replace:template: #!/bin/bash -v mkdir /mnt/db_files chown mysql:mysql /mnt/db_files volume_path="/dev/disk/by-id/virtio-$(echo volume_id | cut -c -20)" echo ${volume_path} mkfs.ext4 ${volume_path} echo "${volume_path} /mnt/db_files ext4 defaults 1 2" >> /etc/fstab mount /mnt/db_files yum -y install mariadb-server mariadb systemctl start mariadb systemctl stop mariadb chown mysql:mysql /mnt/db_files touch /var/log/mariadb/mariadb.log chown mysql:mysql /var/log/mariadb/mariadb.log mv -f /var/lib/mysql /mnt/db_files/ sed -i 's/\/var\/lib\/mysql/\/mnt\/db_files\/mysql/' /etc/my.cnf echo "[client]" >> /etc/my.cnf echo "socket=/mnt/db_files/mysql/mysql.sock" >> /etc/my.cnf systemctl start mariadb systemctl enable mariadb mysqladmin -u root password db_rootpassword cat << EOF | mysql -u root --password=db_rootpassword CREATE DATABASE db_name; CREATE USER 'db_user'@'localhost'; SET PASSWORD FOR 'db_user'@'localhost'=PASSWORD("db_password"); GRANT ALL PRIVILEGES ON db_name.* TO 'db_user'@'localhost' IDENTIFIED BY 'db_password'; CREATE USER 'db_user'@'%'; SET PASSWORD FOR 'db_user'@'%'=PASSWORD("db_password"); GRANT ALL PRIVILEGES ON db_name.* TO 'db_user'@'%' IDENTIFIED BY 'db_password'; FLUSH PRIVILEGES; EOFparams:db_rootpassword: { get_param: db_root_password }db_name: { get_param: db_name }db_user: { get_param: db_user }db_password: { get_param: db_password }volume_id: { get_resource: db_files_volume }outputs:completition:description: Database setup is complete, login username and password arevalue:str_replace:template: Database Name=$dbName, Database Admin Acct=$dbAdminparams:$dbName: { get_param: db_name }$dbAdmin: { get_param: db_username }instance_ip:description: IP address of the deployed database instancevalue: { get_attr: [db_instance, first_address] }
Application Credentials are an authentication mechanism that grants the holder access to a single Keystone project.
User accounts use passwords would be hard coded into the application, which is a security vulnerability. If the user account password is changed, any application using that account would also need to be modified. To solve these security issues, application credentials are built as a subset of the user account that builds them, and uses secrets instead of passwords. Secrets can be changed as needed, are not hard coded into the application, and are not affected when the user account from which the application credential was created changes its password.
Application credentials:
Have their own secrets.
Can only access one project, no matter how many projects the user is in.
Can have all or a subset of roles that the user has on the project.
Are user-lived, meaning that when the user is deleted then the application expires.
No embedding of user passwords in applications.
Recommended practice is to rotate application credentials whenever developers leave the application team.
You can use the command-line interface to create, delete, list, and show application credentials.
The Dashboard displays stacks, templates, and resources in a more usable and easier to read output.
To create an application credential from the Dashboard, log in as a privileged user and navigate to → and then click .
The Dashboard is a web UI that allows you to provide various parameters.
By default the application credentials are forbidden from being used to create further application credentials. If your application needs to be able to perform these actions, select unrestricted.
You will then have the option to download the clouds.yaml and openrc files. To issue a token, move the clouds.yaml file into the /home/user/.config/openstack/ directory to run the openstack token issue command.
[user@demo ~(admin)]$ openstack --os-cloud openstack token issue
+------------+-------------------------------------+
| Field | Value |
+------------+-------------------------------------+
| expires | 2018-08-29T05:37:29+0000 |
| id | gAAAAABbhiMJ4TxxFlTMdsYJpfStsGo.....|
| project_id | 1a74eabbf05c41baadd716179bb9e1da |
| user_id | ef679eeddfd14f8b86becfd7e1dc84f2 |
+------------+-------------------------------------+After you have created an application credential, users can authenticate with it by using the v3applicationcredential auth type.
The clouds.yaml file will contain the following:
# OS_CLOUD=openstack or --os-cloud=openstack
clouds:
openstack:
auth:
auth_url: http://172.25.250.50:5000
application_credential_id: "4392edbe4f8843c8af7b3cece6d89639"
application_credential_secret: "Umx6R_vrDpqFW4WoXb7rsD-4672reni9qZkcfpQgFWXllavc6HDfg"
region_name: "regionOne"
interface: "public"
identity_api_version: 3
auth_type: "v3applicationcredential"Users can create many application credentials with the same role assignments. This allows for rotation of credentials without breaking the app. Otherwise changing a service user's password will need downtime until the application is fully updated with the new password.
The process for rotating an application credential:
Create a new application credential with a unique name.
Update your application's configuration to use the new ID and the new secret. For applications that are distributed, this can be done one node at a time.
When your application is fully set up with the new application credential, delete the old one.
Configuring Access and Security for Instances
For more information, refer to the Users and Identity Management Guide chapter in the Red Hat OpenStack Platform Guide at https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/16.0/html-single/users_and_identity_management_guide/index
Creating an Application Credential:https://docs.openstack.org/python-openstackclient/ussuri/cli/command-objects/application-credentials.html[]