{"id":253798,"date":"2015-03-25T22:07:02","date_gmt":"2015-03-25T18:07:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=253798"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=253798","title":{"rendered":"Docker \u0438 \u043a\u043e\u0441\u0442\u044b\u043b\u0438 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435"},"content":{"rendered":"<p>     \t<img decoding=\"async\" src=\"\/\/habrastorage.org\/files\/9a2\/961\/a8c\/9a2961a8ce62499c83de4b8971413f43.png\"\/><\/p>\n<p>  \u041d\u0430\u0432\u0435\u044f\u043d\u043e \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0435\u0439 <a href=\"http:\/\/habrahabr.ru\/post\/253877\/\">\u00ab\u041f\u043e\u043d\u0438\u043c\u0430\u044f Docker\u00bb<\/a>, \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0441\u0442\u044b\u043b\u0435\u0439 \u0432\u043e\u043a\u0440\u0443\u0433 \u0434\u043e\u043a\u0435\u0440\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<p>  \u042f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u043e\u0431\u0432\u044f\u0437\u043e\u043a, \u043d\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 (fig) \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0440\u044f\u0432\u044b\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 (kubernetis, mesos) \u2014 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c\u0438 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438.<\/p>\n<p>  \u0412 \u043c\u043e\u0435\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u0448\u0438\u043d, \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0441\u0445\u0435\u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438\u0437 \u0434\u0432\u0443\u0445 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u043e\u0432 \u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0431\u0435\u043a\u0435\u043d\u0434\u0430, ceph (\u0424\u0421) \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0440\u043e\u0443\u043c\u0438\u043d\u0433 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u0442\u0430\u043c, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e.<br \/>  <a name=\"habracut\"><\/a><br \/>  \u0423 \u043c\u0430\u0448\u0438\u043d \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441. \u0423 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u043e\u0432 \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u0438 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439.<\/p>\n<p>  \u0414\u043d\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0441\u0432\u044f\u0437\u043a\u0443 \u0438\u0437 etcd+skydns (\u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432), runit (\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432) \u0438 ansible (\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f). \u0412\u043e\u0442 \u043a\u043e\u0434 \u043c\u043e\u0434\u0443\u043b\u044f ansible, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0431\u0443\u0434\u0443 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">#!\/usr\/bin\/env python  import os, sys from string import Template  def on_error(msg):   def wrap(f):     def wrapped(self, module):       try:         return f(self, module)       except Exception, e:         module.fail_json(msg=&quot;%s %s: %s&quot; % (msg, self.name, str(e)))     return wrapped   return wrap  class Service:   SERVICE_PREFIX = 'docker-'   SERVICES_DIR = '\/etc\/sv'   RUNNING_SERVICES_DIR = '\/etc\/service'    def __init__(self, name, image, args, announce, announce_as, port):     self.name = name     self.image = image     if args is not None:       self.args = args     else:       self.args = ''     self.announce = announce     self.announce_as = announce_as     self.port = port    def _needs_etcd(self):     return self.announce is not None    def _service_name(self):     return self.SERVICE_PREFIX + self.name    def _root_service_dir(self):     return os.path.join(self.SERVICES_DIR, self._service_name())    def _announced_service_dir(self):     return os.path.join(self._root_service_dir(), 'services', 'service')    def _etcd_service_dir(self):     return os.path.join(self._root_service_dir(), 'services', 'announce')    def _run_service_link(self):     return os.path.join(self.RUNNING_SERVICES_DIR, self._service_name())    def _root_run_file(self):     return os.path.join(self._root_service_dir(), 'run')    def _announced_service_run_file(self):     return os.path.join(self._announced_service_dir(), 'run')    def _etcd_run_file(self):     return os.path.join(self._etcd_service_dir(), 'run')    def exists(self):     return os.path.isdir(self._root_service_dir())    def scheduled_to_run(self):     return os.path.exists(self._run_service_link())    @on_error(&quot;Error starting service&quot;)   def start(self, module):     if self._needs_update(module):       self.install(module)     if self.scheduled_to_run():       return False     os.symlink(self._root_service_dir(), self._run_service_link())     return True    @on_error(&quot;Error stopping service&quot;)   def stop(self, module):     if not self.scheduled_to_run():       return False     os.unlink(self._run_service_link())     return True    @on_error(&quot;Error installing service&quot;)   def install(self, module):     if self._needs_update(module):       self.stop(module)       self.remove(module)        self._create_service(module)       return True     else:       return False    @on_error(&quot;Error creating service&quot;)   def _create_service(self, module):     self._create_service_dirs(module)     self._write_run_file(self._root_run_file(), self._render_root_run())     if self._needs_etcd():       self._write_run_file(self._announced_service_run_file(), self._render_service_run())       self._write_run_file(self._etcd_run_file(), self._render_etcd_run())    def _write_run_file(self, name, content):     f = open(name, 'w')     f.write(content)     os.fchmod(f.fileno(), 0755)     f.close()    @on_error(&quot;Error verifying service existence&quot;)   def _needs_update(self, module):     if self.exists():       if os.path.exists(self._root_run_file()):         root_run = self._render_root_run()         curr_run = open(self._root_run_file()).read()         if root_run != curr_run:           return True         if self._needs_etcd():           if os.path.exists(self._announced_service_run_file()):             service_run = self._render_service_run()             curr_run = open(self._announced_service_run_file()).read()             if service_run != curr_run:               return True             if os.path.exists(self._etcd_run_file()):               etcd_run = self._render_etcd_run()               curr_run = open(self._etcd_run_file()).read()               if etcd_run != curr_run:                 return True             else:               return True           else:             return True       else:         return True     else:       return True     return False    @on_error(&quot;Error creating service directory&quot;)   def _create_service_dirs(self, module):     os.mkdir(self._root_service_dir(), 0755)     if self._needs_etcd():       os.mkdir(os.path.join(self._root_service_dir(), 'services'), 0755)       os.mkdir(self._announced_service_dir(), 0755)       os.mkdir(self._etcd_service_dir(), 0755)    @on_error(&quot;Error removing service&quot;)   def remove(self, module):     if not self.exists():       return False      if self.scheduled_to_run():       self.stop(module)      from shutil import rmtree     rmtree(self._root_service_dir())     return True    def _render_root_run(self):     if self._needs_etcd():       return self._render_runsv_run()     else:       return self._render_service_run()    def _render_service_run(self):     args = self.args     if self.announce:       if self.port is not None:         port = self.port       else:         port = self.announce       if self.announce_as != 'container':         args += &quot; -p $ANNOUNCE_IP:&quot; + self.announce + &quot;:&quot; + port     return Template(&quot;&quot;&quot;#!\/bin\/bash  CONTAINER_NAME=$name  ifconfig eth1 &gt;\/dev\/null 2&gt;&1 if [[ $$? -eq 0 ]]; then   PUBILC_IF=eth0   PRIVATE_IF=eth1 else   PUBILC_IF=eth0   PRIVATE_IF=eth0 fi  case &quot;$announce_as&quot; in   public)  ANNOUNCE_IP=&quot;`ifconfig $$PUBILC_IF | sed -En 's\/127.0.0.1\/\/;s\/.*inet (addr:)?(([0-9]*\\.){3}[0-9]*).*\/\\\\2\/p'`&quot;            ;;   private) ANNOUNCE_IP=&quot;`ifconfig $$PRIVATE_IF | sed -En 's\/127.0.0.1\/\/;s\/.*inet (addr:)?(([0-9]*\\.){3}[0-9]*).*\/\\\\2\/p'`&quot;            ;;         *) ANNOUNCE_IP=&quot;&quot;            ;; esac  docker inspect $$CONTAINER_NAME|grep State &gt;\/dev\/null 2&gt;&1 if [ $$? -eq 0 ]; then   docker rm $$CONTAINER_NAME || { echo &quot;cannot remove container $$CONTAINER_NAME&quot;; exit 1; } fi  docker pull $image  exec docker run \\ -i --rm \\ --name $$CONTAINER_NAME \\ --hostname &quot;`hostname`-$name&quot; \\ $args \\ $image &quot;&quot;&quot;).substitute(name=self.name, image=self.image, args=args, announce_as=self.announce_as)    def _render_runsv_run(self):     return &quot;&quot;&quot;#!\/bin\/bash  runsvdir -P services & RUNSVPID=$!  trap &quot;{ sv stop `pwd`\/services\/*; sv wait `pwd`\/services\/*; kill -HUP $RUNSVPID ; exit 0; }&quot; SIGINT SIGTERM  wait &quot;&quot;&quot;    def _render_etcd_run(self):     return Template(&quot;&quot;&quot;#!\/bin\/bash  ETCD=&quot;http:\/\/192.0.2.1:4001&quot; DOMAIN=&quot;com\/example\/prod\/s\/$name\/`hostname`&quot;  ifconfig eth1 &gt;\/dev\/null 2&gt;&1 if [[ $$? -eq 0 ]]; then   PUBILC_IF=eth0   PRIVATE_IF=eth1 else   PUBILC_IF=eth0   PRIVATE_IF=eth0 fi  case &quot;$announce_as&quot; in   public)  ANNOUNCE_IP=&quot;`ifconfig $$PUBILC_IF | sed -En 's\/127.0.0.1\/\/;s\/.*inet (addr:)?(([0-9]*\\.){3}[0-9]*).*\/\\\\2\/p'`&quot;            ;;   private) ANNOUNCE_IP=&quot;`ifconfig $$PRIVATE_IF | sed -En 's\/127.0.0.1\/\/;s\/.*inet (addr:)?(([0-9]*\\.){3}[0-9]*).*\/\\\\2\/p'`&quot;            ;;         *) ANNOUNCE_IP=&quot;&quot;            ;; esac  enable -f \/usr\/lib\/sleep.bash sleep  trap &quot;{ curl -L &quot;$$ETCD\/v2\/keys\/skydns\/$$DOMAIN&quot; -XDELETE ; exit 0; }&quot; SIGINT SIGTERM  while true; do   if [[ &quot;$announce_as&quot; == &quot;container&quot; ]]; then     ANNOUNCE_IP=&quot;`docker inspect --format '{{ .NetworkSettings.IPAddress }}' $name`&quot;   fi   curl -L &quot;$$ETCD\/v2\/keys\/skydns\/$$DOMAIN&quot; -XPUT -d value=&quot;{\\\\&quot;host\\\\&quot;: \\\\&quot;$$ANNOUNCE_IP\\\\&quot;, \\\\&quot;port\\\\&quot;: $port}&quot; -d ttl=60 &gt;\/dev\/null 2&gt;&1   sleep 45 done&quot;&quot;&quot;).substitute(name=self.name, port=self.announce, announce_as=self.announce_as)  def main():   module = AnsibleModule(     argument_spec = dict(         state       = dict(required=True, choices=['present', 'absent', 'enabled', 'disabled']),         name        = dict(required=True),         image       = dict(required=True),         args        = dict(default=None),         announce    = dict(default=None),         announce_as = dict(default='private', choices=['public', 'private', 'container']),         port        = dict(default=None)     )   )    state = module.params['state']   name  = module.params['name']   image = module.params['image']   args = module.params['args']   announce = module.params['announce']   announce_as = module.params['announce_as']   port = module.params['port']   svc = Service(name, image, args, announce, announce_as, port)    if state == 'present':     module.exit_json(changed=svc.install(module))    if state == 'absent':     module.exit_json(changed=svc.remove(module))    if state == 'enabled':     module.exit_json(changed=svc.start(module))    if state == 'disabled':     module.exit_json(changed=svc.stop(module))    module.fail_json(msg='Unexpected position reached')   sys.exit(0)  from ansible.module_utils.basic import * main() <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441; \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c influxdb:<\/p>\n<pre><code class=\"bash\">ansible -i hosts node-back-1 -s -m rundock -a 'state=enabled name=influxdb image=&quot;registry.s.prod.example.com:5000\/influxdb:latest&quot; args=&quot;--volumes-from data.influxdb -p $PRIVATE_IP:8083:8083&quot; announce=8086 port=8086' <\/code><\/pre>\n<p>  Ansible \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0443 \u043d\u043e\u0432\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043b\u044f runit, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0432\u0435 \u043f\u043e\u0434\u0437\u0430\u0434\u0430\u0447\u0438, \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0430\u043d\u043e\u043d\u0441:<\/p>\n<pre><code class=\"bash\">$ cat \/etc\/sv\/docker-influxdb\/services\/service\/run #!\/bin\/bash  CONTAINER_NAME=influxdb INTERFACE=eth0 PRIVATE_IP=&quot;`ifconfig $INTERFACE | sed -En 's\/127.0.0.1\/\/;s\/.*inet (addr:)?(([0-9]*\\.){3}[0-9]*).*\/\\2\/p'`&quot;  docker inspect $CONTAINER_NAME|grep State &gt;\/dev\/null 2&gt;&1 if [ $? -eq 0 ]; then   docker rm $CONTAINER_NAME || { echo &quot;cannot remove container $CONTAINER_NAME&quot;; exit 1; } fi  docker pull registry.s.prod.example.com:5000\/influxdb:latest  exec docker run -i --rm --name $CONTAINER_NAME --hostname &quot;`hostname`-influxdb&quot; --volumes-from data.influxdb -p $PRIVATE_IP:8083:8083 -p $PRIVATE_IP:8086:8086 registry.s.prod.example.com:5000\/influxdb:latest <\/code><\/pre>\n<p>  runit \u0443\u0431\u044c\u0435\u0442 \u0441\u0442\u0430\u0440\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u0435\u0441\u043b\u0438 \u043e\u043d \u0431\u044b\u043b, \u0441\u043a\u0430\u0447\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u0434\u043e\u043a\u0435\u0440 \u0432 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435. \u0415\u0441\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0443\u043c\u0440\u0435\u0442 \u2014 runit \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442. \u0412 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 <code>data.influxdb<\/code> \u0441\u0434\u0435\u043b\u0430\u043d \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043d\u0430 \u043f\u0443\u0442\u0438 \u0432 \u0424\u0421, \u0433\u0434\u0435 influx \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<p>  \u0412\u0442\u043e\u0440\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441:<\/p>\n<pre><code class=\"bash\">$ cat \/etc\/sv\/docker-influxdb\/services\/announce\/run #!\/bin\/bash  ETCD=&quot;http:\/\/192.0.2.1:4001&quot; DOMAIN=&quot;com\/example\/prod\/s\/influxdb\/`hostname`&quot; INTERFACE=eth0  enable -f \/usr\/lib\/sleep.bash sleep  trap &quot;{ curl -L &quot;$ETCD\/v2\/keys\/skydns\/$DOMAIN&quot; -XDELETE ; exit 0; }&quot; SIGINT SIGTERM  while true; do   PRIVATE_IP=&quot;`ifconfig $INTERFACE | sed -En 's\/127.0.0.1\/\/;s\/.*inet (addr:)?(([0-9]*\\.){3}[0-9]*).*\/\\2\/p'`&quot;   curl -L &quot;$ETCD\/v2\/keys\/skydns\/$DOMAIN&quot; -XPUT -d value=&quot;{\\&quot;host\\&quot;: \\&quot;$PRIVATE_IP\\&quot;, \\&quot;port\\&quot;: 8086}&quot; -d ttl=60 &gt;\/dev\/null 2&gt;&1   sleep 45 <\/code><\/pre>\n<p>  \u041c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f bash \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 sleep \u043a\u0430\u043a built-in \u043a\u043e\u043c\u0430\u043d\u0434\u0443, \u0442\u0435\u043f\u0435\u0440\u044c bash \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0434\u043b\u044f \u0434\u043e\u043c\u0435\u043d\u0430, \u0438 influxdb \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e node-back-1.influxdb.s.prod.example.com.<\/p>\n<p>  <b>\u043a\u043e\u0441\u0442\u044b\u043b\u044c<\/b>: \u043f\u043e-\u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443, \u0430\u043d\u043e\u043d\u0441 \u043d\u0430\u0434\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0430\u043d\u043e\u043d\u0441 \u0431\u0443\u0434\u0435\u0442 \u0436\u0438\u0432 \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0443\u0448\u0435\u043b \u0432 crash-loop.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u043a\u0440\u0443\u0442\u0438\u043c grafana \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430:<\/p>\n<pre><code class=\"bash\">ansible -i hosts node-back-1 -s -m rundock -a 'state=enabled name=grafana image=&quot;tutum\/grafana:latest&quot; args=&quot;-e INFLUXDB_HOST=influxdb.s.prod.example.com -e INFLUXDB_PORT=8086 -e INFLUXDB_NAME=metrics -e INFLUXDB_USER=metrics -e INFLUXDB_PASS=metrics -e HTTP_PASS=metrics -e INFLUXDB_IS_GRAFANADB=true&quot; announce=8087 port=80' <\/code><\/pre>\n<p>  \u0422\u0443\u0442 port \u0438 announce \u0440\u0430\u0437\u043d\u044b\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043e\u0442\u0434\u0430\u0435\u0442 grafana \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 80, \u0430 \u043c\u044b \u043e\u0442\u0434\u0430\u0435\u043c \u0435\u0433\u043e \u043d\u0430\u0440\u0443\u0436\u0443 \u043d\u0430 8087.<\/p>\n<p>  \u041d\u0443 \u0438 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0430\u043f\u0441\u0442\u0440\u0438\u043c \u0432 nginx:<\/p>\n<pre><code>upstream docker_grafana {     server grafana.s.prod.example.com:8087;     keepalive 512; } <\/code><\/pre>\n<p>  <b>\u043a\u043e\u0441\u0442\u044b\u043b\u044c<\/b>: \u043f\u043e\u0440\u0442\u044b \u043f\u0440\u0438\u0431\u0438\u0442\u044b \u0440\u0443\u043a\u0430\u043c\u0438. \u041f\u043e-\u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443, \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 <a href=\"https:\/\/github.com\/vlipco\/srv-router\">\u044d\u0442\u043e\u0433\u043e<\/a> \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0443\u0447\u0438\u0442\u044c nginx \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c SRV \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<h3>\u041f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f?<\/h3>\n<p>  \u0424\u0440\u043e\u043d\u0442\u0435\u043d\u0434. \u0415\u0441\u043b\u0438 \u0443\u043c\u0440\u0435\u0442 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434, \u043d\u0430\u0434\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c DNS \u0437\u0430\u043f\u0438\u0441\u0438. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043b\u0435\u0436\u0438\u043c \u0438 \u0433\u0440\u0443\u0441\u0442\u0438\u043c.<\/p>\n<p>  \u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u0435. etcd\/skydns \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u043b\u043e\u0436\u043d\u043e \u0443\u0431\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0430\u0434\u0435\u043a\u0432\u0430\u0442\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u043d\u044b \u0432 \u043a\u043e\u043d\u0441\u0435\u043d\u0441\u0443\u0441.<\/p>\n<p>  \u0411\u0435\u043a\u0435\u043d\u0434-\u0441\u0435\u0440\u0432\u0438\u0441. \u041c\u044b \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u043c \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0435\u0437 \u0438\u043c\u0435\u043d\u0438 \u043c\u0430\u0448\u0438\u043d\u044b, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0435\u043a\u0435\u043d\u0434\u043e\u0432; skydns \u0431\u0443\u0434\u0435\u0442 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0438\u043b\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u0442\u044c \u0443\u043c\u0435\u0440\u0448\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b.<\/p>\n<p>  \u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430. \u0412 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043c\u0438\u0440\u0435 \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043d\u043e \u0432 \u0436\u0438\u0437\u043d\u0438 \u0432\u0441\u0435 \u043f\u0435\u0447\u0430\u043b\u044c\u043d\u0435\u0435. \u0411\u0414, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u044e\u0442 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e, \u043c\u043e\u0433\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0434\u0438\u0441\u043a\u0435 \u0438\u043b\u0438 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c <code>--volume<\/code>. \u0422\u0430\u043c, \u0433\u0434\u0435 \u043d\u0430\u0434\u043e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c\u0438, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 ceph (paxos, \u043f\u043e \u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443, \u0442\u043e\u0436\u0435 \u0441\u043b\u043e\u0436\u043d\u043e \u0443\u0431\u0438\u0442\u044c).      \t<\/p>\n<div class=\"clear\"><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/253999\/\"> http:\/\/habrahabr.ru\/post\/253999\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>     \t<img decoding=\"async\" src=\"\/\/habrastorage.org\/files\/9a2\/961\/a8c\/9a2961a8ce62499c83de4b8971413f43.png\"\/><\/p>\n<p>  \u041d\u0430\u0432\u0435\u044f\u043d\u043e \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0435\u0439 <a href=\"http:\/\/habrahabr.ru\/post\/253877\/\">\u00ab\u041f\u043e\u043d\u0438\u043c\u0430\u044f Docker\u00bb<\/a>, \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0441\u0442\u044b\u043b\u0435\u0439 \u0432\u043e\u043a\u0440\u0443\u0433 \u0434\u043e\u043a\u0435\u0440\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<p>  \u042f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u043e\u0431\u0432\u044f\u0437\u043e\u043a, \u043d\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 (fig) \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0440\u044f\u0432\u044b\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 (kubernetis, mesos) \u2014 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c\u0438 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438.<\/p>\n<p>  \u0412 \u043c\u043e\u0435\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u0448\u0438\u043d, \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0441\u0445\u0435\u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438\u0437 \u0434\u0432\u0443\u0445 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u043e\u0432 \u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0431\u0435\u043a\u0435\u043d\u0434\u0430, ceph (\u0424\u0421) \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0440\u043e\u0443\u043c\u0438\u043d\u0433 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u0442\u0430\u043c, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-253798","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/253798","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=253798"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/253798\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=253798"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=253798"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=253798"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}