рдХреНрд▓рд╕реНрдЯрд░рд╕рд╛рдареА рддреБрдордЪрд╛ рд╕реНрд╡рддрдГрдЪрд╛ рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рдХрд╕рд╛ рдмрдирд╡рд╛рдпрдЪрд╛

рдирдорд╕реНрдХрд╛рд░! рдЖрдореНрд╣реА рд▓реЛрдХрд╛рдВрдирд╛ рдореЛрдареНрдпрд╛ рдбреЗрдЯрд╛рд╕рд╣ рдХрд╛рдо рдХрд░рдгреНрдпрд╛рдЪреЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рджреЗрддреЛ. рдореЛрдареНрдпрд╛ рдбреЗрдЯрд╛рд╡рд░реАрд▓ рд╢реИрдХреНрд╖рдгрд┐рдХ рдХрд╛рд░реНрдпрдХреНрд░рдорд╛рдЪреА рддреНрдпрд╛рдЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рдХреНрд▓рд╕реНрдЯрд░рд╢рд┐рд╡рд╛рдп рдХрд▓реНрдкрдирд╛ рдХрд░рдгреЗ рдЕрд╢рдХреНрдп рдЖрд╣реЗ, рдЬреНрдпрд╛рд╡рд░ рд╕рд░реНрд╡ рд╕рд╣рднрд╛рдЧреА рдПрдХрддреНрд░ рдХрд╛рдо рдХрд░рддрд╛рдд. рдпрд╛ рдХрд╛рд░рдгрд╛рд╕реНрддрд╡, рдЖрдордЪреНрдпрд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдордордзреНрдпреЗ рддреЗ рдиреЗрд╣рдореАрдЪ рдЕрд╕рддреЗ :) рдЖрдореНрд╣реА рддреНрдпрд╛рдЪреЗ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди, рдЯреНрдпреВрдирд┐рдВрдЧ рдЖрдгрд┐ рдкреНрд░рд╢рд╛рд╕рдирд╛рдордзреНрдпреЗ рдЧреБрдВрддрд▓реЗрд▓реЗ рдЕрд╕рддреЛ рдЖрдгрд┐ рд▓реЛрдХ рдереЗрдЯ рдореЕрдкрд░реЗрдбреНрдпреВрд╕ рдЬреЙрдмреНрд╕ рддреЗрдереЗ рд▓реЙрдиреНрдЪ рдХрд░рддрд╛рдд рдЖрдгрд┐ рд╕реНрдкрд╛рд░реНрдХ рд╡рд╛рдкрд░рддрд╛рдд.

рдпрд╛ рдкреЛрд╕реНрдЯрдордзреНрдпреЗ рдЖрдореНрд╣реА рддреБрдореНрд╣рд╛рд▓рд╛ рдХреНрд▓рд╛рдЙрдб рд╡рд╛рдкрд░реВрди рдЖрдордЪреЗ рд╕реНрд╡рддрдГрдЪреЗ рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рд▓рд┐рд╣реВрди рдЕрд╕рдорд╛рди рдХреНрд▓рд╕реНрдЯрд░ рд▓реЛрдбрд┐рдВрдЧрдЪреА рд╕рдорд╕реНрдпрд╛ рдХрд╢реА рд╕реЛрдбрд╡рд▓реА рддреЗ рд╕рд╛рдВрдЧреВ. Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЛрд▓реНрдпреВрд╢рдиреНрд╕.

рд╕рдорд╕реНрдпрд╛

рдЖрдордЪрд╛ рдХреНрд▓рд╕реНрдЯрд░ рдард░рд╛рд╡рд┐рдХ рдореЛрдбрдордзреНрдпреЗ рд╡рд╛рдкрд░рд▓рд╛ рдЬрд╛рдд рдирд╛рд╣реА. рд╡рд┐рд▓реНрд╣реЗрд╡рд╛рдЯ рдЕрддреНрдпрдВрдд рдЕрд╕рдорд╛рди рдЖрд╣реЗ. рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд╡рд░реНрдЧ рдЖрд╣реЗрдд, рдЬреЗрд╡реНрд╣рд╛ рд╕рд░реНрд╡ 30 рд▓реЛрдХ рдЖрдгрд┐ рдПрдХ рд╢рд┐рдХреНрд╖рдХ рдХреНрд▓рд╕реНрдЯрд░рдордзреНрдпреЗ рдЬрд╛рддрд╛рдд рдЖрдгрд┐ рддреЗ рд╡рд╛рдкрд░рдгреНрдпрд╛рд╕ рдкреНрд░рд╛рд░рдВрдн рдХрд░рддрд╛рдд. рдХрд┐рдВрд╡рд╛ рдкреБрдиреНрд╣рд╛, рдЕрдВрддрд┐рдо рдореБрджрддреАрдкреВрд░реНрд╡реАрдЪреЗ рджрд┐рд╡рд╕ рдЖрд╣реЗрдд рдЬреЗрд╡реНрд╣рд╛ рд▓реЛрдб рдореЛрдареНрдпрд╛ рдкреНрд░рдорд╛рдгрд╛рдд рд╡рд╛рдврддреЗ. рдЙрд░реНрд╡рд░рд┐рдд рд╡реЗрд│ рдХреНрд▓рд╕реНрдЯрд░ рдЕрдВрдбрд░рд▓реЛрдб рдореЛрдбрдордзреНрдпреЗ рдХрд╛рд░реНрдп рдХрд░рддреЛ.

