Несомненно Cloudflare очень удобный и полезный сервис. Он берет на себя функцию управления DNS и выступает в роли CDN-прокси для вашего сайта выполняя различные оптимизации трафика. Все это возможно при бесплатной подписке. Однако, есть один минус. Cloudflare на текущий момент не предоставляет возможности балансировки трафика или проверки состояния серверов бэкендов. Т.е. если необходимо использовать несколько ip для одного сайта, то это сделать можно просто добавив эти ip в качестве A-записей для одного имени, но при этом, если один из ip окажется недоступен, то Cloudflare покажет ошибку о недоступности пользователям, а не будет пытаться загрузить данные с работающего сервера. К счастью у сloudflare есть API, который позволяет делегировать решение этой проблемы внешнему инструменту, который будет проверять работоспособность каждого адреса и удалять проблемные адреса из конфигурации DNS. Эта заметка описывает пример такой интеграции с Zabbix.
Скрипт для управления DNS-записями Cloudflare
Для управления DNS-записями я подготовил скрипт, который использует официальный модуль python. Для его использования достачно установить необходимые компоненты:
$ yum -y install python-pip python-requests $ pip install cloudflare
Листинг cloudflare_dns.py, в качестве аргумента ip может использоваться как ip, так и dns-имя (полезно для dyndns):
#!/bin/python import getopt import sys import socket import CloudFlare def main(): zone_name = 'example.com' email = '[email protected]' token = '' try: opts, args = getopt.getopt(sys.argv[1:], "d:i", ["dns=", "ip=", "add", "delete"]) except getopt.GetoptError as err: print str(err) sys.exit(2) dns_name = '' ip_address = '' action = '' for o, a in opts: if o == "--add": action = 'add' elif o == "--delete": action = 'delete' elif o == "--dns": dns_name = a elif o == "--ip": ip_address = a else: assert False, "unhandled option" if ip_address == '': exit('ip empty') elif is_valid_ipv4_address(ip_address) == False: ip = socket.gethostbyname(ip_address) if is_valid_ipv4_address(ip) == True: ip_address = ip else: exit('wrong ip or dns') if dns_name == '': exit('dns empty') cf = CloudFlare.CloudFlare(email=email,token=token) # query for the zone name and expect only one value back try: zones = cf.zones.get(params = {'name':zone_name,'per_page':1}) except Exception as e: exit('/zones.get - %s - api call failed' % (e)) # extract the zone_id which is needed to process that zone zone = zones[0] zone_id = zone['id'] if action == 'add': add_record(cf, zone_id, dns_name, ip_address) elif action == 'delete': delete_record(cf, zone_id, dns_name, ip_address) exit(0) def add_record(cf, zone_id, dns_name, ip_address): dns_data = { 'name':dns_name, 'type':'A', 'content':ip_address, 'proxied':True, } try: res = cf.zones.dns_records.post(zone_id, data=dns_data) except Exception as e: exit('/zones.post - %s - api call failed' % (e)) print 'CREATED: %s %s' % (dns_name, ip_address) exit(0) def delete_record(cf, zone_id, dns_name, ip_address): rec_id = '' # request the DNS records from that zone try: dns_records = cf.zones.dns_records.get(zone_id) except Exception as e: exit('/zones/dns_records.get %d %s - api call failed' % (e, e)) # then all the DNS records for that zone for dns_record in dns_records: if dns_record['type'] not in ['A', 'AAAA']: # we only deal with A / AAAA records continue if dns_record['name'] == dns_name and dns_record['content'] == ip_address: rec_id = dns_record['id'] else: continue if rec_id != '': dns_data = { 'name':dns_name, 'type':'A', 'content':ip_address, } try: res = cf.zones.dns_records.delete(zone_id, rec_id, data=dns_data) except Exception as e: exit('/zones.delete - %s - api call failed' % (e)) print 'DELETED: %s %s' % (dns_name, ip_address) exit(0) def is_valid_ipv4_address(address): try: socket.inet_pton(socket.AF_INET, address) except AttributeError: # no inet_pton here, sorry try: socket.inet_aton(address) except socket.error: return False return address.count('.') == 3 except socket.error: # not a valid address return False return True if __name__ == '__main__': main()
Интеграция Zabbix и Cloudflare для управления dns-записями
Интеграция осуществляется через Веб-мониторинг.
1.Необходимо создать отдельный сценарий для каждого адреса. Примерно так:
2. На сценарии необходимо навесить триггеры:
3. Заключительный этап, необходимо создать действия, которые позволят выполнять скрипт по удалению/добавлению ip-адреса в конфигурацию DNS при срабатывании триггера: