You are on page 1of 15

SVEUILITE U RIJECI

TEHNIKI FAKULTET
Diplomski sveuilini studij raunarstva

Upravljanje u programskom inenjerstvu

7 Funkcionalni primjer koritenja resursa ResourceChain i


ResourceGroup

Rikardo Jakus
0069058561
Rijeka, oujak 2016.

Enzo Licul
0069058647

Sadraj
1.

2.

3.

ResourceChain .................................................................................................................... 1
1.1.

Opis sintakse, parametara i mogunosti ...................................................................... 1

1.2.

Prikaz implementacije HEAT skripte .......................................................................... 2

ResourceGroup .................................................................................................................... 3
2.1.

Opis sintakse, parametara i mogunosti ...................................................................... 4

2.2.

Ideja primjera HEAT skripte ....................................................................................... 4

2.3.

Skaliranje ..................................................................................................................... 5

2.4.

Horizontalno skaliranje ................................................................................................ 5

2.5.

Prikaz implementacije HEAT skripte .......................................................................... 6

Literatura ........................................................................................................................... 13

1. ResourceChain
ResourceChain stvara resurse koji mogu biti meusobno ovisni jedni o drugom. Npr.
moe se koristiti pri odreivanju koji e resursi biti napravljeni u odreenoj fazi razvoja neke
aplikacije.
1.1. Opis sintakse, parametara i mogunosti

Primjer sintakse:

resources:
MyChainResource:
type: OS::Heat::ResourceChain
properties:
resources: <list>
#vrsta resursa koju dodajemo unutar ugnijeenog stoga
concurrent: <boolean>
#opcijonalno; zadana vrijednost je false
resource_properties:
#svojstva koja proslijeujemo svakom predloku u lancu

Kod 1.1: Sintaksa i parametri ResourceChain resursa [1]

Heat e stvoriti lanac koji se sastoji od svakog predloka navedenog u konfiguraciji.


Svaki e se resurs tretirati kao da ima ovisnosti o resursima koji su na popisu resursa bili ispred
njega. Ukoliko je vrijednost concurrent postavljena na true tada e se smatrati da resurs nema
nikakvu ovisnost o prijanjim stvorenim resursima.
Resource_properties sadri vrijednosti koje e biti dodijeljene svakom resursu unutar
lanca. Resursima unutar lanca moemo pristupiti putem indeksa, pri emu indeks odgovara
poloaju predloka unutar vlasnitva resursa.
Primarni nedostatak resursa je taj da se selekcija predloka pomie iz registra resursa u
dijelu s parametrima. Na taj se nain javlja mogunost da e se korisnik zbuniti prilikom
pokuaja proirenja predloka. Takoer oteava se i pronalaenje greke unutar koda, poto
emo morati gledati greku i unutar dijela koji sadri parametre.

1.2. Prikaz implementacije HEAT skripte

heat_template_version: 2015-04-30
parameters:
string-length:
type: number
resources:
my-chain:
type: OS::Heat::ResourceChain
properties:
resources: ['OS::Heat::RandomString',
'OS::Heat::RandomString']
# Za RandomString resource ID je podeen da poprima
# nasumian string, one duljine koju korisnik odabere
# putem get_parm kao vrijednost
resource_properties: length: { get_param: stringlength }
# svakom predloku u lancu prosljeujemo duinu
stringa
outputs:
resource-ids:
value: { get_attr: [my-chain, refs] }
resource-0-value:
value: { get_attr: [my-chain, resource.0, value] }
# definira kojem e se ugnijeenom atributu
# resursa pristupiti, u ovom sluaju pristupamo 'value'
all-resource-attrs:
value: { get_attr: [my-chain, attributes, value] }
# isto tako moemo pristupiti listi svih vrijednosti u grupi

Kod 1.2: Osnovna skripta koja omoguava povezivanje dva RandomString Heat resursa

Slika 1: Pokretanje prijanje skripte javlja sljedeu greku

Pokuavali smo mijenjati verziju predloka (heat_template_version) u verziju


2016-04-08, kako bi Heat pronaao resurs OS:Heat::ResourceChain, ali
koritenjem te verzije javlja nam se sljedea greka.
Koja nam oznaava da se na naem serveru ne moe koristiti novija inaica predloka
(heat_template_version 2016-04-08), to nam oznaava da neemo moi koristit
OS:Heat::ResourceChain resurs. Verzija predloka je bitna, jer svaka verzija sadrava
specifine mogunosti i podrava odreene funkcije. Trenutno izdani predloci: Icehouse 201305-23, Juno 2014-10-16 i Kilo 2015-04-30.