рдЙрдкрд╛рдп #1 рдореНрд╣рдгрдЬреЗ рдПрдХ рдХреНрд▓рд╕реНрдЯрд░ рдареЗрд╡рдгреЗ рдЬреЗ рдкреАрдХ рднрд╛рд░ рд╕рд╣рди рдХрд░реЗрд▓, рдкрд░рдВрддреБ рдЙрд░реНрд╡рд░рд┐рдд рд╡реЗрд│реЗрдд рдирд┐рд╖реНрдХреНрд░рд┐рдп рдЕрд╕реЗрд▓.

рдЙрдкрд╛рдп #2 рдореНрд╣рдгрдЬреЗ рдПрдХ рд▓рд╣рд╛рди рдХреНрд▓рд╕реНрдЯрд░ рдареЗрд╡рдгреЗ, рдЬреНрдпрд╛рдордзреНрдпреЗ рддреБрдореНрд╣реА рд╡рд░реНрдЧрд╛рдВрдкреВрд░реНрд╡реА рдЖрдгрд┐ рдкреАрдХ рд▓реЛрдб рджрд░рдореНрдпрд╛рди рдиреЛрдбреНрд╕ рдореЕрдиреНрдпреБрдЕрд▓реА рдЬреЛрдбрддрд╛.

рдЙрдкрд╛рдп #3 рдореНрд╣рдгрдЬреЗ рдПрдХ рд▓рд╣рд╛рди рдХреНрд▓рд╕реНрдЯрд░ рдареЗрд╡рдгреЗ рдЖрдгрд┐ рдПрдХ рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рд▓рд┐рд╣рд┐рдгреЗ рдЬреЗ рдХреНрд▓рд╕реНрдЯрд░рдЪреНрдпрд╛ рд╡рд░реНрддрдорд╛рди рд▓реЛрдбрдЪреЗ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░реЗрд▓ рдЖрдгрд┐ рд╡рд┐рд╡рд┐рдз API рд╡рд╛рдкрд░реВрди, рдХреНрд▓рд╕реНрдЯрд░рдордзреВрди рдиреЛрдбреНрд╕ рдЬреЛрдбрдгреЗ рдЖрдгрд┐ рдХрд╛рдвреВрди рдЯрд╛рдХрдгреЗ.

рдпрд╛ рдкреЛрд╕реНрдЯрдордзреНрдпреЗ рдЖрдкрдг рдЙрдкрд╛рдп #3 рдмрджреНрджрд▓ рдмреЛрд▓реВ. рд╣реЗ рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рдЕрдВрддрд░реНрдЧрдд рдШрдЯрдХрд╛рдВрдРрд╡рдЬреА рдмрд╛рд╣реНрдп рдШрдЯрдХрд╛рдВрд╡рд░ рдЬрд╛рд╕реНрдд рдЕрд╡рд▓рдВрдмреВрди рдЕрд╕рддреЗ рдЖрдгрд┐ рдкреНрд░рджрд╛рддреЗ рд╕рд╣рд╕рд╛ рддреЗ рдкреНрд░рджрд╛рди рдХрд░рдд рдирд╛рд╣реАрдд. рдЖрдореНрд╣реА Mail.ru Cloud Solutions рдХреНрд▓рд╛рдЙрдб рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░ рд╡рд╛рдкрд░рддреЛ рдЖрдгрд┐ MCS API рд╡рд╛рдкрд░реВрди рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рд▓рд┐рд╣рд┐рддреЛ. рдЖрдгрд┐ рдЖрдореНрд╣реА рдбреЗрдЯрд╛рд╕рд╣ рдХрд╕реЗ рдХрд╛рд░реНрдп рдХрд░рд╛рд╡реЗ рд╣реЗ рд╢рд┐рдХрд╡рд▓реНрдпрд╛рдореБрд│реЗ, рдЖрдореНрд╣реА рддреБрдордЪреНрдпрд╛ рд╕реНрд╡рдд: рдЪреНрдпрд╛ рд╣реЗрддреВрдВрд╕рд╛рдареА рд╕рдорд╛рди рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рдХрд╕реЗ рд▓рд┐рд╣реВ рд╢рдХрддрд╛ рдЖрдгрд┐ рддреЗ рддреБрдордЪреНрдпрд╛ рдХреНрд▓рд╛рдЙрдбрд╕рд╣ рдХрд╕реЗ рд╡рд╛рдкрд░реВ рд╢рдХрддрд╛ рд╣реЗ рджрд░реНрд╢рд╡рд┐рдгреНрдпрд╛рдЪреЗ рдард░рд╡рд▓реЗ рдЖрд╣реЗ.

рдкреВрд░реНрд╡рд╛рдкреЗрдХреНрд╖рд┐рдд

рдкреНрд░рдердо, рддреБрдордЪреНрдпрд╛рдХрдбреЗ рд╣рдбреВрдк рдХреНрд▓рд╕реНрдЯрд░ рдЕрд╕рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ. рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рдЖрдореНрд╣реА рдПрдЪрдбреАрдкреА рд╡рд┐рддрд░рдг рд╡рд╛рдкрд░рддреЛ.

