SREãã¼ã ã® @siroken3 ã§ãã
以åãã¡ã«ã«ãªã§ãªãªã¼ã¹æ段ã¨ãã¦ChatOpsãæ¡ç¨ãã¦ãããã¨ãæ¬ããã°ã§ç´¹ä»ãã¾ãããä»åã¯å é¨ã§ä½¿ã£ã¦ããæè¡ã®ä¸é¨ãç´¹ä»ãããã¨æãã¾ãã
tl;dr
- ã¡ã«ã«ãªã§ã¯ãããã¤ã«Ansible使ã£ã¦ã
- æ¯æ¥ãããã¤ãã¤ã¤ãµã¼ããå¢å /å ¥ãæ¿ãæ¿ããã¨å¿ãåãã
- Mackerelã®APIã¨Ansibleãçµã¿åãããããããã¼ã«ãªã£ã
Insideãããã¤
ã¡ã«ã«ãªã§ã¯ãããã¤ç¨ã®ãµã¼ãã§Slack Botãåãã¦ããããããã¤ã®äºåè¦ä»¶ãæºããã¦ããã確èªããå¾ã大ã¾ãã«ã¯ä»¥ä¸ã®å¦çãå®è¡ãã¦ãã¾ãã
- GitHubãããããã¤å¯¾è±¡ã½ã¼ã¹ã®åå¾
- composer install / gulp ãªã©ã®ãã«ãå¦ç
- 対象ãµã¼ãã«rsyncã§ãããã¤
ãããã®å¦çã¯æ§æ管çãã¼ã«ã§ããAnsibleã使ç¨ãã¦ãã¾ãããããã¤ã®ããã®Slack Bot *1ã¯ãã®Ansibleãå é¨ã§å¼ã³åºãã¦ãããå¾è¿°ããplaybookã®åä½ã§ãããã¤ãå®è¡ãã¦ãã¾ãã
ä»åã¯ãããã¤å¦çã®ãã¡å¯¾è±¡ãµã¼ãã«rsyncã§ãããã¤ã«ãã©ã¼ã«ã¹ããå½æã®èª²é¡ã¨Mackerel+ã¹ã¯ãªããã§è§£æ±ºãã話ã®ç´¹ä»ã«ãªãã¾ãããªãæ®å¿µãªããAnsibleèªèº«ã«ã¤ãã¦ã¯åéã®é¢ä¿ä¸è©³ç´°ã«ã¯ç«ã¡å ¥ãã¾ããã®ã§ããã§ã¯ç°¡åãªèª¬æã«ã¨ã©ãããã¨æãã¾ãã
Ansible playbook
Ansibleã§ã¯ããã¤ãã®ã¿ã¹ã¯ãã¾ã¨ãã¦è¤æ°ã®ãµã¼ãã«å¯¾ãã¦å®è¡ããããã®ã¹ã¯ãªããã YAML å½¢å¼ã§è¨è¿°ãã¾ãããããplaybookã¨å¼ãã§ãã¾ããä¸è¨ã¯ playbook ã®ä¾ã§ãã
- hosts: role-application tasks: - name: deploy synchronize: src: "/var/www/vhosts/api/current/" dest: "/var/www/vhosts/api/current/"
ä¸è¨ã¯ role-application
ã§å®ç¾©ã¨ãã¦ããããµã¼ã群ã対象ã«ã㦠Ansibleãå®è¡ãã¦ãããããã¤ç¨ãµã¼ã㨠/var/www/vhosts/api/current ãã£ã¬ã¯ããªã®ãã¡ã¤ã«ãåæãããã¨ãæå³ãã¦ãã¾ãã
Ansibleã§ã¯ãµã¼ã群ã®ãã¨ãInventoryã¨å¼ãã§ãããå¤æ§ãªå½¢å¼ã§å®ç¾©ãããã¨ãã§ãã¾ããä¸è¨ã¯INIå½¢å¼ã§role-applicationã¨ãããµã¼ã群ã«app[1-2]ãå«ã¾ãã¦ãããã¨ãå®ç¾©ãã¦ããä¾ã§ãã
[role-application] app1 app2
ãããã¤ç¨ã®ãµã¼ãã§ä»¥ä¸ã®ã³ãã³ããå®è¡ãããã¨ã§playbook.ymlã«è¨è¿°ãããã¿ã¹ã¯ãå®è¡ããã¾ãã
$ ansible-playbook -i ./hosts ./playbook.yml
ä¸è¨ã¯ INIå½¢å¼ã®Inventoryã hosts ã¨ãããã¡ã¤ã«åã§ä¿åãplaybookã playbook.yml ã§ä½æããä¾ã§ããBotã¯ä¸è¨ã®ãããªã¹ã¯ãªãããåããã»ã¹ã¨ãã¦å®è¡ãã¦ãã¾ãã
å½æã®èª²é¡
å½åInventory管çã¯ãæ¥æ¬ã®ã¡ã«ã«ãªã§ã¯INIå½¢å¼ã®ãã¡ã¤ã«ãUSAã®Mercariã§ã¯ Ansibleã«å梱ããã¦ãã ec2.py ã¨ããAWSã®EC2ã¤ã³ã¹ã¿ã³ã¹ã®ã¿ã°ããåçã«Inventoryæ å ±ãåå¾ãããã¨ãã§ããDynamic Inventory ã¹ã¯ãªãã*2ã使ã£ã¦ãã¾ããã
ããããå¾æ¥ã®æ¹æ³ã ã¨ãµã¼ãã®å¢è¨ãå ¥ãæ¿ãæ¯ã«INIå½¢å¼ã®ãã¡ã¤ã«ãæ´æ°ããããec2ã®ã¿ã°ãè¨å®ããªããããããå¿ è¦ãããã¾ãããå ãã¦ãµã¼ããå¢ãããå ¥ãæ¿ãã£ã¦ãæä¸ãBotã®GoBoldããã¯ãããã¤ãç¹°ãè¿ãã¦ãã¾ãã
çµæãã»ããã¢ãããããµã¼ãã«ãããã¤ãããªããéã«ãã¾ã ã»ããã¢ããä¸ã®ãµã¼ãã«ãããã¤ããã¦Ansible playbookå®è¡å¤±æãããåé¡ãçºçãããã¨ãããã¾ããã
ããã¯Ansible playbookå®è¡å¤±æãã¦ç¡éªæ°ã«å«ã¶ GoBoldããã人éã¯Botã«æ°ã使ã£ã¦ããæ¸ãæ¥ã
ã
ããã§ä»¥åããå¼ç¤¾ã§ãµã¼ãã®ç®¡çãç£è¦ã«å©ç¨ãã¦ããMackerelã®APIã使ã£ã¦ãããã¤å¯¾è±¡ãµã¼ãã®ç®¡çãèªååãã¾ããã
Mackerel
Mackerel ã¨ã¯æ ªå¼ä¼ç¤¾ã¯ã¦ãªã§éçºããã¦ãããµã¼ã管çã»ç£è¦ãµã¼ãã¹ã§ãã
Mackerelã¯Go製ã®mackerel-agentãç£è¦å¯¾è±¡ãµã¼ãã«ã¤ã³ã¹ãã¼ã«ããã ãã§ç£è¦å¯¾è±¡ã«ãªãã®ã§å°å ¥ã容æã§ããå¼ç¤¾ã§ããµã¼ãã®ã»ããã¢ããæ*3ã«mackerel-agentã®ã¤ã³ã¹ãã¼ã«ãå®æ½ãã¦ãã¾ãã
ããã«Mackerelã¯APIãç¨æããã¦ãããç£è¦å¯¾è±¡ãµã¼ãã®ä¸è¦§ãåå¾ã§ãã¾ããã¾ããµã¼ãã«å¯¾ãã¦Roleã§ã°ã«ã¼ãåã§ãã¾ãã
ec2.py ãããã§ããAnsibleã¯Inventoryã¨ãã¦éçãªãã¡ã¤ã«ä»¥å¤ã«ãJSONå½¢å¼ã§ã¤ã³ãã³ããªæ å ±ãæ¨æºåºåããããã°ã©ã ã§ããã°ãªãã§ãã¤ã³ãã³ããªãã¡ã¤ã«ã¨ãã¦æå®ã§ãã¾ããMackerelãç£è¦ãã¦ãããµã¼ãä¸è¦§ãAPIã§åå¾ããDynamic Inventoryã¹ã¯ãªãããèªä½ããã°ããããã§ãã
Dynamic Inventoryã¹ã¯ãªããèªä½
AnsibleãInventoryã¨ãã¦èªèããã¹ã¯ãªããã«ã¤ãã¦å°ã解説ãã¾ããåè¿°ã®INIãã¡ã¤ã«ã¨åãæ å ±ã表ç¾ãã¦ããã®ã¯ä»¥ä¸ã®JSONã«ãªãã¾ããã¹ã¯ãªããã¯ãã®JSONãæ¨æºåºåã«åºåããã°ããã®ã§ãã
{ "_meta": { "hostvars": { "app1": { "ansible_host": "10.0.0.10", "name": "app1" }, "app2": { "ansible_host": "10.0.0.11", "name": "app2" } } }, "role-application": [ "app1", "app2" ] }
ã¾ããMackerelã®ãã¹ãä¸è¦§ãåå¾ããAPIã®å®è¡çµæã¨ãã¦ä»¥ä¸ã®ããã«1ãµã¼ãããã1ã¤ã®JSONãªãã¸ã§ã¯ãã¨ãã¦æ å ±ãå¾ããã¾ãã(ãã£ã¨ããããã®æ å ±ãå¾ããã¾ãããããã§ã¯ããªãçç¥ãã¦ãã¾ã)
{ name: 'app1', meta: { 'agent-name': 'mackerel-agent/0.35.0 (Revision 7e8ca7b)', 'agent-revision': '7e8ca7b', 'agent-version': '0.35.0', block_device: { ... }, cpu: [ ... ], filesystem: { '/dev/sda1': [Object], '/dev/sda3': [Object], tmpfs: [Object] }, kernel: { ... }, memory: { ... }}, type: 'unknown', status: 'working', memo: '', isRetired: false, id: 'xxxxxxxxxxx', createdAt: 1474589195, displayName: null, roles: { mercari: [ 'role-application' ] }, interfaces: [ { macAddress: 'xx:xx:xx:xx:xx:xx', name: 'eth1', ipv4Addresses: [Object], ipAddress: '10.0.0.10' } ] } { name: 'app2', meta: { ...
Mackerelããã®ã¬ã¹ãã³ã¹ãã name
, interfaces[].ipAddress
ãæ¾ã£ã¦roles
ã§ã°ã«ã¼ãåããã¹ã¯ãªãããèªä½ããDynamic Inventoryã«ãªãã¾ãã
ã¡ã«ã«ãªã§ã¯ãã®ã¹ã¯ãªãããNode.jsã§ä½æãã¾ããããéçºè¨èªã¯åããªãã®ã§PerlãPythonã使ã£ã¦ä½æãããã¨ãã§ãã¾ãã*4
ã¾ã¨ã
Mackerelãå©ç¨ããDynamic Inventoryãå°å
¥ããçµæããµã¼ãã®ã»ããã¢ãããçµããã°èªåçã«ç£è¦å¯¾è±¡ãã¤ãããã¤å¯¾è±¡ã«ããããã¨ãã§ãã¾ãããã¾ããMackerelã§è©²å½ãµã¼ããMackerelã®ã³ã³ããã¼ã«ããã«ããmaintenenceã¢ã¼ãã«ãããã¨ã§ãµã¼ãä¸è¦§ã«å
¥ããªãããã«ãã工夫ãã§ã(Mackerelã¬ã¹ãã³ã¹ã®status
ã§å¤å®)ããããã¤ãããããªããµã¼ãããã£ã¦ãèªç¶ã«å¯¾å¿ã§ãã¾ããæå¾ã«åã³ã®å£°ããä¼ããããã¨æãã¾ãã
以ä¸ãç£è¦å¯¾è±¡ã¨ãããã¤å¯¾è±¡ã®ãµã¼ããæããã¨QoLãåä¸ããã話ã§ããã
*1:ã¡ã«ã«ãªã§ã¯GoBoldããã¨ããæ称ã§ã
*2:Ansibleã§ã¯åçã«ã¤ã³ãã³ããªãåç §ããä»çµã¿ãDynamic Inventory ã¨å¼ãã§ãã¾ã
*3:ãããAnsibleã使ã£ã¦ãã¾ã
*4:Ansibleã«contributeããã¦ããã¹ã¯ãªããã¯Pythonãã»ã¨ãã©ãªã®ã§Pythonã§æ¸ãã°ããã£ãããªã¨å°ãæãã¾ãã