Slika 2: Greka koja se javlja prilikom izmjene predloka

2. ResourceGroup
Stvara jedan ili vie ugnijeenih resursa koji su identino konfigurirani. Njegova svrha
je da korisnicima utedi vrijeme prilikom stvaranja vie jednakih resursa te samim time
poveava produktivnost korisnika, npr. stvaranje 100 identini servera.
Kljuna stvar prilikom koritenja ResourceGroup je ta da ovaj resurs omoguava
razmnoavanje bilo kojeg broja resursa izraenog kao heat stack. Povratna vrijednost prilikom
dohvaanja atributa ovog resursa je popis svih vrijednosti atributa unutar grupe resursa.

Dok e svaki resurs unutar grupe biti identino konfiguriran, ovaj resurs nam doputa
neke bazne prilagodbe za pojedine resurse unutar grupe. U daljnjem primjeru (Primjer 2.1)
slijedi prikaz dodjeljivanja razliitog imena svakom pojedinom serveru unutar jedne
ResourceGroupe.

2.1. Opis sintakse, parametara i mogunosti

Primjer sintakse:
resources:
my_indexed_group:
type: OS::Heat::ResourceGroup
properties:
#count-broj koliko resursa treba napravit
#oekivana integer vrijednost
#default vrijednost 1
count: 3
resource_def:
type: OS::Nova::Server
properties:
# stvara jedinstveno ime za svaki server
# koristei vlastiti index u grupi
name: my_server_%index%
image: CentOS 6.5
flavor: 4GB Performance
Kod 2.1: Skripta stvara tri servera koji imaju isti image i flavor, dok su ima imena razliita (my_server_0,
my_server_1, and my_server_2) [2]

Da bi se dobila vrijednost pojedinog resursa u grupi, moe se koristiti forma


resource.{resource

index}.{attribute

name}. Dok se Resource ID od

pojedinog resursa u grupi moe dobiti preko atributa resource.{resource index}.


Djelovanje resursa ResourceGroup i navedene funkcionalnosti prikazane su u
sljedeem nastavku.

2.2. Ideja primjera HEAT skripte

Ideja ovog projekta je uz pomo resursa ResourceGroup omoguiti horizontalno skaliranje


aplikacije unutar OpenStack okruenja, kako bi se korisnicima omoguila usluga bez kanjenja.

Primjer koji emo ovdje prikazati temelji se na implementaciji i skaliranju vrlo


jednostavnog 'Flask' web posluitelja koji prikazuje naziv (eng. host) posluitelja koji obrauje
korisnike zahtjeve. Kako koristimo balansiranje optereenja nakon svakog novog ponovnog
uitavanja web stranice na koju se spajamo dobit emo razliito ime posluitelja na koji smo
spojeni, jer svaki e put stranica biti obraena od strane razliitog posluitelja.

2.3. Skaliranje

Zamislimo si da imamo jednu aplikaciju na naem virtualnom posluitelju (eng. cloud) i


nakon nekog vremena naa aplikacija stekne razumnu bazu podataka o korisnicima. Kako e
broj naih korisnika biti u stalnom rastu nakon nekog vremena poet e se osjeati usporenost
aplikacije. Usporenost e biti proporcionalna broju korisnika koji koriste aplikaciju. Pitanje je
ta mi zapravo moemo napraviti kako bi poboljali vrijeme odaziva za korisnike ?
Najjednostavnije rjeenje je aurirati trenutnu instancu tako koristit vie CPU jezgri, RAM
memorije ili vie prostora na disku. to se zapravo vrlo lako moe podesiti unutar OpenStack
Horizont GUI-a. Ovakav nain skaliranja instance nazivamo vertikalno skaliranje. Ovakva
vrsta skaliranja dobro radi do jedne toke. Nakon to smo par puta ponovili prijanji postupak
jasno je da emo doi do trenutka kada emo iskoristiti maksimalan broj podranih CPU jezgri,
RAM memorije i prostora na disku. Ukoliko nam promet korisnika i dalje raste, jasno je da sada
vie neemo moi skalirati nau instancu na prijanje opisani nain.