рддреБрдордЪреЗ рдиреЛрдбреНрд╕ рджреНрд░реБрддрдкрдгреЗ рдЬреЛрдбрд▓реЗ рдЬрд╛рдгреНрдпрд╛рд╕рд╛рдареА рдЖрдгрд┐ рдХрд╛рдвреВрди рдЯрд╛рдХрдгреНрдпрд╛рд╕рд╛рдареА, рддреБрдордЪреНрдпрд╛рдХрдбреЗ рдиреЛрдбреНрд╕рдордзреНрдпреЗ рднреВрдорд┐рдХрд╛рдВрдЪреЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╡рд┐рддрд░рдг рдЕрд╕рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ.

  1. рдорд╛рд╕реНрдЯрд░ рдиреЛрдб. рдмрд░рдВ, рдпреЗрдереЗ рд╕реНрдкрд╖реНрдЯ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рд╡рд┐рд╢реЗрд╖рддрдГ рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд╣реАрд╣реА рдирд╛рд╣реА: рдХреНрд▓рд╕реНрдЯрд░рдЪрд╛ рдореБрдЦреНрдп рдиреЛрдб, рдЬреНрдпрд╛рд╡рд░, рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рд╕реНрдкрд╛рд░реНрдХ рдбреНрд░рд╛рдЗрд╡реНрд╣рд░ рд▓реЙрдиреНрдЪ рдХреЗрд▓рд╛ рдЬрд╛рддреЛ, рдЬрд░ рддреБрдореНрд╣реА рдкрд░рд╕реНрдкрд░рд╕рдВрд╡рд╛рджреА рдореЛрдб рд╡рд╛рдкрд░рдд рдЕрд╕рд╛рд▓.
  2. рддрд╛рд░реАрдЦ рдиреЛрдб. рд╣рд╛ рдиреЛрдб рдЖрд╣реЗ рдЬреНрдпрд╛рд╡рд░ рддреБрдореНрд╣реА HDFS рд╡рд░ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд░рддрд╛ рдЖрдгрд┐ рдЬрд┐рдереЗ рдЧрдгрдирд╛ рдХреЗрд▓реА рдЬрд╛рддреЗ.
  3. рд╕рдВрдЧрдгрдХреАрдп рдиреЛрдб. рд╣рд╛ рдПрдХ рдиреЛрдб рдЖрд╣реЗ рдЬрд┐рдереЗ рддреБрдореНрд╣реА HDFS рд╡рд░ рдХрд╛рд╣реАрд╣реА рд╕рдВрдЪрдпрд┐рдд рдХрд░рдд рдирд╛рд╣реА, рдкрд░рдВрддреБ рдЬрд┐рдереЗ рдЧрдгрдирд╛ рдХреЗрд▓реА рдЬрд╛рддреЗ.

рдорд╣рддреНрддреНрд╡рд╛рдЪрд╛ рдореБрджреНрджрд╛. рддрд┐рд╕рд▒реНрдпрд╛ рдкреНрд░рдХрд╛рд░рдЪреНрдпрд╛ рдиреЛрдбреНрд╕рдореБрд│реЗ рдСрдЯреЛрд╕реНрдХреЗрд▓рд┐рдВрдЧ рд╣реЛрдИрд▓. рдЬрд░ рддреБрдореНрд╣реА рджреБрд╕рд▒реНрдпрд╛ рдкреНрд░рдХрд╛рд░рдЪреЗ рдиреЛрдбреНрд╕ рдШреЗрдгреЗ рдЖрдгрд┐ рдЬреЛрдбрдгреЗ рд╕реБрд░реВ рдХреЗрд▓реЗ, рддрд░ рдкреНрд░рддрд┐рд╕рд╛рджрд╛рдЪреА рдЧрддреА рдЦреВрдкрдЪ рдХрдореА рдЕрд╕реЗрд▓ - рдбрд┐рдХрдорд┐рд╢рдирд┐рдВрдЧ рдЖрдгрд┐ рд░рд┐рдХрдордорд┐рдЯрд┐рдВрдЧрд▓рд╛ рддреБрдордЪреНрдпрд╛ рдХреНрд▓рд╕реНрдЯрд░рд╡рд░ рдХрд╛рд╣реА рддрд╛рд╕ рд▓рд╛рдЧрддреАрд▓. рд╣реЗ, рдЕрд░реНрдерд╛рддрдЪ, рдСрдЯреЛрд╕реНрдХреЗрд▓рд┐рдВрдЧрдХрдбреВрди рддреБрдореНрд╣рд╛рд▓рд╛ рдЕрдкреЗрдХреНрд╖рд┐рдд рдирд╛рд╣реА. рдореНрд╣рдгрдЬреЗрдЪ, рдЖрдореНрд╣реА рдкрд╣рд┐рд▓реНрдпрд╛ рдЖрдгрд┐ рджреНрд╡рд┐рддреАрдп рдкреНрд░рдХрд╛рд░рдЪреНрдпрд╛ рдиреЛрдбреНрд╕рд▓рд╛ рд╕реНрдкрд░реНрд╢ рдХрд░рдд рдирд╛рд╣реА. рддреЗ рдХрд┐рдорд╛рди рд╡реНрдпрд╡рд╣рд╛рд░реНрдп рдХреНрд▓рд╕реНрдЯрд░рдЪреЗ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддреАрд▓ рдЬреЗ рдХрд╛рд░реНрдпрдХреНрд░рдорд╛рдЪреНрдпрд╛ рд╕рдВрдкреВрд░реНрдг рдХрд╛рд▓рд╛рд╡рдзреАрдд рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдЕрд╕рддреАрд▓.

рддрд░, рдЖрдордЪреЗ рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рдкрд╛рдпрдерди 3 рдордзреНрдпреЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЖрд╣реЗ, рдХреНрд▓рд╕реНрдЯрд░ рд╕реЗрд╡рд╛ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЕрдВрдмрд╛рд░реА API рд╡рд╛рдкрд░рддреЗ, рд╡рд╛рдкрд░рддреЗ Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЛрд▓реНрдпреВрд╢рдиреНрд╕ рдХрдбреВрди API (MCS) рдорд╢реАрди рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЖрдгрд┐ рдерд╛рдВрдмрд╡рдгреНрдпрд╛рд╕рд╛рдареА.