2.4. Horizontalno skaliranje

Drugi pristup skalabilnosti je omoguiti izvoenje aplikacije na vie jednakih posluitelja.


Izvoenje aplikacije na dva ili vie posluitelja uz ujednaavanje optereenja izmeu
posluiteljima omoguit e nam ravnomjernu distribuciju zahtjeva izmeu klijentima koji
pristupaju naoj aplikaciji. Takav nain skaliranja nazivamo Horizontalno skaliranje. Uz
ovakvu vrstu skaliranja biti e potrebno mnogo due vremena da se doe do granice do koje se
vie nee moi skalirati aplikacija. Budui da moemo nastaviti dodavati posluitelje sve dok
ne ponestane 'Compute' resursa unutar OpenStack okruenja.
Horizontalno skaliranje zahtijeva da aplikacije budu paljivo dizajnirane. Jedan primjer su
aplikacije koje zapisuju podatke na disku. U trenutku kada jedan primjerak aplikacije aurira
5

neku datoteku na disku, svi ostali posluitelji osim navedenoga e postati 'zastarjeli'. Kako bi
stvar funkcionirala, podatkovne datoteke koje trebamo promijeniti na jednoj aplikaciji treba
promijeniti i na svim ostalima.

2.5. Prikaz implementacije HEAT skripte

heat_template_version: 2013-05-23
description: Template that installs a cluster of servers with a load
balancer.
parameters:
image:
type: string
label: Image name or ID
description: Image to be used for compute instance
default: ubuntu_cloud14
flavor:
type: string
label: Flavor
description: Type of instance to be used on the compute instance.
default: m1.small
key:
type: string
label: Key name
description: Name of key-pair to be installed on instance.
default: UPI
private_network:
type: string
label: Private network name or ID
description: Network to attach instance to.
default: my_net1
cluster_size:
type: number
label: Cluster size
description: Number of instances in cluster.
default: 2

servers:
type: comma_delimited_list
label: Servers
description: Comma separated list of servers in the cluster.
port_number:
type: number
label: Port number
description: Port number to proxy.
default: 80
resources:
wait_condition:
type: OS::Heat::WaitCondition
properties:
handle: { get_resource: wh }
count: 1
timeout: 600
wh:
type: OS::Heat::WaitConditionHandle
security_group:
type: OS::Neutron::SecurityGroup
properties:
name: web_server_security_group
rules:
- protocol: tcp
port_range_min: 80
port_range_max: 80
port:
type: OS::Neutron::Port
properties:
networks:
- network: { get_param: private_network }
security_groups:
- { get_resource: security_group }
replacement_policy: AUTO

tiny_cluster:
type: OS::Heat::ResourceGroup
properties:
count: { get_param: cluster_size }
resource_def:
type: OS::Nova::Server
properties:
name: server_%index%
image: { get_param: image }
flavor: { get_param: flavor }
key: { get_param: key }
networks:
- network: { get_param: private_network }
- port: { get_resource: port }
user_data_format: RAW
user_data:
str_replace:
params:
wc_notify: { get_attr: ['wh', 'curl_cli'] }
template: |
#!/bin/bash -ex
# instaliramo potrebne alate
apt-get update
apt-get -y install build-essential python python-dev
python-virtualenv nginx supervisor git
# stvaramo tiny korisnika kako bi pokrenuo proces servera
adduser --disabled-password --gecos "" tiny
# instaliramo

tiny aplikaciju

cd /home/tiny
cat >app.py <<EOF
#!/usr/bin/env python
import socket
from flask import Flask
hostname = socket.gethostname()
app = Flask(__name__)

@app.route('/')
def index():
return 'Hello from {0}!'.format(hostname)
if __name__ == '__main__':
app.run(debug=True)
EOF
# stvaramo virtualenv i instaliramo potrebne alate
virtualenv venv
venv/bin/pip install flask gunicorn==18.0
# stvaramo tiny korisnika vlasnikom aplikacije
chown -R tiny:tiny app.py
# konfiguriramo supervisor da pokrene privatan gunicorn
# web server, i da se automatski pokrene pri bootanju i
# kad se srui (eng. crash)
# stdout i stderr logs from the server will go to
# /var/log/tiny
mkdir /var/log/tiny
cat >/etc/supervisor/conf.d/tiny.conf <<EOF
[program:tiny]
command=/home/tiny/venv/bin/gunicorn -b 127.0.0.1:8000 -w
4 --chdir /home/tiny --log-file - app:app
user=tiny
autostart=true
autorestart=true
stderr_logfile=/var/log/tiny/stderr.log
stdout_logfile=/var/log/tiny/stdout.log
EOF
supervisorctl reread
supervisorctl update
# konfiguriramo nginx kao front-end web server sa
# suprotnim proxy pravilima prema gunicorn serveru

cat >/etc/nginx/sites-available/tiny <<EOF


server {
listen 80;
server_name _;
access_log /var/log/nginx/tiny.access.log;
error_log /var/log/nginx/tiny.error.log;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_redirect off;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For
\$proxy_add_x_forwarded_for;
}
}
EOF
rm -f /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/tiny /etc/nginx/sitesenabled/
service nginx restart
# daj obavjest Heat-u da smo gotovi
wc_notify --data-binary '{"status": "SUCCESS"}'
load_balancer:
type: OS::Nova::Server
properties:
image: { get_param: image }
flavor: { get_param: flavor }
key: { get_param: key }
networks:
- network: { get_param: private_network }
- port: { get_resource: port }
servers: { get_attr: [tiny_cluster, ip] }
user_data_format: RAW
user_data:
str_replace:
params:
__port__: { get_param: port_number }
wc_notify: { get_attr: ['wh', 'curl_cli'] }
template: |

10

#!/bin/bash -ex
# instaliramo potrebne alate
apt-get update
apt-get -y install build-essential python python-dev pythonvirtualenv supervisor haproxy
sed -i 's/ENABLED=0/ENABLED=1/' /etc/default/haproxy
# spremamo orginalnu haproxy konfiguraciju
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy_base.cfg
# stvaramo praznu listu radnih servera
>>/etc/haproxy/servers.json <<EOF
[]
EOF
# stvaramo update skriptu
cat >>/etc/haproxy/update.py <<EOF
import sys
import json
import subprocess
# napunimo servers skriptu sa metadata
metadata = json.loads(sys.stdin.read())
new_servers = json.loads(metadata.get('meta',
{}).get('servers', '[]'))
if not new_servers:
sys.exit(1)

# bad metadata

# usporeujemo listu poznatih servera


current_servers =
json.loads(open('/etc/haproxy/servers.json').read())
if current_servers == new_servers:
sys.exit(0)

# no changes

# stvaranje aurirane liste servera


open('/etc/haproxy/servers.json',
'wt').write(json.dumps(new_servers))

11

cat

# generiranje nove haproxy config datoteke


f = open('/etc/haproxy/haproxy.cfg', 'wt')
f.write(open('/etc/haproxy/haproxy_base.cfg').read())
f.write("""
listen app *:80
mode http
balance roundrobin
option httpclose
option forwardfor
""")
for i, server in enumerate(new_servers):
f.write('

server server-{0} {1}:{2}\n'.format(i,

server, __port__))
f.close()
# ponovno uitavamo haproxy konfiguraciju
print('Reloading haproxy with servers: ' + ',
'.join(new_servers))
subprocess.call(['service', 'haproxy', 'reload'])
EOF
# stvaranje procesa koji prati haproxy
crontab -l >_crontab || true
echo "* * * * * curl -s
http://169.254.169.254/openstack/latest/meta_data.json | python
/etc/haproxy/update.py | /usr/bin/logger -t haproxy_update" >>_crontab
crontab <_crontab
rm _crontab
# notifikacija Heatu da smo gotovi
wc_notify --data-binary '{"status": "SUCCESS"}
'floating_ip:
type: OS::Nova::FloatingIP
properties:
port: { get_attr: [load_balancer, port] }
pool: net04_ext
association:
type: OS::Nova::FloatingIPAssociation
properties:
floating_ip: { get_resource: floating_ip }
server_id: { get_resources: tiny_cluster }

Kod 2.2: Skripta potpunog projekta s komentarima [3]

12

3. Literatura
[1] https://specs.openstack.org/openstack/heat-specs/specs/mitaka/resource-chains.html
[2] http://docs.openstack.org/developer/heat/template_guide/openstack.html
[3] https://developer.rackspace.com/blog/openstack-orchestration-in-depth-part-4-scaling/

13

You might also like