рд╕рдорд╛рдзрд╛рди рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░

  1. рдореЙрдбреНрдпреВрд▓ autoscaler.py. рдпрд╛рдд рддреАрди рд╡рд░реНрдЧ рдЖрд╣реЗрдд: 1) рдЕрдВрдмрд╛рд░реАрд╕рд╣ рдХрд╛рд░реНрдп рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдХрд╛рд░реНрдпреЗ, 2) MCS рд╕рд╣ рдХрд╛рд░реНрдп рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдХрд╛рд░реНрдпреЗ, 3) рдСрдЯреЛрд╕реНрдХреЗрд▓рд░рдЪреНрдпрд╛ рддрд░реНрдХрд╛рд╢реА рдереЗрдЯ рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдпреЗ.
  2. рд╕реНрдХреНрд░рд┐рдкреНрдЯ observer.py. рдореВрд▓рдд: рдпрд╛рдд рднрд┐рдиреНрди рдирд┐рдпрдо рдЕрд╕рддрд╛рдд: рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рдлрдВрдХреНрд╢рдиреНрд╕ рдХрдзреА рдЖрдгрд┐ рдХреЛрдгрддреНрдпрд╛ рдХреНрд╖рдгреА рдХреЙрд▓ рдХрд░рд╛рдпрдЪреЗ.
  3. рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рдлрд╛рдЗрд▓ config.py. рддреНрдпрд╛рдд, рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рдСрдЯреЛрд╕реНрдХреЗрд▓рд┐рдВрдЧрд╕рд╛рдареА рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдиреЛрдбреНрд╕рдЪреА рд╕реВрдЪреА рдЖрдгрд┐ рдЗрддрд░ рдкреЕрд░рд╛рдореАрдЯрд░реНрд╕рд╡рд░ рдкрд░рд┐рдгрд╛рдо рд╣реЛрддреЛ, рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рдирд╡реАрди рдиреЛрдб рдЬреЛрдбрд▓реНрдпрд╛рдкрд╛рд╕реВрди рдХрд┐рддреА рд╡реЗрд│ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рд╛рд╡реА рд▓рд╛рдЧрддреЗ. рд╡рд░реНрдЧ рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЯрд╛рдЗрдорд╕реНрдЯреЕрдореНрдк рджреЗрдЦреАрд▓ рдЖрд╣реЗрдд, рдЬреЗрдгреЗрдХрд░реВрди рдХреНрд▓рд╛рд╕рдЪреНрдпрд╛ рдЖрдзреА рдЬрд╛рд╕реНрддреАрдд рдЬрд╛рд╕реНрдд рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕рд▓реЗрд▓реЗ рдХреНрд▓рд╕реНрдЯрд░ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рд▓реЙрдиреНрдЪ рдХреЗрд▓реЗ рдЬрд╛рдИрд▓.

рдЖрддрд╛ рдкрд╣рд┐рд▓реНрдпрд╛ рджреЛрди рдлрд╛рдЗрд▓реНрд╕рдордзреАрд▓ рдХреЛрдбрдЪреЗ рддреБрдХрдбреЗ рдкрд╛рд╣реВ.

1. Autoscaler.py рдореЙрдбреНрдпреВрд▓

рдЕрдВрдмрд░реА рд╡рд░реНрдЧ

рд╡рд░реНрдЧ рдЕрд╕рд▓реЗрд▓рд╛ рдХреЛрдбрдЪрд╛ рддреБрдХрдбрд╛ рдЕрд╕рд╛ рджрд┐рд╕рддреЛ Ambari:

class Ambari:
    def __init__(self, ambari_url, cluster_name, headers, auth):
        self.ambari_url = ambari_url
        self.cluster_name = cluster_name
        self.headers = headers
        self.auth = auth

    def stop_all_services(self, hostname):
        url = self.ambari_url + self.cluster_name + '/hosts/' + hostname + '/host_components/'
        url2 = self.ambari_url + self.cluster_name + '/hosts/' + hostname
        req0 = requests.get(url2, headers=self.headers, auth=self.auth)
        services = req0.json()['host_components']
        services_list = list(map(lambda x: x['HostRoles']['component_name'], services))
        data = {
            "RequestInfo": {
                "context":"Stop All Host Components",
                "operation_level": {
                    "level":"HOST",
                    "cluster_name": self.cluster_name,
                    "host_names": hostname
                },
                "query":"HostRoles/component_name.in({0})".format(",".join(services_list))
            },
            "Body": {
                "HostRoles": {
                    "state":"INSTALLED"
                }
            }
        }
        req = requests.put(url, data=json.dumps(data), headers=self.headers, auth=self.auth)
        if req.status_code in [200, 201, 202]:
            message = 'Request accepted'
        else:
            message = req.status_code
        return message

рд╡рд░, рдЙрджрд╛рд╣рд░рдг рдореНрд╣рдгреВрди, рдЖрдкрдг рдлрдВрдХреНрд╢рдирдЪреА рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА рдкрд╛рд╣реВ рд╢рдХрддрд╛ stop_all_services, рдЬреЗ рдЗрдЪреНрдЫрд┐рдд рдХреНрд▓рд╕реНрдЯрд░ рдиреЛрдбрд╡рд░реАрд▓ рд╕рд░реНрд╡ рд╕реЗрд╡рд╛ рдерд╛рдВрдмрд╡рддреЗ.

рд╡рд░реНрдЧрд╛рдЪреНрдпрд╛ рдкреНрд░рд╡реЗрд╢рджреНрд╡рд╛рд░рд╛рд╡рд░ Ambari рддреБрдореНрд╣реА рдкрд╛рд╕ рдХрд░рд╛:

  • ambari_url, рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рдЬрд╕реЗ 'http://localhost:8080/api/v1/clusters/',
  • cluster_name - рдЕрдВрдмрд╛рд░реАрдордзреАрд▓ рддреБрдордЪреНрдпрд╛ рдХреНрд▓рд╕реНрдЯрд░рдЪреЗ рдирд╛рд╡,
  • headers = {'X-Requested-By': 'ambari'}
  • рдЖрдгрд┐ рдЖрдд auth рдЕрдВрдмрд╛рд░реАрд╕рд╛рдареА рддреБрдордЪрд╛ рд▓реЙрдЧрд┐рди рдЖрдгрд┐ рдкрд╛рд╕рд╡рд░реНрдб рд╣рд╛ рдЖрд╣реЗ: auth = ('login', 'password').

рдлрдВрдХреНрд╢рди рд╕реНрд╡рддрдГ REST API рджреНрд╡рд╛рд░реЗ рдЕрдВрдмрд╛рд░реАрд▓рд╛ рджреЛрди рдХреЙрд▓ рдХрд░рдгреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЕрдзрд┐рдХ рдХрд╛рд╣реА рдирд╛рд╣реА. рддрд╛рд░реНрдХрд┐рдХ рджреГрд╖реНрдЯрд┐рдХреЛрдирд╛рддреВрди, рдЖрдореНрд╣рд╛рд▓рд╛ рдкреНрд░рдердо рдиреЛрдбрд╡рд░ рдЪрд╛рд▓реВ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рд╕реЗрд╡рд╛рдВрдЪреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреЗ, рдЖрдгрд┐ рдирдВрддрд░ рджрд┐рд▓реЗрд▓реНрдпрд╛ рдХреНрд▓рд╕реНрдЯрд░рд╡рд░, рджрд┐рд▓реЗрд▓реНрдпрд╛ рдиреЛрдбрд╡рд░, рд╕реВрдЪреАрдордзреВрди рд░рд╛рдЬреНрдпрд╛рдХрдбреЗ рд╕реЗрд╡рд╛ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рдХрд░рдгреНрдпрд╛рд╕ рд╕рд╛рдВрдЧрд┐рддрд▓реЗ. INSTALLED. рд╕рд░реНрд╡ рд╕реЗрд╡рд╛ рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА, рд░рд╛рдЬреНрдпрд╛рдд рдиреЛрдбреНрд╕ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдХрд╛рд░реНрдпреЗ Maintenance рдЗ. рд╕рд╛рд░рдЦреЗ рджрд┐рд╕рддрд╛рдд - рддреЗ API рджреНрд╡рд╛рд░реЗ рдлрдХреНрдд рдХрд╛рд╣реА рд╡рд┐рдирдВрддреНрдпрд╛ рдЖрд╣реЗрдд.

рд╡рд░реНрдЧ Mcs

рд╡рд░реНрдЧ рдЕрд╕рд▓реЗрд▓рд╛ рдХреЛрдбрдЪрд╛ рддреБрдХрдбрд╛ рдЕрд╕рд╛ рджрд┐рд╕рддреЛ Mcs:

class Mcs:
    def __init__(self, id1, id2, password):
        self.id1 = id1
        self.id2 = id2
        self.password = password
        self.mcs_host = 'https://infra.mail.ru:8774/v2.1'

    def vm_turn_on(self, hostname):
        self.token = self.get_mcs_token()
        host = self.hostname_to_vmname(hostname)
        vm_id = self.get_vm_id(host)
        mcs_url1 = self.mcs_host + '/servers/' + self.vm_id + '/action'
        headers = {
            'X-Auth-Token': '{0}'.format(self.token),
            'Content-Type': 'application/json'
        }
        data = {'os-start' : 'null'}
        mcs = requests.post(mcs_url1, data=json.dumps(data), headers=headers)
        return mcs.status_code

рд╡рд░реНрдЧрд╛рдЪреНрдпрд╛ рдкреНрд░рд╡реЗрд╢рджреНрд╡рд╛рд░рд╛рд╡рд░ Mcs рдЖрдореНрд╣реА рдХреНрд▓рд╛рдЙрдбрдордзреНрдпреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдЖрдпрдбреА рдЖрдгрд┐ рдпреВрдЬрд░ рдЖрдпрдбреА рддрд╕реЗрдЪ рддреНрдпрд╛рдЪрд╛ рдкрд╛рд╕рд╡рд░реНрдб рдкрд╛рд╕ рдХрд░рддреЛ. рдХрд╛рд░реНрдпрд╛рдд vm_turn_on рдЖрдореНрд╣рд╛рд▓рд╛ рдПрдХ рдорд╢реАрди рдЪрд╛рд▓реВ рдХрд░рд╛рдпрдЪреА рдЖрд╣реЗ. рдпреЗрдереЗ рддрд░реНрдХ рдереЛрдбреЗ рдЕрдзрд┐рдХ рдХреНрд▓рд┐рд╖реНрдЯ рдЖрд╣реЗ. рдХреЛрдбрдЪреНрдпрд╛ рд╕реБрд░реВрд╡рд╛рддреАрд╕, рдЗрддрд░ рддреАрди рдлрдВрдХреНрд╢рдиреНрд╕ рдореНрд╣рдгрддрд╛рдд: 1) рдЖрдореНрд╣рд╛рд▓рд╛ рдЯреЛрдХрди рдорд┐рд│рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ, 2) рдЖрдореНрд╣рд╛рд▓рд╛ MCS рдордзреАрд▓ рд╣реЛрд╕реНрдЯрдирд╛рд╡ рдорд╢реАрдирдЪреНрдпрд╛ рдирд╛рд╡рд╛рдд рд░реВрдкрд╛рдВрддрд░рд┐рдд рдХрд░рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ, 3) рдпрд╛ рдорд╢реАрдирдЪрд╛ рдЖрдпрдбреА рдорд┐рд│рд╡рд╛. рдкреБрдвреЗ, рдЖрдореНрд╣реА рдлрдХреНрдд рдкреЛрд╕реНрдЯ рд╡рд┐рдирдВрддреА рдХрд░рддреЛ рдЖрдгрд┐ рд╣реЗ рдорд╢реАрди рд▓реЙрдиреНрдЪ рдХрд░рддреЛ.

рдЯреЛрдХрди рдорд┐рд│рд╡рдгреНрдпрд╛рдЪреЗ рдХрд╛рд░реНрдп рдЕрд╕реЗ рджрд┐рд╕рддреЗ:

def get_mcs_token(self):
        url = 'https://infra.mail.ru:35357/v3/auth/tokens?nocatalog'
        headers = {'Content-Type': 'application/json'}
        data = {
            'auth': {
                'identity': {
                    'methods': ['password'],
                    'password': {
                        'user': {
                            'id': self.id1,
                            'password': self.password
                        }
                    }
                },
                'scope': {
                    'project': {
                        'id': self.id2
                    }
                }
            }
        }
        params = (('nocatalog', ''),)
        req = requests.post(url, data=json.dumps(data), headers=headers, params=params)
        self.token = req.headers['X-Subject-Token']
        return self.token

рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рд╡рд░реНрдЧ

рдпрд╛ рд╡рд░реНрдЧрд╛рдд рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд▓реЙрдЬрд┐рдХрд╢реА рд╕рдВрдмрдВрдзрд┐рдд рдлрдВрдХреНрд╢рдиреНрд╕ рдЖрд╣реЗрдд.

рдпрд╛ рд╡рд░реНрдЧрд╛рд╕рд╛рдареА рдХреЛрдбрдЪрд╛ рднрд╛рдЧ рдЕрд╕рд╛ рджрд┐рд╕рддреЛ:

class Autoscaler:
    def __init__(self, ambari, mcs, scaling_hosts, yarn_ram_per_node, yarn_cpu_per_node):
        self.scaling_hosts = scaling_hosts
        self.ambari = ambari
        self.mcs = mcs
        self.q_ram = deque()
        self.q_cpu = deque()
        self.num = 0
        self.yarn_ram_per_node = yarn_ram_per_node
        self.yarn_cpu_per_node = yarn_cpu_per_node

    def scale_down(self, hostname):
        flag1 = flag2 = flag3 = flag4 = flag5 = False
        if hostname in self.scaling_hosts:
            while True:
                time.sleep(5)
                status1 = self.ambari.decommission_nodemanager(hostname)
                if status1 == 'Request accepted' or status1 == 500:
                    flag1 = True
                    logging.info('Decomission request accepted: {0}'.format(flag1))
                    break
            while True:
                time.sleep(5)
                status3 = self.ambari.check_service(hostname, 'NODEMANAGER')
                if status3 == 'INSTALLED':
                    flag3 = True
                    logging.info('Nodemaneger decommissioned: {0}'.format(flag3))
                    break
            while True:
                time.sleep(5)
                status2 = self.ambari.maintenance_on(hostname)
                if status2 == 'Request accepted' or status2 == 500:
                    flag2 = True
                    logging.info('Maintenance request accepted: {0}'.format(flag2))
                    break
            while True:
                time.sleep(5)
                status4 = self.ambari.check_maintenance(hostname, 'NODEMANAGER')
                if status4 == 'ON' or status4 == 'IMPLIED_FROM_HOST':
                    flag4 = True
                    self.ambari.stop_all_services(hostname)
                    logging.info('Maintenance is on: {0}'.format(flag4))
                    logging.info('Stopping services')
                    break
            time.sleep(90)
            status5 = self.mcs.vm_turn_off(hostname)
            while True:
                time.sleep(5)
                status5 = self.mcs.get_vm_info(hostname)['server']['status']
                if status5 == 'SHUTOFF':
                    flag5 = True
                    logging.info('VM is turned off: {0}'.format(flag5))
                    break
            if flag1 and flag2 and flag3 and flag4 and flag5:
                message = 'Success'
                logging.info('Scale-down finished')
                logging.info('Cooldown period has started. Wait for several minutes')
        return message

рдЖрдореНрд╣реА рдкреНрд░рд╡реЗрд╢рд╛рд╕рд╛рдареА рд╡рд░реНрдЧ рд╕реНрд╡реАрдХрд╛рд░рддреЛ. Ambari ╨╕ Mcs, рд╕реНрдХреЗрд▓рд┐рдВрдЧрд╕рд╛рдареА рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдиреЛрдбреНрд╕рдЪреА рд╕реВрдЪреА, рддрд╕реЗрдЪ рдиреЛрдб рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рдкреЕрд░рд╛рдореАрдЯрд░реНрд╕: YARN рдордзреАрд▓ рдиреЛрдбрд▓рд╛ рд╡рд╛рдЯрдк рдХреЗрд▓реЗрд▓реА рдореЗрдорд░реА рдЖрдгрд┐ cpu. 2 рдЕрдВрддрд░реНрдЧрдд рдкреЕрд░рд╛рдореАрдЯрд░реНрд╕ q_ram, q_cpu рджреЗрдЦреАрд▓ рдЖрд╣реЗрдд, рдЬреЗ рд░рд╛рдВрдЧ рдЖрд╣реЗрдд. рддреНрдпрд╛рдВрдЪрд╛ рд╡рд╛рдкрд░ рдХрд░реВрди, рдЖрдореНрд╣реА рд╕рдзреНрдпрд╛рдЪреНрдпрд╛ рдХреНрд▓рд╕реНрдЯрд░ рд▓реЛрдбрдЪреА рдореВрд▓реНрдпреЗ рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд░рддреЛ. рдЧреЗрд▓реНрдпрд╛ 5 рдорд┐рдирд┐рдЯрд╛рдВрдд рд╕рд╛рддрддреНрдпрд╛рдиреЗ рд▓реЛрдб рд╡рд╛рдврдд рдЕрд╕рд▓реНрдпрд╛рдЪреЗ рдЖрдкрдг рдкрд╛рд╣рд┐рд▓реНрдпрд╛рд╕, рдЖрдкрдг рдХреНрд▓рд╕реНрдЯрд░рдордзреНрдпреЗ +1 рдиреЛрдб рдЬреЛрдбрдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ рдЕрд╕реЗ рдард░рд╡реВ. рдХреНрд▓рд╕реНрдЯрд░ рдЕрдВрдбрд░рдпреБрдЯрд┐рд▓рд╛рдпрдЭреЗрд╢рди рд╕реНрдерд┐рддреАрд╕рд╛рдареА рд╣реЗрдЪ рдЦрд░реЗ рдЖрд╣реЗ.

рд╡рд░реАрд▓ рдХреЛрдб рдлрдВрдХреНрд╢рдирдЪреЗ рдЙрджрд╛рд╣рд░рдг рдЖрд╣реЗ рдЬреЗ рдХреНрд▓рд╕реНрдЯрд░рдордзреВрди рдорд╢реАрди рдХрд╛рдвреВрди рдЯрд╛рдХрддреЗ рдЖрдгрд┐ рдХреНрд▓рд╛рдЙрдбрдордзреНрдпреЗ рдерд╛рдВрдмрд╡рддреЗ. рдкреНрд░рдердо рдбрд┐рдХрдорд┐рд╢рдирд┐рдВрдЧ рдЖрд╣реЗ YARN Nodemanager, рдирдВрддрд░ рдореЛрдб рдЪрд╛рд▓реВ рд╣реЛрдИрд▓ Maintenance, рдирдВрддрд░ рдЖрдореНрд╣реА рдорд╢реАрдирд╡рд░реАрд▓ рд╕рд░реНрд╡ рд╕реЗрд╡рд╛ рдерд╛рдВрдмрд╡рддреЛ рдЖрдгрд┐ рдХреНрд▓рд╛рдЙрдбрдордзреАрд▓ рд╡реНрд╣рд░реНрдЪреНрдпреБрдЕрд▓ рдорд╢реАрди рдмрдВрдж рдХрд░рддреЛ.

2. Script observer.py

рддреЗрдереВрди рдирдореБрдирд╛ рдХреЛрдб:

if scaler.assert_up(config.scale_up_thresholds) == True:
        hostname = cloud.get_vm_to_up(config.scaling_hosts)
        if hostname != None:
            status1 = scaler.scale_up(hostname)
            if status1 == 'Success':
                text = {"text": "{0} has been successfully scaled-up".format(hostname)}
                post = {"text": "{0}".format(text)}
                json_data = json.dumps(post)
                req = requests.post(webhook, data=json_data.encode('ascii'), headers={'Content-Type': 'application/json'})
                time.sleep(config.cooldown_period*60)

рддреНрдпрд╛рдордзреНрдпреЗ, рдЖрдореНрд╣реА рдХреНрд▓рд╕реНрдЯрд░рдЪреА рдХреНрд╖рдорддрд╛ рд╡рд╛рдврд╡рдгреНрдпрд╛рд╕рд╛рдареА рдкрд░рд┐рд╕реНрдерд┐рддреА рдирд┐рд░реНрдорд╛рдг рдХреЗрд▓реА рдЖрд╣реЗ рдХрд╛ рдЖрдгрд┐ рд░рд╛рдЦреАрд╡ рдордзреНрдпреЗ рдХрд╛рд╣реА рдорд╢реАрди рдЖрд╣реЗрдд рдХрд╛ рддреЗ рддрдкрд╛рд╕рддреЛ, рддреНрдпрд╛рдкреИрдХреА рдПрдХрд╛рдЪреЗ рд╣реЛрд╕реНрдЯрдирд╛рд╡ рдорд┐рд│рд╡рд╛, рддреЗ рдХреНрд▓рд╕реНрдЯрд░рдордзреНрдпреЗ рдЬреЛрдбрд╛ рдЖрдгрд┐ рдЖрдордЪреНрдпрд╛ рдЯреАрдордЪреНрдпрд╛ рд╕реНрд▓реЕрдХрд╡рд░ рддреНрдпрд╛рдмрджреНрджрд▓ рд╕рдВрджреЗрд╢ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рд╛. рдЬреНрдпрд╛рдирдВрддрд░ рддреЗ рд╕реБрд░реВ рд╣реЛрддреЗ cooldown_period, рдЬреЗрд╡реНрд╣рд╛ рдЖрдореНрд╣реА рдХреНрд▓рд╕реНрдЯрд░рдордзреВрди рдХрд╛рд╣реАрд╣реА рдЬреЛрдбрдд рдХрд┐рдВрд╡рд╛ рдХрд╛рдврдд рдирд╛рд╣реА, рдкрд░рдВрддреБ рдлрдХреНрдд рд▓реЛрдбрдЪреЗ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░рддреЛ. рдЬрд░ рддреЗ рд╕реНрдерд┐рд░ рдЭрд╛рд▓реЗ рдЕрд╕реЗрд▓ рдЖрдгрд┐ рдЗрд╖реНрдЯрддрдо рд▓реЛрдб рд╡реНрд╣реЕрд▓реНрдпреВрдЬрдЪреНрдпрд╛ рдХреЙрд░рд┐рдбреЙрд░рдордзреНрдпреЗ рдЕрд╕реЗрд▓, рддрд░ рдЖрдореНрд╣реА рдлрдХреНрдд рдирд┐рд░реАрдХреНрд╖рдг рдЪрд╛рд▓реВ рдареЗрд╡рддреЛ. рдЬрд░ рдПрдХ рдиреЛрдб рдкреБрд░реЗрд╕рд╛ рдирд╕реЗрд▓ рддрд░ рдЖрдореНрд╣реА рджреБрд╕рд░рд╛ рдЬреЛрдбрддреЛ.

рдЖрдордЪреНрдпрд╛рдХрдбреЗ рдзрдбрд╛ рдкреБрдвреЗ рдЕрд╕реЗрд▓ рдЕрд╢рд╛ рдкреНрд░рдХрд░рдгрд╛рдВрд╕рд╛рдареА, рдЖрдореНрд╣рд╛рд▓рд╛ рдЖрдзреАрдЪ рдорд╛рд╣рд┐рдд рдЖрд╣реЗ рдХреА рдПрдХ рдиреЛрдб рдкреБрд░реЗрд╕реЗ рдирд╛рд╣реА, рдореНрд╣рдгреВрди рдЖрдореНрд╣реА рддреНрд╡рд░рд┐рдд рд╕рд░реНрд╡ рд╡рд┐рдирд╛рдореВрд▓реНрдп рдиреЛрдбреНрд╕ рд╕реБрд░реВ рдХрд░рддреЛ рдЖрдгрд┐ рдзрдбрд╛ рд╕рдВрдкреЗрдкрд░реНрдпрдВрдд рддреНрдпрд╛рдВрдирд╛ рд╕рдХреНрд░рд┐рдп рдареЗрд╡рддреЛ. рд╣реЗ рдХреНрд░рд┐рдпрд╛рдХрд▓рд╛рдк рдЯрд╛рдЗрдорд╕реНрдЯреЕрдореНрдкрдЪреА рд╕реВрдЪреА рд╡рд╛рдкрд░реВрди рдШрдбрддреЗ.

рдирд┐рд╖реНрдХрд░реНрд╖

рдЬреЗрд╡реНрд╣рд╛ рддреБрдореНрд╣рд╛рд▓рд╛ рдЕрд╕рдорд╛рди рдХреНрд▓рд╕реНрдЯрд░ рд▓реЛрдбрд┐рдВрдЧрдЪрд╛ рдЕрдиреБрднрд╡ рдпреЗрддреЛ рддреЗрд╡реНрд╣рд╛ рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рд╣реЗ рдЕрд╢рд╛ рдкреНрд░рдХрд░рдгрд╛рдВрд╕рд╛рдареА рдПрдХ рдЪрд╛рдВрдЧрд▓рд╛ рдЖрдгрд┐ рд╕реЛрдпреАрд╕реНрдХрд░ рдЙрдкрд╛рдп рдЖрд╣реЗ. рддреБрдореНрд╣реА рдПрдХрд╛рдЪ рд╡реЗрд│реА рдкреАрдХ рд▓реЛрдбрд╕рд╛рдареА рдЗрдЪреНрдЫрд┐рдд рдХреНрд▓рд╕реНрдЯрд░ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рд╕рд╛рдзреНрдп рдХрд░рддрд╛ рдЖрдгрд┐ рддреНрдпрд╛рдЪ рд╡реЗрд│реА рд╣реЗ рдХреНрд▓рд╕реНрдЯрд░ рдЕрдВрдбрд░рд▓реЛрдб рджрд░рдореНрдпрд╛рди рдареЗрд╡реВ рдирдХрд╛, рдкреИрд╢рд╛рдЪреА рдмрдЪрдд рдХрд░рд╛. рддрд╕реЗрдЪ, рд╣реЗ рд╕рд░реНрд╡ рддреБрдордЪреНрдпрд╛ рд╕рд╣рднрд╛рдЧрд╛рд╢рд┐рд╡рд╛рдп рдЖрдкреЛрдЖрдк рдШрдбрддреЗ. рдСрдЯреЛрд╕реНрдХреЗрд▓рд░ рд╕реНрд╡рддрдГ рдХреНрд▓рд╕реНрдЯрд░ рдореЕрдиреЗрдЬрд░ API рдЖрдгрд┐ рдХреНрд▓рд╛рдЙрдб рдкреНрд░рджрд╛рддрд╛ API рдЪреНрдпрд╛ рд╡рд┐рдирдВрддреАрдЪреНрдпрд╛ рд╕рдВрдЪрд╛рдкреЗрдХреНрд╖рд╛ рдЕрдзрд┐рдХ рдХрд╛рд╣реА рдирд╛рд╣реА, рдПрдХрд╛ рд╡рд┐рд╢рд┐рд╖реНрдЯ рддрд░реНрдХрд╛рдиреБрд╕рд╛рд░ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЖрд╣реЗ. рдЖрдореНрд╣реА рдЖрдзреА рд▓рд┐рд╣рд┐рд▓реНрдпрд╛рдкреНрд░рдорд╛рдгреЗ рдиреЛрдбреНрд╕рдЪреЗ 3 рдкреНрд░рдХрд╛рд░рд╛рдВрдордзреНрдпреЗ рд╡рд┐рднрд╛рдЬрди рдХрд░рдгреЗ рд╣реЗ рддреБрдореНрд╣рд╛рд▓рд╛ рдирд┐рд╢реНрдЪрд┐рддрдкрдгреЗ рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ. рдЖрдгрд┐ рддреБрдореНрд╣реА рдЖрдирдВрджреА рд╡реНрд╣рд╛рд▓.

рд╕реНрддреНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╛